Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Microsoft deprecating Teams webhooks, new "Workflows" uses incompatible schema #3920

Closed
The-M1k3y opened this issue Jul 9, 2024 · 43 comments · Fixed by #4024
Closed

Microsoft deprecating Teams webhooks, new "Workflows" uses incompatible schema #3920

The-M1k3y opened this issue Jul 9, 2024 · 43 comments · Fixed by #4024

Comments

@The-M1k3y
Copy link

The-M1k3y commented Jul 9, 2024

Update: For a (seemingly functional) workaround see my comment #3920 (comment) below.

Original Issue:

While setting up a new alertmanager - Teams notification via Webhook I noticed a new warning that the current webhook interface will be deprecated.

From August 15th onwards it will not be possible to setup new webhooks.
On October 1st all existing webhooks will stop working.

Details here: https://devblogs.microsoft.com/microsoft365dev/retirement-of-office-365-connectors-within-microsoft-teams/

A few tests show, that the workflow trigger "Teams webhook" uses a different scheme for its data.

schema of new endpoint according to documentation:

{
	"schema": {
		"type": "object",
		"properties": {
			"type": {
				"type": "string"
			},
			"attachments": {
				"type": "array",
				"items": {
					"type": "object",
					"properties": {
						"contentType": {
							"type": "string"
						},
						"content": {
							"type": "object",
							"properties": {
								"$schema": {
									"type": "string"
								},
								"type": {
									"type": "string"
								},
								"version": {
									"type": "string"
								},
								"body": {
									"type": "array",
									"items": {
										"type": "object",
										"properties": {
											"type": {
												"type": "string"
											}
										},
										"required": [
											"type"
										]
									}
								}
							}
						}
					},
					"required": [
						"contentType",
						"content"
					]
				}
			}
		}
	}
}

minimal example of a working request body:

{
	"attachments": [
		{
			"contentType": "application/vnd.microsoft.card.adaptive",
			"content": {
				"body":[
					{
						"type": "TextBlock",
						"text": "**MessageHeader**\n\nThis is a test message 5"
					}
				]
			}
		}
	]
}
@zhan9san
Copy link
Contributor

@The-M1k3y

Thanks for reporting this.

I'll look into it.

@lindeberg
Copy link

Related to: #3503

@The-M1k3y
Copy link
Author

I have built a crude workaround to make the new Flow system accept the "old" data format.

Start by creating a new "Post to a channel when a webhook request is received" Flow, which can be created by clicking on the "Set up workflow" link in the warning message or in power automate directly., then do the following modifications:

  1. Insert a new Action "Compose" (Data Operation) between "When a Teams webhook request is received" and "Send each adaptive card"

  2. Insert the following code in the new Compose Step under Parameters -> Inputs:

[
  {
    "contentType": "application/vnd.microsoft.card.adaptive",
    "content": {
      "body": [
        {
          "type": "TextBlock",
          "weight": "Bolder",
          "size": "ExtraLarge",
          "text": "@{triggerBody()?['title']}"
        },
        {
          "type": "TextBlock",
          "text": "@{triggerBody()?['text']}"
        }
      ],
      "msteams": {
        "width": "Full"
      }
    }
  }
]
  1. Change the Input of the "Send each adaptive card" step (Parameters -> Select An Output From Previous Steps) to the following:
    @outputs('Compose')

  2. Configure the "Post your own adaptive card as the Flow bot to a channel" card to send the message to the correct destination.

Be warned: I have no idea how reliable this will work or what content might get lost. This was my first time ever working with power automate and as far as I can tell it is a piece of s*** with the documentation doing an impressive balancing act between not existing and being completely useless and incomplete.

There seems to be some limitations regarding private channels, but I'm way to annoyed by this whole ordeal to figure it out at the moment. It works in private channels when the message gets sent as the User instead of the Flow Bot as long as the User is a member of the channel.

@Mehdizada
Copy link

Is there any workaround about this issue? i am using msteams_config in alertmanager. Any ideas how to handle it with Workflows?

@aidanhall34
Copy link

Is there any workaround about this issue? i am using msteams_config in alertmanager. Any ideas how to handle it with Workflows?

tl;dr
Plop JSON in the text field and parse it from PowerAutomate.

I am working on a hacky solution atm.
We can use Power automation functions to parse JSON. We can build our own templates in the "text" field of an alert and do whatever is required to process the message in PowerAutomate🙃
image
This is how I define my JSON blob as a template:
tmp/templates/teams.tmpl

{{ define "teams.txt" }}{'foo':'bar'}{{ end }}

Alert Manager config:

receivers:
  - name: "teams"
    msteams_configs:
      - send_resolved: true
        webhook_url: ""
        text: '{{ template "teams.txt" . }}'

