website icon indicating copy to clipboard operation
website copied to clipboard

[Enhancement] Better documentation on variable shortcuts

Open bdowling opened this issue 8 months ago • 1 comments

Description

I was attempting to do what I thought would be a simple task of annotating any mutated objects with the policy and rule that caused the annotation. (I realize this could have issues with cascaded mutations).

However, I found that the shortcuts documentation for relative variables $(./../../foo/bar) seems to be lacking a bit. I spent an unnecessary amount of time trying to do the simple task of annotating mutated records with the policy and rule name, and in the end was unable to figure out how to obtain the policy name. I feel like some of this should be accessible in a more general name.

  1. The documentation only mentions relative URLs, does not mention that absolute References also work $(/name)
  2. The number of levels that you have to go "UP" does not make sense to me given the rule spec.
  3. The whole Policy does not appear to be available, since /name is the rule. I was attempting to access metadata/name for the policy -- Is there any way to gain access to this in the mutation?

I dug into the code a little to look at some of the tests because there appeared to be more examples there than in the docs..

Thanks!

Examples:

apiVersion: v1
kind: Service
metadata:
  name: httpbin-lb
  namespace: test
spec:
  internalTrafficPolicy: Cluster
  ipFamilies:
  - IPv4
  ipFamilyPolicy: SingleStack
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: httpbin
  sessionAffinity: None
  type: LoadBalancer

Policy:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: test-policy
  annotations:
    foo: bar
spec:
  rules:
  - name: test-rule
    match:
      any:
      - resources:
          kinds:
          - Service
    mutate:
      patchStrategicMerge:
        metadata:
          annotations:
            # This fails, tried numerous different ./../../../ etc
            # my.io/kyverno-policy: "$(./../../../../../../../../../metadata/name)"
            my.io/kyverno-rule: "$(./../../../../../../../../name)"
            # The above depth is confusing based on the rule spec.
            # error="policy contains invalid variables: variable substitution failed for rule test-rule: got nil resolved variable $(./../../../../name) at path /mutate/patchStrategicMerge/metadata/annotations/my.io\\/kyverno-rule2: <nil>"
            # my.io/kyverno-rule2: "$(./../../../../name)"
            my.io/kyverno-rule-absolute: "$(/name)"

Results:

policy test-policy applied to test/Service/httpbin-lb:
apiVersion: v1
kind: Service
metadata:
  annotations:
    my.io/kyverno-rule: test-rule
    my.io/kyverno-rule-absolute: test-rule
  name: httpbin-lb
  namespace: test
spec:
  internalTrafficPolicy: Cluster
  ipFamilies:
  - IPv4
  ipFamilyPolicy: SingleStack
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: httpbin
  sessionAffinity: None
  type: LoadBalancer

Slack discussion

No response

bdowling avatar Apr 26 '25 10:04 bdowling

For reference regarding item 2, here's the flattened policy rule:

% yq -o json <test-relative.yaml|gron
json = {};
json.apiVersion = "kyverno.io/v1";
json.kind = "ClusterPolicy";
json.metadata.annotations = {};
json.metadata.annotations.foo = "bar";
json.metadata.name = "test-policy";
...
json.spec.rules[0].match.any[0].resources = {};
json.spec.rules[0].match.any[0].resources.kinds = [];
json.spec.rules[0].match.any[0].resources.kinds[0] = "Service";
json.spec.rules[0].mutate = {};
json.spec.rules[0].mutate.patchStrategicMerge = {};
json.spec.rules[0].mutate.patchStrategicMerge.metadata = {};
json.spec.rules[0].mutate.patchStrategicMerge.metadata.annotations = {};
json.spec.rules[0].mutate.patchStrategicMerge.metadata.annotations["my.io/kyverno-rule"] = "$(./../../../../../../../../name)";
json.spec.rules[0].mutate.patchStrategicMerge.metadata.annotations["my.io/kyverno-rule-absolute"] = "$(/name)";
json.spec.rules[0].name = "test-rule";

Given that, I would expect from the "annotations" that the rule2 annotation would go back 4 dots/levels to reach /name, but as shown in my example, that is not the case.

# error="policy contains invalid variables: variable substitution failed for rule test-rule: got nil resolved variable $(./../../../../name) at path /mutate/patchStrategicMerge/metadata/annotations/my.io\\/kyverno-rule2: <nil>"
           my.io/kyverno-rule2: "$(./../../../../name)"

bdowling avatar Apr 26 '25 10:04 bdowling