summary refs log tree commit diff
path: root/nixos/modules/services/continuous-integration/jenkins/job-builder.nix
diff options
context:
space:
mode:
authorBjørn Forsman <bjorn.forsman@gmail.com>2015-10-08 22:15:15 +0200
committerBjørn Forsman <bjorn.forsman@gmail.com>2015-11-03 16:32:31 +0100
commit27f41d8c0afd2e1380bbab4eea45a16f9345f90c (patch)
treeffe2f8d26407ca85dd5f5f677c6f5d2404c0253b /nixos/modules/services/continuous-integration/jenkins/job-builder.nix
parenta487b3326b3eb31c6fbd38ddd394932031ad000e (diff)
downloadnixpkgs-27f41d8c0afd2e1380bbab4eea45a16f9345f90c.tar
nixpkgs-27f41d8c0afd2e1380bbab4eea45a16f9345f90c.tar.gz
nixpkgs-27f41d8c0afd2e1380bbab4eea45a16f9345f90c.tar.bz2
nixpkgs-27f41d8c0afd2e1380bbab4eea45a16f9345f90c.tar.lz
nixpkgs-27f41d8c0afd2e1380bbab4eea45a16f9345f90c.tar.xz
nixpkgs-27f41d8c0afd2e1380bbab4eea45a16f9345f90c.tar.zst
nixpkgs-27f41d8c0afd2e1380bbab4eea45a16f9345f90c.zip
nixos: add services.jenkins.jobBuilder option
This option allows to define (declarative) Jenkins jobs, using Jenkins
Job Builder (JJB) as backend.

Example:

  services.jenkins = {
    enable = true;
    jobBuilder = {
      enable = true;
      yamlJobs = ''
        - job:
            name: jenkins-job-test
            builders:
              - shell: echo 'Hello world!'
      '';
    };
  };

Jobs can be defined using YAML, JSON and Nix.

Note that it really is declarative configuration; if you remove a
previously defined job, the module will remove the jobdir under
$JENKINS_HOME.

Jobs managed through the Jenkins WebUI (or by other means) are not
touched by this module.

