diff options
Diffstat (limited to 'modules/apps/jenkins/default.nix')
-rw-r--r-- | modules/apps/jenkins/default.nix | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/modules/apps/jenkins/default.nix b/modules/apps/jenkins/default.nix new file mode 100644 index 0000000..d0ccb25 --- /dev/null +++ b/modules/apps/jenkins/default.nix @@ -0,0 +1,149 @@ +{ config, lib, pkgs, ... }: + +let + + inherit (builtins) + attrNames isBool isString ; + + inherit (lib) + concatMapStringsSep concatStringsSep escape filter filterAttrs + foldAttrs foldl hasPrefix mapAttrs mapAttrsToList mkOption nameValuePair + optionalString ; + + inherit (lib.types) + attrsOf submodule ; + + explicit = filterAttrs (n: v: n != "_module" && v != null); + isKey = s: s != null && hasPrefix "/run/keys/" s; + + instances = explicit config.nixsap.apps.jenkins; + users = mapAttrsToList (_: i: i.user) instances; + + maybeFile = n: c: if hasPrefix "/" c then c else pkgs.writeXML n c; + configFiles = name: cfg: mapAttrs (n: v: maybeFile "jenkins-${name}-${n}" v) cfg.config; + jobFiles = name: cfg: mapAttrs (n: v: maybeFile "jenkins-${name}-job-${n}.xml" v) cfg.jobs; + + keyrings = + let + # This requires read-write mode of evaluation: + keys = n: i: filter isKey (import (pkgs.xinclude2nix ( + (mapAttrsToList (_: f: f) (configFiles n i)) + ++ (mapAttrsToList (_: f: f) (jobFiles n i)) + ))); + ik = mapAttrsToList (n: i: { "${i.user}" = keys n i; } ) instances; + in foldAttrs (l: r: l ++ r) [] ik; + + mkService = name: cfg: + let + + mkOpt = n: v: if isBool v then (if v then "--${n}" else "") + else if isString v then "--${n}='${v}'" + else "--${n}=${toString v}"; + + path = ".war.path"; + + startJenkins = pkgs.writeBashScript "jenkins-${name}-start" '' + set -euo pipefail + umask 0027 + export HOME='${cfg.home}' + + cd '${cfg.home}' + + find -maxdepth 1 \( \ + -iname '*.xml' \ + -o -iname '*.bak' \ + -o -iname '*.log' \ + -o -iname '*.tmp' \ + -o -iname '*.txt' \ + \) -delete + + ${concatStringsSep "\n" ( + mapAttrsToList (n: p: + # XXX Jenkins does not support XInclude + # XXX We use XInclude to include secret files (keys) + '' + ${pkgs.libxml2}/bin/xmllint --xinclude --format '${p}' > '${n}' + '') (configFiles name cfg) + )} + + if [ -d jobs ]; then + find jobs -maxdepth 1 -mindepth 1 -type d \ + ${concatMapStringsSep " " (k: "-not -name '${escape [ "[" ] k}'") (attrNames cfg.jobs)} \ + -print0 | xargs -0 --verbose --no-run-if-empty rm -rf + fi + + ${concatStringsSep "\n" ( + mapAttrsToList (n: p: '' + mkdir -p -- 'jobs/${n}' + rm -rf -- 'jobs/${n}/config.xml' + ${pkgs.libxml2}/bin/xmllint --xinclude --format '${p}' > 'jobs/${n}/config.xml' + '') (jobFiles name cfg) + )} + + if [ -f ${path} ]; then + old=$(cat ${path}) + else + old= + fi + + # FIXME: make sure old content is flushed + if [ '${cfg.war}' != "$old" ]; then + rm -rf war plugins + echo '${cfg.war}' > ${path} + fi + + exec ${cfg.jre}/bin/java \ + -DJENKINS_HOME='${cfg.home}' \ + -jar '${cfg.war}' \ + ${concatStringsSep " \\\n " ( + mapAttrsToList mkOpt (explicit cfg.options))} + ''; + + in { + "jenkins-${name}" = { + description = "Jenkins (${name}) automation server"; + wantedBy = [ "multi-user.target" ]; + after = [ "keys.target" "network.target" "local-fs.target" ]; + inherit (cfg) path; + preStart = '' + mkdir -p -- '${cfg.home}' + + # XXX ignore potentially dangling symlinks + # XXX like lastStable -> builds/lastStableBuild. + # XXX chmod/chown fail on them + find '${cfg.home}' -not -type l \( \ + -not -user '${cfg.user}' \ + -or -not -group '${cfg.user}' \ + -or \( -type d -not -perm -u=wrx,g=rx \) \ + -or \( -type f -not -perm -u=rw,g=r \) \ + \) \ + -exec chown -c -- '${cfg.user}:${cfg.user}' {} + \ + -exec chmod -c -- u=rwX,g=rX,o= {} + + + ''; + serviceConfig = { + ExecStart = startJenkins; + KillMode = "mixed"; + PermissionsStartOnly = true; + Restart = "always"; + TimeoutSec = 0; + User = cfg.user; + }; + }; + }; + +in { + + options.nixsap.apps.jenkins = mkOption { + description = "Jenkins instances"; + default = {}; + type = attrsOf (submodule (import ./instance.nix pkgs)); + }; + + config = { + systemd.services = foldl (a: b: a//b) {} (mapAttrsToList mkService instances); + nixsap.deployment.keyrings = keyrings; + nixsap.system.users.daemons = users; + }; + +} |