this repo has no description
1{
2 nixpkgs,
3 system,
4 hostSystem,
5 self,
6}: let
7 envVar = name: let
8 var = builtins.getEnv name;
9 in
10 if var == ""
11 then throw "\$${name} must be defined, see https://docs.tangled.org/hacking-on-tangled.html#hacking-on-tangled for more details"
12 else var;
13 envVarOr = name: default: let
14 var = builtins.getEnv name;
15 in
16 if var != ""
17 then var
18 else default;
19
20 plcUrl = envVarOr "TANGLED_VM_PLC_URL" "https://plc.directory";
21 jetstream = envVarOr "TANGLED_VM_JETSTREAM_ENDPOINT" "wss://jetstream1.us-west.bsky.network/subscribe";
22 relayUrl = envVarOr "TANGLED_VM_RELAY_URL" "https://relay1.us-east.bsky.network";
23in
24 nixpkgs.lib.nixosSystem {
25 inherit system;
26 modules = [
27 self.nixosModules.knot
28 self.nixosModules.spindle
29 ({
30 lib,
31 config,
32 pkgs,
33 ...
34 }: {
35 virtualisation.vmVariant.virtualisation = {
36 host.pkgs = import nixpkgs {system = hostSystem;};
37
38 graphics = false;
39 memorySize = 2048;
40 diskSize = 10 * 1024;
41 cores = 2;
42 forwardPorts = [
43 # ssh
44 {
45 from = "host";
46 host.port = 2222;
47 guest.port = 22;
48 }
49 # knot
50 {
51 from = "host";
52 host.port = 6444;
53 guest.port = 6444;
54 }
55 # spindle
56 {
57 from = "host";
58 host.port = 6555;
59 guest.port = 6555;
60 }
61 {
62 from = "host";
63 host.port = 6556;
64 guest.port = 2480;
65 }
66 ];
67 sharedDirectories = {
68 # We can't use the 9p mounts directly for most of these
69 # as SQLite is incompatible with them. So instead we
70 # mount the shared directories to a different location
71 # and copy the contents around on service start/stop.
72 knotData = {
73 source = "$TANGLED_VM_DATA_DIR/knot";
74 target = "/mnt/knot-data";
75 };
76 spindleData = {
77 source = "$TANGLED_VM_DATA_DIR/spindle";
78 target = "/mnt/spindle-data";
79 };
80 spindleLogs = {
81 source = "$TANGLED_VM_DATA_DIR/spindle-logs";
82 target = "/var/log/spindle";
83 };
84 };
85 };
86 # 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
87 networking.firewall.enable = false;
88 time.timeZone = "Europe/London";
89 services.getty.autologinUser = "root";
90 environment.systemPackages = with pkgs; [curl vim git sqlite litecli];
91 services.tangled.knot = {
92 enable = true;
93 motd = "Welcome to the development knot!\n";
94 server = {
95 owner = envVar "TANGLED_VM_KNOT_OWNER";
96 hostname = envVarOr "TANGLED_VM_KNOT_HOST" "localhost:6444";
97 plcUrl = plcUrl;
98 jetstreamEndpoint = jetstream;
99 listenAddr = "0.0.0.0:6444";
100 };
101 };
102 services.tangled.spindle = {
103 enable = true;
104 atpRelayUrl = relayUrl;
105 server = {
106 owner = envVar "TANGLED_VM_SPINDLE_OWNER";
107 hostname = envVarOr "TANGLED_VM_SPINDLE_HOST" "localhost:6555";
108 plcUrl = plcUrl;
109 listenAddr = "0.0.0.0:6555";
110 dev = true;
111 queueSize = 100;
112 maxJobCount = 2;
113 secrets = {
114 provider = "sqlite";
115 };
116 };
117 };
118 users = {
119 # So we don't have to deal with permission clashing between
120 # blank disk VMs and existing state
121 users.${config.services.tangled.knot.gitUser}.uid = 666;
122 groups.${config.services.tangled.knot.gitUser}.gid = 666;
123
124 # TODO: separate spindle user
125 };
126 systemd.services = let
127 mkDataSyncScripts = source: target: {
128 enableStrictShellChecks = true;
129
130 preStart = lib.mkBefore ''
131 mkdir -p ${target}
132 ${lib.getExe pkgs.rsync} -a ${source}/ ${target}
133 '';
134
135 postStop = lib.mkAfter ''
136 ${lib.getExe pkgs.rsync} -a ${target}/ ${source}
137 '';
138
139 serviceConfig.PermissionsStartOnly = true;
140 };
141 in {
142 knot = mkDataSyncScripts "/mnt/knot-data" config.services.tangled.knot.stateDir;
143 spindle = mkDataSyncScripts "/mnt/spindle-data" config.services.tangled.spindle.server.stateDir;
144 };
145 })
146 ];
147 }