[BUG] Cannot compare precondition expression's value in `foreach`
Software version numbers State the version numbers of applications involved in the bug.
- Kubernetes version: 1.23.3
- Kubernetes platform (if applicable; ex., EKS, GKE, OpenShift): K3d
- Kyverno version: 1.6 main
Describe the bug
A validate.foreach loop using preconditions does not allow existence/non-existence expressions and throws an error like Failed to parse value type doesn't match key type.
To Reproduce Steps to reproduce the behavior:
- Apply this policy:
apiVersion : kyverno.io/v1
kind: ClusterPolicy
metadata:
name: enforce-limits-fraction
spec:
validationFailureAction: enforce
rules:
- name: check-memory-requests-limits
match:
any:
- resources:
kinds:
- Pod
preconditions:
- key: "{{ request.operation }}"
operator: In
value:
- CREATE
- UPDATE
validate:
message: Limits may not exceed 2.5x the requests.
foreach:
- list: "request.object.spec.containers"
preconditions:
all:
- key: "{{ element.resources.limits.memory || '' }}"
operator: NotEquals
value: ""
- key: "{{ element.resources.requests.memory || '' }}"
operator: NotEquals
value: ""
deny:
conditions:
any:
- key: "{{ divide('{{ element.resources.limits.memory }}', '{{ element.resources.requests.memory }}') }}"
operator: GreaterThan
value: 2.5
- Try to apply this resource, which should be blocked yet it is allowed.
apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
containers:
- name: app
image: images.my-company.example/app:v4
resources:
requests:
memory: 100Mi
limits:
memory: 300Mi
- See in the logs it was skipped because the existence check in the preconditions didn't execute:
kyverno-94798cfb-rx5w8 kyverno I0129 22:51:56.120183 1 vars.go:378] EngineValidate "msg"="variable substituted" "kind"="Pod" "name"="frontend" "namespace"="default" "policy"="enforce-limits-fraction" "rule"="check-memory-requests-limits" "path"="/0/key" "value"="CREATE" "variable"="{{ request.operation }}"
kyverno-94798cfb-rx5w8 kyverno I0129 22:51:56.122463 1 vars.go:378] EngineValidate "msg"="variable substituted" "kind"="Pod" "name"="frontend" "namespace"="default" "policy"="enforce-limits-fraction" "rule"="check-memory-requests-limits" "path"="/all/0/key" "value"="300Mi" "variable"="{{ element.resources.limits.memory || '' }}"
kyverno-94798cfb-rx5w8 kyverno I0129 22:51:56.123042 1 vars.go:378] EngineValidate "msg"="variable substituted" "kind"="Pod" "name"="frontend" "namespace"="default" "policy"="enforce-limits-fraction" "rule"="check-memory-requests-limits" "path"="/all/1/key" "value"="100Mi" "variable"="{{ element.resources.requests.memory || '' }}"
kyverno-94798cfb-rx5w8 kyverno E0129 22:51:56.123775 1 notequal.go:84] EngineValidate "msg"="Failed to parse value type doesn't match key type" "error"="parse error: " "kind"="Pod" "name"="frontend" "namespace"="default" "policy"="enforce-limits-fraction" "rule"="check-memory-requests-limits"
kyverno-94798cfb-rx5w8 kyverno I0129 22:51:56.123832 1 validation.go:277] EngineValidate "msg"="skip rule" "kind"="Pod" "name"="frontend" "namespace"="default" "policy"="enforce-limits-fraction" "rule"="check-memory-requests-limits" "reason"="preconditions not met"
Expected behavior
A precondition(s) in foreach.validate should properly allow existence/non-existence checks like they work outside.
Additional context Observed when implementing https://github.com/kyverno/policies/issues/175