mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-31 03:45:17 +00:00
fix: cascading mutations (#6411)
* fix: cascading mutations Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * remove explicit AddResource call Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * update resource in context Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> --------- Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
parent
bc7b73401e
commit
33a07f3c80
15 changed files with 150 additions and 10 deletions
|
@ -30,7 +30,6 @@ func (e *engine) mutate(
|
||||||
policy := policyContext.Policy()
|
policy := policyContext.Policy()
|
||||||
resp = engineapi.NewEngineResponseFromPolicyContext(policyContext, nil)
|
resp = engineapi.NewEngineResponseFromPolicyContext(policyContext, nil)
|
||||||
matchedResource := policyContext.NewResource()
|
matchedResource := policyContext.NewResource()
|
||||||
enginectx := policyContext.JSONContext()
|
|
||||||
var skippedRules []string
|
var skippedRules []string
|
||||||
|
|
||||||
logger.V(4).Info("start mutate policy processing", "startTime", startTime)
|
logger.V(4).Info("start mutate policy processing", "startTime", startTime)
|
||||||
|
@ -76,15 +75,6 @@ func (e *engine) mutate(
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.V(3).Info("processing mutate rule")
|
logger.V(3).Info("processing mutate rule")
|
||||||
resource, err := policyContext.JSONContext().Query("request.object")
|
|
||||||
policyContext.JSONContext().Reset()
|
|
||||||
if err == nil && resource != nil {
|
|
||||||
if err := enginectx.AddResource(resource.(map[string]interface{})); err != nil {
|
|
||||||
logger.Error(err, "unable to update resource object")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logger.Error(err, "failed to query resource object")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := internal.LoadContext(ctx, e, policyContext, rule); err != nil {
|
if err := internal.LoadContext(ctx, e, policyContext, rule); err != nil {
|
||||||
if _, ok := err.(gojmespath.NotFoundError); ok {
|
if _, ok := err.(gojmespath.NotFoundError); ok {
|
||||||
|
@ -233,6 +223,10 @@ func (f *forEachMutator) mutateForEach(ctx context.Context) *mutate.Response {
|
||||||
f.resource.unstructured = mutateResp.PatchedResource
|
f.resource.unstructured = mutateResp.PatchedResource
|
||||||
allPatches = append(allPatches, mutateResp.Patches...)
|
allPatches = append(allPatches, mutateResp.Patches...)
|
||||||
}
|
}
|
||||||
|
f.log.Info("mutateResp.PatchedResource", "resource", mutateResp.PatchedResource)
|
||||||
|
if err := f.policyContext.JSONContext().AddResource(mutateResp.PatchedResource.Object); err != nil {
|
||||||
|
f.log.Error(err, "failed to update resource in context")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
apiVersion: kuttl.dev/v1beta1
|
||||||
|
kind: TestStep
|
||||||
|
apply:
|
||||||
|
- policy.yaml
|
||||||
|
assert:
|
||||||
|
- policy-assert.yaml
|
|
@ -0,0 +1,6 @@
|
||||||
|
apiVersion: kuttl.dev/v1beta1
|
||||||
|
kind: TestStep
|
||||||
|
apply:
|
||||||
|
- file: configmap.yaml
|
||||||
|
assert:
|
||||||
|
- configmap-assert.yaml
|
|
@ -0,0 +1,9 @@
|
||||||
|
## Description
|
||||||
|
|
||||||
|
This test creates a policy with two mutation rules.
|
||||||
|
The second rule depends on the mutation in the first rule.
|
||||||
|
To succeed, the changes in the first mutation rule need to cascade correctly to get the second rule to execute correctly.
|
||||||
|
|
||||||
|
## Related issue
|
||||||
|
|
||||||
|
https://github.com/kyverno/kyverno/issues/6210
|
|
@ -0,0 +1,7 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: cm
|
||||||
|
annotations:
|
||||||
|
mutation1: '1'
|
||||||
|
mutation2: 'found mutation1: 1'
|
|
@ -0,0 +1,4 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: cm
|
|
@ -0,0 +1,9 @@
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: mutate-chain
|
||||||
|
status:
|
||||||
|
conditions:
|
||||||
|
- reason: Succeeded
|
||||||
|
status: 'True'
|
||||||
|
type: Ready
|
|
@ -0,0 +1,33 @@
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: mutate-chain
|
||||||
|
spec:
|
||||||
|
background: false
|
||||||
|
validationFailureAction: Enforce
|
||||||
|
rules:
|
||||||
|
- name: mutation1
|
||||||
|
match:
|
||||||
|
all:
|
||||||
|
- resources:
|
||||||
|
kinds:
|
||||||
|
- v1/ConfigMap
|
||||||
|
mutate:
|
||||||
|
foreach:
|
||||||
|
- list: "['dummy']"
|
||||||
|
patchStrategicMerge:
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
# value is a counter in case K8s decides for multiple mutation rounds
|
||||||
|
mutation1: "{{ not_null(request.object.metadata.annotations.mutation1, '0') | add(@, '1') }}"
|
||||||
|
- name: mutation2
|
||||||
|
match:
|
||||||
|
all:
|
||||||
|
- resources:
|
||||||
|
kinds:
|
||||||
|
- v1/ConfigMap
|
||||||
|
mutate:
|
||||||
|
patchStrategicMerge:
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
mutation2: "found mutation1: {{ request.object.metadata.annotations.mutation1 || '<nothing>' }}"
|
|
@ -0,0 +1,6 @@
|
||||||
|
apiVersion: kuttl.dev/v1beta1
|
||||||
|
kind: TestStep
|
||||||
|
apply:
|
||||||
|
- policy.yaml
|
||||||
|
assert:
|
||||||
|
- policy-assert.yaml
|
|
@ -0,0 +1,6 @@
|
||||||
|
apiVersion: kuttl.dev/v1beta1
|
||||||
|
kind: TestStep
|
||||||
|
apply:
|
||||||
|
- file: configmap.yaml
|
||||||
|
assert:
|
||||||
|
- configmap-assert.yaml
|
|
@ -0,0 +1,9 @@
|
||||||
|
## Description
|
||||||
|
|
||||||
|
This test creates a policy with two mutation rules.
|
||||||
|
The second rule depends on the mutation in the first rule.
|
||||||
|
To succeed, the changes in the first mutation rule need to cascade correctly to get the second rule to execute correctly.
|
||||||
|
|
||||||
|
## Related issue
|
||||||
|
|
||||||
|
https://github.com/kyverno/kyverno/issues/6210
|
|
@ -0,0 +1,7 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: cm
|
||||||
|
annotations:
|
||||||
|
mutation1: '1'
|
||||||
|
mutation2: 'found mutation1: 1'
|
|
@ -0,0 +1,4 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: cm
|
|
@ -0,0 +1,9 @@
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: mutate-chain
|
||||||
|
status:
|
||||||
|
conditions:
|
||||||
|
- reason: Succeeded
|
||||||
|
status: 'True'
|
||||||
|
type: Ready
|
|
@ -0,0 +1,31 @@
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: mutate-chain
|
||||||
|
spec:
|
||||||
|
background: false
|
||||||
|
validationFailureAction: Enforce
|
||||||
|
rules:
|
||||||
|
- name: mutation1
|
||||||
|
match:
|
||||||
|
all:
|
||||||
|
- resources:
|
||||||
|
kinds:
|
||||||
|
- v1/ConfigMap
|
||||||
|
mutate:
|
||||||
|
patchStrategicMerge:
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
# value is a counter in case K8s decides for multiple mutation rounds
|
||||||
|
mutation1: "{{ not_null(request.object.metadata.annotations.mutation1, '0') | add(@, '1') }}"
|
||||||
|
- name: mutation2
|
||||||
|
match:
|
||||||
|
all:
|
||||||
|
- resources:
|
||||||
|
kinds:
|
||||||
|
- v1/ConfigMap
|
||||||
|
mutate:
|
||||||
|
patchStrategicMerge:
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
mutation2: "found mutation1: {{ request.object.metadata.annotations.mutation1 || '<nothing>' }}"
|
Loading…
Add table
Reference in a new issue