argoproj / applicationset

The ApplicationSet controller manages multiple Argo CD Applications as a single ApplicationSet unit, supporting deployments to large numbers of clusters, deployments of large monorepos, and enabling secure Application self-service.
https://argocd-applicationset.readthedocs.io/
Apache License 2.0
584 stars 278 forks source link

Feature Request: ApplicationSet Generators Should Support Jinja Conditionals #618

Closed zimmertr closed 1 year ago

zimmertr commented 1 year ago

Summary:

When using a generator with an ApplicationSet, for example git, one may wish to conditionally set the Destination of the generated Applications. Jinja2 conditionals normally enable this logic. Argo's usage of Jinja2 conditionals does not support it, however. Consider the following example:


Current Behavior:

Imagine you have Argo deploying Applications to a handful of clusters using an ApplicationSet. We'll name these clusters:

foo-prod-cluster
foo-dev-cluster
foo-staging-cluster

You could then create an Kustomize overlay in your git repository named after the cluster:

applications/example-app/kustomize/overlays/foo-prod-cluster
applications/example-app/kustomize/overlays/foo-dev-cluster
applications/example-app/kustomize/overlays/foo-staging-cluster

And configure your ApplicationSet to reference them with a wildcard:

  - git:
      repoURL: https://myrepo.com/repo
      directories: 
        - path: applications/example-app/kustomize/overlays/*

And then you can reference the destination cluster by name easily using the ApplicationSet's built in path parameter:

spec:
      source:
        repoURL: https://myrepo.com/repo
        path: "{{ path }}" 
      destination:
        name:  "{{ path.basenameNormalized }}"

Now imagine you have a handful of clusters that follow varying naming conventions. Worse yet, imagine their names are long. (Like even longer than these) For example:

foo-foo-bar-bar-prod-cluster
foo-foo-bar-bar-dev-cluster
foo-foo-bar-bar-staging-cluster
bar-bar-foo-foo-management-cluster

If you created overlays for them in your repository it would look like this:

applications/example-app/kustomize/overlays/foo-foo-bar-bar-prod-cluster
applications/example-app/kustomize/overlays/foo-foo-bar-bar-dev-cluster
applications/example-app/kustomize/overlays/foo-foo-bar-bar-staging-cluster
applications/example-app/kustomize/overlays/bar-bar-foo-foo-management-cluster

You can still use the same path parameter to reference them:

spec:
      source:
        repoURL: https://myrepo.com/repo
        path: "{{ path }}" 
      destination:
        name:  "{{ path.basenameNormalized }}"

However, each of your overlays in your git repository must also be long and repetitive. If Argo ApplicationSets supported Jinja Conditionals, this could be cleaned up a lot. For example, your overlays could instead be named:

applications/example-app/kustomize/overlays/prod
applications/example-app/kustomize/overlays/dev
applications/example-app/kustomize/overlays/staging
applications/example-app/kustomize/overlays/management

And you could assemble the cluster name using a conditional in your ApplicationSet:

spec:
      source:
        repoURL: https://myrepo.com/repo
        path: "{{ path }}" 
      destination:
        {% if 'management' == path.basenameNormalized %}
        name: "bar-bar-foo-foo-management-cluster"
        {% else %}
        name: "foo-foo-bar-bar-{{ path.basenameNormalized }}-cluster"
        {% endif %}

Which would make your git repository have less redundancy and appear more legible. I tried to use a Jinja Conditional as expressed above, And Argo returned the following error:

error: error parsing applications/example-app/argocd/example-app-applicationset-git.yml: error converting YAML to JSON: yaml: line 24: found character that cannot start any token

zimmertr commented 1 year ago

Turns out Argo can use Go Text Templating and this can be done like this instead!

destination:
    name: '{{ ternary "bar-bar-foo-foo-management-cluster" (printf "foo-foo-bar-bar-%s-cluster" (.path.basenameNormalized) (eq .path.basenameNormalized "management" ) }}'

https://pkg.go.dev/text/template#hdr-Examples