argoproj / argo-cd

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

ArogCD Notifications feature parity with FluxCD (v2) for Slack #14226

Open asaf400 opened 1 year ago

asaf400 commented 1 year ago

Summary

Currently ArgoCD notifications (from notification-controller - which is now native) are quite limited in details \ information in regards to slack notification, only specifiying that a sync started | ended | failed.. image

I am referring to several issues:

Motivation

I recently migrated our k8s IaC repo (kustomize based + flux helm operator) from fluxcd v1 to ArgoCD, FluxCD v1 provided a slack notification with detailed information about any change that occurred, and FluxCD v2 while produces a more summarized message, still provides enough information;

here's an example (redacted info) from FluxCD v1:

it specifies which k8s resource was updated during the sync, and if there was image updates in the docker registry, what images tag were deployed. image

it essentially boils down to: for each change (git | kustomzie | image | helm) Why it was triggered (event) What changed/updated

Proposal

todaywasawesome commented 1 year ago

Great idea.

sushank3 commented 1 year ago

Hi, based on the feedback, I have made changes according to the enhancement proposal. I have attached the updated proposal for your review.

The first snippet uses the "fields" property (in two sections) to create a table of information, while the second snippet uses the "blocks" property to create a more structured layout.

Enhancements done:

Snippet 1:

Screenshot from 2023-09-09 13-06-37

Screenshot from 2023-09-09 13-08-16

     "fields": [
      {
        "title": "Sync Status",
        ...
      },
      {
        "title": "Revision",
        ...
      },
      {
        "title": "OperationinitiatedBy",
        ...
      }
      ...
      ...
      ]
    }       
    ]

Snippet 2:

Screenshot from 2023-09-09 13-09-21

Screenshot from 2023-09-09 13-07-23

      "blocks": [

          {
            "type": "section",
            "text": {
              ...
            }
          }, 
          {
            "type": "section",
            "text": {
              ...
            }
          },
          {
            "type": "section",
            "text": {
              ...
            }
          }
        ]
      }
    ]
asaf400 commented 1 year ago

Ohh my, @sushank3 That looks awesome, I'll go over those options with my team, but I see your point there..

Snippet 1 is compact, so it would result in a cleaner slack channel when there are multiple applications or updates in close proximity, so it's more dense, which is a tradeoff, since it may not be easily human readble..

Snippet 2 is more easy on the eyes, but it would result in long messages in a slack channel..

Could you share the Fork/Branch you are working on right now for these snippets? Internally we have cooked something up as well, but it only addresses my 2nd point

ArgoCD Does not specify what was applied during the sync

My teammate rewrote part of the notification template, but it's only that, so it doesn't fix the other problems: sync trigger and revision

asaf400 commented 1 year ago
2023-09-10 10_18_08-sandbox-argocd-notifications - Unit - 7 new items - Slack

This is what my teammate was able to achieve with only modifications for the template, but because the other features required deeper golang changes we did not invest time into that, we had other more pressing matters in our argo integration.

                attachments: |
                  [{
                    "title": "{{ .app.metadata.name}}",
                    "title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
                    "color": "#18be52",
                    "fields": [
                    {
                      "title": "Sync Status",
                      "value": "{{.app.status.sync.status}}",
                      "short": true
                    },
                    {
                      "title": "Repository",
                      "value": "{{.app.spec.source.repoURL}}",
                      "short": true
                    }
                    {{range $index, $r := .app.status.operationState.syncResult.resources}}
                    ,{
                      "title": "Updated Resource",
                      "value": "{{$r.message}}",
                      "short": false
                    }
                    {{end}}
                    ]
                  }]
sushank3 commented 1 year ago

Oh! I think I misunderstood the aspect related to the trigger source.

I've made similar modifications to what your team did, but with a slight difference. Instead of displaying "Updated Resources" for each individual resource, I've opted for using a single title.

I hope this clarifies my approach.


