From de5b6cf13efac442885f6b20caffeb67f9920115 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Isma=C3=ABl=20Bouya?= Date: Tue, 26 Jul 2022 02:23:57 +0200 Subject: [PATCH] Move notification systems to apprise --- flakes/private/buildbot/flake.nix | 5 +- .../private/buildbot/common/build_helpers.py | 102 +++++------------- .../buildbot/projects/caldance/__init__.py | 2 +- .../projects/cryptoportfolio/__init__.py | 2 +- .../buildbot/projects/immaeEu/__init__.py | 2 +- .../buildbot/projects/test/__init__.py | 2 +- modules/private/environment.nix | 3 +- modules/private/gitolite/default.nix | 1 + modules/private/monitoring/myplugins.nix | 14 +-- modules/private/monitoring/objects_master.nix | 4 +- .../monitoring/objects_monitoring-1.nix | 4 + .../monitoring/plugins/notify_by_apprise | 31 ++++++ .../private/websites/tools/tools/default.nix | 7 ++ .../private/websites/tools/tools/webhooks.nix | 6 +- 14 files changed, 89 insertions(+), 96 deletions(-) create mode 100755 modules/private/monitoring/plugins/notify_by_apprise diff --git a/flakes/private/buildbot/flake.nix b/flakes/private/buildbot/flake.nix index eb699a0..1cbd0ea 100644 --- a/flakes/private/buildbot/flake.nix +++ b/flakes/private/buildbot/flake.nix @@ -45,8 +45,9 @@ ''; }); common_packages = pkgs: [ - pkgs.libvirt pkgs.treq pkgs.ldap3 buildbot-full - pkgs.buildbot-worker pkgs.pip buildbot_common wokkel + (pkgs.apprise.overridePythonAttrs(old: { propagatedBuildInputs = old.propagatedBuildInputs ++ [ pkgs.sleekxmpp ]; })) pkgs.libvirt pkgs.treq pkgs.ldap3 + buildbot-full pkgs.buildbot-worker pkgs.pip buildbot_common + wokkel ]; }; buildslist-plugin = pkgs.callPackage ./buildslist { diff --git a/modules/private/buildbot/common/build_helpers.py b/modules/private/buildbot/common/build_helpers.py index ebd49ae..77e6c07 100644 --- a/modules/private/buildbot/common/build_helpers.py +++ b/modules/private/buildbot/common/build_helpers.py @@ -4,10 +4,11 @@ from shutil import which __all__ = [ "force_scheduler", "deploy_scheduler", "git_hook_scheduler", - "clean_branch", "package_and_upload", "SlackStatusPush", + "clean_branch", "package_and_upload", "AppriseStatusPush", "XMPPStatusPush", "NixShellCommand", "all_builder_names", "compute_build_infos", "deploy_ssh_command", - "configure_slack_push", "configure_xmpp_push", "deploy_hook_scheduler", + "configure_apprise_push", + "configure_xmpp_push", "deploy_hook_scheduler", ] # Small helpers" @@ -119,45 +120,35 @@ def deploy_hook_scheduler(project, builders, timer=1): def all_builder_names(c): return [builder.name for builder in c['builders']] -# Slack/XMPP status push +# Apprise/XMPP status push from buildbot.reporters.http import HttpStatusPushBase from twisted.internet import defer from twisted.python import log -from buildbot.util import httpclientservice from buildbot.reporters import utils from buildbot.process import results from twisted.words.protocols.jabber.jid import JID from wokkel import client, xmppim from functools import partial +import apprise -class SlackStatusPush(HttpStatusPushBase): - name = "SlackStatusPush" +class AppriseStatusPush(HttpStatusPushBase): + name = "AppriseStatusPush" @defer.inlineCallbacks - def reconfigService(self, serverUrl, **kwargs): + def reconfigService(self, appriseUrls, **kwargs): + self.appriseUrls = appriseUrls yield HttpStatusPushBase.reconfigService(self, **kwargs) - self._http = yield httpclientservice.HTTPClientService.getService( - self.master, serverUrl) @defer.inlineCallbacks def send(self, build): yield utils.getDetailsForBuild(self.master, build, wantProperties=True) - response = yield self._http.post("", json=self.format(build)) - if response.code != 200: - log.msg("%s: unable to upload status: %s" % - (response.code, response.content)) + appobject = apprise.Apprise() + message = self.format(build) + for url in self.appriseUrls: + appobject.add(url.format(**message)) + yield appobject.notify(title=message["title"], body=message["text"]) def format(self, build): - colors = [ - "#36A64F", # success - "#F1E903", # warnings - "#DA0505", # failure - "#FFFFFF", # skipped - "#000000", # exception - "#FFFFFF", # retry - "#D02CA9", # cancelled - ] - if "environment" in build["properties"]: msg = "{} environment".format(build["properties"]["environment"][0]) if "build" in build["properties"]: @@ -178,71 +169,30 @@ class SlackStatusPush(HttpStatusPushBase): else: duration = "{}s".format(seconds) - text = "Build <{}|{}> of {}'s {} was {} in {}.".format( - build["url"], build["buildid"], + text = "Build {} ({}) of {}'s {} was {} in {}.".format( + build["number"], build["url"], build["builder"]["name"], msg, results.Results[build["results"]], duration, ) - fields = [ - { - "title": "Build", - "value": "<{}|{}>".format(build["url"], build["buildid"]), - "short": True, - }, - { - "title": "Project", - "value": build["builder"]["name"], - "short": True, - }, - { - "title": "Build status", - "value": results.Results[build["results"]], - "short": True, - }, - { - "title": "Build duration", - "value": duration, - "short": True, - }, - ] - if "environment" in build["properties"]: - fields.append({ - "title": "Environment", - "value": build["properties"]["environment"][0], - "short": True, - }) - if "build" in build["properties"]: - fields.append({ - "title": "Archive", - "value": build["properties"]["build"][0], - "short": True, - }) - attachments = [{ - "fallback": "", - "color": colors[build["results"]], - "fields": fields - }] else: - text = "Build <{}|{}> of {}'s {} started.".format( - build["url"], build["buildid"], + text = "Build {} ({}) of {}'s {} started.".format( + build["number"], build["url"], build["builder"]["name"], msg, ) - attachments = [] - return { "username": "Buildbot", - "icon_url": "http://docs.buildbot.net/current/_static/icon.png", + "image_url": "http://docs.buildbot.net/current/_static/icon.png", "text": text, - "attachments": attachments, + "title": "", } -def configure_slack_push(c, secrets_file, builders): - c['services'].append(SlackStatusPush( - name="slack_status", builders=builders, - serverUrl=open(secrets_file + "/slack_webhook", "r").read().rstrip())) +def configure_apprise_push(c, secrets_file, builders): + c['services'].append(AppriseStatusPush( + name="apprise_status", builders=builders, + appriseUrls=open(secrets_file + "/apprise_webhooks", "r").read().split("\n"))) class XMPPStatusPush(HttpStatusPushBase): name = "XMPPStatusPush" @@ -292,7 +242,7 @@ class XMPPStatusPush(HttpStatusPushBase): duration = "{}s".format(seconds) text = "Build {} ( {} ) of {}'s {} was {} in {}.".format( - build["buildid"], build["url"], + build["number"], build["url"], build["builder"]["name"], msg, results.Results[build["results"]], @@ -300,7 +250,7 @@ class XMPPStatusPush(HttpStatusPushBase): ) else: text = "Build {} ( {} ) of {}'s {} started.".format( - build["buildid"], build["url"], + build["number"], build["url"], build["builder"]["name"], msg, ) diff --git a/modules/private/buildbot/projects/caldance/__init__.py b/modules/private/buildbot/projects/caldance/__init__.py index 747e86e..fe3ff64 100644 --- a/modules/private/buildbot/projects/caldance/__init__.py +++ b/modules/private/buildbot/projects/caldance/__init__.py @@ -70,7 +70,7 @@ def configure(c): configure_build(c, db_lock.access('exclusive')) configure_deploy(c, db_lock.access('exclusive')) - configure_slack_push(c, E.SECRETS_FILE, all_builder_names(c)) + configure_apprise_push(c, E.SECRETS_FILE, all_builder_names(c)) configure_xmpp_push(c, E.SECRETS_FILE, all_builder_names(c), E.XMPP_RECIPIENTS) def configure_build(c, lock): diff --git a/modules/private/buildbot/projects/cryptoportfolio/__init__.py b/modules/private/buildbot/projects/cryptoportfolio/__init__.py index b99ebb5..46c783e 100644 --- a/modules/private/buildbot/projects/cryptoportfolio/__init__.py +++ b/modules/private/buildbot/projects/cryptoportfolio/__init__.py @@ -44,7 +44,7 @@ def configure(c): configure_build(c) configure_deploy(c) - configure_slack_push(c, E.SECRETS_FILE, all_builder_names(c)) + configure_apprise_push(c, E.SECRETS_FILE, all_builder_names(c)) def configure_build(c): front_builder_name = "Front_build" diff --git a/modules/private/buildbot/projects/immaeEu/__init__.py b/modules/private/buildbot/projects/immaeEu/__init__.py index e817ad0..a98648e 100644 --- a/modules/private/buildbot/projects/immaeEu/__init__.py +++ b/modules/private/buildbot/projects/immaeEu/__init__.py @@ -82,7 +82,7 @@ def configure(c): c['schedulers'].append(force_scheduler("force_immae_eu", withbranch)) c['schedulers'].append(force_scheduler("force_no_branch_immae_eu", withoutbranch, nobranch=True)) - configure_slack_push(c, E.SECRETS_FILE, all_builder_names(c)) + configure_apprise_push(c, E.SECRETS_FILE, all_builder_names(c)) configure_xmpp_push(c, E.SECRETS_FILE, all_builder_names(c), E.XMPP_RECIPIENTS) BRANCH_TO_SYMFONY_ENV = { diff --git a/modules/private/buildbot/projects/test/__init__.py b/modules/private/buildbot/projects/test/__init__.py index 926a6bb..d5893fd 100644 --- a/modules/private/buildbot/projects/test/__init__.py +++ b/modules/private/buildbot/projects/test/__init__.py @@ -66,7 +66,7 @@ def configure(c): configure_build(c) configure_deploy(c) - configure_slack_push(c, E.SECRETS_FILE, all_builder_names(c)) + configure_apprise_push(c, E.SECRETS_FILE, all_builder_names(c)) configure_xmpp_push(c, E.SECRETS_FILE, all_builder_names(c), E.XMPP_RECIPIENTS) def configure_build(c): diff --git a/modules/private/environment.nix b/modules/private/environment.nix index b321e03..ae00298 100644 --- a/modules/private/environment.nix +++ b/modules/private/environment.nix @@ -586,8 +586,7 @@ in }; }; nrdp_tokens = mkOption { type = listOf str; description = "Tokens allowed to push status update"; }; - slack_url = mkOption { type = str; description = "Slack webhook url to push status update"; }; - slack_channel = mkOption { type = str; description = "Slack channel to push status update"; }; + apprise_urls = mkOption { type = str; description = "Apprise space-separated urls to push status update"; }; netdata_aggregator = mkOption { type = str; description = "Url where netdata information should be sent"; }; netdata_keys = mkOption { type = attrsOf str; description = "netdata host keys"; }; contacts = mkOption { type = attrsOf unspecified; description = "Contact dicts to fill naemon objects"; }; diff --git a/modules/private/gitolite/default.nix b/modules/private/gitolite/default.nix index d02a4ef..e34d4fa 100644 --- a/modules/private/gitolite/default.nix +++ b/modules/private/gitolite/default.nix @@ -59,6 +59,7 @@ in { users.users.gitolite.packages = let python-packages = python-packages: with python-packages; [ simplejson + apprise urllib3 sleekxmpp pyyaml diff --git a/modules/private/monitoring/myplugins.nix b/modules/private/monitoring/myplugins.nix index 76aa557..4997e90 100644 --- a/modules/private/monitoring/myplugins.nix +++ b/modules/private/monitoring/myplugins.nix @@ -21,24 +21,24 @@ in }; notify-primary = { resources = { - USER206 = config.myEnv.monitoring.slack_channel; - USER207 = config.myEnv.monitoring.slack_url; + USER210 = config.myEnv.monitoring.apprise_urls; }; commands = { # $OVE is to force naemon to run via shell instead of execve which fails here notify-host-by-email = "ADMINEMAIL=\"$ADMINEMAIL$\" SERVICENOTIFICATIONID=\"$SERVICENOTIFICATIONID$\" HOSTSTATE=\"$HOSTSTATE$\" HOSTOUTPUT=\"$HOSTOUTPUT$\" $USER2$/notify_by_email host \"$NOTIFICATIONTYPE$\" \"$HOSTALIAS$\" \"$LONGDATETIME$\" \"$CONTACTEMAIL$\" $OVE"; # $OVE is to force naemon to run via shell instead of execve which fails here notify-service-by-email = "ADMINEMAIL=\"$ADMINEMAIL$\" SERVICENOTIFICATIONID=\"$SERVICENOTIFICATIONID$\" SERVICEDESC=\"$SERVICEDESC$\" SERVICESTATE=\"$SERVICESTATE$\" SERVICEOUTPUT=\"$SERVICEOUTPUT$\" $USER2$/notify_by_email service \"$NOTIFICATIONTYPE$\" \"$HOSTALIAS$\" \"$LONGDATETIME$\" \"$CONTACTEMAIL$\" $OVE"; - notify-by-slack = "HOST=\"$HOSTALIAS$\" SERVICESTATE=\"$SERVICESTATE$\" SERVICEDESC=\"$SERVICEDESC$\" SERVICEOUTPUT=\"$SERVICEOUTPUT$\" $USER2$/notify_by_slack \"$ARG1$\" \"$ARG2$\""; + notify-host-by-apprise = "HOST=\"$HOSTALIAS$\" NOTIFICATIONTYPE=\"$NOTIFICATIONTYPE$\" HOSTSTATE=\"$HOSTSTATE$\" HOSTOUTPUT=\"$HOSTOUTPUT$\" $USER2$/notify_by_apprise host \"$ARG1$\""; + notify-service-by-apprise = "HOST=\"$HOSTALIAS$\" NOTIFICATIONTYPE=\"$NOTIFICATIONTYPE$\" SERVICESTATE=\"$SERVICESTATE$\" SERVICEDESC=\"$SERVICEDESC$\" SERVICEOUTPUT=\"$SERVICEOUTPUT$\" $USER2$/notify_by_apprise service \"$ARG1$\""; }; chunk = '' - cp ${./plugins}/{notify_by_email,notify_by_slack} $out - patchShebangs $out/{notify_by_email,notify_by_slack} + cp ${./plugins}/{notify_by_email,notify_by_apprise} $out + patchShebangs $out/{notify_by_email,notify_by_apprise} wrapProgram $out/notify_by_email --prefix PATH : ${lib.makeBinPath [ pkgs.mailutils ]} - wrapProgram $out/notify_by_slack --prefix PATH : ${lib.makeBinPath [ - pkgs.curl pkgs.jq + wrapProgram $out/notify_by_apprise --prefix PATH : ${lib.makeBinPath [ + pkgs.apprise ]} ''; }; diff --git a/modules/private/monitoring/objects_master.nix b/modules/private/monitoring/objects_master.nix index 30bfe73..7b6c84e 100644 --- a/modules/private/monitoring/objects_master.nix +++ b/modules/private/monitoring/objects_master.nix @@ -4,8 +4,8 @@ immae = config.myEnv.monitoring.contacts.immae // { use = "generic-contact"; contactgroups = "admins"; - host_notification_commands = "notify-host-by-email,notify-by-slack!$USER206$!$USER207$"; - service_notification_commands = "notify-service-by-email,notify-by-slack!$USER206$!$USER207$"; + host_notification_commands = "notify-host-by-email,notify-host-by-apprise!$USER210$"; + service_notification_commands = "notify-service-by-email,notify-service-by-apprise!$USER210$"; }; }; command = { diff --git a/modules/private/monitoring/objects_monitoring-1.nix b/modules/private/monitoring/objects_monitoring-1.nix index 352ed79..f82af21 100644 --- a/modules/private/monitoring/objects_monitoring-1.nix +++ b/modules/private/monitoring/objects_monitoring-1.nix @@ -5,6 +5,10 @@ # Dummy host for testing # "dummy-host" = { # alias = "dummy.host"; + # check_interval = "0.3"; + # max_check_attempts = "1"; + # flap_detection_enabled = "0"; + # notification_interval = "0.1"; # address = "dummy.host"; # use = "linux-server"; # check_command = "check_ok"; diff --git a/modules/private/monitoring/plugins/notify_by_apprise b/modules/private/monitoring/plugins/notify_by_apprise new file mode 100755 index 0000000..82bc5a3 --- /dev/null +++ b/modules/private/monitoring/plugins/notify_by_apprise @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +APPRISE_USERNAME="Naemon" +APPRISE_USERICON="https://assets.immae.eu/monitoring.png" +APPRISE_URLS=$(echo "$2" | sed -e "s/{username}/$APPRISE_USERNAME/g" -e "s@{image_url}@$APPRISE_USERICON@g") + +if [ "$SERVICESTATE" = "CRITICAL" ]; then + ICON="❗" +elif [ "$SERVICESTATE" = "WARNING" ]; then + ICON="⚠️:" +elif [ "$SERVICESTATE" = "OK" ]; then + ICON="✅" +elif [ "$SERVICESTATE" = "UNKNOWN" ]; then + ICON="❓" +elif [ "$HOSTSTATE" = "UP" ]; then + ICON="✅" +elif [ "$HOSTSTATE" = "DOWN" ]; then + ICON="❗" +elif [ "$HOSTSTATE" = "UNKNOWN" ]; then + ICON="❓" +elif [ "$HOSTSTATE" = "UNREACHABLE" ]; then + ICON="❓" +else + ICON="◻" +fi + +if [ "$1" = "host" ]; then + apprise --title "${ICON} ${NOTIFICATIONTYPE} ${HOST} is ${HOSTSTATE}" --body "$HOSTOUTPUT" $APPRISE_URLS +else + apprise --title "${ICON} ${NOTIFICATIONTYPE} ${SERVICEDESC} on ${HOST} is ${SERVICESTATE}" --body "$SERVICEOUTPUT" $APPRISE_URLS +fi diff --git a/modules/private/websites/tools/tools/default.nix b/modules/private/websites/tools/tools/default.nix index 6ca4c17..e640eb6 100644 --- a/modules/private/websites/tools/tools/default.nix +++ b/modules/private/websites/tools/tools/default.nix @@ -55,8 +55,14 @@ let e.empteintesduweb.monitoranswers e.lr94.autosubscribe e.phpbbmodders.adduser ]); }; + webhooks-bin-env = pkgs.buildEnv { + name = "webhook-env"; + paths = [ pkgs.apprise ]; + pathsToLink = [ "/bin" ]; + }; webhooks = pkgs.callPackage ./webhooks.nix { env = config.myEnv.tools.webhooks; + binEnv = webhooks-bin-env; }; dmarc-reports = pkgs.callPackage ./dmarc_reports.nix { env = config.myEnv.tools.dmarc_reports; @@ -305,6 +311,7 @@ in { "php_admin_value[open_basedir]" = builtins.concatStringsSep ":" [ "/run/wrappers/bin/sendmail" landing "/tmp" config.secrets.fullPaths."webapps/webhooks" + "${webhooks-bin-env}/bin" ]; }; phpEnv = { diff --git a/modules/private/websites/tools/tools/webhooks.nix b/modules/private/websites/tools/tools/webhooks.nix index c24c09c..d21e733 100644 --- a/modules/private/websites/tools/tools/webhooks.nix +++ b/modules/private/websites/tools/tools/webhooks.nix @@ -1,17 +1,17 @@ -{ lib, env }: +{ lib, env, binEnv }: { keys = lib.attrsets.mapAttrs' (k: v: lib.nameValuePair "webapps/webhooks/${k}.php" { user = "wwwrun"; group = "wwwrun"; permissions = "0400"; - text = v; + text = builtins.replaceStrings ["{{webhooks-bin-env}}"] [ "${binEnv}" ] v; }) env // lib.attrsets.mapAttrs' (k: v: lib.nameValuePair "webapps/webhooks/${k}/index.php" { user = "wwwrun"; group = "wwwrun"; permissions = "0400"; - text = v; + text = builtins.replaceStrings ["{{webhooks-bin-env}}"] [ "${binEnv}" ] v; }) env // { "webapps/webhooks" = { isDir = true; -- 2.41.0