argoproj / argo-cd

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

Additional values not working with git generator templates #16830

Open mihaigalos opened 11 months ago

mihaigalos commented 11 months ago

Checklist:

Describe the bug

I'm using a generator in a monorepo containing the appset and custom overlays.

component_helm.yaml:

clusters:
  dev:
    name: proj-dex
    namespace: proj-dex
    targetRevision: 2023.51.1
    repoURL: https://do.main/orga/proj-dex-manifest.git

applicationSet.yaml:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: "dev-appset"
  namespace: proj-argocd
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
   - git:
      requeueAfterSeconds: 300
      repoURL: 'https://do.main/orga/proj-mono.git'
      revision: HEAD
      files:
      - path: 'core/*/component_helm.yaml'
      values: # <--------------- This does not get applied in [1]
        stage: 'dev1'
        name: '{{.clusters.dev.name}}'
        namespace: '{{.clusters.dev.namespace}}'
      template:
        metadata: {}
        spec:
          project: proj
          sources:
          - repoURL: '{{.clusters.dev.repoURL}}'
            targetRevision: '{{.clusters.dev.targetRevision}}'
            path: deployment
            helm:
              ignoreMissingValueFiles: true
              valueFiles:
              - $values/all/accounts/account1.yaml
              - $values/{{index .path.segments 0}}/{{index .path.segments 1}}/values.yaml
              - $values/{{index .path.segments 0}}/{{index .path.segments 1}}/clusters/dev.yaml
              - $values/{{index .path.segments 0}}/{{index .path.segments 1}}/stages/dev-dev1.yaml
          - repoURL: 'https://do.main/orga/proj-mono.git'
            targetRevision: HEAD
            ref: values
          destination: {}
template:
    metadata:
      name: '{{.values.name}}' # <----------------- [1] Not getting applied here. 
    spec:
      project: 'proj'
      source:
        targetRevision: '{{.clusters.dev.targetRevision}}'
        repoURL: '{{.clusters.dev.repoURL}}'
        path: 'deployment'
      destination:
        server: https://kubernetes.default.svc
        namespace: '{{.values.stage}}-{{.values.namespace}}' # <----------------- [1] Also not getting applied here.

To Reproduce See above appset.

Expected behavior

Additional values as specified here are consumed by the top-level template. Screenshots

Version

v2.9.3

Logs

rojspencer-e3 commented 10 months ago

Ran in to this myself sort of.

I can set values but none of the data in the file that was found is available.

For example, only way I could see what was going on was to use . and use the value in a helm paramter to see what showed up.

  generators:
    - matrix:
        generators:
          - clusters: {}
          - git:
              repoURL: https://github.com/mycompany/argocd-infra
              revision: HEAD
              files:
                # find all argocd.json files
                - path: 'components/**/argocd.json'
              values:
                # enabled: '{{ or (dig "clusters" .name "enabled" false .) (dig "clusters" "all" "enabled" false .) }}'
                enabled: '{{ . }}'
# ...snip
        - repoURL: '{{ .source.repoURL }}'
          targetRevision: '{{ dig "clusters" .name "chartRevision" .source.targetRevision . }}'
          chart: '{{ dig "source" "chart" "" . }}'
          path: '{{ dig "source" "path" "" . }}'
          helm:
            version: v3
            releaseName: '{{ dig "source" "chart" "" . }}'
            ignoreMissingValueFiles: true
            valueFiles:
              - $values/{{ .path.path }}/values.yaml
              - $values/{{ .path.path }}/values.{{ .name }}.yaml
            parameters:
              - name: "global.additionalLabels.argocd-enabled"
                value: '{{ .values.enabled }}'

