ArgoCD Plugin Generator was introduced recently.
This feature let's us to create our own generator and extend the functionality of ArgoCD ApplicationSet. The plugin can be written in any language and it should be able to run in a container.
It would make adding new feature to ArgoCD ApplicationSet much easier. plugins can be used in matrix and merge generators to extend functionality of other generators.
For more information the sample repo can be checked.
PullRequest generator is a plugin that can generate an Application for each PR in a Github repository. It checked for labels in PRs and if the labels in PR matches with the labels in ApplicationSet it will create an Application for that PR.
generators: - pullRequest: github: # The GitHub organization or user. owner: araminian # The Github repository repo: BRApplication # Labels is used to filter the PRs that you want to target. (optional) labels: - advertisers requeueAfterSeconds: 180For instance here, We are generating an Application for each PR in BRApplication repository that has advertisers label. The labels is optional and if it is not provided it will generate an Application for each PR in the repository.
In our setup we have an Preview Environment ApplicationSet for each backend service which checks if there is a PR with [ServiceName] as label and if there is a PR with that label it will create an Application for that PR and deploy it to Preview Environment.
Like following example that deploy a preview environment for advertisers service if there is a PR with advertisers label.
generators: - pullRequest: github: # The GitHub organization or user. owner: araminian # The Github repository repo: BRApplication # Labels is used to filter the PRs that you want to target. (optional) labels: - advertisers requeueAfterSeconds: 180A PR can have more than one service label and we want to deploy a Preview Environment for each service label in that PR. For instance if a PR has advertisers and campaigns labels we want to deploy a Preview Environment for each of them.
The label assignment is done by Github Actions. If the PR has a change related to a service it will add that service name as a label to the PR.
There are some scenarios that we don't want a preview environment to be deployed for a PR:
- Saving resources in non-working hours
- No need for preview environment for a
PRthat has a change inREADME.mdor documents - No preview environment needed
Our solution relies on new plugin generator. The idea is to check the PR labels and if the PR has a label defined like no-preview, it will generate Application for that PR and services but not point to the real K8S manifest instead it will point to a blackhole directory that has no K8S manifest in it.
The reason for using blackhole direcotry is that we can't limit PullRequest generator functionallity, but we can limit the path that is used for finding manifests.
The blackhole directory should be created in gitops repo. Here is an example of blackhole directory.
Let see an exmaple of ApplicationSet that uses PullRequestGenerator and applicationset-pr-filter-plugin plugin:
apiVersion: argoproj.io/v1alpha1 kind: ApplicationSet metadata: name: br-pr namespace: argocd spec: goTemplate: true generators: - matrix: generators: - pullRequest: github: # The GitHub organization or user. owner: araminian # The Github repository repo: BRApplication # Labels is used to filter the PRs that you want to target. (optional) labels: - advertisers requeueAfterSeconds: 180 - plugin: configMapRef: name: applicationset-pr-filter-plugin input: parameters: labels: "{{.labels}}" excludeLabel: "no-preview" path: "manifests/app/" blackHole: "manifests/blackhole/" number: "{{.number}}" template: metadata: name: "br-{{.branch}}-{{.number}}" spec: source: repoURL: "https://github.com/araminian/BRApplication.git" targetRevision: HEAD path: "{{.generatedPath}}" directory: include: '{*.yml,*.yaml}' project: "default" destination: server: https://kubernetes.default.svc namespace: "default" syncPolicy: syncOptions: - CreateNamespace=trueThe important part is the plugin generator:
- plugin: configMapRef: name: applicationset-pr-filter-plugin input: parameters: labels: "{{.labels}}" excludeLabel: "no-preview" path: "manifests/app/" blackHole: "manifests/blackhole/" number: "{{.number}}" The configMapRef is defining the configMap that ApplicationSet Controller will use to find the plugin and how it can call it.
The input.parameters is specifying the input that will be passed to the plugin and the plugin will use it to generate the output.
-
The
labelswill be provided byPull Request Generator. It will be a list of labels that are assigned to thePR. -
The
excludeLabelis the label that if it exists inPRwe don't need a preview environment and useblackhole. -
The
pathis the real path that we have our service manifests in it. -
The
blackHoleis the path that we want to use if we don't want a preview environment for aPR. And it's empty directory. -
The
numberis thePRnumber that we want to generateApplicationfor it.
Our logic for plugin:
- Check all
labelsinPRand ifexcludeLabelexists inPR, setgeneratedPathtoblackHolepath. - If
excludeLabeldoesn't exist inPR, setgeneratedPathtopathpath which is the real path that we have our service manifests in it. - Output the
generatedPathasoutputofplugin, which will be available inApplicationSettemplate.
So adding no-preview label to PRs will generate Application for that PR but it will point to blackhole directory which has no K8S manifest in it, which means we don't deploy any Kubernetes resources for that PR.
template: metadata: name: "br-{{.branch}}-{{.number}}" spec: source: repoURL: "https://github.com/araminian/BRApplication.git" targetRevision: HEAD path: "{{.generatedPath}}" directory: include: '{*.yml,*.yaml}' project: "default" destination: server: https://kubernetes.default.svc namespace: "default" syncPolicy: syncOptions: - CreateNamespace=truethe {{.generatedPath}} will be replaced with the output of plugin which is the path that we want to use for generating Application. It can be either blackHole or path.
- Install new version of
argoCD.Plugin Generatorfeature is not available instableversion yet!!
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/master/manifests/core-install.yaml- Install
pluginand it's cofigurations:
for more information about Plugin Generator check here
kubectl apply -f ./manifests- Create
ApplicationSetwithplugingenerator:
- plugin: configMapRef: name: applicationset-pr-filter-plugin input: parameters: labels: "{{.labels}}" excludeLabel: "no-preview" path: "manifests/app/" blackHole: "manifests/blackhole/" number: "{{.number}}"