+2
-1
.gitignore
+2
-1
.gitignore
+4
-6
docs/hacking.md
+4
-6
docs/hacking.md
···
64
64
You will also need to set the `$TANGLED_VM_SPINDLE_OWNER`
65
65
variable to some value. If you don't want to [set up a
66
66
spindle](#running-a-spindle), you can use any placeholder
67
-
value.
67
+
value.
68
68
69
-
You can now start a lightweight NixOS VM using
70
-
`nixos-shell` like so:
69
+
You can now start a lightweight NixOS VM like so:
71
70
72
71
```bash
73
-
nix run .#vm
74
-
# or nixos-shell --flake .#vm
72
+
nix run --impure .#vm
75
73
76
-
# hit Ctrl-a + c + q to exit the VM
74
+
# type `poweroff` at the shell to exit the VM
77
75
```
78
76
79
77
This starts a knot on port 6000, a spindle on port 6555
+22
-27
flake.nix
+22
-27
flake.nix
···
175
175
program = ''${tailwind-watcher}/bin/run'';
176
176
};
177
177
vm = let
178
-
system =
178
+
guestSystem =
179
179
if pkgs.stdenv.hostPlatform.isAarch64
180
-
then "aarch64"
181
-
else "x86_64";
182
-
183
-
nixos-shell = pkgs.nixos-shell.overrideAttrs (old: {
184
-
patches =
185
-
(old.patches or [])
186
-
++ [
187
-
# https://github.com/Mic92/nixos-shell/pull/94
188
-
(pkgs.fetchpatch {
189
-
name = "fix-foreign-vm.patch";
190
-
url = "https://github.com/Mic92/nixos-shell/commit/113e4cc55ae236b5b0b1fbd8b321e9b67c77580e.patch";
191
-
hash = "sha256-eauetBK0wXAOcd9PYbExokNCiwz2QyFnZ4FnwGi9VCo=";
192
-
})
193
-
];
194
-
});
180
+
then "aarch64-linux"
181
+
else "x86_64-linux";
195
182
in {
196
183
type = "app";
197
-
program = toString (pkgs.writeShellScript "vm" ''
198
-
${nixos-shell}/bin/nixos-shell --flake .#vm-${system} --guest-system ${system}-linux
199
-
'');
184
+
program =
185
+
(pkgs.writeShellApplication {
186
+
name = "launch-vm";
187
+
text = ''
188
+
rootDir=$(jj --ignore-working-copy root || git rev-parse --show-toplevel) || (echo "error: can't find repo root?"; exit 1)
189
+
cd "$rootDir"
190
+
191
+
mkdir -p nix/vm-data/{knot,repos,spindle,spindle-logs}
192
+
193
+
export TANGLED_VM_DATA_DIR="$rootDir/nix/vm-data"
194
+
exec ${pkgs.lib.getExe
195
+
(import ./nix/vm.nix {
196
+
inherit nixpkgs self;
197
+
system = guestSystem;
198
+
hostSystem = system;
199
+
}).config.system.build.vm}
200
+
'';
201
+
})
202
+
+ /bin/launch-vm;
200
203
};
201
204
gomod2nix = {
202
205
type = "app";
···
257
260
imports = [./nix/modules/spindle.nix];
258
261
259
262
services.tangled-spindle.package = lib.mkDefault self.packages.${pkgs.system}.spindle;
260
-
};
261
-
nixosConfigurations.vm-x86_64 = import ./nix/vm.nix {
262
-
inherit self nixpkgs;
263
-
system = "x86_64-linux";
264
-
};
265
-
nixosConfigurations.vm-aarch64 = import ./nix/vm.nix {
266
-
inherit self nixpkgs;
267
-
system = "aarch64-linux";
268
263
};
269
264
};
270
265
}
+54
-16
nix/vm.nix
+54
-16
nix/vm.nix
···
1
1
{
2
2
nixpkgs,
3
3
system,
4
+
hostSystem,
4
5
self,
5
6
}: let
6
7
envVar = name: let
···
16
17
self.nixosModules.knot
17
18
self.nixosModules.spindle
18
19
({
20
+
lib,
19
21
config,
20
22
pkgs,
21
23
...
22
24
}: {
23
-
nixos-shell = {
24
-
inheritPath = false;
25
-
mounts = {
26
-
mountHome = false;
27
-
mountNixProfile = false;
28
-
};
29
-
};
30
-
virtualisation = {
25
+
virtualisation.vmVariant.virtualisation = {
26
+
host.pkgs = import nixpkgs {system = hostSystem;};
27
+
28
+
graphics = false;
31
29
memorySize = 2048;
32
30
diskSize = 10 * 1024;
33
31
cores = 2;
···
51
49
guest.port = 6555;
52
50
}
53
51
];
52
+
sharedDirectories = {
53
+
# We can't use the 9p mounts directly for most of these
54
+
# as SQLite is incompatible with them. So instead we
55
+
# mount the shared directories to a different location
56
+
# and copy the contents around on service start/stop.
57
+
knotData = {
58
+
source = "$TANGLED_VM_DATA_DIR/knot";
59
+
target = "/mnt/knot-data";
60
+
};
61
+
spindleData = {
62
+
source = "$TANGLED_VM_DATA_DIR/spindle";
63
+
target = "/mnt/spindle-data";
64
+
};
65
+
spindleLogs = {
66
+
source = "$TANGLED_VM_DATA_DIR/spindle-logs";
67
+
target = "/var/log/spindle";
68
+
};
69
+
};
54
70
};
71
+
# This is fine because any and all ports that are forwarded to host are explicitly marked above, we don't need a separate guest firewall
72
+
networking.firewall.enable = false;
55
73
services.getty.autologinUser = "root";
56
74
environment.systemPackages = with pkgs; [curl vim git sqlite litecli];
57
-
systemd.tmpfiles.rules = let
58
-
u = config.services.tangled-knot.gitUser;
59
-
g = config.services.tangled-knot.gitUser;
60
-
in [
61
-
"d /var/lib/knot 0770 ${u} ${g} - -" # Create the directory first
62
-
"f+ /var/lib/knot/secret 0660 ${u} ${g} - KNOT_SERVER_SECRET=${envVar "TANGLED_VM_KNOT_SECRET"}"
63
-
];
64
75
services.tangled-knot = {
65
76
enable = true;
66
77
motd = "Welcome to the development knot!\n";
67
78
server = {
68
-
secretFile = "/var/lib/knot/secret";
79
+
secretFile = builtins.toFile "knot-secret" ("KNOT_SERVER_SECRET=" + (envVar "TANGLED_VM_KNOT_SECRET"));
69
80
hostname = "localhost:6000";
70
81
listenAddr = "0.0.0.0:6000";
71
82
};
···
81
92
provider = "sqlite";
82
93
};
83
94
};
95
+
};
96
+
users = {
97
+
# So we don't have to deal with permission clashing between
98
+
# blank disk VMs and existing state
99
+
users.${config.services.tangled-knot.gitUser}.uid = 666;
100
+
groups.${config.services.tangled-knot.gitUser}.gid = 666;
101
+
102
+
# TODO: separate spindle user
103
+
};
104
+
systemd.services = let
105
+
mkDataSyncScripts = source: target: {
106
+
enableStrictShellChecks = true;
107
+
108
+
preStart = lib.mkBefore ''
109
+
mkdir -p ${target}
110
+
${lib.getExe pkgs.rsync} -a ${source}/ ${target}
111
+
'';
112
+
113
+
postStop = lib.mkAfter ''
114
+
${lib.getExe pkgs.rsync} -a ${target}/ ${source}
115
+
'';
116
+
117
+
serviceConfig.PermissionsStartOnly = true;
118
+
};
119
+
in {
120
+
knot = mkDataSyncScripts "/mnt/knot-data" config.services.tangled-knot.stateDir;
121
+
spindle = mkDataSyncScripts "/mnt/spindle-data" (builtins.dirOf config.services.tangled-spindle.server.dbPath);
84
122
};
85
123
})
86
124
];