This is what got set for .values.enabled:

            map[metadata:map[annotations:map[managed-by:argocd.argoproj.io]
            labels:map[argocd.argoproj.io/secret-type:cluster]]
            name:deployment-prod nameNormalized:deployment-prod
            server:https://kubernetes.default.svc]

In other words, it only saw values from the cluster generator, nothing from the argocd.json file

ixxeL2097 commented 9 months ago

I think I got the same kind of problem. I work with ArgoCD version 2.10.2

Here is my applicationSet :

---
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: stg-apps
  namespace: argocd
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - git:
      repoURL: 'https://gitlab.com/example.git'
      revision: main
      directories:
        - path: 'stg/test/*/*'
      values:
        cluster: in-cluster
  - git:
      repoURL: 'https://gitlab.com/example.git'
      revision: main
      files:
        - path: 'stg/test/{{ index .path.segments 2 }}/{{ .path.basenameNormalized }}/config.json'
  template:
    metadata:
      name: '{{ .path.basenameNormalized }}'
      annotations:
        argocd-image-updater.argoproj.io/app.helm.image-name: '{{ index .path.segments 2 }}.image.name'
        argocd-image-updater.argoproj.io/app.helm.image-tag: '{{ index .path.segments 2 }}.image.tag'
        argocd-image-updater.argoproj.io/app.update-strategy: semver
        argocd-image-updater.argoproj.io/app.allow-tags: 'regexp:{{.regexp}}'
        argocd-image-updater.argoproj.io/git-branch: main
        argocd-image-updater.argoproj.io/image-list: 'app={{.registry}}/{{ .path.basenameNormalized }}'
        argocd-image-updater.argoproj.io/write-back-method: git
        notifications.argoproj.io/subscribe.on-sync-succeeded.slack: infra-deploiements
      finalizers: []
    spec:
      project: test
      destination:
        name: '{{.values.cluster}}'
        namespace: '{{ index .path.segments 1 }}'
      source:
        repoURL: 'https://gitlab.com/example.git'
        path: '{{.path.path}}'
        targetRevision: main
      syncPolicy:
        automated:
          prune: true
          selfHeal: true
        syncOptions:
          - Validate=true
          - PruneLast=false
          - RespectIgnoreDifferences=true
          - Replace=false
          - ApplyOutOfSyncOnly=true
          - CreateNamespace=true
          - ServerSideApply=true

And here is my json file discovered by git file generator:

{
    "regexp": "^v1.[0-9]+.[0-9]+-rc[0-9]+",
    "registry": "europe-west9-docker.pkg.dev/test/example"
}

For some reason I cannot understand, ArgoCD can access regexp but not registry. I get the following error :

failed to execute go template app={{.registry}}/{{ .path.basenameNormalized }}: template: :1:6: executing "" at <.registry>: map has no entry for key "registry"

Any idea on how to solve this ?

P.S: I also tried using these 2 git generators in a matrix but it doesnt help much

mogopz commented 9 months ago

I seem to be hitting the same issue on v2.10.3.

This is my ApplicationSet:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: promtail
  namespace: argocd
spec:
  goTemplate: true
  generators:
    - matrix:
        generators:
          - clusters: {}
            selector:
              matchExpressions:
                - key: server
                  operator: NotIn
                  values:
                    - https://kubernetes.default.svc
          - git:
              repoURL: https://github.com/org/repo
              revision: HEAD
              files:
                - path: 'charts/**/config.yaml'
              values:
                enabled: '{{ dig "clusters" .name "enabled" false . }}'
      # This doesn't work because the values from config.yaml are not available
      selector:
        matchLabels:
          enabled: "true"
  template:
    metadata:
      name: '{{ .name }}-promtail'
    spec:
      project: cluster-services
      sources:
        - repoURL: https://github.com/org/repo
          targetRevision: '{{ dig "clusters" .name "valuesRevision" "HEAD" . }}'
          ref: values
        - repoURL: '{{ .source.repoURL }}'
          targetRevision: '{{ dig "clusters" .name "chartRevision" .source.targetRevision . }}'
          chart: '{{ default "" .source.chart }}'
          path: '{{ default "" .source.path }}'
          helm:
            valueFiles:
              - $values/{{ .path.path }}/values/values.yaml
              - $values/{{ .path.path }}/values/{{ .metadata.labels.environment }}/{{ .name }}.yaml
      destination:
        server: '{{ .server }}'
        namespace: '{{ .destination.namespace }}'
      syncPolicy:
        syncOptions:
          - CreateNamespace=true
          - ApplyOutOfSyncOnly=true
          - ServerSideApply=true
          - FailOnSharedResource=true

And this is my config.yaml:

source:
  repoURL: https://grafana.github.io/helm-charts
  chart: promtail
  targetRevision: 6.15.5
destination:
  namespace: monitoring
clusters:
  my-cluster:
    chartRevision: 6.15.0
    enabled: true

I did the same trick @rojspencer-e3 shared and can confirm it only seems to have the values from the cluster generator.

I was following an article with the same setup that was posted Nov 7th 2023 so it must be a very recently introduced bug (link)

kaos commented 9 months ago

I've found the templating logic broken when using nested generators in combination with gotTemplate syntax, in that the templates are evaluated multiple times (once for each generator, twice for the .values block, if any) so you'd need to add extra levels of escaping.

I've gone through iterations running with a custom argo unit test to find out how many levels of nested I need to escape for our use case, and came up with this, for your reference:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: ...
  namespace: argocd
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
    - matrix:
        generators:
          - clusters:
              values:
                deployment_area: "{{.nameNormalized}}"
          - matrix:
              generators:
                - scmProvider:
                    cloneProtocol: https
                    github:
                      organization: acme
                      api: https://api.github.com/
                      appSecretName: some-credentials
                    filters:
                      - repositoryMatch: "-config$"
                        labelMatch: gitops-deploy-repo
                        pathsExist: [apps]
                    values:
                      project: |-
                        {{`{{ .repository | replace "-config" "" }}`}}
                - git:
                    repoURL: "{{`{{ .url }}`}}"
                    revision: "{{`{{ .branch }}`}}"
                    files:
                      - path: "apps/*/envs/*/{{ .values.deployment_area }}/values.yaml"
                    values:
                      app: |-
                        {{"{{`{{ index .path.segments 1 }}`}}"}}
                      deployment_environment: |-
                        {{"{{`{{ index .path.segments 3 }}`}}"}}
                      # name: `<app>-<deployment_environment>`
                      name: |-
                        {{"{{`{{ index .path.segments 1 }}-{{ index .path.segments 3 }}`}}"}}
                      # default namespace_suffix: `-<deployment_environment>`
                      namespace_suffix: |-
                        {{"{{`{{ if ne ($x := (dig \"namespace_suffix\" nil .)) nil }}{{ $x }}{{ else }}-{{ index .path.segments 3 }}{{ end }}`}}"}}
                      variant: |-
                        {{"{{`{{ dig \"variant\" \"other\" . }}`}}"}}
  template:
    metadata:
      name: "{{ .values.name }}"
      labels:
        app: "{{ .values.app }}"
# ...

I put as much as possible into the .values block to make it easier to reference in the template, and also to reduce churn if we need to change stuff.

blade5502 commented 8 months ago

Running into exact the same issue with argo v2.10.4, values from config.json git generator files are not accessible within the generator, accessing the variables in template works fine though.

Have exactly the same use case of a post generator selector to enable/disable an application for a particular cluster

spec:
  goTemplate: true
  generators:
    - matrix:
        generators:
          - clusters: {}
          - git:
              files:
                - path: cluster-testing/**/.argocd.json
              repoURL: git@github.com:user/my_repo.git
              revision: HEAD
              values:
                enabled: '{{ dig "clusters" .name "enabled" false . }}'
      selector:
        matchLabel:
          enabled: "true"
carlcauchi commented 8 months ago

@blade5502 @mogopz I have the same issue and same use case as yours - did you manage to resolve this by any chance?

memelet commented 8 months ago

@blade5502 is my use case as well. Trying to conditionally enable based on a value in the git discovered file. I can of course use the values in the template, but the selector never matches.

This would seem like the most common use case.

mogopz commented 8 months ago

@blade5502 @mogopz I have the same issue and same use case as yours - did you manage to resolve this by any chance?

For now I'm just filtering clusters in the Cluster Generator until this gets fixed.

h4ckroot commented 7 months ago

Hey, any update on this? I am having the same issue: values does not show any values from the passed in config file!

dolan-a commented 7 months ago

One hacky workaround for the "enabled" filtering is to use nested matrix-generators with a final list-generator for defining the "enabled" parameter.

Here's an example using cluster configs. I'm using an "env" annotation on the cluster-config, but using the cluster-config name (e.g., ".name") should work as well.

apiVersion: v1
kind: Secret
metadata:
  namespace: argocd
  name: cluster-secret
  labels:
    argocd.argoproj.io/secret-type: cluster
  annotations:
    my-org.com/cluster-env: dev
type: Opaque
stringData:
  name: dev-cluster
  server: https://dev-cluster.my-org.com

---
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: cluster-apps
  namespace: argocd
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
    - matrix:
        generators:
          - matrix:
              generators:
                - clusters: {}
                - git:
                    repoURL: https://github.com/my-org/gitops-repo.git
                    revision: main
                    files:
                      - path: 'apps/*/.argocd.yaml'
          - list:
              elements:
                - clusterEnv: '{{ index .metadata.annotations "my-org.com/cluster-env" }}'
                  appEnabled: '{{ dig "clusters" (index .metadata.annotations "my-org.com/cluster-env") "enabled" false . }}'
      selector:
        matchLabels:
          appEnabled: "true"
  template:
    metadata:
    ...

(Also, +1 for .argocd.yaml instead of .argocd.json)

cgarcia-l commented 6 months ago

Same case and same issue... I can't find a way to solve it

ArieLevs commented 5 months ago

Ran in to this myself sort of.

@rojspencer-e3 I have exactly same use case like you described, trying to use cluster + git generators, when the values from git should override all others. with no success, it just does not work.

were you able to find a workaround?

irizzant commented 5 months ago

See also https://github.com/argoproj/argo-cd/issues/17610, it's not possible to use templating in selectors either. Don't know if it may be related to this.

I've tried to do something like https://github.com/argoproj/argo-cd/issues/16830#issuecomment-2088750814 but it does NOT work for me:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: platform
  namespace: argocd
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:  
  - matrix:
      generators:
        - matrix:
            generators:
              - clusters: {}
              - git:
                  repoURL: '{{.metadata.annotations.addons_repo_url}}'
                  revision: '{{.metadata.annotations.addons_repo_revision}}'
                  directories:
                  - path: '{{.metadata.annotations.addons_repo_basepath}}/apps/*/envs/*'
        - list:
            elements:
              - environment: '{{.metadata.labels.environment}}'
    selector:
      matchLabels:
        environment: '{{.path.basename}}'        
reedjosh commented 3 months ago

https://github.com/argoproj/argo-cd/issues/14152

I think setting applyNestedSelectors: true may solve some of these issue.

irizzant commented 3 months ago

I think applyNestedSelectors works in the nested matrix generator, not in the external

- matrix:
    generators:
      - matrix:
          generators:
            - list
                elements:
                  - # (...)
              selector: { } # Only applied when applyNestedSelectors is true
andrii-korotkov-verkada commented 4 weeks ago

ArgoCD versions 2.10 and below have reached EOL. Can you upgrade and let us know if the issue is still present, please?

mra-cfs commented 3 weeks ago

I have seen this issue still present in 2.11.7 and now 2.11.12

juanmancebo commented 2 weeks ago

Similar case there. In my case I need something like this:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: cluster-apps
  namespace: argocd
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
    - matrix:
        generators:
             - scmProvider: {}
             - matrix:
                 generators: 
                     - clusters: {}
                     - git:
                         repoURL: '{{ .url }}'
                         revision: '{{ .branch }}'
                         files:
                           - path: '.deployment/argocd.yaml'
                         values:
                           enabled: '{{ dig "clusters" .name "enabled" false . }}'
       selector:
         matchLabel:
           enabled: "true"
  template: {}
  templatePatch: {}

but I get below error

    message: '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 {{ dig "clusters" .name "enabled
      false . }}: template: :1:18: executing "" at <.name>: map has no entry for key
      name"'
    reason: ApplicationGenerationFromParamsError
