From b76c1cc0f290ff3ca419d37da4bef9d72eda0179 Mon Sep 17 00:00:00 2001 From: Jose Date: Fri, 9 Feb 2018 10:09:07 +0100 Subject: [PATCH 01/28] #45 Add Dockerfile, sample config.ini and scripts for replacing variables and starting Prom2teams --- dockerhub/Dockerfile | 18 ++++++++++++++++++ dockerhub/config.ini | 6 ++++++ dockerhub/prom2teams_start.sh | 3 +++ dockerhub/replace_config.py | 12 ++++++++++++ 4 files changed, 39 insertions(+) create mode 100644 dockerhub/Dockerfile create mode 100644 dockerhub/config.ini create mode 100644 dockerhub/prom2teams_start.sh create mode 100644 dockerhub/replace_config.py diff --git a/dockerhub/Dockerfile b/dockerhub/Dockerfile new file mode 100644 index 0000000..97942f8 --- /dev/null +++ b/dockerhub/Dockerfile @@ -0,0 +1,18 @@ +FROM python:3.5-slim-jessie + +LABEL maintainer="labs@idealista.com" + +EXPOSE 8089 + +RUN pip install prom2teams +COPY config.ini /opt/prom2teams/config.ini +COPY prom2teams_start.sh /opt/prom2teams/prom2teams_start.sh +COPY replace_config.py /opt/prom2teams/replace_config.py + +ENV PROM2TEAMS_PORT="8089" +ENV PROM2TEAMS_HOST="0.0.0.0" +ENV PROM2TEAMS_LOGLEVEL="INFO" +ENV PROM2TEAMS_CONNECTOR="" +ENV PROM2TEAMS_CONFIGPATH="/opt/prom2teams/config.ini" + +ENTRYPOINT ["bash", "/opt/prom2teams/prom2teams_start.sh"] diff --git a/dockerhub/config.ini b/dockerhub/config.ini new file mode 100644 index 0000000..7a3a338 --- /dev/null +++ b/dockerhub/config.ini @@ -0,0 +1,6 @@ +[HTTP Server] +Host: prom2teamshost +Port: prom2teamsport + +[Microsoft Teams] +Connector: prom2teamsconnector diff --git a/dockerhub/prom2teams_start.sh b/dockerhub/prom2teams_start.sh new file mode 100644 index 0000000..980af31 --- /dev/null +++ b/dockerhub/prom2teams_start.sh @@ -0,0 +1,3 @@ +#!/bin/bash +python /opt/prom2teams/replace_config.py +prom2teams --configpath /opt/prom2teams/config.ini --loglevel $PROM2TEAMS_LOGLEVEL diff --git a/dockerhub/replace_config.py b/dockerhub/replace_config.py new file mode 100644 index 0000000..3bd6b0c --- /dev/null +++ b/dockerhub/replace_config.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python +import os + +with open('/opt/prom2teams/config.ini', 'r') as file: + filedata = file.read() + +filedata = filedata.replace("prom2teamsport", os.environ.get("PROM2TEAMS_PORT")) +filedata = filedata.replace("prom2teamshost", os.environ.get("PROM2TEAMS_HOST")) +filedata = filedata.replace("prom2teamsconnector", os.environ.get("PROM2TEAMS_CONNECTOR")) + +with open('/opt/prom2teams/config.ini', 'w') as file: + file.write(filedata) From 7f12be1bc519b1e54226690288d8d0587805c299 Mon Sep 17 00:00:00 2001 From: Jose Date: Fri, 9 Feb 2018 12:43:09 +0100 Subject: [PATCH 02/28] #45 Remove unnecessary variable --- dockerhub/Dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/dockerhub/Dockerfile b/dockerhub/Dockerfile index 97942f8..6fe7e27 100644 --- a/dockerhub/Dockerfile +++ b/dockerhub/Dockerfile @@ -13,6 +13,5 @@ ENV PROM2TEAMS_PORT="8089" ENV PROM2TEAMS_HOST="0.0.0.0" ENV PROM2TEAMS_LOGLEVEL="INFO" ENV PROM2TEAMS_CONNECTOR="" -ENV PROM2TEAMS_CONFIGPATH="/opt/prom2teams/config.ini" ENTRYPOINT ["bash", "/opt/prom2teams/prom2teams_start.sh"] From c5f8faa6277ba8a2022088e9987656958ece5486 Mon Sep 17 00:00:00 2001 From: giancarlo Date: Thu, 15 Feb 2018 17:17:16 +0100 Subject: [PATCH 03/28] #22: First version allowing multiple connectors --- .idea/misc.xml | 4 + .idea/modules.xml | 8 + .idea/prom2teams.iml | 13 + .idea/vcs.xml | 6 + .idea/workspace.xml | 733 +++++++++++++++++++++ prom2teams/message/parser.py | 5 +- prom2teams/server.py | 110 ++-- prom2teams/teams/client.py | 6 +- requirements.txt | 4 +- tests/data/jsons/all_ok.json | 4 +- tests/data/multiple_connectors_config.ini | 8 + tests/data/overriding_defaults.ini | 2 +- tests/data/without_overriding_defaults.ini | 6 +- tests/test_json_fields.py | 16 +- tests/test_server.py | 19 +- 15 files changed, 845 insertions(+), 99 deletions(-) create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/prom2teams.iml create mode 100644 .idea/vcs.xml create mode 100644 .idea/workspace.xml create mode 100644 tests/data/multiple_connectors_config.ini diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..29fca8c --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..fe358af --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/prom2teams.iml b/.idea/prom2teams.iml new file mode 100644 index 0000000..58514a3 --- /dev/null +++ b/.idea/prom2teams.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..ec34984 --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,733 @@ + + + + + + + + + + + + + + + + + + + + + parse + get_config + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1518619060622 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file From 5cf5f41923199a43ab1f37e4481a0d392f0eadfc Mon Sep 17 00:00:00 2001 From: giancarlo Date: Fri, 16 Feb 2018 12:01:39 +0100 Subject: [PATCH 05/28] #22: fix test_get_config_without_override / DeprecationWarning added --- prom2teams/server.py | 18 +++++++++++++++++- tests/data/without_overriding_defaults.ini | 4 ---- tests/test_server.py | 2 +- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/prom2teams/server.py b/prom2teams/server.py index fabb272..1ff2c95 100644 --- a/prom2teams/server.py +++ b/prom2teams/server.py @@ -1,6 +1,7 @@ import logging import configparser import os +import warnings from logging.config import fileConfig from flask import Flask, request @@ -34,6 +35,8 @@ def post(self, connector): @api.route('/') class AlarmSenderDeprecated(Resource): def post(self): + deprecated_message = "Call to deprecated function. It will be removed in future versions. Please view the README file." + show_deprecated_warning(deprecated_message) json_str = request.get_json() webhook_url = config['Microsoft Teams']['Connector'] send_alarms_to_teams(json_str, webhook_url, template_path) @@ -65,14 +68,27 @@ def load_logging_config(log_file_path, log_level): def get_config(provided_config_file): provided_config = configparser.ConfigParser() + default_config_path = os.path.join(dir, 'config.ini') + try: + + with open(default_config_path) as f_default: + provided_config.read_file(f_default) + with open(provided_config_file) as f_prov: provided_config.read_file(f_prov) + if not provided_config.options('Microsoft Teams'): raise MissingConnectorConfigKeyException('missing connector key in provided config') except configparser.NoSectionError: raise MissingConnectorConfigKeyException('missing required Microsoft Teams / ' 'connector key in provided config') - return provided_config + + +def show_deprecated_warning(message): + warnings.simplefilter('always', DeprecationWarning) + warnings.warn(message=message, category=DeprecationWarning) + warnings.simplefilter('default', DeprecationWarning) + diff --git a/tests/data/without_overriding_defaults.ini b/tests/data/without_overriding_defaults.ini index 02efc03..270550f 100644 --- a/tests/data/without_overriding_defaults.ini +++ b/tests/data/without_overriding_defaults.ini @@ -1,6 +1,2 @@ -[HTTP Server] -Host: 1.1.1.1 -Port: 8089 - [Microsoft Teams] Connector = some_url diff --git a/tests/test_server.py b/tests/test_server.py index fe55a7e..30a0a52 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -29,7 +29,7 @@ def test_get_config_without_override(self): 'without_overriding_defaults.ini' config = server.get_config(provided_config_relative_path) - self.assertEqual(config.get('HTTP Server', 'Host'), '1.1.1.1') + self.assertEqual(config.get('HTTP Server', 'Host'), '0.0.0.0') self.assertEqual(config.get('HTTP Server', 'Port'), '8089') self.assertTrue(config.get('Microsoft Teams', 'Connector')) From e9efa9d233bed10900604984245d3cd72a6d5d83 Mon Sep 17 00:00:00 2001 From: manuhortet Date: Mon, 19 Feb 2018 10:01:54 +0100 Subject: [PATCH 06/28] minor changes in style + changed the warnings for decrecation --- README.md | 5 ++++- bin/prom2teams | 3 +-- prom2teams/message/parser.py | 1 - prom2teams/server.py | 14 ++++++-------- tests/context.py | 2 +- tests/test_server.py | 6 ++---- 6 files changed, 14 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 3362a24..ee04fc9 100644 --- a/README.md +++ b/README.md @@ -62,9 +62,12 @@ Host: # default: 0.0.0.0 Port: # default: 8089 [Microsoft Teams] -Connector: # required value +connector1: # required value +connector2: # required value +... ``` + ### Configuring Prometheus The [webhook receiver](https://prometheus.io/docs/alerting/configuration/#) in Prometheus allows configuring a prom2teams server. diff --git a/bin/prom2teams b/bin/prom2teams index 7add482..b5ea3f5 100755 --- a/bin/prom2teams +++ b/bin/prom2teams @@ -1,9 +1,9 @@ #!/usr/bin/env python3 - import sys import os import argparse + try: from prom2teams.server import run except ImportError: @@ -22,5 +22,4 @@ if __name__ == "__main__": parser.add_argument('-t', '--templatepath', help='Jinja2 template file path', required=False) args = parser.parse_args() - run(args.configpath, args.templatepath, args.logfilepath, args.loglevel) diff --git a/prom2teams/message/parser.py b/prom2teams/message/parser.py index 09a1ed6..4d97464 100644 --- a/prom2teams/message/parser.py +++ b/prom2teams/message/parser.py @@ -10,7 +10,6 @@ def check_fields(json_alerts_attr, json_alerts_labels_attr, json_alerts_annotati fields = mandatory_fields + optional_fields alert_fields = {} - for field in fields: alert_field_key = 'alert_' + field if field in json_alerts_attr: diff --git a/prom2teams/server.py b/prom2teams/server.py index 1ff2c95..c0af151 100644 --- a/prom2teams/server.py +++ b/prom2teams/server.py @@ -16,7 +16,9 @@ logger = logging.getLogger() dir = os.path.dirname(__file__) + def run(provided_config_file, template_path, log_file_path, log_level): + warnings.simplefilter('once', PendingDeprecationWarning) config = get_config(provided_config_file) load_logging_config(log_file_path, log_level) host = config['HTTP Server']['Host'] @@ -35,7 +37,8 @@ def post(self, connector): @api.route('/') class AlarmSenderDeprecated(Resource): def post(self): - deprecated_message = "Call to deprecated function. It will be removed in future versions. Please view the README file." + deprecated_message = "Call to deprecated function. It will be removed in future versions. " \ + "Please view the README file." show_deprecated_warning(deprecated_message) json_str = request.get_json() webhook_url = config['Microsoft Teams']['Connector'] @@ -57,7 +60,7 @@ def send_alarms_to_teams(json, teams_webhook_url, template_path): def load_logging_config(log_file_path, log_level): config_file = os.path.join(dir, 'logging_console_config.ini') defaults = {'log_level': log_level} - if(log_file_path): + if log_file_path: config_file = os.path.join(dir, 'logging_file_config.ini') defaults = { 'log_level': log_level, @@ -69,9 +72,7 @@ def load_logging_config(log_file_path, log_level): def get_config(provided_config_file): provided_config = configparser.ConfigParser() default_config_path = os.path.join(dir, 'config.ini') - try: - with open(default_config_path) as f_default: provided_config.read_file(f_default) @@ -88,7 +89,4 @@ def get_config(provided_config_file): def show_deprecated_warning(message): - warnings.simplefilter('always', DeprecationWarning) - warnings.warn(message=message, category=DeprecationWarning) - warnings.simplefilter('default', DeprecationWarning) - + warnings.warn(message=message, category=PendingDeprecationWarning) diff --git a/tests/context.py b/tests/context.py index 8595e3b..0c60e7e 100644 --- a/tests/context.py +++ b/tests/context.py @@ -1,7 +1,7 @@ import os import sys -sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../prom2teams'))) +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../prom2teams'))) from prom2teams import server, exceptions from prom2teams.message.parser import parse diff --git a/tests/test_server.py b/tests/test_server.py index 30a0a52..df604a1 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -1,11 +1,10 @@ import unittest -from context import server -from context import exceptions +from .context import server +from .context import exceptions class TestServer(unittest.TestCase): - TEST_CONFIG_FILES_PATH = 'tests/data/' DEFAULT_CONFIG_RELATIVE_PATH = './prom2teams/config.ini' @@ -42,7 +41,6 @@ def test_get_config_overriding_defaults(self): self.assertEqual(config.get('HTTP Server', 'Port'), '9089') self.assertTrue(config.get('Microsoft Teams', 'Connector')) - def test_connectors_configured(self): provided_config_relative_path = self.TEST_CONFIG_FILES_PATH + \ 'multiple_connectors_config.ini' From 98c4cedd720188a9d058dcc0bcaac55625e6332a Mon Sep 17 00:00:00 2001 From: manuhortet Date: Mon, 19 Feb 2018 12:00:17 +0100 Subject: [PATCH 07/28] minor changes in README --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ee04fc9..0713100 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Alert example -**prom2teams** is an HTTP server built with Python that receives alert notifications from a previously configured [Prometheus Alertmanager](https://github.com/prometheus/alertmanager) instance and forwards it to [Microsoft Teams](https://teams.microsoft.com/) using defined connectors. +**prom2teams** is a Web server built with Python that receives alert notifications from a previously configured [Prometheus Alertmanager](https://github.com/prometheus/alertmanager) instance and forwards it to [Microsoft Teams](https://teams.microsoft.com/) using defined connectors. - [Getting Started](#getting-started) - [Prerequisities](#prerequisities) @@ -62,8 +62,8 @@ Host: # default: 0.0.0.0 Port: # default: 8089 [Microsoft Teams] -connector1: # required value -connector2: # required value +connector1: # At least one connector is required +connector2: ... ``` @@ -74,9 +74,11 @@ The [webhook receiver](https://prometheus.io/docs/alerting/configuration/# ``` ### Templating From dcefd586a017e55238c452db3bd3d01b1f7a22df Mon Sep 17 00:00:00 2001 From: manuhortet Date: Mon, 19 Feb 2018 12:29:06 +0100 Subject: [PATCH 08/28] minor change in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0713100..13d1f5a 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ The url is formed by the host and port defined in the previous step. ``` # The prom2teams endpoint to send HTTP POST requests to. -url: 0.0.0.0:8089/ +url: 0.0.0.0:8089/v2/ ``` ### Templating From d34c702967ec5e1cfab8395256615d0562f3f57f Mon Sep 17 00:00:00 2001 From: manuhortet Date: Mon, 19 Feb 2018 13:35:40 +0100 Subject: [PATCH 09/28] conflict importing modules solved --- tests/test_server.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_server.py b/tests/test_server.py index df604a1..47e11c4 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -1,7 +1,7 @@ import unittest -from .context import server -from .context import exceptions +from context import server +from context import exceptions class TestServer(unittest.TestCase): From 07436f1bf3e92130518b01ff0e878c8352b91ae0 Mon Sep 17 00:00:00 2001 From: manuhortet Date: Mon, 19 Feb 2018 16:23:45 +0100 Subject: [PATCH 10/28] solved some minor observations before PR --- README.md | 7 ++++--- prom2teams/config.ini | 2 +- prom2teams/message/parser.py | 4 +++- prom2teams/server.py | 7 +++++-- requirements.txt | 8 ++++---- tests/data/jsons/all_ok.json | 2 +- tests/data/multiple_connectors_config.ini | 6 +++--- tests/data/overriding_defaults.ini | 2 +- tests/data/without_overriding_defaults.ini | 2 +- 9 files changed, 23 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 13d1f5a..786047b 100644 --- a/README.md +++ b/README.md @@ -62,8 +62,9 @@ Host: # default: 0.0.0.0 Port: # default: 8089 [Microsoft Teams] -connector1: # At least one connector is required -connector2: +# At least one connector is required here +Connector1: +ConnectorTwo: ... ``` @@ -78,7 +79,7 @@ The url is formed by the host and port defined in the previous step. ``` # The prom2teams endpoint to send HTTP POST requests to. -url: 0.0.0.0:8089/v2/ +url: 0.0.0.0:8089/v2/ ``` ### Templating diff --git a/prom2teams/config.ini b/prom2teams/config.ini index 58fe534..e84bc03 100644 --- a/prom2teams/config.ini +++ b/prom2teams/config.ini @@ -1,3 +1,3 @@ [HTTP Server] Host: 0.0.0.0 -Port: 8089 +Port: 9089 diff --git a/prom2teams/message/parser.py b/prom2teams/message/parser.py index 4d97464..61b5f49 100644 --- a/prom2teams/message/parser.py +++ b/prom2teams/message/parser.py @@ -1,6 +1,8 @@ import json import logging +from flask_restplus import reqparse + logger = logging.getLogger() @@ -33,5 +35,5 @@ def parse(json_values): json_alerts_attr = alert json_alerts_labels_attr = json_alerts_attr['labels'] json_alerts_annotations_attr = json_alerts_attr['annotations'] - parsed_alarms['alarm_' + str(i)]=check_fields(json_alerts_attr, json_alerts_labels_attr, json_alerts_annotations_attr) + parsed_alarms['alarm_' + str(i)] = check_fields(json_alerts_attr, json_alerts_labels_attr, json_alerts_annotations_attr) return parsed_alarms diff --git a/prom2teams/server.py b/prom2teams/server.py index c0af151..f5089cf 100644 --- a/prom2teams/server.py +++ b/prom2teams/server.py @@ -5,7 +5,7 @@ from logging.config import fileConfig from flask import Flask, request -from flask_restplus import Api, Resource +from flask_restplus import Api, Resource, reqparse from prom2teams.teams.client import post from prom2teams.teams.json_composer import compose @@ -49,7 +49,10 @@ def post(self): def send_alarms_to_teams(json, teams_webhook_url, template_path): - alarms = parse(json) + parser = reqparse.RequestParser() + parser.add_argument("alert", action="append") + alarms = + # alarms = parse(json) for key, alarm in alarms.items(): sending_alarm = compose(template_path, alarm) logger.debug('The message that will be sent is: %s', diff --git a/requirements.txt b/requirements.txt index 84ce943..a988a48 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ ## Requirements -requests -jinja2 -flask -flask-restplus \ No newline at end of file +requests==2.9.1 +Jinja2==2.10 +Flask==0.12.2 +flask-restplus==0.10.1 diff --git a/tests/data/jsons/all_ok.json b/tests/data/jsons/all_ok.json index ef749ee..6092232 100644 --- a/tests/data/jsons/all_ok.json +++ b/tests/data/jsons/all_ok.json @@ -8,7 +8,7 @@ "alertname": "DiskSpace", "device": "rootfs", "fstype": "rootfs", - "instance": "idealista.Test", + "instance": "cs30.evilcorp", "job": "fsociety", "mountpoint": "/", "severity": "severe" diff --git a/tests/data/multiple_connectors_config.ini b/tests/data/multiple_connectors_config.ini index d11575e..e24628e 100644 --- a/tests/data/multiple_connectors_config.ini +++ b/tests/data/multiple_connectors_config.ini @@ -3,6 +3,6 @@ Host: 1.1.1.1 Port: 9089 [Microsoft Teams] -connector1 = teams_webhook_url -connector2 = another_teams_webhook_url -connector3 = definitely_another_teams_webhook_url \ No newline at end of file +connector1: teams_webhook_url +connector2: another_teams_webhook_url +connector3: definitely_another_teams_webhook_url \ No newline at end of file diff --git a/tests/data/overriding_defaults.ini b/tests/data/overriding_defaults.ini index c700256..990bb08 100644 --- a/tests/data/overriding_defaults.ini +++ b/tests/data/overriding_defaults.ini @@ -3,4 +3,4 @@ Host: 1.1.1.1 Port: 9089 [Microsoft Teams] -Connector = some_url +Connector: some_url diff --git a/tests/data/without_overriding_defaults.ini b/tests/data/without_overriding_defaults.ini index 270550f..87cc092 100644 --- a/tests/data/without_overriding_defaults.ini +++ b/tests/data/without_overriding_defaults.ini @@ -1,2 +1,2 @@ [Microsoft Teams] -Connector = some_url +Connector: some_url From b1e8108d3235debc51f8efb0f19f22c75c613c11 Mon Sep 17 00:00:00 2001 From: manuhortet Date: Mon, 19 Feb 2018 16:27:35 +0100 Subject: [PATCH 11/28] Port default value switched back to 8089 --- prom2teams/config.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prom2teams/config.ini b/prom2teams/config.ini index e84bc03..58fe534 100644 --- a/prom2teams/config.ini +++ b/prom2teams/config.ini @@ -1,3 +1,3 @@ [HTTP Server] Host: 0.0.0.0 -Port: 9089 +Port: 8089 From 4ecf2a896fb480dd510a816df145ef66f70f1c2e Mon Sep 17 00:00:00 2001 From: manuhortet Date: Mon, 19 Feb 2018 16:30:42 +0100 Subject: [PATCH 12/28] cleaned server.py --- prom2teams/server.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/prom2teams/server.py b/prom2teams/server.py index f5089cf..610a473 100644 --- a/prom2teams/server.py +++ b/prom2teams/server.py @@ -49,10 +49,7 @@ def post(self): def send_alarms_to_teams(json, teams_webhook_url, template_path): - parser = reqparse.RequestParser() - parser.add_argument("alert", action="append") - alarms = - # alarms = parse(json) + alarms = parse(json) for key, alarm in alarms.items(): sending_alarm = compose(template_path, alarm) logger.debug('The message that will be sent is: %s', From 36f689f65ed545a344cc37657e1b440b029488c3 Mon Sep 17 00:00:00 2001 From: giancarlo Date: Tue, 20 Feb 2018 18:41:57 +0100 Subject: [PATCH 13/28] new parser and Swagger UI --- prom2teams/message/alarm_mapper.py | 37 +++++++++++++++++ prom2teams/message/alarm_schema.py | 29 ++++++++++++++ prom2teams/message/message_schema.py | 33 +++++++++++++++ prom2teams/message/parser.py | 39 ------------------ prom2teams/model.py | 40 +++++++++++++++++++ prom2teams/server.py | 35 +++++++++------- prom2teams/teams/json_composer.py | 4 +- prom2teams/teams/template.j2 | 26 ++++++------ requirements.txt | 2 + tests/context.py | 2 +- tests/data/jsons/without_mandatory_field.json | 3 +- tests/test_json_fields.py | 16 +++++--- 12 files changed, 189 insertions(+), 77 deletions(-) create mode 100644 prom2teams/message/alarm_mapper.py create mode 100644 prom2teams/message/alarm_schema.py create mode 100644 prom2teams/message/message_schema.py delete mode 100644 prom2teams/message/parser.py create mode 100644 prom2teams/model.py diff --git a/prom2teams/message/alarm_mapper.py b/prom2teams/message/alarm_mapper.py new file mode 100644 index 0000000..a695904 --- /dev/null +++ b/prom2teams/message/alarm_mapper.py @@ -0,0 +1,37 @@ +import logging + +from .message_schema import MessageSchema +from .alarm_schema import Alarm, AlarmSchema + + +logger = logging.getLogger() + +class AlarmMapper: + + def map_to_alarms(json): + alarms = [] + schema = MessageSchema() + result = schema.load(json) + + message = result.data + + for alert in message['alerts']: + # mandatory + status = alert['status'] + summary = alert['annotations']['summary'] + instance = alert['labels']['instance'] + name = alert['labels']['alertname'] + description = alert['annotations']['description'] + severity = alert['labels']['severity'] + + + alarm = Alarm(name, status, severity, summary, instance, description) + alarms.append(alarm) + + return alarms + + def map_alarm_to_json(alarm): + schema = AlarmSchema() + result = schema.dump(alarm) + return result.data + diff --git a/prom2teams/message/alarm_schema.py b/prom2teams/message/alarm_schema.py new file mode 100644 index 0000000..59431bf --- /dev/null +++ b/prom2teams/message/alarm_schema.py @@ -0,0 +1,29 @@ +from marshmallow import Schema, fields + + +class AlarmSchema(Schema): + status = fields.Str() + severity = fields.Str() + summary = fields.Str() + instance = fields.Str() + description = fields.Str() + name = fields.Str() + +class Alarm: + def __init__(self, name, status, severity, summary, instance, description): + self.name = name + self.status = status + self.severity = severity + self.summary = summary + self.instance = instance + self.description = description + + + + + + + + + + diff --git a/prom2teams/message/message_schema.py b/prom2teams/message/message_schema.py new file mode 100644 index 0000000..36615a1 --- /dev/null +++ b/prom2teams/message/message_schema.py @@ -0,0 +1,33 @@ +from marshmallow import Schema, fields, validates + + +class MessageSchema(Schema): + receiver = fields.Str() + status = fields.Str(default='unknown', missing='unknown') + alerts = fields.Nested('AlertSchema', many=True) + externalURL = fields.Str() + version = fields.Str() + + +class AlertSchema(Schema): + status = fields.Str(default='unknown', missing='unknown') + labels = fields.Nested('LabelSchema', many=False) + annotations = fields.Nested('AnnotationSchema', many=False) + startsAt = fields.Date() + endsAt = fields.Date() + generatorURL = fields.Str() + + +class LabelSchema(Schema): + alertname = fields.Str(default='unknown', missing='unknown') + device = fields.Str() + fstype = fields.Str() + instance = fields.Str(default='unknown', missing='unknown') + job = fields.Str() + mountpoint = fields.Str() + severity = fields.Str(default=None, missing=None) + + +class AnnotationSchema(Schema): + description = fields.Str(default=None, missing=None) + summary = fields.Str(default='unknown', missing='unknown') diff --git a/prom2teams/message/parser.py b/prom2teams/message/parser.py deleted file mode 100644 index 61b5f49..0000000 --- a/prom2teams/message/parser.py +++ /dev/null @@ -1,39 +0,0 @@ -import json -import logging - -from flask_restplus import reqparse - - -logger = logging.getLogger() - -def check_fields(json_alerts_attr, json_alerts_labels_attr, json_alerts_annotations_attr): - mandatory_fields = ['alertname', 'status', 'instance', 'summary'] - optional_fields = ['severity', 'description'] - fields = mandatory_fields + optional_fields - - alert_fields = {} - for field in fields: - alert_field_key = 'alert_' + field - if field in json_alerts_attr: - alert_fields[alert_field_key] = json_alerts_attr[field] - elif field in json_alerts_labels_attr: - alert_fields[alert_field_key] = json_alerts_labels_attr[field] - elif field in json_alerts_annotations_attr: - alert_fields[alert_field_key] = json_alerts_annotations_attr[field] - # If the field isn't in the JSON but it's a mandatory field, then we use default values - elif field in mandatory_fields: - if field in json_alerts_attr: - alert_fields[alert_field_key] = json_alerts_attr[field] - else: - alert_fields[alert_field_key] = 'unknown' - return alert_fields - - -def parse(json_values): - parsed_alarms = {} - for i, alert in enumerate(json_values['alerts']): - json_alerts_attr = alert - json_alerts_labels_attr = json_alerts_attr['labels'] - json_alerts_annotations_attr = json_alerts_attr['annotations'] - parsed_alarms['alarm_' + str(i)] = check_fields(json_alerts_attr, json_alerts_labels_attr, json_alerts_annotations_attr) - return parsed_alarms diff --git a/prom2teams/model.py b/prom2teams/model.py new file mode 100644 index 0000000..615f25d --- /dev/null +++ b/prom2teams/model.py @@ -0,0 +1,40 @@ +from flask_restplus import fields +from .server import api + +annotations = api.model('annotations', { + 'description': fields.String(default='disk usage 93% on rootfs device'), + 'summary': fields.String(default='Disk usage alert on CS30.evilcorp') +}) + +labels = api.model('labels', { + 'alertname': fields.String(default='DiskSpace'), + 'fstype': fields.String(default='rootfs'), + 'device': fields.String(default='rootfs'), + 'instance': fields.String(default='cs30.evilcorp'), + 'job': fields.String(default='fsociety'), + 'mounterpoint': fields.String(default='/'), + 'severity': fields.String(default='severe') +}) + +alert = api.model('alert', { + 'status': fields.String(default='Resolved'), + 'startsAt': fields.String(default='2017-05-09T07:01:37.803Z'), + 'endsAt': fields.String(default='2017-05-09T07:01:37.803Z'), + 'generatorURL': fields.String(default='my.prometheusserver.url'), + 'labels': fields.Nested(labels), + 'annotations': fields.Nested(annotations) +}) + +message = api.model('message', { + 'receiver': fields.String(default='test_webhook'), + 'status': fields.String(default='Resolved'), + 'alerts': fields.List(fields.Nested(alert)), + 'externalURL': fields.String(default='my.prometheusalertmanager.url'), + 'version': fields.String(default='4') +}) + + + + + + diff --git a/prom2teams/server.py b/prom2teams/server.py index 610a473..802fbb3 100644 --- a/prom2teams/server.py +++ b/prom2teams/server.py @@ -5,17 +5,23 @@ from logging.config import fileConfig from flask import Flask, request -from flask_restplus import Api, Resource, reqparse +from flask_restplus import Api, Resource from prom2teams.teams.client import post from prom2teams.teams.json_composer import compose -from prom2teams.message.parser import parse +from prom2teams.message.alarm_mapper import AlarmMapper from prom2teams.exceptions import MissingConnectorConfigKeyException +app = Flask(__name__) +app.config.SWAGGER_UI_JSONEDITOR = True +api = Api(app, version='2.0', title='Prom2Teams API', + description='A swagger interface for Prom2Teams webservices',) logger = logging.getLogger() dir = os.path.dirname(__file__) +from .model import message + def run(provided_config_file, template_path, log_file_path, log_level): warnings.simplefilter('once', PendingDeprecationWarning) @@ -24,14 +30,15 @@ def run(provided_config_file, template_path, log_file_path, log_level): host = config['HTTP Server']['Host'] port = int(config['HTTP Server']['Port']) - app = Flask(__name__) - api = Api(app) @api.route('/v2/') + @api.doc(params={'connector': 'Name of connector to use'}) class AlarmSender(Resource): + @api.expect(message) def post(self, connector): - json_str = request.get_json() + json = request.get_json() + alarms = AlarmMapper.map_to_alarms(json) webhook_url = config['Microsoft Teams'][connector] - send_alarms_to_teams(json_str, webhook_url, template_path) + send_alarms_to_teams(alarms, webhook_url, template_path) return 'OK', 201 @api.route('/') @@ -40,20 +47,20 @@ def post(self): deprecated_message = "Call to deprecated function. It will be removed in future versions. " \ "Please view the README file." show_deprecated_warning(deprecated_message) - json_str = request.get_json() + json = request.get_json() + alarms = AlarmMapper.map_to_alarms(json) webhook_url = config['Microsoft Teams']['Connector'] - send_alarms_to_teams(json_str, webhook_url, template_path) + send_alarms_to_teams(alarms, webhook_url, template_path) return 'OK', 201 app.run(host=host, port=port, debug=False) -def send_alarms_to_teams(json, teams_webhook_url, template_path): - alarms = parse(json) - for key, alarm in alarms.items(): - sending_alarm = compose(template_path, alarm) - logger.debug('The message that will be sent is: %s', - str(sending_alarm)) +def send_alarms_to_teams(alarms, teams_webhook_url, template_path): + + for alarm in alarms: + sending_alarm = compose(template_path, AlarmMapper.map_alarm_to_json(alarm)) + logger.debug('The message that will be sent is: %s', str(sending_alarm)) post(teams_webhook_url, sending_alarm) diff --git a/prom2teams/teams/json_composer.py b/prom2teams/teams/json_composer.py index 78c0971..75e2249 100644 --- a/prom2teams/teams/json_composer.py +++ b/prom2teams/teams/json_composer.py @@ -9,9 +9,7 @@ def compose(template_path, msg_text): template = get_template(template_path) - rendered_template = template.render( - alert_status=msg_text['alert_status'], - msg_text=msg_text) + rendered_template = template.render(status=msg_text['status'], msg_text=msg_text) return rendered_template diff --git a/prom2teams/teams/template.j2 b/prom2teams/teams/template.j2 index 72836e7..423cd55 100644 --- a/prom2teams/teams/template.j2 +++ b/prom2teams/teams/template.j2 @@ -11,26 +11,26 @@ { "@type": "MessageCard", "@context": "http://schema.org/extensions", - "themeColor": "{% if alert_status=='resolved' %} {{ theme_colors.resolved }} {% else %} {{ theme_colors[msg_text.alert_severity] }} {% endif %}", - "summary": "{{ msg_text.alert_summary }}", - "title": "Prometheus alarm {% if alert_status=='resolved' %} (Resolved) {% elif alert_status=='unknown' %} (status unknown) {% endif %}", + "themeColor": "{% if status=='resolved' %} {{ theme_colors.resolved }} {% else %} {{ theme_colors[msg_text.severity] }} {% endif %}", + "summary": "{{ msg_text.summary }}", + "title": "Prometheus alarm {% if status=='resolved' %} (Resolved) {% elif status=='unknown' %} (status unknown) {% endif %}", "sections": [{ - "activityTitle": "{{ msg_text.alert_summary }}", - "facts": [{% if msg_text.alert_alertname %}{ + "activityTitle": "{{ msg_text.summary }}", + "facts": [{% if msg_text.name %}{ "name": "Alarm", - "value": "{{ msg_text.alert_alertname }}" - },{% endif %}{% if msg_text.alert_instance %}{ + "value": "{{ msg_text.name }}" + },{% endif %}{% if msg_text.instance %}{ "name": "In host", - "value": "{{ msg_text.alert_instance }}" - },{% endif %}{% if msg_text.alert_severity %}{ + "value": "{{ msg_text.instance }}" + },{% endif %}{% if msg_text.severity %}{ "name": "Severity", - "value": "{{ msg_text.alert_severity }}" - },{% endif %}{% if msg_text.alert_description %}{ + "value": "{{ msg_text.severity }}" + },{% endif %}{% if msg_text.description %}{ "name": "Description", - "value": "{{ msg_text.alert_description }}" + "value": "{{ msg_text.description }}" },{% endif %}{ "name": "Status", - "value": "{{ msg_text.alert_status }}" + "value": "{{ msg_text.status }}" }], "markdown": true }] diff --git a/requirements.txt b/requirements.txt index a988a48..c53159d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,5 @@ requests==2.9.1 Jinja2==2.10 Flask==0.12.2 flask-restplus==0.10.1 +marshmallow==2.15.0 + diff --git a/tests/context.py b/tests/context.py index 0c60e7e..55a4529 100644 --- a/tests/context.py +++ b/tests/context.py @@ -4,4 +4,4 @@ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../prom2teams'))) from prom2teams import server, exceptions -from prom2teams.message.parser import parse +from prom2teams.message.alarm_mapper import AlarmMapper diff --git a/tests/data/jsons/without_mandatory_field.json b/tests/data/jsons/without_mandatory_field.json index 713b4b5..6a1893d 100644 --- a/tests/data/jsons/without_mandatory_field.json +++ b/tests/data/jsons/without_mandatory_field.json @@ -9,7 +9,8 @@ "mountpoint": "/" }, "annotations": { - "description": "disk usage 73% on rootfs device" + "description": "disk usage 73% on rootfs device", + "severity": "severe" }, "startsAt": "2017-05-09T07:01:37.803Z", "endsAt": "2017-05-09T07:08:37.818278068Z", diff --git a/tests/test_json_fields.py b/tests/test_json_fields.py index 6f0f2cc..02c749f 100644 --- a/tests/test_json_fields.py +++ b/tests/test_json_fields.py @@ -1,7 +1,7 @@ import unittest import json -from context import parse +from context import AlarmMapper class TestJSONFields(unittest.TestCase): @@ -11,26 +11,30 @@ class TestJSONFields(unittest.TestCase): def test_json_with_all_fields(self): with open(self.TEST_CONFIG_FILES_PATH + 'all_ok.json') as json_data: json_received = json.load(json_data) - alert_fields = parse(json_received) + alarm = AlarmMapper.map_to_alarms(json_received)[0] + alert_fields = AlarmMapper.map_alarm_to_json(alarm) self.assertNotIn('unknown', str(alert_fields)) def test_json_without_mandatory_field(self): with open(self.TEST_CONFIG_FILES_PATH + 'without_mandatory_field.json') as json_data: json_received = json.load(json_data) - alert_fields = parse(json_received) + alarm = AlarmMapper.map_to_alarms(json_received)[0] + alert_fields = AlarmMapper.map_alarm_to_json(alarm) self.assertIn('unknown', str(alert_fields)) def test_json_without_optional_field(self): with open(self.TEST_CONFIG_FILES_PATH + 'without_optional_field.json') as json_data: json_received = json.load(json_data) - alert_fields = parse(json_received) + alarm = AlarmMapper.map_to_alarms(json_received)[0] + alert_fields = AlarmMapper.map_alarm_to_json(alarm) self.assertNotIn('unknown', str(alert_fields)) def test_json_without_instance_field(self): with open(self.TEST_CONFIG_FILES_PATH + 'without_instance_field.json') as json_data: json_received = json.load(json_data) - alert_fields = parse(json_received) - self.assertEqual('unknown', str(alert_fields['alarm_0']['alert_instance'])) + alarm = AlarmMapper.map_to_alarms(json_received)[0] + alert_fields = AlarmMapper.map_alarm_to_json(alarm) + self.assertEqual('unknown', str(alert_fields['instance'])) if __name__ == '__main__': unittest.main() From 89e6a837a23d51bc6f32063bb047e5c83a795393 Mon Sep 17 00:00:00 2001 From: manuhortet Date: Tue, 20 Feb 2018 23:33:04 +0100 Subject: [PATCH 14/28] app and api launch moved to specific .py --- prom2teams/api.py | 7 +++++++ prom2teams/config.ini | 3 +++ 2 files changed, 10 insertions(+) create mode 100644 prom2teams/api.py diff --git a/prom2teams/api.py b/prom2teams/api.py new file mode 100644 index 0000000..13b228a --- /dev/null +++ b/prom2teams/api.py @@ -0,0 +1,7 @@ +from flask import Flask +from flask_restplus import Api + + +app = Flask(__name__) +app.config.SWAGGER_UI_JSONEDITOR = True +api = Api(app, version='2.0', title='Prom2Teams API', description='A swagger interface for Prom2Teams webservices') \ No newline at end of file diff --git a/prom2teams/config.ini b/prom2teams/config.ini index 58fe534..3f24ddf 100644 --- a/prom2teams/config.ini +++ b/prom2teams/config.ini @@ -1,3 +1,6 @@ [HTTP Server] Host: 0.0.0.0 Port: 8089 + +[Microsoft Teams] +connector1: https://outlook.office.com/webhook/2fac82d3-23c4-467e-9b77-093b17eb6bf7@d78b7929-c2a3-4897-ae9a-7d8f8dc1a1cf/IncomingWebhook/077606df729b4b2681e350f47f689a41/9d67a37c-7cb1-4795-81a2-be00586eb8af \ No newline at end of file From 15df18abcb503bc3755460acebe9d937a0b93d2c Mon Sep 17 00:00:00 2001 From: manuhortet Date: Tue, 20 Feb 2018 23:40:09 +0100 Subject: [PATCH 15/28] solved minor problem on config.ini --- prom2teams/config.ini | 3 --- 1 file changed, 3 deletions(-) diff --git a/prom2teams/config.ini b/prom2teams/config.ini index 3f24ddf..58fe534 100644 --- a/prom2teams/config.ini +++ b/prom2teams/config.ini @@ -1,6 +1,3 @@ [HTTP Server] Host: 0.0.0.0 Port: 8089 - -[Microsoft Teams] -connector1: https://outlook.office.com/webhook/2fac82d3-23c4-467e-9b77-093b17eb6bf7@d78b7929-c2a3-4897-ae9a-7d8f8dc1a1cf/IncomingWebhook/077606df729b4b2681e350f47f689a41/9d67a37c-7cb1-4795-81a2-be00586eb8af \ No newline at end of file From c6506d045b977a3b0071e1dccff4a4231c527b9d Mon Sep 17 00:00:00 2001 From: manuhortet Date: Wed, 21 Feb 2018 09:45:50 +0100 Subject: [PATCH 16/28] app logic moved to api.py --- prom2teams/api.py | 50 ++++++++++++++++++++++++++++++++++++++++--- prom2teams/model.py | 2 +- prom2teams/server.py | 51 +++----------------------------------------- 3 files changed, 51 insertions(+), 52 deletions(-) diff --git a/prom2teams/api.py b/prom2teams/api.py index 13b228a..5de3fba 100644 --- a/prom2teams/api.py +++ b/prom2teams/api.py @@ -1,7 +1,51 @@ -from flask import Flask -from flask_restplus import Api +import warnings + +from flask import Flask, request +from flask_restplus import Api, Resource +from prom2teams.teams.client import post +from prom2teams.teams.json_composer import compose +from prom2teams.message.alarm_mapper import AlarmMapper app = Flask(__name__) app.config.SWAGGER_UI_JSONEDITOR = True -api = Api(app, version='2.0', title='Prom2Teams API', description='A swagger interface for Prom2Teams webservices') \ No newline at end of file +api = Api(app, version='2.0', title='Prom2Teams API', + description='A swagger interface for Prom2Teams webservices') + + +def run_app(config, template_path, host, port, message, logger): + @api.route('/v2/') + @api.doc(params={'connector': 'Name of connector to use'}) + class AlarmSender(Resource): + @api.expect(message) + def post(self, connector): + json = request.get_json() + alarms = AlarmMapper.map_to_alarms(json) + webhook_url = config['Microsoft Teams'][connector] + send_alarms_to_teams(alarms, webhook_url, template_path, logger) + return 'OK', 201 + + @api.route('/') + class AlarmSenderDeprecated(Resource): + def post(self): + deprecated_message = "Call to deprecated function. It will be removed in future versions. " \ + "Please view the README file." + show_deprecated_warning(deprecated_message) + json = request.get_json() + alarms = AlarmMapper.map_to_alarms(json) + webhook_url = config['Microsoft Teams']['Connector'] + send_alarms_to_teams(alarms, webhook_url, template_path) + return 'OK', 201 + + app.run(host=host, port=port, debug=False) + + +def send_alarms_to_teams(alarms, teams_webhook_url, template_path, logger): + for alarm in alarms: + sending_alarm = compose(template_path, AlarmMapper.map_alarm_to_json(alarm)) + logger.debug('The message that will be sent is: %s', str(sending_alarm)) + post(teams_webhook_url, sending_alarm) + + +def show_deprecated_warning(message): + warnings.warn(message=message, category=PendingDeprecationWarning) \ No newline at end of file diff --git a/prom2teams/model.py b/prom2teams/model.py index 615f25d..2383ba2 100644 --- a/prom2teams/model.py +++ b/prom2teams/model.py @@ -1,5 +1,5 @@ from flask_restplus import fields -from .server import api +from .api import api annotations = api.model('annotations', { 'description': fields.String(default='disk usage 93% on rootfs device'), diff --git a/prom2teams/server.py b/prom2teams/server.py index 802fbb3..b372d04 100644 --- a/prom2teams/server.py +++ b/prom2teams/server.py @@ -2,26 +2,16 @@ import configparser import os import warnings +import prom2teams.model from logging.config import fileConfig -from flask import Flask, request -from flask_restplus import Api, Resource - -from prom2teams.teams.client import post -from prom2teams.teams.json_composer import compose -from prom2teams.message.alarm_mapper import AlarmMapper from prom2teams.exceptions import MissingConnectorConfigKeyException +from .api import run_app -app = Flask(__name__) -app.config.SWAGGER_UI_JSONEDITOR = True -api = Api(app, version='2.0', title='Prom2Teams API', - description='A swagger interface for Prom2Teams webservices',) logger = logging.getLogger() dir = os.path.dirname(__file__) -from .model import message - def run(provided_config_file, template_path, log_file_path, log_level): warnings.simplefilter('once', PendingDeprecationWarning) @@ -30,38 +20,7 @@ def run(provided_config_file, template_path, log_file_path, log_level): host = config['HTTP Server']['Host'] port = int(config['HTTP Server']['Port']) - @api.route('/v2/') - @api.doc(params={'connector': 'Name of connector to use'}) - class AlarmSender(Resource): - @api.expect(message) - def post(self, connector): - json = request.get_json() - alarms = AlarmMapper.map_to_alarms(json) - webhook_url = config['Microsoft Teams'][connector] - send_alarms_to_teams(alarms, webhook_url, template_path) - return 'OK', 201 - - @api.route('/') - class AlarmSenderDeprecated(Resource): - def post(self): - deprecated_message = "Call to deprecated function. It will be removed in future versions. " \ - "Please view the README file." - show_deprecated_warning(deprecated_message) - json = request.get_json() - alarms = AlarmMapper.map_to_alarms(json) - webhook_url = config['Microsoft Teams']['Connector'] - send_alarms_to_teams(alarms, webhook_url, template_path) - return 'OK', 201 - - app.run(host=host, port=port, debug=False) - - -def send_alarms_to_teams(alarms, teams_webhook_url, template_path): - - for alarm in alarms: - sending_alarm = compose(template_path, AlarmMapper.map_alarm_to_json(alarm)) - logger.debug('The message that will be sent is: %s', str(sending_alarm)) - post(teams_webhook_url, sending_alarm) + run_app(config, template_path, host, port, prom2teams.model.message, logger) def load_logging_config(log_file_path, log_level): @@ -93,7 +52,3 @@ def get_config(provided_config_file): raise MissingConnectorConfigKeyException('missing required Microsoft Teams / ' 'connector key in provided config') return provided_config - - -def show_deprecated_warning(message): - warnings.warn(message=message, category=PendingDeprecationWarning) From 2f54189eacec6019c937e8a80bc36c7c0d8bb059 Mon Sep 17 00:00:00 2001 From: giancarlo Date: Wed, 21 Feb 2018 15:44:07 +0100 Subject: [PATCH 17/28] everything refactored and organized --- README.md | 5 +- prom2teams/api.py | 51 -------------- prom2teams/config.ini | 2 +- prom2teams/message/alarm_mapper.py | 37 ----------- .../{message => prometheus}/__init__.py | 0 .../{message => prometheus}/message_schema.py | 27 +++++++- prom2teams/server.py | 6 +- prom2teams/teams/alarm_mapper.py | 23 +++++++ prom2teams/teams/json_composer.py | 7 +- .../teams_alarm_schema.py} | 14 +--- prom2teams/teams/template.j2 | 2 +- prom2teams/web_service/__init__.py | 0 prom2teams/web_service/api.py | 66 +++++++++++++++++++ .../{teams => web_service}/exceptions.py | 0 prom2teams/{ => web_service}/model.py | 8 +-- .../client.py => web_service/teams_client.py} | 6 +- tests/context.py | 4 +- tests/data/jsons/teams_alarm_all_ok.json | 27 ++++++++ tests/data/multiple_connectors_config.ini | 6 +- tests/test_json_fields.py | 47 +++++++++---- 20 files changed, 196 insertions(+), 142 deletions(-) delete mode 100644 prom2teams/api.py delete mode 100644 prom2teams/message/alarm_mapper.py rename prom2teams/{message => prometheus}/__init__.py (100%) rename prom2teams/{message => prometheus}/message_schema.py (52%) create mode 100644 prom2teams/teams/alarm_mapper.py rename prom2teams/{message/alarm_schema.py => teams/teams_alarm_schema.py} (90%) create mode 100644 prom2teams/web_service/__init__.py create mode 100644 prom2teams/web_service/api.py rename prom2teams/{teams => web_service}/exceptions.py (100%) rename prom2teams/{ => web_service}/model.py (96%) rename prom2teams/{teams/client.py => web_service/teams_client.py} (89%) create mode 100644 tests/data/jsons/teams_alarm_all_ok.json diff --git a/README.md b/README.md index 786047b..7e52506 100644 --- a/README.md +++ b/README.md @@ -63,12 +63,11 @@ Port: # default: 8089 [Microsoft Teams] # At least one connector is required here -Connector1: -ConnectorTwo: +Connector: +AnotherConnector: ... ``` - ### Configuring Prometheus The [webhook receiver](https://prometheus.io/docs/alerting/configuration/#) in Prometheus allows configuring a prom2teams server. diff --git a/prom2teams/api.py b/prom2teams/api.py deleted file mode 100644 index 5de3fba..0000000 --- a/prom2teams/api.py +++ /dev/null @@ -1,51 +0,0 @@ -import warnings - -from flask import Flask, request -from flask_restplus import Api, Resource -from prom2teams.teams.client import post -from prom2teams.teams.json_composer import compose -from prom2teams.message.alarm_mapper import AlarmMapper - - -app = Flask(__name__) -app.config.SWAGGER_UI_JSONEDITOR = True -api = Api(app, version='2.0', title='Prom2Teams API', - description='A swagger interface for Prom2Teams webservices') - - -def run_app(config, template_path, host, port, message, logger): - @api.route('/v2/') - @api.doc(params={'connector': 'Name of connector to use'}) - class AlarmSender(Resource): - @api.expect(message) - def post(self, connector): - json = request.get_json() - alarms = AlarmMapper.map_to_alarms(json) - webhook_url = config['Microsoft Teams'][connector] - send_alarms_to_teams(alarms, webhook_url, template_path, logger) - return 'OK', 201 - - @api.route('/') - class AlarmSenderDeprecated(Resource): - def post(self): - deprecated_message = "Call to deprecated function. It will be removed in future versions. " \ - "Please view the README file." - show_deprecated_warning(deprecated_message) - json = request.get_json() - alarms = AlarmMapper.map_to_alarms(json) - webhook_url = config['Microsoft Teams']['Connector'] - send_alarms_to_teams(alarms, webhook_url, template_path) - return 'OK', 201 - - app.run(host=host, port=port, debug=False) - - -def send_alarms_to_teams(alarms, teams_webhook_url, template_path, logger): - for alarm in alarms: - sending_alarm = compose(template_path, AlarmMapper.map_alarm_to_json(alarm)) - logger.debug('The message that will be sent is: %s', str(sending_alarm)) - post(teams_webhook_url, sending_alarm) - - -def show_deprecated_warning(message): - warnings.warn(message=message, category=PendingDeprecationWarning) \ No newline at end of file diff --git a/prom2teams/config.ini b/prom2teams/config.ini index 58fe534..8d306b5 100644 --- a/prom2teams/config.ini +++ b/prom2teams/config.ini @@ -1,3 +1,3 @@ [HTTP Server] Host: 0.0.0.0 -Port: 8089 +Port: 8089 \ No newline at end of file diff --git a/prom2teams/message/alarm_mapper.py b/prom2teams/message/alarm_mapper.py deleted file mode 100644 index a695904..0000000 --- a/prom2teams/message/alarm_mapper.py +++ /dev/null @@ -1,37 +0,0 @@ -import logging - -from .message_schema import MessageSchema -from .alarm_schema import Alarm, AlarmSchema - - -logger = logging.getLogger() - -class AlarmMapper: - - def map_to_alarms(json): - alarms = [] - schema = MessageSchema() - result = schema.load(json) - - message = result.data - - for alert in message['alerts']: - # mandatory - status = alert['status'] - summary = alert['annotations']['summary'] - instance = alert['labels']['instance'] - name = alert['labels']['alertname'] - description = alert['annotations']['description'] - severity = alert['labels']['severity'] - - - alarm = Alarm(name, status, severity, summary, instance, description) - alarms.append(alarm) - - return alarms - - def map_alarm_to_json(alarm): - schema = AlarmSchema() - result = schema.dump(alarm) - return result.data - diff --git a/prom2teams/message/__init__.py b/prom2teams/prometheus/__init__.py similarity index 100% rename from prom2teams/message/__init__.py rename to prom2teams/prometheus/__init__.py diff --git a/prom2teams/message/message_schema.py b/prom2teams/prometheus/message_schema.py similarity index 52% rename from prom2teams/message/message_schema.py rename to prom2teams/prometheus/message_schema.py index 36615a1..f822050 100644 --- a/prom2teams/message/message_schema.py +++ b/prom2teams/prometheus/message_schema.py @@ -1,4 +1,4 @@ -from marshmallow import Schema, fields, validates +from marshmallow import Schema, fields, post_load class MessageSchema(Schema): @@ -8,6 +8,21 @@ class MessageSchema(Schema): externalURL = fields.Str() version = fields.Str() + @post_load + def get_alerts(self, message): + prom_alerts = [] + for alert in message['alerts']: + status = alert['status'] + summary = alert['annotations']['summary'] + instance = alert['labels']['instance'] + name = alert['labels']['alertname'] + description = alert['annotations']['description'] + severity = alert['labels']['severity'] + + alert = PrometheusAlert(name, status, severity, summary, instance, description) + prom_alerts.append(alert) + return prom_alerts + class AlertSchema(Schema): status = fields.Str(default='unknown', missing='unknown') @@ -31,3 +46,13 @@ class LabelSchema(Schema): class AnnotationSchema(Schema): description = fields.Str(default=None, missing=None) summary = fields.Str(default='unknown', missing='unknown') + + +class PrometheusAlert: + def __init__(self, name, status, severity, summary, instance, description): + self.name = name + self.status = status + self.severity = severity + self.summary = summary + self.instance = instance + self.description = description \ No newline at end of file diff --git a/prom2teams/server.py b/prom2teams/server.py index b372d04..db933bb 100644 --- a/prom2teams/server.py +++ b/prom2teams/server.py @@ -2,11 +2,11 @@ import configparser import os import warnings -import prom2teams.model +import prom2teams.web_service.model from logging.config import fileConfig from prom2teams.exceptions import MissingConnectorConfigKeyException -from .api import run_app +from prom2teams.web_service.api import run_app logger = logging.getLogger() @@ -20,7 +20,7 @@ def run(provided_config_file, template_path, log_file_path, log_level): host = config['HTTP Server']['Host'] port = int(config['HTTP Server']['Port']) - run_app(config, template_path, host, port, prom2teams.model.message, logger) + run_app(config, template_path, host, port, prom2teams.web_service.model.message, logger) def load_logging_config(log_file_path, log_level): diff --git a/prom2teams/teams/alarm_mapper.py b/prom2teams/teams/alarm_mapper.py new file mode 100644 index 0000000..1bde2cd --- /dev/null +++ b/prom2teams/teams/alarm_mapper.py @@ -0,0 +1,23 @@ +import logging + +from prom2teams.teams.teams_alarm_schema import TeamsAlarm, TeamsAlarmSchema + +logger = logging.getLogger() + + +class TeamsAlarmMapper: + + def map_alarm_to_json(alarm): + schema = TeamsAlarmSchema() + result = schema.dump(alarm) + return result.data + + def map_prom_alerts_to_teams_alarms(alerts): + teams_alarms = [] + schema = TeamsAlarmSchema() + for alert in alerts: + alarm = TeamsAlarm(alert.name, alert.status, alert.severity, + alert.summary, alert.instance, alert.description) + json_alarm = schema.dump(alarm).data + teams_alarms.append(json_alarm) + return teams_alarms diff --git a/prom2teams/teams/json_composer.py b/prom2teams/teams/json_composer.py index 75e2249..b9376ba 100644 --- a/prom2teams/teams/json_composer.py +++ b/prom2teams/teams/json_composer.py @@ -7,10 +7,11 @@ DEFAULT_TEMPLATE_NAME = 'template.j2' -def compose(template_path, msg_text): +def compose_all(template_path, alarms_json): template = get_template(template_path) - rendered_template = template.render(status=msg_text['status'], msg_text=msg_text) - return rendered_template + rendered_templates = [template.render(status=json_alarm['status'], msg_text=json_alarm) + for json_alarm in alarms_json] + return rendered_templates def get_template(template_path): diff --git a/prom2teams/message/alarm_schema.py b/prom2teams/teams/teams_alarm_schema.py similarity index 90% rename from prom2teams/message/alarm_schema.py rename to prom2teams/teams/teams_alarm_schema.py index 59431bf..080c030 100644 --- a/prom2teams/message/alarm_schema.py +++ b/prom2teams/teams/teams_alarm_schema.py @@ -1,7 +1,7 @@ from marshmallow import Schema, fields -class AlarmSchema(Schema): +class TeamsAlarmSchema(Schema): status = fields.Str() severity = fields.Str() summary = fields.Str() @@ -9,7 +9,7 @@ class AlarmSchema(Schema): description = fields.Str() name = fields.Str() -class Alarm: +class TeamsAlarm: def __init__(self, name, status, severity, summary, instance, description): self.name = name self.status = status @@ -17,13 +17,3 @@ def __init__(self, name, status, severity, summary, instance, description): self.summary = summary self.instance = instance self.description = description - - - - - - - - - - diff --git a/prom2teams/teams/template.j2 b/prom2teams/teams/template.j2 index 423cd55..8a1fff7 100644 --- a/prom2teams/teams/template.j2 +++ b/prom2teams/teams/template.j2 @@ -34,4 +34,4 @@ }], "markdown": true }] -} +} \ No newline at end of file diff --git a/prom2teams/web_service/__init__.py b/prom2teams/web_service/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/prom2teams/web_service/api.py b/prom2teams/web_service/api.py new file mode 100644 index 0000000..4734761 --- /dev/null +++ b/prom2teams/web_service/api.py @@ -0,0 +1,66 @@ +import warnings + +from flask import Flask, request +from flask_restplus import Api, Resource +from prom2teams.web_service.teams_client import post +from prom2teams.teams.json_composer import compose_all +from prom2teams.prometheus.message_schema import MessageSchema +from prom2teams.teams.alarm_mapper import TeamsAlarmMapper + + +app = Flask(__name__) +app.config.SWAGGER_UI_JSONEDITOR = True +api = Api(app, version='2.0', title='Prom2Teams API', + description='A swagger interface for Prom2Teams webservices') + + +def run_app(config, template_path, host, port, message, logger): + @api.route('/v2/') + @api.doc(params={'connector': 'Name of connector to use'}) + class AlarmSender(Resource): + @api.expect(message) + def post(self, connector): + webhook_url = config['Microsoft Teams'][connector] + message_schema = MessageSchema() + alerts = message_schema.load(request.get_json()).data + alarms = TeamsAlarmMapper.map_prom_alerts_to_teams_alarms(alerts) + sending_alarms = compose_all(template_path, alarms) + send_alarms_to_teams(sending_alarms, webhook_url, template_path, logger) + return 'OK', 201 + + @api.route('/') + class AlarmSenderDeprecated(Resource): + @api.expect(message) + def post(self): + webhook_url = config['Microsoft Teams']['Connector'] + deprecated_message = "Call to deprecated function. It will be removed in future versions. " \ + "Please view the README file." + show_deprecated_warning(deprecated_message) + message_schema = MessageSchema() + alerts = message_schema.load(request.get_json()).data + alarms = TeamsAlarmMapper.map_prom_alerts_to_teams_alarms(alerts) + sending_alarms = compose_all(template_path, alarms) + send_alarms_to_teams(sending_alarms, webhook_url, template_path, logger) + return 'OK', 201 + + @api.errorhandler + def default_error_handler(e): + message = 'An unhandled exception occurred.' + logger.exception(message + e) + return {'message': message}, 500 + + app.run(host=host, port=port, debug=False) + + +def send_alarms_to_teams(sending_alarms, teams_webhook_url, template_path, logger): + for team_alarm in sending_alarms: + print(team_alarm) + logger.debug('The message that will be sent is: %s', str(team_alarm)) + post(teams_webhook_url, team_alarm) + + +def show_deprecated_warning(message): + warnings.warn(message=message, category=PendingDeprecationWarning) + + + diff --git a/prom2teams/teams/exceptions.py b/prom2teams/web_service/exceptions.py similarity index 100% rename from prom2teams/teams/exceptions.py rename to prom2teams/web_service/exceptions.py diff --git a/prom2teams/model.py b/prom2teams/web_service/model.py similarity index 96% rename from prom2teams/model.py rename to prom2teams/web_service/model.py index 2383ba2..99f0c92 100644 --- a/prom2teams/model.py +++ b/prom2teams/web_service/model.py @@ -1,5 +1,5 @@ from flask_restplus import fields -from .api import api +from prom2teams.web_service.api import api annotations = api.model('annotations', { 'description': fields.String(default='disk usage 93% on rootfs device'), @@ -32,9 +32,3 @@ 'externalURL': fields.String(default='my.prometheusalertmanager.url'), 'version': fields.String(default='4') }) - - - - - - diff --git a/prom2teams/teams/client.py b/prom2teams/web_service/teams_client.py similarity index 89% rename from prom2teams/teams/client.py rename to prom2teams/web_service/teams_client.py index 533a79f..626711e 100644 --- a/prom2teams/teams/client.py +++ b/prom2teams/web_service/teams_client.py @@ -1,6 +1,6 @@ import requests -from .exceptions import MicrosoftTeamsRequestException +from prom2teams.web_service.exceptions import MicrosoftTeamsRequestException session = requests.Session() @@ -8,15 +8,11 @@ def post(teams_webhook_url, message): - response = session.post(teams_webhook_url, data=message) - if not response.ok: exception_msg = 'Error performing request to: {}.' \ ' Returned status code: {}.' \ ' Returned data: {}' - raise MicrosoftTeamsRequestException(exception_msg.format(teams_webhook_url, str(response.status_code), str(response.text))) - diff --git a/tests/context.py b/tests/context.py index 55a4529..5e52c1a 100644 --- a/tests/context.py +++ b/tests/context.py @@ -4,4 +4,6 @@ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../prom2teams'))) from prom2teams import server, exceptions -from prom2teams.message.alarm_mapper import AlarmMapper +from prom2teams.teams.alarm_mapper import TeamsAlarmMapper +from prom2teams.teams.json_composer import compose_all +from prom2teams.prometheus.message_schema import MessageSchema diff --git a/tests/data/jsons/teams_alarm_all_ok.json b/tests/data/jsons/teams_alarm_all_ok.json new file mode 100644 index 0000000..4cbbcaf --- /dev/null +++ b/tests/data/jsons/teams_alarm_all_ok.json @@ -0,0 +1,27 @@ +{ + "@type": "MessageCard", + "@context": "http://schema.org/extensions", + "themeColor": " 2DC72D ", + "summary": "Disk usage alert on CS30.evilcorp", + "title": "Prometheus alarm (Resolved) ", + "sections": [{ + "activityTitle": "Disk usage alert on CS30.evilcorp", + "facts": [{ + "name": "Alarm", + "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 + }] +} \ No newline at end of file diff --git a/tests/data/multiple_connectors_config.ini b/tests/data/multiple_connectors_config.ini index e24628e..dd7c630 100644 --- a/tests/data/multiple_connectors_config.ini +++ b/tests/data/multiple_connectors_config.ini @@ -3,6 +3,6 @@ Host: 1.1.1.1 Port: 9089 [Microsoft Teams] -connector1: teams_webhook_url -connector2: another_teams_webhook_url -connector3: definitely_another_teams_webhook_url \ No newline at end of file +Connector1: teams_webhook_url +Connector2: another_teams_webhook_url +Connector3: definitely_another_teams_webhook_url \ No newline at end of file diff --git a/tests/test_json_fields.py b/tests/test_json_fields.py index 02c749f..26e8bf6 100644 --- a/tests/test_json_fields.py +++ b/tests/test_json_fields.py @@ -1,40 +1,59 @@ import unittest import json -from context import AlarmMapper - +from context import TeamsAlarmMapper, MessageSchema, compose_all class TestJSONFields(unittest.TestCase): TEST_CONFIG_FILES_PATH = 'tests/data/jsons/' + TEST_CONFIG_TEMPLATE_PATH = 'prom2teams/teams/template.j2' def test_json_with_all_fields(self): with open(self.TEST_CONFIG_FILES_PATH + 'all_ok.json') as json_data: json_received = json.load(json_data) - alarm = AlarmMapper.map_to_alarms(json_received)[0] - alert_fields = AlarmMapper.map_alarm_to_json(alarm) - self.assertNotIn('unknown', str(alert_fields)) + message_schema = MessageSchema() + alerts = message_schema.load(json_received).data + alarm = TeamsAlarmMapper.map_prom_alerts_to_teams_alarms(alerts)[0] + self.assertNotIn('unknown', str(alarm)) def test_json_without_mandatory_field(self): with open(self.TEST_CONFIG_FILES_PATH + 'without_mandatory_field.json') as json_data: json_received = json.load(json_data) - alarm = AlarmMapper.map_to_alarms(json_received)[0] - alert_fields = AlarmMapper.map_alarm_to_json(alarm) - self.assertIn('unknown', str(alert_fields)) + message_schema = MessageSchema() + alerts = message_schema.load(json_received).data + alarm = TeamsAlarmMapper.map_prom_alerts_to_teams_alarms(alerts)[0] + self.assertIn('unknown', str(alarm)) def test_json_without_optional_field(self): with open(self.TEST_CONFIG_FILES_PATH + 'without_optional_field.json') as json_data: json_received = json.load(json_data) - alarm = AlarmMapper.map_to_alarms(json_received)[0] - alert_fields = AlarmMapper.map_alarm_to_json(alarm) - self.assertNotIn('unknown', str(alert_fields)) + message_schema = MessageSchema() + alerts = message_schema.load(json_received).data + alarm = TeamsAlarmMapper.map_prom_alerts_to_teams_alarms(alerts)[0] + self.assertNotIn('unknown', str(alarm)) def test_json_without_instance_field(self): with open(self.TEST_CONFIG_FILES_PATH + 'without_instance_field.json') as json_data: json_received = json.load(json_data) - alarm = AlarmMapper.map_to_alarms(json_received)[0] - alert_fields = AlarmMapper.map_alarm_to_json(alarm) - self.assertEqual('unknown', str(alert_fields['instance'])) + message_schema = MessageSchema() + alerts = message_schema.load(json_received).data + alarm = TeamsAlarmMapper.map_prom_alerts_to_teams_alarms(alerts)[0] + self.assertEqual('unknown', str(alarm['instance'])) + + def test_compose_all(self): + with open(self.TEST_CONFIG_FILES_PATH + 'all_ok.json') as json_data : + with open(self.TEST_CONFIG_FILES_PATH + 'teams_alarm_all_ok.json') as expected_data: + json_received = json.load(json_data) + json_expected = json.load(expected_data) + + message_schema = MessageSchema() + alerts = message_schema.load(json_received).data + alarms = TeamsAlarmMapper.map_prom_alerts_to_teams_alarms(alerts) + rendered_data = compose_all(self.TEST_CONFIG_TEMPLATE_PATH, alarms)[0] + json_rendered = json.loads(rendered_data) + + self.assertDictEqual(json_rendered, json_expected) + if __name__ == '__main__': unittest.main() From 4d39d6abc1fdc9168e4f243a39850f2b346b5500 Mon Sep 17 00:00:00 2001 From: manuhortet Date: Wed, 21 Feb 2018 16:34:12 +0100 Subject: [PATCH 18/28] minor change in README --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 7e52506..45babb6 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ $ prom2teams --help **Note:** default log level is INFO. Messages are redirected to stdout if no log file path is provided. + ### Config file The config file is an [INI file](https://docs.python.org/3/library/configparser.html#supported-ini-file-structure) and should have the structure described below: @@ -90,6 +91,13 @@ If such a field is not included a default value of 'unknown' is assigned as desc Other optional fields are skipped and not included in the Teams message. +#### Swagger UI + +Accessing to `:` (e.g. `localhost:8089`) in a web browser shows the API documentation. + +Swagger UI + + ## Testing To run the test suite you should type the following: From a7876a36790de92bbc7ed74c2614cf46d3f1e85b Mon Sep 17 00:00:00 2001 From: manuhortet Date: Wed, 21 Feb 2018 16:37:22 +0100 Subject: [PATCH 19/28] problem showing images on README --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 45babb6..2c744b8 100644 --- a/README.md +++ b/README.md @@ -95,8 +95,7 @@ Other optional fields are skipped and not included in the Teams message. Accessing to `:` (e.g. `localhost:8089`) in a web browser shows the API documentation. -Swagger UI - +Swagger UI ## Testing From e9c15d320c5b0db51b96e1922f30cc317d63b25e Mon Sep 17 00:00:00 2001 From: manuhortet Date: Wed, 21 Feb 2018 16:38:10 +0100 Subject: [PATCH 20/28] image problem solved --- assets/swagger.png | Bin 0 -> 75188 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/swagger.png diff --git a/assets/swagger.png b/assets/swagger.png new file mode 100644 index 0000000000000000000000000000000000000000..ecc4c45d6abbf57bd9a5895de01204cb3d3a5fc4 GIT binary patch literal 75188 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 AW&i*H literal 0 HcmV?d00001 From 575fa32bd59363d86781aad4086141ee9207ebfe Mon Sep 17 00:00:00 2001 From: Javier Monterrubio Date: Thu, 22 Feb 2018 18:49:33 +0100 Subject: [PATCH 21/28] #49 Provide uwsgi init Some refactors made to admit this initialization --- .gitignore | 1 + README.md | 44 ++++---- bin/prom2teams | 18 +-- bin/prom2teams_uwsgi | 12 ++ bin/wsgi.py | 13 +++ .../web_service => config}/__init__.py | 0 config/logging.yml | 29 +++++ config/settings.py | 22 ++++ prom2teams/__init__.py | 3 + prom2teams/app/__init__.py | 106 ++++++++++++++++++ prom2teams/{ => app}/exceptions.py | 4 + prom2teams/app/sender.py | 17 +++ .../{web_service => app}/teams_client.py | 7 +- prom2teams/app/versions/__init__.py | 0 prom2teams/app/versions/v1/__init__.py | 14 +++ .../{web_service => app/versions/v1}/model.py | 10 +- prom2teams/app/versions/v1/namespace.py | 28 +++++ prom2teams/app/versions/v2/__init__.py | 14 +++ prom2teams/app/versions/v2/model.py | 34 ++++++ prom2teams/app/versions/v2/namespace.py | 21 ++++ prom2teams/config.ini | 3 - prom2teams/logging_console_config.ini | 21 ---- prom2teams/logging_file_config.ini | 21 ---- prom2teams/prometheus/message_schema.py | 2 +- prom2teams/server.py | 54 --------- prom2teams/teams/alarm_mapper.py | 31 +++-- prom2teams/teams/json_composer.py | 7 +- prom2teams/teams/teams_alarm_schema.py | 1 + prom2teams/web_service/api.py | 66 ----------- prom2teams/web_service/exceptions.py | 2 - requirements.txt | 3 +- .../templates/teams.j2 | 0 tests/context.py | 4 +- tests/test_json_fields.py | 20 ++-- tests/test_server.py | 54 --------- 35 files changed, 387 insertions(+), 299 deletions(-) create mode 100755 bin/prom2teams_uwsgi create mode 100644 bin/wsgi.py rename {prom2teams/web_service => config}/__init__.py (100%) create mode 100644 config/logging.yml create mode 100644 config/settings.py create mode 100644 prom2teams/app/__init__.py rename prom2teams/{ => app}/exceptions.py (50%) create mode 100644 prom2teams/app/sender.py rename prom2teams/{web_service => app}/teams_client.py (68%) create mode 100644 prom2teams/app/versions/__init__.py create mode 100644 prom2teams/app/versions/v1/__init__.py rename prom2teams/{web_service => app/versions/v1}/model.py (86%) create mode 100644 prom2teams/app/versions/v1/namespace.py create mode 100644 prom2teams/app/versions/v2/__init__.py create mode 100644 prom2teams/app/versions/v2/model.py create mode 100644 prom2teams/app/versions/v2/namespace.py delete mode 100644 prom2teams/config.ini delete mode 100644 prom2teams/logging_console_config.ini delete mode 100644 prom2teams/logging_file_config.ini delete mode 100644 prom2teams/server.py delete mode 100644 prom2teams/web_service/api.py delete mode 100644 prom2teams/web_service/exceptions.py rename prom2teams/teams/template.j2 => resources/templates/teams.j2 (100%) delete mode 100644 tests/test_server.py diff --git a/.gitignore b/.gitignore index e016d69..63e10ec 100644 --- a/.gitignore +++ b/.gitignore @@ -84,6 +84,7 @@ celerybeat-schedule env/ venv/ ENV/ +.env.leave #Pycharm stuff *.settings diff --git a/README.md b/README.md index 2c744b8..0c1caf4 100644 --- a/README.md +++ b/README.md @@ -42,31 +42,33 @@ $ pip3 install prom2teams ## Usage + - To start the server (a config file path must be provided, log file path, log level and Jinja2 template path are optional arguments): ```bash -# To start the server (a config file path must be provided, log file path, log level and Jinja2 template path are optional arguments): -$ prom2teams --configpath [--logfilepath ] [--loglevel (DEBUG|INFO|WARNING|ERROR|CRITICAL)] [--templatepath ] +$ prom2teams --configpath [--loglevel (DEBUG|INFO|WARNING|ERROR|CRITICAL)] [--templatepath ] +``` + The config file can be provided also using an env var ***APP_CONFIG_FILE*** + + For production environment it's recommended to use a WSGI web application. In this case you can use the [wsgi](bin/prom2teams_uwsgi) version -# To show the help message: + - To show the help message: +```bash $ prom2teams --help ``` -**Note:** default log level is INFO. Messages are redirected to stdout if no log file path is provided. +**Note:** default log level is DEBUG. Messages are redirected to stdout. ### Config file -The config file is an [INI file](https://docs.python.org/3/library/configparser.html#supported-ini-file-structure) and should have the structure described below: +Take a look to the [settings](config/settings.py) file for the default properties. All these properties can be overrided. +To start the service you must provide a new config file with at least one Microsoft Teams connector ``` -[HTTP Server] -Host: # default: 0.0.0.0 -Port: # default: 8089 - -[Microsoft Teams] -# At least one connector is required here -Connector: -AnotherConnector: -... +MICROSOFT_TEAMS = { + Connector: , + AnotherConnector: , + ... +} ``` ### Configuring Prometheus @@ -78,13 +80,13 @@ The url is formed by the host and port defined in the previous step. **Note:** In order to keep compatibility with previous versions, v2.0 keep attending the default connector ("Connector") in the endpoint 0.0.0.0:8089. This will be removed in future versions. ``` -# The prom2teams endpoint to send HTTP POST requests to. +// The prom2teams endpoint to send HTTP POST requests to. url: 0.0.0.0:8089/v2/ ``` ### Templating -prom2teams provides a [default template](app/teams/template.j2) built with [Jinja2](http://jinja.pocoo.org/docs/2.9/) to render messages in Microsoft Teams. This template could be overrided using the 'templatepath' argument ('--templatepath ') during the application start. +prom2teams provides a [default template](resources/templates/teams.j2) built with [Jinja2](http://jinja.pocoo.org/docs/2.9/) to render messages in Microsoft Teams. This template could be overrided using the 'templatepath' argument ('--templatepath ') during the application start. Some fields are considered mandatory when received from Alert Manager. If such a field is not included a default value of 'unknown' is assigned as described below: @@ -93,16 +95,20 @@ Other optional fields are skipped and not included in the Teams message. #### Swagger UI -Accessing to `:` (e.g. `localhost:8089`) in a web browser shows the API documentation. +Accessing to `:` (e.g. `localhost:8001`) in a web browser shows the API v1 documentation. + +Swagger UI + +Accessing to `:/v2` (e.g. `localhost:8001/v2`) in a web browser shows the API v2 documentation. -Swagger UI +Swagger UI ## Testing To run the test suite you should type the following: ```bash -# After cloning prom2teams :) +// After cloning prom2teams :) $ python3 -m unittest discover tests ``` diff --git a/bin/prom2teams b/bin/prom2teams index b5ea3f5..7cae9da 100755 --- a/bin/prom2teams +++ b/bin/prom2teams @@ -1,25 +1,13 @@ #!/usr/bin/env python3 import sys import os -import argparse try: - from prom2teams.server import run + from prom2teams.app import app as application except ImportError: sys.path.append(os.path.abspath('./')) - from prom2teams.server import run + from prom2teams.app import app as application if __name__ == "__main__": - parser = argparse.ArgumentParser(description='Receives alert notifications ' - 'from Prometheus Alertmanager ' - '(https://github.com/prometheus/alertmanager) ' - 'and sends it to Microsoft Teams using configured connectors ') - - parser.add_argument('-c', '--configpath', help='config INI file path', required=True) - parser.add_argument('-l', '--logfilepath', help='log file path', required=False) - parser.add_argument('-v', '--loglevel', help='log level', required=False, default='INFO') - parser.add_argument('-t', '--templatepath', help='Jinja2 template file path', required=False) - - args = parser.parse_args() - run(args.configpath, args.templatepath, args.logfilepath, args.loglevel) + application.run() diff --git a/bin/prom2teams_uwsgi b/bin/prom2teams_uwsgi new file mode 100755 index 0000000..e013798 --- /dev/null +++ b/bin/prom2teams_uwsgi @@ -0,0 +1,12 @@ +#!/bin/bash + +set -e + +if [[ -n $1 ]]; then + config=$1 +else + echo "Provide a uwsgi ini file" + exit 1 +fi + +uwsgi $config diff --git a/bin/wsgi.py b/bin/wsgi.py new file mode 100644 index 0000000..f9db4ff --- /dev/null +++ b/bin/wsgi.py @@ -0,0 +1,13 @@ +import sys +import os + + +try: + from prom2teams.app import app as application +except ImportError: + sys.path.append(os.path.abspath('./')) + from prom2teams.app import app as application + + +if __name__ == "__main__": + application.run() diff --git a/prom2teams/web_service/__init__.py b/config/__init__.py similarity index 100% rename from prom2teams/web_service/__init__.py rename to config/__init__.py diff --git a/config/logging.yml b/config/logging.yml new file mode 100644 index 0000000..b1ffa8d --- /dev/null +++ b/config/logging.yml @@ -0,0 +1,29 @@ +version: 1 +formatters: + simple: + format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s' +handlers: + console: + class: logging.StreamHandler + level: DEBUG + formatter: simple + stream: ext://sys.stdout + file: + class : logging.handlers.RotatingFileHandler + formatter: simple + filename: /tmp/prom2teams.log + maxBytes: 2097152 #200MB + backupCount: 7 + encoding: utf8 +loggers: + prom2teams: + level: DEBUG + handlers: [console] + propagate: no + prom2teams.app: + level: INFO + handlers: [console] + propagate: no +root: + level: DEBUG + handlers: [console] \ No newline at end of file diff --git a/config/settings.py b/config/settings.py new file mode 100644 index 0000000..5656149 --- /dev/null +++ b/config/settings.py @@ -0,0 +1,22 @@ +APP_NAME = 'prom2teams' +# Flask settings +DEBUG = True +SERVER_NAME = 'localhost:8001' + +# Flask-Restplus settings +SWAGGER_UI_DOC_EXPANSION = 'list' +SWAGGER_UI_JSONEDITOR = True +VALIDATE = True +MASK_SWAGGER = False +ERROR_404_HELP = False + +# Logging extra settings +LOG_FILE_PATH = '/var/log/' + APP_NAME + '/' + APP_NAME + '.log' +LOG_LEVEL = 'DEBUG' + +# Api +API_V1_URL_PREFIX = '' +API_V2_URL_PREFIX = '/v2' + +# Template +TEMPLATE_PATH = None diff --git a/prom2teams/__init__.py b/prom2teams/__init__.py index e69de29..dffb2d0 100644 --- a/prom2teams/__init__.py +++ b/prom2teams/__init__.py @@ -0,0 +1,3 @@ +import os + +root = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)) diff --git a/prom2teams/app/__init__.py b/prom2teams/app/__init__.py new file mode 100644 index 0000000..6036569 --- /dev/null +++ b/prom2teams/app/__init__.py @@ -0,0 +1,106 @@ +import argparse +import configparser +import logging.config +import os + +import yaml +from flask import Flask, Blueprint + +from prom2teams import root +from .teams_client import post +from .versions.v1 import api_v1 +from .versions.v1.namespace import ns as ns_v1 +from .versions.v2 import api_v2 +from .versions.v2.namespace import ns as ns_v2 +from .exceptions import MissingConnectorConfigKeyException + +log = logging.getLogger(__name__) + +app = Flask(__name__) + + +def _config_command_line(): + parser = argparse.ArgumentParser(description='Receives alert notifications ' + 'from Prometheus Alertmanager ' + '(https://github.com/prometheus/alertmanager) ' + 'and sends it to Microsoft Teams using configured connectors ') + + parser.add_argument('-c', '--configpath', help='config INI file path', required=False) + parser.add_argument('-l', '--logfilepath', help='log file path', required=False) + parser.add_argument('-v', '--loglevel', help='log level', required=False) + parser.add_argument('-t', '--templatepath', help='Jinja2 template file path', required=False) + return parser.parse_args() + + +def _setup_logging(application): + with open(os.path.join(root, 'config/logging.yml'), 'rt') as f: + config = yaml.safe_load(f.read()) + + for logger in config['loggers']: + config['loggers'][logger]['level'] = application.config['LOG_LEVEL'] + config['root']['level'] = application.config['LOG_LEVEL'] + config['loggers']['prom2teams.app']['level'] = 'INFO' + + environment = os.getenv('APP_ENVIRONMENT', 'None') + if environment == 'pro' or environment == 'pre': + config['handlers']['file']['filename'] = application.config['LOG_FILE_PATH'] + for logger in config['loggers']: + config['loggers'][logger]['handlers'] = ['file'] + config['root']['handlers'] = ['file'] + else: + del config['handlers']['file'] + + logging.config.dictConfig(config) + + +def _config_app(application): + try: + # Load the default configuration + application.config.from_object('config.settings') + + # Load the configuration from the instance folder + instance = os.path.join(root, 'instance') + config = os.path.join(instance, 'config.py') + if os.path.isdir(instance) and os.path.exists(os.path.join(instance, 'config.py')): + application.config.from_pyfile(config) + + # Load the file specified by the APP_CONFIG_FILE environment variable + # Variables defined here will override those in the default configuration + if 'APP_CONFIG_FILE' in os.environ: + application.config.from_envvar('APP_CONFIG_FILE') + + command_line_args = _config_command_line() + if command_line_args.configpath: + application.config.from_pyfile(command_line_args.configpath) + if command_line_args.logfilepath: + application.config['LOG_FILE_PATH'] = command_line_args.logfilepath + if command_line_args.loglevel: + application.config['LOG_LEVEL'] = command_line_args.loglevel + if command_line_args.templatepath: + application.config['TEMPLATE_PATH'] = command_line_args.templatepath + + if not application.config['MICROSOFT_TEAMS']: + raise MissingConnectorConfigKeyException('missing connector key in config') + + except configparser.NoSectionError: + raise MissingConnectorConfigKeyException('missing required Microsoft Teams / connector key') + + +def _register_api(application, api, namespace, blueprint): + api.init_app(blueprint) + api.add_namespace(namespace) + application.register_blueprint(blueprint) + + +def init_app(application): + _config_app(application) + _setup_logging(application) + + blueprint_v1 = Blueprint('api_v1', __name__, url_prefix=application.config['API_V1_URL_PREFIX']) + blueprint_v2 = Blueprint('api_v2', __name__, url_prefix=application.config['API_V2_URL_PREFIX']) + _register_api(application, api_v1, ns_v1, blueprint_v1) + _register_api(application, api_v2, ns_v2, blueprint_v2) + + +init_app(app) +log.info(app.config['APP_NAME'] + ' started on ' + app.config['SERVER_NAME']) diff --git a/prom2teams/exceptions.py b/prom2teams/app/exceptions.py similarity index 50% rename from prom2teams/exceptions.py rename to prom2teams/app/exceptions.py index 32e0e24..0488d6d 100644 --- a/prom2teams/exceptions.py +++ b/prom2teams/app/exceptions.py @@ -1,2 +1,6 @@ +class MicrosoftTeamsRequestException(Exception): + pass + + class MissingConnectorConfigKeyException(Exception): pass diff --git a/prom2teams/app/sender.py b/prom2teams/app/sender.py new file mode 100644 index 0000000..17549d8 --- /dev/null +++ b/prom2teams/app/sender.py @@ -0,0 +1,17 @@ +import logging + +from flask import current_app as app + +from prom2teams.teams.alarm_mapper import map_prom_alerts_to_teams_alarms +from prom2teams.teams.json_composer import compose_all +from .teams_client import post + +log = logging.getLogger('prom2teams') + + +def send_alarms(alerts, teams_webhook_url): + alarms = map_prom_alerts_to_teams_alarms(alerts) + sending_alarms = compose_all(alarms, app.config['TEMPLATE_PATH']) + for team_alarm in sending_alarms: + log.debug('The message that will be sent is: %s', str(team_alarm)) + post(teams_webhook_url, team_alarm) diff --git a/prom2teams/web_service/teams_client.py b/prom2teams/app/teams_client.py similarity index 68% rename from prom2teams/web_service/teams_client.py rename to prom2teams/app/teams_client.py index 626711e..4687621 100644 --- a/prom2teams/web_service/teams_client.py +++ b/prom2teams/app/teams_client.py @@ -1,7 +1,6 @@ import requests -from prom2teams.web_service.exceptions import MicrosoftTeamsRequestException - +from .exceptions import MicrosoftTeamsRequestException session = requests.Session() session.headers.update({'Content-Type': 'application/json'}) @@ -14,5 +13,5 @@ def post(teams_webhook_url, message): ' Returned status code: {}.' \ ' Returned data: {}' raise MicrosoftTeamsRequestException(exception_msg.format(teams_webhook_url, - str(response.status_code), - str(response.text))) + str(response.status_code), + str(response.text))) diff --git a/prom2teams/app/versions/__init__.py b/prom2teams/app/versions/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/prom2teams/app/versions/v1/__init__.py b/prom2teams/app/versions/v1/__init__.py new file mode 100644 index 0000000..cf65a5a --- /dev/null +++ b/prom2teams/app/versions/v1/__init__.py @@ -0,0 +1,14 @@ +import logging +from flask_restplus import Api + +log = logging.getLogger(__name__) + +api_v1 = Api(version='1.0', title='Prom2Teams API v1', + description='A swagger interface for Prom2Teams webservices') + + +@api_v1.errorhandler +def default_error_handler(e): + msg = 'An unhandled exception occurred.' + log.exception(msg + e) + return {'message': msg}, 500 diff --git a/prom2teams/web_service/model.py b/prom2teams/app/versions/v1/model.py similarity index 86% rename from prom2teams/web_service/model.py rename to prom2teams/app/versions/v1/model.py index 99f0c92..cc579c4 100644 --- a/prom2teams/web_service/model.py +++ b/prom2teams/app/versions/v1/model.py @@ -1,12 +1,12 @@ from flask_restplus import fields -from prom2teams.web_service.api import api +from . import api_v1 -annotations = api.model('annotations', { +annotations = api_v1.model('annotations', { 'description': fields.String(default='disk usage 93% on rootfs device'), 'summary': fields.String(default='Disk usage alert on CS30.evilcorp') }) -labels = api.model('labels', { +labels = api_v1.model('labels', { 'alertname': fields.String(default='DiskSpace'), 'fstype': fields.String(default='rootfs'), 'device': fields.String(default='rootfs'), @@ -16,7 +16,7 @@ 'severity': fields.String(default='severe') }) -alert = api.model('alert', { +alert = api_v1.model('alert', { 'status': fields.String(default='Resolved'), 'startsAt': fields.String(default='2017-05-09T07:01:37.803Z'), 'endsAt': fields.String(default='2017-05-09T07:01:37.803Z'), @@ -25,7 +25,7 @@ 'annotations': fields.Nested(annotations) }) -message = api.model('message', { +message = api_v1.model('message', { 'receiver': fields.String(default='test_webhook'), 'status': fields.String(default='Resolved'), 'alerts': fields.List(fields.Nested(alert)), diff --git a/prom2teams/app/versions/v1/namespace.py b/prom2teams/app/versions/v1/namespace.py new file mode 100644 index 0000000..ca09639 --- /dev/null +++ b/prom2teams/app/versions/v1/namespace.py @@ -0,0 +1,28 @@ +import warnings + +from flask import request, current_app as app +from flask_restplus import Resource + +from prom2teams.app.sender import send_alarms +from prom2teams.prometheus.message_schema import MessageSchema + + +from .model import * + +ns = api_v1.namespace(name='', description='Version 1 connections') + + +@ns.route('/') +class AlarmSender(Resource): + + @api_v1.expect(message) + def post(self): + _show_deprecated_warning("Call to deprecated function. It will be removed in future versions. " + "Please view the README file.") + alerts = MessageSchema().load(request.get_json()).data + send_alarms(alerts, app.config['MICROSOFT_TEAMS']['Connector']) + return 'OK', 201 + + +def _show_deprecated_warning(msg): + warnings.warn(message=msg, category=PendingDeprecationWarning) diff --git a/prom2teams/app/versions/v2/__init__.py b/prom2teams/app/versions/v2/__init__.py new file mode 100644 index 0000000..1b4d1b8 --- /dev/null +++ b/prom2teams/app/versions/v2/__init__.py @@ -0,0 +1,14 @@ +import logging +from flask_restplus import Api + +log = logging.getLogger(__name__) + +api_v2 = Api(version='2.0', title='Prom2Teams API v2', + description='A swagger interface for Prom2Teams webservices') + + +@api_v2.errorhandler +def default_error_handler(e): + msg = 'An unhandled exception occurred.' + log.exception(msg + e) + return {'message': msg}, 500 diff --git a/prom2teams/app/versions/v2/model.py b/prom2teams/app/versions/v2/model.py new file mode 100644 index 0000000..350254c --- /dev/null +++ b/prom2teams/app/versions/v2/model.py @@ -0,0 +1,34 @@ +from flask_restplus import fields +from . import api_v2 + +annotations = api_v2.model('annotations', { + 'description': fields.String(default='disk usage 93% on rootfs device'), + 'summary': fields.String(default='Disk usage alert on CS30.evilcorp') +}) + +labels = api_v2.model('labels', { + 'alertname': fields.String(default='DiskSpace'), + 'fstype': fields.String(default='rootfs'), + 'device': fields.String(default='rootfs'), + 'instance': fields.String(default='cs30.evilcorp'), + 'job': fields.String(default='fsociety'), + 'mounterpoint': fields.String(default='/'), + 'severity': fields.String(default='severe') +}) + +alert = api_v2.model('alert', { + 'status': fields.String(default='Resolved'), + 'startsAt': fields.String(default='2017-05-09T07:01:37.803Z'), + 'endsAt': fields.String(default='2017-05-09T07:01:37.803Z'), + 'generatorURL': fields.String(default='my.prometheusserver.url'), + 'labels': fields.Nested(labels), + 'annotations': fields.Nested(annotations) +}) + +message = api_v2.model('message', { + 'receiver': fields.String(default='test_webhook'), + 'status': fields.String(default='Resolved'), + 'alerts': fields.List(fields.Nested(alert)), + 'externalURL': fields.String(default='my.prometheusalertmanager.url'), + 'version': fields.String(default='4') +}) diff --git a/prom2teams/app/versions/v2/namespace.py b/prom2teams/app/versions/v2/namespace.py new file mode 100644 index 0000000..59b8cb8 --- /dev/null +++ b/prom2teams/app/versions/v2/namespace.py @@ -0,0 +1,21 @@ +from flask import request, current_app as app +from flask_restplus import Resource + +from prom2teams.app.sender import send_alarms +from prom2teams.prometheus.message_schema import MessageSchema + + +from .model import * + +ns = api_v2.namespace(name='', description='Version 2 connections') + + +@ns.route('/') +@api_v2.doc(params={'connector': 'Name of connector to use'}) +class AlarmSender(Resource): + + @api_v2.expect(message) + def post(self, connector): + alerts = MessageSchema().load(request.get_json()).data + send_alarms(alerts, app.config['MICROSOFT_TEAMS'][connector]) + return 'OK', 201 diff --git a/prom2teams/config.ini b/prom2teams/config.ini deleted file mode 100644 index 8d306b5..0000000 --- a/prom2teams/config.ini +++ /dev/null @@ -1,3 +0,0 @@ -[HTTP Server] -Host: 0.0.0.0 -Port: 8089 \ No newline at end of file diff --git a/prom2teams/logging_console_config.ini b/prom2teams/logging_console_config.ini deleted file mode 100644 index 1f3f403..0000000 --- a/prom2teams/logging_console_config.ini +++ /dev/null @@ -1,21 +0,0 @@ -[loggers] -keys=root - -[handlers] -keys=stream_handler - -[formatters] -keys=formatter - -[logger_root] -level=%(log_level)s -handlers=stream_handler - -[handler_stream_handler] -class=StreamHandler -level=%(log_level)s -formatter=formatter -args=(sys.stdout,) - -[formatter_formatter] -format=%(asctime)s %(name)-4s %(levelname)-4s %(message)s diff --git a/prom2teams/logging_file_config.ini b/prom2teams/logging_file_config.ini deleted file mode 100644 index d994937..0000000 --- a/prom2teams/logging_file_config.ini +++ /dev/null @@ -1,21 +0,0 @@ -[loggers] -keys=root - -[handlers] -keys=file_handler - -[formatters] -keys=formatter - -[logger_root] -level=%(log_level)s -handlers=file_handler - -[handler_file_handler] -class=FileHandler -args=('%(log_file_path)s',) -level=%(log_level)s -formatter=formatter - -[formatter_formatter] -format=%(asctime)s %(name)-4s %(levelname)-4s %(message)s diff --git a/prom2teams/prometheus/message_schema.py b/prom2teams/prometheus/message_schema.py index f822050..68a9427 100644 --- a/prom2teams/prometheus/message_schema.py +++ b/prom2teams/prometheus/message_schema.py @@ -55,4 +55,4 @@ def __init__(self, name, status, severity, summary, instance, description): self.severity = severity self.summary = summary self.instance = instance - self.description = description \ No newline at end of file + self.description = description diff --git a/prom2teams/server.py b/prom2teams/server.py deleted file mode 100644 index db933bb..0000000 --- a/prom2teams/server.py +++ /dev/null @@ -1,54 +0,0 @@ -import logging -import configparser -import os -import warnings -import prom2teams.web_service.model - -from logging.config import fileConfig -from prom2teams.exceptions import MissingConnectorConfigKeyException -from prom2teams.web_service.api import run_app - - -logger = logging.getLogger() -dir = os.path.dirname(__file__) - - -def run(provided_config_file, template_path, log_file_path, log_level): - warnings.simplefilter('once', PendingDeprecationWarning) - config = get_config(provided_config_file) - load_logging_config(log_file_path, log_level) - host = config['HTTP Server']['Host'] - port = int(config['HTTP Server']['Port']) - - run_app(config, template_path, host, port, prom2teams.web_service.model.message, logger) - - -def load_logging_config(log_file_path, log_level): - config_file = os.path.join(dir, 'logging_console_config.ini') - defaults = {'log_level': log_level} - if log_file_path: - config_file = os.path.join(dir, 'logging_file_config.ini') - defaults = { - 'log_level': log_level, - 'log_file_path': log_file_path - } - fileConfig(config_file, defaults=defaults) - - -def get_config(provided_config_file): - provided_config = configparser.ConfigParser() - default_config_path = os.path.join(dir, 'config.ini') - try: - with open(default_config_path) as f_default: - provided_config.read_file(f_default) - - with open(provided_config_file) as f_prov: - provided_config.read_file(f_prov) - - if not provided_config.options('Microsoft Teams'): - raise MissingConnectorConfigKeyException('missing connector key in provided config') - - except configparser.NoSectionError: - raise MissingConnectorConfigKeyException('missing required Microsoft Teams / ' - 'connector key in provided config') - return provided_config diff --git a/prom2teams/teams/alarm_mapper.py b/prom2teams/teams/alarm_mapper.py index 1bde2cd..9aeba8f 100644 --- a/prom2teams/teams/alarm_mapper.py +++ b/prom2teams/teams/alarm_mapper.py @@ -1,23 +1,18 @@ -import logging - from prom2teams.teams.teams_alarm_schema import TeamsAlarm, TeamsAlarmSchema -logger = logging.getLogger() - -class TeamsAlarmMapper: +def map_alarm_to_json(alarm): + schema = TeamsAlarmSchema() + result = schema.dump(alarm) + return result.data - def map_alarm_to_json(alarm): - schema = TeamsAlarmSchema() - result = schema.dump(alarm) - return result.data - def map_prom_alerts_to_teams_alarms(alerts): - teams_alarms = [] - schema = TeamsAlarmSchema() - for alert in alerts: - alarm = TeamsAlarm(alert.name, alert.status, alert.severity, - alert.summary, alert.instance, alert.description) - json_alarm = schema.dump(alarm).data - teams_alarms.append(json_alarm) - return teams_alarms +def map_prom_alerts_to_teams_alarms(alerts): + teams_alarms = [] + schema = TeamsAlarmSchema() + for alert in alerts: + alarm = TeamsAlarm(alert.name, alert.status, alert.severity, + alert.summary, alert.instance, alert.description) + json_alarm = schema.dump(alarm).data + teams_alarms.append(json_alarm) + return teams_alarms diff --git a/prom2teams/teams/json_composer.py b/prom2teams/teams/json_composer.py index b9376ba..81e40a1 100644 --- a/prom2teams/teams/json_composer.py +++ b/prom2teams/teams/json_composer.py @@ -2,12 +2,13 @@ from jinja2 import Environment, FileSystemLoader +from prom2teams import root -DEFAULT_TEMPLATE_DIR = os.path.dirname(os.path.abspath(__file__)) -DEFAULT_TEMPLATE_NAME = 'template.j2' +DEFAULT_TEMPLATE_DIR = root = os.path.abspath(os.path.join(root, 'resources/templates')) +DEFAULT_TEMPLATE_NAME = 'teams.j2' -def compose_all(template_path, alarms_json): +def compose_all(alarms_json, template_path=None): template = get_template(template_path) rendered_templates = [template.render(status=json_alarm['status'], msg_text=json_alarm) for json_alarm in alarms_json] diff --git a/prom2teams/teams/teams_alarm_schema.py b/prom2teams/teams/teams_alarm_schema.py index 080c030..0e10046 100644 --- a/prom2teams/teams/teams_alarm_schema.py +++ b/prom2teams/teams/teams_alarm_schema.py @@ -9,6 +9,7 @@ class TeamsAlarmSchema(Schema): description = fields.Str() name = fields.Str() + class TeamsAlarm: def __init__(self, name, status, severity, summary, instance, description): self.name = name diff --git a/prom2teams/web_service/api.py b/prom2teams/web_service/api.py deleted file mode 100644 index 4734761..0000000 --- a/prom2teams/web_service/api.py +++ /dev/null @@ -1,66 +0,0 @@ -import warnings - -from flask import Flask, request -from flask_restplus import Api, Resource -from prom2teams.web_service.teams_client import post -from prom2teams.teams.json_composer import compose_all -from prom2teams.prometheus.message_schema import MessageSchema -from prom2teams.teams.alarm_mapper import TeamsAlarmMapper - - -app = Flask(__name__) -app.config.SWAGGER_UI_JSONEDITOR = True -api = Api(app, version='2.0', title='Prom2Teams API', - description='A swagger interface for Prom2Teams webservices') - - -def run_app(config, template_path, host, port, message, logger): - @api.route('/v2/') - @api.doc(params={'connector': 'Name of connector to use'}) - class AlarmSender(Resource): - @api.expect(message) - def post(self, connector): - webhook_url = config['Microsoft Teams'][connector] - message_schema = MessageSchema() - alerts = message_schema.load(request.get_json()).data - alarms = TeamsAlarmMapper.map_prom_alerts_to_teams_alarms(alerts) - sending_alarms = compose_all(template_path, alarms) - send_alarms_to_teams(sending_alarms, webhook_url, template_path, logger) - return 'OK', 201 - - @api.route('/') - class AlarmSenderDeprecated(Resource): - @api.expect(message) - def post(self): - webhook_url = config['Microsoft Teams']['Connector'] - deprecated_message = "Call to deprecated function. It will be removed in future versions. " \ - "Please view the README file." - show_deprecated_warning(deprecated_message) - message_schema = MessageSchema() - alerts = message_schema.load(request.get_json()).data - alarms = TeamsAlarmMapper.map_prom_alerts_to_teams_alarms(alerts) - sending_alarms = compose_all(template_path, alarms) - send_alarms_to_teams(sending_alarms, webhook_url, template_path, logger) - return 'OK', 201 - - @api.errorhandler - def default_error_handler(e): - message = 'An unhandled exception occurred.' - logger.exception(message + e) - return {'message': message}, 500 - - app.run(host=host, port=port, debug=False) - - -def send_alarms_to_teams(sending_alarms, teams_webhook_url, template_path, logger): - for team_alarm in sending_alarms: - print(team_alarm) - logger.debug('The message that will be sent is: %s', str(team_alarm)) - post(teams_webhook_url, team_alarm) - - -def show_deprecated_warning(message): - warnings.warn(message=message, category=PendingDeprecationWarning) - - - diff --git a/prom2teams/web_service/exceptions.py b/prom2teams/web_service/exceptions.py deleted file mode 100644 index 880a4cc..0000000 --- a/prom2teams/web_service/exceptions.py +++ /dev/null @@ -1,2 +0,0 @@ -class MicrosoftTeamsRequestException(Exception): - pass diff --git a/requirements.txt b/requirements.txt index c53159d..c09f51b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,4 +4,5 @@ Jinja2==2.10 Flask==0.12.2 flask-restplus==0.10.1 marshmallow==2.15.0 - +pyyaml==3.12 +uwsgi==2.0.16 \ No newline at end of file diff --git a/prom2teams/teams/template.j2 b/resources/templates/teams.j2 similarity index 100% rename from prom2teams/teams/template.j2 rename to resources/templates/teams.j2 diff --git a/tests/context.py b/tests/context.py index 5e52c1a..534ca01 100644 --- a/tests/context.py +++ b/tests/context.py @@ -3,7 +3,7 @@ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../prom2teams'))) -from prom2teams import server, exceptions -from prom2teams.teams.alarm_mapper import TeamsAlarmMapper +from prom2teams.app import exceptions +from prom2teams.teams.alarm_mapper import * from prom2teams.teams.json_composer import compose_all from prom2teams.prometheus.message_schema import MessageSchema diff --git a/tests/test_json_fields.py b/tests/test_json_fields.py index 26e8bf6..4c15463 100644 --- a/tests/test_json_fields.py +++ b/tests/test_json_fields.py @@ -1,19 +1,19 @@ import unittest import json -from context import TeamsAlarmMapper, MessageSchema, compose_all +from tests.context import MessageSchema, compose_all, map_prom_alerts_to_teams_alarms + class TestJSONFields(unittest.TestCase): - TEST_CONFIG_FILES_PATH = 'tests/data/jsons/' - TEST_CONFIG_TEMPLATE_PATH = 'prom2teams/teams/template.j2' + TEST_CONFIG_FILES_PATH = 'data/jsons/' def test_json_with_all_fields(self): with open(self.TEST_CONFIG_FILES_PATH + 'all_ok.json') as json_data: json_received = json.load(json_data) message_schema = MessageSchema() alerts = message_schema.load(json_received).data - alarm = TeamsAlarmMapper.map_prom_alerts_to_teams_alarms(alerts)[0] + alarm = map_prom_alerts_to_teams_alarms(alerts)[0] self.assertNotIn('unknown', str(alarm)) def test_json_without_mandatory_field(self): @@ -21,7 +21,7 @@ def test_json_without_mandatory_field(self): json_received = json.load(json_data) message_schema = MessageSchema() alerts = message_schema.load(json_received).data - alarm = TeamsAlarmMapper.map_prom_alerts_to_teams_alarms(alerts)[0] + alarm = map_prom_alerts_to_teams_alarms(alerts)[0] self.assertIn('unknown', str(alarm)) def test_json_without_optional_field(self): @@ -29,7 +29,7 @@ def test_json_without_optional_field(self): json_received = json.load(json_data) message_schema = MessageSchema() alerts = message_schema.load(json_received).data - alarm = TeamsAlarmMapper.map_prom_alerts_to_teams_alarms(alerts)[0] + alarm = map_prom_alerts_to_teams_alarms(alerts)[0] self.assertNotIn('unknown', str(alarm)) def test_json_without_instance_field(self): @@ -37,19 +37,19 @@ def test_json_without_instance_field(self): json_received = json.load(json_data) message_schema = MessageSchema() alerts = message_schema.load(json_received).data - alarm = TeamsAlarmMapper.map_prom_alerts_to_teams_alarms(alerts)[0] + alarm = map_prom_alerts_to_teams_alarms(alerts)[0] self.assertEqual('unknown', str(alarm['instance'])) def test_compose_all(self): - with open(self.TEST_CONFIG_FILES_PATH + 'all_ok.json') as json_data : + with open(self.TEST_CONFIG_FILES_PATH + 'all_ok.json') as json_data: with open(self.TEST_CONFIG_FILES_PATH + 'teams_alarm_all_ok.json') as expected_data: json_received = json.load(json_data) json_expected = json.load(expected_data) message_schema = MessageSchema() alerts = message_schema.load(json_received).data - alarms = TeamsAlarmMapper.map_prom_alerts_to_teams_alarms(alerts) - rendered_data = compose_all(self.TEST_CONFIG_TEMPLATE_PATH, alarms)[0] + alarms = map_prom_alerts_to_teams_alarms(alerts) + rendered_data = compose_all(alarms)[0] json_rendered = json.loads(rendered_data) self.assertDictEqual(json_rendered, json_expected) diff --git a/tests/test_server.py b/tests/test_server.py deleted file mode 100644 index 47e11c4..0000000 --- a/tests/test_server.py +++ /dev/null @@ -1,54 +0,0 @@ -import unittest - -from context import server -from context import exceptions - - -class TestServer(unittest.TestCase): - TEST_CONFIG_FILES_PATH = 'tests/data/' - DEFAULT_CONFIG_RELATIVE_PATH = './prom2teams/config.ini' - - def test_get_config_with_invalid_path(self): - invalid_relative_path = self.TEST_CONFIG_FILES_PATH + 'invalid_path' - - self.assertRaises(FileNotFoundError, - server.get_config, - invalid_relative_path) - - def test_get_config_without_required_keys_should_raise_exception(self): - empty_config_relative_path = self.TEST_CONFIG_FILES_PATH + \ - 'empty_config.ini' - - self.assertRaises(exceptions.MissingConnectorConfigKeyException, - server.get_config, - empty_config_relative_path) - - def test_get_config_without_override(self): - provided_config_relative_path = self.TEST_CONFIG_FILES_PATH + \ - 'without_overriding_defaults.ini' - config = server.get_config(provided_config_relative_path) - - self.assertEqual(config.get('HTTP Server', 'Host'), '0.0.0.0') - self.assertEqual(config.get('HTTP Server', 'Port'), '8089') - self.assertTrue(config.get('Microsoft Teams', 'Connector')) - - def test_get_config_overriding_defaults(self): - provided_config_relative_path = self.TEST_CONFIG_FILES_PATH + \ - 'overriding_defaults.ini' - config = server.get_config(provided_config_relative_path) - - self.assertEqual(config.get('HTTP Server', 'Host'), '1.1.1.1') - self.assertEqual(config.get('HTTP Server', 'Port'), '9089') - self.assertTrue(config.get('Microsoft Teams', 'Connector')) - - def test_connectors_configured(self): - provided_config_relative_path = self.TEST_CONFIG_FILES_PATH + \ - 'multiple_connectors_config.ini' - config = server.get_config(provided_config_relative_path) - self.assertEqual(config['Microsoft Teams']['connector1'], 'teams_webhook_url') - self.assertEqual(config['Microsoft Teams']['connector2'], 'another_teams_webhook_url') - self.assertEqual(config['Microsoft Teams']['connector3'], 'definitely_another_teams_webhook_url') - - -if __name__ == '__main__': - unittest.main() From 4593ed9bb08ce260b98fcb991ffe36417c1a62a7 Mon Sep 17 00:00:00 2001 From: Javier Monterrubio Date: Thu, 22 Feb 2018 18:50:00 +0100 Subject: [PATCH 22/28] #49 Add missing file in last commit --- prom2teams/app/__init__.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/prom2teams/app/__init__.py b/prom2teams/app/__init__.py index 6036569..e1bdb14 100644 --- a/prom2teams/app/__init__.py +++ b/prom2teams/app/__init__.py @@ -3,6 +3,7 @@ import logging.config import os +import sys import yaml from flask import Flask, Blueprint @@ -26,7 +27,6 @@ def _config_command_line(): 'and sends it to Microsoft Teams using configured connectors ') parser.add_argument('-c', '--configpath', help='config INI file path', required=False) - parser.add_argument('-l', '--logfilepath', help='log file path', required=False) parser.add_argument('-v', '--loglevel', help='log level', required=False) parser.add_argument('-t', '--templatepath', help='Jinja2 template file path', required=False) return parser.parse_args() @@ -72,18 +72,16 @@ def _config_app(application): command_line_args = _config_command_line() if command_line_args.configpath: application.config.from_pyfile(command_line_args.configpath) - if command_line_args.logfilepath: - application.config['LOG_FILE_PATH'] = command_line_args.logfilepath if command_line_args.loglevel: application.config['LOG_LEVEL'] = command_line_args.loglevel if command_line_args.templatepath: application.config['TEMPLATE_PATH'] = command_line_args.templatepath - if not application.config['MICROSOFT_TEAMS']: + if 'MICROSOFT_TEAMS' not in application.config: raise MissingConnectorConfigKeyException('missing connector key in config') - except configparser.NoSectionError: - raise MissingConnectorConfigKeyException('missing required Microsoft Teams / connector key') + except MissingConnectorConfigKeyException: + sys.exit('No Microsoft Teams connector available') def _register_api(application, api, namespace, blueprint): From c3c72c2838389244a7cd1aa548be53b49d047cf5 Mon Sep 17 00:00:00 2001 From: Javier Monterrubio Date: Fri, 23 Feb 2018 19:46:57 +0100 Subject: [PATCH 23/28] #49 Fix tests init --- tests/__init__.py | 0 tests/context.py | 2 +- tests/test_json_fields.py | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 tests/__init__.py diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/context.py b/tests/context.py index 534ca01..283c73a 100644 --- a/tests/context.py +++ b/tests/context.py @@ -3,7 +3,7 @@ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../prom2teams'))) -from prom2teams.app import exceptions + from prom2teams.teams.alarm_mapper import * from prom2teams.teams.json_composer import compose_all from prom2teams.prometheus.message_schema import MessageSchema diff --git a/tests/test_json_fields.py b/tests/test_json_fields.py index 4c15463..791a3de 100644 --- a/tests/test_json_fields.py +++ b/tests/test_json_fields.py @@ -6,7 +6,7 @@ class TestJSONFields(unittest.TestCase): - TEST_CONFIG_FILES_PATH = 'data/jsons/' + TEST_CONFIG_FILES_PATH = 'tests/data/jsons/' def test_json_with_all_fields(self): with open(self.TEST_CONFIG_FILES_PATH + 'all_ok.json') as json_data: From 5aa1df8c198db28ecff97f7fc238f858173e4d1f Mon Sep 17 00:00:00 2001 From: Javier Monterrubio Date: Sun, 25 Feb 2018 00:05:50 +0100 Subject: [PATCH 24/28] #49 Some refactors :) --- bin/prom2teams | 4 +-- bin/wsgi.py | 4 +-- prom2teams/app/{__init__.py => api.py} | 0 prom2teams/app/exceptions.py | 4 +++ prom2teams/app/sender.py | 27 ++++++++++------ prom2teams/app/versions/v1/namespace.py | 18 +++++++---- prom2teams/app/versions/v2/namespace.py | 18 +++++++---- prom2teams/teams/composer.py | 43 +++++++++++++++++++++++++ prom2teams/teams/json_composer.py | 28 ---------------- tests/context.py | 9 ------ tests/test_json_fields.py | 22 ++++++------- 11 files changed, 102 insertions(+), 75 deletions(-) rename prom2teams/app/{__init__.py => api.py} (100%) create mode 100644 prom2teams/teams/composer.py delete mode 100644 prom2teams/teams/json_composer.py delete mode 100644 tests/context.py diff --git a/bin/prom2teams b/bin/prom2teams index 7cae9da..f8a7067 100755 --- a/bin/prom2teams +++ b/bin/prom2teams @@ -4,10 +4,10 @@ import os try: - from prom2teams.app import app as application + from prom2teams.app.api import app as application except ImportError: sys.path.append(os.path.abspath('./')) - from prom2teams.app import app as application + from prom2teams.app.api import app as application if __name__ == "__main__": application.run() diff --git a/bin/wsgi.py b/bin/wsgi.py index f9db4ff..d6a5001 100644 --- a/bin/wsgi.py +++ b/bin/wsgi.py @@ -3,10 +3,10 @@ try: - from prom2teams.app import app as application + from prom2teams.app.api import app as application except ImportError: sys.path.append(os.path.abspath('./')) - from prom2teams.app import app as application + from prom2teams.app.api import app as application if __name__ == "__main__": diff --git a/prom2teams/app/__init__.py b/prom2teams/app/api.py similarity index 100% rename from prom2teams/app/__init__.py rename to prom2teams/app/api.py diff --git a/prom2teams/app/exceptions.py b/prom2teams/app/exceptions.py index 0488d6d..1bb1cc5 100644 --- a/prom2teams/app/exceptions.py +++ b/prom2teams/app/exceptions.py @@ -4,3 +4,7 @@ class MicrosoftTeamsRequestException(Exception): class MissingConnectorConfigKeyException(Exception): pass + + +class MissingTemplatePathException(Exception): + pass diff --git a/prom2teams/app/sender.py b/prom2teams/app/sender.py index 17549d8..fedee1e 100644 --- a/prom2teams/app/sender.py +++ b/prom2teams/app/sender.py @@ -1,17 +1,26 @@ import logging -from flask import current_app as app - from prom2teams.teams.alarm_mapper import map_prom_alerts_to_teams_alarms -from prom2teams.teams.json_composer import compose_all +from prom2teams.teams.composer import TemplateComposer from .teams_client import post log = logging.getLogger('prom2teams') -def send_alarms(alerts, teams_webhook_url): - alarms = map_prom_alerts_to_teams_alarms(alerts) - sending_alarms = compose_all(alarms, app.config['TEMPLATE_PATH']) - for team_alarm in sending_alarms: - log.debug('The message that will be sent is: %s', str(team_alarm)) - post(teams_webhook_url, team_alarm) +class AlarmSender: + + def __init__(self, template_path=None): + if template_path: + self.json_composer = TemplateComposer(template_path) + else: + self.json_composer = TemplateComposer() + + def _create_alarms(self, alerts): + alarms = map_prom_alerts_to_teams_alarms(alerts) + return self.json_composer.compose_all(alarms) + + def send_alarms(self, alerts, teams_webhook_url): + sending_alarms = self._create_alarms(alerts) + for team_alarm in sending_alarms: + log.debug('The message that will be sent is: %s', str(team_alarm)) + post(teams_webhook_url, team_alarm) diff --git a/prom2teams/app/versions/v1/namespace.py b/prom2teams/app/versions/v1/namespace.py index ca09639..0eb36e2 100644 --- a/prom2teams/app/versions/v1/namespace.py +++ b/prom2teams/app/versions/v1/namespace.py @@ -3,24 +3,30 @@ from flask import request, current_app as app from flask_restplus import Resource -from prom2teams.app.sender import send_alarms +from prom2teams.app.sender import AlarmSender from prom2teams.prometheus.message_schema import MessageSchema - - from .model import * ns = api_v1.namespace(name='', description='Version 1 connections') @ns.route('/') -class AlarmSender(Resource): +class AlertReceiver(Resource): + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.schema = MessageSchema() + if 'TEMPLATE_PATH' in app.config: + self.sender = AlarmSender(app.config['TEMPLATE_PATH']) + else: + self.sender = AlarmSender() @api_v1.expect(message) def post(self): _show_deprecated_warning("Call to deprecated function. It will be removed in future versions. " "Please view the README file.") - alerts = MessageSchema().load(request.get_json()).data - send_alarms(alerts, app.config['MICROSOFT_TEAMS']['Connector']) + alerts = self.schema.load(request.get_json()).data + self.sender.send_alarms(alerts, app.config['MICROSOFT_TEAMS']['Connector']) return 'OK', 201 diff --git a/prom2teams/app/versions/v2/namespace.py b/prom2teams/app/versions/v2/namespace.py index 59b8cb8..55924ba 100644 --- a/prom2teams/app/versions/v2/namespace.py +++ b/prom2teams/app/versions/v2/namespace.py @@ -1,10 +1,8 @@ from flask import request, current_app as app from flask_restplus import Resource -from prom2teams.app.sender import send_alarms +from prom2teams.app.sender import AlarmSender from prom2teams.prometheus.message_schema import MessageSchema - - from .model import * ns = api_v2.namespace(name='', description='Version 2 connections') @@ -12,10 +10,18 @@ @ns.route('/') @api_v2.doc(params={'connector': 'Name of connector to use'}) -class AlarmSender(Resource): +class AlertReceiver(Resource): + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.schema = MessageSchema() + if 'TEMPLATE_PATH' in app.config: + self.sender = AlarmSender(app.config['TEMPLATE_PATH']) + else: + self.sender = AlarmSender() @api_v2.expect(message) def post(self, connector): - alerts = MessageSchema().load(request.get_json()).data - send_alarms(alerts, app.config['MICROSOFT_TEAMS'][connector]) + alerts = self.schema.load(request.get_json()).data + self.sender.send_alarms(alerts, app.config['MICROSOFT_TEAMS'][connector]) return 'OK', 201 diff --git a/prom2teams/teams/composer.py b/prom2teams/teams/composer.py new file mode 100644 index 0000000..a20740e --- /dev/null +++ b/prom2teams/teams/composer.py @@ -0,0 +1,43 @@ +import logging +import os + +from jinja2 import Environment, FileSystemLoader + +from prom2teams import root +from prom2teams.app.exceptions import MissingTemplatePathException + + +log = logging.getLogger('prom2teams') + + +class _Singleton(type): + + def __init__(cls, name, bases, attrs, **kwargs): + super().__init__(name, bases, attrs) + cls._instance = None + + def __call__(cls, *args, **kwargs): + if cls._instance is None: + cls._instance = super().__call__(*args, **kwargs) + return cls._instance + + +class TemplateComposer(metaclass=_Singleton): + + DEFAULT_TEMPLATE_PATH = os.path.abspath(os.path.join(root, 'resources/templates/teams.j2')) + + def __init__(self, template_path=DEFAULT_TEMPLATE_PATH): + log.info(template_path) + if not os.path.isfile(template_path): + raise MissingTemplatePathException('Template {} not exists'.format(template_path)) + + template_dir = os.path.dirname(template_path) + template_name = os.path.basename(template_path) + loader = FileSystemLoader(template_dir) + environment = Environment(loader=loader, trim_blocks=True) + self.template = environment.get_template(template_name) + + def compose_all(self, alarms_json): + rendered_templates = [self.template.render(status=json_alarm['status'], msg_text=json_alarm) + for json_alarm in alarms_json] + return rendered_templates diff --git a/prom2teams/teams/json_composer.py b/prom2teams/teams/json_composer.py deleted file mode 100644 index 81e40a1..0000000 --- a/prom2teams/teams/json_composer.py +++ /dev/null @@ -1,28 +0,0 @@ -import os - -from jinja2 import Environment, FileSystemLoader - -from prom2teams import root - -DEFAULT_TEMPLATE_DIR = root = os.path.abspath(os.path.join(root, 'resources/templates')) -DEFAULT_TEMPLATE_NAME = 'teams.j2' - - -def compose_all(alarms_json, template_path=None): - template = get_template(template_path) - rendered_templates = [template.render(status=json_alarm['status'], msg_text=json_alarm) - for json_alarm in alarms_json] - return rendered_templates - - -def get_template(template_path): - template_dir = DEFAULT_TEMPLATE_DIR - template_name = DEFAULT_TEMPLATE_NAME - - if template_path: - template_dir = os.path.dirname(template_path) - template_name = os.path.basename(template_path) - loader = FileSystemLoader(template_dir) - environment = Environment(loader=loader, trim_blocks=True) - template = environment.get_template(template_name) - return template diff --git a/tests/context.py b/tests/context.py deleted file mode 100644 index 283c73a..0000000 --- a/tests/context.py +++ /dev/null @@ -1,9 +0,0 @@ -import os -import sys - - -sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../prom2teams'))) - -from prom2teams.teams.alarm_mapper import * -from prom2teams.teams.json_composer import compose_all -from prom2teams.prometheus.message_schema import MessageSchema diff --git a/tests/test_json_fields.py b/tests/test_json_fields.py index 791a3de..ef3f405 100644 --- a/tests/test_json_fields.py +++ b/tests/test_json_fields.py @@ -1,7 +1,9 @@ import unittest import json -from tests.context import MessageSchema, compose_all, map_prom_alerts_to_teams_alarms +from prom2teams.teams.alarm_mapper import map_prom_alerts_to_teams_alarms +from prom2teams.prometheus.message_schema import MessageSchema +from prom2teams.app.sender import AlarmSender class TestJSONFields(unittest.TestCase): @@ -11,32 +13,28 @@ class TestJSONFields(unittest.TestCase): def test_json_with_all_fields(self): with open(self.TEST_CONFIG_FILES_PATH + 'all_ok.json') as json_data: json_received = json.load(json_data) - message_schema = MessageSchema() - alerts = message_schema.load(json_received).data + alerts = MessageSchema().load(json_received).data alarm = map_prom_alerts_to_teams_alarms(alerts)[0] self.assertNotIn('unknown', str(alarm)) def test_json_without_mandatory_field(self): with open(self.TEST_CONFIG_FILES_PATH + 'without_mandatory_field.json') as json_data: json_received = json.load(json_data) - message_schema = MessageSchema() - alerts = message_schema.load(json_received).data + alerts = MessageSchema().load(json_received).data alarm = map_prom_alerts_to_teams_alarms(alerts)[0] self.assertIn('unknown', str(alarm)) def test_json_without_optional_field(self): with open(self.TEST_CONFIG_FILES_PATH + 'without_optional_field.json') as json_data: json_received = json.load(json_data) - message_schema = MessageSchema() - alerts = message_schema.load(json_received).data + alerts = MessageSchema().load(json_received).data alarm = map_prom_alerts_to_teams_alarms(alerts)[0] self.assertNotIn('unknown', str(alarm)) def test_json_without_instance_field(self): with open(self.TEST_CONFIG_FILES_PATH + 'without_instance_field.json') as json_data: json_received = json.load(json_data) - message_schema = MessageSchema() - alerts = message_schema.load(json_received).data + alerts = MessageSchema().load(json_received).data alarm = map_prom_alerts_to_teams_alarms(alerts)[0] self.assertEqual('unknown', str(alarm['instance'])) @@ -46,10 +44,8 @@ def test_compose_all(self): json_received = json.load(json_data) json_expected = json.load(expected_data) - message_schema = MessageSchema() - alerts = message_schema.load(json_received).data - alarms = map_prom_alerts_to_teams_alarms(alerts) - rendered_data = compose_all(alarms)[0] + alerts = MessageSchema().load(json_received).data + rendered_data = AlarmSender()._create_alarms(alerts)[0] json_rendered = json.loads(rendered_data) self.assertDictEqual(json_rendered, json_expected) From b57c99aed2c4256b481441c649c848449b308e01 Mon Sep 17 00:00:00 2001 From: Javier Monterrubio Date: Mon, 26 Feb 2018 12:43:33 +0100 Subject: [PATCH 25/28] #49 Update Readme with last modifications and include again .ini file --- README.md | 67 ++++++++++++++++++------ assets/swagger.png | Bin 75188 -> 0 bytes assets/swagger_v1.png | Bin 0 -> 76097 bytes assets/swagger_v2.png | Bin 0 -> 88800 bytes config/logging.yml | 2 +- config/settings.py | 4 +- prom2teams/app/api.py | 46 ++++++++++++++-- prom2teams/app/versions/v1/namespace.py | 1 + prom2teams/app/versions/v2/namespace.py | 3 +- 9 files changed, 100 insertions(+), 23 deletions(-) delete mode 100644 assets/swagger.png create mode 100644 assets/swagger_v1.png create mode 100644 assets/swagger_v2.png diff --git a/README.md b/README.md index 0c1caf4..8bb7674 100644 --- a/README.md +++ b/README.md @@ -42,33 +42,68 @@ $ pip3 install prom2teams ## Usage - - To start the server (a config file path must be provided, log file path, log level and Jinja2 template path are optional arguments): ```bash -$ prom2teams --configpath [--loglevel (DEBUG|INFO|WARNING|ERROR|CRITICAL)] [--templatepath ] +# To start the server (a config file path must be provided, log file path, log level and Jinja2 template path are optional arguments): +$ prom2teams [--configpath ] [--logfilepath ] [--loglevel (DEBUG|INFO|WARNING|ERROR|CRITICAL)] [--templatepath ] + +# To show the help message: +$ prom2teams --help ``` - The config file can be provided also using an env var ***APP_CONFIG_FILE*** - For production environment it's recommended to use a WSGI web application. In this case you can use the [wsgi](bin/prom2teams_uwsgi) version +Another options to start the service are: - - To show the help message: ```bash -$ prom2teams --help +export APP_CONFIG_FILE= +$ prom2teams +``` + +For production environments you should prefer using a WSGI server. You can launch instead: + +```bash +$ prom2teams_uwsgi +``` + +And uwsgi would look like: + +``` +[uwsgi] +module = bin.wsgi +master = true +processes = 5 +#socket = 0.0.0.0:8001 +#protocol = http +socket = /tmp/prom2teams.sock +chmod-socket = 660 +vacuum = true +env = APP_ENVIRONMENT=pro +env = APP_CONFIG_FILE=/etc/default/prom2teams.ini ``` -**Note:** default log level is DEBUG. Messages are redirected to stdout. +**Note:** default log level is DEBUG. Messages are redirected to stdout. To enable file log, set the env APP_ENVIRONMENT=(pro|pre) + ### Config file -Take a look to the [settings](config/settings.py) file for the default properties. All these properties can be overrided. -To start the service you must provide a new config file with at least one Microsoft Teams connector +The config file is an [INI file](https://docs.python.org/3/library/configparser.html#supported-ini-file-structure) and should have the structure described below: ``` -MICROSOFT_TEAMS = { - Connector: , - AnotherConnector: , - ... -} +[Microsoft Teams] +# At least one connector is required here +Connector: +AnotherConnector: +... + +[HTTP Server] +Host: # default: localhost +Port: # default: 8089 + +[Log] +Level: # default: DEBUG +Path: # default: /var/log/prom2teams/prom2teams.log + +[Template] +Path: # default: app resources template ``` ### Configuring Prometheus @@ -97,11 +132,11 @@ Other optional fields are skipped and not included in the Teams message. Accessing to `:` (e.g. `localhost:8001`) in a web browser shows the API v1 documentation. -Swagger UI +Swagger UI Accessing to `:/v2` (e.g. `localhost:8001/v2`) in a web browser shows the API v2 documentation. -Swagger UI +Swagger UI ## Testing diff --git a/assets/swagger.png b/assets/swagger.png deleted file mode 100644 index ecc4c45d6abbf57bd9a5895de01204cb3d3a5fc4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 75188 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 AW&i*H diff --git a/assets/swagger_v1.png b/assets/swagger_v1.png new file mode 100644 index 0000000000000000000000000000000000000000..99e4c20e18068cdcd5647832579485f5bebce503 GIT binary patch literal 76097 zcmeFZcT|(<);H`Nk8(yu1{IM$V^;)3r8gZ>R8T~kbQO^f0z&AF<2WK!L_ld#dJRni zB$PoZB25GmAV8EZAs{6LNJ74S!JIRG=Xu_LzV&|VJ?mXh)|zF=+}!td?eg2d{o7Y~ zeD#VJ?-t=L8#ZjYdEPrQRhW*E50b#x8Hwo01pAWm$#a@U?Go|fzwidr^-E}a&&LDrQbJxT_ zf?pmhKKWMu?K@oYk%VKv1{d=tOf~;;eBNjEYka3t$>2uj-5;z9Xuei)9$30xHM7ES ztW^n<04qSRA9p$zi?6@k@W-Q=H@ny0|G009+4{R*!VWuqxBm7-O5vvUckhD#=feLn z&zc4P4+q6BMjx{EGwnJvE+5qr_qi>K>34Hm?6qx7jZ_yl!#g$kKF^Z}A;R-N-jw=q+lk*)Y8EqZ90I1|C3kuynE%t1d|tBHpXqucnTatU9CdcaCo!do+! ziu5Mu#c|VQH9xQD8A?&3I3+&wMX@K1R6g=l`>8dz+lteDMnxXkV&vzWTQ}steDyTf zrFyAerlIA<$r5pg+@4|^?R)gT(x!PXdt5`pwQ}}+arhfN!}H6>^g+?U&s(j6CnqP* zm-S*Dm#-di5|ptNrLxBq^c#(O{swowo2A$Dx6_jE(nlO%m#>{E^75{OiHy7R)2}