templates:
  - /tmp/templates/*.tmpl

Then use PowerAutomate to parse the text field....
image

# PowerFX lang? idk man https://learn.microsoft.com/en-us/power-platform/power-fx/overview
json(trigger().outputs['body']['text'])

Because I can do loops and conditionals, I am thinking of doing my complex alert routing via PowerAutomate with a single webhook instead of creating a webhook per channel.
I really don't know if I can recommend this approach tho :)

@aidanhall34
Copy link

I hate that this works. I feel gross.

I stole a template from this comment:
#3503 (comment)

Defined the template as the text field (see previous comment for how to do that).
Then created the following PowerAutomate workflow
image
Step 1: Create a "When a Teams webhook request is received" flow or whatever it is.
Step 2: Set a variable by reading the text string field and converting it to an object using the json() function (shown above)
Step 3: create a "post card in chat or channel" step, and read the "card" data from the variable.
image
Set the "Adaptive Card" value to the variable you created in step 2.

# Powerfx function
variables("msgs")

Step 4: Profit!
image

@Mehdizada
Copy link

I hate that this works. I feel gross.

I stole a template from this comment: #3503 (comment)

Defined the template as the text field (see previous comment for how to do that). Then created the following PowerAutomate workflow image Step 1: Create a "When a Teams webhook request is received" flow or whatever it is. Step 2: Set a variable by reading the text string field and converting it to an object using the json() function (shown above) Step 3: create a "post card in chat or channel" step, and read the "card" data from the variable. image Set the "Adaptive Card" value to the variable you created in step 2.

# Powerfx function
variables("msgs")

Step 4: Profit! image

thaks for sharing! i tried as u mentioned but failed in 3rd step(
ExpressionEvaluationFailed. The execution of template action 'Send_each_adaptive_card' failed: the result of the evaluation of 'foreach' expression '@variables('msgs')' is of type 'Object'. The result must be a valid array.
)

I am using alertmanager template in the comment you mentioned, and workflows configuration

@g-pichler
Copy link

I have built a crude workaround to make the new Flow system accept the "old" data format.

Start by creating a new "Post to a channel when a webhook request is received" Flow, which can be created by clicking on the "Set up workflow" link in the warning message or in power automate directly., then do the following modifications:

  1. Insert a new Action "Compose" (Data Operation) between "When a Teams webhook request is received" and "Send each adaptive card"
  2. Insert the following code in the new Compose Step under Parameters -> Inputs:
[
  {
    "contentType": "application/vnd.microsoft.card.adaptive",
    "content": {
      "body": [
        {
          "type": "TextBlock",
          "weight": "Bolder",
          "size": "ExtraLarge",
          "text": "@{triggerBody()?['title']}"
        },
        {
          "type": "TextBlock",
          "text": "@{triggerBody()?['text']}"
        }
      ],
      "msteams": {
        "width": "Full"
      }
    }
  }
]
  1. Change the Input of the "Send each adaptive card" step (Parameters -> Select An Output From Previous Steps) to the following:
    @outputs('Compose')
  2. Configure the "Post your own adaptive card as the Flow bot to a channel" card to send the message to the correct destination.

Be warned: I have no idea how reliable this will work or what content might get lost. This was my first time ever working with power automate and as far as I can tell it is a piece of s*** with the documentation doing an impressive balancing act between not existing and being completely useless and incomplete.

There seems to be some limitations regarding private channels, but I'm way to annoyed by this whole ordeal to figure it out at the moment. It works in private channels when the message gets sent as the User instead of the Flow Bot as long as the User is a member of the channel.

In case somebody else encounters the same error. Using this setup, I was confronted with the error AdaptiveCards.AdaptiveSerializationException: Property 'type' must be 'AdaptiveCard'

I adapted the Compose -> Input to

[
  {
      "content": {
      "type": "AdaptiveCard",
      "version": "1.2",
      "body": [
        {
          "type": "TextBlock",
          "weight": "Bolder",
          "size": "ExtraLarge",
          "text": "@{triggerBody()?['title']}"
        },
        {
          "type": "TextBlock",
          "text": "@{triggerBody()?['text']}"
        }
      ],
      "msteams": {
        "width": "Full"
      }
    }
  }
]

Works like a charm. Thanks a lot.

@Mehdizada
Copy link

Mehdizada commented Jul 14, 2024

I have built a crude workaround to make the new Flow system accept the "old" data format.
Start by creating a new "Post to a channel when a webhook request is received" Flow, which can be created by clicking on the "Set up workflow" link in the warning message or in power automate directly., then do the following modifications:

  1. Insert a new Action "Compose" (Data Operation) between "When a Teams webhook request is received" and "Send each adaptive card"
  2. Insert the following code in the new Compose Step under Parameters -> Inputs:
[
  {
    "contentType": "application/vnd.microsoft.card.adaptive",
    "content": {
      "body": [
        {
          "type": "TextBlock",
          "weight": "Bolder",
          "size": "ExtraLarge",
          "text": "@{triggerBody()?['title']}"
        },
        {
          "type": "TextBlock",
          "text": "@{triggerBody()?['text']}"
        }
      ],
      "msteams": {
        "width": "Full"
      }
    }
  }
]
  1. Change the Input of the "Send each adaptive card" step (Parameters -> Select An Output From Previous Steps) to the following:
    @outputs('Compose')
  2. Configure the "Post your own adaptive card as the Flow bot to a channel" card to send the message to the correct destination.

Be warned: I have no idea how reliable this will work or what content might get lost. This was my first time ever working with power automate and as far as I can tell it is a piece of s*** with the documentation doing an impressive balancing act between not existing and being completely useless and incomplete.
There seems to be some limitations regarding private channels, but I'm way to annoyed by this whole ordeal to figure it out at the moment. It works in private channels when the message gets sent as the User instead of the Flow Bot as long as the User is a member of the channel.

In case somebody else encounters the same error. Using this setup, I was confronted with the error AdaptiveCards.AdaptiveSerializationException: Property 'type' must be 'AdaptiveCard'

I adapted the Compose -> Input to

[
  {
      "content": {
      "type": "AdaptiveCard",
      "version": "1.2",
      "body": [
        {
          "type": "TextBlock",
          "weight": "Bolder",
          "size": "ExtraLarge",
          "text": "@{triggerBody()?['title']}"
        },
        {
          "type": "TextBlock",
          "text": "@{triggerBody()?['text']}"
        }
      ],
      "msteams": {
        "width": "Full"
      }
    }
  }
]

Works like a charm. Thanks a lot.

are you using template in alertmanager side? and what integration are u using in alertmanager? is it msteams ?

@g-pichler
Copy link

are you using template in alertmanager side? and what integration are u using in alertmanager? is it msteams ?

I'm using alertmanager v0.27.0 and the relevant "Config" output in the alertmanager status page is

- name: msteams
  msteams_configs:
  - send_resolved: true
    http_config:
      follow_redirects: true
      enable_http2: true
    webhook_url: <secret>
    title: '{{ template "msteams.default.title" . }}'
    summary: '{{ template "msteams.default.summary" . }}'
    text: '{{ template "msteams.default.text" . }}'

@Mehdizada
Copy link

are you using template in alertmanager side? and what integration are u using in alertmanager? is it msteams ?

I'm using alertmanager v0.27.0 and the relevant "Config" output in the alertmanager status page is

- name: msteams
  msteams_configs:
  - send_resolved: true
    http_config:
      follow_redirects: true
      enable_http2: true
    webhook_url: <secret>
    title: '{{ template "msteams.default.title" . }}'
    summary: '{{ template "msteams.default.summary" . }}'
    text: '{{ template "msteams.default.text" . }}'

Great! that works for me also. Thank you!

@vaz-ar
Copy link

vaz-ar commented Jul 15, 2024

FYI for those of us who were using markdown in the content of the teams notifications, the adaptative cards do not support a lot of things, like tables (https://learn.microsoft.com/en-us/adaptive-cards/authoring-cards/text-features):

Not supported

Headers
Tables
Images
Anything not in the table above

@6fears7
Copy link

6fears7 commented Jul 15, 2024

@Mehdizada

re:

ExpressionEvaluationFailed. The execution of template action 'Send_each_adaptive_card' failed: the result of the evaluation of 'foreach' expression '@variables('msgs')' is of type 'Object'. The result must be a valid array.
)

This issue occurred when the final step changed itself to a foreach action instead of a Post to teams:

Below is what you want to confirm:
image

View #3920 (comment) for more details on the var setup

My AM config:

  - name: generic-prometheus-alerts
    msteams_configs:
      - webhook_url: "Workflow_URL"
        text: '{{ template "adaptivePain.text" . }}'

Beginning of Go template:

{{ define "adaptivePain.text" }}
{
    "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
    "type": "AdaptiveCard",
    "version": "1.2",
    "padding": "None",
    "msteams": {
        "width": "Full"
    },
    
    "body": [
        {
            "type": "Container",
            "id": "alert-msg",
            "padding": "Default",
            "items": [
                {
                    "type": "TextBlock",
                    "id": "alert-summary-title",
                    "text": "[{{- if gt (len .Alerts.Firing) 0 }}FIRING: {{ .Alerts.Firing | len }}] 🔥 {{end}} {{- if gt (len .Alerts.Resolved) 0 }}RESOLVED: {{ .Alerts.Resolved | len }}] ✅ {{end}} {{ with index .Alerts 0 -}}{{ .Labels.alertname }}{{ end }}",
                    "weight": "Bolder",
                    "color": "{{- if gt (len .Alerts.Firing) 0 }}Attention{{end}}{{- if gt (len .Alerts.Resolved) 0 }}Good{{end}}",
                    "size": "ExtraLarge",
                    "horizontalAlignment": "Left"
                },
...

Also note: When I tried updating the variable a few times testing different scenarios, it didn't actually save my changes so I was forced to delete the step and remake it.

My brutal Go template does work in this circumstance as a variable with multiple alerts (below is an example of a grouped alert)

image

Obviously not amazing to use that wicked template but may be a workaround for alerts with functionality attached until a better solution is found

@6fears7
Copy link

6fears7 commented Jul 16, 2024

Also be advised all:

Our team decided to try and go the Microsoft Graph route instead to avoid this madness. We were thinking of using Alertmanager to then ship to an intermediary data transformer to then POST via Graph to the appropriate channels.

The only way for this to work is to have your application registration's permission access in Entrant set as a Delegate, not the application context. You cannot set it to the application context, otherwise when you try to do a POST you'll get an error like:

Unauthorized: Message POST is allowed in application-only context only for import purposes

Why does this matter? It means that the application's permission scope, by acting as a delegate, requires your Microsoft Admin to granularly manage permissions. If you operate a relatively large environment...good luck.

@acdha
Copy link

acdha commented Jul 18, 2024

It looks like Teams has some incompatibilities across the product tiers, none of which are documented. I suspect this is something like the enterprise SKUs but did not want to spend time trying to see if they've hidden that information somewhere else on microsoft.com.

The example in #3920 (comment) came close to working for me but it turned out there were a couple of key differences:

  1. There was no existing "Post to a channel when a webhook request is received" flow. I created a new blank one using “When a Teams web hook request is received”, “Compose”, and “Post card in a chat or channel”.

  2. The Compose input parameter in that comment got a parse error. The version of Teams / Workflows which I have access to expects the input to be a single value, not a list, and also has an undocumented restriction on the Adaptive Card 1.4 schema rather than the latest 1.6 version or the 1.5 version claimed in the Adaptive Card designer, which caused it to unhelpfully say the workflow was successful while the card rendered as “We're sorry, this card couldn't be displayed”. This template works for me:

    {
        "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
        "version": "1.4",
        "type": "AdaptiveCard",
        "body": [
            {
                "type": "TextBlock",
                "size": "Medium",
                "weight": "Bolder",
                "text": "@{triggerBody()?['title']}"
            },
            {
                "type": "TextBlock",
                "text": "@{triggerBody()?['text']}",
                "wrap": true
            }
        ]
    }

@philipsabri
Copy link

Does anyone have a solution for sending from Alertmanager without the msteams_configs and instead the normal webhook webhook_configs? We are stuck on an old version of Alertmanager.

@KoffeinKaio
Copy link

Does anyone have a solution for sending from Alertmanager without the msteams_configs and instead the normal webhook webhook_configs? We are stuck on an old version of Alertmanager.

could you maybe use https://github.com/prometheus-msteams/prometheus-msteams ? I dont know if the workarounds here work for that tool

@philipsabri
Copy link

Does anyone have a solution for sending from Alertmanager without the msteams_configs and instead the normal webhook webhook_configs? We are stuck on an old version of Alertmanager.

could you maybe use https://github.com/prometheus-msteams/prometheus-msteams ? I dont know if the workarounds here work for that tool

It did not work with the dynamic URLs as it seems like it's cutting out some parts of the URL.image I will give it a full try, though.

@sherwinwater
Copy link

sherwinwater commented Jul 19, 2024

The following one works for me.
---set up workflow
Adaptive cart template:

{
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "version": "1.4",
  "type": "AdaptiveCard",
  "body": [
    {
      "type": "TextBlock",
      "size": "Medium",
      "weight": "Bolder",
      "text": "@{triggerBody()?['title']}"
    },
    {
      "type": "TextBlock",
      "text": "@{triggerBody()?['text']}",
      "wrap": true
    }
  ]
}
image

outputs('Compose')

image

alertmanager.yml

  - name: 'prometheus-msteams'
    msteams_configs:
      - send_resolved: true
        webhook_url: 'xxxxx'

in alertmanager.yml, don't use templates:

#templates:
#  - '/etc/alertmanager/templates/msteam.tmpl'

@MajorP93
Copy link

Thanks @The-M1k3y , @acdha and everyone else who shared their solution with the community in this issue.

I was finally able to get MS Teams alerts to work with the workflows feature :-).

@abhi-ganesh
Copy link

How can I prevent my title from being cut off like this towards the end and make it go to a new line instead? -

image

@lzdohh
Copy link

lzdohh commented Jul 23, 2024

@sherwinwater Change msteam.tmpl to the following or do not define msteam.tmpl, you should receive an alert

{{ define "__subject" }}[{{ .Status | toUpper }}{{ if eq .Status "firing" }}:{{ .Alerts.Firing | len }}{{ end }}]{{ end }}

{{ define "msteams.default.summary" }}{{ template "__subject" . }}{{ end }}
{{ define "msteams.default.title" }}{{ template "__subject" . }}{{ end }}
{{ define "msteams.default.text" }}
{{ if gt (len .Alerts.Firing) 0 }}
# Alerts Firing:
- Alertname: {{ (index .Alerts.Firing 0).Labels.alertname }}
{{ range .Alerts.Firing }} - {{ .Annotations.description }}
{{ end }}
{{ end }}
{{ if gt (len .Alerts.Resolved) 0 }}
# Alerts Resolved:
- Alertname: {{ (index .Alerts.Resolved 0).Labels.alertname }}
{{ range .Alerts.Resolved }} - {{ .Annotations.description }}
{{ end }}
{{ end }}
{{ end }}

@sherwinwater
Copy link

@sherwinwater Change msteam.tmpl to the following or do not define msteam.tmpl, you should receive an alert

{{ define "__subject" }}[{{ .Status | toUpper }}{{ if eq .Status "firing" }}:{{ .Alerts.Firing | len }}{{ end }}]{{ end }}

{{ define "msteams.default.summary" }}{{ template "__subject" . }}{{ end }}
{{ define "msteams.default.title" }}{{ template "__subject" . }}{{ end }}
{{ define "msteams.default.text" }}
{{ if gt (len .Alerts.Firing) 0 }}
# Alerts Firing:
- Alertname: {{ (index .Alerts.Firing 0).Labels.alertname }}
{{ range .Alerts.Firing }} - {{ .Annotations.description }}
{{ end }}
{{ end }}
{{ if gt (len .Alerts.Resolved) 0 }}
# Alerts Resolved:
- Alertname: {{ (index .Alerts.Resolved 0).Labels.alertname }}
{{ range .Alerts.Resolved }} - {{ .Annotations.description }}
{{ end }}
{{ end }}
{{ end }}

@lzdohh Thank you so much. It works for me after I remove the msteam.tmpl. thanks.

@bbenouarets
Copy link

The deadline was actually extended. However, the URL of the webhooks must be updated again by December 31, 2024.

If other system administrators are having difficulties locating the affected teams:
I have written a small tool in Golang that uses the Graph API to output the affected teams.

Teams Webhook Finder

This has helped us enormously, as Microsoft does not offer its own solution for reading the affected channels and teams. We have over 350 teams in our company, which we would otherwise have had to search through manually.

I hope I could help someone here with this.

Independently of my day job, I would like to create an alternative to the native “incoming webhooks”. Maybe someone will benefit from it.

@mr-vadyus
Copy link

Does anyone have a solution for sending from Alertmanager without the msteams_configs and instead the normal webhook webhook_configs? We are stuck on an old version of Alertmanager.

could you maybe use https://github.com/prometheus-msteams/prometheus-msteams ? I dont know if the workarounds here work for that tool

It did not work with the dynamic URLs as it seems like it's cutting out some parts of the URL.image I will give it a full try, though.

You just need to decode the webhook endpoint link, decode the url, you can use this online service https://amp.urldecoder.org/, after that a you need to paste clean url in the config, this helped me bypass the utl problem.

Thank you everyone for sharing your solution, I’m happy because I’m understanding I’m not self with this problem.

@maneeshcdls
Copy link

I hate that this works. I feel gross.

I stole a template from this comment: #3503 (comment)

Defined the template as the text field (see previous comment for how to do that). Then created the following PowerAutomate workflow image Step 1: Create a "When a Teams webhook request is received" flow or whatever it is. Step 2: Set a variable by reading the text string field and converting it to an object using the json() function (shown above) Step 3: create a "post card in chat or channel" step, and read the "card" data from the variable. image Set the "Adaptive Card" value to the variable you created in step 2.

# Powerfx function
variables("msgs")

Step 4: Profit! image

@6fears7 I tried this method but got below error
image
any idea how to fix it

@Matelin
Copy link

Matelin commented Jul 30, 2024

@maneeshcdls Does it happen for every alert or only for some?
I was dealing with the simmilar issue a short while ago. Take a closer look at the output produced by "When a Teams webhook request is received" workflow step - especially the description/summary text being put into the request's body insite the "text:" fields. Some alerts may have bad characters in them, like nested quotes or illegal line breaks. I had this issue with built-in Watchdog and Infoinhibitor alerts. Needed to fix the actual description of the alert in defintions.

image

@cassanellicarlo
Copy link

I could successfully send OpenShift Alerts to Microsoft Teams channels using the following:

image

Adaptive Card Template

{
  "type": "AdaptiveCard",
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "version": "1.4",
  "body": [
    {
      "type": "TextBlock",
      "size": "Medium",
      "weight": "Bolder",
      "text": "@{triggerBody()?['title']}",
      "wrap": true
    },
    {
      "type": "TextBlock",
      "text": "@{triggerBody()?['text']}",
      "wrap": true
    }
  ]
}

AlertManager Configuration

  - name: MSTeams
    msteams_configs:
      - webhook_url: <your_url>
        send_resolved: true
        title: "OKD TST Alarm {{ if eq .Status \"firing\" }}\U0001F6A8 FIRING \U0001F6A8{{- else -}}✅ RESOLVED ✅{{- end -}}"
        text: |-
          [OKD Alerting]({{ .ExternalURL }})
          {{ range .Alerts }}
            **Alert**: {{ .Annotations.summary }}
 
            **Severity**: {{ .Labels.severity }}
 
            **Description**: {{ .Annotations.description }}
 
            **Details**:
             
            {{ range .Labels.SortedPairs }} **{{ .Name }}**: {{ .Value }}
 
            {{ end }}
          {{ end }}

Example Card

image

@ronenl1
Copy link

ronenl1 commented Aug 8, 2024

How can I prevent my title from being cut off like this towards the end and make it go to a new line instead? -

image

Adding the msteams width:full to Compose step allowed me to have enough space so the title won't cut off:

{
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "version": "1.4",
  "type": "AdaptiveCard",
  "body": [
    {
      "type": "TextBlock",
      "size": "Medium",
      "weight": "Bolder",
      "text": "@{triggerBody()?['title']}"
    },
    {
      "type": "TextBlock",
      "text": "@{triggerBody()?['text']}",
      "wrap": true
    }
  ],
  "msteams": {
    "width": "Full"
  }
}

@bhargavsangabattula
Copy link

Hi Everyone,
Can you please help to suggest how to remove Lables: and Annotations: titles from alerts and also how to add Sources: URL links as button. As I am using below code.
{
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.4",
"type": "AdaptiveCard",
"body": [
{
"type": "TextBlock",
"size": "Medium",
"weight": "Bolder",
"text": "@{triggerBody()?['title']}"
},
{
"type": "TextBlock",
"text": "@{triggerBody()?['text']}",
"wrap": true
}
],
"msteams": {
"width": "Full"
}
}

@SaurabhKoverhoop
Copy link

Hi Bhargav,
The text that is being passed on to the adaptive card, @{triggerBody()?['text']}, needs to be parsed. You can do this by defining custom functions in the Power Automate workflow.
My apologies for the very brief answer, but I will try and update this later today.

@bhargavsangabattula
Copy link

Hi Bhargav, The text that is being passed on to the adaptive card, @{triggerBody()?['text']}, needs to be parsed. You can do this by defining custom functions in the Power Automate workflow. My apologies for the very brief answer, but I will try and update this later today.

Thanks @SaurabhKoverhoop

@yykudrin
Copy link

my way was like this

Teams Workflow Setup

  1. Navigate to Teams Workflows

  2. Create New Workflow

  3. Go to Data Collection

  4. Select Post to a channel when a webhook request is received

  5. Fill in the Flow Name

  6. Choose the Team

  7. Choose the Channel

  8. Click Create Flow

  9. Copy the request URL:

    https://prod-11.southeastasia.logic.azure.com:443/workflows/7e2c2dc8cc4a4678b1113ede1d55d5a1/triggers/manual/paths/invoke?api-version=2016-06-01&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=c-3iiBjByin64STF8bVGeRrjAu6qhGR7QAs_wZ-aF4Q
    
    • Done!
  10. Edit the Workflow

  11. Go to Workflows

  12. Choose the created workflow

  13. Click Edit

  14. Between When a Teams webhook request is received and Send each adaptive card and one more step, add an action:

  15. In the search field, enter Compose

  16. In the input field, enter the following JSON:

    [
      {
        "contentType": "application/vnd.microsoft.card.adaptive",
        "content": {
          "body": [
            {
              "type": "TextBlock",
              "weight": "Bolder",
              "size": "Large",
              "text": "@{triggerBody()?['title']}"
            },
            {
              "type": "TextBlock",
              "text": "@{triggerBody()?['text']}"
            }
          ],
          "msteams": {
            "width": "Full"
          }
        }
      }
    ]
  17. Click on Send each adaptive card

  18. In the field Select an output from previous steps, enter:

    outputs('Compose')
    
  19. Click OK

  20. Then click Post card in a chat or channel and choose the right user from whom messages will come (I chose User).

  21. Click Save

Alertmanager Configuration

  1. Go to Alertmanager Config

  2. Add Receiver

    • Add the following configuration:

      - name: "test-team"
        msteams_configs:
          - webhook_url: "<webhook from first step>"
            send_resolved: true
            text: '{{ template "msteams.alert" . }}'
  3. Add Template for Text

    • Here is a simple template that includes all the needed information:

      {{ define "msteams.alert" }}
      **Alert**: {{ .CommonLabels.alertname }}
      
      **Severity**: {{ .CommonLabels.severity }}
      
      **Instance**: {{ .CommonLabels.instance }}
      
      {{ range .Alerts }}
        **Description**: {{ .Annotations.description }}
        **Summary**: {{ .Annotations.summary }}
      
        {{ if .StartsAt }}**Started At**: {{ .StartsAt }}{{ end }}
      
        {{ if .EndsAt }}**Ended At**: {{ .EndsAt }}{{ end }}
      
      {{ end }}
      
      **Alertmanager URL**: {{ .ExternalURL }}
      
      {{- if eq .Status "firing" -}}
      [Silence this alert]({{ .ExternalURL }}/#/silences/new?filter=%7B{{- range .CommonLabels.SortedPairs -}}{{- if ne .Name "alertname" -}}{{- .Name }}%3D%22{{- .Value -}}%22%2C%20{{- end -}}{{- end -}}alertname%3D%22{{ .CommonLabels.alertname }}%22%7D)
      {{- end }}
      {{ end }}

ISTIO (optional)

don't forget make domain for webhooks accessible (prod-11.southeastasia.logic.azure.com in this case)

 apiVersion: networking.istio.io/v1alpha3
 kind: ServiceEntry
 metadata:
   name: teams-webhook
 spec:
   hosts:
     - prod-11.southeastasia.logic.azure.com
   ports:
     - name: https
       number: 443
       protocol: HTTPS
   location: MESH_EXTERNAL
   resolution: DNS
   exportTo:
     - "."

@odcheck
Copy link

odcheck commented Aug 29, 2024

@yykudrin thanks for your input , do we miss something at step 18 ? it is yellin' this ain't a correct array if we insert "outputs('Compose')"

@satyamkapoor
Copy link

@odcheck select the Outputs option under compose appearing in Dynamic content.
image

@yykudrin
Copy link

yykudrin commented Sep 4, 2024

@odcheck select the Outputs option under compose appearing in Dynamic content. image

@yykudrin thanks for your input , do we miss something at step 18 ? it is yellin' this ain't a correct array if we insert "outputs('Compose')"

it is Expression

sschne pushed a commit to sschne/alertmanager that referenced this issue Sep 5, 2024
sschne pushed a commit to sschne/alertmanager that referenced this issue Sep 6, 2024
sschne added a commit to sschne/alertmanager that referenced this issue Sep 6, 2024
Signed-off-by: Simon Schneider <github@simon-schneider.eu>
sschne added a commit to sschne/alertmanager that referenced this issue Sep 6, 2024
Signed-off-by: Simon Schneider <github@simon-schneider.eu>
@khanhnt99
Copy link

I have built a crude workaround to make the new Flow system accept the "old" data format.

Start by creating a new "Post to a channel when a webhook request is received" Flow, which can be created by clicking on the "Set up workflow" link in the warning message or in power automate directly., then do the following modifications:

  1. Insert a new Action "Compose" (Data Operation) between "When a Teams webhook request is received" and "Send each adaptive card"
  2. Insert the following code in the new Compose Step under Parameters -> Inputs:
[
  {
    "contentType": "application/vnd.microsoft.card.adaptive",
    "content": {
      "body": [
        {
          "type": "TextBlock",
          "weight": "Bolder",
          "size": "ExtraLarge",
          "text": "@{triggerBody()?['title']}"
        },
        {
          "type": "TextBlock",
          "text": "@{triggerBody()?['text']}"
        }
      ],
      "msteams": {
        "width": "Full"
      }
    }
  }
]
  1. Change the Input of the "Send each adaptive card" step (Parameters -> Select An Output From Previous Steps) to the following:
    @outputs('Compose')
  2. Configure the "Post your own adaptive card as the Flow bot to a channel" card to send the message to the correct destination.

Be warned: I have no idea how reliable this will work or what content might get lost. This was my first time ever working with power automate and as far as I can tell it is a piece of s*** with the documentation doing an impressive balancing act between not existing and being completely useless and incomplete.

There seems to be some limitations regarding private channels, but I'm way to annoyed by this whole ordeal to figure it out at the moment. It works in private channels when the message gets sent as the User instead of the Flow Bot as long as the User is a member of the channel.

Thank you for this. I use this config, in PC work fine but the message not appear on my ios msteam app.

@Lddeiva
Copy link

Lddeiva commented Sep 16, 2024

Hi All, Greetings! When are we expecting the schema changes to be available in the alert manager code so that we can avoid these manual workarounds?

@459below
Copy link

459below commented Oct 9, 2024

Hi everyone,

I created a working workflow which uses the Alertmanager's webhook receiver instead of msteams receiver. I wanted to avoid the alerting getting broken when either Microsoft changes something or Prometheus patches the schema of the msteams receiver. I read multiple times that the webhook receiver is planned to stay fixed in the format of the payload. I also plan on using this workflow to connect Google Alerting to Microsoft Teams as well.

And instead of a third-party middleware to transform Alertmanager's webhook payload, I used the functionality of Workflows directly.

The resulting rendered post in the Teams channel:
image

This is what the workflow looks like:
image

I would have liked to have only one "append to array" in the ForEach segment which adds all the TextBlocks at in a single iteration, but for me the formatting of the JSON got a little mangled. If someone would like to share a hint on this, I would be grateful.

Using this example JSON:

Webhook receiver payload
{
  "version": "4",
  "groupKey": "{}/{alertname=\"HighCPUUsage\"}",
  "status": "firing",
  "receiver": "webhook_receiver",
  "groupLabels": {
    "alertname": "HighCPUUsage"
  },
  "commonLabels": {
    "severity": "critical"
  },
  "commonAnnotations": {
    "summary": "Multiple alerts are firing for high CPU usage."
  },
  "alerts": [
    {
      "status": "firing",
      "labels": {
        "alertname": "HighCPUUsage",
        "severity": "critical",
        "instance": "server-01"
      },
      "annotations": {
        "summary": "High CPU usage detected on instance server-01",
        "description": "CPU usage on instance server-01 has exceeded 90% for the past 5 minutes."
      },
      "startsAt": "2024-10-04T10:00:00Z",
      "endsAt": "0001-01-01T00:00:00Z",
      "generatorURL": "http://localhost:9090/graph?g0.expr=instance_cpu_usage%3E90&g0.tab=1"
    },
    {
      "status": "firing",
      "labels": {
        "alertname": "HighCPUUsage",
        "severity": "critical",
        "instance": "server-02"
      },
      "annotations": {
        "summary": "High CPU usage detected on instance server-02",
        "description": "CPU usage on instance server-02 has exceeded 85% for the past 5 minutes."
      },
      "startsAt": "2024-10-04T10:01:00Z",
      "endsAt": "0001-01-01T00:00:00Z",
      "generatorURL": "http://localhost:9090/graph?g0.expr=instance_cpu_usage%3E85&g0.tab=1"
    },
    {
      "status": "firing",
      "labels": {
        "alertname": "HighCPUUsage",
        "severity": "critical",
        "instance": "server-03"
      },
      "annotations": {
        "summary": "High CPU usage detected on instance server-03",
        "description": "CPU usage on instance server-03 has exceeded 30% for the past 15 minutes."
      },
      "startsAt": "2024-10-04T10:02:00Z",
      "endsAt": "0001-01-01T00:00:00Z",
      "generatorURL": "http://localhost:9090/graph?g0.expr=instance_cpu_usage%3E80&g0.tab=1"
    }
  ],
  "externalURL": "http://localhost:9093",
  "version": "4",
  "receiver": "webhook_receiver"
}

This workflow will work very well for me:

  1. TeamsWebhook
  2. InitializeVariable
    • (Variable) Name: Formatted Alert Messages
    • Type: Array
  3. ParseJson
Schema
{
  "type": "ParseJson",
  "inputs": {
    "content": "@triggerBody()",
    "schema": {
      "type": "object",
      "properties": {
        "version": {
          "type": "string"
        },
        "groupKey": {
          "type": "string"
        },
        "status": {
          "type": "string"
        },
        "receiver": {
          "type": "string"
        },
        "groupLabels": {
          "type": "object",
          "properties": {
            "alertname": {
              "type": "string"
            }
          }
        },
        "commonLabels": {
          "type": "object",
          "properties": {
            "severity": {
              "type": "string"
            }
          }
        },
        "commonAnnotations": {
          "type": "object",
          "properties": {
            "summary": {
              "type": "string"
            }
          }
        },
        "alerts": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "status": {
                "type": "string"
              },
              "labels": {
                "type": "object",
                "properties": {
                  "alertname": {
                    "type": "string"
                  },
                  "severity": {
                    "type": "string"
                  },
                  "instance": {
                    "type": "string"
                  }
                }
              },
              "annotations": {
                "type": "object",
                "properties": {
                  "summary": {
                    "type": "string"
                  },
                  "description": {
                    "type": "string"
                  }
                }
              },
              "startsAt": {
                "type": "string"
              },
              "endsAt": {
                "type": "string"
              },
              "generatorURL": {
                "type": "string"
              }
            },
            "required": [
              "status",
              "labels",
              "annotations",
              "startsAt",
              "endsAt",
              "generatorURL"
            ]
          }
        },
        "externalURL": {
          "type": "string"
        }
      }
    }
  },
  "runAfter": {
    "Initialize_array_formatted_alert_messages": [
      "Succeeded"
    ]
  }
}
  1. Foreach
    • Input: @outputs('Parse_JSON')?['body']?['alerts']
  2. AppendToArrayVariable
    • Action Name: Append 'labels.instance' to message
    • (Input Variable) Name: Formatted Alert Messages
Value
{
  "type": "TextBlock",
  "text": "🖥️:  **Instance:** @{items('For_each')?['labels']?['instance']}",
  "weight": "Bolder",
  "wrap": true
}
  1. AppendToArrayVariable
    • Action Name: Append 'labels.severity' to message
    • (Input Variable) Name: Formatted Alert Messages
Value
{
  "type": "TextBlock",
  "text": "**Severity:** @{items('For_each')?['labels']?['severity']}",
  "wrap": true
}
  1. AppendToArrayVariable
    • Action Name: Append 'status' to message
    • (Input Variable) Name: Formatted Alert Messages
Value
{
  "type": "TextBlock",
  "text": "**Status:** @{items('For_each')?['status']}",
  "wrap": true
}
  1. AppendToArrayVariable
    • Action Name: Append 'labels.severity' to message
    • (Input Variable) Name: Formatted Alert Messages
Value
{
  "type": "TextBlock",
  "text": "**Summary:** @{items('For_each')?['annotations']?['summary']}",
  "wrap": true
}
  1. AppendToArrayVariable
    • Action Name: Append 'annotations.description' to message
    • (Input Variable) Name: Formatted Alert Messages
Value
{
  "type": "TextBlock",
  "text": "**Description:** @{items('For_each')?['annotations']?['description']}",
  "wrap": true
}
  1. AppendToArrayVariable
    • Action Name: Append 'startsAt' to message
    • (Input Variable) Name: Formatted Alert Messages
Value
{
  "type": "TextBlock",
  "text": "**Starts At:** @{items('For_each')?['startsAt']}",
  "wrap": true
}
  1. AppendToArrayVariable
    • Action Name: Append 'endsAt' to message
    • (Input Variable) Name: Formatted Alert Messages
Value
{
  "type": "TextBlock",
  "text": "**Ends At:** @{items('For_each')?['endsAt']}",
  "wrap": true
}
  1. AppendToArrayVariable
    • Action Name: Append 'generatorURL' to message
    • (Input Variable) Name: Formatted Alert Messages
Value
{
  "type": "ActionSet",
  "actions": [
    {
      "type": "Action.OpenUrl",
      "title": "View Details",
      "url": "@{items('For_each')?['generatorURL']}"
    }
  ]
}
  1. AppendToArrayVariable
    • Action Name: Append seperator to message
    • (Input Variable) Name: Formatted Alert Messages
Value
{
  "type": "TextBlock",
  "text": "---",
  "separator": true
}
  1. Compose
    • Action Name: Compose final AdaptiveCard
    • (Input Variable) Name: Formatted Alert Messages
Input
{
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "type": "AdaptiveCard",
  "version": "1.3",
  "msteams": {
    "width": "Full"
  },
  "body": @{variables('Formatted Alert Messages')}
}
16. Post card in a chat or channel

@Lddeiva
Copy link

Lddeiva commented Oct 25, 2024

Anyone looking at #4024 can use this to expedite the deployment of the new Microsoft Teams v2 receiver configuration with workflows (for migrating connectors to workflows). I tested it today.

Note: Please use the release channel version only for testing, and wait for the official version before deploying in production.

image:
  tag: v0.28.0-rc.0
config:
  global:
    resolve_timeout: 5m
  receivers:
    - name: "prometheus-microsoftteams-alertmanager"
      msteamsv2_configs:
        - send_resolved: true
          webhook_url: "your_webhook_url_goes_here"
          title: "{{ range .Alerts }}[{{ .Labels.severity | toUpper }}] {{ .Labels.alertname }}: {{ .Annotations.summary }}\n{{ end }}"
          text: |
            {{ range .Alerts }}
            **Alert Details**
            - **Alert Name:** {{ .Labels.alertname }}
            - **Status:** {{ .Status }}
            - **Severity:** {{ .Labels.severity }}
            - **Description:** {{ .Annotations.description }}

            - **LABELS:** 
              {{ range $key, $value := .Labels }}
              - {{ $key }}: {{ $value }}
              {{ end }}

            - **Starts At:** {{ .StartsAt }}
            {{ if eq .Status "resolved" }}
            - **Ends At:** {{ .EndsAt }}
            {{ else }}
            - **Ends At:** Alert is still firing
            {{ end }}
            {{ end }}
  route:
    group_by: ["alertname"]
    group_interval: 30s
    repeat_interval: 15m
    group_wait: 30s
    receiver: "prometheus-microsoftteams-alertmanager"
    routes:
      - receiver: prometheus-microsoftteams-alertmanager
        match:
          severity: critical

@sebagarayco
Copy link

Hi everyone,

I created a working workflow which uses the Alertmanager's webhook receiver instead of msteams receiver. I wanted to avoid the alerting getting broken when either Microsoft changes something or Prometheus patches the schema of the msteams receiver. I read multiple times that the webhook receiver is planned to stay fixed in the format of the payload. I also plan on using this workflow to connect Google Alerting to Microsoft Teams as well.

And instead of a third-party middleware to transform Alertmanager's webhook payload, I used the functionality of Workflows directly.

The resulting rendered post in the Teams channel: image

This is what the workflow looks like: image

I would have liked to have only one "append to array" in the ForEach segment which adds all the TextBlocks at in a single iteration, but for me the formatting of the JSON got a little mangled. If someone would like to share a hint on this, I would be grateful.

Using this example JSON:

Webhook receiver payload
This workflow will work very well for me:

  1. TeamsWebhook

  2. InitializeVariable

    • (Variable) Name: Formatted Alert Messages
    • Type: Array
  3. ParseJson

Schema
4. Foreach

  • Input: @outputs('Parse_JSON')?['body']?['alerts']
  1. AppendToArrayVariable

    • Action Name: Append 'labels.instance' to message
    • (Input Variable) Name: Formatted Alert Messages

Value
6. AppendToArrayVariable

  • Action Name: Append 'labels.severity' to message
  • (Input Variable) Name: Formatted Alert Messages

Value

{
  "type": "TextBlock",
  "text": "**Severity:** @{items('For_each')?['labels']?['severity']}",
  "wrap": true
}
  1. AppendToArrayVariable

    • Action Name: Append 'status' to message
    • (Input Variable) Name: Formatted Alert Messages

Value
8. AppendToArrayVariable

  • Action Name: Append 'labels.severity' to message
  • (Input Variable) Name: Formatted Alert Messages

Value
9. AppendToArrayVariable

  • Action Name: Append 'annotations.description' to message
  • (Input Variable) Name: Formatted Alert Messages

Value
10. AppendToArrayVariable

* Action Name: `Append 'startsAt' to message`
* (Input Variable) Name: `Formatted Alert Messages`

Value
11. AppendToArrayVariable

* Action Name: `Append 'endsAt' to message`
* (Input Variable) Name: `Formatted Alert Messages`

Value
12. AppendToArrayVariable

* Action Name: `Append 'generatorURL' to message`
* (Input Variable) Name: `Formatted Alert Messages`

Value
14. AppendToArrayVariable

* Action Name: `Append seperator to message`
* (Input Variable) Name: `Formatted Alert Messages`

Value
15. Compose

* Action Name: `Compose final AdaptiveCard`
* (Input Variable) Name: `Formatted Alert Messages`

Input
16. Post card in a chat or channel

Would be possible to export the workflow to a file and paste it here?

@shqnayaz
Copy link

Hi There,
any help and advice is appreiciated.
I have a prometheus-msteams error stating

{"caller":"logging.go:25","err":null,"level":"debug","response_message":"{\"error\":{\"code\":\"InvalidRequestContent\",\"message\":\"The input body for trigger 'manual' of type 'Request' must be of type JSON, but was of type 'application/octet-stream'.\"}}","response_status":400,"ts":"2024-10-29T06:53:56.209244212Z","webhook_url":"https://webhook.com:443/workflows/42704babb511447e92a662d6e18a2b39/triggers/manual/paths/invoke?api-version=2016-06-01&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=dpseP2QWFzzDi40KM7Mj515VCPFOK2MFCOzdfRlkrJE"} {"caller":"transport.go:66","host":"prometheus-msteams:2000","method":"POST","status":200,"took":"46.401091ms","ts":"2024-10-29T06:53:56.209285459Z","uri":"/testworkflow"}

I followed exactly

@shqnayaz
Copy link

shqnayaz commented Nov 4, 2024

Does anyone have a solution for sending from Alertmanager without the msteams_configs and instead the normal webhook webhook_configs? We are stuck on an old version of Alertmanager.

could you maybe use https://github.com/prometheus-msteams/prometheus-msteams ? I dont know if the workarounds here work for that tool

It did not work with the dynamic URLs as it seems like it's cutting out some parts of the URL.image I will give it a full try, though.

Hi @philipsabri
Did you get it working on the older version of alertmanager. ?, seems I am on the same position, its not working for me too.
appreciate if you could share your working snippet.
Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet