about summary refs log tree commit diff
path: root/nixos/modules/services/continuous-integration
diff options
context:
space:
mode:
authorSandro <sandro.jaeckel@gmail.com>2023-07-17 21:46:12 +0200
committerGitHub <noreply@github.com>2023-07-17 21:46:12 +0200
commit61dfd95022a48fc2b8518bcdbf1a96503b07da94 (patch)
tree4e18eacda1abb2119c54d6e2dda50fcb7afcab05 /nixos/modules/services/continuous-integration
parenta6aae555e2ae851ccf86c2b18df693258b0a35de (diff)
parent75f419f222d5458a8a946dd137f7657b57ec4776 (diff)
downloadnixlib-61dfd95022a48fc2b8518bcdbf1a96503b07da94.tar
nixlib-61dfd95022a48fc2b8518bcdbf1a96503b07da94.tar.gz
nixlib-61dfd95022a48fc2b8518bcdbf1a96503b07da94.tar.bz2
nixlib-61dfd95022a48fc2b8518bcdbf1a96503b07da94.tar.lz
nixlib-61dfd95022a48fc2b8518bcdbf1a96503b07da94.tar.xz
nixlib-61dfd95022a48fc2b8518bcdbf1a96503b07da94.tar.zst
nixlib-61dfd95022a48fc2b8518bcdbf1a96503b07da94.zip
Merge pull request #236778 from awakesecurity/jsoo1/buildkite-agent-hooks
nixos/buildkite-agents: simplify service definition
Diffstat (limited to 'nixos/modules/services/continuous-integration')
-rw-r--r--nixos/modules/services/continuous-integration/buildkite-agents.nix261
1 files changed, 100 insertions, 161 deletions
diff --git a/nixos/modules/services/continuous-integration/buildkite-agents.nix b/nixos/modules/services/continuous-integration/buildkite-agents.nix
index a40b939a16c7..a35ca4168074 100644
--- a/nixos/modules/services/continuous-integration/buildkite-agents.nix
+++ b/nixos/modules/services/continuous-integration/buildkite-agents.nix
@@ -1,64 +1,49 @@
 { config, lib, pkgs, ... }:
 
-with lib;
-
 let
   cfg = config.services.buildkite-agents;
 
-  mkHookOption = { name, description, example ? null }: {
-    inherit name;
-    value = mkOption {
-      default = null;
-      description = lib.mdDoc description;
-      type = types.nullOr types.lines;
-    } // (lib.optionalAttrs (example != null) { inherit example; });
-  };
-  mkHookOptions = hooks: listToAttrs (map mkHookOption hooks);
-
-  hooksDir = cfg: let
-    mkHookEntry = name: value: ''
-      cat > $out/${name} <<'EOF'
-      #! ${pkgs.runtimeShell}
-      set -e
-      ${value}
-      EOF
-      chmod 755 $out/${name}
+  hooksDir = hooks:
+    let
+      mkHookEntry = name: text: ''
+        ln --symbolic ${pkgs.writeShellApplication { inherit name text; }}/bin/${name} $out/${name}
+      '';
+    in
+    pkgs.runCommandLocal "buildkite-agent-hooks" { } ''
+      mkdir $out
+      ${lib.concatStringsSep "\n" (lib.mapAttrsToList mkHookEntry hooks)}
     '';