blade5502 commented 2 weeks ago

Could only get it to work with the workaround described above by @pydolan using an extra list generator:

spec:
  goTemplate: true
  generators:
    - matrix:
        generators:
          - matrix:
              generators:
                - clusters: {}
                - git:
                    files:
                      - path: cluster-apps/**/.argocd.json
                    repoURL: git@github.com:example/repo.git
                    revision: HEAD
                    values:
                      enabled: '{{ .source.repoURL }}'
          - list:
              elements:
                - appEnabled: '{{ dig "clusters" .name "enabled" false . }}'
      selector:
        matchLabels:
          appEnabled: 'true'
juanmancebo commented 2 weeks ago

Could only get it to work with the workaround described above by @pydolan using an extra list generator:

spec:
  goTemplate: true
  generators:
    - matrix:
        generators:
          - matrix:
              generators:
                - clusters: {}
                - git:
                    files:
                      - path: cluster-apps/**/.argocd.json
                    repoURL: git@github.com:example/repo.git
                    revision: HEAD
                    values:
                      enabled: '{{ .source.repoURL }}'
          - list:
              elements:
                - appEnabled: '{{ dig "clusters" .name "enabled" false . }}'
      selector:
        matchLabels:
          appEnabled: 'true'

Thank you @blade5502 but unless I'm missing something I think this won't work for my case as I need scm+clusters+git. So I don't know how to add this workaround with list to the nested matrix example that I've shared.

