From 5e9352c3fafcdf9e727c886eaac72aa03e8078cd Mon Sep 17 00:00:00 2001 From: ansalamdaniel Date: Mon, 28 Nov 2022 17:20:04 +0530 Subject: [PATCH] Fix: handling unexpected global-anchor-variable for the apply command Signed-off-by: ansalamdaniel --- .../mutate/patch/strategicPreprocessing.go | 20 ++++++- .../global-anchor/kyverno-test.yaml | 28 ++++++++++ .../global-anchor/patchedResource.yaml | 14 +++++ .../global-anchor/patchedResource1.yaml | 18 ++++++ .../cli/test-mutate/global-anchor/policy.yaml | 25 +++++++++ .../test-mutate/global-anchor/resources.yaml | 55 +++++++++++++++++++ 6 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 test/cli/test-mutate/global-anchor/kyverno-test.yaml create mode 100644 test/cli/test-mutate/global-anchor/patchedResource.yaml create mode 100644 test/cli/test-mutate/global-anchor/patchedResource1.yaml create mode 100644 test/cli/test-mutate/global-anchor/policy.yaml create mode 100644 test/cli/test-mutate/global-anchor/resources.yaml diff --git a/pkg/engine/mutate/patch/strategicPreprocessing.go b/pkg/engine/mutate/patch/strategicPreprocessing.go index 3e268215ad7a..fc05ce6c4b38 100644 --- a/pkg/engine/mutate/patch/strategicPreprocessing.go +++ b/pkg/engine/mutate/patch/strategicPreprocessing.go @@ -137,9 +137,9 @@ func processListOfMaps(logger logr.Logger, pattern, resource *yaml.RNode) error if hasAnyAnchor { anyGlobalConditionPassed := false var lastGlobalAnchorError error = nil + patternElementCopy := patternElement.Copy() for _, resourceElement := range resourceElements { - patternElementCopy := patternElement.Copy() if err := preProcessRecursive(logger, patternElementCopy, resourceElement); err != nil { logger.V(3).Info("anchor mismatch", "reason", err.Error()) if isConditionError(err) { @@ -163,7 +163,25 @@ func processListOfMaps(logger logr.Logger, pattern, resource *yaml.RNode) error } } } + if resource == nil { + if err := preProcessRecursive(logger, patternElementCopy, resource); err != nil { + logger.V(3).Info("anchor mismatch", "reason", err.Error()) + if isConditionError(err) { + continue + } + + if isGlobalConditionError(err) { + lastGlobalAnchorError = err + } + return err + } + + if hasGlobalConditions { + // global anchor has passed, there is no need to return an error + anyGlobalConditionPassed = true + } + } if !anyGlobalConditionPassed && lastGlobalAnchorError != nil { return lastGlobalAnchorError } diff --git a/test/cli/test-mutate/global-anchor/kyverno-test.yaml b/test/cli/test-mutate/global-anchor/kyverno-test.yaml new file mode 100644 index 000000000000..f7952cc01bd3 --- /dev/null +++ b/test/cli/test-mutate/global-anchor/kyverno-test.yaml @@ -0,0 +1,28 @@ +name: validate-service-loadbalancer +policies: + - policy.yaml +resources: + - resources.yaml +results: + - policy: add-safe-to-evict + rule: annotate-empty-dir + resource: pod-without-emptydir-hostpath + kind: Pod + result: skip + - policy: add-safe-to-evict + rule: annotate-empty-dir + resource: pod-with-emptydir-hostpath + patchedResource: patchedResource.yaml + kind: Pod + result: pass + - policy: add-safe-to-evict + rule: annotate-empty-dir + resource: pod-with-emptydir-hostpath-1 + patchedResource: patchedResource1.yaml + kind: Pod + result: pass + - policy: add-safe-to-evict + rule: annotate-empty-dir + resource: pod-without-emptydir-hostpath-1 + kind: Pod + result: skip diff --git a/test/cli/test-mutate/global-anchor/patchedResource.yaml b/test/cli/test-mutate/global-anchor/patchedResource.yaml new file mode 100644 index 000000000000..46f0a328c381 --- /dev/null +++ b/test/cli/test-mutate/global-anchor/patchedResource.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Pod +metadata: + annotations: + cluster-autoscaler.kubernetes.io/safe-to-evict: "true" + name: pod-with-emptydir-hostpath + namespace: default +spec: + containers: + - image: nginx + name: nginx + volumes: + - name: demo-volume + emptyDir: {} diff --git a/test/cli/test-mutate/global-anchor/patchedResource1.yaml b/test/cli/test-mutate/global-anchor/patchedResource1.yaml new file mode 100644 index 000000000000..477a560930bb --- /dev/null +++ b/test/cli/test-mutate/global-anchor/patchedResource1.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Pod +metadata: + annotations: + cluster-autoscaler.kubernetes.io/safe-to-evict: "true" + name: pod-with-emptydir-hostpath-1 + namespace: default +spec: + containers: + - image: nginx + name: nginx + volumeMounts: + - mountPath: /cache + name: cache-volume + volumes: + - name: cache-volume + emptyDir: + sizeLimit: 500Mi diff --git a/test/cli/test-mutate/global-anchor/policy.yaml b/test/cli/test-mutate/global-anchor/policy.yaml new file mode 100644 index 000000000000..88a057a4fce3 --- /dev/null +++ b/test/cli/test-mutate/global-anchor/policy.yaml @@ -0,0 +1,25 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: add-safe-to-evict + annotations: + policies.kyverno.io/category: Workload Management + policies.kyverno.io/description: The Kubernetes cluster autoscaler does not evict pods that + use hostPath or emptyDir volumes. To allow eviction of these pods, the annotation + cluster-autoscaler.kubernetes.io/safe-to-evict=true must be added to the pods. +spec: + rules: + - name: annotate-empty-dir + match: + any: + - resources: + kinds: + - Pod + mutate: + patchStrategicMerge: + metadata: + annotations: + +(cluster-autoscaler.kubernetes.io/safe-to-evict): "true" + spec: + volumes: + - <(emptyDir): {} diff --git a/test/cli/test-mutate/global-anchor/resources.yaml b/test/cli/test-mutate/global-anchor/resources.yaml new file mode 100644 index 000000000000..545246ab8849 --- /dev/null +++ b/test/cli/test-mutate/global-anchor/resources.yaml @@ -0,0 +1,55 @@ +apiVersion: v1 +kind: Pod +metadata: + name: pod-without-emptydir-hostpath +spec: + containers: + - name: nginx + image: nginx +--- +apiVersion: v1 +kind: Pod +metadata: + name: pod-with-emptydir-hostpath +spec: + containers: + - name: nginx + image: nginx + volumes: + - name: demo-volume + emptyDir: {} +--- +apiVersion: v1 +kind: Pod +metadata: + name: pod-with-emptydir-hostpath-1 +spec: + containers: + - name: nginx + image: nginx + volumeMounts: + - mountPath: /cache + name: cache-volume + volumes: + - name: cache-volume + emptyDir: + sizeLimit: 500Mi +--- +apiVersion: v1 +kind: Pod +metadata: + name: pod-without-emptydir-hostpath-1 +spec: + containers: + - name: nginx + image: nginx + volumeMounts: + - name: config-vol + mountPath: /etc/config + volumes: + - name: config-vol + configMap: + name: log-config + items: + - key: log_level + path: log_level