-  in pkgs.runCommand "buildkite-agent-hooks" { preferLocalBuild = true; } ''
-    mkdir $out
-    ${concatStringsSep "\n" (mapAttrsToList mkHookEntry (filterAttrs (n: v: v != null) cfg.hooks))}
-  '';
 
   buildkiteOptions = { name ? "", config, ... }: {
     options = {
-      enable = mkOption {
+      enable = lib.mkOption {
         default = true;
-        type = types.bool;
+        type = lib.types.bool;
         description = lib.mdDoc "Whether to enable this buildkite agent";
       };
 
-      package = mkOption {
+      package = lib.mkOption {
         default = pkgs.buildkite-agent;
-        defaultText = literalExpression "pkgs.buildkite-agent";
+        defaultText = lib.literalExpression "pkgs.buildkite-agent";
         description = lib.mdDoc "Which buildkite-agent derivation to use";
-        type = types.package;
+        type = lib.types.package;
       };
 
-      dataDir = mkOption {
+      dataDir = lib.mkOption {
         default = "/var/lib/buildkite-agent-${name}";
         description = lib.mdDoc "The workdir for the agent";
-        type = types.str;
+        type = lib.types.str;
       };
 
-      runtimePackages = mkOption {
+      runtimePackages = lib.mkOption {
         default = [ pkgs.bash pkgs.gnutar pkgs.gzip pkgs.git pkgs.nix ];
-        defaultText = literalExpression "[ pkgs.bash pkgs.gnutar pkgs.gzip pkgs.git pkgs.nix ]";
+        defaultText = lib.literalExpression "[ pkgs.bash pkgs.gnutar pkgs.gzip pkgs.git pkgs.nix ]";
         description = lib.mdDoc "Add programs to the buildkite-agent environment";
-        type = types.listOf types.package;
+        type = lib.types.listOf lib.types.package;
       };
 
-      tokenPath = mkOption {
-        type = types.path;
+      tokenPath = lib.mkOption {
+        type = lib.types.path;
         description = lib.mdDoc ''
           The token from your Buildkite "Agents" page.
 
@@ -67,25 +52,25 @@ let
         '';
       };
 
-      name = mkOption {
-        type = types.str;
+      name = lib.mkOption {
+        type = lib.types.str;
         default = "%hostname-${name}-%n";
         description = lib.mdDoc ''
           The name of the agent as seen in the buildkite dashboard.
         '';
       };
 
-      tags = mkOption {
-        type = types.attrsOf (types.either types.str (types.listOf types.str));
-        default = {};
-        example = { queue = "default"; docker = "true"; ruby2 ="true"; };
+      tags = lib.mkOption {
+        type = lib.types.attrsOf (lib.types.either lib.types.str (lib.types.listOf lib.types.str));
+        default = { };
+        example = { queue = "default"; docker = "true"; ruby2 = "true"; };
         description = lib.mdDoc ''
           Tags for the agent.
         '';
       };
 
-      extraConfig = mkOption {
-        type = types.lines;
+      extraConfig = lib.mkOption {
+        type = lib.types.lines;
         default = "";
         example = "debug=true";
         description = lib.mdDoc ''
@@ -93,8 +78,8 @@ let
         '';
       };
 
-      privateSshKeyPath = mkOption {
-        type = types.nullOr types.path;
+      privateSshKeyPath = lib.mkOption {
+        type = lib.types.nullOr lib.types.path;
         default = null;
         ## maximum care is taken so that secrets (ssh keys and the CI token)
         ## don't end up in the Nix store.
@@ -108,67 +93,25 @@ let
         '';
       };
 
-      hooks = mkHookOptions [
-        { name = "checkout";
-          description = ''
-            The `checkout` hook script will replace the default checkout routine of the
-            bootstrap.sh script. You can use this hook to do your own SCM checkout
-            behaviour
-          ''; }
-        { name = "command";
-          description = ''
-            The `command` hook script will replace the default implementation of running
-            the build command.
-          ''; }
-        { name = "environment";
-          description = ''
-            The `environment` hook will run before all other commands, and can be used
-            to set up secrets, data, etc. Anything exported in hooks will be available
-            to the build script.
-
-            Note: the contents of this file will be copied to the world-readable
-            Nix store.
-          '';
-          example = ''
-            export SECRET_VAR=`head -1 /run/keys/secret`
-          ''; }
-        { name = "post-artifact";
-          description = ''
-            The `post-artifact` hook will run just after artifacts are uploaded
-          ''; }
-        { name = "post-checkout";
-          description = ''
-            The `post-checkout` hook will run after the bootstrap script has checked out
-            your projects source code.
-          ''; }
-        { name = "post-command";
-          description = ''
-            The `post-command` hook will run after the bootstrap script has run your
-            build commands
-          ''; }
-        { name = "pre-artifact";
-          description = ''
-            The `pre-artifact` hook will run just before artifacts are uploaded
-          ''; }
-        { name = "pre-checkout";
-          description = ''
-            The `pre-checkout` hook will run just before your projects source code is
-            checked out from your SCM provider
-          ''; }
-        { name = "pre-command";
-          description = ''
-            The `pre-command` hook will run just before your build command runs
-          ''; }
-        { name = "pre-exit";
-          description = ''
-            The `pre-exit` hook will run just before your build job finishes
-          ''; }
-      ];
+      hooks = lib.mkOption {
+        type = lib.types.attrsOf lib.types.lines;
+        default = { };
+        example = lib.literalExpression ''
+          {
+            environment = '''
+              export SECRET_VAR=`head -1 /run/keys/secret`
+            ''';
+          }'';
+        description = lib.mdDoc ''
+          "Agent" hooks to install.
+          See <https://buildkite.com/docs/agent/v3/hooks> for possible options.
+        '';
+      };
 
-      hooksPath = mkOption {
-        type = types.path;
-        default = hooksDir config;
-        defaultText = literalMD "generated from {option}`services.buildkite-agents.<name>.hooks`";
+      hooksPath = lib.mkOption {
+        type = lib.types.path;
+        default = hooksDir config.hooks;
+        defaultText = lib.literalMD "generated from {option}`services.buildkite-agents.<name>.hooks`";
         description = lib.mdDoc ''
           Path to the directory storing the hooks.
           Consider using {option}`services.buildkite-agents.<name>.hooks.<name>`
@@ -176,10 +119,10 @@ let
         '';
       };
 
-      shell = mkOption {
-        type = types.str;
+      shell = lib.mkOption {
+        type = lib.types.str;
         default = "${pkgs.bash}/bin/bash -e -c";
-        defaultText = literalExpression ''"''${pkgs.bash}/bin/bash -e -c"'';
+        defaultText = lib.literalExpression ''"''${pkgs.bash}/bin/bash -e -c"'';
         description = lib.mdDoc ''
           Command that buildkite-agent 3 will execute when it spawns a shell.
         '';
@@ -190,9 +133,9 @@ let
   mapAgents = function: lib.mkMerge (lib.mapAttrsToList function enabledAgents);
 in
 {
-  options.services.buildkite-agents = mkOption {
-    type = types.attrsOf (types.submodule buildkiteOptions);
-    default = {};
+  options.services.buildkite-agents = lib.mkOption {
+    type = lib.types.attrsOf (lib.types.submodule buildkiteOptions);
+    default = { };
     description = lib.mdDoc ''
       Attribute set of buildkite agents.
       The attribute key is combined with the hostname and a unique integer to
@@ -213,23 +156,24 @@ in
     };
   });
   config.users.groups = mapAgents (name: cfg: {
-    "buildkite-agent-${name}" = {};
+    "buildkite-agent-${name}" = { };
   });
 
   config.systemd.services = mapAgents (name: cfg: {
-    "buildkite-agent-${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;
-          NIX_REMOTE = "daemon";
-        };
+    "buildkite-agent-${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;
+        NIX_REMOTE = "daemon";
+      };
 
-        ## NB: maximum care is taken so that secrets (ssh keys and the CI token)
-        ##     don't end up in the Nix store.
-        preStart = let
+      ## 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.dataDir}/.ssh";
           tagStr = name: value:
             if lib.isList value
@@ -237,44 +181,39 @@ in
             else "${name}=${value}";
           tagsStr = lib.concatStringsSep "," (lib.mapAttrsToList tagStr cfg.tags);
         in
-          optionalString (cfg.privateSshKeyPath != null) ''
-            mkdir -m 0700 -p "${sshDir}"
-            install -m600 "${toString cfg.privateSshKeyPath}" "${sshDir}/id_rsa"
-          '' + ''
-            cat > "${cfg.dataDir}/buildkite-agent.cfg" <<EOF
-            token="$(cat ${toString cfg.tokenPath})"
-            name="${cfg.name}"
-            shell="${cfg.shell}"
-            tags="${tagsStr}"
-            build-path="${cfg.dataDir}/builds"
-            hooks-path="${cfg.hooksPath}"
-            ${cfg.extraConfig}
-            EOF
-          '';
+        lib.optionalString (cfg.privateSshKeyPath != null) ''
+          mkdir -m 0700 -p "${sshDir}"
+          install -m600 "${toString cfg.privateSshKeyPath}" "${sshDir}/id_rsa"
+        '' + ''
+          cat > "${cfg.dataDir}/buildkite-agent.cfg" <<EOF
+          token="$(cat ${toString cfg.tokenPath})"
+          name="${cfg.name}"
+          shell="${cfg.shell}"
+          tags="${tagsStr}"
+          build-path="${cfg.dataDir}/builds"
+          hooks-path="${cfg.hooksPath}"
+          ${cfg.extraConfig}
+          EOF
+        '';
 
-        serviceConfig =
-          { ExecStart = "${cfg.package}/bin/buildkite-agent start --config ${cfg.dataDir}/buildkite-agent.cfg";
-            User = "buildkite-agent-${name}";
-            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";
-          };
+      serviceConfig = {
+        ExecStart = "${cfg.package}/bin/buildkite-agent start --config ${cfg.dataDir}/buildkite-agent.cfg";
+        User = "buildkite-agent-${name}";
+        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";
       };
+    };
   });
 
-  config.assertions = mapAgents (name: cfg: [
-      { assertion = cfg.hooksPath == (hooksDir cfg) || all (v: v == null) (attrValues cfg.hooks);
-        message = ''
-          Options `services.buildkite-agents.${name}.hooksPath' and
-          `services.buildkite-agents.${name}.hooks.<name>' are mutually exclusive.
-        '';
-      }
-  ]);
-
-  imports = [
-    (mkRemovedOptionModule [ "services" "buildkite-agent"] "services.buildkite-agent has been upgraded from version 2 to version 3 and moved to an attribute set at services.buildkite-agents. Please consult the 20.03 release notes for more information.")
-  ];
+  config.assertions = mapAgents (name: cfg: [{
+    assertion = cfg.hooksPath != hooksDir cfg.hooks -> cfg.hooks == { };
+    message = ''
+      Options `services.buildkite-agents.${name}.hooksPath' and
+      `services.buildkite-agents.${name}.hooks.<name>' are mutually exclusive.
+    '';
+  }]);
 }