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.