mirror of
https://github.com/kubernetes-sigs/node-feature-discovery.git
synced 2025-03-05 08:17:04 +00:00
source/custom: move rule expressions to pkg/apis/nfd/v1alpha1
Create a new package pkg/apis/nfd/v1alpha1 and migrate the custom rule expressions over there. This is the first step in creating a new CRD API for custom rules.
This commit is contained in:
parent
389ff52ede
commit
0757248055
13 changed files with 567 additions and 546 deletions
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package expression
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
@ -29,80 +29,6 @@ import (
|
|||
"sigs.k8s.io/node-feature-discovery/pkg/api/feature"
|
||||
)
|
||||
|
||||
// MatchExpressionSet contains a set of MatchExpressions, each of which is
|
||||
// evaluated against a set of input values.
|
||||
type MatchExpressionSet map[string]*MatchExpression
|
||||
|
||||
// MatchExpression specifies an expression to evaluate against a set of input
|
||||
// values. It contains an operator that is applied when matching the input and
|
||||
// an array of values that the operator evaluates the input against.
|
||||
// NB: CreateMatchExpression or MustCreateMatchExpression() should be used for
|
||||
// creating new instances.
|
||||
// NB: Validate() must be called if Op or Value fields are modified or if a new
|
||||
// instance is created from scratch without using the helper functions.
|
||||
type MatchExpression struct {
|
||||
// Op is the operator to be applied.
|
||||
Op MatchOp
|
||||
|
||||
// Value is the list of values that the operand evaluates the input
|
||||
// against. Value should be empty if the operator is Exists, DoesNotExist,
|
||||
// IsTrue or IsFalse. Value should contain exactly one element if the
|
||||
// operator is Gt or Lt and exactly two elements if the operator is GtLt.
|
||||
// In other cases Value should contain at least one element.
|
||||
Value MatchValue `json:",omitempty"`
|
||||
|
||||
// valueRe caches compiled regexps for "InRegexp" operator
|
||||
valueRe []*regexp.Regexp
|
||||
}
|
||||
|
||||
// MatchOp is the match operator that is applied on values when evaluating a
|
||||
// MatchExpression.
|
||||
type MatchOp string
|
||||
|
||||
// MatchValue is the list of values associated with a MatchExpression.
|
||||
type MatchValue []string
|
||||
|
||||
const (
|
||||
// MatchAny returns always true.
|
||||
MatchAny MatchOp = ""
|
||||
// MatchIn returns true if any of the values stored in the expression is
|
||||
// equal to the input.
|
||||
MatchIn MatchOp = "In"
|
||||
// MatchIn returns true if none of the values in the expression are equal
|
||||
// to the input.
|
||||
MatchNotIn MatchOp = "NotIn"
|
||||
// MatchInRegexp treats values of the expression as regular expressions and
|
||||
// returns true if any of them matches the input.
|
||||
MatchInRegexp MatchOp = "InRegexp"
|
||||
// MatchExists returns true if the input is valid. The expression must not
|
||||
// have any values.
|
||||
MatchExists MatchOp = "Exists"
|
||||
// MatchDoesNotExist returns true if the input is not valid. The expression
|
||||
// must not have any values.
|
||||
MatchDoesNotExist MatchOp = "DoesNotExist"
|
||||
// MatchGt returns true if the input is greater than 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.
|
||||
MatchGt MatchOp = "Gt"
|
||||
// MatchLt returns true if the input is less than 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.
|
||||
MatchLt MatchOp = "Lt"
|
||||
// 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
|
||||
// (number of values in the expression must be exactly two). Both the input
|
||||
// and values must be integer numbers, otherwise an error is returned.
|
||||
MatchGtLt MatchOp = "GtLt"
|
||||
// MatchIsTrue returns true if the input holds the value "true". The
|
||||
// expression must not have any values.
|
||||
MatchIsTrue MatchOp = "IsTrue"
|
||||
// MatchIsTrue returns true if the input holds the value "false". The
|
||||
// expression must not have any values.
|
||||
MatchIsFalse MatchOp = "IsFalse"
|
||||
)
|
||||
|
||||
var matchOps = map[MatchOp]struct{}{
|
||||
MatchAny: struct{}{},
|
||||
MatchIn: struct{}{},
|
439
pkg/apis/nfd/v1alpha1/expression_test.go
Normal file
439
pkg/apis/nfd/v1alpha1/expression_test.go
Normal file
|
@ -0,0 +1,439 @@
|
|||
/*
|
||||
Copyright 2021 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1alpha1_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"sigs.k8s.io/node-feature-discovery/pkg/api/feature"
|
||||
api "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
|
||||
)
|
||||
|
||||
type BoolAssertionFuncf func(assert.TestingT, bool, string, ...interface{}) bool
|
||||
|
||||
type ValueAssertionFuncf func(assert.TestingT, interface{}, string, ...interface{}) bool
|
||||
|
||||
func TestCreateMatchExpression(t *testing.T) {
|
||||
type V = api.MatchValue
|
||||
type TC struct {
|
||||
op api.MatchOp
|
||||
values V
|
||||
err ValueAssertionFuncf
|
||||
}
|
||||
|
||||
tcs := []TC{
|
||||
{op: api.MatchAny, err: assert.Nilf}, // #0
|
||||
{op: api.MatchAny, values: V{"1"}, err: assert.NotNilf},
|
||||
|
||||
{op: api.MatchIn, err: assert.NotNilf},
|
||||
{op: api.MatchIn, values: V{"1"}, err: assert.Nilf},
|
||||
{op: api.MatchIn, values: V{"1", "2", "3", "4"}, err: assert.Nilf},
|
||||
|
||||
{op: api.MatchNotIn, err: assert.NotNilf},
|
||||
{op: api.MatchNotIn, values: V{"1"}, err: assert.Nilf},
|
||||
{op: api.MatchNotIn, values: V{"1", "2"}, err: assert.Nilf},
|
||||
|
||||
{op: api.MatchInRegexp, err: assert.NotNilf},
|
||||
{op: api.MatchInRegexp, values: V{"1"}, err: assert.Nilf},
|
||||
{op: api.MatchInRegexp, values: V{"()", "2", "3"}, err: assert.Nilf},
|
||||
{op: api.MatchInRegexp, values: V{"("}, err: assert.NotNilf},
|
||||
|
||||
{op: api.MatchExists, err: assert.Nilf},
|
||||
{op: api.MatchExists, values: V{"1"}, err: assert.NotNilf},
|
||||
|
||||
{op: api.MatchDoesNotExist, err: assert.Nilf},
|
||||
{op: api.MatchDoesNotExist, values: V{"1"}, err: assert.NotNilf},
|
||||
|
||||
{op: api.MatchGt, err: assert.NotNilf},
|
||||
{op: api.MatchGt, values: V{"1"}, err: assert.Nilf},
|
||||
{op: api.MatchGt, values: V{"-10"}, err: assert.Nilf},
|
||||
{op: api.MatchGt, values: V{"1", "2"}, err: assert.NotNilf},
|
||||
{op: api.MatchGt, values: V{""}, err: assert.NotNilf},
|
||||
|
||||
{op: api.MatchLt, err: assert.NotNilf},
|
||||
{op: api.MatchLt, values: V{"1"}, err: assert.Nilf},
|
||||
{op: api.MatchLt, values: V{"-1"}, err: assert.Nilf},
|
||||
{op: api.MatchLt, values: V{"1", "2", "3"}, err: assert.NotNilf},
|
||||
{op: api.MatchLt, values: V{"a"}, err: assert.NotNilf},
|
||||
|
||||
{op: api.MatchGtLt, err: assert.NotNilf},
|
||||
{op: api.MatchGtLt, values: V{"1"}, err: assert.NotNilf},
|
||||
{op: api.MatchGtLt, values: V{"1", "2"}, err: assert.Nilf},
|
||||
{op: api.MatchGtLt, values: V{"2", "1"}, err: assert.NotNilf},
|
||||
{op: api.MatchGtLt, values: V{"1", "2", "3"}, err: assert.NotNilf},
|
||||
{op: api.MatchGtLt, values: V{"a", "2"}, err: assert.NotNilf},
|
||||
|
||||
{op: api.MatchIsTrue, err: assert.Nilf},
|
||||
{op: api.MatchIsTrue, values: V{"1"}, err: assert.NotNilf},
|
||||
|
||||
{op: api.MatchIsFalse, err: assert.Nilf},
|
||||
{op: api.MatchIsFalse, values: V{"1", "2"}, err: assert.NotNilf},
|
||||
}
|
||||
|
||||
for i, tc := range tcs {
|
||||
_, err := api.CreateMatchExpression(tc.op, tc.values...)
|
||||
tc.err(t, err, "test case #%d (%v) failed", i, tc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatch(t *testing.T) {
|
||||
type V = api.MatchValue
|
||||
type TC struct {
|
||||
op api.MatchOp
|
||||
values V
|
||||
input interface{}
|
||||
valid bool
|
||||
result BoolAssertionFuncf
|
||||
err ValueAssertionFuncf
|
||||
}
|
||||
|
||||
tcs := []TC{
|
||||
{op: api.MatchAny, result: assert.Truef, err: assert.Nilf},
|
||||
{op: api.MatchAny, input: "2", valid: false, result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{op: api.MatchIn, values: V{"1"}, input: "2", valid: false, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchIn, values: V{"1"}, input: "2", valid: true, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchIn, values: V{"1", "2", "3"}, input: "2", valid: false, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchIn, values: V{"1", "2", "3"}, input: "2", valid: true, result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{op: api.MatchNotIn, values: V{"2"}, input: 2, valid: false, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchNotIn, values: V{"1"}, input: 2, valid: true, result: assert.Truef, err: assert.Nilf},
|
||||
{op: api.MatchNotIn, values: V{"1", "2", "3"}, input: "2", valid: false, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchNotIn, values: V{"1", "2", "3"}, input: "2", valid: true, result: assert.Falsef, err: assert.Nilf},
|
||||
|
||||
{op: api.MatchInRegexp, values: V{"val-[0-9]$"}, input: "val-1", valid: false, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchInRegexp, values: V{"val-[0-9]$"}, input: "val-1", valid: true, result: assert.Truef, err: assert.Nilf},
|
||||
{op: api.MatchInRegexp, values: V{"val-[0-9]$"}, input: "val-12", valid: true, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchInRegexp, values: V{"val-[0-9]$", "al-[1-9]"}, input: "val-12", valid: true, result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{op: api.MatchExists, input: nil, valid: false, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchExists, input: nil, valid: true, result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{op: api.MatchDoesNotExist, input: false, valid: false, result: assert.Truef, err: assert.Nilf},
|
||||
{op: api.MatchDoesNotExist, input: false, valid: true, result: assert.Falsef, err: assert.Nilf},
|
||||
|
||||
{op: api.MatchGt, values: V{"2"}, input: 3, valid: false, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchGt, values: V{"2"}, input: 2, valid: true, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchGt, values: V{"2"}, input: 3, valid: true, result: assert.Truef, err: assert.Nilf},
|
||||
{op: api.MatchGt, values: V{"-10"}, input: -3, valid: true, result: assert.Truef, err: assert.Nilf},
|
||||
{op: api.MatchGt, values: V{"2"}, input: "3a", valid: true, result: assert.Falsef, err: assert.NotNilf},
|
||||
|
||||
{op: api.MatchLt, values: V{"2"}, input: "1", valid: false, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchLt, values: V{"2"}, input: "2", valid: true, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchLt, values: V{"-10"}, input: -3, valid: true, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchLt, values: V{"2"}, input: "1", valid: true, result: assert.Truef, err: assert.Nilf},
|
||||
{op: api.MatchLt, values: V{"2"}, input: "1.0", valid: true, result: assert.Falsef, err: assert.NotNilf},
|
||||
|
||||
{op: api.MatchGtLt, values: V{"1", "10"}, input: "1", valid: false, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchGtLt, values: V{"1", "10"}, input: "1", valid: true, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchGtLt, values: V{"1", "10"}, input: "10", valid: true, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchGtLt, values: V{"1", "10"}, input: "2", valid: true, result: assert.Truef, err: assert.Nilf},
|
||||
{op: api.MatchGtLt, values: V{"1", "10"}, input: "1.0", valid: true, result: assert.Falsef, err: assert.NotNilf},
|
||||
|
||||
{op: api.MatchIsTrue, input: true, valid: false, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchIsTrue, input: true, valid: true, result: assert.Truef, err: assert.Nilf},
|
||||
{op: api.MatchIsTrue, input: false, valid: true, result: assert.Falsef, err: assert.Nilf},
|
||||
|
||||
{op: api.MatchIsFalse, input: "false", valid: false, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchIsFalse, input: "false", valid: true, result: assert.Truef, err: assert.Nilf},
|
||||
{op: api.MatchIsFalse, input: "true", valid: true, result: assert.Falsef, err: assert.Nilf},
|
||||
}
|
||||
|
||||
for i, tc := range tcs {
|
||||
me := api.MustCreateMatchExpression(tc.op, tc.values...)
|
||||
res, err := me.Match(tc.valid, tc.input)
|
||||
tc.result(t, res, "test case #%d (%v) failed", i, tc)
|
||||
tc.err(t, err, "test case #%d (%v) failed", i, tc)
|
||||
}
|
||||
|
||||
// Check some special error cases separately because MustCreateMatch panics
|
||||
tcs = []TC{
|
||||
|
||||
{op: api.MatchGt, values: V{"3.0"}, input: 1, valid: true},
|
||||
{op: api.MatchLt, values: V{"0x2"}, input: 1, valid: true},
|
||||
{op: api.MatchGtLt, values: V{"1", "str"}, input: 1, valid: true},
|
||||
{op: "non-existent-op", values: V{"1"}, input: 1, valid: true},
|
||||
}
|
||||
|
||||
for i, tc := range tcs {
|
||||
me := api.MatchExpression{Op: tc.op, Value: tc.values}
|
||||
res, err := me.Match(tc.valid, tc.input)
|
||||
assert.Falsef(t, res, "err test case #%d (%v) failed", i, tc)
|
||||
assert.NotNilf(t, err, "err test case #%d (%v) failed", i, tc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatchKeys(t *testing.T) {
|
||||
type V = api.MatchValue
|
||||
type I = map[string]feature.Nil
|
||||
type TC struct {
|
||||
op api.MatchOp
|
||||
values V
|
||||
name string
|
||||
input I
|
||||
result BoolAssertionFuncf
|
||||
err ValueAssertionFuncf
|
||||
}
|
||||
|
||||
tcs := []TC{
|
||||
{op: api.MatchAny, result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{op: api.MatchExists, name: "foo", input: nil, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchExists, name: "foo", input: I{"bar": {}}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchExists, name: "foo", input: I{"bar": {}, "foo": {}}, result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{op: api.MatchDoesNotExist, name: "foo", input: nil, result: assert.Truef, err: assert.Nilf},
|
||||
{op: api.MatchDoesNotExist, name: "foo", input: I{}, result: assert.Truef, err: assert.Nilf},
|
||||
{op: api.MatchDoesNotExist, name: "foo", input: I{"bar": {}}, result: assert.Truef, err: assert.Nilf},
|
||||
{op: api.MatchDoesNotExist, name: "foo", input: I{"bar": {}, "foo": {}}, result: assert.Falsef, err: assert.Nilf},
|
||||
|
||||
// All other ops should return an error
|
||||
{op: api.MatchIn, values: V{"foo"}, name: "foo", result: assert.Falsef, err: assert.NotNilf},
|
||||
{op: api.MatchNotIn, values: V{"foo"}, name: "foo", result: assert.Falsef, err: assert.NotNilf},
|
||||
{op: api.MatchInRegexp, values: V{"foo"}, name: "foo", result: assert.Falsef, err: assert.NotNilf},
|
||||
{op: api.MatchGt, values: V{"1"}, name: "foo", result: assert.Falsef, err: assert.NotNilf},
|
||||
{op: api.MatchLt, values: V{"1"}, name: "foo", result: assert.Falsef, err: assert.NotNilf},
|
||||
{op: api.MatchGtLt, values: V{"1", "10"}, name: "foo", result: assert.Falsef, err: assert.NotNilf},
|
||||
{op: api.MatchIsTrue, name: "foo", result: assert.Falsef, err: assert.NotNilf},
|
||||
{op: api.MatchIsFalse, name: "foo", result: assert.Falsef, err: assert.NotNilf},
|
||||
}
|
||||
|
||||
for i, tc := range tcs {
|
||||
me := api.MustCreateMatchExpression(tc.op, tc.values...)
|
||||
res, err := me.MatchKeys(tc.name, tc.input)
|
||||
tc.result(t, res, "test case #%d (%v) failed", i, tc)
|
||||
tc.err(t, err, "test case #%d (%v) failed", i, tc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatchValues(t *testing.T) {
|
||||
type V = []string
|
||||
type I = map[string]string
|
||||
|
||||
type TC struct {
|
||||
op api.MatchOp
|
||||
values V
|
||||
name string
|
||||
input I
|
||||
result BoolAssertionFuncf
|
||||
err ValueAssertionFuncf
|
||||
}
|
||||
|
||||
tcs := []TC{
|
||||
{op: api.MatchAny, result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{op: api.MatchIn, values: V{"1", "2"}, name: "foo", input: I{"bar": "2"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchIn, values: V{"1", "2"}, name: "foo", input: I{"foo": "3"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchIn, values: V{"1", "2"}, name: "foo", input: I{"foo": "2"}, result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{op: api.MatchNotIn, values: V{"1", "2"}, name: "foo", input: I{"bar": "2"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchNotIn, values: V{"1", "2"}, name: "foo", input: I{"foo": "3"}, result: assert.Truef, err: assert.Nilf},
|
||||
{op: api.MatchNotIn, values: V{"1", "2"}, name: "foo", input: I{"foo": "2"}, result: assert.Falsef, err: assert.Nilf},
|
||||
|
||||
{op: api.MatchInRegexp, values: V{"1", "2"}, name: "foo", input: I{"bar": "2"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchInRegexp, values: V{"1", "[0-8]"}, name: "foo", input: I{"foo": "9"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchInRegexp, values: V{"1", "[0-8]"}, name: "foo", input: I{"foo": "2"}, result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{op: api.MatchExists, name: "foo", input: I{"bar": "1"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchExists, name: "foo", input: I{"foo": "1"}, result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{op: api.MatchDoesNotExist, name: "foo", input: nil, result: assert.Truef, err: assert.Nilf},
|
||||
{op: api.MatchDoesNotExist, name: "foo", input: I{"foo": "1"}, result: assert.Falsef, err: assert.Nilf},
|
||||
|
||||
{op: api.MatchGt, values: V{"2"}, name: "foo", input: I{"bar": "3"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchGt, values: V{"2"}, name: "foo", input: I{"bar": "3", "foo": "2"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchGt, values: V{"2"}, name: "foo", input: I{"bar": "3", "foo": "3"}, result: assert.Truef, err: assert.Nilf},
|
||||
{op: api.MatchGt, values: V{"2"}, name: "foo", input: I{"bar": "str", "foo": "str"}, result: assert.Falsef, err: assert.NotNilf},
|
||||
|
||||
{op: api.MatchLt, values: V{"2"}, name: "foo", input: I{"bar": "1"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchLt, values: V{"2"}, name: "foo", input: I{"bar": "1", "foo": "2"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchLt, values: V{"2"}, name: "foo", input: I{"bar": "1", "foo": "1"}, result: assert.Truef, err: assert.Nilf},
|
||||
{op: api.MatchLt, values: V{"2"}, name: "foo", input: I{"bar": "str", "foo": "str"}, result: assert.Falsef, err: assert.NotNilf},
|
||||
|
||||
{op: api.MatchGtLt, values: V{"-10", "10"}, name: "foo", input: I{"bar": "1"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchGtLt, values: V{"-10", "10"}, name: "foo", input: I{"bar": "1", "foo": "11"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchGtLt, values: V{"-10", "10"}, name: "foo", input: I{"bar": "1", "foo": "-11"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchGtLt, values: V{"-10", "10"}, name: "foo", input: I{"bar": "1", "foo": "1"}, result: assert.Truef, err: assert.Nilf},
|
||||
{op: api.MatchGtLt, values: V{"-10", "10"}, name: "foo", input: I{"bar": "str", "foo": "str"}, result: assert.Falsef, err: assert.NotNilf},
|
||||
|
||||
{op: api.MatchIsTrue, name: "foo", result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchIsTrue, name: "foo", input: I{"foo": "1"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchIsTrue, name: "foo", input: I{"foo": "true"}, result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{op: api.MatchIsFalse, name: "foo", input: I{"foo": "true"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: api.MatchIsFalse, name: "foo", input: I{"foo": "false"}, result: assert.Truef, err: assert.Nilf},
|
||||
}
|
||||
|
||||
for i, tc := range tcs {
|
||||
me := api.MustCreateMatchExpression(tc.op, tc.values...)
|
||||
res, err := me.MatchValues(tc.name, tc.input)
|
||||
tc.result(t, res, "test case #%d (%v) failed", i, tc)
|
||||
tc.err(t, err, "test case #%d (%v) failed", i, tc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMESMatchKeys(t *testing.T) {
|
||||
type I = map[string]feature.Nil
|
||||
type TC struct {
|
||||
mes string
|
||||
input I
|
||||
result BoolAssertionFuncf
|
||||
err ValueAssertionFuncf
|
||||
}
|
||||
|
||||
tcs := []TC{
|
||||
{result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{input: I{"foo": {}}, result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{mes: `
|
||||
foo: { op: DoesNotExist }
|
||||
bar: { op: Exists }
|
||||
`,
|
||||
input: I{"bar": {}, "baz": {}},
|
||||
result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{mes: `
|
||||
foo: { op: DoesNotExist }
|
||||
bar: { op: Exists }
|
||||
`,
|
||||
input: I{"foo": {}, "bar": {}, "baz": {}},
|
||||
result: assert.Falsef, err: assert.Nilf},
|
||||
|
||||
{mes: `
|
||||
foo: { op: In, value: ["bar"] }
|
||||
bar: { op: Exists }
|
||||
`,
|
||||
input: I{"bar": {}, "baz": {}},
|
||||
result: assert.Falsef, err: assert.NotNilf},
|
||||
}
|
||||
|
||||
for i, tc := range tcs {
|
||||
mes := &api.MatchExpressionSet{}
|
||||
if err := yaml.Unmarshal([]byte(tc.mes), mes); err != nil {
|
||||
t.Fatalf("failed to parse data of test case #%d (%v): %v", i, tc, err)
|
||||
}
|
||||
|
||||
res, err := mes.MatchKeys(tc.input)
|
||||
tc.result(t, res, "test case #%d (%v) failed", i, tc)
|
||||
tc.err(t, err, "test case #%d (%v) failed", i, tc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMESMatchValues(t *testing.T) {
|
||||
type I = map[string]string
|
||||
type TC struct {
|
||||
mes string
|
||||
input I
|
||||
result BoolAssertionFuncf
|
||||
err ValueAssertionFuncf
|
||||
}
|
||||
|
||||
tcs := []TC{
|
||||
{result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{input: I{"foo": "bar"}, result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{mes: `
|
||||
foo: { op: Exists }
|
||||
bar: { op: In, value: ["val", "wal"] }
|
||||
baz: { op: Gt, value: ["10"] }
|
||||
`,
|
||||
input: I{"bar": "val"},
|
||||
result: assert.Falsef, err: assert.Nilf},
|
||||
|
||||
{mes: `
|
||||
foo: { op: Exists }
|
||||
bar: { op: In, value: ["val", "wal"] }
|
||||
baz: { op: Gt, value: ["10"] }
|
||||
`,
|
||||
input: I{"foo": "1", "bar": "val", "baz": "123"},
|
||||
result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{mes: `
|
||||
foo: { op: Exists }
|
||||
bar: { op: In, value: ["val"] }
|
||||
baz: { op: Gt, value: ["10"] }
|
||||
`,
|
||||
input: I{"foo": "1", "bar": "val", "baz": "123.0"},
|
||||
result: assert.Falsef, err: assert.NotNilf},
|
||||
}
|
||||
|
||||
for i, tc := range tcs {
|
||||
mes := &api.MatchExpressionSet{}
|
||||
if err := yaml.Unmarshal([]byte(tc.mes), mes); err != nil {
|
||||
t.Fatalf("failed to parse data of test case #%d (%v): %v", i, tc, err)
|
||||
}
|
||||
|
||||
res, err := mes.MatchValues(tc.input)
|
||||
tc.result(t, res, "test case #%d (%v) failed", i, tc)
|
||||
tc.err(t, err, "test case #%d (%v) failed", i, tc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMESMatchInstances(t *testing.T) {
|
||||
type I = feature.InstanceFeature
|
||||
type A = map[string]string
|
||||
type TC struct {
|
||||
mes string
|
||||
input []I
|
||||
result BoolAssertionFuncf
|
||||
err ValueAssertionFuncf
|
||||
}
|
||||
|
||||
tcs := []TC{
|
||||
{result: assert.Falsef, err: assert.Nilf}, // nil instances -> false
|
||||
|
||||
{input: []I{}, result: assert.Falsef, err: assert.Nilf}, // zero instances -> false
|
||||
|
||||
{input: []I{I{Attributes: A{}}}, result: assert.Truef, err: assert.Nilf}, // one "empty" instance
|
||||
|
||||
{mes: `
|
||||
foo: { op: Exists }
|
||||
bar: { op: Lt, value: ["10"] }
|
||||
`,
|
||||
input: []I{I{Attributes: A{"foo": "1"}}, I{Attributes: A{"bar": "1"}}},
|
||||
result: assert.Falsef, err: assert.Nilf},
|
||||
|
||||
{mes: `
|
||||
foo: { op: Exists }
|
||||
bar: { op: Lt, value: ["10"] }
|
||||
`,
|
||||
input: []I{I{Attributes: A{"foo": "1"}}, I{Attributes: A{"foo": "2", "bar": "1"}}},
|
||||
result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{mes: `
|
||||
bar: { op: Lt, value: ["10"] }
|
||||
`,
|
||||
input: []I{I{Attributes: A{"foo": "1"}}, I{Attributes: A{"bar": "0x1"}}},
|
||||
result: assert.Falsef, err: assert.NotNilf},
|
||||
}
|
||||
|
||||
for i, tc := range tcs {
|
||||
mes := &api.MatchExpressionSet{}
|
||||
if err := yaml.Unmarshal([]byte(tc.mes), mes); err != nil {
|
||||
t.Fatalf("failed to parse data of test case #%d (%v): %v", i, tc, err)
|
||||
}
|
||||
|
||||
res, err := mes.MatchInstances(tc.input)
|
||||
tc.result(t, res, "test case #%d (%v) failed", i, tc)
|
||||
tc.err(t, err, "test case #%d (%v) failed", i, tc)
|
||||
}
|
||||
}
|
95
pkg/apis/nfd/v1alpha1/types.go
Normal file
95
pkg/apis/nfd/v1alpha1/types.go
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
Copyright 2021 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// MatchExpressionSet contains a set of MatchExpressions, each of which is
|
||||
// evaluated against a set of input values.
|
||||
type MatchExpressionSet map[string]*MatchExpression
|
||||
|
||||
// MatchExpression specifies an expression to evaluate against a set of input
|
||||
// values. It contains an operator that is applied when matching the input and
|
||||
// an array of values that the operator evaluates the input against.
|
||||
// NB: CreateMatchExpression or MustCreateMatchExpression() should be used for
|
||||
// creating new instances.
|
||||
// NB: Validate() must be called if Op or Value fields are modified or if a new
|
||||
// instance is created from scratch without using the helper functions.
|
||||
type MatchExpression struct {
|
||||
// Op is the operator to be applied.
|
||||
Op MatchOp
|
||||
|
||||
// Value is the list of values that the operand evaluates the input
|
||||
// against. Value should be empty if the operator is Exists, DoesNotExist,
|
||||
// IsTrue or IsFalse. Value should contain exactly one element if the
|
||||
// operator is Gt or Lt and exactly two elements if the operator is GtLt.
|
||||
// In other cases Value should contain at least one element.
|
||||
Value MatchValue `json:",omitempty"`
|
||||
|
||||
// valueRe caches compiled regexps for "InRegexp" operator
|
||||
valueRe []*regexp.Regexp
|
||||
}
|
||||
|
||||
// MatchOp is the match operator that is applied on values when evaluating a
|
||||
// MatchExpression.
|
||||
type MatchOp string
|
||||
|
||||
// MatchValue is the list of values associated with a MatchExpression.
|
||||
type MatchValue []string
|
||||
|
||||
const (
|
||||
// MatchAny returns always true.
|
||||
MatchAny MatchOp = ""
|
||||
// MatchIn returns true if any of the values stored in the expression is
|
||||
// equal to the input.
|
||||
MatchIn MatchOp = "In"
|
||||
// MatchIn returns true if none of the values in the expression are equal
|
||||
// to the input.
|
||||
MatchNotIn MatchOp = "NotIn"
|
||||
// MatchInRegexp treats values of the expression as regular expressions and
|
||||
// returns true if any of them matches the input.
|
||||
MatchInRegexp MatchOp = "InRegexp"
|
||||
// MatchExists returns true if the input is valid. The expression must not
|
||||
// have any values.
|
||||
MatchExists MatchOp = "Exists"
|
||||
// MatchDoesNotExist returns true if the input is not valid. The expression
|
||||
// must not have any values.
|
||||
MatchDoesNotExist MatchOp = "DoesNotExist"
|
||||
// MatchGt returns true if the input is greater than 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.
|
||||
MatchGt MatchOp = "Gt"
|
||||
// MatchLt returns true if the input is less than 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.
|
||||
MatchLt MatchOp = "Lt"
|
||||
// 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
|
||||
// (number of values in the expression must be exactly two). Both the input
|
||||
// and values must be integer numbers, otherwise an error is returned.
|
||||
MatchGtLt MatchOp = "GtLt"
|
||||
// MatchIsTrue returns true if the input holds the value "true". The
|
||||
// expression must not have any values.
|
||||
MatchIsTrue MatchOp = "IsTrue"
|
||||
// MatchIsTrue returns true if the input holds the value "false". The
|
||||
// expression must not have any values.
|
||||
MatchIsFalse MatchOp = "IsFalse"
|
||||
)
|
|
@ -26,9 +26,9 @@ import (
|
|||
"sigs.k8s.io/yaml"
|
||||
|
||||
"sigs.k8s.io/node-feature-discovery/pkg/api/feature"
|
||||
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
|
||||
"sigs.k8s.io/node-feature-discovery/pkg/utils"
|
||||
"sigs.k8s.io/node-feature-discovery/source"
|
||||
"sigs.k8s.io/node-feature-discovery/source/custom/expression"
|
||||
"sigs.k8s.io/node-feature-discovery/source/custom/rules"
|
||||
)
|
||||
|
||||
|
@ -65,7 +65,7 @@ type FeatureMatcher []FeatureMatcherTerm
|
|||
|
||||
type FeatureMatcherTerm struct {
|
||||
Feature string
|
||||
MatchExpressions expression.MatchExpressionSet
|
||||
MatchExpressions nfdv1alpha1.MatchExpressionSet
|
||||
}
|
||||
|
||||
type config []CustomRule
|
||||
|
|
|
@ -21,7 +21,7 @@ import (
|
|||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"sigs.k8s.io/node-feature-discovery/pkg/api/feature"
|
||||
"sigs.k8s.io/node-feature-discovery/source/custom/expression"
|
||||
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
|
||||
)
|
||||
|
||||
func TestRule(t *testing.T) {
|
||||
|
@ -32,7 +32,7 @@ func TestRule(t *testing.T) {
|
|||
MatchFeatures: FeatureMatcher{
|
||||
FeatureMatcherTerm{
|
||||
Feature: "domain-1.kf-1",
|
||||
MatchExpressions: expression.MatchExpressionSet{"key-1": expression.MustCreateMatchExpression(expression.MatchExists)},
|
||||
MatchExpressions: nfdv1alpha1.MatchExpressionSet{"key-1": nfdv1alpha1.MustCreateMatchExpression(nfdv1alpha1.MatchExists)},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ func TestRule(t *testing.T) {
|
|||
MatchFeatures: FeatureMatcher{
|
||||
FeatureMatcherTerm{
|
||||
Feature: "domain-1.vf-1",
|
||||
MatchExpressions: expression.MatchExpressionSet{"key-1": expression.MustCreateMatchExpression(expression.MatchIn, "val-1")},
|
||||
MatchExpressions: nfdv1alpha1.MatchExpressionSet{"key-1": nfdv1alpha1.MustCreateMatchExpression(nfdv1alpha1.MatchIn, "val-1")},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ func TestRule(t *testing.T) {
|
|||
MatchFeatures: FeatureMatcher{
|
||||
FeatureMatcherTerm{
|
||||
Feature: "domain-1.if-1",
|
||||
MatchExpressions: expression.MatchExpressionSet{"attr-1": expression.MustCreateMatchExpression(expression.MatchIn, "val-1")},
|
||||
MatchExpressions: nfdv1alpha1.MatchExpressionSet{"attr-1": nfdv1alpha1.MustCreateMatchExpression(nfdv1alpha1.MatchIn, "val-1")},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -133,11 +133,11 @@ func TestRule(t *testing.T) {
|
|||
MatchFeatures: FeatureMatcher{
|
||||
FeatureMatcherTerm{
|
||||
Feature: "domain-1.vf-1",
|
||||
MatchExpressions: expression.MatchExpressionSet{"key-1": expression.MustCreateMatchExpression(expression.MatchIn, "val-x")},
|
||||
MatchExpressions: nfdv1alpha1.MatchExpressionSet{"key-1": nfdv1alpha1.MustCreateMatchExpression(nfdv1alpha1.MatchIn, "val-x")},
|
||||
},
|
||||
FeatureMatcherTerm{
|
||||
Feature: "domain-1.if-1",
|
||||
MatchExpressions: expression.MatchExpressionSet{"attr-1": expression.MustCreateMatchExpression(expression.MatchIn, "val-1")},
|
||||
MatchExpressions: nfdv1alpha1.MatchExpressionSet{"attr-1": nfdv1alpha1.MustCreateMatchExpression(nfdv1alpha1.MatchIn, "val-1")},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -145,7 +145,7 @@ func TestRule(t *testing.T) {
|
|||
assert.Nilf(t, err, "unexpected error: %v", err)
|
||||
assert.Nil(t, m, "instances should not have matched")
|
||||
|
||||
r5.MatchFeatures[0].MatchExpressions["key-1"] = expression.MustCreateMatchExpression(expression.MatchIn, "val-1")
|
||||
r5.MatchFeatures[0].MatchExpressions["key-1"] = nfdv1alpha1.MustCreateMatchExpression(nfdv1alpha1.MatchIn, "val-1")
|
||||
m, err = r5.execute(f)
|
||||
assert.Nilf(t, err, "unexpected error: %v", err)
|
||||
assert.Equal(t, r5.Labels, m, "instances should have matched")
|
||||
|
@ -156,7 +156,7 @@ func TestRule(t *testing.T) {
|
|||
MatchFeatures: FeatureMatcher{
|
||||
FeatureMatcherTerm{
|
||||
Feature: "domain-1.kf-1",
|
||||
MatchExpressions: expression.MatchExpressionSet{"key-na": expression.MustCreateMatchExpression(expression.MatchExists)},
|
||||
MatchExpressions: nfdv1alpha1.MatchExpressionSet{"key-na": nfdv1alpha1.MustCreateMatchExpression(nfdv1alpha1.MatchExists)},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -170,11 +170,11 @@ func TestRule(t *testing.T) {
|
|||
MatchFeatures: FeatureMatcher{
|
||||
FeatureMatcherTerm{
|
||||
Feature: "domain-1.kf-1",
|
||||
MatchExpressions: expression.MatchExpressionSet{"key-1": expression.MustCreateMatchExpression(expression.MatchExists)},
|
||||
MatchExpressions: nfdv1alpha1.MatchExpressionSet{"key-1": nfdv1alpha1.MustCreateMatchExpression(nfdv1alpha1.MatchExists)},
|
||||
},
|
||||
},
|
||||
})
|
||||
r5.MatchFeatures[0].MatchExpressions["key-1"] = expression.MustCreateMatchExpression(expression.MatchIn, "val-1")
|
||||
r5.MatchFeatures[0].MatchExpressions["key-1"] = nfdv1alpha1.MustCreateMatchExpression(nfdv1alpha1.MatchIn, "val-1")
|
||||
m, err = r5.execute(f)
|
||||
assert.Nilf(t, err, "unexpected error: %v", err)
|
||||
assert.Equal(t, r5.Labels, m, "instances should have matched")
|
||||
|
|
|
@ -1,439 +0,0 @@
|
|||
/*
|
||||
Copyright 2021 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package expression_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"sigs.k8s.io/node-feature-discovery/pkg/api/feature"
|
||||
e "sigs.k8s.io/node-feature-discovery/source/custom/expression"
|
||||
)
|
||||
|
||||
type BoolAssertionFuncf func(assert.TestingT, bool, string, ...interface{}) bool
|
||||
|
||||
type ValueAssertionFuncf func(assert.TestingT, interface{}, string, ...interface{}) bool
|
||||
|
||||
func TestCreateMatchExpression(t *testing.T) {
|
||||
type V = e.MatchValue
|
||||
type TC struct {
|
||||
op e.MatchOp
|
||||
values V
|
||||
err ValueAssertionFuncf
|
||||
}
|
||||
|
||||
tcs := []TC{
|
||||
{op: e.MatchAny, err: assert.Nilf}, // #0
|
||||
{op: e.MatchAny, values: V{"1"}, err: assert.NotNilf},
|
||||
|
||||
{op: e.MatchIn, err: assert.NotNilf},
|
||||
{op: e.MatchIn, values: V{"1"}, err: assert.Nilf},
|
||||
{op: e.MatchIn, values: V{"1", "2", "3", "4"}, err: assert.Nilf},
|
||||
|
||||
{op: e.MatchNotIn, err: assert.NotNilf},
|
||||
{op: e.MatchNotIn, values: V{"1"}, err: assert.Nilf},
|
||||
{op: e.MatchNotIn, values: V{"1", "2"}, err: assert.Nilf},
|
||||
|
||||
{op: e.MatchInRegexp, err: assert.NotNilf},
|
||||
{op: e.MatchInRegexp, values: V{"1"}, err: assert.Nilf},
|
||||
{op: e.MatchInRegexp, values: V{"()", "2", "3"}, err: assert.Nilf},
|
||||
{op: e.MatchInRegexp, values: V{"("}, err: assert.NotNilf},
|
||||
|
||||
{op: e.MatchExists, err: assert.Nilf},
|
||||
{op: e.MatchExists, values: V{"1"}, err: assert.NotNilf},
|
||||
|
||||
{op: e.MatchDoesNotExist, err: assert.Nilf},
|
||||
{op: e.MatchDoesNotExist, values: V{"1"}, err: assert.NotNilf},
|
||||
|
||||
{op: e.MatchGt, err: assert.NotNilf},
|
||||
{op: e.MatchGt, values: V{"1"}, err: assert.Nilf},
|
||||
{op: e.MatchGt, values: V{"-10"}, err: assert.Nilf},
|
||||
{op: e.MatchGt, values: V{"1", "2"}, err: assert.NotNilf},
|
||||
{op: e.MatchGt, values: V{""}, err: assert.NotNilf},
|
||||
|
||||
{op: e.MatchLt, err: assert.NotNilf},
|
||||
{op: e.MatchLt, values: V{"1"}, err: assert.Nilf},
|
||||
{op: e.MatchLt, values: V{"-1"}, err: assert.Nilf},
|
||||
{op: e.MatchLt, values: V{"1", "2", "3"}, err: assert.NotNilf},
|
||||
{op: e.MatchLt, values: V{"a"}, err: assert.NotNilf},
|
||||
|
||||
{op: e.MatchGtLt, err: assert.NotNilf},
|
||||
{op: e.MatchGtLt, values: V{"1"}, err: assert.NotNilf},
|
||||
{op: e.MatchGtLt, values: V{"1", "2"}, err: assert.Nilf},
|
||||
{op: e.MatchGtLt, values: V{"2", "1"}, err: assert.NotNilf},
|
||||
{op: e.MatchGtLt, values: V{"1", "2", "3"}, err: assert.NotNilf},
|
||||
{op: e.MatchGtLt, values: V{"a", "2"}, err: assert.NotNilf},
|
||||
|
||||
{op: e.MatchIsTrue, err: assert.Nilf},
|
||||
{op: e.MatchIsTrue, values: V{"1"}, err: assert.NotNilf},
|
||||
|
||||
{op: e.MatchIsFalse, err: assert.Nilf},
|
||||
{op: e.MatchIsFalse, values: V{"1", "2"}, err: assert.NotNilf},
|
||||
}
|
||||
|
||||
for i, tc := range tcs {
|
||||
_, err := e.CreateMatchExpression(tc.op, tc.values...)
|
||||
tc.err(t, err, "test case #%d (%v) failed", i, tc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatch(t *testing.T) {
|
||||
type V = e.MatchValue
|
||||
type TC struct {
|
||||
op e.MatchOp
|
||||
values V
|
||||
input interface{}
|
||||
valid bool
|
||||
result BoolAssertionFuncf
|
||||
err ValueAssertionFuncf
|
||||
}
|
||||
|
||||
tcs := []TC{
|
||||
{op: e.MatchAny, result: assert.Truef, err: assert.Nilf},
|
||||
{op: e.MatchAny, input: "2", valid: false, result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{op: e.MatchIn, values: V{"1"}, input: "2", valid: false, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchIn, values: V{"1"}, input: "2", valid: true, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchIn, values: V{"1", "2", "3"}, input: "2", valid: false, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchIn, values: V{"1", "2", "3"}, input: "2", valid: true, result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{op: e.MatchNotIn, values: V{"2"}, input: 2, valid: false, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchNotIn, values: V{"1"}, input: 2, valid: true, result: assert.Truef, err: assert.Nilf},
|
||||
{op: e.MatchNotIn, values: V{"1", "2", "3"}, input: "2", valid: false, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchNotIn, values: V{"1", "2", "3"}, input: "2", valid: true, result: assert.Falsef, err: assert.Nilf},
|
||||
|
||||
{op: e.MatchInRegexp, values: V{"val-[0-9]$"}, input: "val-1", valid: false, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchInRegexp, values: V{"val-[0-9]$"}, input: "val-1", valid: true, result: assert.Truef, err: assert.Nilf},
|
||||
{op: e.MatchInRegexp, values: V{"val-[0-9]$"}, input: "val-12", valid: true, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchInRegexp, values: V{"val-[0-9]$", "al-[1-9]"}, input: "val-12", valid: true, result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{op: e.MatchExists, input: nil, valid: false, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchExists, input: nil, valid: true, result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{op: e.MatchDoesNotExist, input: false, valid: false, result: assert.Truef, err: assert.Nilf},
|
||||
{op: e.MatchDoesNotExist, input: false, valid: true, result: assert.Falsef, err: assert.Nilf},
|
||||
|
||||
{op: e.MatchGt, values: V{"2"}, input: 3, valid: false, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchGt, values: V{"2"}, input: 2, valid: true, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchGt, values: V{"2"}, input: 3, valid: true, result: assert.Truef, err: assert.Nilf},
|
||||
{op: e.MatchGt, values: V{"-10"}, input: -3, valid: true, result: assert.Truef, err: assert.Nilf},
|
||||
{op: e.MatchGt, values: V{"2"}, input: "3a", valid: true, result: assert.Falsef, err: assert.NotNilf},
|
||||
|
||||
{op: e.MatchLt, values: V{"2"}, input: "1", valid: false, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchLt, values: V{"2"}, input: "2", valid: true, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchLt, values: V{"-10"}, input: -3, valid: true, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchLt, values: V{"2"}, input: "1", valid: true, result: assert.Truef, err: assert.Nilf},
|
||||
{op: e.MatchLt, values: V{"2"}, input: "1.0", valid: true, result: assert.Falsef, err: assert.NotNilf},
|
||||
|
||||
{op: e.MatchGtLt, values: V{"1", "10"}, input: "1", valid: false, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchGtLt, values: V{"1", "10"}, input: "1", valid: true, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchGtLt, values: V{"1", "10"}, input: "10", valid: true, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchGtLt, values: V{"1", "10"}, input: "2", valid: true, result: assert.Truef, err: assert.Nilf},
|
||||
{op: e.MatchGtLt, values: V{"1", "10"}, input: "1.0", valid: true, result: assert.Falsef, err: assert.NotNilf},
|
||||
|
||||
{op: e.MatchIsTrue, input: true, valid: false, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchIsTrue, input: true, valid: true, result: assert.Truef, err: assert.Nilf},
|
||||
{op: e.MatchIsTrue, input: false, valid: true, result: assert.Falsef, err: assert.Nilf},
|
||||
|
||||
{op: e.MatchIsFalse, input: "false", valid: false, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchIsFalse, input: "false", valid: true, result: assert.Truef, err: assert.Nilf},
|
||||
{op: e.MatchIsFalse, input: "true", valid: true, result: assert.Falsef, err: assert.Nilf},
|
||||
}
|
||||
|
||||
for i, tc := range tcs {
|
||||
me := e.MustCreateMatchExpression(tc.op, tc.values...)
|
||||
res, err := me.Match(tc.valid, tc.input)
|
||||
tc.result(t, res, "test case #%d (%v) failed", i, tc)
|
||||
tc.err(t, err, "test case #%d (%v) failed", i, tc)
|
||||
}
|
||||
|
||||
// Check some special error cases separately because MustCreateMatch panics
|
||||
tcs = []TC{
|
||||
|
||||
{op: e.MatchGt, values: V{"3.0"}, input: 1, valid: true},
|
||||
{op: e.MatchLt, values: V{"0x2"}, input: 1, valid: true},
|
||||
{op: e.MatchGtLt, values: V{"1", "str"}, input: 1, valid: true},
|
||||
{op: "non-existent-op", values: V{"1"}, input: 1, valid: true},
|
||||
}
|
||||
|
||||
for i, tc := range tcs {
|
||||
me := e.MatchExpression{Op: tc.op, Value: tc.values}
|
||||
res, err := me.Match(tc.valid, tc.input)
|
||||
assert.Falsef(t, res, "err test case #%d (%v) failed", i, tc)
|
||||
assert.NotNilf(t, err, "err test case #%d (%v) failed", i, tc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatchKeys(t *testing.T) {
|
||||
type V = e.MatchValue
|
||||
type I = map[string]feature.Nil
|
||||
type TC struct {
|
||||
op e.MatchOp
|
||||
values V
|
||||
name string
|
||||
input I
|
||||
result BoolAssertionFuncf
|
||||
err ValueAssertionFuncf
|
||||
}
|
||||
|
||||
tcs := []TC{
|
||||
{op: e.MatchAny, result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{op: e.MatchExists, name: "foo", input: nil, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchExists, name: "foo", input: I{"bar": {}}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchExists, name: "foo", input: I{"bar": {}, "foo": {}}, result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{op: e.MatchDoesNotExist, name: "foo", input: nil, result: assert.Truef, err: assert.Nilf},
|
||||
{op: e.MatchDoesNotExist, name: "foo", input: I{}, result: assert.Truef, err: assert.Nilf},
|
||||
{op: e.MatchDoesNotExist, name: "foo", input: I{"bar": {}}, result: assert.Truef, err: assert.Nilf},
|
||||
{op: e.MatchDoesNotExist, name: "foo", input: I{"bar": {}, "foo": {}}, result: assert.Falsef, err: assert.Nilf},
|
||||
|
||||
// All other ops should return an error
|
||||
{op: e.MatchIn, values: V{"foo"}, name: "foo", result: assert.Falsef, err: assert.NotNilf},
|
||||
{op: e.MatchNotIn, values: V{"foo"}, name: "foo", result: assert.Falsef, err: assert.NotNilf},
|
||||
{op: e.MatchInRegexp, values: V{"foo"}, name: "foo", result: assert.Falsef, err: assert.NotNilf},
|
||||
{op: e.MatchGt, values: V{"1"}, name: "foo", result: assert.Falsef, err: assert.NotNilf},
|
||||
{op: e.MatchLt, values: V{"1"}, name: "foo", result: assert.Falsef, err: assert.NotNilf},
|
||||
{op: e.MatchGtLt, values: V{"1", "10"}, name: "foo", result: assert.Falsef, err: assert.NotNilf},
|
||||
{op: e.MatchIsTrue, name: "foo", result: assert.Falsef, err: assert.NotNilf},
|
||||
{op: e.MatchIsFalse, name: "foo", result: assert.Falsef, err: assert.NotNilf},
|
||||
}
|
||||
|
||||
for i, tc := range tcs {
|
||||
me := e.MustCreateMatchExpression(tc.op, tc.values...)
|
||||
res, err := me.MatchKeys(tc.name, tc.input)
|
||||
tc.result(t, res, "test case #%d (%v) failed", i, tc)
|
||||
tc.err(t, err, "test case #%d (%v) failed", i, tc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatchValues(t *testing.T) {
|
||||
type V = []string
|
||||
type I = map[string]string
|
||||
|
||||
type TC struct {
|
||||
op e.MatchOp
|
||||
values V
|
||||
name string
|
||||
input I
|
||||
result BoolAssertionFuncf
|
||||
err ValueAssertionFuncf
|
||||
}
|
||||
|
||||
tcs := []TC{
|
||||
{op: e.MatchAny, result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{op: e.MatchIn, values: V{"1", "2"}, name: "foo", input: I{"bar": "2"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchIn, values: V{"1", "2"}, name: "foo", input: I{"foo": "3"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchIn, values: V{"1", "2"}, name: "foo", input: I{"foo": "2"}, result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{op: e.MatchNotIn, values: V{"1", "2"}, name: "foo", input: I{"bar": "2"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchNotIn, values: V{"1", "2"}, name: "foo", input: I{"foo": "3"}, result: assert.Truef, err: assert.Nilf},
|
||||
{op: e.MatchNotIn, values: V{"1", "2"}, name: "foo", input: I{"foo": "2"}, result: assert.Falsef, err: assert.Nilf},
|
||||
|
||||
{op: e.MatchInRegexp, values: V{"1", "2"}, name: "foo", input: I{"bar": "2"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchInRegexp, values: V{"1", "[0-8]"}, name: "foo", input: I{"foo": "9"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchInRegexp, values: V{"1", "[0-8]"}, name: "foo", input: I{"foo": "2"}, result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{op: e.MatchExists, name: "foo", input: I{"bar": "1"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchExists, name: "foo", input: I{"foo": "1"}, result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{op: e.MatchDoesNotExist, name: "foo", input: nil, result: assert.Truef, err: assert.Nilf},
|
||||
{op: e.MatchDoesNotExist, name: "foo", input: I{"foo": "1"}, result: assert.Falsef, err: assert.Nilf},
|
||||
|
||||
{op: e.MatchGt, values: V{"2"}, name: "foo", input: I{"bar": "3"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchGt, values: V{"2"}, name: "foo", input: I{"bar": "3", "foo": "2"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchGt, values: V{"2"}, name: "foo", input: I{"bar": "3", "foo": "3"}, result: assert.Truef, err: assert.Nilf},
|
||||
{op: e.MatchGt, values: V{"2"}, name: "foo", input: I{"bar": "str", "foo": "str"}, result: assert.Falsef, err: assert.NotNilf},
|
||||
|
||||
{op: e.MatchLt, values: V{"2"}, name: "foo", input: I{"bar": "1"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchLt, values: V{"2"}, name: "foo", input: I{"bar": "1", "foo": "2"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchLt, values: V{"2"}, name: "foo", input: I{"bar": "1", "foo": "1"}, result: assert.Truef, err: assert.Nilf},
|
||||
{op: e.MatchLt, values: V{"2"}, name: "foo", input: I{"bar": "str", "foo": "str"}, result: assert.Falsef, err: assert.NotNilf},
|
||||
|
||||
{op: e.MatchGtLt, values: V{"-10", "10"}, name: "foo", input: I{"bar": "1"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchGtLt, values: V{"-10", "10"}, name: "foo", input: I{"bar": "1", "foo": "11"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchGtLt, values: V{"-10", "10"}, name: "foo", input: I{"bar": "1", "foo": "-11"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchGtLt, values: V{"-10", "10"}, name: "foo", input: I{"bar": "1", "foo": "1"}, result: assert.Truef, err: assert.Nilf},
|
||||
{op: e.MatchGtLt, values: V{"-10", "10"}, name: "foo", input: I{"bar": "str", "foo": "str"}, result: assert.Falsef, err: assert.NotNilf},
|
||||
|
||||
{op: e.MatchIsTrue, name: "foo", result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchIsTrue, name: "foo", input: I{"foo": "1"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchIsTrue, name: "foo", input: I{"foo": "true"}, result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{op: e.MatchIsFalse, name: "foo", input: I{"foo": "true"}, result: assert.Falsef, err: assert.Nilf},
|
||||
{op: e.MatchIsFalse, name: "foo", input: I{"foo": "false"}, result: assert.Truef, err: assert.Nilf},
|
||||
}
|
||||
|
||||
for i, tc := range tcs {
|
||||
me := e.MustCreateMatchExpression(tc.op, tc.values...)
|
||||
res, err := me.MatchValues(tc.name, tc.input)
|
||||
tc.result(t, res, "test case #%d (%v) failed", i, tc)
|
||||
tc.err(t, err, "test case #%d (%v) failed", i, tc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMESMatchKeys(t *testing.T) {
|
||||
type I = map[string]feature.Nil
|
||||
type TC struct {
|
||||
mes string
|
||||
input I
|
||||
result BoolAssertionFuncf
|
||||
err ValueAssertionFuncf
|
||||
}
|
||||
|
||||
tcs := []TC{
|
||||
{result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{input: I{"foo": {}}, result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{mes: `
|
||||
foo: { op: DoesNotExist }
|
||||
bar: { op: Exists }
|
||||
`,
|
||||
input: I{"bar": {}, "baz": {}},
|
||||
result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{mes: `
|
||||
foo: { op: DoesNotExist }
|
||||
bar: { op: Exists }
|
||||
`,
|
||||
input: I{"foo": {}, "bar": {}, "baz": {}},
|
||||
result: assert.Falsef, err: assert.Nilf},
|
||||
|
||||
{mes: `
|
||||
foo: { op: In, value: ["bar"] }
|
||||
bar: { op: Exists }
|
||||
`,
|
||||
input: I{"bar": {}, "baz": {}},
|
||||
result: assert.Falsef, err: assert.NotNilf},
|
||||
}
|
||||
|
||||
for i, tc := range tcs {
|
||||
mes := &e.MatchExpressionSet{}
|
||||
if err := yaml.Unmarshal([]byte(tc.mes), mes); err != nil {
|
||||
t.Fatalf("failed to parse data of test case #%d (%v): %v", i, tc, err)
|
||||
}
|
||||
|
||||
res, err := mes.MatchKeys(tc.input)
|
||||
tc.result(t, res, "test case #%d (%v) failed", i, tc)
|
||||
tc.err(t, err, "test case #%d (%v) failed", i, tc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMESMatchValues(t *testing.T) {
|
||||
type I = map[string]string
|
||||
type TC struct {
|
||||
mes string
|
||||
input I
|
||||
result BoolAssertionFuncf
|
||||
err ValueAssertionFuncf
|
||||
}
|
||||
|
||||
tcs := []TC{
|
||||
{result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{input: I{"foo": "bar"}, result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{mes: `
|
||||
foo: { op: Exists }
|
||||
bar: { op: In, value: ["val", "wal"] }
|
||||
baz: { op: Gt, value: ["10"] }
|
||||
`,
|
||||
input: I{"bar": "val"},
|
||||
result: assert.Falsef, err: assert.Nilf},
|
||||
|
||||
{mes: `
|
||||
foo: { op: Exists }
|
||||
bar: { op: In, value: ["val", "wal"] }
|
||||
baz: { op: Gt, value: ["10"] }
|
||||
`,
|
||||
input: I{"foo": "1", "bar": "val", "baz": "123"},
|
||||
result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{mes: `
|
||||
foo: { op: Exists }
|
||||
bar: { op: In, value: ["val"] }
|
||||
baz: { op: Gt, value: ["10"] }
|
||||
`,
|
||||
input: I{"foo": "1", "bar": "val", "baz": "123.0"},
|
||||
result: assert.Falsef, err: assert.NotNilf},
|
||||
}
|
||||
|
||||
for i, tc := range tcs {
|
||||
mes := &e.MatchExpressionSet{}
|
||||
if err := yaml.Unmarshal([]byte(tc.mes), mes); err != nil {
|
||||
t.Fatalf("failed to parse data of test case #%d (%v): %v", i, tc, err)
|
||||
}
|
||||
|
||||
res, err := mes.MatchValues(tc.input)
|
||||
tc.result(t, res, "test case #%d (%v) failed", i, tc)
|
||||
tc.err(t, err, "test case #%d (%v) failed", i, tc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMESMatchInstances(t *testing.T) {
|
||||
type I = feature.InstanceFeature
|
||||
type A = map[string]string
|
||||
type TC struct {
|
||||
mes string
|
||||
input []I
|
||||
result BoolAssertionFuncf
|
||||
err ValueAssertionFuncf
|
||||
}
|
||||
|
||||
tcs := []TC{
|
||||
{result: assert.Falsef, err: assert.Nilf}, // nil instances -> false
|
||||
|
||||
{input: []I{}, result: assert.Falsef, err: assert.Nilf}, // zero instances -> false
|
||||
|
||||
{input: []I{I{Attributes: A{}}}, result: assert.Truef, err: assert.Nilf}, // one "empty" instance
|
||||
|
||||
{mes: `
|
||||
foo: { op: Exists }
|
||||
bar: { op: Lt, value: ["10"] }
|
||||
`,
|
||||
input: []I{I{Attributes: A{"foo": "1"}}, I{Attributes: A{"bar": "1"}}},
|
||||
result: assert.Falsef, err: assert.Nilf},
|
||||
|
||||
{mes: `
|
||||
foo: { op: Exists }
|
||||
bar: { op: Lt, value: ["10"] }
|
||||
`,
|
||||
input: []I{I{Attributes: A{"foo": "1"}}, I{Attributes: A{"foo": "2", "bar": "1"}}},
|
||||
result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{mes: `
|
||||
bar: { op: Lt, value: ["10"] }
|
||||
`,
|
||||
input: []I{I{Attributes: A{"foo": "1"}}, I{Attributes: A{"bar": "0x1"}}},
|
||||
result: assert.Falsef, err: assert.NotNilf},
|
||||
}
|
||||
|
||||
for i, tc := range tcs {
|
||||
mes := &e.MatchExpressionSet{}
|
||||
if err := yaml.Unmarshal([]byte(tc.mes), mes); err != nil {
|
||||
t.Fatalf("failed to parse data of test case #%d (%v): %v", i, tc, err)
|
||||
}
|
||||
|
||||
res, err := mes.MatchInstances(tc.input)
|
||||
tc.result(t, res, "test case #%d (%v) failed", i, tc)
|
||||
tc.err(t, err, "test case #%d (%v) failed", i, tc)
|
||||
}
|
||||
}
|
|
@ -19,14 +19,14 @@ package rules
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
|
||||
"sigs.k8s.io/node-feature-discovery/source"
|
||||
"sigs.k8s.io/node-feature-discovery/source/cpu"
|
||||
"sigs.k8s.io/node-feature-discovery/source/custom/expression"
|
||||
)
|
||||
|
||||
// CpuIDRule implements Rule for the custom source
|
||||
type CpuIDRule struct {
|
||||
expression.MatchExpressionSet
|
||||
nfdv1alpha1.MatchExpressionSet
|
||||
}
|
||||
|
||||
func (r *CpuIDRule) Match() (bool, error) {
|
||||
|
|
|
@ -19,14 +19,14 @@ package rules
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
|
||||
"sigs.k8s.io/node-feature-discovery/source"
|
||||
"sigs.k8s.io/node-feature-discovery/source/custom/expression"
|
||||
"sigs.k8s.io/node-feature-discovery/source/kernel"
|
||||
)
|
||||
|
||||
// KconfigRule implements Rule for the custom source
|
||||
type KconfigRule struct {
|
||||
expression.MatchExpressionSet
|
||||
nfdv1alpha1.MatchExpressionSet
|
||||
}
|
||||
|
||||
func (r *KconfigRule) Match() (bool, error) {
|
||||
|
|
|
@ -19,14 +19,14 @@ package rules
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
|
||||
"sigs.k8s.io/node-feature-discovery/source"
|
||||
"sigs.k8s.io/node-feature-discovery/source/custom/expression"
|
||||
"sigs.k8s.io/node-feature-discovery/source/kernel"
|
||||
)
|
||||
|
||||
// LoadedKModRule matches loaded kernel modules in the system
|
||||
type LoadedKModRule struct {
|
||||
expression.MatchExpressionSet
|
||||
nfdv1alpha1.MatchExpressionSet
|
||||
}
|
||||
|
||||
// Match loaded kernel modules on provided list of kernel modules
|
||||
|
|
|
@ -20,14 +20,14 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
|
||||
"sigs.k8s.io/node-feature-discovery/source"
|
||||
"sigs.k8s.io/node-feature-discovery/source/custom/expression"
|
||||
"sigs.k8s.io/node-feature-discovery/source/system"
|
||||
)
|
||||
|
||||
// NodenameRule matches on nodenames configured in a ConfigMap
|
||||
type NodenameRule struct {
|
||||
expression.MatchExpression
|
||||
nfdv1alpha1.MatchExpression
|
||||
}
|
||||
|
||||
func (r *NodenameRule) Match() (bool, error) {
|
||||
|
@ -43,8 +43,8 @@ func (r *NodenameRule) UnmarshalJSON(data []byte) error {
|
|||
return err
|
||||
}
|
||||
// Force regexp matching
|
||||
if r.Op == expression.MatchIn {
|
||||
r.Op = expression.MatchInRegexp
|
||||
if r.Op == nfdv1alpha1.MatchIn {
|
||||
r.Op = nfdv1alpha1.MatchInRegexp
|
||||
}
|
||||
// We need to run Validate() because operator forcing above
|
||||
return r.Validate()
|
||||
|
|
|
@ -19,13 +19,13 @@ package rules
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
|
||||
"sigs.k8s.io/node-feature-discovery/source"
|
||||
"sigs.k8s.io/node-feature-discovery/source/custom/expression"
|
||||
"sigs.k8s.io/node-feature-discovery/source/pci"
|
||||
)
|
||||
|
||||
type PciIDRule struct {
|
||||
expression.MatchExpressionSet
|
||||
nfdv1alpha1.MatchExpressionSet
|
||||
}
|
||||
|
||||
// Match PCI devices on provided PCI device attributes
|
||||
|
|
|
@ -19,13 +19,13 @@ package rules
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
|
||||
"sigs.k8s.io/node-feature-discovery/source"
|
||||
"sigs.k8s.io/node-feature-discovery/source/custom/expression"
|
||||
"sigs.k8s.io/node-feature-discovery/source/usb"
|
||||
)
|
||||
|
||||
type UsbIDRule struct {
|
||||
expression.MatchExpressionSet
|
||||
nfdv1alpha1.MatchExpressionSet
|
||||
}
|
||||
|
||||
// Match USB devices on provided USB device attributes
|
||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
|||
package custom
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/node-feature-discovery/source/custom/expression"
|
||||
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
|
||||
"sigs.k8s.io/node-feature-discovery/source/custom/rules"
|
||||
)
|
||||
|
||||
|
@ -31,8 +31,8 @@ func getStaticFeatureConfig() []CustomRule {
|
|||
MatchOn: []LegacyMatcher{
|
||||
{
|
||||
PciID: &rules.PciIDRule{
|
||||
MatchExpressionSet: expression.MatchExpressionSet{
|
||||
"vendor": expression.MustCreateMatchExpression(expression.MatchIn, "15b3"),
|
||||
MatchExpressionSet: nfdv1alpha1.MatchExpressionSet{
|
||||
"vendor": nfdv1alpha1.MustCreateMatchExpression(nfdv1alpha1.MatchIn, "15b3"),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -45,9 +45,9 @@ func getStaticFeatureConfig() []CustomRule {
|
|||
MatchOn: []LegacyMatcher{
|
||||
{
|
||||
LoadedKMod: &rules.LoadedKModRule{
|
||||
MatchExpressionSet: expression.MatchExpressionSet{
|
||||
"ib_uverbs": expression.MustCreateMatchExpression(expression.MatchExists),
|
||||
"rdma_ucm": expression.MustCreateMatchExpression(expression.MatchExists),
|
||||
MatchExpressionSet: nfdv1alpha1.MatchExpressionSet{
|
||||
"ib_uverbs": nfdv1alpha1.MustCreateMatchExpression(nfdv1alpha1.MatchExists),
|
||||
"rdma_ucm": nfdv1alpha1.MustCreateMatchExpression(nfdv1alpha1.MatchExists),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
Loading…
Add table
Reference in a new issue