]> git.immae.eu Git - perso/Immae/Config/Nix.git/blobdiff - modules/private/buildbot/common/build_helpers.py
Rework buildbot configuration
[perso/Immae/Config/Nix.git] / modules / private / buildbot / common / build_helpers.py
index acea90591f5ca16b524e0e41b7d22087ef72cf7c..55b8b989d26aa664a7aac9298f839af19e2e997e 100644 (file)
@@ -3,9 +3,11 @@ from buildbot_buildslist import BuildsList
 from shutil import which
 
 __all__ = [
-        "force_scheduler", "deploy_scheduler", "hook_scheduler",
+        "force_scheduler", "deploy_scheduler", "git_hook_scheduler",
         "clean_branch", "package_and_upload", "SlackStatusPush",
-        "XMPPStatusPush", "NixShellCommand"
+        "XMPPStatusPush", "LdapEdit", "NixShellCommand",
+        "all_builder_names", "compute_build_infos", "deploy_ssh_command",
+        "configure_slack_push", "configure_xmpp_push", "deploy_hook_scheduler",
         ]
 
 # Small helpers"
@@ -19,22 +21,21 @@ def clean_branch(props):
 def package_and_upload(package, package_dest, package_url):
     return [
             steps.ShellCommand(name="build package",
-                logEnviron=False, haltOnFailure=True, workdir="source",
+                logEnviron=False, haltOnFailure=True,
                 command=["git", "archive", "HEAD", "-o", package]),
 
             steps.FileUpload(name="upload package", workersrc=package,
-                workdir="source", masterdest=package_dest,
+                masterdest=package_dest,
                 url=package_url, mode=0o644),
 
             steps.ShellCommand(name="cleanup package", logEnviron=False,
-                haltOnFailure=True, workdir="source", alwaysRun=True,
+                haltOnFailure=True, alwaysRun=True,
                 command=["rm", "-f", package]),
             ]
 
 # Steps
 class NixShellCommand(steps.ShellCommand):
     def __init__(self, command=None, pure=True, nixfile=None, **kwargs):
-        assert(isinstance(command, str))
         oldpath = kwargs.get("env", {}).get("PATH", None)
         if which("nix-shell", path=oldpath) is None:
             kwargs["env"] = kwargs.get("env", {})
@@ -52,14 +53,18 @@ class NixShellCommand(steps.ShellCommand):
         super().__init__(command=nixcommand, **kwargs)
 
 # Schedulers
-def force_scheduler(name, builders):
+def force_scheduler(name, builders, nobranch=False):
+    if nobranch:
+        branch = util.FixedParameter(name="branch", default="")
+    else:
+        branch=util.StringParameter(name="branch", label="Git reference (tag, branch)", required=True)
+
     return schedulers.ForceScheduler(name=name,
         label="Force build", buttonName="Force build",
         reason=util.StringParameter(name="reason", label="Reason", default="Force build"),
         codebases=[
             util.CodebaseParameter("",
-                branch=util.StringParameter(
-                    name="branch", label="Git reference (tag, branch)", required=True),
+                branch=branch,
                 revision=util.FixedParameter(name="revision", default=""),
                 repository=util.FixedParameter(name="repository", default=""),
                 project=util.FixedParameter(name="project", default=""),
@@ -88,10 +93,21 @@ def deploy_scheduler(name, builders):
             ]
         )
 
-def hook_scheduler(project, timer=10):
+def git_hook_scheduler(project, builders=[], timer=1):
+    if len(builders) == 0:
+        builders = ["{}_build".format(project)]
+    return schedulers.AnyBranchScheduler(
+            change_filter=util.ChangeFilter(category="gitolite-hooks", project=project),
+            name="{}_git_hook".format(project), treeStableTimer=timer, builderNames=builders)
+
+def deploy_hook_scheduler(project, builders, timer=1):
     return schedulers.AnyBranchScheduler(
-            change_filter=util.ChangeFilter(category="hooks", project=project),
-            name=project, treeStableTimer=timer, builderNames=["{}_build".format(project)])
+            change_filter=util.ChangeFilter(category="deploy_webhook", project=project),
+            name="{}_deploy".format(project), treeStableTimer=timer, builderNames=builders)
+
+# Builders
+def all_builder_names(c):
+    return [builder.name for builder in c['builders']]
 
 # Slack/XMPP status push
 from buildbot.reporters.http import HttpStatusPushBase
