1
0
Fork 0
mirror of https://github.com/kubernetes-sigs/node-feature-discovery.git synced 2025-04-23 20:57:10 +00:00

NFD API: Add the 'type' field for MatchExpression

This commit is contained in:
Marcin Franczyk 2025-04-03 20:16:03 +02:00
parent 242a4f439f
commit 4cf8032ac5
7 changed files with 374 additions and 62 deletions
api/nfd/v1alpha1
deployment
base/nfd-crds
helm/node-feature-discovery/crds
docs/usage
go.mod
pkg/apis/nfd/nodefeaturerule

View file

@ -296,16 +296,34 @@ type MatchExpression struct {
// In other cases Value should contain at least one element.
// +optional
Value MatchValue `json:"value,omitempty"`
// Type defines the value type for specific operators.
// The currently supported type is 'version' for Gt,Ge,Lt,Le,GtLt,GeLe operators.
// +optional
Type ValueType `json:"type,omitempty"`
}
// MatchOp is the match operator that is applied on values when evaluating a
// MatchExpression.
// +kubebuilder:validation:Enum="In";"NotIn";"InRegexp";"Exists";"DoesNotExist";"Gt";"Lt";"GtLt";"IsTrue";"IsFalse"
// +kubebuilder:validation:Enum="In";"NotIn";"InRegexp";"Exists";"DoesNotExist";"Gt";"Ge";"Lt";"Le";"GtLt";"GeLe";"IsTrue";"IsFalse"
type MatchOp string
// MatchValue is the list of values associated with a MatchExpression.
type MatchValue []string
// ValueType represents the type of value in the expression.
type ValueType string
const (
// TypeEmpty is a default value for the expression type.
TypeEmpty ValueType = ""
// TypeVersion represents a version with the following supported formats (major.minor.patch):
// %d.%d.%d (e.g., 1.2.3),
// %d.%d (e.g., 1.2),
// %d (e.g., 1)
TypeVersion ValueType = "version"
)
const (
// MatchAny returns always true.
MatchAny MatchOp = ""

View file

@ -204,11 +204,19 @@ spec:
- Exists
- DoesNotExist
- Gt
- Ge
- Lt
- Le
- GtLt
- GeLe
- IsTrue
- IsFalse
type: string
type:
description: |-
Type defines the value type for specific operators.
The currently supported type is 'version' for Gt,Ge,Lt,Le,GtLt,GeLe operators.
type: string
value:
description: |-
Value is the list of values that the operand evaluates the input
@ -240,11 +248,19 @@ spec:
- Exists
- DoesNotExist
- Gt
- Ge
- Lt
- Le
- GtLt
- GeLe
- IsTrue
- IsFalse
type: string
type:
description: |-
Type defines the value type for specific operators.
The currently supported type is 'version' for Gt,Ge,Lt,Le,GtLt,GeLe operators.
type: string
value:
description: |-
Value is the list of values that the operand evaluates the input
@ -295,11 +311,19 @@ spec:
- Exists
- DoesNotExist
- Gt
- Ge
- Lt
- Le
- GtLt
- GeLe
- IsTrue
- IsFalse
type: string
type:
description: |-
Type defines the value type for specific operators.
The currently supported type is 'version' for Gt,Ge,Lt,Le,GtLt,GeLe operators.
type: string
value:
description: |-
Value is the list of values that the operand evaluates the input
@ -331,11 +355,19 @@ spec:
- Exists
- DoesNotExist
- Gt
- Ge
- Lt
- Le
- GtLt
- GeLe
- IsTrue
- IsFalse
type: string
type:
description: |-
Type defines the value type for specific operators.
The currently supported type is 'version' for Gt,Ge,Lt,Le,GtLt,GeLe operators.
type: string
value:
description: |-
Value is the list of values that the operand evaluates the input
@ -511,11 +543,19 @@ spec:
- Exists
- DoesNotExist
- Gt
- Ge
- Lt
- Le
- GtLt
- GeLe
- IsTrue
- IsFalse
type: string
type:
description: |-
Type defines the value type for specific operators.
The currently supported type is 'version' for Gt,Ge,Lt,Le,GtLt,GeLe operators.
type: string
value:
description: |-
Value is the list of values that the operand evaluates the input
@ -547,11 +587,19 @@ spec:
- Exists
- DoesNotExist
- Gt
- Ge
- Lt
- Le
- GtLt
- GeLe
- IsTrue
- IsFalse
type: string
type:
description: |-
Type defines the value type for specific operators.
The currently supported type is 'version' for Gt,Ge,Lt,Le,GtLt,GeLe operators.
type: string
value:
description: |-
Value is the list of values that the operand evaluates the input
@ -602,11 +650,19 @@ spec:
- Exists
- DoesNotExist
- Gt
- Ge
- Lt
- Le
- GtLt
- GeLe
- IsTrue
- IsFalse
type: string
type:
description: |-
Type defines the value type for specific operators.
The currently supported type is 'version' for Gt,Ge,Lt,Le,GtLt,GeLe operators.
type: string
value:
description: |-
Value is the list of values that the operand evaluates the input
@ -638,11 +694,19 @@ spec:
- Exists
- DoesNotExist
- Gt
- Ge
- Lt
- Le
- GtLt
- GeLe
- IsTrue
- IsFalse
type: string
type:
description: |-
Type defines the value type for specific operators.
The currently supported type is 'version' for Gt,Ge,Lt,Le,GtLt,GeLe operators.
type: string
value:
description: |-
Value is the list of values that the operand evaluates the input

View file

@ -204,11 +204,19 @@ spec:
- Exists
- DoesNotExist
- Gt
- Ge
- Lt
- Le
- GtLt
- GeLe
- IsTrue
- IsFalse
type: string
type:
description: |-
Type defines the value type for specific operators.
The currently supported type is 'version' for Gt,Ge,Lt,Le,GtLt,GeLe operators.
type: string
value:
description: |-
Value is the list of values that the operand evaluates the input
@ -240,11 +248,19 @@ spec:
- Exists
- DoesNotExist
- Gt
- Ge
- Lt
- Le
- GtLt
- GeLe
- IsTrue
- IsFalse
type: string
type:
description: |-
Type defines the value type for specific operators.
The currently supported type is 'version' for Gt,Ge,Lt,Le,GtLt,GeLe operators.
type: string
value:
description: |-
Value is the list of values that the operand evaluates the input
@ -295,11 +311,19 @@ spec:
- Exists
- DoesNotExist
- Gt
- Ge
- Lt
- Le
- GtLt
- GeLe
- IsTrue
- IsFalse
type: string
type:
description: |-
Type defines the value type for specific operators.
The currently supported type is 'version' for Gt,Ge,Lt,Le,GtLt,GeLe operators.
type: string
value:
description: |-
Value is the list of values that the operand evaluates the input
@ -331,11 +355,19 @@ spec:
- Exists
- DoesNotExist
- Gt
- Ge
- Lt
- Le
- GtLt
- GeLe
- IsTrue
- IsFalse
type: string
type:
description: |-
Type defines the value type for specific operators.
The currently supported type is 'version' for Gt,Ge,Lt,Le,GtLt,GeLe operators.
type: string
value:
description: |-
Value is the list of values that the operand evaluates the input
@ -511,11 +543,19 @@ spec:
- Exists
- DoesNotExist
- Gt
- Ge
- Lt
- Le
- GtLt
- GeLe
- IsTrue
- IsFalse
type: string
type:
description: |-
Type defines the value type for specific operators.
The currently supported type is 'version' for Gt,Ge,Lt,Le,GtLt,GeLe operators.
type: string
value:
description: |-
Value is the list of values that the operand evaluates the input
@ -547,11 +587,19 @@ spec:
- Exists
- DoesNotExist
- Gt
- Ge
- Lt
- Le
- GtLt
- GeLe
- IsTrue
- IsFalse
type: string
type:
description: |-
Type defines the value type for specific operators.
The currently supported type is 'version' for Gt,Ge,Lt,Le,GtLt,GeLe operators.
type: string
value:
description: |-
Value is the list of values that the operand evaluates the input
@ -602,11 +650,19 @@ spec:
- Exists
- DoesNotExist
- Gt
- Ge
- Lt
- Le
- GtLt
- GeLe
- IsTrue
- IsFalse
type: string
type:
description: |-
Type defines the value type for specific operators.
The currently supported type is 'version' for Gt,Ge,Lt,Le,GtLt,GeLe operators.
type: string
value:
description: |-
Value is the list of values that the operand evaluates the input
@ -638,11 +694,19 @@ spec:
- Exists
- DoesNotExist
- Gt
- Ge
- Lt
- Le
- GtLt
- GeLe
- IsTrue
- IsFalse
type: string
type:
description: |-
Type defines the value type for specific operators.
The currently supported type is 'version' for Gt,Ge,Lt,Le,GtLt,GeLe operators.
type: string
value:
description: |-
Value is the list of values that the operand evaluates the input

View file

@ -786,6 +786,7 @@ feature.
value:
- <value-1>
- ...
type: <type>
```
In each MatchExpression the `key` specifies the name of of the feature element
@ -820,6 +821,13 @@ below.
The `value` field of MatchExpression is a list of string arguments to the
operator.
Type optional `type` field specifies the type of the `value` field.
Valid types for specific operators are described below.
| Type | Description | Supported Operators |
| --------- | ----------- | ------------------- |
| `version` | Input is recognized as a version in the following formats (major.minor.patch) `%d.%d.%d`, `%d.%d`, `%d` (e.g., "1.2.3", "1.2", "1") |`Gt`,`Ge`,`Lt`,`Le`,`GtLt`,`GeLe` |
##### matchName
The `.matchFeatures[].matchName` field is used to match against the

2
go.mod
View file

@ -3,6 +3,7 @@ module sigs.k8s.io/node-feature-discovery
go 1.24
require (
github.com/Masterminds/semver/v3 v3.3.0
github.com/Masterminds/sprig/v3 v3.3.0
github.com/fsnotify/fsnotify v1.8.0
github.com/google/go-cmp v0.7.0
@ -45,7 +46,6 @@ require (
dario.cat/mergo v1.0.1 // indirect
github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.3.0 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/NYTimes/gziphandler v1.1.1 // indirect
github.com/OneOfOne/xxhash v1.2.8 // indirect

View file

@ -26,6 +26,7 @@ import (
"maps"
semver "github.com/Masterminds/semver/v3"
"k8s.io/klog/v2"
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1"
@ -123,39 +124,88 @@ func evaluateMatchExpression(m *nfdv1alpha1.MatchExpression, valid bool, value i
return false, fmt.Errorf("invalid expression, 'value' field must contain exactly one element for Op %q (have %v)", m.Op, m.Value)
}
l, err := strconv.Atoi(value)
if err != nil {
return false, fmt.Errorf("not a number %q", value)
}
r, err := strconv.Atoi(m.Value[0])
if err != nil {
return false, fmt.Errorf("not a number %q in %v", m.Value[0], m)
switch m.Type {
case nfdv1alpha1.TypeVersion:
l, err := extractVersion(value)
if err != nil {
return false, fmt.Errorf("not a version %q", value)
}
r, err := extractVersion(m.Value[0])
if err != nil {
return false, fmt.Errorf("not a version %q in %v", m.Value[0], m)
}
if (m.Op == nfdv1alpha1.MatchLt && l.LessThan(r)) ||
(m.Op == nfdv1alpha1.MatchLe && l.LessThanEqual(r)) ||
(m.Op == nfdv1alpha1.MatchGt && l.GreaterThan(r)) ||
(m.Op == nfdv1alpha1.MatchGe && l.GreaterThanEqual(r)) {
return true, nil
}
return false, nil
case nfdv1alpha1.TypeEmpty:
l, err := strconv.Atoi(value)
if err != nil {
return false, fmt.Errorf("not a number %q", value)
}
r, err := strconv.Atoi(m.Value[0])
if err != nil {
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.MatchLe) ||
(l > r && m.Op == nfdv1alpha1.MatchGt) || (l >= r && m.Op == nfdv1alpha1.MatchGe) {
return true, nil
}
default:
return false, fmt.Errorf("invalid expression, 'type' field only accepts %q value for Op %q (have %q)", nfdv1alpha1.TypeVersion, m.Op, m.Type)
}
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
}
case nfdv1alpha1.MatchGtLt, nfdv1alpha1.MatchGeLe:
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)
}
v, err := strconv.Atoi(value)
if err != nil {
return false, fmt.Errorf("not a number %q", value)
}
lr := make([]int, 2)
for i := range 2 {
lr[i], err = strconv.Atoi(m.Value[i])
switch m.Type {
case nfdv1alpha1.TypeVersion:
v, err := extractVersion(value)
if err != nil {
return false, fmt.Errorf("not a number %q in %v", m.Value[i], m)
return false, fmt.Errorf("not a version %q", value)
}
lr := make([]*semver.Version, 2)
for i := range 2 {
lr[i], err = extractVersion(m.Value[i])
if err != nil {
return false, fmt.Errorf("not a version %q in %v", m.Value[i], m)
}
}
if (m.Op == nfdv1alpha1.MatchGtLt && v.GreaterThan(lr[0]) && v.LessThan(lr[1])) ||
(m.Op == nfdv1alpha1.MatchGeLe && v.GreaterThanEqual(lr[0]) && v.LessThanEqual(lr[1])) {
return true, nil
}
return false, nil
case nfdv1alpha1.TypeEmpty:
v, err := strconv.Atoi(value)
if err != nil {
return false, fmt.Errorf("not a number %q", value)
}
lr := make([]int, 2)
for i := range 2 {
lr[i], err = strconv.Atoi(m.Value[i])
if err != nil {
return false, fmt.Errorf("not a number %q in %v", m.Value[i], m)
}
}
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 (v > lr[0] && v < lr[1] && m.Op == nfdv1alpha1.MatchGtLt) ||
(v >= lr[0] && v <= lr[1] && m.Op == nfdv1alpha1.MatchGeLe), nil
default:
return false, fmt.Errorf("invalid expression, 'type' field only accepts %q value for Op %q (have %q)", nfdv1alpha1.TypeVersion, m.Op, m.Type)
}
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 (v > lr[0] && v < lr[1] && m.Op == nfdv1alpha1.MatchGtLt) ||
(v >= lr[0] && v <= lr[1] && m.Op == nfdv1alpha1.MatchGeLe), nil
case nfdv1alpha1.MatchIsTrue:
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)
@ -540,3 +590,22 @@ func MatchNamesMulti(m *nfdv1alpha1.MatchExpression, keys map[string]nfdv1alpha1
return len(ret) > 0, ret, nil
}
func extractVersion(v string) (*semver.Version, error) {
version, err := semver.NewVersion(v)
if err != nil {
return nil, err
}
// TODO: handle pre-release part of semver version
// additionally support kernel version flavors.
//
// Currently pre-release / flavor of the version is ignored
// that's why it's set to empty.
*version, err = version.SetPrerelease("")
if err != nil {
return nil, err
}
return version, nil
}

View file

@ -197,13 +197,14 @@ func TestEvaluateMatchExpressionValues(t *testing.T) {
type I = map[string]string
type TC struct {
name string
op nfdv1alpha1.MatchOp
values V
key string
input I
result BoolAssertionFunc
err ValueAssertionFunc
name string
op nfdv1alpha1.MatchOp
values V
valueType nfdv1alpha1.ValueType
key string
input I
result BoolAssertionFunc
err ValueAssertionFunc
}
tcs := []TC{
@ -231,45 +232,133 @@ func TestEvaluateMatchExpressionValues(t *testing.T) {
{name: "16", op: nfdv1alpha1.MatchGt, values: V{"2"}, key: "foo", input: I{"bar": "3", "foo": "2"}, result: assert.False, 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: "19", op: nfdv1alpha1.MatchGt, values: V{"2.0"}, key: "foo", input: I{"bar": "str", "foo": "3"}, result: assert.False, err: assert.NotNil},
{name: "20", op: nfdv1alpha1.MatchGt, values: V{"2"}, valueType: "", key: "foo", input: I{"bar": "3", "foo": "2"}, result: assert.False, err: assert.Nil},
{name: "21", op: nfdv1alpha1.MatchGt, values: V{"2"}, valueType: "version", key: "foo", input: I{"bar": "3"}, result: assert.False, err: assert.Nil},
{name: "22", op: nfdv1alpha1.MatchGt, values: V{"2"}, valueType: "version", key: "foo", input: I{"bar": "3", "foo": "2"}, result: assert.False, err: assert.Nil},
{name: "23", op: nfdv1alpha1.MatchGt, values: V{"2"}, valueType: "version", key: "foo", input: I{"bar": "3", "foo": "3"}, result: assert.True, err: assert.Nil},
{name: "24", op: nfdv1alpha1.MatchGt, values: V{"2.0"}, valueType: "version", key: "foo", input: I{"bar": "3", "foo": "2.0"}, result: assert.False, err: assert.Nil},
{name: "25", op: nfdv1alpha1.MatchGt, values: V{"2.0"}, valueType: "version", key: "foo", input: I{"bar": "3", "foo": "2.1"}, result: assert.True, err: assert.Nil},
{name: "26", op: nfdv1alpha1.MatchGt, values: V{"2.0.1"}, valueType: "version", key: "foo", input: I{"bar": "3", "foo": "2.0.1"}, result: assert.False, err: assert.Nil},
{name: "27", op: nfdv1alpha1.MatchGt, values: V{"2.0.1"}, valueType: "version", key: "foo", input: I{"bar": "3", "foo": "2.0.2"}, result: assert.True, err: assert.Nil},
{name: "28", op: nfdv1alpha1.MatchGt, values: V{"2.0.1"}, valueType: "version", key: "foo", input: I{"bar": "str", "foo": "str"}, result: assert.False, err: assert.NotNil},
{name: "19", op: nfdv1alpha1.MatchGe, values: V{"2"}, key: "foo", input: I{"bar": "3"}, 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.MatchGe, values: V{"2"}, key: "foo", input: I{"bar": "3", "foo": "3"}, result: assert.True, err: assert.Nil},
{name: "22", op: nfdv1alpha1.MatchGe, values: V{"2"}, key: "foo", input: I{"bar": "str", "foo": "str"}, result: assert.False, err: assert.NotNil},
{name: "29", op: nfdv1alpha1.MatchGe, values: V{"2"}, key: "foo", input: I{"bar": "3"}, result: assert.False, err: assert.Nil},
{name: "30", op: nfdv1alpha1.MatchGe, values: V{"2"}, key: "foo", input: I{"bar": "3", "foo": "2"}, result: assert.True, err: assert.Nil},
{name: "31", op: nfdv1alpha1.MatchGe, values: V{"2"}, key: "foo", input: I{"bar": "3", "foo": "3"}, result: assert.True, err: assert.Nil},
{name: "32", op: nfdv1alpha1.MatchGe, values: V{"2"}, key: "foo", input: I{"bar": "str", "foo": "str"}, result: assert.False, err: assert.NotNil},
{name: "33", op: nfdv1alpha1.MatchGe, values: V{"2.0"}, key: "foo", input: I{"bar": "3", "foo": "3"}, result: assert.False, err: assert.NotNil},
{name: "34", op: nfdv1alpha1.MatchGe, values: V{"2"}, valueType: "", key: "foo", input: I{"bar": "3", "foo": "2"}, result: assert.True, err: assert.Nil},
{name: "35", op: nfdv1alpha1.MatchGe, values: V{"2"}, valueType: "version", key: "foo", input: I{"bar": "3"}, result: assert.False, err: assert.Nil},
{name: "36", op: nfdv1alpha1.MatchGe, values: V{"2"}, valueType: "version", key: "foo", input: I{"bar": "3", "foo": "2"}, result: assert.True, err: assert.Nil},
{name: "37", op: nfdv1alpha1.MatchGe, values: V{"2"}, valueType: "version", key: "foo", input: I{"bar": "3", "foo": "3"}, result: assert.True, err: assert.Nil},
{name: "38", op: nfdv1alpha1.MatchGe, values: V{"2"}, valueType: "version", key: "foo", input: I{"bar": "3", "foo": "1"}, result: assert.False, err: assert.Nil},
{name: "39", op: nfdv1alpha1.MatchGe, values: V{"2.0"}, valueType: "version", key: "foo", input: I{"bar": "3"}, result: assert.False, err: assert.Nil},
{name: "40", op: nfdv1alpha1.MatchGe, values: V{"2.0"}, valueType: "version", key: "foo", input: I{"bar": "3", "foo": "2.0"}, result: assert.True, err: assert.Nil},
{name: "41", op: nfdv1alpha1.MatchGe, values: V{"2.0"}, valueType: "version", key: "foo", input: I{"bar": "3", "foo": "2.1"}, result: assert.True, err: assert.Nil},
{name: "42", op: nfdv1alpha1.MatchGe, values: V{"2.0"}, valueType: "version", key: "foo", input: I{"bar": "3", "foo": "1.9"}, result: assert.False, err: assert.Nil},
{name: "43", op: nfdv1alpha1.MatchGe, values: V{"2.0.1"}, valueType: "version", key: "foo", input: I{"bar": "3"}, result: assert.False, err: assert.Nil},
{name: "44", op: nfdv1alpha1.MatchGe, values: V{"2.0.1"}, valueType: "version", key: "foo", input: I{"bar": "3", "foo": "2.0.1"}, result: assert.True, err: assert.Nil},
{name: "45", op: nfdv1alpha1.MatchGe, values: V{"2.0.1"}, valueType: "version", key: "foo", input: I{"bar": "3", "foo": "2.0.2"}, result: assert.True, err: assert.Nil},
{name: "46", op: nfdv1alpha1.MatchGe, values: V{"2.0.1"}, valueType: "version", key: "foo", input: I{"bar": "3", "foo": "2.0.0"}, result: assert.False, err: assert.Nil},
{name: "47", op: nfdv1alpha1.MatchGe, values: V{"2.0.1"}, valueType: "version", key: "foo", input: I{"bar": "str", "foo": "str"}, result: assert.False, err: assert.NotNil},
{name: "23", op: nfdv1alpha1.MatchLt, values: V{"2"}, key: "foo", input: I{"bar": "1"}, 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.MatchLt, values: V{"2"}, 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: "48", op: nfdv1alpha1.MatchLt, values: V{"2"}, key: "foo", input: I{"bar": "1"}, result: assert.False, err: assert.Nil},
{name: "49", op: nfdv1alpha1.MatchLt, values: V{"2"}, key: "foo", input: I{"bar": "1", "foo": "2"}, result: assert.False, err: assert.Nil},
{name: "50", op: nfdv1alpha1.MatchLt, values: V{"2"}, key: "foo", input: I{"bar": "1", "foo": "1"}, result: assert.True, err: assert.Nil},
{name: "51", op: nfdv1alpha1.MatchLt, values: V{"2"}, key: "foo", input: I{"bar": "str", "foo": "str"}, result: assert.False, err: assert.NotNil},
{name: "52", op: nfdv1alpha1.MatchLt, values: V{"2.0"}, key: "foo", input: I{"bar": "str", "foo": "1"}, result: assert.False, err: assert.NotNil},
{name: "53", op: nfdv1alpha1.MatchLt, values: V{"2"}, valueType: "", key: "foo", input: I{"bar": "1", "foo": "2"}, result: assert.False, err: assert.Nil},
{name: "54", op: nfdv1alpha1.MatchLt, values: V{"2"}, valueType: "version", key: "foo", input: I{"bar": "1"}, result: assert.False, err: assert.Nil},
{name: "55", op: nfdv1alpha1.MatchLt, values: V{"2"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "2"}, result: assert.False, err: assert.Nil},
{name: "56", op: nfdv1alpha1.MatchLt, values: V{"2"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "1"}, result: assert.True, err: assert.Nil},
{name: "57", op: nfdv1alpha1.MatchLt, values: V{"2.0"}, valueType: "version", key: "foo", input: I{"bar": "1"}, result: assert.False, err: assert.Nil},
{name: "58", op: nfdv1alpha1.MatchLt, values: V{"2.0"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "2.0"}, result: assert.False, err: assert.Nil},
{name: "59", op: nfdv1alpha1.MatchLt, values: V{"2.0"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "1.9"}, result: assert.True, err: assert.Nil},
{name: "60", op: nfdv1alpha1.MatchLt, values: V{"2.0.1"}, valueType: "version", key: "foo", input: I{"bar": "1"}, result: assert.False, err: assert.Nil},
{name: "61", op: nfdv1alpha1.MatchLt, values: V{"2.0.1"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "2.0.1"}, result: assert.False, err: assert.Nil},
{name: "62", op: nfdv1alpha1.MatchLt, values: V{"2.0.1"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "2.0.0"}, result: assert.True, err: assert.Nil},
{name: "63", op: nfdv1alpha1.MatchLt, values: V{"2.0.1"}, valueType: "version", key: "foo", input: I{"bar": "str", "foo": "str"}, result: assert.False, err: assert.NotNil},
{name: "27", op: nfdv1alpha1.MatchLe, values: V{"2"}, key: "foo", input: I{"bar": "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: "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: "64", op: nfdv1alpha1.MatchLe, values: V{"2"}, key: "foo", input: I{"bar": "1"}, result: assert.False, err: assert.Nil},
{name: "65", op: nfdv1alpha1.MatchLe, values: V{"2"}, key: "foo", input: I{"bar": "1", "foo": "2"}, result: assert.True, err: assert.Nil},
{name: "66", op: nfdv1alpha1.MatchLe, values: V{"2"}, key: "foo", input: I{"bar": "1", "foo": "1"}, result: assert.True, err: assert.Nil},
{name: "67", op: nfdv1alpha1.MatchLe, values: V{"2"}, key: "foo", input: I{"bar": "str", "foo": "str"}, result: assert.False, err: assert.NotNil},
{name: "68", op: nfdv1alpha1.MatchLe, values: V{"2"}, key: "foo", input: I{"bar": "1", "foo": "1.0"}, result: assert.False, err: assert.NotNil},
{name: "69", op: nfdv1alpha1.MatchLe, values: V{"2"}, valueType: "", key: "foo", input: I{"bar": "1", "foo": "2"}, result: assert.True, err: assert.Nil},
{name: "70", op: nfdv1alpha1.MatchLe, values: V{"2"}, valueType: "version", key: "foo", input: I{"bar": "1"}, result: assert.False, err: assert.Nil},
{name: "71", op: nfdv1alpha1.MatchLe, values: V{"2"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "2"}, result: assert.True, err: assert.Nil},
{name: "72", op: nfdv1alpha1.MatchLe, values: V{"2"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "1"}, result: assert.True, err: assert.Nil},
{name: "73", op: nfdv1alpha1.MatchLe, values: V{"2"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "3"}, result: assert.False, err: assert.Nil},
{name: "74", op: nfdv1alpha1.MatchLe, values: V{"2.0"}, valueType: "version", key: "foo", input: I{"bar": "1.0"}, result: assert.False, err: assert.Nil},
{name: "75", op: nfdv1alpha1.MatchLe, values: V{"2.0"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "2.0"}, result: assert.True, err: assert.Nil},
{name: "76", op: nfdv1alpha1.MatchLe, values: V{"2.0"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "1.0"}, result: assert.True, err: assert.Nil},
{name: "77", op: nfdv1alpha1.MatchLe, values: V{"2.0"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "2.1"}, result: assert.False, err: assert.Nil},
{name: "78", op: nfdv1alpha1.MatchLe, values: V{"2.0.1"}, valueType: "version", key: "foo", input: I{"bar": "1.0"}, result: assert.False, err: assert.Nil},
{name: "79", op: nfdv1alpha1.MatchLe, values: V{"2.0.1"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "2.0.1"}, result: assert.True, err: assert.Nil},
{name: "80", op: nfdv1alpha1.MatchLe, values: V{"2.0.1"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "2.0.0"}, result: assert.True, err: assert.Nil},
{name: "81", op: nfdv1alpha1.MatchLe, values: V{"2.0.1"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "2.0.2"}, result: assert.False, err: assert.Nil},
{name: "82", op: nfdv1alpha1.MatchLe, values: V{"2.0.1"}, valueType: "version", key: "foo", input: I{"bar": "str", "foo": "str"}, result: assert.False, err: assert.NotNil},
{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.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: "83", op: nfdv1alpha1.MatchGtLt, values: V{"-10", "10"}, key: "foo", input: I{"bar": "1"}, result: assert.False, err: assert.Nil},
{name: "84", op: nfdv1alpha1.MatchGtLt, values: V{"-10", "10"}, key: "foo", input: I{"bar": "1", "foo": "11"}, result: assert.False, err: assert.Nil},
{name: "85", op: nfdv1alpha1.MatchGtLt, values: V{"-10", "10"}, key: "foo", input: I{"bar": "1", "foo": "-11"}, result: assert.False, err: assert.Nil},
{name: "86", op: nfdv1alpha1.MatchGtLt, values: V{"-10", "10"}, key: "foo", input: I{"bar": "1", "foo": "1"}, result: assert.True, err: assert.Nil},
{name: "87", op: nfdv1alpha1.MatchGtLt, values: V{"-10", "10"}, key: "foo", input: I{"bar": "str", "foo": "str"}, result: assert.False, err: assert.NotNil},
{name: "88", op: nfdv1alpha1.MatchGtLt, values: V{"-10", "10"}, key: "foo", input: I{"bar": "str", "foo": "5.0"}, result: assert.False, err: assert.NotNil},
{name: "89", op: nfdv1alpha1.MatchGtLt, values: V{"-10", "10"}, valueType: "", key: "foo", input: I{"bar": "1", "foo": "11"}, result: assert.False, err: assert.Nil},
{name: "90", op: nfdv1alpha1.MatchGtLt, values: V{"1", "10"}, valueType: "version", key: "foo", input: I{"bar": "1"}, result: assert.False, err: assert.Nil},
{name: "91", op: nfdv1alpha1.MatchGtLt, values: V{"1", "10"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "11"}, result: assert.False, err: assert.Nil},
{name: "92", op: nfdv1alpha1.MatchGtLt, values: V{"1", "10"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "1"}, result: assert.False, err: assert.Nil},
{name: "93", op: nfdv1alpha1.MatchGtLt, values: V{"1", "10"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "2"}, result: assert.True, err: assert.Nil},
{name: "94", op: nfdv1alpha1.MatchGtLt, values: V{"1", "10"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "0"}, result: assert.False, err: assert.Nil},
{name: "95", op: nfdv1alpha1.MatchGtLt, values: V{"1.0", "10.0"}, valueType: "version", key: "foo", input: I{"bar": "1.1"}, result: assert.False, err: assert.Nil},
{name: "96", op: nfdv1alpha1.MatchGtLt, values: V{"1.0", "10.0"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "10.1"}, result: assert.False, err: assert.Nil},
{name: "97", op: nfdv1alpha1.MatchGtLt, values: V{"1.0", "10.0"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "1.0"}, result: assert.False, err: assert.Nil},
{name: "98", op: nfdv1alpha1.MatchGtLt, values: V{"1.0", "10.0"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "1.1"}, result: assert.True, err: assert.Nil},
{name: "99", op: nfdv1alpha1.MatchGtLt, values: V{"1.0", "10.0"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "0.9"}, result: assert.False, err: assert.Nil},
{name: "100", op: nfdv1alpha1.MatchGtLt, values: V{"1.0.1", "10.0.1"}, valueType: "version", key: "foo", input: I{"bar": "1.1"}, result: assert.False, err: assert.Nil},
{name: "101", op: nfdv1alpha1.MatchGtLt, values: V{"1.0.1", "10.0.1"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "10.0.1"}, result: assert.False, err: assert.Nil},
{name: "102", op: nfdv1alpha1.MatchGtLt, values: V{"1.0.1", "10.0.1"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "1.0.1"}, result: assert.False, err: assert.Nil},
{name: "103", op: nfdv1alpha1.MatchGtLt, values: V{"1.0.1", "10.0.1"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "1.0.2"}, result: assert.True, err: assert.Nil},
{name: "104", op: nfdv1alpha1.MatchGtLt, values: V{"1.0.1", "10.0.1"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "0.0.9"}, result: assert.False, err: assert.Nil},
{name: "105", op: nfdv1alpha1.MatchGtLt, values: V{"1.0.1", "10.0.1"}, 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: "106", op: nfdv1alpha1.MatchGeLe, values: V{"-10", "10"}, key: "foo", input: I{"bar": "1"}, result: assert.False, err: assert.Nil},
{name: "107", op: nfdv1alpha1.MatchGeLe, values: V{"-10", "10"}, key: "foo", input: I{"bar": "-10", "foo": "10"}, result: assert.True, err: assert.Nil},
{name: "108", op: nfdv1alpha1.MatchGeLe, values: V{"-10", "10"}, key: "foo", input: I{"bar": "1", "foo": "-11"}, result: assert.False, err: assert.Nil},
{name: "109", op: nfdv1alpha1.MatchGeLe, values: V{"-10", "10"}, key: "foo", input: I{"bar": "1", "foo": "1"}, result: assert.True, err: assert.Nil},
{name: "110", op: nfdv1alpha1.MatchGeLe, values: V{"-10", "10"}, key: "foo", input: I{"bar": "str", "foo": "str"}, result: assert.False, err: assert.NotNil},
{name: "111", op: nfdv1alpha1.MatchGeLe, values: V{"-10", "10"}, key: "foo", input: I{"bar": "1", "foo": "1.0"}, result: assert.False, err: assert.NotNil},
{name: "112", op: nfdv1alpha1.MatchGeLe, values: V{"-10", "10"}, valueType: "", key: "foo", input: I{"bar": "-10", "foo": "10"}, result: assert.True, err: assert.Nil},
{name: "113", op: nfdv1alpha1.MatchGeLe, values: V{"1", "10"}, valueType: "version", key: "foo", input: I{"bar": "1"}, result: assert.False, err: assert.Nil},
{name: "114", op: nfdv1alpha1.MatchGeLe, values: V{"1", "10"}, valueType: "version", key: "foo", input: I{"bar": "-10", "foo": "10"}, result: assert.True, err: assert.Nil},
{name: "115", op: nfdv1alpha1.MatchGeLe, values: V{"1", "10"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "-11"}, result: assert.False, err: assert.NotNil},
{name: "116", op: nfdv1alpha1.MatchGeLe, values: V{"1", "10"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "1"}, result: assert.True, err: assert.Nil},
{name: "117", op: nfdv1alpha1.MatchGeLe, values: V{"1", "10"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "0"}, result: assert.False, err: assert.Nil},
{name: "118", op: nfdv1alpha1.MatchGeLe, values: V{"1.0", "10.0"}, valueType: "version", key: "foo", input: I{"bar": "1"}, result: assert.False, err: assert.Nil},
{name: "119", op: nfdv1alpha1.MatchGeLe, values: V{"1.0", "10.0"}, valueType: "version", key: "foo", input: I{"bar": "-10", "foo": "10.0"}, result: assert.True, err: assert.Nil},
{name: "120", op: nfdv1alpha1.MatchGeLe, values: V{"1.0", "10.0"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "10.1"}, result: assert.False, err: assert.Nil},
{name: "121", op: nfdv1alpha1.MatchGeLe, values: V{"1.0", "10.0"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "1.1"}, result: assert.True, err: assert.Nil},
{name: "122", op: nfdv1alpha1.MatchGeLe, values: V{"1.0", "10.0"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "0.9"}, result: assert.False, err: assert.Nil},
{name: "123", op: nfdv1alpha1.MatchGeLe, values: V{"1.0.1", "10.0.1"}, valueType: "version", key: "foo", input: I{"bar": "1"}, result: assert.False, err: assert.Nil},
{name: "124", op: nfdv1alpha1.MatchGeLe, values: V{"1.0.1", "10.0.1"}, valueType: "version", key: "foo", input: I{"bar": "-10", "foo": "10.0.1"}, result: assert.True, err: assert.Nil},
{name: "125", op: nfdv1alpha1.MatchGeLe, values: V{"1.0.1", "10.0.1"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "10.0.2"}, result: assert.False, err: assert.Nil},
{name: "126", op: nfdv1alpha1.MatchGeLe, values: V{"1.0.1", "10.0.1"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "1.0.2"}, result: assert.True, err: assert.Nil},
{name: "127", op: nfdv1alpha1.MatchGeLe, values: V{"1.0.1", "10.0.1"}, valueType: "version", key: "foo", input: I{"bar": "1", "foo": "0.0.9"}, result: assert.False, err: assert.Nil},
{name: "128", op: nfdv1alpha1.MatchGeLe, values: V{"1.0.1", "10.0.1"}, valueType: "version", 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: "129", op: nfdv1alpha1.MatchIsTrue, key: "foo", result: assert.False, err: assert.Nil},
{name: "130", op: nfdv1alpha1.MatchIsTrue, key: "foo", input: I{"foo": "1"}, result: assert.False, err: assert.Nil},
{name: "131", 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},
{name: "132", op: nfdv1alpha1.MatchIsFalse, key: "foo", input: I{"foo": "true"}, result: assert.False, err: assert.Nil},
{name: "133", op: nfdv1alpha1.MatchIsFalse, key: "foo", input: I{"foo": "false"}, result: assert.True, err: assert.Nil},
}
for _, tc := range tcs {
t.Run(tc.name, func(t *testing.T) {
me := &nfdv1alpha1.MatchExpression{Op: tc.op, Value: tc.values}
me := &nfdv1alpha1.MatchExpression{Op: tc.op, Value: tc.values, Type: tc.valueType}
res, err := evaluateMatchExpressionValues(me, tc.key, tc.input)
tc.result(t, res)
tc.err(t, err)