mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-31 03:45:17 +00:00
Add an object_from_lists function (#3824)
This commit is contained in:
parent
876a216b5f
commit
c3604c1170
6 changed files with 132 additions and 0 deletions
|
@ -64,6 +64,7 @@ var (
|
||||||
parseJson = "parse_json"
|
parseJson = "parse_json"
|
||||||
parseYAML = "parse_yaml"
|
parseYAML = "parse_yaml"
|
||||||
items = "items"
|
items = "items"
|
||||||
|
objectFromLists = "object_from_lists"
|
||||||
)
|
)
|
||||||
|
|
||||||
const errorPrefix = "JMESPath function '%s': "
|
const errorPrefix = "JMESPath function '%s': "
|
||||||
|
@ -382,6 +383,17 @@ func GetFunctions() []*FunctionEntry {
|
||||||
ReturnType: []JpType{JpArray},
|
ReturnType: []JpType{JpArray},
|
||||||
Note: "converts a map to an array of objects where each key:value is an item in the array",
|
Note: "converts a map to an array of objects where each key:value is an item in the array",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Entry: &gojmespath.FunctionEntry{Name: objectFromLists,
|
||||||
|
Arguments: []ArgSpec{
|
||||||
|
{Types: []JpType{JpArray}},
|
||||||
|
{Types: []JpType{JpArray}},
|
||||||
|
},
|
||||||
|
Handler: jpObjectFromLists,
|
||||||
|
},
|
||||||
|
ReturnType: []JpType{JpObject},
|
||||||
|
Note: "converts a pair of lists containing keys and values to an object",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -844,6 +856,33 @@ func jpItems(arguments []interface{}) (interface{}, error) {
|
||||||
return arrayOfObj, nil
|
return arrayOfObj, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func jpObjectFromLists(arguments []interface{}) (interface{}, error) {
|
||||||
|
keys, ok := arguments[0].([]interface{})
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf(invalidArgumentTypeError, arguments, 0, "Array")
|
||||||
|
}
|
||||||
|
values, ok := arguments[1].([]interface{})
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf(invalidArgumentTypeError, arguments, 1, "Array")
|
||||||
|
}
|
||||||
|
|
||||||
|
output := map[string]interface{}{}
|
||||||
|
|
||||||
|
for i, ikey := range keys {
|
||||||
|
key, err := ifaceToString(ikey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(invalidArgumentTypeError, arguments, 0, "StringArray")
|
||||||
|
}
|
||||||
|
if i < len(values) {
|
||||||
|
output[key] = values[i]
|
||||||
|
} else {
|
||||||
|
output[key] = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output, nil
|
||||||
|
}
|
||||||
|
|
||||||
// InterfaceToString casts an interface to a string type
|
// InterfaceToString casts an interface to a string type
|
||||||
func ifaceToString(iface interface{}) (string, error) {
|
func ifaceToString(iface interface{}) (string, error) {
|
||||||
switch i := iface.(type) {
|
switch i := iface.(type) {
|
||||||
|
|
|
@ -1334,3 +1334,50 @@ func Test_Items(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_ObjectFromLists(t *testing.T) {
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
keys string
|
||||||
|
values string
|
||||||
|
expectedResult map[string]interface{}
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
keys: `["key1", "key2"]`,
|
||||||
|
values: `["1", "2"]`,
|
||||||
|
expectedResult: map[string]interface{}{
|
||||||
|
"key1": "1",
|
||||||
|
"key2": "2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keys: `["key1", "key2"]`,
|
||||||
|
values: `[1, "2"]`,
|
||||||
|
expectedResult: map[string]interface{}{
|
||||||
|
"key1": 1.0,
|
||||||
|
"key2": "2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
keys: `["key1", "key2"]`,
|
||||||
|
values: `[1]`,
|
||||||
|
expectedResult: map[string]interface{}{
|
||||||
|
"key1": 1.0,
|
||||||
|
"key2": nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tc := range testCases {
|
||||||
|
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
||||||
|
query, err := New("object_from_lists(`" + tc.keys + "`,`" + tc.values + "`)")
|
||||||
|
assert.NilError(t, err)
|
||||||
|
res, err := query.Search("")
|
||||||
|
assert.NilError(t, err)
|
||||||
|
result, ok := res.(map[string]interface{})
|
||||||
|
assert.Assert(t, ok)
|
||||||
|
assert.DeepEqual(t, result, tc.expectedResult)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -82,3 +82,9 @@ results:
|
||||||
patchedResource: patchedResource11.yaml
|
patchedResource: patchedResource11.yaml
|
||||||
kind: Pod
|
kind: Pod
|
||||||
result: skip
|
result: skip
|
||||||
|
- policy: example
|
||||||
|
rule: object_from_lists
|
||||||
|
resource: example
|
||||||
|
patchedResource: patched-resource.yaml
|
||||||
|
kind: Pod
|
||||||
|
result: pass
|
7
test/cli/test-mutate/patched-resource.yaml
Normal file
7
test/cli/test-mutate/patched-resource.yaml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: example
|
||||||
|
annotations:
|
||||||
|
key1: "1"
|
||||||
|
key2: "1"
|
|
@ -75,3 +75,27 @@ spec:
|
||||||
options:
|
options:
|
||||||
- name: ndots
|
- name: ndots
|
||||||
value: "1"
|
value: "1"
|
||||||
|
---
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: example
|
||||||
|
spec:
|
||||||
|
rules:
|
||||||
|
- name: object_from_lists
|
||||||
|
context:
|
||||||
|
- name: annotations
|
||||||
|
variable:
|
||||||
|
jmesPath: items(request.object.metadata.annotations, 'key', 'value')[?starts_with(key, 'key')]
|
||||||
|
- name: annotations
|
||||||
|
variable:
|
||||||
|
jmesPath: object_from_lists(annotations[].key, annotations[].value)
|
||||||
|
match:
|
||||||
|
resources:
|
||||||
|
kinds:
|
||||||
|
- Pod
|
||||||
|
mutate:
|
||||||
|
patchesJson6902: |-
|
||||||
|
- path: "/metadata/annotations"
|
||||||
|
op: replace
|
||||||
|
value: {{ annotations }}
|
||||||
|
|
|
@ -98,3 +98,12 @@ spec:
|
||||||
image: nginx:latest
|
image: nginx:latest
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: example
|
||||||
|
annotations:
|
||||||
|
key1: "1"
|
||||||
|
key2: "1"
|
||||||
|
notkey: "2"
|
||||||
|
|
Loading…
Add table
Reference in a new issue