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:
parent
338d2ad473
commit
d61f87e0f9
2 changed files with 179 additions and 20 deletions
|
@ -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) {
|
||||
|
|
|
@ -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(`{
|
||||
|
|
Loading…
Reference in a new issue