diff --git a/helm/files/teams.j2 b/helm/files/teams.j2 index f1cf61d..dddddff 100644 --- a/helm/files/teams.j2 +++ b/helm/files/teams.j2 @@ -1,44 +1,71 @@ -{%- set - theme_colors = { - 'resolved' : '2DC72D', - 'critical' : '8C1A1A', - 'severe' : '8C1A1A', - 'warning' : 'FF9A0B', - 'unknown' : 'CCCCCC' - } --%} - { - "@type": "MessageCard", - "@context": "http://schema.org/extensions", - "themeColor": "{% if status=='resolved' %} {{ theme_colors.resolved }} {% else %} {{ theme_colors[msg_text.severity] }} {% endif %}", - "summary": "{% if status=='resolved' %}(Resolved) {% endif %}{{ msg_text.summary }}", - "title": "Prometheus alert {% if status=='resolved' %}(Resolved) {% elif status=='unknown' %} (status unknown) {% endif %}", - "sections": [{ - "activityTitle": "{{ msg_text.summary }}", - "facts": [{% if msg_text.name %}{ - "name": "Alert", - "value": "{{ msg_text.name }}" - },{% endif %}{% if msg_text.instance %}{ - "name": "In host", - "value": "{{ msg_text.instance }}" - },{% endif %}{% if msg_text.severity %}{ - "name": "Severity", - "value": "{{ msg_text.severity }}" - },{% endif %}{% if msg_text.description %}{ - "name": "Description", - "value": "{{ msg_text.description }}" - },{% endif %}{ - "name": "Status", - "value": "{{ msg_text.status }}" - }{% if msg_text.extra_labels %}{% for key in msg_text.extra_labels %},{ - "name": "{{ key }}", - "value": "{{ msg_text.extra_labels[key] }}" - }{% endfor %}{% endif %} - {% if msg_text.extra_annotations %}{% for key in msg_text.extra_annotations %},{ - "name": "{{ key }}", - "value": "{{ msg_text.extra_annotations[key] }}" - }{% endfor %}{% endif %}], - "markdown": true - }] -} + "type": "message", + "attachments": [ + { + "contentType": "application/vnd.microsoft.card.adaptive", + "content": { + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.4", + "msteams": { + "width": "Full" + }, + "body": [ + { + "type": "ColumnSet", + "style": "{% if status=='resolved' %}good{% else %}attention{% endif %}", + "columns": [ + { + "type": "Column", + "width": "stretch", + "items": [ + { + "type": "TextBlock", + "text": "Prometheus alert {{ msg_text.name }} {% if status=='resolved' %}(Resolved){% elif status=='unknown' %}(status unknown){% else %}triggered{% endif %}", + "weight": "Bolder", + "size": "Large" + }, + { + "type": "TextBlock", + "text": "{% if status=='resolved' %}(Resolved) {% endif %}{{ msg_text.summary }}", + "wrap": true + } + ] + } + ] + }, + { + "type": "FactSet", + "facts": [ + {% if msg_text.name %} { "title": "Alert", "value": "{{ msg_text.name }}" }, {% endif %} + {% if msg_text.instance %} { "title": "In host", "value": "{{ msg_text.instance }}" }, {% endif %} + {% if msg_text.severity %} { "title": "Severity", "value": "{{ msg_text.severity }}" }, {% endif %} + {% if msg_text.description %} { "title": "Description", "value": "{{ msg_text.description }}" }, {% endif %} + { "title": "Status", "value": "{{ msg_text.status }}" } + {% if msg_text.extra_labels %} + {% for key in msg_text.extra_labels %} + , { "title": "{{ key }}", "value": "{{ msg_text.extra_labels[key] }}" } + {% endfor %} + {% endif %} + {% if msg_text.extra_annotations %} + {% for key in msg_text.extra_annotations %} + , { "title": "{{ key }}", "value": "{{ msg_text.extra_annotations[key] }}" } + {% endfor %} + {% endif %} + ] + } + ] + {% if msg_text.runbook_url %} + , + "actions": [ + { + "type": "Action.OpenUrl", + "title": "View details", + "url": "{{ msg_text.runbook_url }}" + } + ] + {% endif %} + } + } + ] +} \ No newline at end of file diff --git a/prom2teams/app/teams_client.py b/prom2teams/app/teams_client.py index 92579fb..ffa7219 100644 --- a/prom2teams/app/teams_client.py +++ b/prom2teams/app/teams_client.py @@ -44,7 +44,7 @@ def simple_post(teams_webhook_url, message): def _do_post(self, teams_webhook_url, message): response = self.session.post(teams_webhook_url, data=message, timeout=self.timeout) - if not response.ok or response.text != '1': + if not response.status_code == 202 and not (response.status_code == 200 and response.text == '1'): exception_msg = 'Error performing request to: {}.\n' \ ' Returned status code: {}.\n' \ ' Returned data: {}\n' \ diff --git a/prom2teams/resources/templates/teams.j2 b/prom2teams/resources/templates/teams.j2 index de8ac31..dddddff 100644 --- a/prom2teams/resources/templates/teams.j2 +++ b/prom2teams/resources/templates/teams.j2 @@ -1,57 +1,71 @@ -{%- set - theme_colors = { - 'resolved' : '2DC72D', - 'critical' : '8C1A1A', - 'severe' : '8C1A1A', - 'warning' : 'FF9A0B', - 'unknown' : 'CCCCCC' - } --%} - { - "@type": "MessageCard", - "@context": "http://schema.org/extensions", - "themeColor": "{% if status=='resolved' %} {{ theme_colors.resolved }} {% else %} {{ theme_colors[msg_text.severity] }} {% endif %}", - "summary": "{% if status=='resolved' %}(Resolved) {% endif %}{{ msg_text.summary }}", - "title": "Prometheus alert {% if status=='resolved' %}(Resolved) {% elif status=='unknown' %} (status unknown) {% endif %}", - "sections": [{ - "activityTitle": "{{ msg_text.summary }}", - "facts": [{% if msg_text.name %}{ - "name": "Alert", - "value": "{{ msg_text.name }}" - },{% endif %}{% if msg_text.instance %}{ - "name": "In host", - "value": "{{ msg_text.instance }}" - },{% endif %}{% if msg_text.severity %}{ - "name": "Severity", - "value": "{{ msg_text.severity }}" - },{% endif %}{% if msg_text.description %}{ - "name": "Description", - "value": "{{ msg_text.description }}" - },{% endif %}{ - "name": "Status", - "value": "{{ msg_text.status }}" - }{% if msg_text.extra_labels %}{% for key in msg_text.extra_labels %},{ - "name": "{{ key }}", - "value": "{{ msg_text.extra_labels[key] }}" - }{% endfor %}{% endif %} - {% if msg_text.extra_annotations %}{% for key in msg_text.extra_annotations %},{ - "name": "{{ key }}", - "value": "{{ msg_text.extra_annotations[key] }}" - }{% endfor %}{% endif %}], - "markdown": true - }] - {% if msg_text.runbook_url %} - , - "potentialAction": [ - { - "@context": "http://schema.org", - "@type": "ViewAction", - "name": "Runbook", - "target": [ - "{{ msg_text.runbook_url }}" + "type": "message", + "attachments": [ + { + "contentType": "application/vnd.microsoft.card.adaptive", + "content": { + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.4", + "msteams": { + "width": "Full" + }, + "body": [ + { + "type": "ColumnSet", + "style": "{% if status=='resolved' %}good{% else %}attention{% endif %}", + "columns": [ + { + "type": "Column", + "width": "stretch", + "items": [ + { + "type": "TextBlock", + "text": "Prometheus alert {{ msg_text.name }} {% if status=='resolved' %}(Resolved){% elif status=='unknown' %}(status unknown){% else %}triggered{% endif %}", + "weight": "Bolder", + "size": "Large" + }, + { + "type": "TextBlock", + "text": "{% if status=='resolved' %}(Resolved) {% endif %}{{ msg_text.summary }}", + "wrap": true + } + ] + } ] - } - ] - {% endif %} -} + }, + { + "type": "FactSet", + "facts": [ + {% if msg_text.name %} { "title": "Alert", "value": "{{ msg_text.name }}" }, {% endif %} + {% if msg_text.instance %} { "title": "In host", "value": "{{ msg_text.instance }}" }, {% endif %} + {% if msg_text.severity %} { "title": "Severity", "value": "{{ msg_text.severity }}" }, {% endif %} + {% if msg_text.description %} { "title": "Description", "value": "{{ msg_text.description }}" }, {% endif %} + { "title": "Status", "value": "{{ msg_text.status }}" } + {% if msg_text.extra_labels %} + {% for key in msg_text.extra_labels %} + , { "title": "{{ key }}", "value": "{{ msg_text.extra_labels[key] }}" } + {% endfor %} + {% endif %} + {% if msg_text.extra_annotations %} + {% for key in msg_text.extra_annotations %} + , { "title": "{{ key }}", "value": "{{ msg_text.extra_annotations[key] }}" } + {% endfor %} + {% endif %} + ] + } + ] + {% if msg_text.runbook_url %} + , + "actions": [ + { + "type": "Action.OpenUrl", + "title": "View details", + "url": "{{ msg_text.runbook_url }}" + } + ] + {% endif %} + } + } + ] +} \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 33fcddd..020111b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ flask-restplus==0.12.1 marshmallow==3.0.0rc6 jinja2==2.11.3 Flask==1.0.2 -pyyaml==5.4 +pyyaml==6.0.1 uwsgi==2.0.20 prometheus_flask_exporter==0.9.0 werkzeug==0.16.1 diff --git a/tests/data/json_files/teams_alert_all_ok.json b/tests/data/json_files/teams_alert_all_ok.json index fab8a6e..7d83808 100644 --- a/tests/data/json_files/teams_alert_all_ok.json +++ b/tests/data/json_files/teams_alert_all_ok.json @@ -1,27 +1,54 @@ { - "@type": "MessageCard", - "@context": "http://schema.org/extensions", - "themeColor": " 2DC72D ", - "summary": "(Resolved) Disk usage alert on CS30.evilcorp", - "title": "Prometheus alert (Resolved) ", - "sections": [{ - "activityTitle": "Disk usage alert on CS30.evilcorp", - "facts": [{ - "name": "Alert", - "value": "DiskSpace" - },{ - "name": "In host", - "value": "cs30.evilcorp" - },{ - "name": "Severity", - "value": "severe" - },{ - "name": "Description", - "value": "disk usage 93% on rootfs device" - },{ - "name": "Status", - "value": "resolved" - }], - "markdown": true - }] + "type": "message", + "attachments": [ + { + "contentType": "application/vnd.microsoft.card.adaptive", + "content": { + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.4", + "msteams": { + "width": "Full" + }, + "body": [ + { + "type": "ColumnSet", + "style": "good", + "columns": [ + { + "type": "Column", + "width": "stretch", + "items": [ + { + "type": "TextBlock", + "text": "Prometheus alert DiskSpace (Resolved)", + "weight": "Bolder", + "size": "Large" + }, + { + "type": "TextBlock", + "text": "(Resolved) Disk usage alert on CS30.evilcorp", + "wrap": true + } + ] + } + ] + }, + { + "type": "FactSet", + "facts": [ + { "title": "Alert", "value": "DiskSpace" }, + { "title": "In host", "value": "cs30.evilcorp" }, + { "title": "Severity", "value": "severe" }, + { + "title": "Description", + "value": "disk usage 93% on rootfs device" + }, + { "title": "Status", "value": "resolved" } + ] + } + ] + } + } + ] } diff --git a/tests/data/json_files/teams_alert_all_ok_extra_annotations.json b/tests/data/json_files/teams_alert_all_ok_extra_annotations.json index 7699d8f..1bc7c51 100644 --- a/tests/data/json_files/teams_alert_all_ok_extra_annotations.json +++ b/tests/data/json_files/teams_alert_all_ok_extra_annotations.json @@ -1,49 +1,65 @@ { - "@type": "MessageCard", - "@context": "http://schema.org/extensions", - "themeColor": " 2DC72D ", - "summary": "(Resolved) Disk usage alert on CS30.evilcorp", - "title": "Prometheus alert (Resolved) ", - "sections": [ + "type": "message", + "attachments": [ { - "activityTitle": "Disk usage alert on CS30.evilcorp", - "facts": [ - { - "name": "Alert", - "value": "DiskSpace" + "contentType": "application/vnd.microsoft.card.adaptive", + "content": { + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.4", + "msteams": { + "width": "Full" }, - { - "name": "In host", - "value": "cs30.evilcorp" - }, - { - "name": "Severity", - "value": "severe" - }, - { - "name": "Description", - "value": "disk usage 93% on rootfs device" - }, - { - "name": "Status", - "value": "resolved" - }, - { - "name": "runbook_url", - "value": "https://cs30-evilcorp-runbooks.com/rootfs-device-high-disk-usage" - } - ], - "markdown": true - } - ], - "potentialAction": [ - { - "@context": "http://schema.org", - "@type": "ViewAction", - "name": "Runbook", - "target": [ - "https://cs30-evilcorp-runbooks.com/rootfs-device-high-disk-usage" - ] + "body": [ + { + "type": "ColumnSet", + "style": "good", + "columns": [ + { + "type": "Column", + "width": "stretch", + "items": [ + { + "type": "TextBlock", + "text": "Prometheus alert DiskSpace (Resolved)", + "weight": "Bolder", + "size": "Large" + }, + { + "type": "TextBlock", + "text": "(Resolved) Disk usage alert on CS30.evilcorp", + "wrap": true + } + ] + } + ] + }, + { + "type": "FactSet", + "facts": [ + { "title": "Alert", "value": "DiskSpace" }, + { "title": "In host", "value": "cs30.evilcorp" }, + { "title": "Severity", "value": "severe" }, + { + "title": "Description", + "value": "disk usage 93% on rootfs device" + }, + { "title": "Status", "value": "resolved" }, + { + "title": "runbook_url", + "value": "https://cs30-evilcorp-runbooks.com/rootfs-device-high-disk-usage" + } + ] + } + ], + "actions": [ + { + "type": "Action.OpenUrl", + "title": "View details", + "url": "https://cs30-evilcorp-runbooks.com/rootfs-device-high-disk-usage" + } + ] + } } ] -} \ No newline at end of file +} diff --git a/tests/data/json_files/teams_alert_all_ok_extra_labels.json b/tests/data/json_files/teams_alert_all_ok_extra_labels.json index 5374271..f08ff36 100644 --- a/tests/data/json_files/teams_alert_all_ok_extra_labels.json +++ b/tests/data/json_files/teams_alert_all_ok_extra_labels.json @@ -1,43 +1,56 @@ { - "@type": "MessageCard", - "@context": "http://schema.org/extensions", - "themeColor": " 2DC72D ", - "summary": "(Resolved) Disk usage alert on CS30.evilcorp", - "title": "Prometheus alert (Resolved) ", - "sections": [ - { - "activityTitle": "Disk usage alert on CS30.evilcorp", + "type": "message", + "attachments": [ + { + "contentType": "application/vnd.microsoft.card.adaptive", + "content": { + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.4", + "msteams": { + "width": "Full" + }, + "body": [ + { + "type": "ColumnSet", + "style": "good", + "columns": [ + { + "type": "Column", + "width": "stretch", + "items": [ + { + "type": "TextBlock", + "text": "Prometheus alert DiskSpace (Resolved)", + "weight": "Bolder", + "size": "Large" + }, + { + "type": "TextBlock", + "text": "(Resolved) Disk usage alert on CS30.evilcorp", + "wrap": true + } + ] + } + ] + }, + { + "type": "FactSet", "facts": [ - { - "name": "Alert", - "value": "DiskSpace" - }, - { - "name": "In host", - "value": "cs30.evilcorp" - }, - { - "name": "Severity", - "value": "severe" - }, - { - "name": "Description", - "value": "disk usage 93% on rootfs device" - }, - { - "name": "Status", - "value": "resolved" - }, - { - "name": "job", - "value": "fsociety" - }, - { - "name": "prometheus", - "value": "keep" - } - ], - "markdown": true - } - ] -} \ No newline at end of file + { "title": "Alert", "value": "DiskSpace" }, + { "title": "In host", "value": "cs30.evilcorp" }, + { "title": "Severity", "value": "severe" }, + { + "title": "Description", + "value": "disk usage 93% on rootfs device" + }, + { "title": "Status", "value": "resolved" }, + { "title": "job", "value": "fsociety" }, + { "title": "prometheus", "value": "keep" } + ] + } + ] + } + } + ] +} diff --git a/tests/data/json_files/teams_alert_all_ok_multiple.json b/tests/data/json_files/teams_alert_all_ok_multiple.json index 1cb49fa..4f7808d 100644 --- a/tests/data/json_files/teams_alert_all_ok_multiple.json +++ b/tests/data/json_files/teams_alert_all_ok_multiple.json @@ -1,27 +1,54 @@ { - "@type": "MessageCard", - "@context": "http://schema.org/extensions", - "themeColor": " 2DC72D ", - "summary": "(Resolved) Disk usage alert on CS30.evilcorp, Disk usage alert on CS31.evilcorp", - "title": "Prometheus alert (Resolved) ", - "sections": [{ - "activityTitle": "Disk usage alert on CS30.evilcorp, Disk usage alert on CS31.evilcorp", - "facts": [{ - "name": "Alert", - "value": "DiskSpace" - },{ - "name": "In host", - "value": "cs30.evilcorp, cs31.evilcorp" - },{ - "name": "Severity", - "value": "critical, severe" - },{ - "name": "Description", - "value": "disk usage 93% on rootfs device, disk usage 94% on rootfs device" - },{ - "name": "Status", - "value": "resolved" - }], - "markdown": true - }] + "type": "message", + "attachments": [ + { + "contentType": "application/vnd.microsoft.card.adaptive", + "content": { + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.4", + "msteams": { + "width": "Full" + }, + "body": [ + { + "type": "ColumnSet", + "style": "good", + "columns": [ + { + "type": "Column", + "width": "stretch", + "items": [ + { + "type": "TextBlock", + "text": "Prometheus alert DiskSpace (Resolved)", + "weight": "Bolder", + "size": "Large" + }, + { + "type": "TextBlock", + "text": "(Resolved) Disk usage alert on CS30.evilcorp, Disk usage alert on CS31.evilcorp", + "wrap": true + } + ] + } + ] + }, + { + "type": "FactSet", + "facts": [ + { "title": "Alert", "value": "DiskSpace" }, + { "title": "In host", "value": "cs30.evilcorp, cs31.evilcorp" }, + { "title": "Severity", "value": "critical, severe" }, + { + "title": "Description", + "value": "disk usage 93% on rootfs device, disk usage 94% on rootfs device" + }, + { "title": "Status", "value": "resolved" } + ] + } + ] + } + } + ] } diff --git a/tests/data/json_files/teams_alert_all_ok_splitted.json b/tests/data/json_files/teams_alert_all_ok_splitted.json index 0537adf..4e5ce35 100644 --- a/tests/data/json_files/teams_alert_all_ok_splitted.json +++ b/tests/data/json_files/teams_alert_all_ok_splitted.json @@ -1,72 +1,110 @@ - [ - { - "@type": "MessageCard", - "@context": "http://schema.org/extensions", - "themeColor": " 2DC72D ", - "summary": "(Resolved) Disk usage alert on CS31.evilcorp", - "title": "Prometheus alert (Resolved) ", - "sections": [ +[ + { + "type": "message", + "attachments": [ + { + "contentType": "application/vnd.microsoft.card.adaptive", + "content": { + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.4", + "msteams": { + "width": "Full" + }, + "body": [ + { + "type": "ColumnSet", + "style": "good", + "columns": [ { - "activityTitle": "Disk usage alert on CS31.evilcorp", - "facts": [ - { - "name": "Alert", - "value": "DiskSpace" - }, - { - "name": "In host", - "value": "cs31.evilcorp" - }, - { - "name": "Severity", - "value": "critical" - }, - { - "name": "Description", - "value": "disk usage 94% on rootfs device" - }, - { - "name": "Status", - "value": "resolved" - } - ], - "markdown": true + "type": "Column", + "width": "stretch", + "items": [ + { + "type": "TextBlock", + "text": "Prometheus alert DiskSpace (Resolved)", + "weight": "Bolder", + "size": "Large" + }, + { + "type": "TextBlock", + "text": "(Resolved) Disk usage alert on CS31.evilcorp", + "wrap": true + } + ] } - ] - }, - { - "@type": "MessageCard", - "@context": "http://schema.org/extensions", - "themeColor": " 2DC72D ", - "summary": "(Resolved) Disk usage alert on CS30.evilcorp", - "title": "Prometheus alert (Resolved) ", - "sections": [ + ] + }, + { + "type": "FactSet", + "facts": [ + { "title": "Alert", "value": "DiskSpace" }, + { "title": "In host", "value": "cs31.evilcorp" }, + { "title": "Severity", "value": "critical" }, { - "activityTitle": "Disk usage alert on CS30.evilcorp", - "facts": [ - { - "name": "Alert", - "value": "DiskSpace" - }, - { - "name": "In host", - "value": "cs30.evilcorp" - }, - { - "name": "Severity", - "value": "severe" - }, - { - "name": "Description", - "value": "disk usage 93% on rootfs device" - }, - { - "name": "Status", - "value": "resolved" - } - ], - "markdown": true + "title": "Description", + "value": "disk usage 94% on rootfs device" + }, + { "title": "Status", "value": "resolved" } + ] + } + ] + } + } + ] + }, + { + "type": "message", + "attachments": [ + { + "contentType": "application/vnd.microsoft.card.adaptive", + "content": { + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.4", + "msteams": { + "width": "Full" + }, + "body": [ + { + "type": "ColumnSet", + "style": "good", + "columns": [ + { + "type": "Column", + "width": "stretch", + "items": [ + { + "type": "TextBlock", + "text": "Prometheus alert DiskSpace (Resolved)", + "weight": "Bolder", + "size": "Large" + }, + { + "type": "TextBlock", + "text": "(Resolved) Disk usage alert on CS30.evilcorp", + "wrap": true + } + ] } - ] + ] + }, + { + "type": "FactSet", + "facts": [ + { "title": "Alert", "value": "DiskSpace" }, + { "title": "In host", "value": "cs30.evilcorp" }, + { "title": "Severity", "value": "severe" }, + { + "title": "Description", + "value": "disk usage 93% on rootfs device" + }, + { "title": "Status", "value": "resolved" } + ] + } + ] } - ] \ No newline at end of file + } + ] + } +] diff --git a/tests/data/json_files/teams_alert_with_common_items.json b/tests/data/json_files/teams_alert_with_common_items.json index c2eb4c0..97460dd 100644 --- a/tests/data/json_files/teams_alert_with_common_items.json +++ b/tests/data/json_files/teams_alert_with_common_items.json @@ -1,61 +1,68 @@ { - "@type": "MessageCard", - "@context": "http://schema.org/extensions", - "themeColor": " 2DC72D ", - "summary": "(Resolved) CPU throttling", - "title": "Prometheus alert (Resolved) ", - "sections": [ - { - "activityTitle": "CPU throttling", + "type": "message", + "attachments": [ + { + "contentType": "application/vnd.microsoft.card.adaptive", + "content": { + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.4", + "msteams": { + "width": "Full" + }, + "body": [ + { + "type": "ColumnSet", + "style": "good", + "columns": [ + { + "type": "Column", + "width": "stretch", + "items": [ + { + "type": "TextBlock", + "text": "Prometheus alert CPUThrottlingHigh (Resolved)", + "weight": "Bolder", + "size": "Large" + }, + { + "type": "TextBlock", + "text": "(Resolved) CPU throttling", + "wrap": true + } + ] + } + ] + }, + { + "type": "FactSet", "facts": [ - { - "name": "Alert", - "value": "CPUThrottlingHigh" - }, - { - "name": "In host", - "value": "unknown" - }, - { - "name": "Severity", - "value": "warning" - }, - { - "name": "Description", - "value": "unknown" - }, - { - "name": "Status", - "value": "resolved" - }, - { - "name": "container_name", - "value": "config-reloader" - }, - { - "name": "pod_name", - "value": "alertmanager-ot-mon-prometheus-operator-alertmanager-0" - }, - { - "name": "namespace", - "value": "monitoring" - }, - { - "name": "prometheus", - "value": "monitoring/ot-mon-prometheus-operator-prometheus" - } - ], - "markdown": true - } - ], - "potentialAction": [ - { - "@context": "http://schema.org", - "@type": "ViewAction", - "name": "Runbook", - "target": [ - "https://cs30-evilcorp-runbooks.com/rootfs-device-high-disk-usage" + { "title": "Alert", "value": "CPUThrottlingHigh" }, + { "title": "In host", "value": "unknown" }, + { "title": "Severity", "value": "warning" }, + { "title": "Description", "value": "unknown" }, + { "title": "Status", "value": "resolved" }, + { "title": "container_name", "value": "config-reloader" }, + { + "title": "pod_name", + "value": "alertmanager-ot-mon-prometheus-operator-alertmanager-0" + }, + { "title": "namespace", "value": "monitoring" }, + { + "title": "prometheus", + "value": "monitoring/ot-mon-prometheus-operator-prometheus" + } ] - } - ] + } + ], + "actions": [ + { + "type": "Action.OpenUrl", + "title": "View details", + "url": "https://cs30-evilcorp-runbooks.com/rootfs-device-high-disk-usage" + } + ] + } + } + ] } diff --git a/tests/data/json_files/teams_without_fingerprint.json b/tests/data/json_files/teams_without_fingerprint.json index f1464f5..7d83808 100644 --- a/tests/data/json_files/teams_without_fingerprint.json +++ b/tests/data/json_files/teams_without_fingerprint.json @@ -1,27 +1,54 @@ { - "@type": "MessageCard", - "@context": "http://schema.org/extensions", - "themeColor": " 2DC72D ", - "summary": "(Resolved) Disk usage alert on CS30.evilcorp", - "title": "Prometheus alert (Resolved) ", - "sections": [{ - "activityTitle": "Disk usage alert on CS30.evilcorp", - "facts": [{ - "name": "Alert", - "value": "DiskSpace" - },{ - "name": "In host", - "value": "cs30.evilcorp" - },{ - "name": "Severity", - "value": "severe" - },{ - "name": "Description", - "value": "disk usage 93% on rootfs device" - },{ - "name": "Status", - "value": "resolved" - }], - "markdown": true - }] + "type": "message", + "attachments": [ + { + "contentType": "application/vnd.microsoft.card.adaptive", + "content": { + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.4", + "msteams": { + "width": "Full" + }, + "body": [ + { + "type": "ColumnSet", + "style": "good", + "columns": [ + { + "type": "Column", + "width": "stretch", + "items": [ + { + "type": "TextBlock", + "text": "Prometheus alert DiskSpace (Resolved)", + "weight": "Bolder", + "size": "Large" + }, + { + "type": "TextBlock", + "text": "(Resolved) Disk usage alert on CS30.evilcorp", + "wrap": true + } + ] + } + ] + }, + { + "type": "FactSet", + "facts": [ + { "title": "Alert", "value": "DiskSpace" }, + { "title": "In host", "value": "cs30.evilcorp" }, + { "title": "Severity", "value": "severe" }, + { + "title": "Description", + "value": "disk usage 93% on rootfs device" + }, + { "title": "Status", "value": "resolved" } + ] + } + ] + } + } + ] } diff --git a/tests/e2e/test.sh b/tests/e2e/test.sh index cf915f4..18609b3 100755 --- a/tests/e2e/test.sh +++ b/tests/e2e/test.sh @@ -3,164 +3,391 @@ create_containers(){ echo "Creating containers..." - docker-compose up --build -d > /dev/null 2>&1 + docker-compose up --build -d } create_expectations_and_responses(){ echo "Creating expectations and responses in teams mockserver..." sleep 10 # To wait for containers to start curl -s -v -X PUT "http://localhost:1080/mockserver/expectation" -d '{ - "httpRequest" : { - "method" : "POST", - "path" : "/api/test", - "body": { - "@type": "MessageCard", - "@context": "http://schema.org/extensions", - "themeColor": " 8C1A1A ", - "summary": "Node exporter down on node1.summit", - "title": "Prometheus alert ", - "sections": [{ - "activityTitle": "Node exporter down on node1.summit", - "facts": [{ - "name": "Alert", - "value": "NodeExporter" - },{ - "name": "In host", - "value": "node1.summit" - },{ - "name": "Severity", - "value": "critical" - },{ - "name": "Description", - "value": "Node exporter down on node1.summit" - },{ - "name": "Status", - "value": "firing" - },{ - "name": "job", - "value": "node_exporter" - },{ - "name": "env", - "value": "production" - },{ - "name": "notify_room", - "value": "test" - },{ - "name": "type", - "value": "nodeexporter" - } ], - "markdown": true - }] - } - }, - "httpResponse" : { - "statusCode": 200, - "body" : "1" - } - }' > /dev/null 2>&1 + "httpRequest": { + "method": "POST", + "path": "/api/test", + "body": { + "type": "message", + "attachments": [ + { + "contentType": "application/vnd.microsoft.card.adaptive", + "content": { + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.4", + "msteams": { + "width": "Full" + }, + "body": [ + { + "type": "ColumnSet", + "style": "attention", + "columns": [ + { + "type": "Column", + "width": "stretch", + "items": [ + { + "type": "TextBlock", + "text": "Prometheus alert NodeExporter triggered", + "weight": "Bolder", + "size": "Large" + }, + { + "type": "TextBlock", + "text": "Node exporter down on node1.summit", + "wrap": true + } + ] + } + ] + }, + { + "type": "FactSet", + "facts": [ + { + "title": "Alert", + "value": "NodeExporter" + }, + { + "title": "In host", + "value": "node1.summit" + }, + { + "title": "Severity", + "value": "critical" + }, + { + "title": "Description", + "value": "Node exporter down on node1.summit" + }, + { + "title": "Status", + "value": "firing" + }, + { + "title": "job", + "value": "node_exporter" + }, + { + "title": "notify_room", + "value": "test" + }, + { + "title": "env", + "value": "production" + }, + { + "title": "type", + "value": "nodeexporter" + } + ] + } + ] + } + } + ] + } + }, + "httpResponse": { + "statusCode": 200, + "body": "1" + } + }' > /dev/null 2>&1 curl -s -v -X PUT "http://localhost:1080/mockserver/expectation" -d '{ - "httpRequest" : { - "method" : "POST", - "path" : "/api/test", - "body": { - "@type": "MessageCard", - "@context": "http://schema.org/extensions", - "themeColor": " 8C1A1A ", - "summary": "Node exporter down on node2.summit", - "title": "Prometheus alert ", - "sections": [{ - "activityTitle": "Node exporter down on node2.summit", - "facts": [{ - "name": "Alert", - "value": "NodeExporter" - },{ - "name": "In host", - "value": "node2.summit" - },{ - "name": "Severity", - "value": "critical" - },{ - "name": "Description", - "value": "Node exporter down on node2.summit" - },{ - "name": "Status", - "value": "firing" - },{ - "name": "job", - "value": "node_exporter" - },{ - "name": "env", - "value": "production" - },{ - "name": "notify_room", - "value": "test" - },{ - "name": "type", - "value": "nodeexporter" - } ], - "markdown": true - }] - } - }, - "httpResponse" : { - "statusCode": 200, - "body" : "1" - } - }' > /dev/null 2>&1 + "httpRequest": { + "method": "POST", + "path": "/api/test", + "body": { + "type": "message", + "attachments": [ + { + "contentType": "application/vnd.microsoft.card.adaptive", + "content": { + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.4", + "msteams": { + "width": "Full" + }, + "body": [ + { + "type": "ColumnSet", + "style": "attention", + "columns": [ + { + "type": "Column", + "width": "stretch", + "items": [ + { + "type": "TextBlock", + "text": "Prometheus alert NodeExporter triggered", + "weight": "Bolder", + "size": "Large" + }, + { + "type": "TextBlock", + "text": "Node exporter down on node2.summit", + "wrap": true + } + ] + } + ] + }, + { + "type": "FactSet", + "facts": [ + { + "title": "Alert", + "value": "NodeExporter" + }, + { + "title": "In host", + "value": "node2.summit" + }, + { + "title": "Severity", + "value": "critical" + }, + { + "title": "Description", + "value": "Node exporter down on node2.summit" + }, + { + "title": "Status", + "value": "firing" + }, + { + "title": "job", + "value": "node_exporter" + }, + { + "title": "notify_room", + "value": "test" + }, + { + "title": "env", + "value": "production" + }, + { + "title": "type", + "value": "nodeexporter" + } + ] + } + ] + } + } + ] + } + }, + "httpResponse": { + "statusCode": 200, + "body": "1" + } + }' > /dev/null 2>&1 + + curl -s -v -X PUT "http://localhost:1080/mockserver/expectation" -d '{ + "httpRequest": { + "method": "POST", + "path": "/api/test", + "body": { + "type": "message", + "attachments": [ + { + "contentType": "application/vnd.microsoft.card.adaptive", + "content": { + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.4", + "msteams": { + "width": "Full" + }, + "body": [ + { + "type": "ColumnSet", + "style": "attention", + "columns": [ + { + "type": "Column", + "width": "stretch", + "items": [ + { + "type": "TextBlock", + "text": "Prometheus alert NodeExporter triggered", + "weight": "Bolder", + "size": "Large" + }, + { + "type": "TextBlock", + "text": "Node exporter down on node3.summit", + "wrap": true + } + ] + } + ] + }, + { + "type": "FactSet", + "facts": [ + { + "title": "Alert", + "value": "NodeExporter" + }, + { + "title": "In host", + "value": "node3.summit" + }, + { + "title": "Severity", + "value": "critical" + }, + { + "title": "Description", + "value": "Node exporter down on node3.summit" + }, + { + "title": "Status", + "value": "firing" + }, + { + "title": "job", + "value": "node_exporter" + }, + { + "title": "notify_room", + "value": "test" + }, + { + "title": "type", + "value": "nodeexporter" + }, + { + "title": "env", + "value": "production" + }, + ] + } + ] + } + } + ] + } + }, + "httpResponse": { + "statusCode": 202 + } + }' > /dev/null 2>&1 } run_tests(){ echo "Running tests..." - # Alertmanager 0.21.0 request + # Alertmanager 0.21.0 request test1=$(curl -s -o /dev/null -w "%{http_code}\n" -X POST "http://localhost:8089/v2/connector" -H "accept: application/json" -H "Content-Type: application/json" -d "{ \"receiver\": \"test\", \"status\": \"firing\", \"alerts\": [ { \"status\": \"firing\", \"labels\": { \"alertname\": \"NodeExporter\", \"env\": \"production\", \"instance\": \"node1.summit\", \"job\": \"node_exporter\", \"notify_room\": \"test\", \"severity\": \"critical\", \"type\": \"nodeexporter\" }, \"annotations\": { \"description\": \"Node exporter down on node1.summit\", \"summary\": \"Node exporter down on node1.summit\" }, \"startsAt\": \"2020-09-16T07:38:01.586706006Z\", \"endsAt\": \"0001-01-01T00:00:00Z\", \"generatorURL\": \"\", \"fingerprint\": \"e4ad109767ee663e\" } ], \"groupLabels\": { \"alertname\": \"NodeExporter\" }, \"commonLabels\": { \"alertname\": \"NodeExporter\", \"job\": \"node_exporter\", \"severity\": \"critical\", \"type\": \"nodeexporter\" }, \"commonAnnotations\": {}, \"externalURL\": \"http://localhost:9093\", \"version\": \"4\", \"groupKey\": \"{}/{notify_room=~\\\"^(?:.*test.*)$\\\"}:{alertname=\\\"NodeExporter\\\"}\", \"truncatedAlerts\": 0}") # Alertmanager 0.20.0 request test2=$(curl -s -o /dev/null -w "%{http_code}\n" -X POST "http://localhost:8089/v2/connector" -H "accept: application/json" -H "Content-Type: application/json" -d "{ \"receiver\": \"test\", \"status\": \"firing\", \"alerts\": [ { \"status\": \"firing\", \"labels\": { \"alertname\": \"NodeExporter\", \"env\": \"production\", \"instance\": \"node2.summit\", \"job\": \"node_exporter\", \"notify_room\": \"test\", \"severity\": \"critical\", \"type\": \"nodeexporter\" }, \"annotations\": { \"description\": \"Node exporter down on node2.summit\", \"summary\": \"Node exporter down on node2.summit\" }, \"startsAt\": \"2020-09-16T08:09:50.791949454Z\", \"endsAt\": \"0001-01-01T00:00:00Z\", \"generatorURL\": \"\", \"fingerprint\": \"96b211b05dc430e8\" } ], \"groupLabels\": { \"alertname\": \"NodeExporter\" }, \"commonLabels\": { \"alertname\": \"NodeExporter\", \"env\": \"production\", \"job\": \"node_exporter\", \"notify_room\": \"test\", \"severity\": \"critical\", \"type\": \"nodeexporter\" }, \"commonAnnotations\": {}, \"externalURL\": \"http://localhost:9093\", \"version\": \"4\", \"groupKey\": \"{}/{notify_room=~\\\"^(?:.*test.*)$\\\"}:{alertname=\\\"NodeExporter\\\"}\"}") + # Alertmanager Teams workflow + test3=$(curl -s -o /dev/null -w "%{http_code}\n" -X POST "http://localhost:8089/v2/connector" -H "accept: application/json" -H "Content-Type: application/json" -d "{ \"receiver\": \"test\", \"status\": \"firing\", \"alerts\": [ { \"status\": \"firing\", \"labels\": { \"alertname\": \"NodeExporter\", \"env\": \"production\", \"instance\": \"node3.summit\", \"job\": \"node_exporter\", \"notify_room\": \"test\", \"severity\": \"critical\", \"type\": \"nodeexporter\" }, \"annotations\": { \"description\": \"Node exporter down on node3.summit\", \"summary\": \"Node exporter down on node3.summit\" }, \"startsAt\": \"2020-09-16T07:38:01.586706006Z\", \"endsAt\": \"0001-01-01T00:00:00Z\", \"generatorURL\": \"\", \"fingerprint\": \"e4ad109767ee663e\" } ], \"groupLabels\": { \"alertname\": \"NodeExporter\" }, \"commonLabels\": { \"alertname\": \"NodeExporter\", \"job\": \"node_exporter\", \"severity\": \"critical\", \"type\": \"nodeexporter\" }, \"commonAnnotations\": {}, \"externalURL\": \"http://localhost:9093\", \"version\": \"4\", \"groupKey\": \"{}/{notify_room=~\\\"^(?:.*test.*)$\\\"}:{alertname=\\\"NodeExporter\\\"}\", \"truncatedAlerts\": 0}") + test1verify=$(curl -s -w "%{http_code}\n" -X PUT "http://localhost:1080/mockserver/verify" -d '{ - "httpRequest" : { - "method" : "POST", - "path" : "/api/test", - "body": { - "@type": "MessageCard", - "@context": "http://schema.org/extensions", - "themeColor": " 8C1A1A ", - "summary": "Node exporter down on node1.summit", - "title": "Prometheus alert ", - "sections": [{ - "activityTitle": "Node exporter down on node1.summit", - "facts": [{ - "name": "Alert", - "value": "NodeExporter" - },{ - "name": "In host", - "value": "node1.summit" - },{ - "name": "Severity", - "value": "critical" - },{ - "name": "Description", - "value": "Node exporter down on node1.summit" - },{ - "name": "Status", - "value": "firing" - },{ - "name": "job", - "value": "node_exporter" - },{ - "name": "env", - "value": "production" - },{ - "name": "notify_room", - "value": "test" - },{ - "name": "type", - "value": "nodeexporter" - } ], - "markdown": true - }] - } + "httpRequest": { + "method": "POST", + "path": "/api/test", + "body": { + "type": "message", + "attachments": [ + { + "contentType": "application/vnd.microsoft.card.adaptive", + "content": { + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.4", + "msteams": { + "width": "Full" + }, + "body": [ + { + "type": "ColumnSet", + "style": "attention", + "columns": [ + { + "type": "Column", + "width": "stretch", + "items": [ + { + "type": "TextBlock", + "text": "Prometheus alert NodeExporter triggered", + "weight": "Bolder", + "size": "Large" + }, + { + "type": "TextBlock", + "text": "Node exporter down on node1.summit", + "wrap": true + } + ] + } + ] + }, + { + "type": "FactSet", + "facts": [ + { + "title": "Alert", + "value": "NodeExporter" + }, + { + "title": "In host", + "value": "node1.summit" + }, + { + "title": "Severity", + "value": "critical" + }, + { + "title": "Description", + "value": "Node exporter down on node1.summit" + }, + { + "title": "Status", + "value": "firing" + }, + { + "title": "job", + "value": "node_exporter" + }, + { + "title": "env", + "value": "production" + }, + { + "title": "notify_room", + "value": "test" + }, + { + "title": "type", + "value": "nodeexporter" + } + + ] + } + ] + } + } + ] + } + } + }, }, "times": { "atLeast": 1, @@ -169,47 +396,91 @@ run_tests(){ }') test2verify=$(curl -s -w "%{http_code}\n" -X PUT "http://localhost:1080/mockserver/verify" -d '{ - "httpRequest" : { - "method" : "POST", - "path" : "/api/test", + "httpRequest": { + "method": "POST", + "path": "/api/test", "body": { - "@type": "MessageCard", - "@context": "http://schema.org/extensions", - "themeColor": " 8C1A1A ", - "summary": "Node exporter down on node2.summit", - "title": "Prometheus alert ", - "sections": [{ - "activityTitle": "Node exporter down on node2.summit", - "facts": [{ - "name": "Alert", - "value": "NodeExporter" - },{ - "name": "In host", - "value": "node2.summit" - },{ - "name": "Severity", - "value": "critical" - },{ - "name": "Description", - "value": "Node exporter down on node2.summit" - },{ - "name": "Status", - "value": "firing" - },{ - "name": "job", - "value": "node_exporter" - },{ - "name": "env", - "value": "production" - },{ - "name": "notify_room", - "value": "test" - },{ - "name": "type", - "value": "nodeexporter" - } ], - "markdown": true - }] + "type": "message", + "attachments": [ + { + "contentType": "application/vnd.microsoft.card.adaptive", + "content": { + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.4", + "msteams": { + "width": "Full" + }, + "body": [ + { + "type": "ColumnSet", + "style": "attention", + "columns": [ + { + "type": "Column", + "width": "stretch", + "items": [ + { + "type": "TextBlock", + "text": "Prometheus alert NodeExporter triggered", + "weight": "Bolder", + "size": "Large" + }, + { + "type": "TextBlock", + "text": "Node exporter down on node2.summit", + "wrap": true + } + ] + } + ] + }, + { + "type": "FactSet", + "facts": [ + { + "title": "Alert", + "value": "NodeExporter" + }, + { + "title": "In host", + "value": "node2.summit" + }, + { + "title": "Severity", + "value": "critical" + }, + { + "title": "Description", + "value": "Node exporter down on node2.summit" + }, + { + "title": "Status", + "value": "firing" + }, + { + "title": "job", + "value": "node_exporter" + }, + { + "title": "notify_room", + "value": "test" + }, + { + "title": "env", + "value": "production" + }, + { + "title": "type", + "value": "nodeexporter" + } + ] + } + ] + } + } + ] + } } }, "times": { @@ -218,6 +489,100 @@ run_tests(){ } }') + test3verify=$(curl -s -w "%{http_code}\n" -X PUT "http://localhost:1080/mockserver/verify" -d '{ + "httpRequest": { + "method": "POST", + "path": "/api/test", + "body": { + "type": "message", + "attachments": [ + { + "contentType": "application/vnd.microsoft.card.adaptive", + "content": { + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.4", + "msteams": { + "width": "Full" + }, + "body": [ + { + "type": "ColumnSet", + "style": "attention", + "columns": [ + { + "type": "Column", + "width": "stretch", + "items": [ + { + "type": "TextBlock", + "text": "Prometheus alert NodeExporter triggered", + "weight": "Bolder", + "size": "Large" + }, + { + "type": "TextBlock", + "text": "Node exporter down on node3.summit", + "wrap": true + } + ] + } + ] + }, + { + "type": "FactSet", + "facts": [ + { + "title": "Alert", + "value": "NodeExporter" + }, + { + "title": "In host", + "value": "node3.summit" + }, + { + "title": "Severity", + "value": "critical" + }, + { + "title": "Description", + "value": "Node exporter down on node3.summit" + }, + { + "title": "Status", + "value": "firing" + }, + { + "title": "job", + "value": "node_exporter" + }, + { + "title": "notify_room", + "value": "test" + }, + { + "title": "env", + "value": "production" + }, + { + "title": "type", + "value": "nodeexporter" + } + ] + } + ] + } + } + ] + } + } + }, + "times": { + "atLeast": 1, + "atMost": 1 + } + }') + passing=1 if [[ "$test1" -eq 201 && "$test1verify" -eq 202 ]] then @@ -233,6 +598,13 @@ run_tests(){ echo "Test 2: Failed" passing=0 fi + if [[ "$test3" -eq 201 && "$test3verify" -eq 202 ]] + then + echo "Test 3: OK" + else + echo "Test 3: Failed" + passing=0 + fi } destroy_containers(){ diff --git a/tests/test_json_fields.py b/tests/test_json_fields.py index e74b716..e6ef6bc 100644 --- a/tests/test_json_fields.py +++ b/tests/test_json_fields.py @@ -1,12 +1,13 @@ -import unittest -import os import json +import os +import unittest + +from deepdiff import DeepDiff -from prom2teams.teams.alert_mapper import map_prom_alerts_to_teams_alerts -from prom2teams.prometheus.message_schema import MessageSchema from prom2teams.app.sender import AlertSender +from prom2teams.prometheus.message_schema import MessageSchema +from prom2teams.teams.alert_mapper import map_prom_alerts_to_teams_alerts -from deepdiff import DeepDiff class TestJSONFields(unittest.TestCase): TEST_CONFIG_FILES_PATH = './tests/data/json_files/' @@ -115,15 +116,15 @@ def test_with_extra_annotations(self): excluded_annotations = ('message', ) with open(os.path.join(self.TEST_CONFIG_FILES_PATH, 'all_ok_extra_annotations.json')) as json_data: with open(os.path.join(self.TEST_CONFIG_FILES_PATH, 'teams_alert_all_ok_extra_annotations.json')) as expected_data: - json_received = json.load(json_data) - json_expected = json.load(expected_data) + json_received = json.load(json_data) + json_expected = json.load(expected_data) - alerts = MessageSchema(exclude_annotations=excluded_annotations).load(json_received) - rendered_data = AlertSender()._create_alerts(alerts)[0] - json_rendered = json.loads(rendered_data) + alerts = MessageSchema(exclude_annotations=excluded_annotations).load(json_received) + rendered_data = AlertSender()._create_alerts(alerts)[0] + json_rendered = json.loads(rendered_data) - diff = DeepDiff(json_rendered, json_expected, ignore_order=True) - self.assertTrue(not diff) + diff = DeepDiff(json_rendered, json_expected, ignore_order=True) + self.assertTrue(not diff) def test_with_too_long_payload(self): with open(os.path.join(self.TEST_CONFIG_FILES_PATH, 'all_ok_multiple.json')) as json_data: @@ -132,7 +133,8 @@ def test_with_too_long_payload(self): json_expected = json.load(expected_data) alerts = MessageSchema().load(json_received) - rendered_data = '[' + ','.join([a.replace("\n\n\n", " ") for a in AlertSender(group_alerts_by='name', teams_client_config={'MAX_PAYLOAD': 800})._create_alerts(alerts)]) + ']' + + rendered_data = '[' + ','.join([a.replace("\n\n\n", " ") for a in AlertSender(group_alerts_by='name', teams_client_config={'MAX_PAYLOAD': 1600})._create_alerts(alerts)]) + ']' json_rendered = json.loads(rendered_data) diff = DeepDiff(json_rendered, json_expected, ignore_order=True)