carvel-dev / ytt

YAML templating tool that works on YAML structure instead of text
https://carvel.dev/ytt
Apache License 2.0
1.68k stars 137 forks source link

Edit a rule in a Kubernetes ClusterRole object #762

Closed damienleger closed 2 years ago

damienleger commented 2 years ago

Hello,

I have this Kubernetes ClusterRole object, I try to edit one rule and add the "list" verb. I don't succeed in having a good #@overlay/match line. I just give up, please help me πŸ™

#@ load("@ytt:overlay", "overlay")
---
kind: ClusterRole
metadata:
  name: test
rules:
- nonResourceURLs:
  - /metrics
  verbs:
  - get
- apiGroups:
  - ""
  resources:
  - nodes/metrics
  - nodes/spec
  - nodes/proxy
  - nodes/stats
  verbs:
  - get
- apiGroups:
  - ""
  resources:
  - endpoints
  verbs:
  - get

#@overlay/match by=overlay.all, expects=1
---
rules:
#!overlay/match by=(lambda x,l,r: "endpoints" in l["resources"])
#@overlay/match by=(lambda x,l,r: yaml.encode([{"resources":["endpoints"]}]) in l, expects=1
- resources:
  - endpoints
  verbs:
  - get
  - list

P.S.: On a side node, I love YTT and array but EVERYTIME I need to work with arrays like this there is zero useful doc it's just a nightmare. This is all about lambda, left, right, index, yamlfragment and stuff. All of this is gibberish to me. I have a really poor understanding of what in "left", and "right" (also this one seems never been used?!) without example. And it's really frustrating to being "obliged" to ask for help for something that seems so basic. I have found something that could help on github issue if only the answer wasn't that enigmatic https://github.com/vmware-tanzu/carvel-ytt/issues/317

mamachanko commented 2 years ago

@damienleger thank you for your feedback! We have empathy for your sentiment πŸ’―.

This should provide you with the desired outcome:

#@ load("@ytt:overlay", "overlay")

---
kind: ClusterRole
rules:
  - apiGroups:
    - ""
    resources:
    - endpoints
    verbs:
    - get
  - apiGroups:
    - other
    resources:
    - other
    verbs:
    - other

#@overlay/match by=overlay.subset({"kind": "ClusterRole"})
---
rules:
  #@overlay/match by=lambda i,l,r: "endpoints" in list(l["resources"]), expects="0+"
  - verbs:
    - list

Yields:

kind: ClusterRole
rules:
- apiGroups:
  - ""
  resources:
  - endpoints
  verbs:
  - get
  - list
- apiGroups:
  - other
  resources:
  - other
  verbs:
  - other

In the larger picture, where or how would you have expected docs on https://carvel.dev/ytt/docs/latest/ ? I am handing you a magic wand πŸͺ„.

damienleger commented 2 years ago

Thanks @mamachanko, I've tweaked a bit for my case and it's working

#@ load("@ytt:overlay", "overlay")
---
kind: ClusterRole
metadata:
  name: test
rules:
- nonResourceURLs:
  - /metrics
  verbs:
  - get
- apiGroups:
  - ""
  resources:
  - nodes/metrics
  - nodes/spec
  - nodes/proxy
  - nodes/stats
  verbs:
  - get
- apiGroups:
  - ""
  resources:
  - endpoints
  verbs:
  - get

#@overlay/match by=overlay.subset({"kind": "ClusterRole"})
---
rules:
  #@overlay/match by=lambda i,l,r: "resources" in l and "endpoints" in list(l["resources"]), expects="0+"
  - verbs:
    - list

In the larger picture, where or how would you have expected docs on https://carvel.dev/ytt/docs/latest/ ? I am handing you a magic wand πŸͺ„.

First of all I'd like to apologize for my not so kind P.S. phrasing. I wrote this issue after 2h+ of battle with the overlay.match and was upset.

About doc, imho

I'd say more explanation of the lambda would be great also, or some specific section for troubleshooting: how to display what's in index/left/right if it's possible. I had zero ideas I needed to use list() function for my case and still not sure actually. I suppose it's because left is yamlfragment https://carvel.dev/ytt/docs/v0.43.0/lang-ref-ytt-overlay/#custom-overlay-matcher-functions . Lambda development looks too much trial-and-error imho.

mamachanko commented 2 years ago

@damienleger Please, do not apologise. ytt's overlays are particularly idiosyncratic - even if powerful πŸ˜„

Thank you very much for sharing your thoughts on documentation. That is terrific feedback. πŸ†

I suppose it's because left is yamlfragment https://carvel.dev/ytt/docs/v0.43.0/lang-ref-ytt-overlay/#custom-overlay-matcher-functions .

Yes, I think you nailed it.

damienleger commented 2 years ago

Before closing, just sharing one of my overlay.yaml that covers lots of examples of what can be done on a k8s Deployment. The last part dealing with lists in the more tricky. I think it can help if you want to enrich the documentation with more k8s examples. ☺️

base yaml: https://raw.githubusercontent.com/kyverno/kyverno/v1.6.3/config/install.yaml

overlay.yaml:

#@ load("@ytt:overlay", "overlay")
#@ load("@ytt:data", "data")

#@overlay/match by=overlay.subset({"kind": "Deployment"})
---
spec:
  replicas: 3
  template:
    metadata:
      #@overlay/match missing_ok=True
      annotations:
        ad.datadoghq.com/kyverno.logs: |-
          [{
            "source": "kyverno",
            "service": "kyverno",
            "log_processing_rules": [{
              "type": "include_at_match",
              "name": "include_validation_errors",
              "pattern" : "ValidationFailureAction"
            }]
          }]
    spec:
      #@overlay/match missing_ok=True
      priorityClassName: system-cluster-critical
      #@overlay/replace
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 100
              podAffinityTerm:
                labelSelector:
                  matchLabels:
                    app.kubernetes.io/name: kyverno
                topologyKey: topology.kubernetes.io/zone
            - weight: 50
              podAffinityTerm:
                labelSelector:
                  matchLabels:
                    app.kubernetes.io/name: kyverno
                topologyKey: kubernetes.io/hostname
      containers:
        #@overlay/match by="name"
        - name: kyverno
          #@overlay/replace
          resources:
            limits:
              memory: 2Gi
            requests:
              cpu: #@ "500m" if data.values.env == "production" else "1000m"
              memory: 1Gi
          args:
            #@overlay/match by=overlay.subset("-v=2")
            #@overlay/replace
            - -v=0

how to run: ytt -f install.yaml -f overlay.yaml --data-value-yaml env="production"

mamachanko commented 1 year ago

Thank you @damienleger !

There are a couple of similar examples in ytt's community space. The fact that you did not encounter them is a sign that we might want to think about aggregating them, or link at the relevant places.

For reference: