diff --git a/CHANGELOG.md b/CHANGELOG.md index cb0b79c..4048a60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ This project adheres to [Semantic Versioning](http://semver.org/) and [Keep a ch ## [Unreleased](https://github.com/idealista/prom2teams/tree/develop) +## [3.2.3](https://github.com/idealista/prom2teams/tree/3.2.3) +[Full Changelog](https://github.com/idealista/prom2teams/compare/3.2.2...3.2.3) +### Fixed +- *[#271](https://github.com/idealista/prom2teams/pull/271) Sending a message with double quotes in TeamsAlert fields breaks MS Teams communication* @earthquakesan + ## [3.2.2](https://github.com/idealista/prom2teams/tree/3.2.2) [Full Changelog](https://github.com/idealista/prom2teams/compare/3.2.1...3.2.2) ### Changed diff --git a/helm/Chart.yaml b/helm/Chart.yaml index b028c12..e5427f6 100644 --- a/helm/Chart.yaml +++ b/helm/Chart.yaml @@ -1,5 +1,5 @@ apiVersion: v1 -appVersion: "3.2.2" +appVersion: "3.2.3" description: A Helm chart for Prom2Teams name: prom2teams version: 0.2.0 diff --git a/prom2teams/teams/alert_mapper.py b/prom2teams/teams/alert_mapper.py index 25b20b2..254a758 100644 --- a/prom2teams/teams/alert_mapper.py +++ b/prom2teams/teams/alert_mapper.py @@ -1,6 +1,7 @@ from collections import defaultdict, OrderedDict from prom2teams.teams.teams_alert_schema import TeamsAlert, TeamsAlertSchema +from prom2teams.teams.teams_alert_validation import remove_double_quotes_from_teams_alert GROUPABLE_FIELDS = ['name', 'description', 'instance', 'severity', 'status', 'summary', 'fingerprint', 'runbook_url'] @@ -18,6 +19,7 @@ def map_prom_alerts_to_teams_alerts(alerts): alert.summary, alert.instance, alert.description, alert.fingerprint, alert.runbook_url, alert.extra_labels, alert.extra_annotations) + alert = remove_double_quotes_from_teams_alert(alert) json_alert = schema.dump(alert) teams_alerts.append(json_alert) return teams_alerts diff --git a/prom2teams/teams/teams_alert_validation.py b/prom2teams/teams/teams_alert_validation.py new file mode 100644 index 0000000..6c4a1e8 --- /dev/null +++ b/prom2teams/teams/teams_alert_validation.py @@ -0,0 +1,15 @@ +def remove_double_quotes_from_teams_alert(alert): + """Remove double quotes from all the fields""" + for field in alert.__dict__: + if field == "extra_annotations" or field == "extra_labels": + new_inner_map = {} + for inner_field in alert.__getattribute__(field): + original_value = alert.__getattribute__(field)[inner_field] + modified_value = original_value.replace('"', '') + new_inner_map[inner_field] = modified_value + alert.__setattr__(field, new_inner_map) + else: + original_value = alert.__getattribute__(field) + modified_value = original_value.replace('"', '') + alert.__setattr__(field, modified_value) + return alert diff --git a/setup.py b/setup.py index ff25f28..b792fc4 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ setup(name='prom2teams', - version='3.2.2', + version='3.2.3', description='Project that redirects Prometheus Alert Manager ' 'notifications to Microsoft Teams', long_description=readme, diff --git a/tests/test_alert_validation.py b/tests/test_alert_validation.py new file mode 100644 index 0000000..932325c --- /dev/null +++ b/tests/test_alert_validation.py @@ -0,0 +1,54 @@ +import unittest +import os + +from prom2teams.teams.teams_alert_validation import remove_double_quotes_from_teams_alert +from prom2teams.teams.teams_alert_schema import TeamsAlert + +ALERT = { + "name": "Watchdog", + "status": "firing", + "severity": 'non""""e', + "summary": "unknown", + "instance": "unknown", + "description": "unknown", + "fingerprint": '07109567b88e9"""""eb6c', + "runbook_url": "", + "extra_labels": {'prometheus': 'cattle-monitoring-s"""""ystem/rancher-monitoring-prometheus'}, + "extra_annotations": {'message': 'This is an alert meant to ensure that the entire alerting pipeline is functional.\nThis alert is always firing, therefore it should always be firing in Alertmanager\nand always fire against a receiver. There are integrations with various notification\nmechanisms that send a notification when this alert is not firing. For example the\n"DeadMansSnitch" integration in PagerDuty.\n'}, +} + +ALERT_WITHOUT_QUOTES = { + "name": "Watchdog", + "status": "firing", + "severity": 'none', + "summary": "unknown", + "instance": "unknown", + "description": "unknown", + "fingerprint": '07109567b88e9eb6c', + "runbook_url": "", + "extra_labels": {'prometheus': 'cattle-monitoring-system/rancher-monitoring-prometheus'}, + "extra_annotations": {'message': 'This is an alert meant to ensure that the entire alerting pipeline is functional.\nThis alert is always firing, therefore it should always be firing in Alertmanager\nand always fire against a receiver. There are integrations with various notification\nmechanisms that send a notification when this alert is not firing. For example the\nDeadMansSnitch integration in PagerDuty.\n'}, +} + +TEAMS_ALERT = TeamsAlert(ALERT['name'], ALERT['status'].lower(), ALERT['severity'], + ALERT['summary'], ALERT['instance'], ALERT['description'], + ALERT['fingerprint'], ALERT['runbook_url'], ALERT['extra_labels'], + ALERT['extra_annotations']) + +TEAMS_ALERT_WITHOUT_QUOTES = TeamsAlert(ALERT_WITHOUT_QUOTES['name'], ALERT_WITHOUT_QUOTES['status'].lower(), ALERT_WITHOUT_QUOTES['severity'], + ALERT_WITHOUT_QUOTES['summary'], ALERT_WITHOUT_QUOTES['instance'], ALERT_WITHOUT_QUOTES['description'], + ALERT_WITHOUT_QUOTES['fingerprint'], ALERT_WITHOUT_QUOTES['runbook_url'], ALERT_WITHOUT_QUOTES['extra_labels'], + ALERT_WITHOUT_QUOTES['extra_annotations']) + + +class TestServer(unittest.TestCase): + def test_remove_double_quotes_from_teams_alert(self): + alert = remove_double_quotes_from_teams_alert(TEAMS_ALERT) + self.assertEqual(alert.extra_labels, TEAMS_ALERT_WITHOUT_QUOTES.extra_labels) + self.assertEqual(alert.extra_annotations, TEAMS_ALERT_WITHOUT_QUOTES.extra_annotations) + self.assertEqual(alert.severity, TEAMS_ALERT_WITHOUT_QUOTES.severity) + self.assertEqual(alert.fingerprint, TEAMS_ALERT_WITHOUT_QUOTES.fingerprint) + + +if __name__ == '__main__': + unittest.main()