summary refs log tree commit diff
path: root/nixos/modules/services/continuous-integration/gitlab-runner.nix
blob: bd4cf6a37bad8e853e55f123ae047b6b2ada8244 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
{ config, lib, pkgs, ... }:

with lib;

let
  cfg = config.services.gitlab-runner;
  configFile =
    if (cfg.configFile == null) then
      (pkgs.runCommand "config.toml" {
        buildInputs = [ pkgs.remarshal ];
        preferLocalBuild = true;
      } ''
        remarshal -if json -of toml \
          < ${pkgs.writeText "config.json" (builtins.toJSON cfg.configOptions)} \
          > $out
      '')
    else
      cfg.configFile;
  hasDocker = config.virtualisation.docker.enable;
in
{
  options.services.gitlab-runner = {
    enable = mkEnableOption "Gitlab Runner";

    configFile = mkOption {
      default = null;
      description = ''
        Configuration file for gitlab-runner.
        Use this option in favor of configOptions to avoid placing CI tokens in the nix store.

        <option>configFile</option> takes precedence over <option>configOptions</option>.

        Warning: Not using <option>configFile</option> will potentially result in secrets
        leaking into the WORLD-READABLE nix store.
      '';
      type = types.nullOr types.path;
    };

    configOptions = mkOption {
      description = ''
        Configuration for gitlab-runner
        <option>configFile</option> will take precedence over this option.

        Warning: all Configuration, especially CI token, will be stored in a
        WORLD-READABLE file in the Nix Store.

        If you want to protect your CI token use <option>configFile</option> instead.
      '';
      type = types.attrs;
      example = {
        concurrent = 2;
        runners = [{
          name = "docker-nix-1.11";
          url = "https://CI/";
          token = "TOKEN";
          executor = "docker";
          builds_dir = "";
          docker = {
            host = "";
            image = "nixos/nix:1.11";
            privileged = true;
            disable_cache = true;
            cache_dir = "";
          };
        }];
      };
    };

    gracefulTermination = mkOption {
      default = false;
      type = types.bool;
      description = ''
        Finish all remaining jobs before stopping, restarting or reconfiguring.
        If not set gitlab-runner will stop immediatly without waiting for jobs to finish,
        which will lead to failed builds.
      '';
    };

    gracefulTimeout = mkOption {
      default = "infinity";
      type = types.str;
      example = "5min 20s";
      description = ''Time to wait until a graceful shutdown is turned into a forceful one.'';
    };

    workDir = mkOption {
      default = "/var/lib/gitlab-runner";
      type = types.path;
      description = "The working directory used";
    };

    package = mkOption {
      description = "Gitlab Runner package to use";
      default = pkgs.gitlab-runner;
      defaultText = "pkgs.gitlab-runner";
      type = types.package;
      example = literalExample "pkgs.gitlab-runner_1_11";
    };

    packages = mkOption {
      default = [ pkgs.bash pkgs.docker-machine ];
      defaultText = "[ pkgs.bash pkgs.docker-machine ]";
      type = types.listOf types.package;
      description = ''
        Packages to add to PATH for the gitlab-runner process.
      '';
    };

  };

  config = mkIf cfg.enable {
    systemd.services.gitlab-runner = {
      path = cfg.packages;
      environment = config.networking.proxy.envVars // {
        # Gitlab runner will not start if the HOME variable is not set
        HOME = cfg.workDir;
      };
      description = "Gitlab Runner";
      after = [ "network.target" ]
        ++ optional hasDocker "docker.service";
      requires = optional hasDocker "docker.service";
      wantedBy = [ "multi-user.target" ];
      reloadIfChanged = true;
      restartTriggers = [
         config.environment.etc."gitlab-runner/config.toml".source
      ];
      serviceConfig = {
        StateDirectory = "gitlab-runner";
        ExecReload= "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
        ExecStart = ''${cfg.package.bin}/bin/gitlab-runner run \
          --working-directory ${cfg.workDir} \
          --config /etc/gitlab-runner/config.toml \
          --service gitlab-runner \
          --user gitlab-runner \
        '';

      } //  optionalAttrs (cfg.gracefulTermination) {
        TimeoutStopSec = "${cfg.gracefulTimeout}";
        KillSignal = "SIGQUIT";
        KillMode = "process";
      };
    };

    # Make the gitlab-runner command availabe so users can query the runner
    environment.systemPackages = [ cfg.package ];

    # Make sure the config can be reloaded on change
    environment.etc."gitlab-runner/config.toml".source = configFile;

    users.users.gitlab-runner = {
      group = "gitlab-runner";
      extraGroups = optional hasDocker "docker";
      uid = config.ids.uids.gitlab-runner;
      home = cfg.workDir;
      createHome = true;
    };

    users.groups.gitlab-runner.gid = config.ids.gids.gitlab-runner;
  };
}