argoproj / argo-cd

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

empty strings treated as unset env var in sidecar plugin #18720

Open karlschriek opened 3 months ago

karlschriek commented 3 months ago

Checklist:

Describe the bug

We are using a custom plugin to render manifests in a sidecar plugin. The plugin uses the "ARGOCDENV..." environment variables to render manifests. When we set an env var equal to an empty string, that var does not show up within the plugin at all. There are plenty of legitimate use cases where we want to be able to input an empty string, however as it is now, the plugin will fail because it finds that the environment variable does not exist at all.

To Reproduce

This would be a bit difficult to reproduce without doing an approximate plugin setup. I can provide detailed instructions for that if needed (please let me know). But it might be simpler for someone to just confirm that whenever a config plugin is called with an env var that is set equal to "", that the env var is in fact not passed to the plugin at all.

Expected behavior

I would expect if I set the following

    plugin:
      name: myplugin
      env:
        - name: SOMEVAR
          value: ""
        - name: ANOTHERVAR
          value: "foo"

That the env var ARGOCD_ENV_SOMEVAR is available within the plugin

Version

v2.11.3+3f344d5

Logs

Paste any relevant application logs here.
christianh814 commented 3 months ago

@karlschriek Do you expect ARGOCD_ENV_SOMEVAR to be there but just empty?

karlschriek commented 3 months ago

Yes exactly. There is a difference between an unset var and a var that has been set to an empty string!

crenshaw-dev commented 3 months ago

The proposed behavior makes more sense to me as well. I'd support a PR to fix the bug.

karlschriek commented 2 months ago

I may be mistaken but I suspect this would be quite easy to fix for someone who is familiar with the particular code. Is there someone who would be willing to pick it up?

juwon8891 commented 1 month ago

@karlschriek I'm interested in this issue. Can you tell me how to reproduce it in detail?

karlschriek commented 1 month ago

@juwon8891 the below describes a setup that you can test against.

I've placed some example code in this repo https://github.com/karlschriek/kustomize-gomplate-example. This example uses a plugin that runs kustomize | gomplate. The kustomize part will render yamls from a kustomization.yaml file. This is then piped to gomplate, which will replace placeholders such as {{.Env.ARGOCD_ENV_SOMEVAR}} with the contents of the ARGOCD_ENV_SOMEVAR environment variable.

Below I explain the contents of each folder (and also copy in some of the code here directly)

1. repo-server folder

To configure the repo server with a kustomize | gomplate plugin, here is what you need:

argocd-plugins-cm

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-plugins-cm
data:
  sidecar-plugin-kustomize-gomplate.yaml: |
    apiVersion: argoproj.io/v1alpha1
    kind: ConfigManagementPlugin
    metadata:
      name: sidecar-plugin-kustomize-gomplate
    spec:
      version: v1.0
      init:
      discover:
        fileName: "kustomization.yaml"
      generate:
        command: ["bash", "-c"]
        args:
          - |
            set -eo pipefail && kustomize build . | gomplate

The repo-server would need to look as follows (this is not the full repo-server deployment, just additional changes you need to patch in)

argocd-repo-server.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: argocd-repo-server
spec:
  template:
    spec:
      volumes:
        - name: shared
          emptyDir: {}
        - name: tmp-kustomize-gomplate
          emptyDir: {}
        - name: argocd-plugins-cm
          configMap:
            name: argocd-plugins-cm
      initContainers:
        - name: download-binaries
          image: ubuntu:focal
          command: ["/bin/bash", "-c"]
          args:
            - |
              set -e

              apt-get -qq update
              apt-get -qq upgrade -y
              apt-get -qq install -y wget

              KUSTOMIZE_VER=4.3.0
              echo "Download Kustomize ${KUSTOMIZE_VER}"
              wget https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv${KUSTOMIZE_VER}/kustomize_v${KUSTOMIZE_VER}_linux_amd64.tar.gz
              tar xzf kustomize_v${KUSTOMIZE_VER}_linux_amd64.tar.gz
              chmod +x ./kustomize
              mv ./kustomize /shared/bin/kustomize

              GOMPLATE_VER=3.10.0
              echo "Download Gomplate ${GOMPLATE_VER}"
              wget https://github.com/hairyhenderson/gomplate/releases/download/v${GOMPLATE_VER}/gomplate_linux-amd64
              chmod +x ./gomplate_linux-amd64
              mv ./gomplate_linux-amd64 /shared/bin/gomplate

              echo "Done."
          volumeMounts:
            - mountPath: /shared/bin
              name: shared
              subPath: bin
      containers:
        - name: sidecar-plugin-kustomize-gomplate
          image: ubuntu:22.04
          command: ["/bin/bash", "-c"]
          args:
            - |
              /var/run/argocd/argocd-cmp-server
          volumeMounts:
            - mountPath: /var/run/argocd
              name: var-files
            - mountPath: /home/argocd/cmp-server/plugins
              name: plugins
            - mountPath: /home/argocd/cmp-server/config/plugin.yaml
              subPath: sidecar-plugin-kustomize-gomplate.yaml
              name: argocd-plugins-cm
            - mountPath: /tmp
              name: tmp-kustomize-gomplate
            - mountPath: /usr/local/bin/kustomize
              name: shared
              subPath: bin/kustomize              
            - mountPath: /usr/local/bin/gomplate
              name: shared
              subPath: bin/gomplate 

2. application folder

An example application that would make use of the above is as follows:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: myapp
  namespace: argocd
spec:
  destination:
    namespace: default
    server: https://kubernetes.default.svc
  project: default
  source:
    path: target
    plugin:
      env:
        - name: SOMEVAR
          value: ""
        - name: ANOTHERVAR
          value: "foo"
    repoURL: https://github.com/karlschriek/kustomize-gomplate-example.git
    targetRevision: main
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

3. target folder

This example application points here: https://github.com/karlschriek/kustomize-gomplate-example/tree/main/target

And should render a ConfigMap. The kustomize step should produce this:

apiVersion: v1
kind: ConfigMap
metadata:
  name: myconfig
data:
  someinput: |
    I am inputting {{.Env.ARGOCD_ENV_SOMEVAR}} here and {{.Env.ARGOCD_ENV_ANOTHERVAR}}

After piping to gomplate the final rendered text should be:

apiVersion: v1
kind: ConfigMap
metadata:
  name: myconfig
data:
  someinput: |
    I am inputting here and foo

However, what will actually happen is that the plugin will exit with this error:

ERR  error="failed to render template -: template: -:4:25: executing \"-\" at <.Env.ARGOCD_ENV_SOMEVAR>: map has no entry for key \"ARGOCD_ENV_SOMEVAR\""

Since it will view the ARGOCD_ENV_SOMEVAR var as being unset, rather than being set as an empty string.

juwon8891 commented 1 month ago

Hello @crenshaw-dev Is the pr related to this issue https://github.com/argoproj/argo-cd/pull/19324 ?