diff options
author | Matthieu Coudron <mcoudron@hotmail.com> | 2022-10-21 15:18:10 +0200 |
---|---|---|
committer | Matthieu Coudron <teto@users.noreply.github.com> | 2023-01-05 11:43:32 +0100 |
commit | c61f554c1aa9fbec38b73cb7bbb205572673a5ba (patch) | |
tree | c6cb997c14a305f3c140f9a88cfb9d7173ccfd2b /nixos/modules/services | |
parent | da98602aa968ff4d9e3c1e53ae6149651f8a2850 (diff) |
modules.gitlab-runner: accept space in names
when you register a runner with spaces in its name (possible if you use 'description' option) then the runners never get unregistered because our bash scripts assume no space in names. This solves the issue Retreiving the fullname of the runner via `gitlab-runner list` got surprisingly hard between lazy-capture issues and `gitlab-runner list` displaying invisible (CSI) characters that break the regex etc. Which is why I fell back on the pseudo-json format. This PR adds the hash in the name, which allows to keep both the stateless aspect of the module while allowing for a freeform name. I found using bash associative arrays easier to use/debug than the current approach.
Diffstat (limited to 'nixos/modules/services')
-rw-r--r-- | nixos/modules/services/continuous-integration/gitlab-runner.nix | 90 |
1 files changed, 66 insertions, 24 deletions
diff --git a/nixos/modules/services/continuous-integration/gitlab-runner.nix b/nixos/modules/services/continuous-integration/gitlab-runner.nix index 7b1c4da862606..d18c4cff04057 100644 --- a/nixos/modules/services/continuous-integration/gitlab-runner.nix +++ b/nixos/modules/services/continuous-integration/gitlab-runner.nix @@ -4,24 +4,41 @@ with lib; let cfg = config.services.gitlab-runner; hasDocker = config.virtualisation.docker.enable; + + /* The whole logic of this module is to diff the hashes of the desired vs existing runners + The hash is recorded in the runner's name because we can't do better yet + See https://gitlab.com/gitlab-org/gitlab-runner/-/issues/29350 for more details + */ + genRunnerName = service: let + hash = substring 0 12 (hashString "md5" (unsafeDiscardStringContext (toJSON service))); + in if service ? description + then "${hash} ${service.description}" + else "${name}_${config.networking.hostName}_${hash}"; + hashedServices = mapAttrs' - (name: service: nameValuePair - "${name}_${config.networking.hostName}_${ - substring 0 12 - (hashString "md5" (unsafeDiscardStringContext (toJSON service)))}" - service) - cfg.services; - configPath = "$HOME/.gitlab-runner/config.toml"; - configureScript = pkgs.writeShellScriptBin "gitlab-runner-configure" ( - if (cfg.configFile != null) then '' - mkdir -p $(dirname ${configPath}) + (name: service: nameValuePair (genRunnerName service) service) cfg.services; + configPath = ''"$HOME"/.gitlab-runner/config.toml''; + configureScript = pkgs.writeShellApplication { + name = "gitlab-runner-configure"; + runtimeInputs = with pkgs; [ + bash + gawk + jq + moreutils + remarshal + util-linux + cfg.package + perl + python3 + ]; + text = if (cfg.configFile != null) then '' cp ${cfg.configFile} ${configPath} # make config file readable by service chown -R --reference=$HOME $(dirname ${configPath}) '' else '' export CONFIG_FILE=${configPath} - mkdir -p $(dirname ${configPath}) + mkdir -p "$(dirname "${configPath}")" touch ${configPath} # update global options @@ -34,22 +51,43 @@ let # remove no longer existing services gitlab-runner verify --delete - # current and desired state - NEEDED_SERVICES=$(echo ${concatStringsSep " " (attrNames hashedServices)} | tr " " "\n") - REGISTERED_SERVICES=$(gitlab-runner list 2>&1 | grep 'Executor' | awk '{ print $1 }') + ${toShellVar "NEEDED_SERVICES" (lib.mapAttrs (name: value: 1) hashedServices)} + + declare -A REGISTERED_SERVICES + + while IFS="," read -r name token; + do + REGISTERED_SERVICES["$name"]="$token" + done < <(gitlab-runner --log-format json list 2>&1 | grep Token | jq -r '.msg +"," + .Token') + + echo "NEEDED_SERVICES: " "''${!NEEDED_SERVICES[@]}" + echo "REGISTERED_SERVICES:" "''${!REGISTERED_SERVICES[@]}" # difference between current and desired state - NEW_SERVICES=$(grep -vxF -f <(echo "$REGISTERED_SERVICES") <(echo "$NEEDED_SERVICES") || true) - OLD_SERVICES=$(grep -vxF -f <(echo "$NEEDED_SERVICES") <(echo "$REGISTERED_SERVICES") || true) + declare -A NEW_SERVICES + for name in "''${!NEEDED_SERVICES[@]}"; do + if [ ! -v 'REGISTERED_SERVICES[$name]' ]; then + NEW_SERVICES[$name]=1 + fi + done + + declare -A OLD_SERVICES + # shellcheck disable=SC2034 + for name in "''${!REGISTERED_SERVICES[@]}"; do + if [ ! -v 'NEEDED_SERVICES[$name]' ]; then + OLD_SERVICES[$name]=1 + fi + done # register new services ${concatStringsSep "\n" (mapAttrsToList (name: service: '' - if echo "$NEW_SERVICES" | grep -xq "${name}"; then + # TODO so here we should mention NEW_SERVICES + if [ -v 'NEW_SERVICES["${name}"]' ] ; then bash -c ${escapeShellArg (concatStringsSep " \\\n " ([ "set -a && source ${service.registrationConfigFile} &&" "gitlab-runner register" "--non-interactive" - (if service.description != null then "--description \"${service.description}\"" else "--name '${name}'") + "--name '${name}'" "--executor ${service.executor}" "--limit ${toString service.limit}" "--request-concurrency ${toString service.requestConcurrency}" @@ -92,22 +130,26 @@ let fi '') hashedServices)} + # check key is in array https://stackoverflow.com/questions/30353951/how-to-check-if-dictionary-contains-a-key-in-bash + + echo "NEW_SERVICES: ''${NEW_SERVICES[*]}" + echo "OLD_SERVICES: ''${OLD_SERVICES[*]}" # unregister old services - for NAME in $(echo "$OLD_SERVICES") + for NAME in "''${!OLD_SERVICES[@]}" do - [ ! -z "$NAME" ] && gitlab-runner unregister \ + [ -n "$NAME" ] && gitlab-runner unregister \ --name "$NAME" && sleep 1 done # make config file readable by service - chown -R --reference=$HOME $(dirname ${configPath}) - ''); + chown -R --reference="$HOME" "$(dirname ${configPath})" + ''; + }; startScript = pkgs.writeShellScriptBin "gitlab-runner-start" '' export CONFIG_FILE=${configPath} exec gitlab-runner run --working-directory $HOME ''; -in -{ +in { options.services.gitlab-runner = { enable = mkEnableOption (lib.mdDoc "Gitlab Runner"); configFile = mkOption { |