From 19fd6167e925c5f080870e51decda47f83d9e610 Mon Sep 17 00:00:00 2001 From: Winter Date: Mon, 11 Aug 2025 23:30:49 -0400 Subject: [PATCH] nix/modules/knot: don't use an activation script to set up git user home Change-Id: vyyyyttpvxtwzztpmqqolzzxmvxskpsl It's unidiomatic, and doesn't allow extension by way of changing the systemd service options (like is done in the following commit). Signed-off-by: Winter --- nix/modules/knot.nix | 51 +++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/nix/modules/knot.nix b/nix/modules/knot.nix index e431045..3376f51 100644 --- a/nix/modules/knot.nix +++ b/nix/modules/knot.nix @@ -126,30 +126,6 @@ in cfg.package ]; - system.activationScripts.gitConfig = let - setMotd = - if cfg.motdFile != null && cfg.motd != null - then throw "motdFile and motd cannot be both set" - else '' - ${optionalString (cfg.motdFile != null) "cat ${cfg.motdFile} > ${cfg.stateDir}/motd"} - ${optionalString (cfg.motd != null) ''printf "${cfg.motd}" > ${cfg.stateDir}/motd''} - ''; - in '' - mkdir -p "${cfg.repo.scanPath}" - chown -R ${cfg.gitUser}:${cfg.gitUser} "${cfg.repo.scanPath}" - - mkdir -p "${cfg.stateDir}/.config/git" - cat > "${cfg.stateDir}/.config/git/config" << EOF - [user] - name = Git User - email = git@example.com - [receive] - advertisePushOptions = true - EOF - ${setMotd} - chown -R ${cfg.gitUser}:${cfg.gitUser} "${cfg.stateDir}" - ''; - users.users.${cfg.gitUser} = { isSystemUser = true; useDefaultShell = true; @@ -185,8 +161,35 @@ in description = "knot service"; after = ["network.target" "sshd.service"]; wantedBy = ["multi-user.target"]; + enableStrictShellChecks = true; + + preStart = let + setMotd = + if cfg.motdFile != null && cfg.motd != null + then throw "motdFile and motd cannot be both set" + else '' + ${optionalString (cfg.motdFile != null) "cat ${cfg.motdFile} > ${cfg.stateDir}/motd"} + ${optionalString (cfg.motd != null) ''printf "${cfg.motd}" > ${cfg.stateDir}/motd''} + ''; + in '' + mkdir -p "${cfg.repo.scanPath}" + chown -R ${cfg.gitUser}:${cfg.gitUser} "${cfg.repo.scanPath}" + + mkdir -p "${cfg.stateDir}/.config/git" + cat > "${cfg.stateDir}/.config/git/config" << EOF + [user] + name = Git User + email = git@example.com + [receive] + advertisePushOptions = true + EOF + ${setMotd} + chown -R ${cfg.gitUser}:${cfg.gitUser} "${cfg.stateDir}" + ''; + serviceConfig = { User = cfg.gitUser; + PermissionsStartOnly = true; WorkingDirectory = cfg.stateDir; Environment = [ "KNOT_REPO_SCAN_PATH=${cfg.repo.scanPath}" -- 2.43.0 From ad9c04b44349a83316f5466f37280cbed3ebbfbe Mon Sep 17 00:00:00 2001 From: Winter Date: Mon, 11 Aug 2025 20:16:15 -0400 Subject: [PATCH] nix/vm: store service data in a shared folder on the host Change-Id: tkullpkzpmstpurqrvlzqpupwkkuzymz This also switches away from `nixos-shell` in the process as by this point it wasn't really adding much to our setup except inflexibility. Signed-off-by: Winter --- .gitignore | 1 + docs/hacking.md | 8 +++--- flake.nix | 49 ++++++++++++++++------------------- nix/vm.nix | 68 +++++++++++++++++++++++++++++++++++++------------ 4 files changed, 78 insertions(+), 48 deletions(-) diff --git a/.gitignore b/.gitignore index 2e9ab2f..3c098f5 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ patches .env *.rdb .envrc +/nix/vm-data diff --git a/docs/hacking.md b/docs/hacking.md index a16c0ab..5cd6c08 100644 --- a/docs/hacking.md +++ b/docs/hacking.md @@ -60,14 +60,12 @@ and generate a knot secret. Set `$TANGLED_KNOT_SECRET` to it, ideally in a `.envrc` with [direnv](https://direnv.net) so you don't lose it. -You can now start a lightweight NixOS VM using -`nixos-shell` like so: +You can now start a lightweight NixOS VM like so: ```bash -nix run .#vm -# or nixos-shell --flake .#vm +nix run --impure .#vm -# hit Ctrl-a + c + q to exit the VM +# type `poweroff` at the shell to exit the VM ``` This starts a knot on port 6000, a spindle on port 6555 diff --git a/flake.nix b/flake.nix index db11dd2..c402184 100644 --- a/flake.nix +++ b/flake.nix @@ -175,28 +175,31 @@ program = ''${tailwind-watcher}/bin/run''; }; vm = let - system = + guestSystem = if pkgs.stdenv.hostPlatform.isAarch64 - then "aarch64" - else "x86_64"; - - nixos-shell = pkgs.nixos-shell.overrideAttrs (old: { - patches = - (old.patches or []) - ++ [ - # https://github.com/Mic92/nixos-shell/pull/94 - (pkgs.fetchpatch { - name = "fix-foreign-vm.patch"; - url = "https://github.com/Mic92/nixos-shell/commit/113e4cc55ae236b5b0b1fbd8b321e9b67c77580e.patch"; - hash = "sha256-eauetBK0wXAOcd9PYbExokNCiwz2QyFnZ4FnwGi9VCo="; - }) - ]; - }); + then "aarch64-linux" + else "x86_64-linux"; in { type = "app"; - program = toString (pkgs.writeShellScript "vm" '' - ${nixos-shell}/bin/nixos-shell --flake .#vm-${system} --guest-system ${system}-linux - ''); + program = + (pkgs.writeShellApplication { + name = "launch-vm"; + text = '' + rootDir=$(jj --ignore-working-copy root || git rev-parse --show-toplevel) || (echo "error: can't find repo root?"; exit 1) + cd "$rootDir" + + mkdir -p nix/vm-data/{knot,repos,spindle,spindle-logs} + + export TANGLED_VM_DATA_DIR="$rootDir/nix/vm-data" + exec ${pkgs.lib.getExe + (import ./nix/vm.nix { + inherit nixpkgs self; + system = guestSystem; + hostSystem = system; + }).config.system.build.vm} + ''; + }) + + /bin/launch-vm; }; gomod2nix = { type = "app"; @@ -258,13 +261,5 @@ services.tangled-spindle.package = lib.mkDefault self.packages.${pkgs.system}.spindle; }; - nixosConfigurations.vm-x86_64 = import ./nix/vm.nix { - inherit self nixpkgs; - system = "x86_64-linux"; - }; - nixosConfigurations.vm-aarch64 = import ./nix/vm.nix { - inherit self nixpkgs; - system = "aarch64-linux"; - }; }; } diff --git a/nix/vm.nix b/nix/vm.nix index 6297fcb..3e0b0ca 100644 --- a/nix/vm.nix +++ b/nix/vm.nix @@ -1,6 +1,7 @@ { nixpkgs, system, + hostSystem, self, }: let envVar = name: let @@ -16,18 +17,15 @@ in self.nixosModules.knot self.nixosModules.spindle ({ + lib, config, pkgs, ... }: { - nixos-shell = { - inheritPath = false; - mounts = { - mountHome = false; - mountNixProfile = false; - }; - }; - virtualisation = { + virtualisation.vmVariant.virtualisation = { + host.pkgs = import nixpkgs {system = hostSystem;}; + + graphics = false; memorySize = 2048; diskSize = 10 * 1024; cores = 2; @@ -51,21 +49,32 @@ in guest.port = 6555; } ]; + sharedDirectories = { + # We can't use the 9p mounts directly for most of these + # as SQLite is incompatible with them. So instead we + # mount the shared directories to a different location + # and copy the contents around on service start/stop. + knotData = { + source = "$TANGLED_VM_DATA_DIR/knot"; + target = "/mnt/knot-data"; + }; + spindleData = { + source = "$TANGLED_VM_DATA_DIR/spindle"; + target = "/mnt/spindle-data"; + }; + spindleLogs = { + source = "$TANGLED_VM_DATA_DIR/spindle-logs"; + target = "/var/log/spindle"; + }; + }; }; services.getty.autologinUser = "root"; environment.systemPackages = with pkgs; [curl vim git sqlite litecli]; - systemd.tmpfiles.rules = let - u = config.services.tangled-knot.gitUser; - g = config.services.tangled-knot.gitUser; - in [ - "d /var/lib/knot 0770 ${u} ${g} - -" # Create the directory first - "f+ /var/lib/knot/secret 0660 ${u} ${g} - KNOT_SERVER_SECRET=${envVar "TANGLED_VM_KNOT_SECRET"}" - ]; services.tangled-knot = { enable = true; motd = "Welcome to the development knot!\n"; server = { - secretFile = "/var/lib/knot/secret"; + secretFile = builtins.toFile "knot-secret" ("KNOT_SERVER_SECRET=" + (envVar "TANGLED_VM_KNOT_SECRET")); hostname = "localhost:6000"; listenAddr = "0.0.0.0:6000"; }; @@ -82,6 +91,33 @@ in }; }; }; + users = { + # So we don't have to deal with permission clashing between + # blank disk VMs and existing state + users.${config.services.tangled-knot.gitUser}.uid = 666; + groups.${config.services.tangled-knot.gitUser}.gid = 666; + + # TODO: separate spindle user + }; + systemd.services = let + mkDataSyncScripts = source: target: { + enableStrictShellChecks = true; + + preStart = lib.mkBefore '' + mkdir -p ${target} + ${lib.getExe pkgs.rsync} -a ${source}/ ${target} + ''; + + postStop = lib.mkAfter '' + ${lib.getExe pkgs.rsync} -a ${target}/ ${source} + ''; + + serviceConfig.PermissionsStartOnly = true; + }; + in { + knot = mkDataSyncScripts "/mnt/knot-data" config.services.tangled-knot.stateDir; + spindle = mkDataSyncScripts "/mnt/spindle-data" (builtins.dirOf config.services.tangled-spindle.server.dbPath); + }; }) ]; } -- 2.43.0