From: Ismaƫl Bouya Date: Wed, 27 Mar 2019 12:13:00 +0000 (+0100) Subject: Add xmpp push notifications to buildbot and gitolite X-Git-Tag: nur_publish~187 X-Git-Url: https://git.immae.eu/?p=perso%2FImmae%2FConfig%2FNix.git;a=commitdiff_plain;h=256d607c2db3e56a2f481a2097ffa3ccd109d141 Add xmpp push notifications to buildbot and gitolite --- diff --git a/nixops/modules/buildbot/apprise.json b/nixops/modules/buildbot/apprise.json new file mode 100644 index 0000000..b408ea4 --- /dev/null +++ b/nixops/modules/buildbot/apprise.json @@ -0,0 +1,15 @@ +{ + "tag": "c9b957c-master", + "meta": { + "name": "apprise", + "url": "https://github.com/caronc/apprise", + "branch": "master" + }, + "github": { + "owner": "caronc", + "repo": "apprise", + "rev": "c9b957c4341e7d43e5be6463bd317a7401d083d9", + "sha256": "01zz4mh3xvplrm5xalzrcncnh0jq5y51pmdxkr4hdd6dz9wx0mbg", + "fetchSubmodules": true + } +} diff --git a/nixops/modules/buildbot/common/build_helpers.py b/nixops/modules/buildbot/common/build_helpers.py index f51de54..63733e7 100644 --- a/nixops/modules/buildbot/common/build_helpers.py +++ b/nixops/modules/buildbot/common/build_helpers.py @@ -3,7 +3,8 @@ from buildbot_buildslist import BuildsList __all__ = [ "force_scheduler", "deploy_scheduler", "hook_scheduler", - "clean_branch", "package_and_upload", "SlackStatusPush" + "clean_branch", "package_and_upload", "SlackStatusPush", + "XMPPStatusPush" ] # Small helpers" @@ -71,13 +72,16 @@ def hook_scheduler(project, timer=10): change_filter=util.ChangeFilter(category="hooks", project=project), name=project, treeStableTimer=timer, builderNames=["{}_build".format(project)]) -# Slack status push +# Slack/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 + class SlackStatusPush(HttpStatusPushBase): name = "SlackStatusPush" @@ -188,5 +192,66 @@ class SlackStatusPush(HttpStatusPushBase): "attachments": attachments, } +class XMPPStatusPush(HttpStatusPushBase): + name = "XMPPStatusPush" + + @defer.inlineCallbacks + def reconfigService(self, password, recipients, **kwargs): + yield HttpStatusPushBase.reconfigService(self, **kwargs) + self.password = password + self.recipients = recipients + + @defer.inlineCallbacks + def send(self, build): + yield utils.getDetailsForBuild(self.master, build, wantProperties=True) + body = self.format(build) + factory = client.DeferredClientFactory(JID("notify_bot@immae.fr/buildbot"), self.password) + factory.streamManager.logTraffic = True + d = client.clientCreator(factory) + def send_message(stream): + message = xmppim.Message(recipient=JID(recipient), body=body) + message.stanzaType = 'chat' + stream.send(message.toElement()) + # To allow chaining + return stream + for recipient in self.recipients: + d.addCallback(send_message) + d.addCallback(lambda _: factory.streamManager.xmlstream.sendFooter()) + d.addErrback(log.err) + + def format(self, build): + if "environment" in build["properties"]: + msg = "{} environment".format(build["properties"]["environment"][0]) + if "build" in build["properties"]: + msg = "of archive {} in ".format(build["properties"]["build"][0]) + msg + elif len(build["buildset"]["sourcestamps"][0]["branch"]) > 0: + msg = "revision {}".format(build["buildset"]["sourcestamps"][0]["branch"]) + else: + msg = "build" + + if build["complete"]: + timedelta = int((build["complete_at"] - build["started_at"]).total_seconds()) + hours, rest = divmod(timedelta, 3600) + minutes, seconds = divmod(rest, 60) + if hours > 0: + duration = "{}h {}min {}s".format(hours, minutes, seconds) + elif minutes > 0: + duration = "{}min {}s".format(minutes, seconds) + else: + duration = "{}s".format(seconds) + text = "Build {} ( {} ) of {}'s {} was {} in {}.".format( + build["buildid"], build["url"], + build["builder"]["name"], + msg, + results.Results[build["results"]], + duration, + ) + else: + text = "Build {} ( {} ) of {}'s {} started.".format( + build["buildid"], build["url"], + build["builder"]["name"], + msg, + ) + return text diff --git a/nixops/modules/buildbot/default.nix b/nixops/modules/buildbot/default.nix index 21b784b..c670b7d 100644 --- a/nixops/modules/buildbot/default.nix +++ b/nixops/modules/buildbot/default.nix @@ -57,6 +57,33 @@ in }; config = lib.mkIf config.services.buildbot.enable { + nixpkgs.overlays = [ (self: super: rec { + python3 = super.python3.override { + packageOverrides = python-self: python-super: { + wokkel = python-self.buildPythonPackage rec { + pname = "wokkel"; + version = "18.0.0"; + src = python-self.fetchPypi { + inherit pname version; + sha256 = "1spq44gg8gsviqx1dvlmjpgfc0wk0jpyx4ap01y2pad1ai9cw016"; + }; + propagatedBuildInputs = with python-self; [ twisted.extras.tls twisted incremental dateutil ]; + doChecks = false; + }; + apprise = python-self.buildPythonPackage rec { + pname = "apprise"; + version = "0.7.4"; + src = (mylibs.fetchedGithub ./apprise.json).src; + propagatedBuildInputs = with python-self; [ decorator + requests requests_oauthlib oauthlib urllib3 six click + markdown pyyaml sleekxmpp + ]; + doChecks = false; + }; + }; + }; + }) ]; + ids.uids.buildbot = myconfig.env.buildbot.user.uid; ids.gids.buildbot = myconfig.env.buildbot.user.gid; @@ -171,6 +198,7 @@ in }); HOME = "${varDir}/${project.name}"; PYTHONPATH = "${buildbot.pythonModule.withPackages (self: project.pythonPackages self pkgs ++ [ + pkgs.python3Packages.wokkel pkgs.python3Packages.treq pkgs.python3Packages.ldap3 buildbot pkgs.python3Packages.buildbot-worker buildbot_common buildbot_config diff --git a/nixops/modules/buildbot/projects/caldance/__init__.py b/nixops/modules/buildbot/projects/caldance/__init__.py index 1069c35..2c0bad5 100644 --- a/nixops/modules/buildbot/projects/caldance/__init__.py +++ b/nixops/modules/buildbot/projects/caldance/__init__.py @@ -19,6 +19,7 @@ class E(): LDAP_HOST = "ldap.immae.eu" LDAP_DN = "cn=buildbot,ou=services,dc=immae,dc=eu" LDAP_ROLES_BASE = "ou=roles,ou=hosts,dc=immae,dc=eu" + XMPP_RECIPIENTS = os.environ["BUILDBOT_XMPP_RECIPIENTS"].split(" ") PUPPET_HOST = { "integration": "root@caldance.immae.eu", @@ -89,6 +90,11 @@ def configure(c): name="slack_status_caldance", builders=["Caldance_build", "Caldance_deploy"], serverUrl=open(E.SECRETS_FILE + "/slack_webhook", "r").read().rstrip())) + c['services'].append(XMPPStatusPush( + name="xmpp_status_caldance", + builders=["Caldance_build", "Caldance_deploy"], + recipients=E.XMPP_RECIPIENTS, + password=open(E.SECRETS_FILE + "/notify_xmpp_password", "r").read().rstrip())) def factory(project, ignore_fails=False): release_file = "{1}/{0}_%(kw:clean_branch)s.tar.gz" diff --git a/nixops/modules/buildbot/projects/test/__init__.py b/nixops/modules/buildbot/projects/test/__init__.py index 0644920..e6b8d51 100644 --- a/nixops/modules/buildbot/projects/test/__init__.py +++ b/nixops/modules/buildbot/projects/test/__init__.py @@ -19,6 +19,7 @@ class E(): LDAP_HOST = "ldap.immae.eu" LDAP_DN = "cn=buildbot,ou=services,dc=immae,dc=eu" LDAP_ROLES_BASE = "ou=roles,ou=hosts,dc=immae,dc=eu" + XMPP_RECIPIENTS = os.environ["BUILDBOT_XMPP_RECIPIENTS"].split(" ") # master.cfg SECRETS_FILE = os.getcwd() + "/secrets" @@ -84,6 +85,11 @@ def configure(c): name="slack_status_test_project", builders=["TestProject_build", "TestProject_deploy"], serverUrl=open(E.SECRETS_FILE + "/slack_webhook", "r").read().rstrip())) + c['services'].append(XMPPStatusPush( + name="xmpp_status_test_project", + builders=["TestProject_build", "TestProject_deploy"], + recipients=E.XMPP_RECIPIENTS, + password=open(E.SECRETS_FILE + "/notify_xmpp_password", "r").read().rstrip())) def factory(): package = util.Interpolate("test_%(kw:clean_branch)s.tar.gz", clean_branch=clean_branch) diff --git a/nixops/modules/gitolite/default.nix b/nixops/modules/gitolite/default.nix index 844bd0f..8703fbb 100644 --- a/nixops/modules/gitolite/default.nix +++ b/nixops/modules/gitolite/default.nix @@ -48,6 +48,7 @@ in { python-packages = python-packages: with python-packages; [ simplejson urllib3 + sleekxmpp ]; in [