argoproj / argo-cd

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

Allows `templatePatch` to load YAML config values #17255

Closed datlife closed 8 months ago

datlife commented 8 months ago

Checklist:

Describe the bug Related to https://github.com/argoproj/argo-cd/pull/14893

templatePatch doesn't reconstruct YAML config properly. Apparently it converts to JSON object first and then converts back to YAML.

To Reproduce

I have argocd config YAML files for different environments to allow ApplicationSet generate applications. This is a sample of the config.yaml

# apps/chatbot/overlays/on-prem-cluster/argocd-config.yaml 
appName: chatbot
env: staging
cluster: 
  name: on-prem-cluster
  namespace: chatbot
autoSync: true
syncPolicy:
  automated:
    prune: true 
    selfHeal: false
    allowEmpty: false

Here is my applicationSet definition:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: chatbot-appset
  namespace: argocd
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - git:
      repoURL: redacted
      revision: redacted
      files:
        - path: apps/chatbot/overlays/*/argocd-config.yaml 
  template:
    metadata:
      name: '{{ .env }}-{{ .appName }}'
    spec:
      project: "chatbot"
      source:
        directory:
          recurse: false
        repoURL:  redacted
        targetRevision:  redacted
        path: '{{.path.path}}'
      destination:
        name: '{{ .cluster.name }}'
        namespace: '{{ .cluster.namespace }}'
  templatePatch: |
    {{- if .autoSync }}
    spec:
      syncPolicy: 
      {{ .syncPolicy | toYaml}}
    {{- end }}

Expected behavior

I expect the templatePatch being able to generate nested YAML objects. In the above example, an application manifest should be as the following:

project: chatbot
source:
  repoURL: redacted
  path: apps/chatbot/overlays/on-prem-cluster
  targetRevision: redacted
destination:
  namespace: chatbot
  name: on-prem-cluster
syncPolicy:
  automated:
    prune: true
    selfHeal: false
    allowEmpty: false

However, in reality, syncPolicy was ignored and empty. However, if I change the templatePatch to this format, it works:

  templatePatch: |
    {{- if .autoSync }}
    spec:
      syncPolicy: 
        automated: 
          prune: {{ .syncPolicy.automated.prune}}
          selfHeal: {{ .syncPolicy.automated.selfHeal}}
          allowEmpty: {{ .syncPolicy.automated.allowEmpty}}
    {{- end }}

Version

$ argocd version     
argocd: v2.10.1+a79e0ea.dirty
  BuildDate: 2024-02-14T22:07:13Z
  GitCommit: a79e0eaca415461dc36615470cecc25d6d38cefb
  GitTreeState: dirty
  GoVersion: go1.21.7
  Compiler: gc
  Platform: darwin/arm64
argocd-server: v2.10.1+a79e0ea.dirty
  BuildDate: 2024-02-14T22:07:13Z
  GitCommit: a79e0eaca415461dc36615470cecc25d6d38cefb
  GitTreeState: dirty
  GoVersion: go1.21.7
  Compiler: gc
  Platform: darwin/arm64
  Kustomize Version: v4.5.4 2022-03-28T23:06:20Z
  Helm Version: v3.13.3+gc8b9489
  Kubectl Version: v0.26.11
  Jsonnet Version: v0.20.0
datlife commented 8 months ago

If I updated the string value of templatePatch to JSON, it works.

  templatePatch: |- 
  {
    {{- if .autoSync }}
    "spec": {
      "syncPolicy": {{ .syncPolicy | toJson}}
    }
    {{- end }}
  }'
crenshaw-dev commented 8 months ago

I'd bet quite a bit of money that the problem is indentation. Helm templates make heavy use of an indent function.

JSON is YAML, so I'd recommend doing this:

  templatePatch: |
    {{- if .autoSync }}
    spec:
      syncPolicy: {{ .syncPolicy | toJson }}
    {{- end }}

As a matter of fact, I'd recommend always piping variables to toJson so that things like strings get properly escaped.

datlife commented 8 months ago

Thanks! In the documentation, it said it accepts YAML object as templatePatch so I thought it would be trivial to use YAML object. I'll stick to JSON format for now

crenshaw-dev commented 8 months ago

YAML is never trivial. 😆 But it was a fair expectation. If you can think of a good docs update that will help others, I'd be happy to review.