attachments: |
        [
        {
          "mrkdwn_in": ["text", "fields"],
          "text": "*Application:* {{ .app.metadata.name}}\n",
          "color": "#18be52",
          "fields": [
          {
            "title": "Sync status:",
            "value": "{{.app.status.sync.status}}",
            "short": true
          },

          {
            "title": "Revision:",
            "value": "{{.app.status.sync.revision}}",
            "short": true
          },
          {
            "title": "Operation initiated by:",
            "value": "*username:* {{.app.status.operationState.operation.initiatedBy.username}}\n*automated:* {{.app.status.operationState.operation.initiatedBy.automated}}", 
            "short": true 
          }
          ]
        },

        {
          "color": "#18be52",
          "fields": [
            {"title": "Resources updated:"}
            {{range $index, $c := .app.status.operationState.syncResult.resources}}
            {{if not $index}},{{end}}
            {{if $index}},{{end}}
            {
              "value": "+ {{$c.message}}\n",
              "short": true
            }
            {{end}} 
            ]
        },
asaf400 commented 6 months ago

Bump for Argo, This still needs work from Argo and Image-updater..

asaf400 commented 3 weeks ago

The best my team and I have been able to achieve without modifying argocd code is this template for argo-cd (base**) chart:

spec.source.helm.valuesObject.notifications.templates.template.app-sync-succeeded:

              email:
                subject: Application {{.app.metadata.name}} has been successfully synced.
              message: |
                {{- $myList := list -}}
                {{- $images := .app.status.operationState.syncResult.source.kustomize.images -}}

                {{- range $index, $r := .app.status.operationState.syncResult.resources -}}
                    {{- if and (eq $r.status "Synced") (or (eq $r.kind "Deployment") (eq $r.kind "StatefulSet")) (hasSuffix "configured" $r.message) -}}
                        {{- $imageVersion := "unknown" -}} {{/* Default value if not available */}}

                        {{- $resourceName := $r.name -}} {{/* Resource name for matching */}}

                        {{- range $i := $images -}}
                            {{- $imageParts := splitList ":" $i -}} {{/* Split on ':' to separate name and version */}}
                            {{- $imageName := index $imageParts 0 -}} {{/* Extract the name part (before ':') */}}
                            {{- $imageNameParts := splitList "/" $imageName -}} {{/* Split name on '/' to get the last part */}}
                            {{- $finalImageName := index $imageNameParts (sub (len $imageNameParts) 1) -}} {{/* Get the actual image name */}}

                            {{- if eq $resourceName $finalImageName -}} {{/* Match resource name with image name */}}
                                {{- $imageVersion = index $imageParts 1 -}} {{/* Extract the version part (after ':') */}}
                            {{- end -}}
                        {{- end -}}

                        {{- $myList = append $myList (print $r.name " (" $imageVersion ")") -}}
                    {{- end -}}
                {{- end -}}

                {{- if eq .serviceType "slack" -}}
                    Application {{.app.metadata.name}} has been successfully synced at {{.app.status.operationState.finishedAt}}.
                    Sync operation details are available at: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true .

                    Applications Image updates:
                    {{range $name := $myList}}
                        {{- $name}},
                    {{- end -}}
                    have been updated.

                {{- else -}}
                    {{- if gt (len $myList) 0 -}}
                        Applications:
                        {{range $name := $myList}}
                            {{- $name}},
                        {{end}}
                        have been updated
                    {{- end -}}
                {{- end -}}
              slack:
                deliveryPolicy: Post
                groupingKey: ""
                notifyBroadcast: false

Using some funky go-templating and sprig wizardry🧙 we have been able to 'extract' all deployable resource that were updated in the sync cycle, and match each .app.status.operationState.syncResult.source.kustomize.images to deployment name (natively assuming k8s resource names == image repo name)

in order to print the deployed image versions, because devs already know the latest image tag they expect from CD image push, or pre-defined tagging rules (build-id, counter, etc..)

The results are as follows: 2024-08-26 16_31_07-prod-argocd-notifications (Channel) - Unit - Slack

** not to be confused with argo-cd-notifications which is defunct, and is now a zombie project between life and death 🧟 Edit: Semantics