From 9b79d5b298ead3bfdc14e32b179aec1b08434c10 Mon Sep 17 00:00:00 2001 From: Corey O'Connor Date: Mon, 10 Feb 2014 12:07:12 -0800 Subject: [PATCH 1/4] Add jenkins continuous integration server and user. By default the jenkins server is executed under the user "jenkins". Which can be configured using users.jenkins.* options. If a different user is requested by changing services.jenkins.user then none of the users.jenkins options apply. This patch does not include jenkins slave configuration. Some config options will probably change when this is implemented. Aspects like the user and environment are typically identical between slave and master. The service configs are different. The design is for users.jenkins to cover the shared aspects while services.jenkins and services.jenkins-slave cover the master and slave specific aspects, respectively. Another option would be to place everything under services.jenkins and have a config that selects master vs slave. --- nixos/modules/misc/ids.nix | 2 + nixos/modules/module-list.nix | 2 + .../jenkins/default.nix | 97 +++++++++++++++++++ .../continuous-integration/jenkins/user.nix | 61 ++++++++++++ nixos/tests/default.nix | 1 + nixos/tests/jenkins.nix | 14 +++ .../jenkins/default.nix | 18 ++++ pkgs/top-level/all-packages.nix | 2 + 8 files changed, 197 insertions(+) create mode 100644 nixos/modules/services/continuous-integration/jenkins/default.nix create mode 100644 nixos/modules/services/continuous-integration/jenkins/user.nix create mode 100644 nixos/tests/jenkins.nix create mode 100644 pkgs/development/tools/continuous-integration/jenkins/default.nix diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index ad344dfbc11..6b41c7c7c0e 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -117,6 +117,7 @@ couchdb = 106; searx = 107; kippo = 108; + jenkins = 109; # When adding a uid, make sure it doesn't match an existing gid. @@ -212,6 +213,7 @@ couchdb = 106; searx = 107; kippo = 108; + jenkins = 109; # When adding a gid, make sure it doesn't match an existing uid. diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 8a7d32adf34..f3d6bdb297d 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -81,6 +81,8 @@ ./services/backup/rsnapshot.nix ./services/backup/sitecopy-backup.nix ./services/backup/tarsnap.nix + ./services/continuous-integration/jenkins/default.nix + ./services/continuous-integration/jenkins/user.nix ./services/databases/4store-endpoint.nix ./services/databases/4store.nix ./services/databases/couchdb.nix diff --git a/nixos/modules/services/continuous-integration/jenkins/default.nix b/nixos/modules/services/continuous-integration/jenkins/default.nix new file mode 100644 index 00000000000..330dbab14e7 --- /dev/null +++ b/nixos/modules/services/continuous-integration/jenkins/default.nix @@ -0,0 +1,97 @@ +{ config, pkgs, ... }: +with pkgs.lib; +let + cfg = config.services.jenkins; + userCfg = config.users.jenkins; +in { + options = { + services.jenkins = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable the jenkins continuous integration server. + ''; + }; + + user = mkOption { + default = "jenkins"; + type = with types; string; + description = '' + User the jenkins server should execute under. Defaults to the "jenkins" user. + ''; + }; + + home = mkOption { + default = userCfg.home; + type = with types; string; + description = '' + The path to use as JENKINS_HOME. Defaults to the home of the "jenkins" user. + ''; + }; + + port = mkOption { + default = 8080; + type = types.uniq types.int; + description = '' + Specifies port number on which the jenkins HTTP interface listens. The default is 8080 + ''; + }; + + packages = mkOption { + default = [ pkgs.stdenv pkgs.git pkgs.jdk pkgs.openssh pkgs.nix ]; + type = types.listOf types.package; + description = '' + Packages to add to PATH for the jenkins process. + ''; + }; + + environment = mkOption { + default = { NIX_REMOTE = "daemon"; }; + type = with types; attrsOf string; + description = '' + Additional environment variables to be passed to the jenkins process. + The environment will always include JENKINS_HOME. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + users.jenkins.enable = true; + + systemd.services.jenkins = { + description = "jenkins continuous integration server"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + + environment = { + JENKINS_HOME = cfg.home; + } // cfg.environment; + + path = cfg.packages; + + script = '' + ${pkgs.jdk}/bin/java -jar ${pkgs.jenkins} --httpPort=${toString cfg.port} + ''; + + postStart = '' + until ${pkgs.curl}/bin/curl -L localhost:${toString cfg.port} ; do + sleep 10 + done + while true ; do + index=`${pkgs.curl}/bin/curl -L localhost:${toString cfg.port}` + if [[ !("$index" =~ 'Please wait while Jenkins is restarting' || + "$index" =~ 'Please wait while Jenkins is getting ready to work') ]]; then + exit 0 + fi + sleep 30 + done + ''; + + serviceConfig = { + User = cfg.user; + }; + }; + }; +} diff --git a/nixos/modules/services/continuous-integration/jenkins/user.nix b/nixos/modules/services/continuous-integration/jenkins/user.nix new file mode 100644 index 00000000000..cb4d9a60a4a --- /dev/null +++ b/nixos/modules/services/continuous-integration/jenkins/user.nix @@ -0,0 +1,61 @@ +{ config, pkgs, ... }: +with pkgs.lib; +let + cfg = config.users.jenkins; +in { + options = { + users.jenkins = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable the jenkins user. By default enabling a jenkins service enables the + jenkins user. The "user" config property of the service can be used to select a different + user. + ''; + }; + + extraGroups = mkOption { + default = []; + type = with types; listOf string; + description = '' + Extra groups of the "jenkins" user. + ''; + }; + + group = mkOption { + default = "jenkins"; + description = '' + Default group of "jenkins" user. + ''; + }; + + home = mkOption { + default = "/var/lib/jenkins"; + type = types.string; + description = '' + Home of the "jenkins" user and JENKINS_HOME. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + users.extraGroups = optional (cfg.group == "jenkins") { + name = "jenkins"; + gid = config.ids.gids.jenkins; + }; + + users.extraUsers = { + jenkins = { + description = "jenkins user"; + createHome = true; + home = cfg.home; + group = cfg.group; + extraGroups = cfg.extraGroups; + useDefaultShell = true; + uid = config.ids.uids.jenkins; + }; + }; + }; +} diff --git a/nixos/tests/default.nix b/nixos/tests/default.nix index b37a0d5fa0c..5b68862a2cd 100644 --- a/nixos/tests/default.nix +++ b/nixos/tests/default.nix @@ -14,6 +14,7 @@ with import ../lib/testing.nix { inherit system minimal; }; efi-installer = makeTests (import ./efi-installer.nix); gnome3 = makeTest (import ./gnome3.nix); ipv6 = makeTest (import ./ipv6.nix); + jenkins = makeTest (import ./jenkins.nix); kde4 = makeTest (import ./kde4.nix); #kexec = makeTest (import ./kexec.nix); login = makeTest (import ./login.nix {}); diff --git a/nixos/tests/jenkins.nix b/nixos/tests/jenkins.nix new file mode 100644 index 00000000000..b05a9d3eaf9 --- /dev/null +++ b/nixos/tests/jenkins.nix @@ -0,0 +1,14 @@ +{ pkgs, ... }: +{ + nodes = { + master = { pkgs, config, ... }: { + services.jenkins.enable = true; + }; + }; + + testScript = '' + startAll; + + $master->waitForUnit("jenkins"); + ''; +} diff --git a/pkgs/development/tools/continuous-integration/jenkins/default.nix b/pkgs/development/tools/continuous-integration/jenkins/default.nix new file mode 100644 index 00000000000..565693ddd79 --- /dev/null +++ b/pkgs/development/tools/continuous-integration/jenkins/default.nix @@ -0,0 +1,18 @@ +{ stdenv, fetchurl }: + +stdenv.mkDerivation rec { + name = "jenkins"; + version = "1.550"; + + src = fetchurl { + url = "http://mirrors.jenkins-ci.org/war/${version}/jenkins.war"; + sha256 = "1ziimbfs9kylga0xmxlfsfcc7qsirs5bnx00pa99m2l5sz2ki793"; + }; + meta = { + description = "An extendable open source continuous integration server."; + homepage = http://jenkins-ci.org; + maintainers = [ stdenv.lib.maintainers.coconnor ]; + }; + + buildCommand = "ln -s $src $out"; +} diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 4603179fafc..4bb7acfba1f 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -3686,6 +3686,8 @@ let jikespg = callPackage ../development/tools/parsing/jikespg { }; + jenkins = callPackage ../development/tools/continuous-integration/jenkins { }; + lcov = callPackage ../development/tools/analysis/lcov { }; leiningen = callPackage ../development/tools/build-managers/leiningen { }; From 292ece425e430a297eec2c3044f43e264f3b8dd3 Mon Sep 17 00:00:00 2001 From: Corey O'Connor Date: Tue, 25 Feb 2014 15:44:07 -0800 Subject: [PATCH 2/4] match systemd style and silent curl progress bar during startup check --- .../services/continuous-integration/jenkins/default.nix | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nixos/modules/services/continuous-integration/jenkins/default.nix b/nixos/modules/services/continuous-integration/jenkins/default.nix index 330dbab14e7..6e3f6abbb87 100644 --- a/nixos/modules/services/continuous-integration/jenkins/default.nix +++ b/nixos/modules/services/continuous-integration/jenkins/default.nix @@ -61,7 +61,7 @@ in { users.jenkins.enable = true; systemd.services.jenkins = { - description = "jenkins continuous integration server"; + description = "Jenkins Continuous Integration Server"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; @@ -76,11 +76,11 @@ in { ''; postStart = '' - until ${pkgs.curl}/bin/curl -L localhost:${toString cfg.port} ; do + until ${pkgs.curl}/bin/curl -s -L localhost:${toString cfg.port} ; do sleep 10 done while true ; do - index=`${pkgs.curl}/bin/curl -L localhost:${toString cfg.port}` + index=`${pkgs.curl}/bin/curl -s -L localhost:${toString cfg.port}` if [[ !("$index" =~ 'Please wait while Jenkins is restarting' || "$index" =~ 'Please wait while Jenkins is getting ready to work') ]]; then exit 0 From 4b6e67f6c43c49dd2cb950c152d22cf59b5364a6 Mon Sep 17 00:00:00 2001 From: Corey O'Connor Date: Thu, 27 Feb 2014 10:29:59 -0800 Subject: [PATCH 3/4] add platform and license to package metadata. --- .../tools/continuous-integration/jenkins/default.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkgs/development/tools/continuous-integration/jenkins/default.nix b/pkgs/development/tools/continuous-integration/jenkins/default.nix index 565693ddd79..5194684261c 100644 --- a/pkgs/development/tools/continuous-integration/jenkins/default.nix +++ b/pkgs/development/tools/continuous-integration/jenkins/default.nix @@ -11,6 +11,8 @@ stdenv.mkDerivation rec { meta = { description = "An extendable open source continuous integration server."; homepage = http://jenkins-ci.org; + license = stdenv.lib.licenses.mit; + platforms = stdenv.lib.platforms.all; maintainers = [ stdenv.lib.maintainers.coconnor ]; }; From 40de28afca0faa6673948bf99f444faad1d1a2d4 Mon Sep 17 00:00:00 2001 From: Corey O'Connor Date: Thu, 6 Mar 2014 10:06:53 -0800 Subject: [PATCH 4/4] remove users.jenkins config start on slave config. Uses standard NixOS user config merging. Work in progress: The slave config does not actually start the slave agent. This just configures a jenkins user if required. Bare minimum to enable a nice jenkins SSH slave. --- nixos/modules/module-list.nix | 2 +- .../jenkins/default.nix | 31 +++++++-- .../continuous-integration/jenkins/slave.nix | 67 +++++++++++++++++++ .../continuous-integration/jenkins/user.nix | 61 ----------------- nixos/tests/jenkins.nix | 21 ++++++ 5 files changed, 115 insertions(+), 67 deletions(-) create mode 100644 nixos/modules/services/continuous-integration/jenkins/slave.nix delete mode 100644 nixos/modules/services/continuous-integration/jenkins/user.nix diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index f3d6bdb297d..b419942057a 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -82,7 +82,7 @@ ./services/backup/sitecopy-backup.nix ./services/backup/tarsnap.nix ./services/continuous-integration/jenkins/default.nix - ./services/continuous-integration/jenkins/user.nix + ./services/continuous-integration/jenkins/slave.nix ./services/databases/4store-endpoint.nix ./services/databases/4store.nix ./services/databases/couchdb.nix diff --git a/nixos/modules/services/continuous-integration/jenkins/default.nix b/nixos/modules/services/continuous-integration/jenkins/default.nix index 6e3f6abbb87..c3dc59a9fbd 100644 --- a/nixos/modules/services/continuous-integration/jenkins/default.nix +++ b/nixos/modules/services/continuous-integration/jenkins/default.nix @@ -2,7 +2,6 @@ with pkgs.lib; let cfg = config.services.jenkins; - userCfg = config.users.jenkins; in { options = { services.jenkins = { @@ -18,15 +17,24 @@ in { default = "jenkins"; type = with types; string; description = '' - User the jenkins server should execute under. Defaults to the "jenkins" user. + User the jenkins server should execute under. + ''; + }; + + group = mkOption { + default = "jenkins"; + type = with types; string; + description = '' + User the jenkins server should execute under. ''; }; home = mkOption { - default = userCfg.home; + default = "/var/lib/jenkins"; type = with types; string; description = '' - The path to use as JENKINS_HOME. Defaults to the home of the "jenkins" user. + The path to use as JENKINS_HOME. If the default user "jenkins" is configured then + this is the home of the "jenkins" user. ''; }; @@ -58,7 +66,20 @@ in { }; config = mkIf cfg.enable { - users.jenkins.enable = true; + users.extraGroups = optional (cfg.group == "jenkins") { + name = "jenkins"; + gid = config.ids.gids.jenkins; + }; + + users.extraUsers = optional (cfg.user == "jenkins") { + name = "jenkins"; + description = "jenkins user"; + createHome = true; + home = cfg.home; + group = cfg.group; + useDefaultShell = true; + uid = config.ids.uids.jenkins; + }; systemd.services.jenkins = { description = "Jenkins Continuous Integration Server"; diff --git a/nixos/modules/services/continuous-integration/jenkins/slave.nix b/nixos/modules/services/continuous-integration/jenkins/slave.nix new file mode 100644 index 00000000000..1d31ab830f6 --- /dev/null +++ b/nixos/modules/services/continuous-integration/jenkins/slave.nix @@ -0,0 +1,67 @@ +{ config, pkgs, ... }: +with pkgs.lib; +let + cfg = config.services.jenkinsSlave; + masterCfg = config.services.jenkins; +in { + options = { + services.jenkinsSlave = { + # todo: + # * assure the profile of the jenkins user has a JRE and any specified packages. This would + # enable ssh slaves. + # * Optionally configure the node as a jenkins ad-hoc slave. This would imply configuration + # properties for the master node. + enable = mkOption { + type = types.bool; + default = false; + description = '' + If true the system will be configured to work as a jenkins slave. + If the system is also configured to work as a jenkins master then this has no effect. + In progress: Currently only assures the jenkins user is configured. + ''; + }; + + user = mkOption { + default = "jenkins"; + type = with types; string; + description = '' + User the jenkins slave agent should execute under. + ''; + }; + + group = mkOption { + default = "jenkins"; + type = with types; string; + description = '' + User the jenkins slave agent should execute under. + ''; + }; + + home = mkOption { + default = "/var/lib/jenkins"; + type = with types; string; + description = '' + The path to use as JENKINS_HOME. If the default user "jenkins" is configured then + this is the home of the "jenkins" user. + ''; + }; + }; + }; + + config = mkIf (cfg.enable && !masterCfg.enable) { + users.extraGroups = optional (cfg.group == "jenkins") { + name = "jenkins"; + gid = config.ids.gids.jenkins; + }; + + users.extraUsers = optional (cfg.user == "jenkins") { + name = "jenkins"; + description = "jenkins user"; + createHome = true; + home = cfg.home; + group = cfg.group; + useDefaultShell = true; + uid = config.ids.uids.jenkins; + }; + }; +} diff --git a/nixos/modules/services/continuous-integration/jenkins/user.nix b/nixos/modules/services/continuous-integration/jenkins/user.nix deleted file mode 100644 index cb4d9a60a4a..00000000000 --- a/nixos/modules/services/continuous-integration/jenkins/user.nix +++ /dev/null @@ -1,61 +0,0 @@ -{ config, pkgs, ... }: -with pkgs.lib; -let - cfg = config.users.jenkins; -in { - options = { - users.jenkins = { - enable = mkOption { - type = types.bool; - default = false; - description = '' - Whether to enable the jenkins user. By default enabling a jenkins service enables the - jenkins user. The "user" config property of the service can be used to select a different - user. - ''; - }; - - extraGroups = mkOption { - default = []; - type = with types; listOf string; - description = '' - Extra groups of the "jenkins" user. - ''; - }; - - group = mkOption { - default = "jenkins"; - description = '' - Default group of "jenkins" user. - ''; - }; - - home = mkOption { - default = "/var/lib/jenkins"; - type = types.string; - description = '' - Home of the "jenkins" user and JENKINS_HOME. - ''; - }; - }; - }; - - config = mkIf cfg.enable { - users.extraGroups = optional (cfg.group == "jenkins") { - name = "jenkins"; - gid = config.ids.gids.jenkins; - }; - - users.extraUsers = { - jenkins = { - description = "jenkins user"; - createHome = true; - home = cfg.home; - group = cfg.group; - extraGroups = cfg.extraGroups; - useDefaultShell = true; - uid = config.ids.uids.jenkins; - }; - }; - }; -} diff --git a/nixos/tests/jenkins.nix b/nixos/tests/jenkins.nix index b05a9d3eaf9..e6524ec5653 100644 --- a/nixos/tests/jenkins.nix +++ b/nixos/tests/jenkins.nix @@ -1,8 +1,22 @@ +# verifies: +# 1. jenkins service starts on master node +# 2. jenkins user can be extended on both master and slave +# 3. jenkins service not started on slave node { pkgs, ... }: { nodes = { master = { pkgs, config, ... }: { services.jenkins.enable = true; + + # should have no effect + services.jenkinsSlave.enable = true; + + users.extraUsers.jenkins.extraGroups = [ "users" ]; + }; + slave = { pkgs, config, ... }: { + services.jenkinsSlave.enable = true; + + users.extraUsers.jenkins.extraGroups = [ "users" ]; }; }; @@ -10,5 +24,12 @@ startAll; $master->waitForUnit("jenkins"); + print $master->execute("sudo -u jenkins groups"); + $master->mustSucceed("sudo -u jenkins groups | grep jenkins | grep users"); + + print $slave->execute("sudo -u jenkins groups"); + $slave->mustSucceed("sudo -u jenkins groups | grep jenkins | grep users"); + + $slave->mustFail("systemctl status jenkins.service"); ''; }