dt$DDK7 zg>B+AZ3V1cYbCFDI!$+> zhhgXjRxN5u==MQR&XBEQU{XcbN@n*Q^w1nZ3%Q6Z+WW4&&D)%0iNcfXTZhtlYud}- zm67)mB$G*rNnIA*^19iSi%r2++l>Oh_Pqa5pO}c040d8}El%MuLv47=VffjCXcb#w zKM)iahFu`+QZLd9L;j+ZX??d1HEdC2<#55rz%}mni4y|ek~V~ucBgh#)zlE@Z3sN;b6LO@#3W=|M78f4As};KHmEV0}@qR{L*dY}OItmA-P9H%0$D=$w)HE4p?*Y@JZ;y|AmTSUOGl8ibi2qzWcOKZfY*f zhTIsZ2v62fckmf;DsXJKAE+aD%ofsZKldIcI_E{Isi}GIG75CqEhCX#)~OXxo+(J0 zxq_3-x0_0a1!3Kkdv>=dikFBkbfScIp{eMaXCiWpIT9i8>C@!L`jSSsR3HBmwe_tq zCexx)Lk2MP2+0v*x$EqBU$txT_1$rC3FN9EUStWB!{3WBNZm*3OJ45tlAvbqW=K$p zSP|Ekn))&_<(JDtaC%m|2{-p@3K^s&@M@)9#))Ah75H1yaF_+M;X4vL8z+vgQRZpgG-^~)k&QG#;eHQ@d508}`l0!@f*H2Vg zmEA4d-a$;1#HV(uM}5iO(ufBvb)=M-*xqZ%M$0shvTO_-LIi+pQ=Gc6hIyM?*EvtW zQ$=ZA*qRhmi$gOWeydku8!U^JbLu!(?B9QIhoR-gFUN~6V$ftPPp z-+YQWbN|8KI1$5_D`m}|L2?7!G^xo{(Cou`qD_ZhlWA>sSv5sN$t z`O_n*p^of4GatslGilV5dtF{hL<`M+2K z{x|ozx^0lXkf=c#YTa8KA%$C-($zkV29`JU3XwfxXJ_YCL@o2(l7``&-FK%koEo%R zX{+t$*s1Z_PPcFgrLo9E|^cALo?5Yi`w41Iz0jP0L5sdDc?6o1HnvCkd9`@s$>d=oqYJlN3Rsh0%W9q_v_}ZTT65CWK-rnqYIUEA zuzb^-B)ZM6L)51HDCZ%FJ~Dfr>)}>X^{nlL=0^Cda({G6j>O4diiaocYNa?$(XYLd z_1%FfCC$MO3KcZTpCXHX?qLah7I>|*3r8&vohs8pqyX^`w#fbKKm^V>WMkG$!V2WA zxVhzu=o?-^N4q~Cc|ES&$vICZ845YPO$eRn(}RDopg)eVXv^?DYET$!NlG)HYMX+s z6mhkD!vTFcRX;29Q7pE+X_9@Nq|>kGc^#twE7*KouDh;A^v1VoUd_>qqMh4d#q7E|xqEha;8QzM(wWZ~7R z&SuX*RVJfEom6u+x*gtgGY{${pR!f6YDZ~;f+IHP_^#f#^FTpo8mzL&E@q^C98{dv zn$Wbd7@faAJYD(mXYU^8LZ47=815=Hgb|Z=Qo4v8v+H&k1tKN)ehL;%gi3P#gHtcZ zZFHU4u|e$Ng?2DeT|*z@-hwalYuh{uZO&rjt8$cdDQ!ihJ_=;QnFB#_SfVq&qodGt z)|s(SO6j>|=38*qehq>;j+YF!6(z8rG=G^l!4~YS3mJZG!V?4yc*|tvQc`p5ESX)x zI(o`d2NDf_4VLmIw4Q8oQTw048KjrluV47T;W>b$Z}-3D75^OD&QJ{>)C5R-_V}M; z){M}U!CxuPEsamNMm@beIQ8gxlBn}cqQ}CNRt}@|RD(??jrbWH) z18%OOXtm=y-^8w z05sjo8WsLxhAT426XE?KsTXoHjsD|Qa2Pz+XZw7WHDo(Zy+A36O<+;i=>b@gDeQ9q3#hqGOnGZ}uPto5m*GiHmnVw>k|6Hri)&F1pCWdiAD#w<`W9rz7GQ zxRoPY02(n7ySan;iK zo7iwMd-qy1I+jML_5BFx3fT#k-M8=NJCAMgM{LvEz-zn3*?VbqN{G0imK*y1EpUb4 zlc^tDb~GEl7rQRl*+@eZxG))%28jDN!bj!B+`5uuxc_OVhw7h|%lPE#_wxKdyS={^ z;e6~3x=b0=)&fPd_WQjxUYxR0Hap^cYpYWkH}|quTMLdN4D{~}I9?3rx?V4v8=3F7 zp^M=xlTXTxf_Ar>9J~{?69+$cxhKTX7_uY{gE};J8B8Ot__v$=lQz+&`E(GEMx#|u zXS^p?JQ`Kt&^X(BImb{-o+6&B<#yM@mhRXwZ0YED6eW2OdVlh^Q;PcAbqc0OE@^6J zpR{U?hnh-Zk^`^L$!)b0Zys_qaU3P@6uN%rdhO!4un5ZB%h#KvOLb`e_$ekZIM|@q zN;yI_CZ`*%QYz=`=#n-QE4{pGFTY#0NDZKT1Z~?)6^foF0q2Eqz{B$%Y{<~?&P8$k z9>U!ek}VcTB<6L@K64&k5tA}3b@QPnPJ24c00ro8_@uj1f^w8?yD@6+y>`*00+WPc z=Ht0Z&dX-^Y=@h72w6@&h{S2jQ5{C$loaT!3YmY3VQFR+r%^9K++%oukvcYhYW#_6 z>7*InVh&+ahfJdyYVW$G8vCiIMr(wThHMx!1(EaBmkt!y?9;%S0W0U4_HF{9t#z`^ z<8BeF5ymrlu{pq^xmQCb?yZP^_gKZh;jqGagu5ItbU#zTOu1B7?6GtrU=641MTENL z=9k{)rmIDALGLx)*IXEcTO!UFB?~%VdbkoS&4%0craLiFk*$4o9<8kt92KR3y04o7y8@x5%g8dhnsQOKQD3X=7_Lx#&s`@qC`1% ze3~paa87!VEHxD?>O@JIN!c3WXEJ^ujKh6quTq3W>Co{CPNQqrO+r4r<7;nzX)i2f zF^oOPr(@amMn<_jY$m(qjf~VFLI8w0QIjpFBiDMLy5itYibUUE#9Y_R=BkrRVwAju zE)(~M1>Kb{#n&Af3q9y@Qi;E)@$`nUtcw6o%ogJL?$<_Oy0pUZ>MY$Y2u#@$@H8UL zykS}@2|Zx#Izf31^*Az_cZv5p5ST)6jdadgk%;zS|D?lBro%$rCzHE#pSNX^Ur5lI zx8_R;Pk5}$_9(q>d9MMB!oMAv-4LFlj1GJXqfXyKJCHnOm){y6VpWDS@ zCERs$)Zt?NR|ke)dvZ25)k((WzP}b{P^n%MVrf2N$`YPN1?t|sBJqksL1>)0y`&bt zJo)hKQzaEC`h}OKZihy*%k)h>hD2KD=u(WAey-DM>I&g+>Y^Hlawl5SkyU;f#f%WL zt0LBF1SMxf?Ehn}JcBa+!tEl?aD zr-N&D${(HggC>CMiAjc9`^x>CTzuhit_j9#Qrik^htOf`k3IH$Fa*f@L}rHLjM*!T zLOm7#f#`5qCW!?)l{bU%AXIqK07 zq7ZN;+Sry9Ucs%EQYhdT%;$TPAg%2Zq(iu3#4nag?It_4PfLwoQd3BVN8tzQQIoU+ zsz?NmyhbAHMjv~EJ)_Xl54IEb-rN0PN_Yk5?|o+3l9F@Sds;Viv+T^H0NI{(OZsHF z!j1L6mb55BtYPPT*#}VsdcNT%!L%}xak%&nV`1)ag0R z#=bK*-%6g8$3OGJx`1-B?D~FIQK$W%pIH+YoDN(|(7}fJ9mqf^d(zI(s>+~=0>{fmdZW$(4u`mMV6LN@Ijiz5T<3P{N)cKjx; z1+?ragR%7WOn$bGqpiwZQ?sXK-EP6RS2S&0k{KwvJg#^!5%}frlcNnu&?!?^g>N)ina^&~mS= z{`45S81FOa5+l3J!L*P;tGyZd+z`fk&OiShfWLtMcpM^p&)N z(v5)O@iO@)0JU%OpPR(v@RY%vw=~PZkkL1h7?f zIX`o4fzjeVxVX}3Z|q|Rs4+iQf$qme2{_J;RhR&*s>$@Ysn|SN73!0@A}%gIvyl?8 zoNJ6c4$E^oy2EV^XY_vGnQ3vmj; z<>xDMSdgUzR@3G|{2xB|J%&JzJ2tb;;V$VSD}KJ%3c8!-oG z(+NIVIk^hE>QGAffLFhH=9Rs8vVekjnINdR^~rsM;f}c4>Nq(9|R!A3r-d!PCLMSr&lwo@6CegX5<>x}U|X1x%Lo z47YqXp8jNEEtc5v${zgYH2#%^uql8~C;3-9r3k;(0z3w4)#oA4ZYv*WHLyqL4L(W{ zeyQn>$SH9thw{VvHW)+#puK=%u*F@yJr&+lv(+Fe(_40J=IK;MB9fyOsUJmn^Gn4} zEum{d=#86F2o0BCA4}(vryo8#+a+k)>o!jJFse_nm;gHZCVYQT2}s;QB2o1L zr(=vk0&!@xUJ*+-dH~x0y0M7zCLaAipOF@62Znu>7pL0N(~jg{*1Ja*Uo!kF(730x zv`nj`4Ox}`Pk{xK-woP)8QUKS*1B-A&>b}G0Vj&kG~dg~86X-8xbI7en$4>R^i3}% z>_qP0xU?#e@!MZY_pJ1n;|z1|PQrx?OK4&+`^TI%^)Xr)w2=FE(5`f4vSI=*HIv0;46vqwg53(yjFDUu{f~k2>y> zUsUMhHyTW^51B~7bNH$IwX=rxM zC@5t3vF^TaKAS!ENTC*?BdXz*PyqtK+e38=K$lN1NeB}(wP@3$(&;6x^b-pLX404WE4VM!O-eD1=hgfz zp~#g7&0*)RI9W9;0FtvDn5d{(zHxdylE@92C6Gxff35T6fa3gU&=1(s;i4-E2W@Jv zdu95e)J1Z`QM)ezz#YhGAqxN#dVG9eWJ6wbwBfx7RNIlWE-s+Rk~;;nsGg5I$ytlo zBhmu`Q5LVnrJ#5Y{nm$zEiEm!nEIzQhV7x`woQ{(5@aob#s7QY;O;bDDeT?(#=i1% znFJUxP%M2e!^J70zz1q?YnWNqJ!ro6BWa@c&N-IYync7fMQ?5C-JmISo3)U%-)kyqj|e_ zfOE@$t59(EPiEqS|BQ>sx}LNqq*9QRa~vq+eKU6EPhy4nd>K>XP;jMw^Q4O}0VVCR z%hPZ6?bH%3%K5ZEH!s)h8)>bhKW^s}v1ofEi$OYk2Og>gHMn0pdOvNhTKkK1OdGvBrs`uoMl%pv65vtgLbLolroP@D^%`^xJa1N9V=ok<0QmB;PR8|3V? z@eIjw>iurNhrvz8)bYO^9~1%5{;w#{m&&mJ4`OPD+xh!M|1q)e!zmOOe6+qYk^Q_b zyKVth^5C5thVw(mzPHFQc5R+PJkIQ<9Ch$52HaX4?5bSD3W50U!2`*&UjvnYHcxco zp|umTA^EKlQh3rSqUpR*_yugr$2F0n+WMKjcZ#aB(!>4{RwX}Uok=Qorp;GJz1>?VZ(|%KKwKG7G<`)P^Y~gaYAK?b& zSpSM1I|gKvK@T!@QSA7abGkWM^^FPPtpf06LHClvLz#kGW_9AXj*O>uE67xoT62TkR z#3O8Q_*S8AR5E7ZO$mQKcWZ}+Ls={|kTQmZ$I^zEP4E@;b)U69vto70r6MCxxknLM zH__O_P(f*i4${kE#3i%;d&s zrnT;+R1~O(!PHg;h{d&M0_83tQto*8@qeninjhJ@h zycRchC~5z3aMMsKYZbp>3QE6@dX_^E_dO!9bJ6NC;*)yb5NY=0qWpt-#YVSV#dVn# z6QOc3c}}o+G}BpgkFgbjm2kk_-6`;mM6(sc>?J6kwD8hV?@-z6 zCL|K>c_*WB;j+5-+P|Gw8T!>&Ilk@a#|w3m+bjEje%4~_V-=c!QkxT!00RZw=rBqz zhlCodTJNB5C7*dHaltTN#^3=L2I-Oi9QELgR7yoiwzDS`K2G zNdyc`(GH?nJby`L+Gz+}uqus1YFg5(p)5qelpI3^Qh6Z5apBJp(y=3=Qfc9K(P^Xs z&s}VFEb48nltOnKda2r^WVpq_c;LgYwMBIerR?gwii7FHox#(w}V3hj)Q`Mio<8l8)5j&M-mkP z1+&y_L&$e|%-+uZ+eNx`Qx4R(Dr$L_FTm+_dvepC090WjGt!;h7B#?Ef+Pn6tGhR{ zWW)=*;@?9kmGoM4Qv$o}XvI)HUY4}@<*wU%kzz)PJT})aXy5MhT1Ig@8_k82HOjW} zx7gpEL7Z4$|HKE~oZ&F6BYO5=5h1f{V7}S)x$2xTPxSL!4UuZqlHMp`_(tr|oIs}Y z;rI(3Z+gc*UCig!J>ROT*;pMVyxX%>58xkOJ%U`KiG8OP`*+wfI>#jnM9~C2Uvy1< z+ht5)eJ)0AKGo5G3=ps)Joh{h8;DzgD3RA67YIQUs?PZy6r2tW_v(2C#@tZDCz^+z(=%NW_;K(_FCz^} zP=Tsq8W3!&I5=bi1a=0uGQ7zeZ?7S9)t`d}u3CQSU;)^VTd%3Nb^TmQz|DI_r$fz9 zf~>c7(pEgtluj?--#~%N6OBrUg@it?%*{1MaOa*a@V9n+XFQ6jOa%1&)n5Oo4S%hv zqVk$QXvp`k%LT54fIiHW67=ONwLp~dRh$hWyh20|%B&naW&*0;zZ5=#Q}(X-4Gx6i zzGnfvg(N*yl=A)n1f@K8N-eIwPrY7;_;rmlh4|)uXTke5pqQ7vG#lo42ZjdCRz#Jp zr)GgnrFe-HxbHRCoaaTyBUNLnBQuB303J)yrS!L_hRgueBa3*9^-Ytao}?s9_-BAN zs~+QP^$qtQLntvt=hm$gwFMa6LZ^x<>3#eR@ExEzBgc9r17f&VTNplm)hy&XwI0t! z0&@$X^jZR*sR}vqEao5CL1W;^{VkjT32mU^KKn#2YRxqV0^Y;)c`>VgjDTByV9?V` zi4-^Zgv12?|dC!M890CwqrY?vxx>TM$AAhUy*)K@deN zs9-rUaFNXqnqK}>m7nCbeJ>9d552`4_?B7$&d9xvyzon&_CKeA9!?2yD*QJe0%z=2 zd@4RHAgEx)!BiIu|I4$q2pBydlfvorcQzRKk@1hvi(nv&1Y(aeoc+7 zIzuqc|6}vQx*KHj2JwXBgd7IGeXm8y1%_+auSf3&sGJ_0Cm4WwSY<3Rm$-Gp_-E@+ zGK#yk|8QSrI9WWOFt1e!f2FrO8K}}nndb(w_2SNUaJ)0yoy}Yg&EkYL`zu^ccm*}i zuN;)R7u*9O-0_w5f~c(N4S@Ns+ZH?V5r=`?grvWU&&%-sF8UPy!yE zfADEegS%CQzuH=wxM7N0jO5OPsHew}NaVa)jn&fAlWIbt#(JV>fofGGx2w`OninpO z9!eNaS#2+W1@)o+Fnb_UKgP=cdc&Ha)~~PU%t?M7_Oj>^&JT2Y-2Bt^6Gmwo`hXNS z7y*2{7AS3(5 z1+6>46U{tp9MMiBHnsWf4=DK%Oz?jH>%#1+&Yf=obwSd>7|ppd69)#?cl!>H zLfGpYI{B?&mxIT~P@;gGe*t}soPUPYDtUU@r5rQgmml}?n2F6)8fWw@Swy+d?>Tk! zaf^WLjoWnO2s|O*_~f#Pazvb9rbrUodd~Tl^hsS**V9~+ZDCngMDKf$7liQTAm*eP z_)>*BPcV_c*400Uo>XD|K)1UT4GJUeS+E7P?>-!{yW;xD?9Omcg3oBqjs)?fTc}8S zP2#HW4eHl+9yS3GZwQ(J`}b;ELGDy6uqklB^GlpyZ5-nKUd z<8}wc1=SJkv9>8YeH1QtLk*?ooN`cxrGNMS?m+s=jgNd$`=8x>+Q;>3AYe#PneEC4 zWvwYC3dEIqI-{tDLh_7F<*2*%Pn#%)efrmX!CVeIO%l`_f59_z;cfhYlF-6Cx5in3 z1=hhLW)lr#nEp>Dk(i5T+;LRcX}H(pjD%7^6=+SM)NI9$9sz}0&!AU@7+2p1 zQo|l&V&qS>CxgyH?Pd$ZlV}MuO=aYE7kzvz#1oi-}c5>Du zwENME6xM)X?v%?Zu=_m#P(|q7ps@WV)|wd!WbkvrK#iS1w4_0KS4` z6WS!B<}=v^hy{vWF1ur=f~YhLUm|XFj;IQ%@wy*Q%j5ZVRr_l4Rt)471xIbv=vXv88DA~vPoF(b=t+{JId zW>F0mem2&c(~>sBMe;mbNnf2W_6iL;s2=j*fm*4sX2=PAlKH14dEco4fI?#M=azRPX8t>pVcyGQxI(PV3yKlHJ)syCAECGW}x*`+97rm_4W_6tkb|V1AZ(fLq}S zP3SU?*1|PT=gIZm#U7UJ z038Q|8v*|Ib4YAs^zbvUggir3QTE<@afpo$0-i7Du8FV}fOQ4O4_w7s2*&J(rEG5w zx2rx%exvKW>^0CKbf^ZeHaV+xfc7=9m>1n11;>hF9; z;54Sd_5aFZuh8Gu#(P9|8JdED?@#|OzlYSS5+k{cYztL7Y6D{5NTCd5={G(ez%WB2 zVfWJ56q17TnjvtRs8jQ!^_b4r=`#MFgNs*euz^?O2{wyOvlXgyJFWK?_#Esc6z+NBwp#SliBc#aA6fQ|q5{lz&eMNxxS=w<$W|gmH zw`@bjxEApOgKD<8DSSia$mD>qS8E-3dB-OMQzKML-zTyLh$aJt18~)AxZaFs8?QM? zE(7mCpAamMT!Z4l%bgeK8N>l1Zy7d@A;szRrLt5lz_thgW1j=BZJ=f`-?{7Lx_QBO z&oAvqJ94*wGdV)(s& zZz6wykl~Xd*r>4J#Vc!!%jnzqvVl1EQb*n%l>ie+34o_ysI{z!)I5|t5b`1`w1ZlpTFD^8ycbtm69;^PByQc7wt*>I zUpTBxD}NjB;gaToQwpBzvQ#qB1TtAd#2+4ErJb5tsZoGW5%^@CE|DNu{RX8WotnM) zH!AiJE$D7Bq+*}5)N!8}enr+_hkq`D*2*AGc?qa$eEg!bcheroTarY44RetB+;%$S z;~ii@7cl=^r1s$5RvDH#`_Cc$Eobw8ePJZXZNEdoP@8VcgEr^Q&n^yco}lXZ!1XuJ z;Q!^SPEdzEt-Rl2oINM*Co$HZwN?KIkb-dH# z)1V2}rXnx$!ov#hAQl%1C@lvsX3?Gq5kCfXALQVfZv4TW4=;xQ*qak<7BDvii6$@< zmkZ}e3N_R32_{u!{K?fo?&4(7TJU>CuQ5ZvLme`!bj)y5_EUIAxkD$=a7GU-cfsMM zMC_Y+g7GHTPW&O&L_5fFqR;jZ1V#dGSz-tU{7g6hpulnly`UcPbr#+#Rqe)eq3*?p(?()YV6{nhII zPv*8ilNyz)lou3ge_q=5TuQb2!tJOmE-nEXeeEC3ol?Iw+;1B%vuyF0@?5C>u^2h< z_^Ibo8^;=H+by@Z*M<9sW$lW?y<3S86hd@a5oOpfmZSX6n@4lE`gI|tEgO(m?GDdI zjeRWcxxqZIvDnO0j$U#Ey)WP1Vw*Ja7sKt2P{O9vB@k%tRp#w!NC39z58xafuG`wQ(A!G` zJ`LYC(LU6Z&JuE&&OuE)t?SNX+$2JMe^B!}8^->APrAmzQ_KPdY zV9=HRa?M;^=UqWr{G;h`URf;jrPX*4k^*aagHLi3nT}k$Q?`S1o_$XSd6LaSGWmSR z$KMyIH^_`pDPxLP9`zs^VME*NoaS2(k%TC>^eXxMTPBJ}cd-rB4xo(`2g;Wbl&F~D zqH$)TLC>uP7iJtKOkJ3@7%^_=>cI{U;*%}gO>J?_2v%c%)ZAp~eu$a;7|i!^rJ(%pY;of1?H+uP*zDRuRMN^+c18WEGXEg5R{vPfVZB(z z*34{N)>LcrPaLO9(345PH00u%fr$8BE~rfu_KB3A>TI#~;hoV6qRu+bjS|0g9VXf> z!VND#l)c&hI~lW{aJORb-|Y#{mET4bxU^SoC`_ZX(!u)Q+&ad?>$`Emb@v`@?lJ$l z^(7U*CFb9a;;`fCjNP(eXvYgxAi>JnoSMt+@>_DvkHEik#=me|Ja_B(8?JNEL?XYE zX3!|kPAJSkr|oZk0{gjz%=i9>U$u=tN@9zHB#pnK)E?O(w0~>!z>f!x{`J?tpTQH2 z=IOcUJ9mmD&u-&~Mr;ncTl@wda?REnhaJy@e_!(bBH?XZ&Py)0k3#(0^5zTO`?+;( zU0qlC>@5Cf9z8b&9K&V{U9%Qq8h3>QmmK<3WzCnDoBAaq45SDE8^0;o%idV-WF<%FR{l7r6AI!dMoTFH8krhV&i7Y2ZCSkEiX+crbpq zdxnP(X>yt(EH%EPhSH`u_57j_4`DY-2bX)RG4q2W>_G`<(j?Glo1sj$iST{_kN^G}G3A#&(3 z0_R`% zv7b|EG8N(PxGcquOYu%Yku%(3Y#MGIgXK9c_52Gf*hKS0S4|w);4Dlxe0NGDSYb_BFw&0m19K6D z6ofM-F?kx--g0GctiQRns7Z;6?L5^a@PnX7By2sKrWa&FY1qb(;`E|$M?z^^9Mya5 zE1CVot&5vzo1pJn$UG4D8q4B^s69wpiXsG>+?rEI(pc+oB8vg;AUSiWeM@h<0*!*- zS;T1yqX*ctp{QH*_XT6mz1~h?E$h{VFH;A9#!15$9t6QEkAY$~Mmu-wi&q=yM$;xr zGEem3SXSa8_OU%eT51#zr@u0Ci%N4%sCIli757mTH~x_?{Pl zaLiN+8{zLC*pgelwqAh_*Thl@#8|8yQiJ*)7K?HrXv523YH0tKWGu7FdZR5{UYIeA zWHb)iTfzQzp1E?(1taD{lyEm41tk&G3YT+`JtAy%$pj}_EF4uNH7u^#G{L;LK1ATi zS+bM)S|Ac|Hqx7-4Cd#1lF4y(bi~r@zOL4M*vfl|vmOjwC5!KtUC<0P@qvdi%}jJB z@+7x_$j0RhXadNo84*SxYB7z^116S6rkZNLN3#O2{&gjCWt&y}s>QUHADXnZ4+lxF zpMSZ9ok1TlS#IU(x@9fTMz7wDPbt;O)4`?jG^aRNHJf z^+h);D7OIbC9AkzkJh*_82anc&g!Px4^6*30i@5F040XMS+k%Woq=Y$sa2CqXJw_f zt)5vRX(6n@A#^2 zjb>bAv3YvBZz%*S_aE6(Qb6(iW`>>!*kY&NOJ88-f7fjle@4ervJ z*@k$?0QhD5rk&2Hi^WZl8+WmHoq>LS9BIm+W(*Dogk^H*yj;&dK~b;cYIwqTQg`RS zx~bjKR$;PJY84K;k0n7~X~4FYj^d zw0{829^&ZQt1FdZ4y+a_EuH zN439DSgHZD=AMJkjy`|y*|6Gc&@(WgNLnG!&MqUdvt%-bFtf=G`xC*MH*3s|)XHDK zemyHcU&4E&rW|~xfR~q7M?B%-+S=M-l(L$d0O*=-YG$_Y5IEHYkH-%_ziRL#IT_cH zs!YtQxT?0&2s5N#;F4?Nd{#~-W@oR3uWz`yS9?ye-tD=6&O)YM!Wj{@p>la&mh zK4M$nbqJnFyr&f-_HnS>8JY_Jkt3d5?aLq#i6T!8#cgbDqk<#f^@J^SReKGK zGcO+&5{d!GwGK8RIVEVT%a`4^IP~;kh_6>EesO?(CQWTu&^w!yX ztU=W{Lqqjrd8)F{B+T2nE>y8E0JSh?5~MZNnI1JeJ8Rt-5&*rt%)Z{~#*G^%kHu;g6%}36#BPc9vnLQTzI$c2ou5Ry2L=X6 zhy?3sa;vks`3G}L%T{pSjYRYbU0vN{sU58wD^sM&j?^=C3Ro^&RyN&E`Vd&Wy83$3hZlDf#&(dv zkuvdbT#hBT8*Q-W=jY|aHCy}%YEI*d{QUe6Ks&riJw9+mW~`KLwPEOps9x-Au!<5I zfopT`3rb4TmK=B5YQ~sXHA7xjR(1l{rJ$&&qm-IXUEhMg=1WlQR+g`jC;9=L<-7_;upB3( za^rge0fDUQ>cE$N3W%@u53J$`QjvNJC)kE!^J7bwtE;TIDV z+ovmpZdkq`sB!B?YpCLA0BUB;BtQ%BC6IQNnP3YG3*Ys{k4z6mB_&;VclT8q&18LS ziM!Q~GE-AKf&yy}Sj%_fZK6KxoOr@h>ZsBdaNo{_LZyzvm$vgm%y9qyeF#X{WM^mR z@^BV?nnH;KlD$LZjVuuDR3)#-(fS}<%n{{0%>_^J42kkumL327Nwi`jV9y;QGM6r2 zKFnB~Z|BgWWUwkT_J>;)6%@3=h$1vAH1R5Hnq1;hf&^dhA38qIn45%gf7800|fy8)FiDMr!tk zuFX9J-~(XN%dRP06FCAQ5uHkQX3?nt#N_8y-vNJ<7A&kDc$%}Y>)vizHFb4~7@j?X zD&HPa@&uuM@G3yqec_Y75Jv)8a`W;^CwLG&sy#Hrc_HjLaNvONhvqx{LP8y=c2Az@ z*49>L&E!a}UwQD#B-1y)-b&t{HnYHLoRVknl`%tjp7--x`FX|7-TmP(#z#*_M<-1) zRO#3xtoau*>*<2%`IOXD#6NdH==f}IYrsep<$;38jEpCM@saCvnsPonivW_?EV|^Wc5Q z`D8CGbOFeK(Bw^mgoK6z94-Pzn?_~uZdw>$F)9g6G^?sg5pV}2b@A;J<6xq`K%S@P z=Axl_gBOVlkpUtB7=eD%&whYnujc!Lto4q#bd6xSYVT3CiC_n8nCb-s1Br&=R&%tX zhK3+WbfvEa=;`TYmz11NNl6h$lxAfeixq(h4_A9du^2$8Y)ni{z+U>+7k9T$t*+=W zmqj+f&ZVeYJM!7>fT5xLKt~e8b?eyL@PEE(B(S`Lh>XHc*H`y>%^aoxEJGAzS1kyS zGv{1kQFV27gO%=Ppki`ZGv=3JRxM3MJ#g-qMc1qT{t8N-gWm=O1ju78H+!~%1+Uy( z@N>Yy=uB7loqYEcXoNFBX?ApUY{Zq+41+0ybFp?oKx|cJ_YmlYRzP4u%@BpR?d>a+ z+W;;2gBC{KD5obSC0RFx1Gm*561}YA;!~26lH;IJj#-B5YZ<*GRaI3RXn-cI5ZdWz z_xJaIA}(E#+*0216TdnVu?Wx|C>9I=m<)+XCJ-A4F#rNbLj;%x!{}p24-5>HyZ7a} zH)#!5Wy}hUcmaj5Pr?`g;l$5Vo&M;&`UUw>K%acTzxa~N`=q3#&VYrud-pD+aDlLP zHIZ5yd7?8jGfzlK#Q^#Iw4J|Vw6Asy6&mLU4j+RIp6>2%fdrQWcn6~~!+PKv{|IiA zYR%v_(@U4WE4D(%f;FhQwdAC2$m;oi?_N-|5d+voHz+8`+`?jl6CVcPtA{{P{#X;F z+=qJvT0hAtc@6D<@2SLD*hkBl8a;QL&1RoCdGcXdS(!VWOeMhM0QR{PgPjOv_T@m; zpKQVp3>RBL~Kob};R=NU9^Xs;er0r_H1sDNj zhEzpxNL^Drb_|$SdjW!h#rg&5nFql=3_)M5q=nb5sD`e2f^h=%6a!9~yG0$aTA{o= z!?vM0+y%e_X1T%L>Pho2qq!E5($s^bmApsz!O)9}i?bUW5v?AoP}Ch<)|>U(lUJm9 zc1Ox2w?q2KP8!ple|9g#Vc;@=Qde7s7l*@cVhHiw3I(lK)Eq))z)}0W3l)HKnJAep z7s9bnwi)') -@api_v2.doc(params={'connector': 'Name of connector to use'}) +@api_v2.doc(params={'connector': 'Name of connector to use'}, + responses={201: 'OK'}) class AlertReceiver(Resource): def __init__(self, *args, **kwargs): From 33042dc138da89588111b72008ca7679fd2b449d Mon Sep 17 00:00:00 2001 From: Javier Monterrubio Date: Mon, 26 Feb 2018 13:29:23 +0100 Subject: [PATCH 26/28] #49 Update Readme with last modifications and reinclude config tests --- README.md | 9 +-- prom2teams/app/api.py | 123 ++------------------------------ prom2teams/app/configuration.py | 115 +++++++++++++++++++++++++++++ tests/test_app_configuration.py | 44 ++++++++++++ 4 files changed, 170 insertions(+), 121 deletions(-) create mode 100644 prom2teams/app/configuration.py create mode 100644 tests/test_app_configuration.py diff --git a/README.md b/README.md index 8bb7674..efa28a3 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ **prom2teams** is a Web server built with Python that receives alert notifications from a previously configured [Prometheus Alertmanager](https://github.com/prometheus/alertmanager) instance and forwards it to [Microsoft Teams](https://teams.microsoft.com/) using defined connectors. - [Getting Started](#getting-started) - - [Prerequisities](#prerequisities) + - [Prerequisities](#prerequisites) - [Installing](#installing) - [Usage](#usage) - [Config file](#config-file) @@ -42,8 +42,10 @@ $ pip3 install prom2teams ## Usage +**Important:** Config path must be provided with at least one Microsoft Teams Connector. Check the options to know how you can supply it. + ```bash -# To start the server (a config file path must be provided, log file path, log level and Jinja2 template path are optional arguments): +# To start the server (config file path , log file path, log level and Jinja2 template path are optional arguments): $ prom2teams [--configpath ] [--logfilepath ] [--loglevel (DEBUG|INFO|WARNING|ERROR|CRITICAL)] [--templatepath ] # To show the help message: @@ -82,7 +84,6 @@ env = APP_CONFIG_FILE=/etc/default/prom2teams.ini **Note:** default log level is DEBUG. Messages are redirected to stdout. To enable file log, set the env APP_ENVIRONMENT=(pro|pre) - ### Config file The config file is an [INI file](https://docs.python.org/3/library/configparser.html#supported-ini-file-structure) and should have the structure described below: @@ -121,7 +122,7 @@ url: 0.0.0.0:8089/v2/ ### Templating -prom2teams provides a [default template](resources/templates/teams.j2) built with [Jinja2](http://jinja.pocoo.org/docs/2.9/) to render messages in Microsoft Teams. This template could be overrided using the 'templatepath' argument ('--templatepath ') during the application start. +prom2teams provides a [default template](resources/templates/teams.j2) built with [Jinja2](http://jinja.pocoo.org/docs/2.10/) to render messages in Microsoft Teams. This template could be overrided using the 'templatepath' argument ('--templatepath ') during the application start. Some fields are considered mandatory when received from Alert Manager. If such a field is not included a default value of 'unknown' is assigned as described below: diff --git a/prom2teams/app/api.py b/prom2teams/app/api.py index c135f90..fca1b73 100644 --- a/prom2teams/app/api.py +++ b/prom2teams/app/api.py @@ -1,143 +1,32 @@ -import argparse -import configparser import logging.config -import os -import sys -import yaml from flask import Flask, Blueprint -from prom2teams import root -from .teams_client import post +from prom2teams.app.configuration import config_app, setup_logging from .versions.v1 import api_v1 from .versions.v1.namespace import ns as ns_v1 from .versions.v2 import api_v2 from .versions.v2.namespace import ns as ns_v2 -from .exceptions import MissingConnectorConfigKeyException log = logging.getLogger(__name__) app = Flask(__name__) -def _config_command_line(): - parser = argparse.ArgumentParser(description='Receives alert notifications ' - 'from Prometheus Alertmanager ' - '(https://github.com/prometheus/alertmanager) ' - 'and sends it to Microsoft Teams using configured connectors ') - - parser.add_argument('-c', '--configpath', help='config INI file path', required=False) - parser.add_argument('-l', '--logfilepath', help='log file path', required=False) - parser.add_argument('-v', '--loglevel', help='log level', required=False) - parser.add_argument('-t', '--templatepath', help='Jinja2 template file path', required=False) - return parser.parse_args() - - -def _setup_logging(application): - with open(os.path.join(root, 'config/logging.yml'), 'rt') as f: - config = yaml.safe_load(f.read()) - - for logger in config['loggers']: - config['loggers'][logger]['level'] = application.config['LOG_LEVEL'] - config['root']['level'] = application.config['LOG_LEVEL'] - config['loggers']['prom2teams.app']['level'] = 'INFO' - - environment = os.getenv('APP_ENVIRONMENT', 'None') - if environment == 'pro' or environment == 'pre': - config['handlers']['file']['filename'] = application.config['LOG_FILE_PATH'] - for logger in config['loggers']: - config['loggers'][logger]['handlers'] = ['file'] - config['root']['handlers'] = ['file'] - else: - del config['handlers']['file'] - - logging.config.dictConfig(config) - - -def _config_app(application): - try: - # Load the default configuration - application.config.from_object('config.settings') - - # Load the configuration from the instance folder - instance = os.path.join(root, 'instance') - config = os.path.join(instance, 'config.py') - if os.path.isdir(instance) and os.path.exists(config): - application.config.from_pyfile(config) - - # Load the file specified by the APP_CONFIG_FILE environment variable - # Variables defined here will override those in the default configuration - if 'APP_CONFIG_FILE' in os.environ: - config_provided = _config_provided(os.getenv('APP_CONFIG_FILE')) - _update_application_configuration(application, config_provided) - - # Parse and load command line properties - # Variables defined here will override previous configuration - command_line_args = _config_command_line() - if command_line_args.configpath: - config_provided = _config_provided(command_line_args.configpath) - _update_application_configuration(application, config_provided) - if command_line_args.loglevel: - application.config['LOG_LEVEL'] = command_line_args.loglevel - if command_line_args.logfilepath: - application.config['LOG_FILE_PATH'] = command_line_args.logfilepath - if command_line_args.templatepath: - application.config['TEMPLATE_PATH'] = command_line_args.templatepath - - if 'MICROSOFT_TEAMS' not in application.config: - raise MissingConnectorConfigKeyException('missing connector key in config') - - except MissingConnectorConfigKeyException: - sys.exit('No Microsoft Teams connector available') - - -def _update_application_configuration(application, configuration): - if 'Microsoft Teams' in configuration: - application.config['MICROSOFT_TEAMS'] = configuration['Microsoft Teams'] - if 'Template' in configuration and 'Path' in configuration['Template']: - application.config['TEMPLATE_PATH'] = configuration['Template']['Path'] - if 'Log' in configuration and 'Level' in configuration['Log']: - application.config['LOG_LEVEL'] = configuration['Log']['Level'] - if 'Log' in configuration and 'Path' in configuration['Log']: - application.config['LOG_FILE_PATH'] = configuration['Log']['Path'] - if 'HTTP Server' in configuration: - _host, _port = application.config['SERVER_NAME'].split(':', 1) - if 'Host' in configuration['HTTP Server']: - _host = configuration['HTTP Server']['Host'] - if 'Port' in configuration['HTTP Server']: - _port = configuration['HTTP Server']['Port'] - application.config['SERVER_NAME'] = _host + ':' + _port - - -def _config_provided(filepath): - config = configparser.ConfigParser() - try: - with open(filepath) as f_prov: - config.read_file(f_prov) - - if not config.options('Microsoft Teams'): - raise MissingConnectorConfigKeyException('missing connector key in provided config') - - except configparser.NoSectionError: - raise MissingConnectorConfigKeyException('missing required Microsoft Teams / ' - 'connector key in provided config') - return config - - -def _register_api(application, api, namespace, blueprint): +def register_api(application, api, namespace, blueprint): api.init_app(blueprint) api.add_namespace(namespace) application.register_blueprint(blueprint) def init_app(application): - _config_app(application) - _setup_logging(application) + config_app(application) + setup_logging(application) blueprint_v1 = Blueprint('api_v1', __name__, url_prefix=application.config['API_V1_URL_PREFIX']) blueprint_v2 = Blueprint('api_v2', __name__, url_prefix=application.config['API_V2_URL_PREFIX']) - _register_api(application, api_v1, ns_v1, blueprint_v1) - _register_api(application, api_v2, ns_v2, blueprint_v2) + register_api(application, api_v1, ns_v1, blueprint_v1) + register_api(application, api_v2, ns_v2, blueprint_v2) init_app(app) diff --git a/prom2teams/app/configuration.py b/prom2teams/app/configuration.py new file mode 100644 index 0000000..188fce4 --- /dev/null +++ b/prom2teams/app/configuration.py @@ -0,0 +1,115 @@ +import argparse +import configparser +import logging.config + +import os + +import sys +import yaml + +from prom2teams import root +from prom2teams.app.exceptions import MissingConnectorConfigKeyException + + +def _config_command_line(): + parser = argparse.ArgumentParser(description='Receives alert notifications ' + 'from Prometheus Alertmanager ' + '(https://github.com/prometheus/alertmanager) ' + 'and sends it to Microsoft Teams using configured connectors ') + + parser.add_argument('-c', '--configpath', help='config INI file path', required=False) + parser.add_argument('-l', '--logfilepath', help='log file path', required=False) + parser.add_argument('-v', '--loglevel', help='log level', required=False) + parser.add_argument('-t', '--templatepath', help='Jinja2 template file path', required=False) + return parser.parse_args() + + +def _update_application_configuration(application, configuration): + if 'Microsoft Teams' in configuration: + application.config['MICROSOFT_TEAMS'] = configuration['Microsoft Teams'] + if 'Template' in configuration and 'Path' in configuration['Template']: + application.config['TEMPLATE_PATH'] = configuration['Template']['Path'] + if 'Log' in configuration and 'Level' in configuration['Log']: + application.config['LOG_LEVEL'] = configuration['Log']['Level'] + if 'Log' in configuration and 'Path' in configuration['Log']: + application.config['LOG_FILE_PATH'] = configuration['Log']['Path'] + if 'HTTP Server' in configuration: + _host, _port = application.config['SERVER_NAME'].split(':', 1) + if 'Host' in configuration['HTTP Server']: + _host = configuration['HTTP Server']['Host'] + if 'Port' in configuration['HTTP Server']: + _port = configuration['HTTP Server']['Port'] + application.config['SERVER_NAME'] = _host + ':' + _port + + +def _config_provided(filepath): + config = configparser.ConfigParser() + try: + with open(filepath) as f_prov: + config.read_file(f_prov) + + if not config.options('Microsoft Teams'): + raise MissingConnectorConfigKeyException('missing connector key in provided config') + + except configparser.NoSectionError: + raise MissingConnectorConfigKeyException('missing required Microsoft Teams / ' + 'connector key in provided config') + return config + + +def setup_logging(application): + with open(os.path.join(root, 'config/logging.yml'), 'rt') as f: + config = yaml.safe_load(f.read()) + + for logger in config['loggers']: + config['loggers'][logger]['level'] = application.config['LOG_LEVEL'] + config['root']['level'] = application.config['LOG_LEVEL'] + config['loggers']['prom2teams.app']['level'] = 'INFO' + + environment = os.getenv('APP_ENVIRONMENT', 'None') + if environment == 'pro' or environment == 'pre': + config['handlers']['file']['filename'] = application.config['LOG_FILE_PATH'] + for logger in config['loggers']: + config['loggers'][logger]['handlers'] = ['file'] + config['root']['handlers'] = ['file'] + else: + del config['handlers']['file'] + + logging.config.dictConfig(config) + + +def config_app(application): + try: + # Load the default configuration + application.config.from_object('config.settings') + + # Load the configuration from the instance folder + instance = os.path.join(root, 'instance') + config = os.path.join(instance, 'config.py') + if os.path.isdir(instance) and os.path.exists(config): + application.config.from_pyfile(config) + + # Load the file specified by the APP_CONFIG_FILE environment variable + # Variables defined here will override those in the default configuration + if 'APP_CONFIG_FILE' in os.environ: + config_provided = _config_provided(os.getenv('APP_CONFIG_FILE')) + _update_application_configuration(application, config_provided) + + # Parse and load command line properties + # Variables defined here will override previous configuration + command_line_args = _config_command_line() + if command_line_args.configpath: + config_provided = _config_provided(command_line_args.configpath) + _update_application_configuration(application, config_provided) + if command_line_args.loglevel: + application.config['LOG_LEVEL'] = command_line_args.loglevel + if command_line_args.logfilepath: + application.config['LOG_FILE_PATH'] = command_line_args.logfilepath + if command_line_args.templatepath: + application.config['TEMPLATE_PATH'] = command_line_args.templatepath + + if 'MICROSOFT_TEAMS' not in application.config: + raise MissingConnectorConfigKeyException('missing connector key in config') + + except MissingConnectorConfigKeyException: + sys.exit('No Microsoft Teams connector available') diff --git a/tests/test_app_configuration.py b/tests/test_app_configuration.py new file mode 100644 index 0000000..51b2d2d --- /dev/null +++ b/tests/test_app_configuration.py @@ -0,0 +1,44 @@ +import unittest +from prom2teams.app import configuration +from prom2teams.app import exceptions + + +class TestServer(unittest.TestCase): + TEST_CONFIG_FILES_PATH = 'tests/data/' + DEFAULT_CONFIG_RELATIVE_PATH = './prom2teams/config.ini' + + def test_get_config_with_invalid_path(self): + invalid_relative_path = self.TEST_CONFIG_FILES_PATH + 'invalid_path' + self.assertRaises(FileNotFoundError, configuration._config_provided, invalid_relative_path) + + def test_get_config_without_required_keys_should_raise_exception(self): + empty_config_relative_path = self.TEST_CONFIG_FILES_PATH + 'empty_config.ini' + + self.assertRaises(exceptions.MissingConnectorConfigKeyException, configuration._config_provided, + empty_config_relative_path) + + def test_get_config_without_override(self): + provided_config_relative_path = self.TEST_CONFIG_FILES_PATH + 'without_overriding_defaults.ini' + config = configuration._config_provided(provided_config_relative_path) + + self.assertTrue(config.get('Microsoft Teams', 'Connector')) + + def test_get_config_overriding_defaults(self): + provided_config_relative_path = self.TEST_CONFIG_FILES_PATH + 'overriding_defaults.ini' + config = configuration._config_provided(provided_config_relative_path) + + self.assertEqual(config.get('HTTP Server', 'Host'), '1.1.1.1') + self.assertEqual(config.get('HTTP Server', 'Port'), '9089') + self.assertTrue(config.get('Microsoft Teams', 'Connector')) + + def test_connectors_configured(self): + provided_config_relative_path = self.TEST_CONFIG_FILES_PATH + 'multiple_connectors_config.ini' + config = configuration._config_provided(provided_config_relative_path) + + self.assertEqual(config['Microsoft Teams']['connector1'], 'teams_webhook_url') + self.assertEqual(config['Microsoft Teams']['connector2'], 'another_teams_webhook_url') + self.assertEqual(config['Microsoft Teams']['connector3'], 'definitely_another_teams_webhook_url') + + +if __name__ == '__main__': + unittest.main() From 5df8ae9aea98d339566a6b57ba25152b025d089c Mon Sep 17 00:00:00 2001 From: Javier Monterrubio Date: Tue, 27 Feb 2018 15:04:03 +0100 Subject: [PATCH 27/28] Prepare version 2.0.0 --- CHANGELOG.md | 6 ++++++ setup.py | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e4fdf4..94a83bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ This project adheres to [Semantic Versioning](http://semver.org/) and [Keep a ch ## [Unreleased](https://github.com/idealista/prom2teams/tree/develop) +## [2.0.0](https://github.com/idealista/prom2teams/tree/2.0.0) +[Full Changelog](https://github.com/idealista/prom2teams/compare/1.3.0...2.0.0) +### Added +- *[#49](https://github.com/idealista/prom2teams/issues/49) Update service startup for production environment* @jmonterrubio +- *[#22](https://github.com/idealista/prom2teams/issues/22) Allow to configure multiple connectors* @manuhortet @Gkrlo + ## [1.3.0](https://github.com/idealista/prom2teams/tree/1.3.0) [Full Changelog](https://github.com/idealista/prom2teams/compare/1.2.0...1.3.0) ### Added diff --git a/setup.py b/setup.py index 33aaf40..9f62a13 100644 --- a/setup.py +++ b/setup.py @@ -24,7 +24,7 @@ def read_requirements_file(): setup(name='prom2teams', - version='1.3.0', + version='2.0.0', description='Project that redirects Prometheus Alert Manager ' 'notifications to Microsoft Teams', long_description=readme, @@ -33,7 +33,7 @@ def read_requirements_file(): 'flake8', 'pypandoc' ], - scripts=['bin/prom2teams'], + scripts=['bin/prom2teams', 'bin/prom2teams_uwsgi'], package_data = { '': ['*.ini', '*.j2',], }, From d235dd2e83c69de10174ac721fc438f2b326809f Mon Sep 17 00:00:00 2001 From: Javier Monterrubio Date: Wed, 28 Feb 2018 11:39:22 +0100 Subject: [PATCH 28/28] #49 Fixes module distribution --- MANIFEST.in | 6 ++---- README.md | 5 +++-- bin/prom2teams | 3 ++- bin/prom2teams_uwsgi | 4 ++-- prom2teams/__init__.py | 2 +- {config => prom2teams/app}/__init__.py | 0 prom2teams/app/api.py | 2 +- prom2teams/app/configuration.py | 6 +++--- prom2teams/config/__init__.py | 0 {config => prom2teams/config}/logging.yml | 2 +- {config => prom2teams/config}/settings.py | 0 {resources => prom2teams/resources}/templates/teams.j2 | 0 setup.py | 10 +++++++--- 13 files changed, 22 insertions(+), 18 deletions(-) rename {config => prom2teams/app}/__init__.py (100%) create mode 100644 prom2teams/config/__init__.py rename {config => prom2teams/config}/logging.yml (97%) rename {config => prom2teams/config}/settings.py (100%) rename {resources => prom2teams/resources}/templates/teams.j2 (100%) diff --git a/MANIFEST.in b/MANIFEST.in index 1bdaeaf..034ff77 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,7 +1,5 @@ include README.md include LICENSE include requirements.txt -include config.ini -include logging_console_config.ini -include logging_file_config.ini -include prom2teams/teams/template.j2 +include */config/* +recursive-include */resources/ * diff --git a/README.md b/README.md index efa28a3..9628d7a 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,6 @@ And uwsgi would look like: ``` [uwsgi] -module = bin.wsgi master = true processes = 5 #socket = 0.0.0.0:8001 @@ -81,6 +80,8 @@ env = APP_ENVIRONMENT=pro env = APP_CONFIG_FILE=/etc/default/prom2teams.ini ``` +Consider not provide `chdir` property neither `module` property. + **Note:** default log level is DEBUG. Messages are redirected to stdout. To enable file log, set the env APP_ENVIRONMENT=(pro|pre) @@ -122,7 +123,7 @@ url: 0.0.0.0:8089/v2/ ### Templating -prom2teams provides a [default template](resources/templates/teams.j2) built with [Jinja2](http://jinja.pocoo.org/docs/2.10/) to render messages in Microsoft Teams. This template could be overrided using the 'templatepath' argument ('--templatepath ') during the application start. +prom2teams provides a [default template](prom2teams/resources/templates/teams.j2) built with [Jinja2](http://jinja.pocoo.org/docs/2.10/) to render messages in Microsoft Teams. This template could be overrided using the 'templatepath' argument ('--templatepath ') during the application start. Some fields are considered mandatory when received from Alert Manager. If such a field is not included a default value of 'unknown' is assigned as described below: diff --git a/bin/prom2teams b/bin/prom2teams index f8a7067..1bb8c17 100755 --- a/bin/prom2teams +++ b/bin/prom2teams @@ -10,4 +10,5 @@ except ImportError: from prom2teams.app.api import app as application if __name__ == "__main__": - application.run() + _host, _port = application.config['SERVER_NAME'].split(':', 1) + application.run(host=_host, port=int(_port)) diff --git a/bin/prom2teams_uwsgi b/bin/prom2teams_uwsgi index e013798..6e0a9b9 100755 --- a/bin/prom2teams_uwsgi +++ b/bin/prom2teams_uwsgi @@ -5,8 +5,8 @@ set -e if [[ -n $1 ]]; then config=$1 else - echo "Provide a uwsgi ini file" + echo "Provide a uwsgi ini file (without module and chdir flag)" exit 1 fi -uwsgi $config +uwsgi $config --chdir `dirname "$0"` --module wsgi diff --git a/prom2teams/__init__.py b/prom2teams/__init__.py index dffb2d0..a6b280b 100644 --- a/prom2teams/__init__.py +++ b/prom2teams/__init__.py @@ -1,3 +1,3 @@ import os -root = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)) +root = os.path.abspath(os.path.dirname(__file__)) diff --git a/config/__init__.py b/prom2teams/app/__init__.py similarity index 100% rename from config/__init__.py rename to prom2teams/app/__init__.py diff --git a/prom2teams/app/api.py b/prom2teams/app/api.py index fca1b73..e88c205 100644 --- a/prom2teams/app/api.py +++ b/prom2teams/app/api.py @@ -8,7 +8,7 @@ from .versions.v2 import api_v2 from .versions.v2.namespace import ns as ns_v2 -log = logging.getLogger(__name__) +log = logging.getLogger('prom2teams_app') app = Flask(__name__) diff --git a/prom2teams/app/configuration.py b/prom2teams/app/configuration.py index 188fce4..a6dd13e 100644 --- a/prom2teams/app/configuration.py +++ b/prom2teams/app/configuration.py @@ -64,7 +64,7 @@ def setup_logging(application): for logger in config['loggers']: config['loggers'][logger]['level'] = application.config['LOG_LEVEL'] config['root']['level'] = application.config['LOG_LEVEL'] - config['loggers']['prom2teams.app']['level'] = 'INFO' + config['loggers']['prom2teams_app']['level'] = 'INFO' environment = os.getenv('APP_ENVIRONMENT', 'None') if environment == 'pro' or environment == 'pre': @@ -81,10 +81,10 @@ def setup_logging(application): def config_app(application): try: # Load the default configuration - application.config.from_object('config.settings') + application.config.from_object('prom2teams.config.settings') # Load the configuration from the instance folder - instance = os.path.join(root, 'instance') + instance = os.path.join(os.path.join(root, os.pardir), 'instance') config = os.path.join(instance, 'config.py') if os.path.isdir(instance) and os.path.exists(config): application.config.from_pyfile(config) diff --git a/prom2teams/config/__init__.py b/prom2teams/config/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/config/logging.yml b/prom2teams/config/logging.yml similarity index 97% rename from config/logging.yml rename to prom2teams/config/logging.yml index cd073c1..87fe5cd 100644 --- a/config/logging.yml +++ b/prom2teams/config/logging.yml @@ -20,7 +20,7 @@ loggers: level: DEBUG handlers: [console] propagate: no - prom2teams.app: + prom2teams_app: level: INFO handlers: [console] propagate: no diff --git a/config/settings.py b/prom2teams/config/settings.py similarity index 100% rename from config/settings.py rename to prom2teams/config/settings.py diff --git a/resources/templates/teams.j2 b/prom2teams/resources/templates/teams.j2 similarity index 100% rename from resources/templates/teams.j2 rename to prom2teams/resources/templates/teams.j2 diff --git a/setup.py b/setup.py index 9f62a13..c0c4172 100644 --- a/setup.py +++ b/setup.py @@ -33,10 +33,14 @@ def read_requirements_file(): 'flake8', 'pypandoc' ], - scripts=['bin/prom2teams', 'bin/prom2teams_uwsgi'], - package_data = { - '': ['*.ini', '*.j2',], + scripts=[ + 'bin/prom2teams', + 'bin/prom2teams_uwsgi' + ], + package_data={ + '': ['*.ini', '*.j2'], }, + include_package_data=True, url='http://github.com/idealista/prom2teams', author='Idealista, S.A.U', author_email='labs@idealista.com',

Z9?LYWzRLsC=do#&6`y)(_vKZD$}jst+Cr| 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궛g_aTt4`xVx8KTFW;om04cofsQd2Ux8Y1 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 literal 0 HcmV?d00001 diff --git a/assets/swagger_v2.png b/assets/swagger_v2.png new file mode 100644 index 0000000000000000000000000000000000000000..88d67844f44fc53006b3fb90b4de7fa93aa37a76 GIT binary patch literal 88800 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