argoproj / argo-cd

Declarative Continuous Deployment for Kubernetes
https://argo-cd.readthedocs.io
Apache License 2.0
17.39k stars 5.28k forks source link

Parameter substitution does not work correctly with nested matrix generators in the second child (only when goTemplate=true) #17261

Open ricoapon opened 6 months ago

ricoapon commented 6 months ago

Checklist:

Describe the bug

When using a matrix generator, the parameters from the first child should be substituted in the second child. When using two matrix generators (one nested in the other), you have two options for applying them:

  1. matrix(child1, matrix(child2, child3))
  2. matrix(matrix(child1, child2), child3)

Assuming you have parameter outputs from child1 AND child2 that are used in child3, it should not matter (in theory) which of the options you use. I found out that using the first option does not work when using goTemplate=true, but it does when using goTemplate=false.

To Reproduce

I created a very simple example with only lists that shows the issue.

spec:
  goTemplate: true
  goTemplateOptions: [ "missingkey=error" ]
  generators:
    - matrix:
        generators:
          - list:
              elements:
                - key1: value1
          - matrix:
              generators:
                - list:
                    elements:
                      - key2: value2
                - list:
                    elements:
                      - substitute1: '{{ .key1 }}'
                        substitute2: '{{ .key2 }}'

This is the same as option 1 I mentioned above. And this gives an error: failed to get params for second generator in the matrix generator: child generator returned an error on parameter generation: failed to replace parameters in generator: failed to deeply replace JSON field contents: failed to execute go template {{ .key2 }}: template: :1:3: executing "" at <.key2>: map has no entry for key "key2"

Now when you turn off goTemplate, it works just fine:

spec:
  generators:
    - matrix:
        generators:
         - matrix:
              generators:
                - list:
                    elements:
                      - key1: value1
                - list:
                    elements:
                      - key2: value2
         - list:
             elements:
               - substitute1: '{{ key1 }}'
                 substitute2: '{{ key2 }}'

And if you use option 2, it also works just fine.

spec:
  goTemplate: true
  goTemplateOptions: [ "missingkey=error" ]
  generators:
    - matrix:
        generators:
         - matrix:
              generators:
                - list:
                    elements:
                      - key1: value1
                - list:
                    elements:
                      - key2: value2
         - list:
             elements:
               - substitute1: '{{ .key1 }}'
                 substitute2: '{{ .key2 }}'

Expected behavior

Substitution of parameters for the matrix generator works the same, independent of applied order.

Version

argocd: v2.9.2+c5ea5c4
  BuildDate: 2023-11-20T18:17:07Z
  GitCommit: c5ea5c4df52943a6fff6c0be181fde5358970304
  GitTreeState: clean
  GoVersion: go1.20.11
  Compiler: gc
  Platform: linux/amd64
rarexixi commented 5 months ago

This example will also report an error:failed to get params for second generator in the matrix generator: child generator returned an error on parameter generation: failed to replace parameters in generator: failed to execute go template {{index .metadata.labels "rarexixi/env"}}

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: appset-cm-test-matrix
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - matrix:
      generators:
      - git:
          repoURL: https://gitee.com/rarexixi/argocd-appset-generator.git
          revision: HEAD
          directories:
          - path: config-map/*
          - path: "config-map/logs"
            exclude: true
          values:
            basename: '{{.path.basename}}'
      - clusters:
          selector:
            matchLabels:
              rarexixi/group: dip
          values:
            env: '{{index .metadata.labels "rarexixi/env"}}' # report an error
  template:
    metadata:
      name: 'cm-test-matrix-{{.values.basename}}-{{index .metadata.labels "rarexixi/env"}}' # work well 
      labels:
        appset-name: appset-cm-test-matrix
    spec:
      project: default
      source:
        repoURL: https://gitee.com/rarexixi/argocd-appset-generator.git
        targetRevision: HEAD
        path: "{{.path.path}}"
      destination:
        server: "{{.server}}"
        namespace: dip-system
llavaud commented 5 months ago

I had similar issue and found a workaround by adding an additional layer of Helm templating:

- clusters:
    selector:
      matchLabels:
        rarexixi/group: dip
    values:
      basename: '{{- `{{ index .metadata.labels "rarexixi/env" }}` -}}'

It seems the matrix generator do another round of Helm templating when adding values on the second generator, welcome Helmception... 😵

rarexixi commented 5 months ago

@llavaud Thanks,It works like this:

      - clusters:
          selector:
            matchLabels:
              rarexixi/group: dip
          values:
            env: '{{- printf `{{ index .metadata.labels "rarexixi/env" }}` -}}'
llavaud commented 5 months ago

@llavaud Thanks,It works like this:

      - clusters:
          selector:
            matchLabels:
              chj.cloud/group: dip
          values:
            env: '{{- printf `{{ index .metadata.labels "chj.cloud/env" }}` -}}'

yes I just updated, I pasted my code that live in an Helm Chart, so I have another Helm level ;)