blade5502 commented 2 weeks ago

Could only get it to work with the workaround described above by @pydolan using an extra list generator:

spec:
  goTemplate: true
  generators:
    - matrix:
        generators:
          - matrix:
              generators:
                - clusters: {}
                - git:
                    files:
                      - path: cluster-apps/**/.argocd.json
                    repoURL: git@github.com:example/repo.git
                    revision: HEAD
                    values:
                      enabled: '{{ .source.repoURL }}'
          - list:
              elements:
                - appEnabled: '{{ dig "clusters" .name "enabled" false . }}'
      selector:
        matchLabels:
          appEnabled: 'true'

Thank you @blade5502 but unless I'm missing something I think this won't work for my case as I need scm+clusters+git. So I don't know how to add this workaround with list to the nested matrix example that I've shared.

Try that:

spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
    - matrix:
        generators:
             - scmProvider: {}
             - matrix:
                 generators: 
                     - clusters: {}
                     - git:
                         repoURL: '{{ .url }}'
                         revision: '{{ .branch }}'
                         files:
                           - path: '.deployment/argocd.yaml'
             - list:
                 elements:
                   - appEnabled: '{{ dig "clusters" .name "enabled" false . }}'
       selector:
         matchLabel:
           appEnabled: 'true'
  template: {}
  templatePatch: {}
juanmancebo commented 2 weeks ago

Thanks again @blade5502. This will fail as nowadays matrix only supports two child generators as you can see in the docs.