@a11ign/screenreader-fleet 0.0.0-reserved.0 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +94 -2
- package/dist/capture-client.d.mts +49 -0
- package/dist/capture-client.d.mts.map +1 -0
- package/dist/capture-client.mjs +352 -0
- package/dist/capture-client.mjs.map +1 -0
- package/dist/check-worker-code.d.mts +34 -0
- package/dist/check-worker-code.d.mts.map +1 -0
- package/dist/check-worker-code.mjs +173 -0
- package/dist/check-worker-code.mjs.map +1 -0
- package/dist/cli-flags.d.mts +71 -0
- package/dist/cli-flags.d.mts.map +1 -0
- package/dist/cli-flags.mjs +207 -0
- package/dist/cli-flags.mjs.map +1 -0
- package/dist/code-drift.d.mts +140 -0
- package/dist/code-drift.d.mts.map +1 -0
- package/dist/code-drift.mjs +284 -0
- package/dist/code-drift.mjs.map +1 -0
- package/dist/command-line-census.d.mts +33 -0
- package/dist/command-line-census.d.mts.map +1 -0
- package/dist/command-line-census.mjs +96 -0
- package/dist/command-line-census.mjs.map +1 -0
- package/dist/compare-workers.d.mts +3 -0
- package/dist/compare-workers.d.mts.map +1 -0
- package/dist/compare-workers.mjs +332 -0
- package/dist/compare-workers.mjs.map +1 -0
- package/dist/control-plane-isolation.d.mts +45 -0
- package/dist/control-plane-isolation.d.mts.map +1 -0
- package/dist/control-plane-isolation.mjs +67 -0
- package/dist/control-plane-isolation.mjs.map +1 -0
- package/dist/deploy-worker.d.mts +3 -0
- package/dist/deploy-worker.d.mts.map +1 -0
- package/dist/deploy-worker.mjs +333 -0
- package/dist/deploy-worker.mjs.map +1 -0
- package/dist/doctor.d.mts +216 -0
- package/dist/doctor.d.mts.map +1 -0
- package/dist/doctor.mjs +962 -0
- package/dist/doctor.mjs.map +1 -0
- package/dist/fleet-consistency.d.mts +235 -0
- package/dist/fleet-consistency.d.mts.map +1 -0
- package/dist/fleet-consistency.mjs +436 -0
- package/dist/fleet-consistency.mjs.map +1 -0
- package/dist/fleet-env.d.mts +228 -0
- package/dist/fleet-env.d.mts.map +1 -0
- package/dist/fleet-env.mjs +509 -0
- package/dist/fleet-env.mjs.map +1 -0
- package/dist/fleet-scripts.d.mts +11 -0
- package/dist/fleet-scripts.d.mts.map +1 -0
- package/dist/fleet-scripts.mjs +41 -0
- package/dist/fleet-scripts.mjs.map +1 -0
- package/dist/git-safe-env.d.mts +10 -0
- package/dist/git-safe-env.d.mts.map +1 -0
- package/dist/git-safe-env.mjs +44 -0
- package/dist/git-safe-env.mjs.map +1 -0
- package/dist/guest-run.d.mts +26 -0
- package/dist/guest-run.d.mts.map +1 -0
- package/dist/guest-run.mjs +164 -0
- package/dist/guest-run.mjs.map +1 -0
- package/dist/host-address.d.mts +33 -0
- package/dist/host-address.d.mts.map +1 -0
- package/dist/host-address.mjs +105 -0
- package/dist/host-address.mjs.map +1 -0
- package/dist/host-capacity.d.mts +64 -0
- package/dist/host-capacity.d.mts.map +1 -0
- package/dist/host-capacity.mjs +152 -0
- package/dist/host-capacity.mjs.map +1 -0
- package/dist/host-metrics.d.mts +116 -0
- package/dist/host-metrics.d.mts.map +1 -0
- package/dist/host-metrics.mjs +201 -0
- package/dist/host-metrics.mjs.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/local-vm.d.ts +125 -0
- package/dist/local-vm.d.ts.map +1 -0
- package/dist/local-vm.js +360 -0
- package/dist/local-vm.js.map +1 -0
- package/dist/measure-guard.d.mts +34 -0
- package/dist/measure-guard.d.mts.map +1 -0
- package/dist/measure-guard.mjs +73 -0
- package/dist/measure-guard.mjs.map +1 -0
- package/dist/normalise-fleet.d.mts +2 -0
- package/dist/normalise-fleet.d.mts.map +1 -0
- package/dist/normalise-fleet.mjs +76 -0
- package/dist/normalise-fleet.mjs.map +1 -0
- package/dist/npm-cli-executable.d.mts +42 -0
- package/dist/npm-cli-executable.d.mts.map +1 -0
- package/dist/npm-cli-executable.mjs +159 -0
- package/dist/npm-cli-executable.mjs.map +1 -0
- package/dist/probe-outcome.d.mts +89 -0
- package/dist/probe-outcome.d.mts.map +1 -0
- package/dist/probe-outcome.mjs +104 -0
- package/dist/probe-outcome.mjs.map +1 -0
- package/dist/protocol-guard.d.mts +34 -0
- package/dist/protocol-guard.d.mts.map +1 -0
- package/dist/protocol-guard.mjs +121 -0
- package/dist/protocol-guard.mjs.map +1 -0
- package/dist/source-walk.d.mts +12 -0
- package/dist/source-walk.d.mts.map +1 -0
- package/dist/source-walk.mjs +56 -0
- package/dist/source-walk.mjs.map +1 -0
- package/dist/transient-fault.d.mts +6 -0
- package/dist/transient-fault.d.mts.map +1 -0
- package/dist/transient-fault.mjs +86 -0
- package/dist/transient-fault.mjs.map +1 -0
- package/dist/utm-deprecated.d.mts +6 -0
- package/dist/utm-deprecated.d.mts.map +1 -0
- package/dist/utm-deprecated.mjs +23 -0
- package/dist/utm-deprecated.mjs.map +1 -0
- package/dist/worker-code-check.d.mts +29 -0
- package/dist/worker-code-check.d.mts.map +1 -0
- package/dist/worker-code-check.mjs +78 -0
- package/dist/worker-code-check.mjs.map +1 -0
- package/dist/worker-health.d.mts +56 -0
- package/dist/worker-health.d.mts.map +1 -0
- package/dist/worker-health.mjs +73 -0
- package/dist/worker-health.mjs.map +1 -0
- package/dist/worker-http.d.mts +103 -0
- package/dist/worker-http.d.mts.map +1 -0
- package/dist/worker-http.mjs +277 -0
- package/dist/worker-http.mjs.map +1 -0
- package/dist/worker-stats.d.mts +66 -0
- package/dist/worker-stats.d.mts.map +1 -0
- package/dist/worker-stats.mjs +143 -0
- package/dist/worker-stats.mjs.map +1 -0
- package/package.json +96 -4
- package/src/local-worker/autounattend.xml +280 -0
- package/src/local-worker/build-vm.sh +218 -0
- package/src/local-worker/clone-worker.sh +141 -0
- package/src/local-worker/create-utm-vm.sh +202 -0
- package/src/local-worker/fetch-windows-iso.sh +238 -0
- package/src/local-worker/first-boot.cmd +58 -0
- package/src/local-worker/worker-ctl.sh +442 -0
- package/src/provisioning/README.md +28 -0
- package/src/provisioning/apply-foreground-lock-timeout.ps1 +71 -0
- package/src/provisioning/bare-metal/README.md +213 -0
- package/src/provisioning/bare-metal/a11y-bootstrap.service +58 -0
- package/src/provisioning/bare-metal/autounattend.xml +428 -0
- package/src/provisioning/bare-metal/serve-bootstrap.sh +86 -0
- package/src/provisioning/bootstrap-control-plane.sh +463 -0
- package/src/provisioning/bootstrap-windows-worker.ps1 +649 -0
- package/src/provisioning/build-lean-worker-image.ps1 +275 -0
- package/src/provisioning/diagnose-nvda-worker.ps1 +174 -0
- package/src/provisioning/provision-nvda-worker.ps1 +827 -0
- package/src/provisioning/set-display-mode.ps1 +411 -0
- package/src/provisioning/stamp-provision-revision.ps1 +184 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# Zero-touch worker install (bare metal, x64)
|
|
2
|
+
|
|
3
|
+
PXE-boot a mini PC and it joins the fleet: Windows installs, `witness` logs in, sshd comes up with your
|
|
4
|
+
key already installed, and the worker serves `/health`. **No console visit.**
|
|
5
|
+
|
|
6
|
+
**This path is for this project's own fleet, not for an outside contributor.** It PXE-boots against
|
|
7
|
+
infrastructure only this project runs — Proxmox CT 110 `iventoy-pxe`, the fleet-control container
|
|
8
|
+
serving the bootstrap payload below, and `inventory.yml`/`ansible.cfg` wiring that live outside this
|
|
9
|
+
checkout. A stranger with a spare Windows box and none of that cannot follow this start to finish; they
|
|
10
|
+
would need to first stand up equivalent PXE/control-plane infrastructure of their own, which nothing
|
|
11
|
+
here asks them to do because it isn't written for that reader. If that's you, see
|
|
12
|
+
[`../README.md`](../README.md) for the routes that are: your own Windows machine
|
|
13
|
+
(`bootstrap-windows-worker.ps1`) or the GitHub Action (no machine at all).
|
|
14
|
+
|
|
15
|
+
## Detach the network until first boot has pinned Edge
|
|
16
|
+
|
|
17
|
+
**Learned on a11y-worker-7, 2026-09-04, and it cost a reimage.** Nothing in first boot mentioned Edge
|
|
18
|
+
until then. The box installed Windows, came up with a network, and Edge updated itself to 152 while
|
|
19
|
+
`npm install` was still running. `roles/worker/tasks/edge-version.yml` then refused, correctly:
|
|
20
|
+
|
|
21
|
+
> a11y-worker-7 is on Edge 152.0.4191.62, NEWER than the pinned 151.0.4129.107. Chromium will not install
|
|
22
|
+
> over a newer build and Windows will not let it be uninstalled, so this role cannot bring it back.
|
|
23
|
+
|
|
24
|
+
`browserVersion` is FIRST in `fleet-consistency`'s MUST_MATCH list and part of the capture cache key, so a
|
|
25
|
+
box on a different Edge build does not merely underperform — **every capture run refuses to start, on
|
|
26
|
+
every box.** The only remedies are reimaging that one machine or moving the pin and recapturing the whole
|
|
27
|
+
corpus.
|
|
28
|
+
|
|
29
|
+
Bootstrap step 5 now stops the Edge updater and installs the pinned build, and it runs BEFORE the handoff
|
|
30
|
+
to provisioning. That closes the window in the normal case. It cannot close it entirely: the box needs a
|
|
31
|
+
network for step 3 to fetch the payload, and Edge can begin updating in the minutes before step 5 lands.
|
|
32
|
+
|
|
33
|
+
So on a slow box, or one that sat at the desktop before you got to it, **check before assuming**:
|
|
34
|
+
|
|
35
|
+
```powershell
|
|
36
|
+
(Get-Item 'C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe').VersionInfo.ProductVersion
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Newer than the pin means reimage now, while it is cheap. Step 5 says so itself rather than trying and
|
|
40
|
+
reporting success.
|
|
41
|
+
|
|
42
|
+
## How a box gets installed, end to end
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
PXE -> iVentoy serves the Windows ISO + autounattend.xml
|
|
46
|
+
-> Windows installs unattended, creates `witness`, auto-logs on
|
|
47
|
+
-> FirstLogonCommands fetches 3 files over HTTP from the control plane
|
|
48
|
+
-> first-boot.cmd waits for DHCP, stages the key, runs bootstrap elevated
|
|
49
|
+
-> bootstrap installs node/git/sshd, sets DefaultShell, installs the operator key
|
|
50
|
+
-> the box is reachable by Ansible. No console visit after the firmware step.
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 1. At the machine, once — do both while you are there
|
|
54
|
+
|
|
55
|
+
Nothing can automate this: the box is off and has no OS to ask.
|
|
56
|
+
|
|
57
|
+
- **Enable Wake-on-LAN** in firmware. Usually under Power Management; may be called *Wake on LAN/WLAN*,
|
|
58
|
+
*Power On By PCIe*, or *Resume by PCI-E Device*. On HP and Dell business desktops **Deep Sleep must
|
|
59
|
+
also be disabled** — it cuts the NIC's standby power and silently defeats WoL.
|
|
60
|
+
- **Note the MAC.** It goes in `inventory.yml` and is the one fact about a box that cannot be discovered
|
|
61
|
+
while it is off.
|
|
62
|
+
- Set it to network-boot.
|
|
63
|
+
|
|
64
|
+
### 2. On the control plane, serve the payload
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
./serve-bootstrap.sh ~/.ssh/<fleet key filename>.pub # port 8099
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
It refuses a private key, and it is not a service — Ctrl-C when the box is up.
|
|
71
|
+
|
|
72
|
+
### 3. In iVentoy
|
|
73
|
+
|
|
74
|
+
The PXE server is **Proxmox CT 110 `iventoy-pxe`** (address in `inventory.yml`), web UI on `:26000`.
|
|
75
|
+
|
|
76
|
+
Point the Windows 11 x64 ISO's **Auto Install Script** at this directory's `autounattend.xml`, and set a
|
|
77
|
+
non-zero boot timeout so the install starts without a keypress.
|
|
78
|
+
|
|
79
|
+
**Check the PXE service is started** — the container running is not the same as the service running, and
|
|
80
|
+
with it stopped a machine set to network-boot finds nothing at all, which looks exactly like a firmware
|
|
81
|
+
boot-order mistake and is not one.
|
|
82
|
+
|
|
83
|
+
Ask iVentoy, do not probe the port:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
curl -s -X POST -H 'Content-Type: application/json' \
|
|
87
|
+
-d '{"method":"query_status"}' http://<the pxe host>:26000/iventoy/json # {"status": "running"}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**TFTP is UDP.** A TCP connect to port 69 fails whether the service is up or down, so it cannot
|
|
91
|
+
distinguish the two — which is this repo's recurring rule (a check that shares a failure mode with the
|
|
92
|
+
thing it checks verifies nothing) in its cheapest possible form. It was got wrong here first time and
|
|
93
|
+
reported a running server as stopped. `nc -zvu` is the port-level check if you want one; `query_status`
|
|
94
|
+
is better, because it asks the service rather than the socket.
|
|
95
|
+
|
|
96
|
+
The same endpoint drives the rest: `start_server`, `stop_server`, `sys_ip_list`, `get_img_tree`,
|
|
97
|
+
`img_add_auto_script`, `img_set_auto_id`, `img_set_auto_timeout`.
|
|
98
|
+
|
|
99
|
+
**Check the address in `autounattend.xml`.** It has `http://<fleet-control host>:8099` baked in, and that must be
|
|
100
|
+
the machine running `serve-bootstrap.sh`.
|
|
101
|
+
|
|
102
|
+
That address is the **fleet-control container**, not the iVentoy host, and the reason is that
|
|
103
|
+
`serve-bootstrap.sh` needs two things that live there and nowhere else: the repo (it copies
|
|
104
|
+
`first-boot.cmd` and `bootstrap-windows-worker.ps1` out of the checkout) and the fleet public key. Serving
|
|
105
|
+
from the PXE host instead would mean cloning the repo onto it and copying a key across, which puts fleet
|
|
106
|
+
material on a second box to save nothing. Both are on the same bridge, so a machine that can PXE-boot from
|
|
107
|
+
one can certainly fetch three files over HTTP from the other.
|
|
108
|
+
|
|
109
|
+
### Why the files are fetched rather than injected
|
|
110
|
+
|
|
111
|
+
iVentoy's file injection decompresses into **`X:`** — the WinPE RAM disk, which is gone by the time
|
|
112
|
+
`FirstLogonCommands` runs. The UTM path can scan drive letters because its support ISO stays attached;
|
|
113
|
+
nothing stays attached here. Rebuilding the install ISO to carry the files is the other option, and this
|
|
114
|
+
project has already spent a day on El Torito boot catalogues and `0xc0000225` to earn the opinion that it
|
|
115
|
+
is not worth it for three small files.
|
|
116
|
+
|
|
117
|
+
### 4. Then, entirely remotely
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
npm run fleet:discover -- --enroll # finds the box, reads its MAC from ARP, adds it
|
|
121
|
+
cd ../../../ansible
|
|
122
|
+
ansible a11y_workers -m ansible.windows.win_ping -l a11y-worker-N
|
|
123
|
+
ansible-playbook provision-role.yml -l a11y-worker-N --check --diff
|
|
124
|
+
ansible-playbook provision-role.yml -l a11y-worker-N
|
|
125
|
+
ansible-playbook sleep.yml -l a11y-worker-N && ansible-playbook wake.yml -l a11y-worker-N
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
That last line is the point of the firmware step: WoL is only really verified by powering a box down and
|
|
129
|
+
getting it back, and it is far better to find a wrong firmware setting while you are still next to the
|
|
130
|
+
machine.
|
|
131
|
+
|
|
132
|
+
## Four things this file does differently from the UTM one, and why
|
|
133
|
+
|
|
134
|
+
The sibling at `../../local-worker/autounattend.xml` is the proven recipe. This is that recipe on real
|
|
135
|
+
hardware and a real network, and the differences are not cosmetic:
|
|
136
|
+
|
|
137
|
+
- **No plaintext password.** The arm64 file embeds `witness`/`witness` and justifies it as *"a disposable
|
|
138
|
+
local VM behind QEMU user-mode networking"*. None of that is true of a mini PC on your LAN. The account
|
|
139
|
+
is created **blank** instead, which `LimitBlankPasswordUse=1` confines to console logon — no SMB, no
|
|
140
|
+
RDP, no password SSH. Strictly narrower than a password, and nothing secret is committed.
|
|
141
|
+
- **No VirtIO drivers.** Those paths point at UTM's support ISO; real hardware has inbox drivers, and
|
|
142
|
+
leaving them in fails the windowsPE pass looking for a drive that is not there.
|
|
143
|
+
- **`ComputerName` is `*`.** Twelve machines answering to `A11Y-WORKER` is a NetBIOS conflict. Workers are
|
|
144
|
+
addressed by IP from the inventory anyway.
|
|
145
|
+
- **The TPM/CPU bypasses are load-bearing, not a VM workaround.** The 6th- and 7th-gen boxes in this fleet
|
|
146
|
+
are not on Windows 11's supported-CPU list and Setup refuses them without these.
|
|
147
|
+
|
|
148
|
+
## It installs on unsupported hardware, deliberately
|
|
149
|
+
|
|
150
|
+
The fleet is second-hand mini PCs, and several generations of them are not on Windows 11's supported-CPU
|
|
151
|
+
list at all. The bypasses are therefore load-bearing rather than a lab convenience, and they are applied
|
|
152
|
+
in **two places**, because one is not enough:
|
|
153
|
+
|
|
154
|
+
| where | what it covers |
|
|
155
|
+
|---|---|
|
|
156
|
+
| `windowsPE` → `HKLM\System\Setup\LabConfig` | the install itself: CPU, TPM, Secure Boot, RAM, storage |
|
|
157
|
+
| `specialize` → `HKLM\SYSTEM\Setup\LabConfig` + `MoSetup` | the INSTALLED system, so later feature updates do not refuse |
|
|
158
|
+
|
|
159
|
+
The second one is the easy thing to miss. The WinPE keys live in the installer's registry and do not
|
|
160
|
+
survive into the running OS, so a box installs happily and then, months later on a machine nobody is
|
|
161
|
+
watching, declines a feature update with "this PC doesn't meet the minimum requirements".
|
|
162
|
+
`AllowUpgradesWithUnsupportedTPMOrCPU` under `MoSetup` is what covers the upgrade path specifically.
|
|
163
|
+
|
|
164
|
+
Two names, deliberately both: `BypassStorageCheck` is what Setup reads; `BypassDiskCheck` was inherited
|
|
165
|
+
from the arm64 file and appears in no Microsoft documentation. An ignored registry value costs nothing
|
|
166
|
+
and a missing one costs the install, so both are written.
|
|
167
|
+
|
|
168
|
+
`BypassNRO` removes 24H2's "connect to the internet and sign in with a Microsoft account" wall at OOBE.
|
|
169
|
+
`HideOnlineAccountScreens` plus a local account usually carries it — but *usually* is not a property you
|
|
170
|
+
want on a fleet whose screens you cannot see.
|
|
171
|
+
|
|
172
|
+
## It wipes disk 0 without asking
|
|
173
|
+
|
|
174
|
+
That is what makes it hands-off, and it is why the PXE entry serving this must be aimed at machines you
|
|
175
|
+
have set aside — not set as a default-for-everything boot option.
|
|
176
|
+
|
|
177
|
+
## The media is VERSIONED — refresh `autounattend.xml` before every install
|
|
178
|
+
|
|
179
|
+
This file is copied onto the boot media (iVentoy's auto-install script, or a Ventoy USB stick), so a
|
|
180
|
+
stick prepared once carries whatever this file said that day. It has been fixed **three times since the
|
|
181
|
+
fleet was built**, and each fix came from a real install that failed:
|
|
182
|
+
|
|
183
|
+
| | |
|
|
184
|
+
|---|---|
|
|
185
|
+
| `279e161` 15 Aug | aims the payload fetch at fleet-control (`<fleet-control host>:8099`) rather than the PXE host |
|
|
186
|
+
| `5d4b877` 15 Aug | the install asked for a locale the media does not carry |
|
|
187
|
+
| `4fff4c6` 23 Aug | the product key stopped matching the edition once `install.wim` was split |
|
|
188
|
+
|
|
189
|
+
**But do NOT reflash a stick that has installed boxes successfully, and the third row is why.**
|
|
190
|
+
|
|
191
|
+
The product-key fix is conditional on the MEDIA, not on the box. The generic KMS key worked while the ISO
|
|
192
|
+
shipped a single `install.wim`, and only began failing once `install.wim` was SPLIT into `install.swm`
|
|
193
|
+
parts to fit a file-size limit — Setup then validates the key against the edition it resolved from the
|
|
194
|
+
split image and the two disagree. A stick whose ISO is unsplit never meets that.
|
|
195
|
+
|
|
196
|
+
Measured on this fleet: all four workers first-booted between 15 and 16 August, at commits that are
|
|
197
|
+
ancestors of the 23 August fix. So they were installed WITH the KMS key and they installed fine, which is
|
|
198
|
+
positive evidence that stick's ISO is unsplit. The two 15 August fixes (locale, payload address) are
|
|
199
|
+
already in it.
|
|
200
|
+
|
|
201
|
+
So the honest rule is **check what changed and why, rather than refreshing on principle**. The current
|
|
202
|
+
file is the more portable one — no key at all works on split and unsplit media alike — but that
|
|
203
|
+
combination has been proven zero times on unsplit media, and the stick's has been proven four times.
|
|
204
|
+
Swapping a proven combination for an untested one, in the one phase of the process with no remote
|
|
205
|
+
diagnosis, is the wrong trade. Refresh when a fix applies to your media, or when you change the ISO.
|
|
206
|
+
|
|
207
|
+
`serve-bootstrap.sh` must be RUNNING on the control plane while the box installs: the media fetches three
|
|
208
|
+
files over HTTP and is not self-contained (see *Why the files are fetched rather than injected*).
|
|
209
|
+
|
|
210
|
+
This section previously read "Untested end to end — this x64 adaptation has not been PXE-booted yet."
|
|
211
|
+
That is stale: the three fixes above are what a real install produces, and the fleet is four boxes. It is
|
|
212
|
+
not a claim of a clean unattended run start to finish, which nobody has recorded. The place to look when
|
|
213
|
+
it stalls is still `C:\a11y-first-boot.log` on the box, written before anything else can fail.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# The bootstrap payload server, as a service on the control plane.
|
|
2
|
+
#
|
|
3
|
+
# Install (on fleet-control, as root):
|
|
4
|
+
#
|
|
5
|
+
# cp a11y-bootstrap.service /etc/systemd/system/
|
|
6
|
+
# systemctl daemon-reload && systemctl enable --now a11y-bootstrap
|
|
7
|
+
# systemctl status a11y-bootstrap
|
|
8
|
+
#
|
|
9
|
+
# ## Why this exists
|
|
10
|
+
#
|
|
11
|
+
# `serve-bootstrap.sh` used to be started by hand and stopped with Ctrl-C, which is fine for one install
|
|
12
|
+
# you are watching and wrong for a fleet meant to install itself. It was found running with PPID 1 and no
|
|
13
|
+
# unit: a reboot of this container would have removed it silently, and the NEXT box to install would have
|
|
14
|
+
# come up perfectly, logged on, retried three fetches sixty times each, given up after ~15 minutes, and sat
|
|
15
|
+
# at a working desktop with no node, no sshd, no key and no worker. From outside that reads as a bad image,
|
|
16
|
+
# and the only evidence is C:\a11y-first-boot.log on a machine you cannot SSH to. Hence Restart=always.
|
|
17
|
+
#
|
|
18
|
+
# ## The paths are this box's, deliberately
|
|
19
|
+
#
|
|
20
|
+
# `inventory.yml` hardcodes addresses for the same reason: there is one control plane, and a layer of
|
|
21
|
+
# indirection to make a single-instance path configurable buys nothing but a second place to be wrong.
|
|
22
|
+
# If the checkout or the key moves, edit them here.
|
|
23
|
+
#
|
|
24
|
+
# ## RESTART AFTER CHANGING THE PAYLOAD
|
|
25
|
+
#
|
|
26
|
+
# `serve-bootstrap.sh` copies first-boot.cmd and bootstrap-windows-worker.ps1 into a `mktemp -d` at START
|
|
27
|
+
# and serves that snapshot -- so a long-running service serves whatever the checkout held when it last
|
|
28
|
+
# started, not what it holds now. That is the one way this unit can be quietly wrong. After a `git pull`
|
|
29
|
+
# that touches either script:
|
|
30
|
+
#
|
|
31
|
+
# systemctl restart a11y-bootstrap
|
|
32
|
+
#
|
|
33
|
+
# ## It serves a PUBLIC key continuously
|
|
34
|
+
#
|
|
35
|
+
# The script's own header called it "a small exposure and a real one" and told you to Ctrl-C when the box
|
|
36
|
+
# was up. Running always widens that from minutes to permanently. It is a public key, and the two scripts
|
|
37
|
+
# are in this repo -- but this was a deliberate choice to trade that for installs that do not depend on
|
|
38
|
+
# somebody having remembered to start a server.
|
|
39
|
+
|
|
40
|
+
[Unit]
|
|
41
|
+
Description=a11ign worker bootstrap payload (first-boot.cmd, bootstrap script, operator public key)
|
|
42
|
+
Documentation=file:///root/a11y-witness/packages/worker-fleet/src/provisioning/bare-metal/README.md
|
|
43
|
+
After=network-online.target
|
|
44
|
+
Wants=network-online.target
|
|
45
|
+
|
|
46
|
+
[Service]
|
|
47
|
+
Type=simple
|
|
48
|
+
ExecStart=/root/a11y-witness/packages/worker-fleet/src/provisioning/bare-metal/serve-bootstrap.sh /root/.ssh/a11y-witness_ed25519.pub 8099
|
|
49
|
+
Restart=always
|
|
50
|
+
RestartSec=5
|
|
51
|
+
|
|
52
|
+
# The script refuses a private key and refuses a file that is not a public key, so a misconfigured
|
|
53
|
+
# ExecStart fails fast rather than serving the wrong thing. These stop it becoming anything more.
|
|
54
|
+
NoNewPrivileges=yes
|
|
55
|
+
PrivateTmp=yes
|
|
56
|
+
|
|
57
|
+
[Install]
|
|
58
|
+
WantedBy=multi-user.target
|