Microsoft Team automated notifications

Вопрос: насколько сложно\просто настроить автоматизированые уведомления в Microsoft Teams по сравнению со Slack?

Email

Как по мне так это killer feature которая ну очень user friendly, т.к. по сути даже не нужны никакие скрипты и даже человек отдаленный от инженерии, поковырять рулы в почте сможет что то автоматизировать

Создав канал в teams кликаем по троеточию и выбираем get channel email

image-20240507-105515.png

В появившемся окошке забираем почтовый адрес этого канала

image-20240507-105546.png

Идем в почту и отправляем самое обычное письмо на этот адрес - профит

image-20240507-105614.png

Имхо это очень даже крутой подход, в отрыве от всех притязаний к teams, нужно отдать должное

WebHook

Второй способ чуть ближе к тому с чем сталкиваемся в том же слаке, но при этом и тут он по своему проще

Идем в настройки канала

image-20240507-105745.png

В самом низу кликаем кнопку Edit в разделе Connections

image-20240507-105859.png

В появившемся попапе в поиске вводим WebHook и кликаем add или configure

image-20240507-105945.png

Вводим название, опционально логотип и давим create

image-20240507-110048.png

Чутка подумав оно обновит страничку и покажет сам webhook

image-20240507-110121.png

Так же в самом канале появиться уведомление о том что был подключен вебхук

image-20240507-110211.png

Так, ну и осталось отправить сообщение, с первого попавшегося в сети примера все завелось

curl -X POST 'https://ruaup.webhook.office.com/webhookb2/1893ca41-23b0-4307-b1e7-2f74c899e5fb@695e64b5-2d13-4ea8-bb11-a6fda2d60c41/IncomingWebhook/177657ef132b424cbb6bae18416f8361/57434352-42b0-4090-9d36-9561ae89c607' -H 'Content-Type: application/json' -d '{
  "type": "message",
  "attachments": [
    {
      "contentType": "application/vnd.microsoft.card.adaptive",
      "content": {
        "type": "AdaptiveCard",
        "body": [
          {
            "type": "TextBlock",
            "text": "Message Text"
          }
        ],
        "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
        "version": "1.0"
      }
    }
  ]
}'

image-20240507-110256.png

Formatting

Скидываю заготовку пример которой поделился Бартек

curl -X POST 'https://ruaup.webhook.office.com/webhookb2/1893ca41-23b0-4307-b1e7-2f74c899e5fb@695e64b5-2d13-4ea8-bb11-a6fda2d60c41/IncomingWebhook/177657ef132b424cbb6bae18416f8361/57434352-42b0-4090-9d36-9561ae89c607' -H 'Content-Type: application/json' -d '{
  "@type": "MessageCard",
  "@context": "http://schema.org/extensions",
  "themeColor": "0076D7",
  "title": "Title goes here",
  "text": "Text goes here",
  "sections": [
    {
      "activityTitle": "Section title goes here",
      "activitySubtitle": "section subtitle goes here",
      "facts": [
        {
          "name": "key1",
          "value": "val1"
        },
        {
          "name": "key2",
          "value": "val2"
        },
        {
          "name": "key3",
          "value": "val3"
        }
      ]
    }
  ]
}'

image-20240507-111038.png

Mention

Тут трохи мудреное, по концовке, самый простой и рабочий способ

curl -s -i -X POST 'https://ruaup.webhook.office.com/webhookb2/1893ca41-23b0-4307-b1e7-2f74c899e5fb@695e64b5-2d13-4ea8-bb11-a6fda2d60c41/IncomingWebhook/177657ef132b424cbb6bae18416f8361/57434352-42b0-4090-9d36-9561ae89c607' -H 'Content-Type: application/json' -d '{
  "type": "message",
  "attachments": [
    {
      "contentType": "application/vnd.microsoft.card.adaptive",
      "content": {
        "type": "AdaptiveCard",
        "body": [
          {
            "type": "TextBlock",
            "text": "Hello <at>alexandrm@rabota.ua</at>"
          }
        ],
        "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
        "version": "1.0",
        "msteams": {
          "entities": [
            {
              "type": "mention",
              "text": "<at>alexandrm@rabota.ua</at>",
              "mentioned": {
                "id": "alexandrm@rabota.ua",
                "name": "alexandrm@rabota.ua"
              }
            }
          ]
        }
      }
    }
  ]
}'

image-20240513-071728.png

Designer

https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/connectors-using?tabs=cURL%2Ctext1

https://adaptivecards.io/designer/

https://adaptivecards.io/samples/

Эдакий WYSIWYG тул для сообщений Teams

image-20240513-071425.png

Alertmanager

Пример на что может быть похоже уведомление от alertmanager

image-20240513-082249.png

