notifications-engine icon indicating copy to clipboard operation
notifications-engine copied to clipboard

feat: use url from annotation value for webhook-notification

Open jimtoniq opened this issue 4 years ago • 7 comments

This feature is enabling to set an Webhook-URL within the annotation. The value is already written into Destination.Recipient and now used when it's an valid URL. Can therefore be set from ArgoCD UI.

jimtoniq avatar Sep 16 '21 08:09 jimtoniq

Codecov Report

Merging #46 (5218c34) into master (0e1f1ed) will increase coverage by 0.12%. The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master      #46      +/-   ##
==========================================
+ Coverage   48.21%   48.33%   +0.12%     
==========================================
  Files          29       29              
  Lines        1680     1684       +4     
==========================================
+ Hits          810      814       +4     
  Misses        687      687              
  Partials      183      183              
Impacted Files Coverage Δ
pkg/services/webhook.go 69.35% <100.00%> (+2.11%) :arrow_up:

Continue to review full report at Codecov.

Legend - Click here to learn more Δ = absolute <relative> (impact), ø = not affected, ? = missing data Powered by Codecov. Last update 0e1f1ed...5218c34. Read the comment docs.

codecov[bot] avatar Sep 23 '21 12:09 codecov[bot]

@jimtoniq Would you add docs for this features?

ryota-sakamoto avatar Sep 23 '21 12:09 ryota-sakamoto

@ryota-sakamoto Sure! hope that one is enough

jimtoniq avatar Sep 23 '21 15:09 jimtoniq

Hi Alex, thanks for looking into my PR.

With our webhook-service configuration, we have something like this

  service.webhook.mattermost_webhook: |
    url: https://{mattermost-host}/hooks/{hook-id}
    headers:
    - name: Content-Type
      value: application/json

We want our users to configure their webook-url on their own (via UI with app-annotations), but with the above configuration, we would need to create several webhook-service-configs for each new webhook on many mattermost-channel. The url above shouldn't be optional but a fallback.

With the email-service, its possible (or even required) to set the recipient from annotation, as its read from dest.Recipient https://github.com/argoproj/notifications-engine/blob/0e1f1eda5f52843e21f5b8fb50e4b0ef81bcab2a/pkg/services/email.go#L84 Thats why I tried making use of the dest.Recipient in the webhook-service, as its already read from the annotation and consider it as a overwrite.

I see it as a flexible solution to have the notification-template be the same, with less manual yaml-configuration but custom webhook-urls.

Do you think we would need to make changes to not break other usages? Let me know

jimtoniq avatar Dec 10 '21 15:12 jimtoniq

@jimtoniq , in your use case, is it required to override mattermost host for each recipient? If not then you already can use {{recipient}} in template:

  service.webhook.mattermost_webhook: |
    url: https://{mattermost-host}/hooks/
    headers:
    - name: Content-Type
      value: application/json
  template.<templateName>: |
    webhook:
      <webhook-name>:
        method: POST
        path: /{{recipient}}
        body: |
          <optional-body-template>

So the request will be sent to https://{mattermost-host}/hooks/{{recipient}}

If you need to override whole URL then we need to make a code change. I just realized we can support url field in template - probably this is the cleanest solution and won't break existing behavior

alexmt avatar Dec 10 '21 22:12 alexmt

We would like to set the entire url from the annotation. So that we could have one service and one template for each webhook-service.

Then annotations on the Application can be

notifications.argoproj.io/subscribe.app-health-degraded.mattermost_webhook: https://mymattermost.domain.tld/hooks/abcd1234 for one app, for another one notifications.argoproj.io/subscribe.app-health-degraded.mattermost_webhook: https://anothermattermost.domain.tld/hooks/bcd0123 without having to configure multiple services or templates in our argocd-notifications configuration.

With the current state, we would create two services for the upper example:

service.webhook.mymattermost_webhook: |
    url: https://mymattermost.domain.tld/hooks/abcd1234
    headers:
    - name: Content-Type
      value: application/json
service.webhook.anothermattermost_webhook: |
    url: https://anothermattermost.domain.tld/hooks/bcd0123
    headers:
    - name: Content-Type
      value: application/json

and two redundant webhook-templates

   template.app-health-degraded: |
     email:
       subject: Application {{.app.metadata.name}} has degraded.
     message: |
       {{if eq .serviceType "slack"}}:exclamation:{{end}} Application {{.app.metadata.name}} has degraded.
       Application details: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}.
     webhook:
      mymattermost_webhook:
        method: POST
        body: |
          {
            "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
              }]
            }]
          }
      anothermattermost_webhook:
        method: POST
        body: |
          {
            "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
              }]
            }]
          }

to use them with annotations: notifications.argoproj.io/subscribe.app-health-degraded.mymattermost_webhook: "" notifications.argoproj.io/subscribe.app-health-degraded.anothermattermost_webhook: ""

jimtoniq avatar Dec 13 '21 09:12 jimtoniq

Sorry for the long response @jimtoniq .

Got it . In this case I would recommend adding the url field in webhook template. So you could define mattermost service once and use url: "{{recipient}}" in template to support customizing the full URL.

  service.webhook.mymattermost_webhook: |
    headers:
    - name: Content-Type
      value: application/json
   template.app-health-degraded: |
     webhook:
      mymattermost_webhook:
        method: POST
        url: "{{recipient}}"
        body: |
          {
            "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
              }]
            }]
          }

Does it sounds good?

alexmt avatar Dec 14 '21 23:12 alexmt