at 25.11-pre 34 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7 8let 9 inherit (builtins) 10 hashString 11 map 12 substring 13 toJSON 14 toString 15 unsafeDiscardStringContext 16 ; 17 18 inherit (lib) 19 any 20 assertMsg 21 attrValues 22 concatStringsSep 23 escapeShellArg 24 filterAttrs 25 hasPrefix 26 isStorePath 27 literalExpression 28 mapAttrs' 29 mapAttrsToList 30 mkDefault 31 mkEnableOption 32 mkIf 33 mkOption 34 mkPackageOption 35 mkRemovedOptionModule 36 mkRenamedOptionModule 37 nameValuePair 38 optional 39 optionalAttrs 40 optionals 41 teams 42 toShellVar 43 types 44 ; 45 46 cfg = config.services.gitlab-runner; 47 hasDocker = config.virtualisation.docker.enable; 48 hasPodman = config.virtualisation.podman.enable && config.virtualisation.podman.dockerSocket.enable; 49 50 /* 51 The whole logic of this module is to diff the hashes of the desired vs existing runners 52 The hash is recorded in the runner's name because we can't do better yet 53 See https://gitlab.com/gitlab-org/gitlab-runner/-/issues/29350 for more details 54 */ 55 genRunnerName = 56 name: service: 57 let 58 hash = substring 0 12 (hashString "md5" (unsafeDiscardStringContext (toJSON service))); 59 in 60 if service ? description && service.description != null then 61 "${hash} ${service.description}" 62 else 63 "${name}_${config.networking.hostName}_${hash}"; 64 65 hashedServices = mapAttrs' ( 66 name: service: nameValuePair (genRunnerName name service) service 67 ) cfg.services; 68 configPath = ''"$HOME"/.gitlab-runner/config.toml''; 69 configureScript = pkgs.writeShellApplication { 70 name = "gitlab-runner-configure"; 71 runtimeInputs = 72 [ cfg.package ] 73 ++ (with pkgs; [ 74 bash 75 gawk 76 jq 77 moreutils 78 remarshal 79 util-linux 80 perl 81 python3 82 ]); 83 text = 84 if (cfg.configFile != null) then 85 '' 86 cp ${cfg.configFile} ${configPath} 87 # make config file readable by service 88 chown -R --reference="$HOME" "$(dirname ${configPath})" 89 '' 90 else 91 '' 92 export CONFIG_FILE=${configPath} 93 94 mkdir -p "$(dirname ${configPath})" 95 touch ${configPath} 96 97 # update global options 98 remarshal --if toml --of json --stringify ${configPath} \ 99 | jq -cM 'with_entries(select([.key] | inside(["runners"])))' \ 100 | jq -scM '.[0] + .[1]' - <(echo ${escapeShellArg (toJSON cfg.settings)}) \ 101 | remarshal --if json --of toml \ 102 | sponge ${configPath} 103 104 # remove no longer existing services 105 gitlab-runner verify --delete 106 107 ${toShellVar "NEEDED_SERVICES" (lib.mapAttrs (name: value: 1) hashedServices)} 108 109 declare -A REGISTERED_SERVICES 110 111 while IFS="," read -r name token; 112 do 113 REGISTERED_SERVICES["$name"]="$token" 114 done < <(gitlab-runner --log-format json list 2>&1 | grep Token | jq -r '.msg +"," + .Token') 115 116 echo "NEEDED_SERVICES: " "''${!NEEDED_SERVICES[@]}" 117 echo "REGISTERED_SERVICES:" "''${!REGISTERED_SERVICES[@]}" 118 119 # difference between current and desired state 120 declare -A NEW_SERVICES 121 for name in "''${!NEEDED_SERVICES[@]}"; do 122 if [ ! -v 'REGISTERED_SERVICES[$name]' ]; then 123 NEW_SERVICES[$name]=1 124 fi 125 done 126 127 declare -A OLD_SERVICES 128 # shellcheck disable=SC2034 129 for name in "''${!REGISTERED_SERVICES[@]}"; do 130 if [ ! -v 'NEEDED_SERVICES[$name]' ]; then 131 OLD_SERVICES[$name]=1 132 fi 133 done 134 135 # register new services 136 ${concatStringsSep "\n" ( 137 mapAttrsToList (name: service: '' 138 # TODO so here we should mention NEW_SERVICES 139 if [ -v 'NEW_SERVICES["${name}"]' ] ; then 140 bash -c ${ 141 escapeShellArg ( 142 concatStringsSep " \\\n " ( 143 [ 144 "set -a && source ${ 145 if service.registrationConfigFile != null then 146 service.registrationConfigFile 147 else 148 service.authenticationTokenConfigFile 149 } &&" 150 "gitlab-runner register" 151 "--non-interactive" 152 "--name '${name}'" 153 "--executor ${service.executor}" 154 "--limit ${toString service.limit}" 155 "--request-concurrency ${toString service.requestConcurrency}" 156 ] 157 ++ optional ( 158 service.authenticationTokenConfigFile == null 159 ) "--maximum-timeout ${toString service.maximumTimeout}" 160 ++ service.registrationFlags 161 ++ optional (service.buildsDir != null) "--builds-dir ${service.buildsDir}" 162 ++ optional (service.cloneUrl != null) "--clone-url ${service.cloneUrl}" 163 ++ optional ( 164 service.preGetSourcesScript != null 165 ) "--pre-get-sources-script ${service.preGetSourcesScript}" 166 ++ optional ( 167 service.postGetSourcesScript != null 168 ) "--post-get-sources-script ${service.postGetSourcesScript}" 169 ++ optional (service.preBuildScript != null) "--pre-build-script ${service.preBuildScript}" 170 ++ optional (service.postBuildScript != null) "--post-build-script ${service.postBuildScript}" 171 ++ optional ( 172 service.authenticationTokenConfigFile == null && service.tagList != [ ] 173 ) "--tag-list ${concatStringsSep "," service.tagList}" 174 ++ optional (service.authenticationTokenConfigFile == null && service.runUntagged) "--run-untagged" 175 ++ optional ( 176 service.authenticationTokenConfigFile == null && service.protected 177 ) "--access-level ref_protected" 178 ++ optional service.debugTraceDisabled "--debug-trace-disabled" 179 ++ map (e: "--env ${escapeShellArg e}") ( 180 mapAttrsToList (name: value: "${name}=${value}") service.environmentVariables 181 ) 182 ++ optionals (hasPrefix "docker" service.executor) ( 183 assert ( 184 assertMsg ( 185 service.dockerImage != null 186 ) "dockerImage option is required for ${service.executor} executor (${name})" 187 ); 188 [ "--docker-image ${service.dockerImage}" ] 189 ++ optional service.dockerDisableCache "--docker-disable-cache" 190 ++ optional service.dockerPrivileged "--docker-privileged" 191 ++ optional (service.dockerPullPolicy != null) "--docker-pull-policy ${service.dockerPullPolicy}" 192 ++ map (v: "--docker-volumes ${escapeShellArg v}") service.dockerVolumes 193 ++ map (v: "--docker-extra-hosts ${escapeShellArg v}") service.dockerExtraHosts 194 ++ map (v: "--docker-allowed-images ${escapeShellArg v}") service.dockerAllowedImages 195 ++ map (v: "--docker-allowed-services ${escapeShellArg v}") service.dockerAllowedServices 196 ) 197 ) 198 ) 199 } && sleep 1 || exit 1 200 fi 201 '') hashedServices 202 )} 203 204 # check key is in array https://stackoverflow.com/questions/30353951/how-to-check-if-dictionary-contains-a-key-in-bash 205 206 echo "NEW_SERVICES: ''${NEW_SERVICES[*]}" 207 echo "OLD_SERVICES: ''${OLD_SERVICES[*]}" 208 # unregister old services 209 for NAME in "''${!OLD_SERVICES[@]}" 210 do 211 [ -n "$NAME" ] && gitlab-runner unregister \ 212 --name "$NAME" && sleep 1 213 done 214 215 # make config file readable by service 216 chown -R --reference="$HOME" "$(dirname ${configPath})" 217 ''; 218 }; 219 startScript = pkgs.writeShellScriptBin "gitlab-runner-start" '' 220 export CONFIG_FILE=${configPath} 221 exec gitlab-runner run --working-directory $HOME 222 ''; 223in 224{ 225 options.services.gitlab-runner = { 226 enable = mkEnableOption "Gitlab Runner"; 227 configFile = mkOption { 228 type = types.nullOr types.path; 229 default = null; 230 description = '' 231 Configuration file for gitlab-runner. 232 233 {option}`configFile` takes precedence over {option}`services`. 234 {option}`checkInterval` and {option}`concurrent` will be ignored too. 235 236 This option is deprecated, please use {option}`services` instead. 237 You can use {option}`registrationConfigFile` and 238 {option}`registrationFlags` 239 for settings not covered by this module. 240 ''; 241 }; 242 settings = mkOption { 243 type = types.submodule { 244 freeformType = (pkgs.formats.json { }).type; 245 }; 246 default = { }; 247 description = '' 248 Global gitlab-runner configuration. See 249 <https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-global-section> 250 for supported values. 251 ''; 252 }; 253 gracefulTermination = mkOption { 254 type = types.bool; 255 default = false; 256 description = '' 257 Finish all remaining jobs before stopping. 258 If not set gitlab-runner will stop immediately without waiting 259 for jobs to finish, which will lead to failed builds. 260 ''; 261 }; 262 gracefulTimeout = mkOption { 263 type = types.str; 264 default = "infinity"; 265 example = "5min 20s"; 266 description = '' 267 Time to wait until a graceful shutdown is turned into a forceful one. 268 ''; 269 }; 270 package = mkPackageOption pkgs "gitlab-runner" { 271 example = "gitlab-runner_1_11"; 272 }; 273 extraPackages = mkOption { 274 type = types.listOf types.package; 275 default = [ ]; 276 description = '' 277 Extra packages to add to PATH for the gitlab-runner process. 278 ''; 279 }; 280 services = mkOption { 281 description = "GitLab Runner services."; 282 default = { }; 283 example = literalExpression '' 284 { 285 # runner for building in docker via host's nix-daemon 286 # nix store will be readable in runner, might be insecure 287 nix = { 288 # File should contain at least these two variables: 289 # - `CI_SERVER_URL` 290 # - `REGISTRATION_TOKEN` 291 # 292 # NOTE: Support for runner registration tokens will be removed in GitLab 18.0. 293 # Please migrate to runner authentication tokens soon. For reference, the example 294 # runners below this one are configured with authentication tokens instead. 295 registrationConfigFile = "/run/secrets/gitlab-runner-registration"; 296 297 dockerImage = "alpine"; 298 dockerVolumes = [ 299 "/nix/store:/nix/store:ro" 300 "/nix/var/nix/db:/nix/var/nix/db:ro" 301 "/nix/var/nix/daemon-socket:/nix/var/nix/daemon-socket:ro" 302 ]; 303 dockerDisableCache = true; 304 preBuildScript = pkgs.writeScript "setup-container" ''' 305 mkdir -p -m 0755 /nix/var/log/nix/drvs 306 mkdir -p -m 0755 /nix/var/nix/gcroots 307 mkdir -p -m 0755 /nix/var/nix/profiles 308 mkdir -p -m 0755 /nix/var/nix/temproots 309 mkdir -p -m 0755 /nix/var/nix/userpool 310 mkdir -p -m 1777 /nix/var/nix/gcroots/per-user 311 mkdir -p -m 1777 /nix/var/nix/profiles/per-user 312 mkdir -p -m 0755 /nix/var/nix/profiles/per-user/root 313 mkdir -p -m 0700 "$HOME/.nix-defexpr" 314 315 . ''${pkgs.nix}/etc/profile.d/nix.sh 316 317 ''${pkgs.nix}/bin/nix-env -i ''${concatStringsSep " " (with pkgs; [ nix cacert git openssh ])} 318 319 ''${pkgs.nix}/bin/nix-channel --add https://nixos.org/channels/nixpkgs-unstable 320 ''${pkgs.nix}/bin/nix-channel --update nixpkgs 321 '''; 322 environmentVariables = { 323 ENV = "/etc/profile"; 324 USER = "root"; 325 NIX_REMOTE = "daemon"; 326 PATH = "/nix/var/nix/profiles/default/bin:/nix/var/nix/profiles/default/sbin:/bin:/sbin:/usr/bin:/usr/sbin"; 327 NIX_SSL_CERT_FILE = "/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt"; 328 }; 329 tagList = [ "nix" ]; 330 }; 331 # runner for building docker images 332 docker-images = { 333 # File should contain at least these two variables: 334 # `CI_SERVER_URL` 335 # `CI_SERVER_TOKEN` 336 authenticationTokenConfigFile = "/run/secrets/gitlab-runner-docker-images-token-env"; 337 338 dockerImage = "docker:stable"; 339 dockerVolumes = [ 340 "/var/run/docker.sock:/var/run/docker.sock" 341 ]; 342 tagList = [ "docker-images" ]; 343 }; 344 # runner for executing stuff on host system (very insecure!) 345 # make sure to add required packages (including git!) 346 # to `environment.systemPackages` 347 shell = { 348 # File should contain at least these two variables: 349 # `CI_SERVER_URL` 350 # `CI_SERVER_TOKEN` 351 authenticationTokenConfigFile = "/run/secrets/gitlab-runner-shell-token-env"; 352 353 executor = "shell"; 354 tagList = [ "shell" ]; 355 }; 356 # runner for everything else 357 default = { 358 # File should contain at least these two variables: 359 # `CI_SERVER_URL` 360 # `CI_SERVER_TOKEN` 361 authenticationTokenConfigFile = "/run/secrets/gitlab-runner-default-token-env"; 362 dockerImage = "debian:stable"; 363 }; 364 } 365 ''; 366 type = types.attrsOf ( 367 types.submodule { 368 options = { 369 authenticationTokenConfigFile = mkOption { 370 type = with types; nullOr path; 371 default = null; 372 description = '' 373 Absolute path to a file containing environment variables used for 374 gitlab-runner registrations with *runner authentication tokens*. 375 They replace the deprecated *runner registration tokens*, as 376 outlined in the [GitLab documentation]. 377 378 A list of all supported environment variables can be found with 379 `gitlab-runner register --help`. 380 381 The ones you probably want to set are: 382 - `CI_SERVER_URL=<CI server URL>` 383 - `CI_SERVER_TOKEN=<runner authentication token secret>` 384 385 ::: {.warning} 386 Make sure to use a quoted absolute path, 387 or it is going to be copied to Nix Store. 388 ::: 389 390 [GitLab documentation]: https://docs.gitlab.com/17.0/ee/ci/runners/new_creation_workflow.html#estimated-time-frame-for-planned-changes 391 ''; 392 }; 393 registrationConfigFile = mkOption { 394 type = with types; nullOr path; 395 default = null; 396 description = '' 397 Absolute path to a file with environment variables 398 used for gitlab-runner registration with *runner registration 399 tokens*. 400 401 A list of all supported environment variables can be found in 402 `gitlab-runner register --help`. 403 404 The ones you probably want to set are: 405 - `CI_SERVER_URL=<CI server URL>` 406 - `REGISTRATION_TOKEN=<registration secret>` 407 408 Support for *runner registration tokens* is deprecated since 409 GitLab 16.0, has been disabled by default in GitLab 17.0 and 410 will be removed in GitLab 18.0, as outlined in the 411 [GitLab documentation]. Please consider migrating to 412 [runner authentication tokens] and check the documentation on 413 {option}`services.gitlab-runner.services.<name>.authenticationTokenConfigFile`. 414 415 ::: {.warning} 416 Make sure to use a quoted absolute path, 417 or it is going to be copied to Nix Store. 418 ::: 419 420 [GitLab documentation]: https://docs.gitlab.com/17.0/ee/ci/runners/new_creation_workflow.html#estimated-time-frame-for-planned-changes 421 [runner authentication tokens]: https://docs.gitlab.com/17.0/ee/ci/runners/new_creation_workflow.html#the-new-runner-registration-workflow 422 ''; 423 }; 424 registrationFlags = mkOption { 425 type = types.listOf types.str; 426 default = [ ]; 427 example = [ "--docker-helper-image my/gitlab-runner-helper" ]; 428 description = '' 429 Extra command-line flags passed to 430 `gitlab-runner register`. 431 Execute `gitlab-runner register --help` 432 for a list of supported flags. 433 ''; 434 }; 435 environmentVariables = mkOption { 436 type = types.attrsOf types.str; 437 default = { }; 438 example = { 439 NAME = "value"; 440 }; 441 description = '' 442 Custom environment variables injected to build environment. 443 For secrets you can use {option}`registrationConfigFile` 444 with `RUNNER_ENV` variable set. 445 ''; 446 }; 447 description = mkOption { 448 type = types.nullOr types.str; 449 default = null; 450 description = '' 451 Name/description of the runner. 452 ''; 453 }; 454 executor = mkOption { 455 type = types.str; 456 default = "docker"; 457 description = '' 458 Select executor, eg. shell, docker, etc. 459 See [runner documentation](https://docs.gitlab.com/runner/executors/README.html) for more information. 460 ''; 461 }; 462 buildsDir = mkOption { 463 type = types.nullOr types.path; 464 default = null; 465 example = "/var/lib/gitlab-runner/builds"; 466 description = '' 467 Absolute path to a directory where builds will be stored 468 in context of selected executor (Locally, Docker, SSH). 469 ''; 470 }; 471 cloneUrl = mkOption { 472 type = types.nullOr types.str; 473 default = null; 474 example = "http://gitlab.example.local"; 475 description = '' 476 Overwrite the URL for the GitLab instance. Used if the Runner cant connect to GitLab on the URL GitLab exposes itself. 477 ''; 478 }; 479 dockerImage = mkOption { 480 type = types.nullOr types.str; 481 default = null; 482 description = '' 483 Docker image to be used. 484 ''; 485 }; 486 dockerPullPolicy = mkOption { 487 type = types.nullOr ( 488 types.enum [ 489 "always" 490 "never" 491 "if-not-present" 492 ] 493 ); 494 default = null; 495 description = '' 496 Default pull-policy for Docker images 497 ''; 498 }; 499 dockerVolumes = mkOption { 500 type = types.listOf types.str; 501 default = [ ]; 502 example = [ "/var/run/docker.sock:/var/run/docker.sock" ]; 503 description = '' 504 Bind-mount a volume and create it 505 if it doesn't exist prior to mounting. 506 ''; 507 }; 508 dockerDisableCache = mkOption { 509 type = types.bool; 510 default = false; 511 description = '' 512 Disable all container caching. 513 ''; 514 }; 515 dockerPrivileged = mkOption { 516 type = types.bool; 517 default = false; 518 description = '' 519 Give extended privileges to container. 520 ''; 521 }; 522 dockerExtraHosts = mkOption { 523 type = types.listOf types.str; 524 default = [ ]; 525 example = [ "other-host:127.0.0.1" ]; 526 description = '' 527 Add a custom host-to-IP mapping. 528 ''; 529 }; 530 dockerAllowedImages = mkOption { 531 type = types.listOf types.str; 532 default = [ ]; 533 example = [ 534 "ruby:*" 535 "python:*" 536 "php:*" 537 "my.registry.tld:5000/*:*" 538 ]; 539 description = '' 540 Whitelist allowed images. 541 ''; 542 }; 543 dockerAllowedServices = mkOption { 544 type = types.listOf types.str; 545 default = [ ]; 546 example = [ 547 "postgres:9" 548 "redis:*" 549 "mysql:*" 550 ]; 551 description = '' 552 Whitelist allowed services. 553 ''; 554 }; 555 preGetSourcesScript = mkOption { 556 type = types.nullOr (types.either types.str types.path); 557 default = null; 558 description = '' 559 Runner-specific command script executed before code is pulled. 560 ''; 561 }; 562 postGetSourcesScript = mkOption { 563 type = types.nullOr (types.either types.str types.path); 564 default = null; 565 description = '' 566 Runner-specific command script executed after code is pulled. 567 ''; 568 }; 569 preBuildScript = mkOption { 570 type = types.nullOr (types.either types.str types.path); 571 default = null; 572 description = '' 573 Runner-specific command script executed after code is pulled, 574 just before build executes. 575 ''; 576 }; 577 postBuildScript = mkOption { 578 type = types.nullOr (types.either types.str types.path); 579 default = null; 580 description = '' 581 Runner-specific command script executed after code is pulled 582 and just after build executes. 583 ''; 584 }; 585 tagList = mkOption { 586 type = types.listOf types.str; 587 default = [ ]; 588 description = '' 589 Tag list. 590 591 This option has no effect for runners registered with an runner 592 authentication tokens and will be ignored. 593 ''; 594 }; 595 runUntagged = mkOption { 596 type = types.bool; 597 default = false; 598 description = '' 599 Register to run untagged builds; defaults to 600 `true` when {option}`tagList` is empty. 601 602 This option has no effect for runners registered with an runner 603 authentication tokens and will be ignored. 604 ''; 605 }; 606 limit = mkOption { 607 type = types.int; 608 default = 0; 609 description = '' 610 Limit how many jobs can be handled concurrently by this service. 611 0 (default) simply means don't limit. 612 ''; 613 }; 614 requestConcurrency = mkOption { 615 type = types.int; 616 default = 0; 617 description = '' 618 Limit number of concurrent requests for new jobs from GitLab. 619 ''; 620 }; 621 maximumTimeout = mkOption { 622 type = types.int; 623 default = 0; 624 description = '' 625 What is the maximum timeout (in seconds) that will be set for 626 job when using this Runner. 0 (default) simply means don't limit. 627 628 This option has no effect for runners registered with an runner 629 authentication tokens and will be ignored. 630 ''; 631 }; 632 protected = mkOption { 633 type = types.bool; 634 default = false; 635 description = '' 636 When set to true Runner will only run on pipelines 637 triggered on protected branches. 638 639 This option has no effect for runners registered with an runner 640 authentication tokens and will be ignored. 641 ''; 642 }; 643 debugTraceDisabled = mkOption { 644 type = types.bool; 645 default = false; 646 description = '' 647 When set to true Runner will disable the possibility of 648 using the `CI_DEBUG_TRACE` feature. 649 ''; 650 }; 651 }; 652 } 653 ); 654 }; 655 clear-docker-cache = { 656 enable = mkOption { 657 type = types.bool; 658 default = false; 659 description = '' 660 Whether to periodically prune gitlab runner's Docker resources. If 661 enabled, a systemd timer will run {command}`clear-docker-cache` as 662 specified by the `dates` option. 663 ''; 664 }; 665 666 flags = mkOption { 667 type = types.listOf types.str; 668 default = [ ]; 669 example = [ "prune" ]; 670 description = '' 671 Any additional flags passed to {command}`clear-docker-cache`. 672 ''; 673 }; 674 675 dates = mkOption { 676 default = "weekly"; 677 type = types.str; 678 description = '' 679 Specification (in the format described by 680 {manpage}`systemd.time(7)`) of the time at 681 which the prune will occur. 682 ''; 683 }; 684 685 package = mkOption { 686 default = config.virtualisation.docker.package; 687 defaultText = literalExpression "config.virtualisation.docker.package"; 688 example = literalExpression "pkgs.docker"; 689 description = "Docker package to use for clearing up docker cache."; 690 }; 691 }; 692 }; 693 config = mkIf cfg.enable { 694 assertions = mapAttrsToList (name: serviceConfig: { 695 assertion = 696 serviceConfig.registrationConfigFile == null || serviceConfig.authenticationTokenConfigFile == null; 697 message = "`services.gitlab-runner.${name}.registrationConfigFile` and `services.gitlab-runner.services.${name}.authenticationTokenConfigFile` are mutually exclusive."; 698 }) cfg.services; 699 700 warnings = 701 mapAttrsToList ( 702 name: serviceConfig: 703 "services.gitlab-runner.services.${name}.`registrationConfigFile` points to a file in Nix Store. You should use quoted absolute path to prevent this." 704 ) (filterAttrs (name: serviceConfig: isStorePath serviceConfig.registrationConfigFile) cfg.services) 705 ++ 706 mapAttrsToList 707 ( 708 name: serviceConfig: 709 "services.gitlab-runner.services.${name}.`authenticationTokenConfigFile` points to a file in Nix Store. You should use quoted absolute path to prevent this." 710 ) 711 ( 712 filterAttrs ( 713 name: serviceConfig: isStorePath serviceConfig.authenticationTokenConfigFile 714 ) cfg.services 715 ) 716 ++ 717 mapAttrsToList 718 (name: serviceConfig: '' 719 Runner registration tokens have been deprecated and disabled by default in GitLab >= 17.0. 720 Consider migrating to runner authentication tokens by setting `services.gitlab-runner.services.${name}.authenticationTokenConfigFile`. 721 https://docs.gitlab.com/17.0/ee/ci/runners/new_creation_workflow.html'') 722 ( 723 filterAttrs (name: serviceConfig: serviceConfig.authenticationTokenConfigFile == null) cfg.services 724 ) 725 ++ 726 mapAttrsToList 727 ( 728 name: serviceConfig: 729 ''`services.gitlab-runner.services.${name}.protected` with runner authentication tokens has no effect and will be ignored. Please remove it from your configuration.'' 730 ) 731 ( 732 filterAttrs ( 733 name: serviceConfig: 734 serviceConfig.authenticationTokenConfigFile != null && serviceConfig.protected == true 735 ) cfg.services 736 ) 737 ++ 738 mapAttrsToList 739 ( 740 name: serviceConfig: 741 ''`services.gitlab-runner.services.${name}.runUntagged` with runner authentication tokens has no effect and will be ignored. Please remove it from your configuration.'' 742 ) 743 ( 744 filterAttrs ( 745 name: serviceConfig: 746 serviceConfig.authenticationTokenConfigFile != null && serviceConfig.runUntagged == true 747 ) cfg.services 748 ) 749 ++ 750 mapAttrsToList 751 ( 752 name: v: 753 ''`services.gitlab-runner.services.${name}.maximumTimeout` with runner authentication tokens has no effect and will be ignored. Please remove it from your configuration.'' 754 ) 755 ( 756 filterAttrs ( 757 name: serviceConfig: 758 serviceConfig.authenticationTokenConfigFile != null && serviceConfig.maximumTimeout != 0 759 ) cfg.services 760 ) 761 ++ 762 mapAttrsToList 763 ( 764 name: v: 765 ''`services.gitlab-runner.services.${name}.tagList` with runner authentication tokens has no effect and will be ignored. Please remove it from your configuration.'' 766 ) 767 ( 768 filterAttrs ( 769 serviceName: serviceConfig: 770 serviceConfig.authenticationTokenConfigFile != null && serviceConfig.tagList != [ ] 771 ) cfg.services 772 ); 773 774 environment.systemPackages = [ cfg.package ]; 775 systemd.services.gitlab-runner = { 776 description = "Gitlab Runner"; 777 documentation = [ "https://docs.gitlab.com/runner/" ]; 778 after = 779 [ "network.target" ] ++ optional hasDocker "docker.service" ++ optional hasPodman "podman.service"; 780 781 requires = optional hasDocker "docker.service" ++ optional hasPodman "podman.service"; 782 wantedBy = [ "multi-user.target" ]; 783 environment = config.networking.proxy.envVars // { 784 HOME = "/var/lib/gitlab-runner"; 785 }; 786 787 path = 788 (with pkgs; [ 789 bash 790 gawk 791 jq 792 moreutils 793 remarshal 794 util-linux 795 ]) 796 ++ [ cfg.package ] 797 ++ cfg.extraPackages; 798 799 reloadIfChanged = true; 800 serviceConfig = 801 { 802 # Set `DynamicUser` under `systemd.services.gitlab-runner.serviceConfig` 803 # to `lib.mkForce false` in your configuration to run this service as root. 804 # You can also set `User` and `Group` options to run this service as desired user. 805 # Make sure to restart service or changes won't apply. 806 DynamicUser = true; 807 StateDirectory = "gitlab-runner"; 808 SupplementaryGroups = optional hasDocker "docker" ++ optional hasPodman "podman"; 809 ExecStartPre = "!${configureScript}/bin/gitlab-runner-configure"; 810 ExecStart = "${startScript}/bin/gitlab-runner-start"; 811 ExecReload = "!${configureScript}/bin/gitlab-runner-configure"; 812 } 813 // optionalAttrs cfg.gracefulTermination { 814 TimeoutStopSec = "${cfg.gracefulTimeout}"; 815 KillSignal = "SIGQUIT"; 816 KillMode = "process"; 817 }; 818 }; 819 # Enable periodic clear-docker-cache script 820 systemd.services.gitlab-runner-clear-docker-cache = 821 mkIf (cfg.clear-docker-cache.enable && (any (s: s.executor == "docker") (attrValues cfg.services))) 822 { 823 description = "Prune gitlab-runner docker resources"; 824 restartIfChanged = false; 825 unitConfig.X-StopOnRemoval = false; 826 827 serviceConfig.Type = "oneshot"; 828 829 path = [ 830 cfg.clear-docker-cache.package 831 pkgs.gawk 832 ]; 833 834 script = '' 835 ${pkgs.gitlab-runner}/bin/clear-docker-cache ${toString cfg.clear-docker-cache.flags} 836 ''; 837 838 startAt = cfg.clear-docker-cache.dates; 839 }; 840 # Enable docker if `docker` executor is used in any service 841 virtualisation.docker.enable = mkIf (any (s: s.executor == "docker") (attrValues cfg.services)) ( 842 mkDefault true 843 ); 844 }; 845 imports = [ 846 (mkRenamedOptionModule 847 [ "services" "gitlab-runner" "packages" ] 848 [ "services" "gitlab-runner" "extraPackages" ] 849 ) 850 (mkRemovedOptionModule [ 851 "services" 852 "gitlab-runner" 853 "configOptions" 854 ] "Use services.gitlab-runner.services option instead") 855 (mkRemovedOptionModule [ 856 "services" 857 "gitlab-runner" 858 "workDir" 859 ] "You should move contents of workDir (if any) to /var/lib/gitlab-runner") 860 861 (mkRenamedOptionModule 862 [ "services" "gitlab-runner" "checkInterval" ] 863 [ "services" "gitlab-runner" "settings" "check_interval" ] 864 ) 865 (mkRenamedOptionModule 866 [ "services" "gitlab-runner" "concurrent" ] 867 [ "services" "gitlab-runner" "settings" "concurrent" ] 868 ) 869 (mkRenamedOptionModule 870 [ "services" "gitlab-runner" "sentryDSN" ] 871 [ "services" "gitlab-runner" "settings" "sentry_dsn" ] 872 ) 873 (mkRenamedOptionModule 874 [ "services" "gitlab-runner" "prometheusListenAddress" ] 875 [ "services" "gitlab-runner" "settings" "listen_address" ] 876 ) 877 878 (mkRenamedOptionModule 879 [ "services" "gitlab-runner" "sessionServer" "listenAddress" ] 880 [ "services" "gitlab-runner" "settings" "session_server" "listen_address" ] 881 ) 882 (mkRenamedOptionModule 883 [ "services" "gitlab-runner" "sessionServer" "advertiseAddress" ] 884 [ "services" "gitlab-runner" "settings" "session_server" "advertise_address" ] 885 ) 886 (mkRenamedOptionModule 887 [ "services" "gitlab-runner" "sessionServer" "sessionTimeout" ] 888 [ "services" "gitlab-runner" "settings" "session_server" "session_timeout" ] 889 ) 890 ]; 891 892 meta.maintainers = teams.gitlab.members; 893}