forked from tangled.org/core
Monorepo for Tangled — https://tangled.org
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 docs/hacking.md 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"; 22in 23 nixpkgs.lib.nixosSystem { 24 inherit system; 25 modules = [ 26 self.nixosModules.knot 27 self.nixosModules.spindle 28 ({ 29 lib, 30 config, 31 pkgs, 32 ... 33 }: { 34 virtualisation.vmVariant.virtualisation = { 35 host.pkgs = import nixpkgs {system = hostSystem;}; 36 37 graphics = false; 38 memorySize = 2048; 39 diskSize = 10 * 1024; 40 cores = 2; 41 forwardPorts = [ 42 # ssh 43 { 44 from = "host"; 45 host.port = 2222; 46 guest.port = 22; 47 } 48 # knot 49 { 50 from = "host"; 51 host.port = 6000; 52 guest.port = 6000; 53 } 54 # spindle 55 { 56 from = "host"; 57 host.port = 6555; 58 guest.port = 6555; 59 } 60 ]; 61 sharedDirectories = { 62 # We can't use the 9p mounts directly for most of these 63 # as SQLite is incompatible with them. So instead we 64 # mount the shared directories to a different location 65 # and copy the contents around on service start/stop. 66 knotData = { 67 source = "$TANGLED_VM_DATA_DIR/knot"; 68 target = "/mnt/knot-data"; 69 }; 70 spindleData = { 71 source = "$TANGLED_VM_DATA_DIR/spindle"; 72 target = "/mnt/spindle-data"; 73 }; 74 spindleLogs = { 75 source = "$TANGLED_VM_DATA_DIR/spindle-logs"; 76 target = "/var/log/spindle"; 77 }; 78 }; 79 }; 80 # 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 81 networking.firewall.enable = false; 82 services.dnsmasq.enable = true; 83 services.dnsmasq.settings.address = "/tngl.boltless.dev/10.0.2.2"; 84 security.pki.certificates = [ 85 (builtins.readFile ../local-infra/cert/localtangled/root.crt) 86 ]; 87 time.timeZone = "Europe/London"; 88 services.getty.autologinUser = "root"; 89 environment.systemPackages = with pkgs; [curl vim git sqlite litecli]; 90 services.tangled.knot = { 91 enable = true; 92 motd = "Welcome to the development knot!\n"; 93 server = { 94 owner = envVar "TANGLED_VM_KNOT_OWNER"; 95 hostname = envVarOr "TANGLED_VM_KNOT_HOST" "localhost:6000"; 96 plcUrl = plcUrl; 97 jetstreamEndpoint = jetstream; 98 listenAddr = "0.0.0.0:6000"; 99 }; 100 }; 101 services.tangled.spindle = { 102 enable = true; 103 server = { 104 owner = envVar "TANGLED_VM_SPINDLE_OWNER"; 105 hostname = envVarOr "TANGLED_VM_SPINDLE_OWNER" "localhost:6555"; 106 plcUrl = plcUrl; 107 jetstreamEndpoint = jetstream; 108 listenAddr = "0.0.0.0:6555"; 109 dev = true; 110 queueSize = 100; 111 maxJobCount = 2; 112 secrets = { 113 provider = "sqlite"; 114 }; 115 }; 116 }; 117 users = { 118 # So we don't have to deal with permission clashing between 119 # blank disk VMs and existing state 120 users.${config.services.tangled.knot.gitUser}.uid = 666; 121 groups.${config.services.tangled.knot.gitUser}.gid = 666; 122 123 # TODO: separate spindle user 124 }; 125 systemd.services = let 126 mkDataSyncScripts = source: target: { 127 enableStrictShellChecks = true; 128 129 preStart = lib.mkBefore '' 130 mkdir -p ${target} 131 ${lib.getExe pkgs.rsync} -a ${source}/ ${target} 132 ''; 133 134 postStop = lib.mkAfter '' 135 ${lib.getExe pkgs.rsync} -a ${target}/ ${source} 136 ''; 137 138 serviceConfig.PermissionsStartOnly = true; 139 }; 140 in { 141 knot = mkDataSyncScripts "/mnt/knot-data" config.services.tangled.knot.stateDir; 142 spindle = mkDataSyncScripts "/mnt/spindle-data" (builtins.dirOf config.services.tangled.spindle.server.dbPath); 143 }; 144 }) 145 ]; 146 }