ALPHA: wire is a tool to deploy nixos systems wire.althaea.zone/
1--- 2comment: true 3title: Basic Hive & Deployment 4description: Creating a basic hive and deploying changes to the virtual machine. 5--- 6 7# Basic Hive & Deployment 8 9{{ $frontmatter.description }} 10 11## Editing `hive.nix` 12 13Open a text editor and edit `hive.nix`. You should copy this example, which imports 14the npins sources we added. It also calls `makeHive`, and gives wire `nixpkgs` 15from npins as well. 16 17```nix:line-numbers [hive.nix] 18let 19 # import npins sources 20 sources = import ./npins; 21 # import `wire` from npins sources 22 wire = import sources.wire; 23in 24wire.makeHive { 25 # give wire nixpkgs from npins 26 meta.nixpkgs = import sources.nixpkgs { }; 27 28 # we'll edit this part 29} 30``` 31 32Lets check out what wire sees with `wire show`. 33 34```sh 35[nix-shell]$ wire show 36 INFO eval_hive: evaluating hive HiveNix("/home/marsh/scratch/wire-tutorial/hive.nix") 37 WARN use --json to output something scripting suitable 38Summary: 0 total node(s), totalling 0 keys (0 distinct). 39Note: Listed connections are tried from Left to Right 40 41``` 42 43The line `nodes: {}` means there is no "nodes" in our hive. 44 45## Adding The First Node 46 47Lets add the virtual machine as a node to the hive with the name 48`virtual-machine`. Additionally, we will add `deployment.target`, recalling we 49forwarded sshd `virtual-machine:22` to the port `localhost:2222`: 50 51```nix:line-numbers [hive.nix] 52let 53 sources = import ./npins; 54 wire = import sources.wire; 55in 56wire.makeHive { 57 meta.nixpkgs = import sources.nixpkgs { }; 58 59 virtual-machine = { pkgs, ... }: { # [!code ++] 60 deployment.target = { # [!code ++] 61 port = 2222; # [!code ++] 62 hosts = [ "localhost" ]; # [!code ++] 63 }; # [!code ++] 64 65 nixpkgs.hostPlatform = "x86_64-linux"; # [!code ++] 66 }; # [!code ++] 67} 68``` 69 70## A naive `wire apply` 71 72If we tried to run `wire apply` on our hive at this stage, it likely won't work. 73If you've used NixOS before, you'll notice that many important options are 74missing. But let's try anyway: 75 76```sh 77[nix-shell]$ wire apply 78ERROR apply{goal=Switch on=}:goal{node=virtual-machine}: lib::hive::node: Failed to execute `Evaluate the node` 79Error: × 1 node(s) failed to apply. 80 81Error: 82 × node virtual-machine failed to apply 83 ├─▶ wire::Evaluate 84 85 │ × failed to evaluate `--file /home/marsh/scratch/wire-tutorial/hive.nix topLevels.virtual-machine` from the context 86 │ │ of a hive. 87 88 ╰─▶ nix --extra-experimental-features nix-command --extra-experimental-features flakes eval --json --file /home/marsh/scratch/ 89 wire-tutorial/hive.nix topLevels.virtual-machine --log-format internal-json failed (reason: known-status) with code 1 (last 20 90 lines): 91 error: 92 … while evaluating '(evaluateNode node).config.system.build.toplevel' to select 'drvPath' on it 93 at /nix/store/5pfz0v479gnciac17rcqi2gwyz8pl4s0-source/runtime/evaluate.nix:65:23: 94 64| 95 65| getTopLevel = node: (evaluateNode node).config.system.build.toplevel.drvPath; 96 | ^ 97 66| in 98 99 … while calling the 'head' builtin 100 at /nix/store/n3d1ricw0cb5jd8vvfym6ig0mw7x7sv9-source/lib/attrsets.nix:1701:13: 101 1700| if length values == 1 || pred here (elemAt values 1) (head values) then 102 1701| head values 103 | ^ 104 1702| else 105 106 (stack trace truncated; use '--show-trace' to show the full trace) 107 108 error: 109 Failed assertions: 110 - The ‘fileSystems’ option does not specify your root file system. 111 - You must set the option ‘boot.loader.grub.devices’ or 'boot.loader.grub.mirroredBoots' to make the system bootable. 112 trace: evaluation warning: system.stateVersion is not set, defaulting to 25.11. Read why this matters on https://nixos.org/ 113 manual/nixos/stable/options.html#opt-system.stateVersion. 114 115``` 116 117The command complained about not defining any fileSystems or a boot loader. 118The `${sources.nixpkgs}/nixos/modules/virtualisation/qemu-vm.nix` imported in 119`vm.nix` does 120extra work to make our virtual machine work, which we are currently missing. 121 122## Importing `vm.nix` 123 124Lets import our `vm.nix` to this hive to fix our evaluation errors. 125Additionally, add a new package such as `vim` to our configuration: 126 127```nix:line-numbers [hive.nix] 128let 129 sources = import ./npins; 130 wire = import sources.wire; 131in 132wire.makeHive { 133 meta.nixpkgs = import sources.nixpkgs { }; 134 135 virtual-machine = { pkgs, ... }: { 136 deployment.target = { 137 port = 2222; 138 hosts = [ "localhost" ]; 139 }; 140 141 imports = [ # [!code ++] 142 ./vm.nix # [!code ++] 143 ]; # [!code ++] 144 145 environment.systemPackages = [ pkgs.vim ]; # [!code ++] 146 147 nixpkgs.hostPlatform = "x86_64-linux"; 148 }; 149} 150``` 151 152## Our first deploy 153 154Trying our basic `wire apply` again with these changes: 155 156```sh 157[nix-shell]$ wire apply 158... 159 INFO lib::nix_log: stopping the following units: boot.mount 160 INFO lib::nix_log: NOT restarting the following changed units: systemd-fsck@dev-disk-by\x2dlabel-ESP.service 161 INFO lib::nix_log: activating the configuration... 162 INFO lib::nix_log: setting up /etc... 163 INFO lib::nix_log: restarting systemd... 164 INFO lib::nix_log: reloading user units for root... 165 INFO lib::nix_log: restarting sysinit-reactivation.target 166 INFO lib::nix_log: reloading the following units: dbus.service 167 INFO lib::nix_log: the following new units were started: boot.automount, sysinit-reactivation.target, systemd-tmpfiles-resetup.service 168 INFO apply{goal=Switch on=}:goal{node=virtual-machines}: lib::hive::node: Executing step `Upload key @ PostActivation` 169 INFO apply{goal=Switch on=}: wire::apply: Successfully applied goal to 1 node(s): [Name("virtual-machines")] 170``` 171 172Now, lets confirm these changes were applied to the virtual machine by executing 173`vim` in the virtual machine window: 174 175```sh [Virtual Machine] 176[root@wire-tutorial:~]# vim --version 177VIM - Vi IMproved 9.1 (2024 Jan 02, compiled Jan 01 1980 00:00:00) 178``` 179 180Nice! You successfully deployed a new NixOS configuration to a **remote host**! 181 182::: info 183This followed common steps of adding the node's `deployment.target` details and 184importing it's pre-existing NixOS configuration (in this case, `vm.nix`), a 185pattern you'll be using a lot if you chose to adopt wire. 186::: 187 188In the next section, we'll cover how to deploy secrets / keys to our remote node.