From fb9e963b0e1746438f29b6afbcb5aeeb058e3b77 Mon Sep 17 00:00:00 2001 From: jolheiser Date: Thu, 13 Feb 2025 20:49:08 -0600 Subject: [PATCH] fix nix module for multiple instances --- nix/module.nix | 161 ++++++++++++++++++++++++++----------------------- 1 file changed, 87 insertions(+), 74 deletions(-) diff --git a/nix/module.nix b/nix/module.nix index 66ffd9b..bf7aa55 100644 --- a/nix/module.nix +++ b/nix/module.nix @@ -9,6 +9,7 @@ let pkg = pkgs.callPackage ./pkg.nix { inherit pkgs; }; yamlFormat = pkgs.formats.yaml { }; instanceOptions = + { name, config, ... }: let inherit (lib) mkEnableOption mkOption types; in @@ -25,13 +26,13 @@ let homeDir = mkOption { type = types.str; description = "ugit home directory"; - default = "/var/lib/ugit"; + default = "/var/lib/ugit/${name}"; }; repoDir = mkOption { type = types.str; description = "where ugit stores repositories"; - default = "/var/lib/ugit/repos"; + default = "/var/lib/ugit/${name}/repos"; }; authorizedKeys = mkOption { @@ -43,13 +44,13 @@ let authorizedKeysFile = mkOption { type = types.str; description = "path to authorized_keys file ugit uses for auth"; - default = "/var/lib/ugit/authorized_keys"; + default = "/var/lib/ugit/${name}/authorized_keys"; }; hostKeyFile = mkOption { type = types.str; description = "path to host key file (will be created if it doesn't exist)"; - default = "/var/lib/ugit/ugit_ed25519"; + default = "/var/lib/ugit/${name}/ugit_ed25519"; }; config = mkOption { @@ -60,13 +61,13 @@ let user = mkOption { type = types.str; - default = "ugit"; + default = "ugit-${name}"; description = "User account under which ugit runs"; }; group = mkOption { type = types.str; - default = "ugit"; + default = "ugit-${name}"; description = "Group account under which ugit runs"; }; @@ -116,35 +117,16 @@ in lib.filterAttrs (name: instanceCfg: instanceCfg.enable) cfg ); - systemd.services = lib.mapAttrs' ( - name: instanceCfg: - lib.nameValuePair "ugit-${name}" { - ugit = - let - configFile = pkgs.writeText "ugit.yaml" ( - builtins.readFile (yamlFormat.generate "ugit-yaml" instanceCfg.config) - ); - authorizedKeysFile = pkgs.writeText "ugit_keys" ( - builtins.concatStringsSep "\n" instanceCfg.authorizedKeys - ); - in - { + systemd.services = lib.foldl' ( + acc: name: + let + instanceCfg = cfg.${name}; + in + lib.recursiveUpdate acc ( + lib.optionalAttrs instanceCfg.enable { + "ugit-${name}" = { enable = true; - script = - let - authorizedKeysPath = - if (builtins.length instanceCfg.authorizedKeys) > 0 then - authorizedKeysFile - else - instanceCfg.authorizedKeysFile; - args = [ - "--config=${configFile}" - "--repo-dir=${instanceCfg.repoDir}" - "--ssh.authorized-keys=${authorizedKeysPath}" - "--ssh.host-key=${instanceCfg.hostKeyFile}" - ]; - in - "${instanceCfg.package}/bin/ugitd ${builtins.concatStringsSep " " args}"; + description = "ugit instance ${name}"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; path = [ @@ -158,51 +140,82 @@ in Restart = "always"; RestartSec = "15"; WorkingDirectory = instanceCfg.homeDir; + ExecStart = + let + configFile = pkgs.writeText "ugit-${name}.yaml" ( + builtins.readFile (yamlFormat.generate "ugit-${name}-yaml" instanceCfg.config) + ); + authorizedKeysFile = pkgs.writeText "ugit_${name}_keys" ( + builtins.concatStringsSep "\n" instanceCfg.authorizedKeys + ); + + authorizedKeysPath = + if (builtins.length instanceCfg.authorizedKeys) > 0 then + authorizedKeysFile + else + instanceCfg.authorizedKeysFile; + args = [ + "--config=${configFile}" + "--repo-dir=${instanceCfg.repoDir}" + "--ssh.authorized-keys=${authorizedKeysPath}" + "--ssh.host-key=${instanceCfg.hostKeyFile}" + ]; + in + "${instanceCfg.package}/bin/ugitd ${builtins.concatStringsSep " " args}"; }; }; - ugit-hooks = { - wantedBy = [ "multi-user.target" ]; - after = [ "ugit.service" ]; - requires = [ "ugit.service" ]; - serviceConfig = { - Type = "oneshot"; - ExecStart = - let - script = pkgs.writeShellScript "ugit-hooks-link" ( - builtins.concatStringsSep "\n" ( - map ( - hook: - let - script = pkgs.writeShellScript hook.name hook.content; - path = "${instanceCfg.repoDir}/hooks/pre-receive.d/${hook.name}"; - in - "ln -s ${script} ${path}" - ) instanceCfg.hooks - ) - ); - in - "${script}"; - }; - }; - } - ) (lib.filterAttrs (name: instanceCfg: instanceCfg.enable) cfg); - systemd.tmpfiles.settings.ugit = builtins.listToAttrs ( - map ( - hook: - let - script = pkgs.writeShellScript hook.name hook.content; - path = "${cfg.repoDir}/hooks/pre-receive.d/${hook.name}"; - in - { - name = path; - value = { - "L" = { - argument = "${script}"; + "ugit-${name}-hooks" = { + description = "Setup hooks for ugit instance ${name}"; + wantedBy = [ "multi-user.target" ]; + after = [ "ugit-${name}.service" ]; + requires = [ "ugit-${name}.service" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + User = instanceCfg.user; + Group = instanceCfg.group; + ExecStart = + let + hookDir = "${instanceCfg.repoDir}/hooks/pre-receive.d"; + mkHookScript = + hook: + let + script = pkgs.writeShellScript "ugit-${name}-${hook.name}" hook.content; + in + '' + mkdir -p ${hookDir} + ln -sf ${script} ${hookDir}/${hook.name} + ''; + in + pkgs.writeShellScript "ugit-${name}-hooks-setup" '' + ${builtins.concatStringsSep "\n" (map mkHookScript instanceCfg.hooks)} + ''; }; }; } - ) cfg.hooks - ); + ) + ) { } (builtins.attrNames cfg); + + systemd.tmpfiles.settings = lib.mapAttrs' ( + name: instanceCfg: + builtins.listToAttrs ( + map ( + hook: + let + script = pkgs.writeShellScript hook.name hook.content; + path = "${instanceCfg.repoDir}/hooks/pre-receive.d/${hook.name}"; + in + { + name = path; + value = { + "L" = { + argument = "${script}"; + }; + }; + } + ) instanceCfg.hooks + ) + ) (lib.filterAttrs (name: instanceCfg: instanceCfg.enable) cfg); }; }