@@ -213,6 +229,11 @@ class SlackStatusPush(HttpStatusPushBase):
                 "attachments": attachments,
                 }
 
+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()))
+
 class XMPPStatusPush(HttpStatusPushBase):
     name = "XMPPStatusPush"
 
@@ -275,3 +296,79 @@ class XMPPStatusPush(HttpStatusPushBase):
                     )
 
         return text
+
+def configure_xmpp_push(c, secrets_file, builders, recipients):
+    c['services'].append(XMPPStatusPush(
+        name="xmpp_status", builders=builders, recipients=recipients,
+        password=open(secrets_file + "/notify_xmpp_password", "r").read().rstrip()))
+
+# LDAP edit
+from buildbot.process.buildstep import FAILURE
+from buildbot.process.buildstep import SUCCESS
+from buildbot.process.buildstep import BuildStep
+
+class LdapEdit(BuildStep):
+    name = "LdapEdit"
+    renderables = ["environment", "build_version", "build_hash", "ldap_password"]
+
+    def __init__(self, **kwargs):
+        self.environment = kwargs.pop("environment")
+        self.build_version = kwargs.pop("build_version")
+        self.build_hash = kwargs.pop("build_hash")
+        self.ldap_password = kwargs.pop("ldap_password")
+        self.ldap_host = kwargs.pop("ldap_host")
+        self.ldap_dn = kwargs.pop("ldap_dn")
+        self.ldap_roles_base = kwargs.pop("ldap_roles_base")
+        self.ldap_cn_template = kwargs.pop("ldap_cn_template")
+        self.config_key = kwargs.pop("config_key")
+        super().__init__(**kwargs)
+
+    def run(self):
+        import json
+        from ldap3 import Reader, Writer, Server, Connection, ObjectDef
+        server = Server(self.ldap_host)
+        conn = Connection(server,
+                user=self.ldap_dn,
+                password=self.ldap_password)
+        conn.bind()
+        obj = ObjectDef("immaePuppetClass", conn)
+        r = Reader(conn, obj,
+                "cn={},{}".format(self.ldap_cn_template.format(self.environment), self.ldap_roles_base))
+        r.search()
+        if len(r) > 0:
+            w = Writer.from_cursor(r)
+            for value in w[0].immaePuppetJson.values:
+                config = json.loads(value)
+                if "{}_version".format(self.config_key) in config:
+                    config["{}_version".format(self.config_key)] = self.build_version
+                    config["{}_sha256".format(self.config_key)] = self.build_hash
+                    w[0].immaePuppetJson -= value
+                    w[0].immaePuppetJson += json.dumps(config, indent="  ")
+                    w.commit()
+                    return defer.succeed(SUCCESS)
+        return defer.succeed(FAILURE)
+
+def compute_build_infos(prefix, release_path):
+    @util.renderer
+    def compute(props):
+        import re, hashlib
+        build_file = props.getProperty("build")
+        package_dest = "{}/{}".format(release_path, build_file)
+        version = re.match(r"{0}_(.*).tar.gz".format(prefix), build_file).group(1)
+        with open(package_dest, "rb") as f:
+            sha = hashlib.sha256(f.read()).hexdigest()
+        return {
+                "build_version": version,
+                "build_hash": sha,
+                }
+    return compute
+
+def deploy_ssh_command(ssh_key_path, deploy_hosts):
+    @util.renderer
+    def compute(props):
+        environment = props["environment"] if props.hasProperty("environment") else "integration"
+        ssh_command = [
+                "ssh", "-o", "UserKnownHostsFile=/dev/null", "-o", "StrictHostKeyChecking=no", "-o", "CheckHostIP=no",
+                "-i", ssh_key_path ]
+        return ssh_command + deploy_hosts.get(environment, ["host.invalid"])
+    return compute