From f66c1e4b43ddd7b75686120aa543ed70c61f7bdb Mon Sep 17 00:00:00 2001 From: Yorick van Pelt Date: Thu, 6 Sep 2018 14:02:55 +0200 Subject: [PATCH 01/28] services/buildkite-agent: update service for buildkite 3 --- .../buildkite-agent.nix | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/nixos/modules/services/continuous-integration/buildkite-agent.nix b/nixos/modules/services/continuous-integration/buildkite-agent.nix index 12cc3d2b1ccce..5b61f91520d53 100644 --- a/nixos/modules/services/continuous-integration/buildkite-agent.nix +++ b/nixos/modules/services/continuous-integration/buildkite-agent.nix @@ -93,6 +93,16 @@ in ''; }; + extraSetup = mkOption { + type = types.lines; + default = ""; + example = "touch /var/lib/buildkite-agent/test"; + description = '' + Extra commands to execute (as root) while setting up the buildkite dir and config. + The directory ownership will be fixed up afterwards. + ''; + }; + openssh = { privateKeyPath = mkOption { type = types.path; @@ -181,6 +191,14 @@ in instead. ''; }; + + shell = mkOption { + type = types.string; + default = "${pkgs.bash}/bin/bash -e -c"; + description = '' + Command that buildkite-agent 3 will execute when it spawns a shell. + ''; + }; }; }; @@ -203,10 +221,12 @@ in environment = config.networking.proxy.envVars // { HOME = cfg.dataDir; NIX_REMOTE = "daemon"; + BUILDKITE_SHELL = cfg.shell; }; ## NB: maximum care is taken so that secrets (ssh keys and the CI token) ## don't end up in the Nix store. + ## This preStart script runs as root preStart = let sshDir = "${cfg.dataDir}/.ssh"; in @@ -224,14 +244,21 @@ in hooks-path="${cfg.hooksPath}" ${cfg.extraConfig} EOF + ${cfg.extraSetup} + chown -R buildkite-agent ${cfg.dataDir} ''; serviceConfig = - { ExecStart = "${pkgs.buildkite-agent}/bin/buildkite-agent start --config /var/lib/buildkite-agent/buildkite-agent.cfg"; + { ExecStart = "${cfg.package}/bin/buildkite-agent start --config /var/lib/buildkite-agent/buildkite-agent.cfg"; User = "buildkite-agent"; RestartSec = 5; Restart = "on-failure"; TimeoutSec = 10; + # set a long timeout to give buildkite-agent a chance to finish current builds + TimeoutStopSec = "2 min"; + KillMode = "mixed"; + # run the preStart script as root + PermissionsStartOnly = true; }; }; From 1a517be7be8baf67dcc2170abc39ee4a9bc68e58 Mon Sep 17 00:00:00 2001 From: Yegor Timoshenko Date: Sat, 22 Sep 2018 11:58:45 +0000 Subject: [PATCH 02/28] buildkite-agent: make ssh key optional, remove public key option --- .../buildkite-agent.nix | 40 ++++++++----------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/nixos/modules/services/continuous-integration/buildkite-agent.nix b/nixos/modules/services/continuous-integration/buildkite-agent.nix index 5b61f91520d53..96369c73b5804 100644 --- a/nixos/modules/services/continuous-integration/buildkite-agent.nix +++ b/nixos/modules/services/continuous-integration/buildkite-agent.nix @@ -103,26 +103,16 @@ in ''; }; - openssh = - { privateKeyPath = mkOption { - type = types.path; - description = '' - Private agent key. - - A run-time path to the key file, which is supposed to be provisioned - outside of Nix store. - ''; - }; - publicKeyPath = mkOption { - type = types.path; - description = '' - Public agent key. + sshKeyPath = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + Private agent SSH key. - A run-time path to the key file, which is supposed to be provisioned - outside of Nix store. - ''; - }; - }; + A runtime path to the key file, which is supposed to be provisioned + outside of Nix store. + ''; + }; hooks = mkHookOptions [ { name = "checkout"; @@ -229,12 +219,14 @@ in ## This preStart script runs as root preStart = let sshDir = "${cfg.dataDir}/.ssh"; + sshKeyPath = toString cfg.sshKeyPath; in '' - mkdir -m 0700 -p "${sshDir}" - cp -f "${toString cfg.openssh.privateKeyPath}" "${sshDir}/id_rsa" - cp -f "${toString cfg.openssh.publicKeyPath}" "${sshDir}/id_rsa.pub" - chmod 600 "${sshDir}"/id_rsa* + ${optionalString (cfg.sshKeyPath != null) '' + mkdir -m 0700 -p "${sshDir}" + cp -f "${sshKeyPath}" "${sshDir}/id_rsa" + chmod 600 "${sshDir}"/id_rsa + ''} cat > "${cfg.dataDir}/buildkite-agent.cfg" < Date: Wed, 26 Sep 2018 19:57:32 +0200 Subject: [PATCH 03/28] buildkite-agent2: drop --- nixos/modules/module-list.nix | 2 +- .../buildkite-agent/2.x.nix | 12 ----- .../buildkite-agent/3.x.nix | 15 ------ .../buildkite-agent/default.nix | 48 +++++++++++++++++++ pkgs/top-level/all-packages.nix | 5 +- 5 files changed, 51 insertions(+), 31 deletions(-) delete mode 100644 pkgs/development/tools/continuous-integration/buildkite-agent/2.x.nix delete mode 100644 pkgs/development/tools/continuous-integration/buildkite-agent/3.x.nix create mode 100644 pkgs/development/tools/continuous-integration/buildkite-agent/default.nix diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index fb6bc8e1efe6c..2809ded7fad27 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -247,7 +247,7 @@ ./services/computing/slurm/slurm.nix ./services/continuous-integration/buildbot/master.nix ./services/continuous-integration/buildbot/worker.nix - ./services/continuous-integration/buildkite-agent.nix + ./services/continuous-integration/buildkite-agents.nix ./services/continuous-integration/hail.nix ./services/continuous-integration/hydra/default.nix ./services/continuous-integration/gitlab-runner.nix diff --git a/pkgs/development/tools/continuous-integration/buildkite-agent/2.x.nix b/pkgs/development/tools/continuous-integration/buildkite-agent/2.x.nix deleted file mode 100644 index 6a73e2581822e..0000000000000 --- a/pkgs/development/tools/continuous-integration/buildkite-agent/2.x.nix +++ /dev/null @@ -1,12 +0,0 @@ -{ callPackage, fetchFromGitHub, ... } @ args: - -callPackage ./generic.nix (args // rec { - src = fetchFromGitHub { - owner = "buildkite"; - repo = "agent"; - rev = "v${version}"; - sha256 = "07065hhhb418w5qlqnyiap45r59paysysbwz1l7dmaw3j4q8m8rg"; - }; - version = "2.6.10"; - hasBootstrapScript = true; -}) diff --git a/pkgs/development/tools/continuous-integration/buildkite-agent/3.x.nix b/pkgs/development/tools/continuous-integration/buildkite-agent/3.x.nix deleted file mode 100644 index e8266c2efe2cd..0000000000000 --- a/pkgs/development/tools/continuous-integration/buildkite-agent/3.x.nix +++ /dev/null @@ -1,15 +0,0 @@ -{ bash, callPackage, fetchFromGitHub, ... } @ args: - -callPackage ./generic.nix (args // rec { - src = fetchFromGitHub { - owner = "buildkite"; - repo = "agent"; - rev = "v${version}"; - sha256 = "0sr1rxl92d4wdipl66f1yymx5bmyj1y85v6k22v57rzr6yhyfmsf"; - }; - version = "3.8.4"; - hasBootstrapScript = false; - postPatch = '' - substituteInPlace bootstrap/shell/shell.go --replace /bin/bash ${bash}/bin/bash - ''; -}) diff --git a/pkgs/development/tools/continuous-integration/buildkite-agent/default.nix b/pkgs/development/tools/continuous-integration/buildkite-agent/default.nix new file mode 100644 index 0000000000000..98698712a4993 --- /dev/null +++ b/pkgs/development/tools/continuous-integration/buildkite-agent/default.nix @@ -0,0 +1,48 @@ +{ fetchFromGitHub, stdenv, buildGoPackage, + makeWrapper, coreutils, git, openssh, bash, gnused, gnugrep }: +buildGoPackage rec { + name = "buildkite-agent-${version}"; + version = "3.8.4"; + + goPackagePath = "github.com/buildkite/agent"; + + src = fetchFromGitHub { + owner = "buildkite"; + repo = "agent"; + rev = "v${version}"; + sha256 = "0sr1rxl92d4wdipl66f1yymx5bmyj1y85v6k22v57rzr6yhyfmsf"; + }; + postPatch = '' + substituteInPlace bootstrap/shell/shell.go --replace /bin/bash ${bash}/bin/bash + ''; + + nativeBuildInputs = [ makeWrapper ]; + + # on Linux, the TMPDIR is /build which is the same prefix as this package + # remove once #35068 is merged + noAuditTmpdir = stdenv.isLinux; + + postInstall = '' + # Fix binary name + mv $bin/bin/{agent,buildkite-agent} + + # These are runtime dependencies + wrapProgram $bin/bin/buildkite-agent \ + --prefix PATH : '${stdenv.lib.makeBinPath [ openssh git coreutils gnused gnugrep ]}' + ''; + + meta = with stdenv.lib; { + description = "Build runner for buildkite.com"; + longDescription = '' + The buildkite-agent is a small, reliable, and cross-platform build runner + that makes it easy to run automated builds on your own infrastructure. + It’s main responsibilities are polling buildkite.com for work, running + build jobs, reporting back the status code and output log of the job, + and uploading the job's artifacts. + ''; + homepage = https://buildkite.com/docs/agent; + license = licenses.mit; + maintainers = with maintainers; [ pawelpacana zimbatm rvl ]; + platforms = platforms.unix; + }; +} diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 4a15a88625631..d87dfa922b40f 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -9310,9 +9310,8 @@ in buck = callPackage ../development/tools/build-managers/buck { }; - buildkite-agent = buildkite-agent2; - buildkite-agent2 = callPackage ../development/tools/continuous-integration/buildkite-agent/2.x.nix { }; - buildkite-agent3 = callPackage ../development/tools/continuous-integration/buildkite-agent/3.x.nix { }; + buildkite-agent = buildkite-agent3; + buildkite-agent3 = callPackage ../development/tools/continuous-integration/buildkite-agent { }; libbpf = callPackage ../os-specific/linux/libbpf { }; From 2e74267fb5e74e49dee535d3a1af195ed21f5007 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20H=C3=B6ppner?= Date: Wed, 5 Sep 2018 21:09:47 +0100 Subject: [PATCH 04/28] buildkite-agent: change option meta-data into tags attrset --- nixos/modules/rename.nix | 2 ++ .../buildkite-agent.nix | 19 ++++++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix index df8ebe5058461..bd6f96bffc01c 100644 --- a/nixos/modules/rename.nix +++ b/nixos/modules/rename.nix @@ -276,6 +276,8 @@ with lib; # BLCR (mkRemovedOptionModule [ "environment.blcr.enable" ] "The BLCR module has been removed") + # Buildkite Agent + (mkRenamedOptionModule [ "services" "buildkite-agent" "meta-data"] [ "services" "buildkite-agent" "tags" ]) # Redis (mkRemovedOptionModule [ "services" "redis" "user" ] "The redis module now is hardcoded to the redis user.") diff --git a/nixos/modules/services/continuous-integration/buildkite-agent.nix b/nixos/modules/services/continuous-integration/buildkite-agent.nix index 96369c73b5804..2bbf9eea3987f 100644 --- a/nixos/modules/services/continuous-integration/buildkite-agent.nix +++ b/nixos/modules/services/continuous-integration/buildkite-agent.nix @@ -74,13 +74,17 @@ in ''; }; - meta-data = mkOption { - type = types.str; - default = ""; - example = "queue=default,docker=true,ruby2=true"; + tags = mkOption { + type = let + commasToAttrs = commas: builtins.foldl' + (prev: cur: let pair = builtins.split "=" cur; in + prev // {"${lib.head pair}" = lib.last pair; }) + {} (lib.remove [] (builtins.split "," commas)); in + types.coercedTo types.string commasToAttrs (types.attrsOf types.str); + default = {}; + example = { queue = "default"; docker = "true"; ruby2 ="true"; }; description = '' - Meta data for the agent. This is a comma-separated list of - key=value pairs. + Meta data for the agent. ''; }; @@ -220,6 +224,7 @@ in preStart = let sshDir = "${cfg.dataDir}/.ssh"; sshKeyPath = toString cfg.sshKeyPath; + tagStr = lib.concatStringsSep "," (lib.mapAttrsToList (name: value: "${name}=${value}") cfg.tags); in '' ${optionalString (cfg.sshKeyPath != null) '' @@ -231,7 +236,7 @@ in cat > "${cfg.dataDir}/buildkite-agent.cfg" < Date: Mon, 1 Oct 2018 20:24:29 +0200 Subject: [PATCH 05/28] nixos/buildkite-agents: add module, remove buildkite-agent module --- nixos/modules/rename.nix | 2 +- ...ildkite-agent.nix => buildkite-agents.nix} | 83 +++++++++++-------- 2 files changed, 50 insertions(+), 35 deletions(-) rename nixos/modules/services/continuous-integration/{buildkite-agent.nix => buildkite-agents.nix} (82%) diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix index bd6f96bffc01c..389a32024e295 100644 --- a/nixos/modules/rename.nix +++ b/nixos/modules/rename.nix @@ -277,7 +277,7 @@ with lib; # BLCR (mkRemovedOptionModule [ "environment.blcr.enable" ] "The BLCR module has been removed") # Buildkite Agent - (mkRenamedOptionModule [ "services" "buildkite-agent" "meta-data"] [ "services" "buildkite-agent" "tags" ]) + (mkRemovedOptionModule [ "services" "buildkite-agent"] "services.buildkite-agent has been moved to an attribute set at services.buildkite-agents") # Redis (mkRemovedOptionModule [ "services" "redis" "user" ] "The redis module now is hardcoded to the redis user.") diff --git a/nixos/modules/services/continuous-integration/buildkite-agent.nix b/nixos/modules/services/continuous-integration/buildkite-agents.nix similarity index 82% rename from nixos/modules/services/continuous-integration/buildkite-agent.nix rename to nixos/modules/services/continuous-integration/buildkite-agents.nix index 2bbf9eea3987f..d909eb8cb120d 100644 --- a/nixos/modules/services/continuous-integration/buildkite-agent.nix +++ b/nixos/modules/services/continuous-integration/buildkite-agents.nix @@ -3,7 +3,7 @@ with lib; let - cfg = config.services.buildkite-agent; + cfg = config.services.buildkite-agents; mkHookOption = { name, description, example ? null }: { inherit name; @@ -15,7 +15,7 @@ let }; mkHookOptions = hooks: listToAttrs (map mkHookOption hooks); - hooksDir = let + hooksDir = cfg: let mkHookEntry = name: value: '' cat > $out/${name} <<'EOF' #! ${pkgs.runtimeShell} @@ -29,12 +29,16 @@ let ${concatStringsSep "\n" (mapAttrsToList mkHookEntry (filterAttrs (n: v: v != null) cfg.hooks))} ''; -in - -{ - options = { - services.buildkite-agent = { - enable = mkEnableOption "buildkite-agent"; + buildkiteOptions = { name ? "", config, ... }: + let + fullName = if name == "" then "buildkite-agent" else "buildkite-agent-${name}"; + in + { options = { + enable = mkOption { + default = true; + type = types.bool; + description = "Whether to enable this buildkite agent"; + }; package = mkOption { default = pkgs.buildkite-agent; @@ -44,11 +48,17 @@ in }; dataDir = mkOption { - default = "/var/lib/buildkite-agent"; + default = "/var/lib/${fullName}"; description = "The workdir for the agent"; type = types.str; }; + fullName = mkOption { + readOnly = true; + default = fullName; + description = "Unit name of buildkite agent"; + }; + runtimePackages = mkOption { default = [ pkgs.bash pkgs.nix ]; defaultText = "[ pkgs.bash pkgs.nix ]"; @@ -68,7 +78,7 @@ in name = mkOption { type = types.str; - default = "%hostname-%n"; + default = "%hostname-${name}-%n"; description = '' The name of the agent. ''; @@ -82,7 +92,7 @@ in {} (lib.remove [] (builtins.split "," commas)); in types.coercedTo types.string commasToAttrs (types.attrsOf types.str); default = {}; - example = { queue = "default"; docker = "true"; ruby2 ="true"; }; + example = { queue = "default"; docker = "true"; ruby2 = "true"; }; description = '' Meta data for the agent. ''; @@ -100,7 +110,7 @@ in extraSetup = mkOption { type = types.lines; default = ""; - example = "touch /var/lib/buildkite-agent/test"; + example = "touch $HOME/test"; description = '' Extra commands to execute (as root) while setting up the buildkite dir and config. The directory ownership will be fixed up afterwards. @@ -177,7 +187,7 @@ in hooksPath = mkOption { type = types.path; - default = hooksDir; + default = hooksDir config; defaultText = "generated from services.buildkite-agent.hooks"; description = '' Path to the directory storing the hooks. @@ -193,25 +203,36 @@ in Command that buildkite-agent 3 will execute when it spawns a shell. ''; }; - }; + }; +}; + + enabledAgents = lib.filterAttrs (n: v: v.enable) cfg; + mapAgents = function: lib.mkMerge (lib.mapAttrsToList function enabledAgents); +in { + options.services.buildkite-agents = mkOption { + type = types.attrsOf (types.submodule buildkiteOptions); + default = {}; + description = '' + Attribute set of extra agents. + ''; }; - config = mkIf config.services.buildkite-agent.enable { - users.users.buildkite-agent = - { name = "buildkite-agent"; + config.users.users = mapAgents (name: cfg: { + "${cfg.fullName}" = + { name = cfg.fullName; home = cfg.dataDir; createHome = true; description = "Buildkite agent user"; extraGroups = [ "keys" ]; }; + }); - environment.systemPackages = [ cfg.package ]; - - systemd.services.buildkite-agent = + config.systemd.services = mapAgents (name: cfg: { + "${cfg.fullName}" = { description = "Buildkite Agent"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; - path = cfg.runtimePackages ++ [ pkgs.coreutils ]; + path = cfg.runtimePackages ++ [ cfg.package pkgs.coreutils ]; environment = config.networking.proxy.envVars // { HOME = cfg.dataDir; NIX_REMOTE = "daemon"; @@ -242,12 +263,12 @@ in ${cfg.extraConfig} EOF ${cfg.extraSetup} - chown -R buildkite-agent ${cfg.dataDir} + chown -R ${cfg.fullName} ${cfg.dataDir} ''; serviceConfig = - { ExecStart = "${cfg.package}/bin/buildkite-agent start --config /var/lib/buildkite-agent/buildkite-agent.cfg"; - User = "buildkite-agent"; + { ExecStart = "${cfg.package}/bin/buildkite-agent start --config ${cfg.dataDir}/buildkite-agent.cfg"; + User = cfg.fullName; RestartSec = 5; Restart = "on-failure"; TimeoutSec = 10; @@ -258,19 +279,13 @@ in PermissionsStartOnly = true; }; }; - - assertions = [ - { assertion = cfg.hooksPath == hooksDir || all (v: v == null) (attrValues cfg.hooks); + }); + config.assertions = mapAgents (name: cfg: [ + { assertion = cfg.hooksPath == hooksDir cfg || all isNull (attrValues cfg.hooks); message = '' Options `services.buildkite-agent.hooksPath' and `services.buildkite-agent.hooks.' are mutually exclusive. ''; } - ]; - }; - imports = [ - (mkRenamedOptionModule [ "services" "buildkite-agent" "token" ] [ "services" "buildkite-agent" "tokenPath" ]) - (mkRenamedOptionModule [ "services" "buildkite-agent" "openssh" "privateKey" ] [ "services" "buildkite-agent" "openssh" "privateKeyPath" ]) - (mkRenamedOptionModule [ "services" "buildkite-agent" "openssh" "privateKeyPath" ] [ "services" "buildkite-agent" "sshKeyPath" ]) - ]; + ]); } From da55b5c3d13aed47b2acb44c958f6711cb3bed5b Mon Sep 17 00:00:00 2001 From: Lars Jellema Date: Wed, 24 Jul 2019 17:06:00 +0200 Subject: [PATCH 06/28] buildkite-agents: Improve documentation --- .../continuous-integration/buildkite-agents.nix | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/nixos/modules/services/continuous-integration/buildkite-agents.nix b/nixos/modules/services/continuous-integration/buildkite-agents.nix index d909eb8cb120d..36a2f30e28f5c 100644 --- a/nixos/modules/services/continuous-integration/buildkite-agents.nix +++ b/nixos/modules/services/continuous-integration/buildkite-agents.nix @@ -56,7 +56,9 @@ let fullName = mkOption { readOnly = true; default = fullName; - description = "Unit name of buildkite agent"; + description = '' + Full name of the systemd service unit and of the user it runs as. + ''; }; runtimePackages = mkOption { @@ -80,7 +82,7 @@ let type = types.str; default = "%hostname-${name}-%n"; description = '' - The name of the agent. + The name of the agent as seen in the buildkite dashboard. ''; }; @@ -213,7 +215,11 @@ in { type = types.attrsOf (types.submodule buildkiteOptions); default = {}; description = '' - Attribute set of extra agents. + Attribute set of buildkite agents. + + The attribute key is combined with the hostname and a unique integer to + create the final agent name. This can be overridden by setting the `name` + attribute. ''; }; From 51d520dae7e6dc0c3065133cff6a78fa633131ca Mon Sep 17 00:00:00 2001 From: Florian Klink Date: Mon, 9 Sep 2019 10:55:52 -0700 Subject: [PATCH 07/28] nixos/buildkite-agents: remove PermissionsStartOnly, setup dataDir via StateDirectory --- .../buildkite-agents.nix | 54 +++++++++---------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/nixos/modules/services/continuous-integration/buildkite-agents.nix b/nixos/modules/services/continuous-integration/buildkite-agents.nix index 36a2f30e28f5c..4ab7b0d44fa84 100644 --- a/nixos/modules/services/continuous-integration/buildkite-agents.nix +++ b/nixos/modules/services/continuous-integration/buildkite-agents.nix @@ -30,9 +30,6 @@ let ''; buildkiteOptions = { name ? "", config, ... }: - let - fullName = if name == "" then "buildkite-agent" else "buildkite-agent-${name}"; - in { options = { enable = mkOption { default = true; @@ -47,17 +44,19 @@ let type = types.package; }; - dataDir = mkOption { - default = "/var/lib/${fullName}"; - description = "The workdir for the agent"; - type = types.str; + userName = mkOption { + readOnly = true; + default = name; + description = '' + Username of the systemd service this will run as. + ''; }; - fullName = mkOption { + statePath = mkOption { readOnly = true; - default = fullName; + default = "/var/lib/buildkite-${name}"; description = '' - Full name of the systemd service unit and of the user it runs as. + Absolute path to the buildkite-agent's state directory ''; }; @@ -114,7 +113,7 @@ let default = ""; example = "touch $HOME/test"; description = '' - Extra commands to execute (as root) while setting up the buildkite dir and config. + Extra commands to while setting up the buildkite dir and config. The directory ownership will be fixed up afterwards. ''; }; @@ -224,9 +223,8 @@ in { }; config.users.users = mapAgents (name: cfg: { - "${cfg.fullName}" = - { name = cfg.fullName; - home = cfg.dataDir; + "${cfg.userName}" = + { home = cfg.statePath; createHome = true; description = "Buildkite agent user"; extraGroups = [ "keys" ]; @@ -234,55 +232,53 @@ in { }); config.systemd.services = mapAgents (name: cfg: { - "${cfg.fullName}" = + "${name}" = { description = "Buildkite Agent"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; path = cfg.runtimePackages ++ [ cfg.package pkgs.coreutils ]; environment = config.networking.proxy.envVars // { - HOME = cfg.dataDir; + HOME = cfg.statePath; NIX_REMOTE = "daemon"; BUILDKITE_SHELL = cfg.shell; }; ## NB: maximum care is taken so that secrets (ssh keys and the CI token) - ## don't end up in the Nix store. - ## This preStart script runs as root + ## don't end up in the Nix store. preStart = let - sshDir = "${cfg.dataDir}/.ssh"; + sshDir = "${cfg.statePath}/.ssh"; sshKeyPath = toString cfg.sshKeyPath; - tagStr = lib.concatStringsSep "," (lib.mapAttrsToList (name: value: "${name}=${value}") cfg.tags); + tagStr = lib.concatStringsSep "," (lib.mapAttrsToList (k: v: "${k}=${v}") cfg.tags); in '' ${optionalString (cfg.sshKeyPath != null) '' - mkdir -m 0700 -p "${sshDir}" + mkdir -p "${sshDir}" + chmod 700 "${sshDir}" cp -f "${sshKeyPath}" "${sshDir}/id_rsa" - chmod 600 "${sshDir}"/id_rsa + chmod 600 "${sshDir}/id_rsa" ''} - cat > "${cfg.dataDir}/buildkite-agent.cfg" < "${cfg.statePath}/buildkite-agent.cfg" < Date: Mon, 9 Sep 2019 11:18:45 -0700 Subject: [PATCH 08/28] nixos/buildkite-agents: remove deprecated usage of types.string --- .../services/continuous-integration/buildkite-agents.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nixos/modules/services/continuous-integration/buildkite-agents.nix b/nixos/modules/services/continuous-integration/buildkite-agents.nix index 4ab7b0d44fa84..2aca4c8e2da52 100644 --- a/nixos/modules/services/continuous-integration/buildkite-agents.nix +++ b/nixos/modules/services/continuous-integration/buildkite-agents.nix @@ -91,7 +91,7 @@ let (prev: cur: let pair = builtins.split "=" cur; in prev // {"${lib.head pair}" = lib.last pair; }) {} (lib.remove [] (builtins.split "," commas)); in - types.coercedTo types.string commasToAttrs (types.attrsOf types.str); + types.coercedTo types.str commasToAttrs (types.attrsOf types.str); default = {}; example = { queue = "default"; docker = "true"; ruby2 = "true"; }; description = '' @@ -198,7 +198,7 @@ let }; shell = mkOption { - type = types.string; + type = types.str; default = "${pkgs.bash}/bin/bash -e -c"; description = '' Command that buildkite-agent 3 will execute when it spawns a shell. From 4d1d59dc5aab26040a86e2690ae88f06cfa4818a Mon Sep 17 00:00:00 2001 From: Florian Klink Date: Mon, 9 Sep 2019 13:19:00 -0700 Subject: [PATCH 09/28] nixos/buildkite-agents: fix documentation, defaultTexts --- .../services/continuous-integration/buildkite-agents.nix | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nixos/modules/services/continuous-integration/buildkite-agents.nix b/nixos/modules/services/continuous-integration/buildkite-agents.nix index 2aca4c8e2da52..9e5900462f3a3 100644 --- a/nixos/modules/services/continuous-integration/buildkite-agents.nix +++ b/nixos/modules/services/continuous-integration/buildkite-agents.nix @@ -189,10 +189,10 @@ let hooksPath = mkOption { type = types.path; default = hooksDir config; - defaultText = "generated from services.buildkite-agent.hooks"; + defaultText = "generated from services.buildkite-agents..hooks"; description = '' Path to the directory storing the hooks. - Consider using + Consider using instead. ''; }; @@ -285,8 +285,8 @@ in { config.assertions = mapAgents (name: cfg: [ { assertion = cfg.hooksPath == hooksDir cfg || all isNull (attrValues cfg.hooks); message = '' - Options `services.buildkite-agent.hooksPath' and - `services.buildkite-agent.hooks.' are mutually exclusive. + Options `services.buildkite-agents..hooksPath' and + `services.buildkite-agents..hooks.' are mutually exclusive. ''; } ]); From 944f5bb6f18145228f21d9201842671c6d51ced4 Mon Sep 17 00:00:00 2001 From: Florian Klink Date: Mon, 9 Sep 2019 20:09:57 -0700 Subject: [PATCH 10/28] nixos/buildkite-agents: remove legacy tag syntax The module has already changed significantly anyways. --- .../services/continuous-integration/buildkite-agents.nix | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/nixos/modules/services/continuous-integration/buildkite-agents.nix b/nixos/modules/services/continuous-integration/buildkite-agents.nix index 9e5900462f3a3..683f04e37a991 100644 --- a/nixos/modules/services/continuous-integration/buildkite-agents.nix +++ b/nixos/modules/services/continuous-integration/buildkite-agents.nix @@ -86,12 +86,7 @@ let }; tags = mkOption { - type = let - commasToAttrs = commas: builtins.foldl' - (prev: cur: let pair = builtins.split "=" cur; in - prev // {"${lib.head pair}" = lib.last pair; }) - {} (lib.remove [] (builtins.split "," commas)); in - types.coercedTo types.str commasToAttrs (types.attrsOf types.str); + type = (types.attrsOf types.str); default = {}; example = { queue = "default"; docker = "true"; ruby2 = "true"; }; description = '' From b728ad3daa67a38eb00f3c7dc8606170c6487555 Mon Sep 17 00:00:00 2001 From: Florian Klink Date: Mon, 9 Sep 2019 20:11:43 -0700 Subject: [PATCH 11/28] nixos/buildkite-agents: prefix buildkite- to usernames It would be weird for it to e.g. allocate a user named foo just because one uses foo as the attribute name. --- .../services/continuous-integration/buildkite-agents.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nixos/modules/services/continuous-integration/buildkite-agents.nix b/nixos/modules/services/continuous-integration/buildkite-agents.nix index 683f04e37a991..21d80395f8438 100644 --- a/nixos/modules/services/continuous-integration/buildkite-agents.nix +++ b/nixos/modules/services/continuous-integration/buildkite-agents.nix @@ -46,7 +46,7 @@ let userName = mkOption { readOnly = true; - default = name; + default = "buildkite-${name}"; description = '' Username of the systemd service this will run as. ''; @@ -273,7 +273,7 @@ in { # set a long timeout to give buildkite-agent a chance to finish current builds TimeoutStopSec = "2 min"; KillMode = "mixed"; - StateDirectory = "buildkite-${cfg.userName}"; + StateDirectory = cfg.userName; }; }; }); From aafcfbba7b0ccbcfe761bc4716309d01c29bc53e Mon Sep 17 00:00:00 2001 From: Florian Klink Date: Mon, 9 Sep 2019 20:14:26 -0700 Subject: [PATCH 12/28] nixos/buildkite-agents: move toString to apply attribute of sshKeyPath --- .../services/continuous-integration/buildkite-agents.nix | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nixos/modules/services/continuous-integration/buildkite-agents.nix b/nixos/modules/services/continuous-integration/buildkite-agents.nix index 21d80395f8438..50e68f430e7a1 100644 --- a/nixos/modules/services/continuous-integration/buildkite-agents.nix +++ b/nixos/modules/services/continuous-integration/buildkite-agents.nix @@ -115,6 +115,9 @@ let sshKeyPath = mkOption { type = types.nullOr types.path; + ## NB: maximum care is taken so that secrets (ssh keys and the CI token) + ## don't end up in the Nix store. + apply = final: if final == null then null else toString final; default = null; description = '' Private agent SSH key. @@ -238,18 +241,15 @@ in { BUILDKITE_SHELL = cfg.shell; }; - ## NB: maximum care is taken so that secrets (ssh keys and the CI token) - ## don't end up in the Nix store. preStart = let sshDir = "${cfg.statePath}/.ssh"; - sshKeyPath = toString cfg.sshKeyPath; tagStr = lib.concatStringsSep "," (lib.mapAttrsToList (k: v: "${k}=${v}") cfg.tags); in '' ${optionalString (cfg.sshKeyPath != null) '' mkdir -p "${sshDir}" chmod 700 "${sshDir}" - cp -f "${sshKeyPath}" "${sshDir}/id_rsa" + cp -f "${cfg.sshKeyPath}" "${sshDir}/id_rsa" chmod 600 "${sshDir}/id_rsa" ''} From 43b3420cec4efae9d9d2c8936eb2e5faf47dca14 Mon Sep 17 00:00:00 2001 From: Florian Klink Date: Mon, 9 Sep 2019 20:16:33 -0700 Subject: [PATCH 13/28] nixos/buildkite-agents: move mkRemovedOptionModule for old module to imports --- .../services/continuous-integration/buildkite-agents.nix | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/nixos/modules/services/continuous-integration/buildkite-agents.nix b/nixos/modules/services/continuous-integration/buildkite-agents.nix index 50e68f430e7a1..168e025d1e45d 100644 --- a/nixos/modules/services/continuous-integration/buildkite-agents.nix +++ b/nixos/modules/services/continuous-integration/buildkite-agents.nix @@ -29,7 +29,7 @@ let ${concatStringsSep "\n" (mapAttrsToList mkHookEntry (filterAttrs (n: v: v != null) cfg.hooks))} ''; - buildkiteOptions = { name ? "", config, ... }: + buildkiteOptions = { name ? "", config, ... }: { options = { enable = mkOption { default = true; @@ -208,6 +208,10 @@ let enabledAgents = lib.filterAttrs (n: v: v.enable) cfg; mapAgents = function: lib.mkMerge (lib.mapAttrsToList function enabledAgents); in { + imports = [ + (mkRemovedOptionModule [ "services" "buildkite-agent"] "services.buildkite-agent has been moved to an attribute set at services.buildkite-agents") + ]; + options.services.buildkite-agents = mkOption { type = types.attrsOf (types.submodule buildkiteOptions); default = {}; From 527b943af26cdd5153d77934363d1c2fb16b57a8 Mon Sep 17 00:00:00 2001 From: Florian Klink Date: Mon, 9 Sep 2019 20:17:32 -0700 Subject: [PATCH 14/28] buildkite-agent2: provide `throw` for removed attribute --- pkgs/top-level/all-packages.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index d87dfa922b40f..3f4e959c879aa 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -9311,6 +9311,7 @@ in buck = callPackage ../development/tools/build-managers/buck { }; buildkite-agent = buildkite-agent3; + buildkite-agent2 = throw "buildkite-agent2 is not supported anymore, use buildkite-agent instead"; buildkite-agent3 = callPackage ../development/tools/continuous-integration/buildkite-agent { }; libbpf = callPackage ../os-specific/linux/libbpf { }; From 0a51583d418b09fea1e7382d97acd056dc922106 Mon Sep 17 00:00:00 2001 From: Florian Klink Date: Mon, 9 Sep 2019 11:19:06 -0700 Subject: [PATCH 15/28] nixos/tests: add buildkite-agents test --- nixos/tests/all-tests.nix | 1 + nixos/tests/buildkite-agents.nix | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 nixos/tests/buildkite-agents.nix diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 5643da99e5570..433086c4712f2 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -35,6 +35,7 @@ in boot-stage1 = handleTest ./boot-stage1.nix {}; borgbackup = handleTest ./borgbackup.nix {}; buildbot = handleTest ./buildbot.nix {}; + buildkite-agents = handleTest ./buildkite-agents.nix {}; cadvisor = handleTestOn ["x86_64-linux"] ./cadvisor.nix {}; cassandra = handleTest ./cassandra.nix {}; ceph = handleTestOn ["x86_64-linux"] ./ceph.nix {}; diff --git a/nixos/tests/buildkite-agents.nix b/nixos/tests/buildkite-agents.nix new file mode 100644 index 0000000000000..83ed29cb68de3 --- /dev/null +++ b/nixos/tests/buildkite-agents.nix @@ -0,0 +1,28 @@ +import ./make-test.nix ({ lib, ... } : { + name = "buildkite-agents"; + meta = with lib.maintainers; { + maintainers = [ earvstedt ]; + }; + + machine = { pkgs, ... }: { + services.buildkite-agents = { + foo = { + extraConfig = "debug=true"; + hooks.environment = "export SECRET_VAR=`head -1 /run/keys/secret`"; + tokenPath = (pkgs.writeText "my-token" "1234"); + }; + bar = { + sshKeyPath = (import ./ssh-keys.nix pkgs).snakeOilPrivateKey; + tokenPath = (pkgs.writeText "my-token" "5678"); + }; + }; + }; + + testScript = '' + # we can't wait on the unit to start up, as we obviously can't connect to buildkite, + # but we can look whether files are set up correctly + $machine->waitForFile("/var/lib/buildkite-foo/buildkite-agent.cfg"); + $machine->waitForFile("/var/lib/buildkite-bar/buildkite-agent.cfg"); + $machine->waitForFile("/var/lib/buildkite-bar/.ssh/id_rsa"); + ''; +}) From c46bca9e3835a5b843070e82da2238aae40adf70 Mon Sep 17 00:00:00 2001 From: Yegor Timoshenko Date: Tue, 22 May 2018 20:46:29 +0300 Subject: [PATCH 16/28] nixos/nginx: make sslCertificate and sslCertificateKey nullable https://github.com/NixOS/nixpkgs/pull/40932 --- nixos/modules/services/web-servers/nginx/vhost-options.nix | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nixos/modules/services/web-servers/nginx/vhost-options.nix b/nixos/modules/services/web-servers/nginx/vhost-options.nix index 15b933c984a6d..3446650abee54 100644 --- a/nixos/modules/services/web-servers/nginx/vhost-options.nix +++ b/nixos/modules/services/web-servers/nginx/vhost-options.nix @@ -119,13 +119,15 @@ with lib; }; sslCertificate = mkOption { - type = types.path; + type = types.nullOr types.path; + default = null; example = "/var/host.cert"; description = "Path to server SSL certificate."; }; sslCertificateKey = mkOption { - type = types.path; + type = types.nullOr types.path; + default = null; example = "/var/host.key"; description = "Path to server SSL certificate key."; }; From 43ffdd6dada40f0147c6d6ad6e9d30e758874bd2 Mon Sep 17 00:00:00 2001 From: Yorick van Pelt Date: Thu, 10 Jan 2019 17:24:12 +0100 Subject: [PATCH 17/28] nixos/borgbackup: generate wrappers per job for easy borg access --- nixos/modules/services/backup/borgbackup.nix | 26 ++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/nixos/modules/services/backup/borgbackup.nix b/nixos/modules/services/backup/borgbackup.nix index 2ad116a7872ad..9b279319c6e52 100644 --- a/nixos/modules/services/backup/borgbackup.nix +++ b/nixos/modules/services/backup/borgbackup.nix @@ -98,6 +98,24 @@ let inherit (cfg) startAt; }; + # utility function around makeWrapper + mkWrapperDrv = { + original, name, set ? {}, setDefault ? {} + }: + pkgs.runCommandNoCC "${name}-wrapper" { + buildInputs = [ pkgs.makeWrapper ]; + } (with lib; '' + makeWrapper "${original}" "$out/bin/${name}" \ + ${concatStringsSep " \\\n " (mapAttrsToList (name: value: ''--set ${name} "${value}"'') set)} \ + ${concatStringsSep " \\\n " (mapAttrsToList (name: value: ''--set-default ${name} "${value}"'') setDefault)} + ''); + + mkBorgWrapper = name: cfg: mkWrapperDrv { + original = "${pkgs.borgbackup}/bin/borg"; + name = "borg-job-${name}"; + set = { BORG_REPO = cfg.repo; } // (mkPassEnv cfg) // cfg.environment; + }; + # Paths listed in ReadWritePaths must exist before service is started mkActivationScript = name: cfg: let @@ -169,7 +187,11 @@ in { ###### interface options.services.borgbackup.jobs = mkOption { - description = "Deduplicating backups using BorgBackup."; + description = '' + Deduplicating backups using BorgBackup. + Adding a job will cause a borg-job-NAME wrapper to be added + to your system path, so that you can perform maintenance easily. + ''; default = { }; example = literalExample '' { @@ -610,6 +632,6 @@ in { users = mkMerge (mapAttrsToList mkUsersConfig repos); - environment.systemPackages = with pkgs; [ borgbackup ]; + environment.systemPackages = with pkgs; [ borgbackup ] ++ (mapAttrsToList mkBorgWrapper jobs); }); } From b59a443c41c069706f8b27d91b588dfcd7fd034c Mon Sep 17 00:00:00 2001 From: Yorick van Pelt Date: Wed, 10 Jul 2019 18:41:56 +0200 Subject: [PATCH 18/28] nixos/alertmanager: add environmentFile, substituteAll for secrets --- .../monitoring/prometheus/alertmanager.nix | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/nixos/modules/services/monitoring/prometheus/alertmanager.nix b/nixos/modules/services/monitoring/prometheus/alertmanager.nix index 11d85e9c4fc3a..323a5d493dec0 100644 --- a/nixos/modules/services/monitoring/prometheus/alertmanager.nix +++ b/nixos/modules/services/monitoring/prometheus/alertmanager.nix @@ -18,7 +18,7 @@ let in checkedConfig yml; cmdlineArgs = cfg.extraFlags ++ [ - "--config.file ${alertmanagerYml}" + "--config.file /tmp/alert-manager-substituted.yaml" "--web.listen-address ${cfg.listenAddress}:${toString cfg.port}" "--log.level ${cfg.logLevel}" ] ++ (optional (cfg.webExternalUrl != null) @@ -118,6 +118,16 @@ in { Extra commandline options when launching the Alertmanager. ''; }; + + environmentFile = mkOption { + type = types.nullOr types.path; + default = null; + example = "/root/alertmanager.env"; + description = '' + File to load as environment file. Useful to insert secrets + into the configuration (via substituteAll). + ''; + }; }; }; @@ -135,9 +145,14 @@ in { systemd.services.alertmanager = { wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; + preStart = '' + (source ${pkgs.stdenv}/setup + substituteAll "${alertmanagerYml}" /tmp/alert-manager-substituted.yaml) + ''; serviceConfig = { Restart = "always"; DynamicUser = true; + EnvironmentFile = lib.mkIf (cfg.environmentFile != null) cfg.environmentFile; WorkingDirectory = "/tmp"; ExecStart = "${cfg.package}/bin/alertmanager" + optionalString (length cmdlineArgs != 0) (" \\\n " + From 57c1877419f1819af6456991b441a87658826af5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20H=C3=B6ppner?= Date: Tue, 9 Jul 2019 19:04:24 +0100 Subject: [PATCH 19/28] docker-containers.nix: Give containers more reasonable names --- nixos/modules/virtualisation/docker-containers.nix | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nixos/modules/virtualisation/docker-containers.nix b/nixos/modules/virtualisation/docker-containers.nix index 59b0943f591f1..7134cde7daade 100644 --- a/nixos/modules/virtualisation/docker-containers.nix +++ b/nixos/modules/virtualisation/docker-containers.nix @@ -172,7 +172,7 @@ let ExecStart = concatStringsSep " \\\n " ([ "${pkgs.docker}/bin/docker run" "--rm" - "--name=%n" + "--name=${name}" "--log-driver=${container.log-driver}" ] ++ optional (container.entrypoint != null) "--entrypoint=${escapeShellArg container.entrypoint}" @@ -185,9 +185,9 @@ let ++ [container.image] ++ map escapeShellArg container.cmd ); - ExecStartPre = "-${pkgs.docker}/bin/docker rm -f %n"; - ExecStop = "${pkgs.docker}/bin/docker stop %n"; - ExecStopPost = "-${pkgs.docker}/bin/docker rm -f %n"; + ExecStartPre = "-${pkgs.docker}/bin/docker rm -f ${name}"; + ExecStop = "${pkgs.docker}/bin/docker stop ${name}"; + ExecStopPost = "-${pkgs.docker}/bin/docker rm -f ${name}"; ### There is no generalized way of supporting `reload` for docker ### containers. Some containers may respond well to SIGHUP sent to their From 639092da4d4f4a9ec4ef1375490e1643efa1abda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20H=C3=B6ppner?= Date: Tue, 9 Jul 2019 19:04:45 +0100 Subject: [PATCH 20/28] docker.nix: Add options for named volumes and networks --- nixos/modules/virtualisation/docker.nix | 162 ++++++++++++++++++++++++ nixos/tests/docker.nix | 24 +++- 2 files changed, 184 insertions(+), 2 deletions(-) diff --git a/nixos/modules/virtualisation/docker.nix b/nixos/modules/virtualisation/docker.nix index 7d196a46276ac..d5e7296cd2e9d 100644 --- a/nixos/modules/virtualisation/docker.nix +++ b/nixos/modules/virtualisation/docker.nix @@ -9,6 +9,67 @@ let cfg = config.virtualisation.docker; proxy_env = config.networking.proxy.envVars; + inherit (builtins) attrNames; + + mkUncreateMaybe = networks: volumes: '' + set -euo pipefail + + nexisting=$(${pkgs.coreutils}/bin/mktemp) + nwanted=$(${pkgs.coreutils}/bin/mktemp) + vexisting=$(${pkgs.coreutils}/bin/mktemp) + vwanted=$(${pkgs.coreutils}/bin/mktemp) + + cleanup() { + rm -f "$nexisting" "$nwanted" "$vexisting" "$vwanted" + } + trap cleanup EXIT + + ${pkgs.docker}/bin/docker network ls --format '{{.Name}}' > "$nexisting" + echo -e "bridge\nhost\nnone\n${concatStringsSep "\n" networks}" > "$nwanted" + + ${pkgs.docker}/bin/docker volume ls --format '{{.Name}}' > "$vexisting" + echo -e "${concatStringsSep "\n" volumes}" > "$vwanted" + + nsuperfluous="$(${pkgs.gnugrep}/bin/grep -vxF -f $nwanted $nexisting || true)" + vsuperfluous="$(${pkgs.gnugrep}/bin/grep -vxF -f $vwanted $vexisting || true)" + + while read -r net; do + if [[ ! -z "$net" ]]; then + echo -n "Removed superfluous Docker network: " + ${pkgs.docker}/bin/docker network rm "$net" + fi + done <<< "$nsuperfluous" + + while read -r vol; do + if [[ ! -z "$vol" ]]; then + echo -n "Removed superfluous Docker volume: " + ${pkgs.docker}/bin/docker volume rm "$vol" + fi + done <<< "$vsuperfluous" + ''; + + mkNetworkOpts = opts: concatStringsSep " " + ([ "--driver=${opts.driver}" ] + ++ optional (cfg ? subnet && cfg.subnet != null) "--subnet=${opts.subnet}" + ++ optional (cfg ? ip-range && cfg.ip-range != null) "--ip-range=${opts.ip-range}" + ++ optional (cfg ? gateway && cfg.gateway != null) "--gateway=${opts.gateway}" + ++ optional (cfg ? ipv6 && cfg.ipv6) "--ipv6" + ++ optional (cfg ? internal && cfg.internal) "--internal"); + + + mkNetwork = name: opts: '' + if [[ $(${pkgs.docker}/bin/docker network ls --quiet --filter name=${name} | wc -c) -eq 0 ]]; then + echo "*** docker network create ${mkNetworkOpts opts} ${name}" + ${pkgs.docker}/bin/docker network create ${mkNetworkOpts opts} ${name} + fi + ''; + + mkVolume = name: '' + if [[ $(${pkgs.docker}/bin/docker volume ls --quiet --filter name=${name} | wc -c) -eq 0 ]]; then + echo "*** docker volume create ${name}" + ${pkgs.docker}/bin/docker volume create ${name} + fi + ''; in { @@ -93,6 +154,16 @@ in ''; }; + logLevel = + mkOption { + type = types.enum ["debug" "info" "warn" "error" "fatal"]; + default = "info"; + description = + '' + This option determines the log level for the Docker daemon. + ''; + }; + extraOptions = mkOption { type = types.separatedString " "; @@ -144,6 +215,90 @@ in Docker package to be used in the module. ''; }; + + volumes = mkOption { + default = []; + type = types.listOf types.str; + example = [ "volume_1" "volume_2" ]; + description = '' + A list of named volumes that should be created. + ''; + }; + + + networks = mkOption { + default = {}; + type = types.attrsOf (types.submodule { + options = { + driver = mkOption { + default = "bridge"; + type = types.str; + example = "overlay"; + description = '' + Driver to manage the network. One of bridge, or overlay. + ''; + }; + + subnet = mkOption { + default = null; + type = types.nullOr types.str; + example = "172.28.0.0/16"; + description = '' + Subnet in CIDR format that represents a network segment. + ''; + }; + + ip-range = mkOption { + default = null; + type = types.nullOr types.str; + example = "172.28.5.0/24"; + description = '' + Allocate container ip from a sub-range. + ''; + }; + + gateway = mkOption { + default = null; + type = types.nullOr types.str; + example = "172.28.5.254"; + description = '' + IPv4 or IPv6 Gateway for the master subnet. + ''; + }; + + ipv6 = mkOption { + default = false; + type = types.bool; + example = true; + description = '' + Enable IPv6 networking. + ''; + }; + + internal = mkOption { + default = false; + type = types.bool; + example = true; + description = '' + Restrict external access to the network. + ''; + }; + }; + }); + + example = { + my-network = { + driver = "bridge"; + subnet = "172.28.0.0/16"; + ip-range = "172.28.5.0/24"; + gateway = "172.28.5.254"; + }; + }; + + description = '' + A list of named networks to be created. + ''; + }; }; ###### implementation @@ -157,6 +312,11 @@ in systemd.services.docker = { wantedBy = optional cfg.enableOnBoot "multi-user.target"; environment = proxy_env; + + postStart = mkUncreateMaybe (attrNames cfg.networks) cfg.volumes + + concatStrings (mapAttrsToList mkNetwork cfg.networks) + + concatStrings (map mkVolume cfg.volumes); + serviceConfig = { ExecStart = [ "" @@ -165,11 +325,13 @@ in --group=docker \ --host=fd:// \ --log-driver=${cfg.logDriver} \ + --log-level=${cfg.logLevel} \ ${optionalString (cfg.storageDriver != null) "--storage-driver=${cfg.storageDriver}"} \ ${optionalString cfg.liveRestore "--live-restore" } \ ${optionalString cfg.enableNvidia "--add-runtime nvidia=${pkgs.nvidia-docker}/bin/nvidia-container-runtime" } \ ${cfg.extraOptions} '']; + ExecReload=[ "" "${pkgs.procps}/bin/kill -s HUP $MAINPID" diff --git a/nixos/tests/docker.nix b/nixos/tests/docker.nix index d67b2f8743d80..7932e4d177dcf 100644 --- a/nixos/tests/docker.nix +++ b/nixos/tests/docker.nix @@ -10,8 +10,19 @@ import ./make-test.nix ({ pkgs, ...} : { docker = { pkgs, ... }: { - virtualisation.docker.enable = true; - virtualisation.docker.package = pkgs.docker; + virtualisation.docker = { + enable = true; + package = pkgs.docker; + volumes = [ "thevolume" ]; + networks.thenetwork = { + driver = "bridge"; + subnet = "172.28.0.0/16"; + ip-range = "172.28.5.0/24"; + gateway = "172.28.5.254"; + }; + + logLevel = "warn"; + }; users.users = { noprivs = { @@ -41,6 +52,15 @@ import ./make-test.nix ({ pkgs, ...} : { $docker->fail("sudo -u noprivs docker ps"); $docker->succeed("docker stop sleeping"); + $docker->succeed("docker volume ls | grep thevolume"); + $docker->succeed("docker network ls | grep thenetwork"); + + $docker->succeed("docker volume create superfluousvolume"); + $docker->succeed("docker network create superfluousnetwork"); + $docker->systemctl("restart docker"); + $docker->waitForUnit("docker.service"); + $docker->fail("docker volume ls | grep superfluous"); + # Must match version twice to ensure client and server versions are correct $docker->succeed('[ $(docker version | grep ${pkgs.docker.version} | wc -l) = "2" ]'); ''; From 4c0b97d8808965154ae04671b1dcaad286906722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20H=C3=B6ppner?= Date: Thu, 11 Jul 2019 15:09:25 +0100 Subject: [PATCH 21/28] docker.nix: do not fail the unit if removing a volume fails --- nixos/modules/virtualisation/docker.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nixos/modules/virtualisation/docker.nix b/nixos/modules/virtualisation/docker.nix index d5e7296cd2e9d..5168ea501112f 100644 --- a/nixos/modules/virtualisation/docker.nix +++ b/nixos/modules/virtualisation/docker.nix @@ -36,14 +36,14 @@ let while read -r net; do if [[ ! -z "$net" ]]; then echo -n "Removed superfluous Docker network: " - ${pkgs.docker}/bin/docker network rm "$net" + ${pkgs.docker}/bin/docker network rm "$net" || true fi done <<< "$nsuperfluous" while read -r vol; do if [[ ! -z "$vol" ]]; then echo -n "Removed superfluous Docker volume: " - ${pkgs.docker}/bin/docker volume rm "$vol" + ${pkgs.docker}/bin/docker volume rm "$vol" || true fi done <<< "$vsuperfluous" ''; From 06c09b2967d32dc7adfec8f04f20e36ccb6aab29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20H=C3=B6ppner?= Date: Thu, 11 Jul 2019 20:33:17 +0100 Subject: [PATCH 22/28] docker-containers.nix: always pull explicitly before starting a container --- nixos/modules/virtualisation/docker-containers.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nixos/modules/virtualisation/docker-containers.nix b/nixos/modules/virtualisation/docker-containers.nix index 7134cde7daade..c4127ee94c9b2 100644 --- a/nixos/modules/virtualisation/docker-containers.nix +++ b/nixos/modules/virtualisation/docker-containers.nix @@ -185,7 +185,7 @@ let ++ [container.image] ++ map escapeShellArg container.cmd ); - ExecStartPre = "-${pkgs.docker}/bin/docker rm -f ${name}"; + ExecStartPre = [ "${pkgs.docker}/bin/docker pull ${container.image}" "-${pkgs.docker}/bin/docker rm -f ${name}" ]; ExecStop = "${pkgs.docker}/bin/docker stop ${name}"; ExecStopPost = "-${pkgs.docker}/bin/docker rm -f ${name}"; From f9db075ce5d64abd85c4f8a5bedfe546fe9bca93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20H=C3=B6ppner?= Date: Wed, 17 Jul 2019 17:10:09 +0100 Subject: [PATCH 23/28] Allow docker-containers to use image derivations directly --- .../virtualisation/docker-containers.nix | 36 ++++++++++++++++--- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/nixos/modules/virtualisation/docker-containers.nix b/nixos/modules/virtualisation/docker-containers.nix index c4127ee94c9b2..1e7616e92bc83 100644 --- a/nixos/modules/virtualisation/docker-containers.nix +++ b/nixos/modules/virtualisation/docker-containers.nix @@ -10,11 +10,21 @@ let options = { image = mkOption { - type = types.str; + type = with types; str; description = "Docker image to run."; example = "library/hello-world"; }; + imageFile = mkOption { + type = with types; nullOr package; + default = null; + description = '' + Path to an image file to load instead of pulling from a registry. + If defined, do not pull from registry. + ''; + example = literalExample "pkgs.dockerTools.buildDockerImage {...};"; + }; + cmd = mkOption { type = with types; listOf str; default = []; @@ -153,6 +163,13 @@ let example = "/var/lib/hello_world"; }; + containerDependencies = mkOption { + type = with types; listOf str; + default = []; + description = '' + ''; + }; + extraDockerOptions = mkOption { type = with types; listOf str; default = []; @@ -164,10 +181,13 @@ let }; }; - mkService = name: container: { + mkService = name: container: let + mkAfter = map (x: "docker-${x}.service") container.containerDependencies; + in { wantedBy = [ "multi-user.target" ]; - after = [ "docker.service" "docker.socket" ]; - requires = [ "docker.service" "docker.socket" ]; + after = [ "docker.service" "docker.socket" ] ++ mkAfter; + requires = [ "docker.service" "docker.socket" ] ++ mkAfter; + serviceConfig = { ExecStart = concatStringsSep " \\\n " ([ "${pkgs.docker}/bin/docker run" @@ -185,7 +205,13 @@ let ++ [container.image] ++ map escapeShellArg container.cmd ); - ExecStartPre = [ "${pkgs.docker}/bin/docker pull ${container.image}" "-${pkgs.docker}/bin/docker rm -f ${name}" ]; + + ExecStartPre = ["-${pkgs.docker}/bin/docker rm -f ${name}" + "-${pkgs.docker}/bin/docker image prune -f"] ++ + (if (container.imageFile != null) + then ["${pkgs.docker}/bin/docker load -i ${container.imageFile}"] + else ["${pkgs.docker}/bin/docker pull ${container.image}"]); + ExecStop = "${pkgs.docker}/bin/docker stop ${name}"; ExecStopPost = "-${pkgs.docker}/bin/docker rm -f ${name}"; From f9a5667931d5ca48dcbe3bebae55821847a34ba1 Mon Sep 17 00:00:00 2001 From: Yorick van Pelt Date: Fri, 11 Oct 2019 11:54:10 +0200 Subject: [PATCH 24/28] buildkite-agents: remove rename --- nixos/modules/rename.nix | 2 -- 1 file changed, 2 deletions(-) diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix index 389a32024e295..df8ebe5058461 100644 --- a/nixos/modules/rename.nix +++ b/nixos/modules/rename.nix @@ -276,8 +276,6 @@ with lib; # BLCR (mkRemovedOptionModule [ "environment.blcr.enable" ] "The BLCR module has been removed") - # Buildkite Agent - (mkRemovedOptionModule [ "services" "buildkite-agent"] "services.buildkite-agent has been moved to an attribute set at services.buildkite-agents") # Redis (mkRemovedOptionModule [ "services" "redis" "user" ] "The redis module now is hardcoded to the redis user.") From d1e358c44b5b0dde167798eee2d2843b60181742 Mon Sep 17 00:00:00 2001 From: Yorick van Pelt Date: Mon, 14 Oct 2019 07:34:28 +0200 Subject: [PATCH 25/28] substituteAll: separate into file instead of using from setup.sh --- .../monitoring/prometheus/alertmanager.nix | 2 +- .../substitute/substitute-all.nix | 1 + .../substitute/substitute-lib.sh | 120 ++++++++++++++++++ 3 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 pkgs/build-support/substitute/substitute-lib.sh diff --git a/nixos/modules/services/monitoring/prometheus/alertmanager.nix b/nixos/modules/services/monitoring/prometheus/alertmanager.nix index 323a5d493dec0..1e935ac5b4316 100644 --- a/nixos/modules/services/monitoring/prometheus/alertmanager.nix +++ b/nixos/modules/services/monitoring/prometheus/alertmanager.nix @@ -146,7 +146,7 @@ in { wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; preStart = '' - (source ${pkgs.stdenv}/setup + (source ${(pkgs.substituteAll {}).substitute-lib} substituteAll "${alertmanagerYml}" /tmp/alert-manager-substituted.yaml) ''; serviceConfig = { diff --git a/pkgs/build-support/substitute/substitute-all.nix b/pkgs/build-support/substitute/substitute-all.nix index 57b160bbe9014..2d4d394b5b022 100644 --- a/pkgs/build-support/substitute/substitute-all.nix +++ b/pkgs/build-support/substitute/substitute-all.nix @@ -7,6 +7,7 @@ stdenvNoCC.mkDerivation ({ name = if args ? name then args.name else baseNameOf (toString args.src); builder = ./substitute-all.sh; inherit (args) src; + passthru.substitute-lib = ./substitute-lib.sh; preferLocalBuild = true; allowSubstitutes = false; } // args) diff --git a/pkgs/build-support/substitute/substitute-lib.sh b/pkgs/build-support/substitute/substitute-lib.sh new file mode 100644 index 0000000000000..19e82fd3ffe4e --- /dev/null +++ b/pkgs/build-support/substitute/substitute-lib.sh @@ -0,0 +1,120 @@ +substituteStream() { + local var=$1 + local description=$2 + shift 2 + + while (( "$#" )); do + case "$1" in + --replace) + pattern="$2" + replacement="$3" + shift 3 + local savedvar + savedvar="${!var}" + eval "$var"'=${'"$var"'//"$pattern"/"$replacement"}' + if [ "$pattern" != "$replacement" ]; then + if [ "${!var}" == "$savedvar" ]; then + echo "substituteStream(): WARNING: pattern '$pattern' doesn't match anything in $description" >&2 + fi + fi + ;; + + --subst-var) + local varName="$2" + shift 2 + # check if the used nix attribute name is a valid bash name + if ! [[ "$varName" =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]]; then + echo "substituteStream(): ERROR: substitution variables must be valid Bash names, \"$varName\" isn't." >&2 + return 1 + fi + if [ -z ${!varName+x} ]; then + echo "substituteStream(): ERROR: variable \$$varName is unset" >&2 + return 1 + fi + pattern="@$varName@" + replacement="${!varName}" + eval "$var"'=${'"$var"'//"$pattern"/"$replacement"}' + ;; + + --subst-var-by) + pattern="@$2@" + replacement="$3" + eval "$var"'=${'"$var"'//"$pattern"/"$replacement"}' + shift 3 + ;; + + *) + echo "substituteStream(): ERROR: Invalid command line argument: $1" >&2 + return 1 + ;; + esac + done + + printf "%s" "${!var}" +} + +consumeEntire() { + # read returns non-0 on EOF, so we want read to fail + if IFS='' read -r -N 0 $1; then + echo "consumeEntire(): ERROR: Input null bytes, won't process" >&2 + return 1 + fi +} + +substitute() { + local input="$1" + local output="$2" + shift 2 + + if [ ! -f "$input" ]; then + echo "substitute(): ERROR: file '$input' does not exist" >&2 + return 1 + fi + + local content + consumeEntire content < "$input" + + if [ -e "$output" ]; then chmod +w "$output"; fi + substituteStream content "file '$input'" "$@" > "$output" +} + +substituteInPlace() { + local fileName="$1" + shift + substitute "$fileName" "$fileName" "$@" +} + +_allFlags() { + for varName in $(awk 'BEGIN { for (v in ENVIRON) if (v ~ /^[a-z][a-zA-Z0-9_]*$/) print v }'); do + if (( "${NIX_DEBUG:-0}" >= 1 )); then + printf "@%s@ -> %q\n" "${varName}" "${!varName}" + fi + args+=("--subst-var" "$varName") + done +} + +substituteAllStream() { + local -a args=() + _allFlags + + substituteStream "$1" "$2" "${args[@]}" +} + +# Substitute all environment variables that start with a lowercase character and +# are valid Bash names. +substituteAll() { + local input="$1" + local output="$2" + + local -a args=() + _allFlags + + substitute "$input" "$output" "${args[@]}" +} + + +substituteAllInPlace() { + local fileName="$1" + shift + substituteAll "$fileName" "$fileName" "$@" +} From c2ee33c843f43978d84adb4b3d1cb415937120c6 Mon Sep 17 00:00:00 2001 From: Yorick van Pelt Date: Mon, 14 Oct 2019 08:18:17 +0200 Subject: [PATCH 26/28] buildkite: fix names --- .../services/continuous-integration/buildkite-agents.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nixos/modules/services/continuous-integration/buildkite-agents.nix b/nixos/modules/services/continuous-integration/buildkite-agents.nix index 168e025d1e45d..9346aecb744fe 100644 --- a/nixos/modules/services/continuous-integration/buildkite-agents.nix +++ b/nixos/modules/services/continuous-integration/buildkite-agents.nix @@ -54,7 +54,7 @@ let statePath = mkOption { readOnly = true; - default = "/var/lib/buildkite-${name}"; + default = "/var/lib/buildkite-agent-${name}"; description = '' Absolute path to the buildkite-agent's state directory ''; @@ -234,7 +234,7 @@ in { }); config.systemd.services = mapAgents (name: cfg: { - "${name}" = + "buildkite-${name}" = { description = "Buildkite Agent"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; From a13e14fdbee2cbd8d887a825fdb0bd8494c8900f Mon Sep 17 00:00:00 2001 From: Yorick van Pelt Date: Mon, 14 Oct 2019 09:45:01 +0200 Subject: [PATCH 27/28] buildkite-agents: fix module --- .../continuous-integration/buildkite-agents.nix | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/nixos/modules/services/continuous-integration/buildkite-agents.nix b/nixos/modules/services/continuous-integration/buildkite-agents.nix index 9346aecb744fe..91b372d4efa3d 100644 --- a/nixos/modules/services/continuous-integration/buildkite-agents.nix +++ b/nixos/modules/services/continuous-integration/buildkite-agents.nix @@ -46,7 +46,7 @@ let userName = mkOption { readOnly = true; - default = "buildkite-${name}"; + default = "buildkite-agent-${name}"; description = '' Username of the systemd service this will run as. ''; @@ -245,11 +245,11 @@ in { BUILDKITE_SHELL = cfg.shell; }; - preStart = let + + serviceConfig = let sshDir = "${cfg.statePath}/.ssh"; tagStr = lib.concatStringsSep "," (lib.mapAttrsToList (k: v: "${k}=${v}") cfg.tags); - in - '' + preStart = '' ${optionalString (cfg.sshKeyPath != null) '' mkdir -p "${sshDir}" chmod 700 "${sshDir}" @@ -266,10 +266,10 @@ in { ${cfg.extraConfig} EOF ${cfg.extraSetup} - ''; - - serviceConfig = + chown -R $USER $HOME + ''; in { ExecStart = "${cfg.package}/bin/buildkite-agent start --config ${cfg.statePath}/buildkite-agent.cfg"; + ExecStartPre = "+${pkgs.writeShellScript "bk-agent-prestart" preStart}"; User = cfg.userName; RestartSec = 5; Restart = "on-failure"; From df37062ffef4c79ea166ca58c57f2d9c4ded1997 Mon Sep 17 00:00:00 2001 From: Kirill Elagin Date: Sat, 26 Oct 2019 10:31:44 +0200 Subject: [PATCH 28/28] nixfmt test --- pkgs/tools/misc/txr-copy/default.nix | 41 ++++++++++++++++++++++++++++ pkgs/top-level/all-packages.nix | 2 ++ 2 files changed, 43 insertions(+) create mode 100644 pkgs/tools/misc/txr-copy/default.nix diff --git a/pkgs/tools/misc/txr-copy/default.nix b/pkgs/tools/misc/txr-copy/default.nix new file mode 100644 index 0000000000000..3a41ddd2a7874 --- /dev/null +++ b/pkgs/tools/misc/txr-copy/default.nix @@ -0,0 +1,41 @@ +{ stdenv, fetchurl, bison, flex, libffi }: + +stdenv.mkDerivation rec { + pname = "txr"; + version = "225"; + + src = fetchurl { + url = "http://www.kylheku.com/cgit/txr/snapshot/${pname}-${version}.tar.bz2"; sha256 = "07vh0rmvjr2sir15l3ppp2pnp2d849dg17rzykkzqyk3d5rwfxyj"; + }; + + nativeBuildInputs = [ bison flex ]; + buildInputs = [ libffi ]; + + enableParallelBuilding = true; + + doCheck = true; + checkTarget = "tests"; + + # Remove failing test-- mentions 'usr/bin' so probably related :) + preCheck = "rm -rf tests/017"; + + postInstall = '' + d=$out/share/vim-plugins/txr + mkdir -p $d/{syntax,ftdetect} + + cp {tl,txr}.vim $d/syntax/ + + cat > $d/ftdetect/txr.vim <