Changes v1 -> v2:
* add nixJobs
* let jsonJobs take a list of strings (allows merge)
* 4 space indent in shell code
Diffstat (limited to 'nixos/modules/services/continuous-integration/jenkins/job-builder.nix')
-rw-r--r--nixos/modules/services/continuous-integration/jenkins/job-builder.nix155
1 files changed, 155 insertions, 0 deletions
diff --git a/nixos/modules/services/continuous-integration/jenkins/job-builder.nix b/nixos/modules/services/continuous-integration/jenkins/job-builder.nix
new file mode 100644
index 00000000000..ec15a6a3d70
--- /dev/null
+++ b/nixos/modules/services/continuous-integration/jenkins/job-builder.nix
@@ -0,0 +1,155 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  jenkinsCfg = config.services.jenkins;
+  cfg = config.services.jenkins.jobBuilder;
+
+in {
+  options = {
+    services.jenkins.jobBuilder = {
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether or not to enable the Jenkins Job Builder (JJB) service. It
+          allows defining jobs for Jenkins in a declarative manner.
+
+          Jobs managed through the Jenkins WebUI (or by other means) are left
+          unchanged.
+
+          Note that it really is declarative configuration; if you remove a
+          previously defined job, the corresponding job directory will be
+          deleted.
+
+          Please see the Jenkins Job Builder documentation for more info:
+          <link xlink:href="http://docs.openstack.org/infra/jenkins-job-builder/">
+          http://docs.openstack.org/infra/jenkins-job-builder/</link>
+        '';
+      };
+
+      yamlJobs = mkOption {
+        default = "";
+        type = types.lines;
+        example = ''
+          - job:
+              name: jenkins-job-test-1
+              builders:
+                - shell: echo 'Hello world!'
+        '';
+        description = ''
+          Job descriptions for Jenkins Job Builder in YAML format.
+        '';
+      };
+
+      jsonJobs = mkOption {
+        default = [ ];
+        type = types.listOf types.str;
+        example = literalExample ''
+          [
+            '''
+              [ { "job":
+                  { "name": "jenkins-job-test-2",
+                    "builders": [ "shell": "echo 'Hello world!'" ]
+                  }
+                }
+              ]
+            '''
+          ]
+        '';
+        description = ''
+          Job descriptions for Jenkins Job Builder in JSON format.
+        '';
+      };
+
+      nixJobs = mkOption {
+        default = [ ];
+        type = types.listOf types.attrs;
+        example = literalExample ''
+          [ { job =
+              { name = "jenkins-job-test-3";
+                builders = [
+                  { shell = "echo 'Hello world!'"; }
+                ];
+              };
+            }
+          ];
+        '';
+        description = ''
+          Job descriptions for Jenkins Job Builder in Nix format.
+
+          This is a trivial wrapper around jsonJobs, using builtins.toJSON
+          behind the scene.
+        '';
+      };
+    };
+  };
+
+  config = mkIf (jenkinsCfg.enable && cfg.enable) {
+    systemd.services.jenkins-job-builder = {
+      description = "Jenkins Job Builder Service";
+      # JJB can run either before or after jenkins. We chose after, so we can
+      # always use curl to notify (running) jenkins to reload its config.
+      after = [ "jenkins.service" ];
+      wantedBy = [ "multi-user.target" ];
+
+      path = with pkgs; [ jenkins-job-builder curl ];
+
+      # Q: Why manipulate files directly instead of using "jenkins-jobs upload [...]"?
+      # A: Because this module is for administering a local jenkins install,
+      #    and using local file copy allows us to not worry about
+      #    authentication.
+      script =
+        let
+          yamlJobsFile = builtins.toFile "jobs.yaml" cfg.yamlJobs;
+          jsonJobsFiles =
+            map (x: (builtins.toFile "jobs.json" x))
+              (cfg.jsonJobs ++ [(builtins.toJSON cfg.nixJobs)]);
+          jobBuilderOutputDir = "/run/jenkins-job-builder/output";
+          # Stamp file is placed in $JENKINS_HOME/jobs/$JOB_NAME/ to indicate
+          # ownership. Enables tracking and removal of stale jobs.
+          ownerStamp = ".config-xml-managed-by-nixos-jenkins-job-builder";
+        in
+          ''
+            rm -rf ${jobBuilderOutputDir}
+            cur_decl_jobs=/run/jenkins-job-builder/declarative-jobs
+            rm -f "$cur_decl_jobs"
+
+            # Create / update jobs
+            mkdir -p ${jobBuilderOutputDir}
+            for inputFile in ${yamlJobsFile} ${concatStringsSep " " jsonJobsFiles}; do
+                HOME="${jenkinsCfg.home}" "${pkgs.jenkins-job-builder}/bin/jenkins-jobs" --ignore-cache test -o "${jobBuilderOutputDir}" "$inputFile"
+            done
+
+            for file in "${jobBuilderOutputDir}/"*; do
+                test -f "$file" || continue
+                jobname="$(basename $file)"
+                jobdir="${jenkinsCfg.home}/jobs/$jobname"
+                echo "Creating / updating job \"$jobname\""
+                mkdir -p "$jobdir"
+                touch "$jobdir/${ownerStamp}"
+                cp "$file" "$jobdir/config.xml"
+                echo "$jobname" >> "$cur_decl_jobs"
+            done
+
+            # Remove stale jobs
+            for file in "${jenkinsCfg.home}"/jobs/*/${ownerStamp}; do
+                test -f "$file" || continue
+                jobdir="$(dirname $file)"
+                jobname="$(basename "$jobdir")"
+                grep --quiet --line-regexp "$jobname" "$cur_decl_jobs" 2>/dev/null && continue
+                echo "Deleting stale job \"$jobname\""
+                rm -rf "$jobdir"
+            done
+
+            echo "Asking Jenkins to reload config"
+            curl --silent -X POST http://localhost:${toString jenkinsCfg.port}/reload
+          '';
+      serviceConfig = {
+        User = jenkinsCfg.user;
+        RuntimeDirectory = "jenkins-job-builder";
+      };
+    };
+  };
+}