const body = {
  receiver: "default",
  status: "firing",
  alerts: [
    {
      status: "firing",
      labels: {
        alertname: "demo2",
        component: "bar",
        severity: "info",
      },
      annotations: {},
      startsAt: "2024-05-13T06:11:03.188793747Z",
      endsAt: "0001-01-01T00:00:00Z",
      generatorURL: "",
      fingerprint: "c8002adfd87cf31c",
    },
    {
      status: "firing",
      labels: {
        alertname: "demo2",
        component: "foo",
        severity: "info",
      },
      annotations: {},
      startsAt: "2024-05-13T06:11:03.177669584Z",
      endsAt: "0001-01-01T00:00:00Z",
      generatorURL: "",
      fingerprint: "d31cdf353f33ac5b",
    },
  ],
  groupLabels: { alertname: "demo2", severity: "info" },
  commonLabels: { alertname: "demo2", severity: "info" },
  commonAnnotations: {},
  externalURL: "http://eb024ed65dcf:9093",
  version: "4",
  groupKey: '{}:{alertname="demo2", severity="info"}',
  truncatedAlerts: 0,
};

const email =
  body?.groupLabels?.annotation_owner ||
  body?.commonLabels?.annotation_owner ||
  body?.groupLabels?.owner ||
  body?.commonLabels?.owner ||
  body?.groupLabels?.tag_owner ||
  body?.commonLabels?.tag_owner ||
  body?.alerts?.[0]?.labels?.annotation_owner ||
  body?.alerts?.[0]?.labels?.owner ||
  body?.alerts?.[0]?.labels?.tag_owner ||
  "alexandrm@rabota.ua"; // ''

const payload = {
  type: "message",
  attachments: [
    {
      contentType: "application/vnd.microsoft.card.adaptive",
      content: {
        $schema: "http://adaptivecards.io/schemas/adaptive-card.json",
        version: "1.0",
        type: "AdaptiveCard",
        body: [
          {
            type: "TextBlock",
            weight: "default",
            text: `<at>${email}</at>`,
          },
        ],
        msteams: {
          entities: [
            {
              type: "mention",
              text: `<at>${email}</at>`,
              mentioned: {
                id: email,
                name: email,
              },
            },
          ],
        },
      },
    },
  ],
};

for (const alert of body.alerts) {
  const table = {
    type: "Table",
    columns: [{ width: 1 }, { width: 1 }],
    rows: [],
  };
  for (const [key, val] of Object.entries(alert.labels)) {
    table.rows.push({
      type: "TableRow",
      cells: [
        {
          type: "TableCell",
          items: [
            {
              type: "TextBlock",
              text: key,
              wrap: true,
              weight: "default",
            },
          ],
        },
        {
          type: "TableCell",
          items: [
            {
              type: "TextBlock",
              text: val,
              wrap: true,
              weight: key === "alertname" ? "bolder" : "default", // 'bolder'
              color: "default", // 'attention', 'good', 'warning' depending on key and val, aka status=firing - attention, severity=warning - warning
            },
          ],
        },
      ],
    });
  }
  payload.attachments[0].content.body.push(table);
  const actions = {
    type: "ActionSet",
    actions: [],
  };
  if (alert.generatorURL) {
    actions.actions.push({
      type: "Action.OpenUrl",
      title: "prometheus",
      url: alert.generatorURL,
    });
  }
  if (body.externalURL) {
    actions.actions.push({
      type: "Action.OpenUrl",
      title: "alertmanager",
      url: body.externalURL,
    });
    actions.actions.push({
      type: "Action.OpenUrl",
      title: "silence",
      url: body.externalURL, // TODO: build silence link
    });
  }
  actions.actions.push({
    type: "Action.OpenUrl",
    title: "readme",
    url: `https://rabota.atlassian.net/wiki/search?spaces=OPS&text=${alert.labels.alertname}`,
  });
  payload.attachments[0].content.body.push(actions);
}

console.log(JSON.stringify(payload, null, 4));

const res = await fetch(
  "https://ruaup.webhook.office.com/webhookb2/1893ca41-23b0-4307-b1e7-2f74c899e5fb@695e64b5-2d13-4ea8-bb11-a6fda2d60c41/IncomingWebhook/177657ef132b424cbb6bae18416f8361/57434352-42b0-4090-9d36-9561ae89c607",
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify(payload),
  }
);

console.log(res.status); // 200
console.log(res.statusText); // 'OK'
console.log(await res.text()); // '1'

// {{ define "__alert_silence_link" -}}
//     {{ .ExternalURL }}/#/silences/new?filter=%7B
//     {{- range .CommonLabels.SortedPairs -}}
//         {{- if ne .Name "alertname" -}}
//             {{- .Name }}%3D"{{- .Value -}}"%2C%20
//         {{- end -}}
//     {{- end -}}
//     alertname%3D"{{- .CommonLabels.alertname -}}"%7D
// {{- end }}

// {{/*
// https://hodovi.cc/blog/creating-awesome-alertmanager-templates-for-slack/
// */}}