Trigger a Codefresh Pipeline from Argo CD

Trigger a Codefresh Pipeline from Argo CD

5 min read

Codefresh is an awesome platform for doing GitOps deployments to Kubernetes. Starting last year, the Codefresh team has been adding rich integrations with Argo CD and Argo Rollouts, GitOps observability dashboards, and more. Codefresh pipelines, in particular, have played an integral role in our customers’ progressive delivery workflows by allowing them to orchestrate all of the testing, analysis, and rollback activities that work in conjunction with Argo CD synchronization.

While it is quite common to have one or two primary pipelines that handle these large workflows, it can also be useful to trigger an occasional helper pipeline, based on events in Argo CD. For example, you might want to trigger a pipeline whenever an Argo CD application enters a failed or error state. Perhaps you’d like such a pipeline to gather a log bundle or open a ticket.

The goal of this article is to show you how you can use events in Argo CD to trigger pipelines in Codefresh.

Prerequisites

To follow along with this article, you should already have a Codefresh account and be using our GitOps Runtime to deploy your Argo CD Applications.

The Argo CD Notifications component is disabled by default. To enable it, add the following Helm values to your GitOps Runtime configuration:

...
  argo-cd:
    notifications:
      enabled: true
      secret:
        create: false
...

Configure Argo CD Notifications

First, let’s update the secret to add an API Key for authenticating to Codefresh. You can create an API Key in the Codefresh UI by navigating to the Settings area at the bottom-left, then User Settings, and then API Keys.

Now go ahead and create the secret:

runtime_ns="<the runtime ns>"
codefresh_token="<the codefresh token>"

kubectl apply -n $runtime_ns -f - << EOF
apiVersion: v1
kind: Secret
metadata:
  name: argocd-notifications-secret
stringData:
  codefresh-token: $codefresh_token
type: Opaque
EOF

Once done, you should see a secret like this:

Next, let’s create a little example pipeline in Codefresh. This is the pipeline that we’ll be triggering from Argo CD Notifications. For illustrative purposes, we’ll have it print out all the “ARGOCD” variables that we’ll be passing in from the event in Argo CD.

version: "1.0"
stages:
  - "test"
steps:
  print_webhook_args:
    title: Print variables passed from Argo CD
    stage: "test"
    image: alpine
    commands:
      - env | grep ARGOCD

After you save the pipeline, click the Settings tab and then copy its PIPELINE ID. We’ll need this in a moment.

pipeline-settings
Pipeline Settings

We’ll be performing all the rest of our configuration in the Helm values of our GitOps Runtime. Let’s go ahead and edit them.

...
  argo-cd:
    notifications:
      enabled: true
      secret:
        create: false
      notifiers:
        # First part of the webhook: URL endpoint + creds
        service.webhook.codefresh: |
          url: https://g.codefresh.io
          headers:
          - name: content-type
            value: application/json
          - name: charset
            value: utf-8
          - name: Authorization
            value: $codefresh-token  # this looks up the key in argocd-notifications-secret
      # Second part of the webhook: REST URL path + data to run the pipeline
      templates:
        template.codefresh-trigger-rollback-pipeline: |
          webhook:
            codefresh:
              method: POST
              path: /api/pipelines/run/myProject%2Example-ArgoCD-Notification ## the last section is the full name of your pipeline: <project_name>/<pipeline_name>, URL-encoded
              body: |
                {
                  "variables": {
                    "ARGOCD_APP_NAME": "{{.app.metadata.name}}",
                    "ARGOCD_APP_URL": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
                    "ARGOCD_APP_STATUS": "{{.app.status.operationState.phase}}",
                    "ARGOCD_SYNC_STATUS": "{{.app.status.sync.status}}",
                    "ARGOCD_SYNC_REVISION": "{{.app.status.sync.revision}}",
                    "ARGOCD_SYNC_START_TIME": "{{.app.status.operationState.startedAt}}",
                    "ARGOCD_GIT_URL": "{{.app.spec.source.repoURL}}"
                  }
                }
                
      triggers: 
        # This trigger ties its specified Argo CD events to the webhook above
        trigger.sync-operation-change: |
          - when: app.status.operationState.phase in ['Error', 'Failed']
            oncePer: app.status.sync.revision
            send: [codefresh-simple-test-pipeline]
      subscriptions:
        - recipients:
          - codefresh:""
          triggers:
          - sync-operation-change

I’ll explain what’s going on in these code blocks. The first two blocks define our webhook which will communicate with Codefresh:

  • service.webhook.codefresh – this service defines the base URL and credentials for connecting to Codefresh. It could be used by multiple templates that make different REST calls to Codefresh.
  • template.codefresh-simple-test-pipeline – this template defines the specific REST URL (appended to the base URL) and data that we’ll use to tell Codefresh to run our specific pipeline. You can see that a large part of this data consists of ARGOCD_ variables that we’ll be able to use within the pipeline.

The third block of code, trigger.sync-operation-change ties some events in Argo CD to the webhook defined in the previous 2 blocks. The events we’re specifying here are Error and Failed sync events.

Finally, we’re adding a default subscription to all Argo CD Applications (subscriptions[0]). You can also granularly define the apps that should get a notification subscription by adding the required annotation. Example:

  • notifications.argoproj.io/subscribe.sync-operation-change.codefresh: ""

Now apply the new configuration to the GitOps Runtime! Whew, we’re almost done. For the Argo CD Notification service to read the updated configuration, we’ll want to restart its pod. Since its pod is controlled by a deployment resource, we can just delete the pod, and the deployment will create a new one for us.

% kubectl get pods
NAME                                               READY   STATUS    RESTARTS   AGE
argocd-application-controller-0                    1/1     Running   0          16d
argocd-dex-server-6dc48777d4-gxrfg                 1/1     Running   0          16d
argocd-notifications-controller-6f8559c959-d949m   1/1     Running   0          5h53m
argocd-redis-66b48966cb-cjgw9                      1/1     Running   0          16d
argocd-repo-server-7b579957d9-2srfq                1/1     Running   0          16d
argocd-server-7fdb567cd4-nngbj                     1/1     Running   0          16d
cf-argocd-agent-fdfc56f7d-hn48x                    1/1     Running   31         14d% 

kubectl -n $runtime_ns delete pod argocd-notifications-controller-6f8559c959-d949m
pod "argocd-notifications-controller-6f8559c959-d949m" deleted

Now we’re ready to test!! To create the failure event we’ve defined, we just need to break a manifest in one of the Git repos that Argo CD is syncing. I chose a manifest in one of my teammate’s repositories… doh, sorry Brandon!

argocd-state
Argo CD state

This should be enough to trigger our pipeline in Codefresh!

Be Happy!

Now go check the output from your awesome new pipeline, which was just triggered by a failed sync event in Argo CD!

freestyle-step
Freestyle step

Wow, that looks great. Look at all the rich Argo CD sync information that our pipeline can now access as variables – totally worth the setup effort. And I’m sure Brandon would agree!

Ready to Get Started?
  • safer deployments
  • More frequent deployments
  • resilient deployments