1
0
Fork 0
mirror of https://github.com/kubernetes-sigs/node-feature-discovery.git synced 2025-03-16 21:38:23 +00:00

Merge pull request #2071 from mfranczy/extend-comparison-operators

Add new comparison operators
This commit is contained in:
Kubernetes Prow Robot 2025-03-14 06:43:46 -07:00 committed by GitHub
commit a2600b9f0f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 58 additions and 19 deletions

View file

@ -329,16 +329,31 @@ const (
// Both the input and value must be integer numbers, otherwise an error is // Both the input and value must be integer numbers, otherwise an error is
// returned. // returned.
MatchGt MatchOp = "Gt" MatchGt MatchOp = "Gt"
// MatchGe returns true if the input is greater than or equal to the value of the
// expression (number of values in the expression must be exactly one).
// Both the input and value must be integer numbers, otherwise an error is
// returned.
MatchGe MatchOp = "Ge"
// MatchLt returns true if the input is less than the value of the // MatchLt returns true if the input is less than the value of the
// expression (number of values in the expression must be exactly one). // expression (number of values in the expression must be exactly one).
// Both the input and value must be integer numbers, otherwise an error is // Both the input and value must be integer numbers, otherwise an error is
// returned. // returned.
MatchLt MatchOp = "Lt" MatchLt MatchOp = "Lt"
// MatchLe returns true if the input is less than or equal to the value of the
// expression (number of values in the expression must be exactly one).
// Both the input and value must be integer numbers, otherwise an error is
// returned.
MatchLe MatchOp = "Le"
// MatchGtLt returns true if the input is between two values, i.e. greater // MatchGtLt returns true if the input is between two values, i.e. greater
// than the first value and less than the second value of the expression // than the first value and less than the second value of the expression
// (number of values in the expression must be exactly two). Both the input // (number of values in the expression must be exactly two). Both the input
// and values must be integer numbers, otherwise an error is returned. // and values must be integer numbers, otherwise an error is returned.
MatchGtLt MatchOp = "GtLt" MatchGtLt MatchOp = "GtLt"
// MatchGeLe returns true if the input is between two values including the boundary values,
// i.e. greater than or equal to the first value and less than or equal to the second value
// of the expression (number of values in the expression must be exactly two). Both the input
// and values must be integer numbers, otherwise an error is returned.
MatchGeLe MatchOp = "GeLe"
// MatchIsTrue returns true if the input holds the value "true". The // MatchIsTrue returns true if the input holds the value "true". The
// expression must not have any values. // expression must not have any values.
MatchIsTrue MatchOp = "IsTrue" MatchIsTrue MatchOp = "IsTrue"

View file

@ -809,8 +809,11 @@ below.
| `Exists` | 0 | The key exists | | `Exists` | 0 | The key exists |
| `DoesNotExist` | 0 | The key does not exists | | `DoesNotExist` | 0 | The key does not exists |
| `Gt` | 1 | Input is greater than the value. Both the input and value must be integer numbers. | | `Gt` | 1 | Input is greater than the value. Both the input and value must be integer numbers. |
| `Ge` | 1 | Input is greater than or equal to the value. Both the input and value must be integer numbers. |
| `Lt` | 1 | Input is less than the value. Both the input and value must be integer numbers. | | `Lt` | 1 | Input is less than the value. Both the input and value must be integer numbers. |
| `Le` | 1 | Input is less than or equal to the value. Both the input and value must be integer numbers. |
| `GtLt` | 2 | Input is between two values. Both the input and value must be integer numbers. | | `GtLt` | 2 | Input is between two values. Both the input and value must be integer numbers. |
| `GeLe` | 2 | Input falls within a range that includes the boundary values. Both the input and value must be integer numbers. |
| `IsTrue` | 0 | Input is equal to "true" | | `IsTrue` | 0 | Input is equal to "true" |
| `IsFalse` | 0 | Input is equal "false" | | `IsFalse` | 0 | Input is equal "false" |
@ -968,7 +971,7 @@ The following features are available for matching:
| | | **`enabled`** | bool | `true` if swap partition detected, `false` otherwise | | | | **`enabled`** | bool | `true` if swap partition detected, `false` otherwise |
| **`memory.hugepages`** | attribute | | | Discovery of supported huge pages size on node | | **`memory.hugepages`** | attribute | | | Discovery of supported huge pages size on node |
| | | **`enabled`** | bool | `true` if total number of huge pages (of any page size) have been configured, otherwise `false` | | | | **`enabled`** | bool | `true` if total number of huge pages (of any page size) have been configured, otherwise `false` |
| | | **`hugepages-<page-size>`** | string | total number of huge pages (e.g., `hugepages-1Gi=16`) | | | | **`hugepages-<page-size>`** | string | Total number of huge pages (e.g., `hugepages-1Gi=16`) |
| **`network.device`** | instance | | | Physical (non-virtual) network interfaces present in the system | | **`network.device`** | instance | | | Physical (non-virtual) network interfaces present in the system |
| | | **`name`** | string | Name of the network interface | | | | **`name`** | string | Name of the network interface |
| | | **`<sysfs-attribute>`** | string | Sysfs network interface attribute, available attributes: `operstate`, `speed`, `sriov_numvfs`, `sriov_totalvfs` | | | | **`<sysfs-attribute>`** | string | Sysfs network interface attribute, available attributes: `operstate`, `speed`, `sriov_numvfs`, `sriov_totalvfs` |

View file

@ -46,8 +46,11 @@ var matchOps = map[nfdv1alpha1.MatchOp]struct{}{
nfdv1alpha1.MatchExists: {}, nfdv1alpha1.MatchExists: {},
nfdv1alpha1.MatchDoesNotExist: {}, nfdv1alpha1.MatchDoesNotExist: {},
nfdv1alpha1.MatchGt: {}, nfdv1alpha1.MatchGt: {},
nfdv1alpha1.MatchGe: {},
nfdv1alpha1.MatchLt: {}, nfdv1alpha1.MatchLt: {},
nfdv1alpha1.MatchLe: {},
nfdv1alpha1.MatchGtLt: {}, nfdv1alpha1.MatchGtLt: {},
nfdv1alpha1.MatchGeLe: {},
nfdv1alpha1.MatchIsTrue: {}, nfdv1alpha1.MatchIsTrue: {},
nfdv1alpha1.MatchIsFalse: {}, nfdv1alpha1.MatchIsFalse: {},
} }
@ -115,7 +118,7 @@ func evaluateMatchExpression(m *nfdv1alpha1.MatchExpression, valid bool, value i
return true, nil return true, nil
} }
} }
case nfdv1alpha1.MatchGt, nfdv1alpha1.MatchLt: case nfdv1alpha1.MatchGt, nfdv1alpha1.MatchGe, nfdv1alpha1.MatchLt, nfdv1alpha1.MatchLe:
if len(m.Value) != 1 { if len(m.Value) != 1 {
return false, fmt.Errorf("invalid expression, 'value' field must contain exactly one element for Op %q (have %v)", m.Op, m.Value) return false, fmt.Errorf("invalid expression, 'value' field must contain exactly one element for Op %q (have %v)", m.Op, m.Value)
} }
@ -129,10 +132,11 @@ func evaluateMatchExpression(m *nfdv1alpha1.MatchExpression, valid bool, value i
return false, fmt.Errorf("not a number %q in %v", m.Value[0], m) return false, fmt.Errorf("not a number %q in %v", m.Value[0], m)
} }
if (l < r && m.Op == nfdv1alpha1.MatchLt) || (l > r && m.Op == nfdv1alpha1.MatchGt) { if (l < r && m.Op == nfdv1alpha1.MatchLt) || (l <= r && m.Op == nfdv1alpha1.MatchLe) ||
(l > r && m.Op == nfdv1alpha1.MatchGt) || (l >= r && m.Op == nfdv1alpha1.MatchGe) {
return true, nil return true, nil
} }
case nfdv1alpha1.MatchGtLt: case nfdv1alpha1.MatchGtLt, nfdv1alpha1.MatchGeLe:
if len(m.Value) != 2 { if len(m.Value) != 2 {
return false, fmt.Errorf("invalid expression, value' field must contain exactly two elements for Op %q (have %v)", m.Op, m.Value) return false, fmt.Errorf("invalid expression, value' field must contain exactly two elements for Op %q (have %v)", m.Op, m.Value)
} }
@ -150,7 +154,8 @@ func evaluateMatchExpression(m *nfdv1alpha1.MatchExpression, valid bool, value i
if lr[0] >= lr[1] { if lr[0] >= lr[1] {
return false, fmt.Errorf("invalid expression, value[0] must be less than Value[1] for Op %q (have %v)", m.Op, m.Value) return false, fmt.Errorf("invalid expression, value[0] must be less than Value[1] for Op %q (have %v)", m.Op, m.Value)
} }
return v > lr[0] && v < lr[1], nil return (v > lr[0] && v < lr[1] && m.Op == nfdv1alpha1.MatchGtLt) ||
(v >= lr[0] && v <= lr[1] && m.Op == nfdv1alpha1.MatchGeLe), nil
case nfdv1alpha1.MatchIsTrue: case nfdv1alpha1.MatchIsTrue:
if len(m.Value) != 0 { if len(m.Value) != 0 {
return false, fmt.Errorf("invalid expression, 'value' field must be empty for Op %q (have %v)", m.Op, m.Value) return false, fmt.Errorf("invalid expression, 'value' field must be empty for Op %q (have %v)", m.Op, m.Value)

View file

@ -232,23 +232,39 @@ func TestEvaluateMatchExpressionValues(t *testing.T) {
{name: "17", op: nfdv1alpha1.MatchGt, values: V{"2"}, key: "foo", input: I{"bar": "3", "foo": "3"}, result: assert.True, err: assert.Nil}, {name: "17", op: nfdv1alpha1.MatchGt, values: V{"2"}, key: "foo", input: I{"bar": "3", "foo": "3"}, result: assert.True, err: assert.Nil},
{name: "18", op: nfdv1alpha1.MatchGt, values: V{"2"}, key: "foo", input: I{"bar": "str", "foo": "str"}, result: assert.False, err: assert.NotNil}, {name: "18", op: nfdv1alpha1.MatchGt, values: V{"2"}, key: "foo", input: I{"bar": "str", "foo": "str"}, result: assert.False, err: assert.NotNil},
{name: "19", op: nfdv1alpha1.MatchLt, values: V{"2"}, key: "foo", input: I{"bar": "1"}, result: assert.False, err: assert.Nil}, {name: "19", op: nfdv1alpha1.MatchGe, values: V{"2"}, key: "foo", input: I{"bar": "3"}, result: assert.False, err: assert.Nil},
{name: "20", op: nfdv1alpha1.MatchLt, values: V{"2"}, key: "foo", input: I{"bar": "1", "foo": "2"}, result: assert.False, err: assert.Nil}, {name: "20", op: nfdv1alpha1.MatchGe, values: V{"2"}, key: "foo", input: I{"bar": "3", "foo": "2"}, result: assert.True, err: assert.Nil},
{name: "21", op: nfdv1alpha1.MatchLt, values: V{"2"}, key: "foo", input: I{"bar": "1", "foo": "1"}, result: assert.True, err: assert.Nil}, {name: "21", op: nfdv1alpha1.MatchGe, values: V{"2"}, key: "foo", input: I{"bar": "3", "foo": "3"}, result: assert.True, err: assert.Nil},
{name: "22", op: nfdv1alpha1.MatchLt, values: V{"2"}, key: "foo", input: I{"bar": "str", "foo": "str"}, result: assert.False, err: assert.NotNil}, {name: "22", op: nfdv1alpha1.MatchGe, values: V{"2"}, key: "foo", input: I{"bar": "str", "foo": "str"}, result: assert.False, err: assert.NotNil},
{name: "23", op: nfdv1alpha1.MatchGtLt, values: V{"-10", "10"}, key: "foo", input: I{"bar": "1"}, result: assert.False, err: assert.Nil}, {name: "23", op: nfdv1alpha1.MatchLt, values: V{"2"}, key: "foo", input: I{"bar": "1"}, result: assert.False, err: assert.Nil},
{name: "24", op: nfdv1alpha1.MatchGtLt, values: V{"-10", "10"}, key: "foo", input: I{"bar": "1", "foo": "11"}, result: assert.False, err: assert.Nil}, {name: "24", op: nfdv1alpha1.MatchLt, values: V{"2"}, key: "foo", input: I{"bar": "1", "foo": "2"}, result: assert.False, err: assert.Nil},
{name: "25", op: nfdv1alpha1.MatchGtLt, values: V{"-10", "10"}, key: "foo", input: I{"bar": "1", "foo": "-11"}, result: assert.False, err: assert.Nil}, {name: "25", op: nfdv1alpha1.MatchLt, values: V{"2"}, key: "foo", input: I{"bar": "1", "foo": "1"}, result: assert.True, err: assert.Nil},
{name: "26", op: nfdv1alpha1.MatchGtLt, values: V{"-10", "10"}, key: "foo", input: I{"bar": "1", "foo": "1"}, result: assert.True, err: assert.Nil}, {name: "26", op: nfdv1alpha1.MatchLt, values: V{"2"}, key: "foo", input: I{"bar": "str", "foo": "str"}, result: assert.False, err: assert.NotNil},
{name: "27", op: nfdv1alpha1.MatchGtLt, values: V{"-10", "10"}, key: "foo", input: I{"bar": "str", "foo": "str"}, result: assert.False, err: assert.NotNil},
{name: "28", op: nfdv1alpha1.MatchIsTrue, key: "foo", result: assert.False, err: assert.Nil}, {name: "27", op: nfdv1alpha1.MatchLe, values: V{"2"}, key: "foo", input: I{"bar": "1"}, result: assert.False, err: assert.Nil},
{name: "29", op: nfdv1alpha1.MatchIsTrue, key: "foo", input: I{"foo": "1"}, result: assert.False, err: assert.Nil}, {name: "28", op: nfdv1alpha1.MatchLe, values: V{"2"}, key: "foo", input: I{"bar": "1", "foo": "2"}, result: assert.True, err: assert.Nil},
{name: "30", op: nfdv1alpha1.MatchIsTrue, key: "foo", input: I{"foo": "true"}, result: assert.True, err: assert.Nil}, {name: "29", op: nfdv1alpha1.MatchLe, values: V{"2"}, key: "foo", input: I{"bar": "1", "foo": "1"}, result: assert.True, err: assert.Nil},
{name: "30", op: nfdv1alpha1.MatchLe, values: V{"2"}, key: "foo", input: I{"bar": "str", "foo": "str"}, result: assert.False, err: assert.NotNil},
{name: "31", op: nfdv1alpha1.MatchIsFalse, key: "foo", input: I{"foo": "true"}, result: assert.False, err: assert.Nil}, {name: "31", op: nfdv1alpha1.MatchGtLt, values: V{"-10", "10"}, key: "foo", input: I{"bar": "1"}, result: assert.False, err: assert.Nil},
{name: "32", op: nfdv1alpha1.MatchIsFalse, key: "foo", input: I{"foo": "false"}, result: assert.True, err: assert.Nil}, {name: "32", op: nfdv1alpha1.MatchGtLt, values: V{"-10", "10"}, key: "foo", input: I{"bar": "1", "foo": "11"}, result: assert.False, err: assert.Nil},
{name: "33", op: nfdv1alpha1.MatchGtLt, values: V{"-10", "10"}, key: "foo", input: I{"bar": "1", "foo": "-11"}, result: assert.False, err: assert.Nil},
{name: "34", op: nfdv1alpha1.MatchGtLt, values: V{"-10", "10"}, key: "foo", input: I{"bar": "1", "foo": "1"}, result: assert.True, err: assert.Nil},
{name: "35", op: nfdv1alpha1.MatchGtLt, values: V{"-10", "10"}, key: "foo", input: I{"bar": "str", "foo": "str"}, result: assert.False, err: assert.NotNil},
{name: "36", op: nfdv1alpha1.MatchGeLe, values: V{"-10", "10"}, key: "foo", input: I{"bar": "1"}, result: assert.False, err: assert.Nil},
{name: "37", op: nfdv1alpha1.MatchGeLe, values: V{"-10", "10"}, key: "foo", input: I{"bar": "-10", "foo": "10"}, result: assert.True, err: assert.Nil},
{name: "38", op: nfdv1alpha1.MatchGeLe, values: V{"-10", "10"}, key: "foo", input: I{"bar": "1", "foo": "-11"}, result: assert.False, err: assert.Nil},
{name: "39", op: nfdv1alpha1.MatchGeLe, values: V{"-10", "10"}, key: "foo", input: I{"bar": "1", "foo": "1"}, result: assert.True, err: assert.Nil},
{name: "40", op: nfdv1alpha1.MatchGeLe, values: V{"-10", "10"}, key: "foo", input: I{"bar": "str", "foo": "str"}, result: assert.False, err: assert.NotNil},
{name: "41", op: nfdv1alpha1.MatchIsTrue, key: "foo", result: assert.False, err: assert.Nil},
{name: "42", op: nfdv1alpha1.MatchIsTrue, key: "foo", input: I{"foo": "1"}, result: assert.False, err: assert.Nil},
{name: "43", op: nfdv1alpha1.MatchIsTrue, key: "foo", input: I{"foo": "true"}, result: assert.True, err: assert.Nil},
{name: "44", op: nfdv1alpha1.MatchIsFalse, key: "foo", input: I{"foo": "true"}, result: assert.False, err: assert.Nil},
{name: "45", op: nfdv1alpha1.MatchIsFalse, key: "foo", input: I{"foo": "false"}, result: assert.True, err: assert.Nil},
} }
for _, tc := range tcs { for _, tc := range tcs {