1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-14 11:57:48 +00:00

Context vars with labelselector (#11608)

* refactor: Treat all of the target spec as a single object while replacing variables

Serialize it into a map string interface then back to a target seletor before returning

Signed-off-by: aerosouund <aerosound161@gmail.com>

* test: Add scenario for variables in the label selector test

Signed-off-by: aerosouund <aerosound161@gmail.com>

* Fix: Capitalize error message

Co-authored-by: shuting <shuting@nirmata.com>
Signed-off-by: Ammar Yasser <aerosound161@gmail.com>

* Fix: Adjust error message specification to mention target rather than selector

Co-authored-by: shuting <shuting@nirmata.com>
Signed-off-by: Ammar Yasser <aerosound161@gmail.com>

* fix: Pass the target selector only during variable replacement

Signed-off-by: aerosouund <aerosound161@gmail.com>

---------

Signed-off-by: aerosouund <aerosound161@gmail.com>
Signed-off-by: Ammar Yasser <aerosound161@gmail.com>
Co-authored-by: shuting <shuting@nirmata.com>
This commit is contained in:
Ammar Yasser 2024-11-20 12:36:55 +02:00 committed by GitHub
parent 338d2ad473
commit d61f87e0f9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 179 additions and 20 deletions

View file

@ -2,6 +2,7 @@ package mutation
import (
"context"
"encoding/json"
"fmt"
"github.com/go-logr/logr"
@ -57,31 +58,32 @@ func loadTargets(ctx context.Context, client engineapi.Client, targets []kyverno
}
func resolveSpec(i int, target kyvernov1.TargetResourceSpec, ctx engineapi.PolicyContext, logger logr.Logger) (kyvernov1.TargetSelector, error) {
kind, err := variables.SubstituteAll(logger, ctx.JSONContext(), target.Kind)
var s kyvernov1.TargetSelector
jsonData, err := json.Marshal(target.TargetSelector)
if err != nil {
return kyvernov1.TargetSelector{}, fmt.Errorf("failed to substitute variables in target[%d].Kind %s, value: %v, err: %v", i, target.Kind, kind, err)
return kyvernov1.TargetSelector{}, fmt.Errorf("failed to marshal the mutation target to JSON: %s", err)
}
apiversion, err := variables.SubstituteAll(logger, ctx.JSONContext(), target.APIVersion)
var result map[string]interface{}
if err := json.Unmarshal(jsonData, &result); err != nil {
return kyvernov1.TargetSelector{}, err
}
selector, err := variables.SubstituteAll(logger, ctx.JSONContext(), result)
if err != nil || selector == nil {
return kyvernov1.TargetSelector{}, fmt.Errorf("failed to substitute variables in target[%d]: %v", i, err)
}
substitutedJson, err := json.Marshal(selector)
if err != nil {
return kyvernov1.TargetSelector{}, fmt.Errorf("failed to substitute variables in target[%d].APIVersion %s, value: %v, err: %v", i, target.APIVersion, apiversion, err)
return kyvernov1.TargetSelector{}, err
}
namespace, err := variables.SubstituteAll(logger, ctx.JSONContext(), target.Namespace)
if err != nil || namespace == nil {
return kyvernov1.TargetSelector{}, fmt.Errorf("failed to substitute variables in target[%d].Namespace %s, value: %v, err: %v", i, target.Namespace, namespace, err)
if err := json.Unmarshal(substitutedJson, &s); err != nil {
return kyvernov1.TargetSelector{}, err
}
name, err := variables.SubstituteAll(logger, ctx.JSONContext(), target.Name)
if err != nil || name == nil {
return kyvernov1.TargetSelector{}, fmt.Errorf("failed to substitute variables in target[%d].Name %s, value: %v, err: %v", i, target.Name, name, err)
}
return kyvernov1.TargetSelector{
ResourceSpec: kyvernov1.ResourceSpec{
APIVersion: apiversion.(string),
Kind: kind.(string),
Namespace: namespace.(string),
Name: name.(string),
},
Selector: target.Selector,
}, nil
return s, nil
}
func getTargets(ctx context.Context, client engineapi.Client, target kyvernov1.ResourceSpec, policyCtx engineapi.PolicyContext, lselector *metav1.LabelSelector) ([]resourceInfo, error) {

View file

@ -1521,6 +1521,163 @@ func Test_mutate_existing_resources(t *testing.T) {
}`)},
targetList: "DeploymentList",
},
{
name: "test-labelselector-variables",
policy: []byte(`{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "test-post-mutation"
},
"spec": {
"rules": [
{
"name": "mutate-deploy-on-configmap-update",
"match": {
"any": [
{
"resources": {
"kinds": [
"ConfigMap"
],
"names": [
"dictionary"
],
"namespaces": [
"staging"
]
}
}
]
},
"preconditions": {
"any": [
{
"key": "{{ request.object.data.foo }}",
"operator": "Equals",
"value": "bar"
}
]
},
"mutate": {
"targets": [
{
"apiVersion": "v1",
"kind": "Deployment",
"namespace": "staging",
"selector": {
"matchLabels": {
"parent": "{{ request.object.metadata.name }}"
}
}
}
],
"patchStrategicMerge": {
"metadata": {
"labels": {
"foo": "bar"
}
}
}
}
}
]
}
}`),
trigger: []byte(`{
"apiVersion": "v1",
"data": {
"foo": "bar"
},
"kind": "ConfigMap",
"metadata": {
"name": "dictionary",
"namespace": "staging"
}
}`),
targets: [][]byte{[]byte(`{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"name": "example-A",
"namespace": "staging",
"labels": {
"parent": "dictionary",
"app": "nginx"
}
},
"spec": {
"replicas": 1,
"selector": {
"matchLabels": {
"app": "nginx"
}
},
"template": {
"metadata": {
"labels": {
"app": "nginx"
}
},
"spec": {
"containers": [
{
"name": "nginx",
"image": "nginx:1.14.2",
"ports": [
{
"containerPort": 80
}
]
}
]
}
}
}
}`)},
patchedTargets: [][]byte{[]byte(`{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"name": "example-A",
"namespace": "staging",
"labels": {
"app": "nginx",
"parent": "dictionary",
"foo": "bar"
}
},
"spec": {
"replicas": 1,
"selector": {
"matchLabels": {
"app": "nginx"
}
},
"template": {
"metadata": {
"labels": {
"app": "nginx"
}
},
"spec": {
"containers": [
{
"name": "nginx",
"image": "nginx:1.14.2",
"ports": [
{
"containerPort": 80
}
]
}
]
}
}
}
}`)},
targetList: "DeploymentList",
},
{
name: "test-different-trigger-target",
policy: []byte(`{