Compare commits
No commits in common. "a78fbe1273f2b7e60deb2f638392eaaa87ea4579" and "92a82712dafb6a4d1c38cd324a4a63f825d4ad6f" have entirely different histories.
a78fbe1273
...
92a82712da
3 changed files with 75 additions and 105 deletions
|
|
@ -33,19 +33,9 @@ Each ATM model has two flake outputs:
|
||||||
| `nixosConfigurations.<model>-installed` | installed | full GPT + systemd-boot install, ext4 root, supports `nixos-rebuild switch` |
|
| `nixosConfigurations.<model>-installed` | installed | full GPT + systemd-boot install, ext4 root, supports `nixos-rebuild switch` |
|
||||||
| `packages.x86_64-linux.iso-<model>` | ISO | ISO image of the live variant |
|
| `packages.x86_64-linux.iso-<model>` | ISO | ISO image of the live variant |
|
||||||
| `packages.x86_64-linux.disk-image-<model>` | raw image | dd-able full disk image of the installed variant |
|
| `packages.x86_64-linux.disk-image-<model>` | raw image | dd-able full disk image of the installed variant |
|
||||||
| `nixosConfigurations.<model>-usb` | installed, on a stick | `<model>-installed` hardened to run from a USB stick: `nixos-usb`/`ESP-USB` labels, `nofail` `/boot`, no partition growing, auto-upgrade off (`batm3`, `douro` only) |
|
|
||||||
| `packages.x86_64-linux.disk-image-<model>-usb` | raw image | dd-able image of the `-usb` variant — flash, plug in, boot; no installer step |
|
|
||||||
|
|
||||||
Models: `douro`, `tejo`, `sintra`, `batm3`.
|
Models: `douro`, `tejo`, `sintra`, `batm3`.
|
||||||
|
|
||||||
**Run-from-USB deployments** (`batm3` today, `douro` since the LNbits cutover)
|
|
||||||
skip the Alpine + dd-to-internal-disk procedure below entirely: the stick *is*
|
|
||||||
the system. Flash `disk-image-<model>-usb` with balenaEtcher (it verifies the
|
|
||||||
write — a truncated or bad copy fails stage-1 fsck on first boot) onto a stick
|
|
||||||
of 16 GB or more, plug it in, power on. Updates go in-place against the
|
|
||||||
`<model>-usb` config (`nix copy` the toplevel + `switch-to-configuration`),
|
|
||||||
which keeps pairing and `/var/lib/bitspire`.
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Build a Sintra disk image
|
# Build a Sintra disk image
|
||||||
nix build .#disk-image-sintra
|
nix build .#disk-image-sintra
|
||||||
|
|
|
||||||
|
|
@ -20,24 +20,12 @@
|
||||||
initrd.availableKernelModules = [
|
initrd.availableKernelModules = [
|
||||||
"xhci_pci"
|
"xhci_pci"
|
||||||
"ahci"
|
"ahci"
|
||||||
# USB mass-storage: required to boot the dd'd image from a USB stick
|
|
||||||
# (stage-1 must bind the flash drive as a SCSI disk so
|
|
||||||
# /dev/disk/by-label/* appears). Harmless on the internal install.
|
|
||||||
#
|
|
||||||
# NOTE: deliberately NO "uas" here. Many USB sticks/bridges advertise
|
|
||||||
# UAS but drop off the bus ("device offline error, dev sdb") under
|
|
||||||
# sustained write load. Blacklisting uas below forces the slower-but-
|
|
||||||
# reliable usb-storage (Bulk-Only Transport) path. SATA/mSATA installs
|
|
||||||
# don't use uas anyway. (Same hardening as batm3.nix.)
|
|
||||||
"usb_storage"
|
"usb_storage"
|
||||||
"sd_mod"
|
"sd_mod"
|
||||||
"sdhci_pci"
|
"sdhci_pci"
|
||||||
"i915"
|
"i915"
|
||||||
];
|
];
|
||||||
|
|
||||||
# Keep the USB flash drive off the flaky UAS driver (see note above).
|
|
||||||
blacklistedKernelModules = [ "uas" ];
|
|
||||||
|
|
||||||
kernelModules = [
|
kernelModules = [
|
||||||
"kvm-intel"
|
"kvm-intel"
|
||||||
"i2c-dev"
|
"i2c-dev"
|
||||||
|
|
@ -49,9 +37,6 @@
|
||||||
"vt.handoff=7" # Bay Trail: preserve BIOS display init
|
"vt.handoff=7" # Bay Trail: preserve BIOS display init
|
||||||
"quiet"
|
"quiet"
|
||||||
"splash"
|
"splash"
|
||||||
# Disable USB autosuspend so the boot medium (and kiosk peripherals)
|
|
||||||
# aren't power-suspended mid-I/O — another cause of "device offline".
|
|
||||||
"usbcore.autosuspend=-1"
|
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
155
flake.nix
155
flake.nix
|
|
@ -349,61 +349,6 @@
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
# Module that turns an <model>-installed config into the one a dd'd USB
|
|
||||||
# stick actually runs. Shared by every *-usb variant so the USB-boot
|
|
||||||
# hazards are solved once:
|
|
||||||
# - distinct fs labels (nixos-usb / ESP-USB) so stage-1 can't latch an
|
|
||||||
# internal drive that already holds a generic nixos/ESP-labelled install;
|
|
||||||
# - nofail /boot: the firmware already loaded the bootloader before Linux;
|
|
||||||
# without nofail a slow/late ESP-USB enumeration (BOT is slower than UAS)
|
|
||||||
# blows past systemd's 90s device-timeout into emergency mode with root
|
|
||||||
# locked — a dead end. nofail + short timeout lets the already-mounted
|
|
||||||
# root carry the boot; /boot mounts if/when it shows;
|
|
||||||
# - NO growPartition/autoResize: sfdisk rewriting the partition table on
|
|
||||||
# first boot is the single most bus-stressing write, and flaky USB
|
|
||||||
# bridges drop off the bus mid-rewrite (sfdisk wedges in D-state and
|
|
||||||
# ESP-USB vanishes with the device). Persistent state is a few MB and
|
|
||||||
# the image ships ~2GB free. The internal-disk images keep it;
|
|
||||||
# - autoUpgrade off: no scheduled nix-store churn or bootloader writes on
|
|
||||||
# the stick. Updates go in-place via `nix copy` + switch-to-configuration
|
|
||||||
# against the named <model>-usb config (preserves pairing + /var/lib).
|
|
||||||
usbBootModule = { lib, ... }: {
|
|
||||||
fileSystems."/".device = lib.mkForce "/dev/disk/by-label/nixos-usb";
|
|
||||||
fileSystems."/boot".device = lib.mkForce "/dev/disk/by-label/ESP-USB";
|
|
||||||
fileSystems."/boot".options = [ "nofail" "x-systemd.device-timeout=10s" ];
|
|
||||||
system.autoUpgrade.enable = lib.mkForce false;
|
|
||||||
};
|
|
||||||
|
|
||||||
# dd-able USB image of a <model>-usb config. make-disk-image gives the
|
|
||||||
# ext4 root the nixos-usb label directly (-L) but hardcodes the ESP FAT
|
|
||||||
# label to "ESP", so the volume is relabelled to ESP-USB afterwards —
|
|
||||||
# volume label only; bootloader files are untouched and UEFI loads
|
|
||||||
# /EFI/BOOT/BOOTX64.EFI regardless. Keeps systemd-boot: both the batm3
|
|
||||||
# and douro firmware UEFI-USB-boot fine via that removable fallback.
|
|
||||||
mkUsbDiskImage = machineModel: usbConfig:
|
|
||||||
let
|
|
||||||
baseImage = import (nixpkgs + "/nixos/lib/make-disk-image.nix") {
|
|
||||||
inherit pkgs lib;
|
|
||||||
config = usbConfig.config;
|
|
||||||
format = "raw";
|
|
||||||
partitionTableType = "efi";
|
|
||||||
diskSize = "auto";
|
|
||||||
label = "nixos-usb"; # ext4 root label (make-disk-image -L)
|
|
||||||
};
|
|
||||||
in
|
|
||||||
pkgs.runCommand "nixos-disk-image-${machineModel}-usb"
|
|
||||||
{ nativeBuildInputs = [ pkgs.parted pkgs.mtools ]; }
|
|
||||||
''
|
|
||||||
mkdir -p $out
|
|
||||||
cp --sparse=always ${baseImage}/nixos.img $out/nixos.img
|
|
||||||
chmod +w $out/nixos.img
|
|
||||||
espStart=$(parted -sm "$out/nixos.img" unit B print | awk -F: '$1==1 {gsub("B","",$2); print $2}')
|
|
||||||
echo "ESP partition starts at byte $espStart — relabelling to ESP-USB"
|
|
||||||
export MTOOLS_SKIP_CHECK=1
|
|
||||||
mlabel -i "$out/nixos.img@@$espStart" ::ESP-USB
|
|
||||||
printf 'verify ESP label: '; mlabel -i "$out/nixos.img@@$espStart" -s :: || true
|
|
||||||
'';
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
# ── NixOS Configurations (top-level, not per-system) ──────────
|
# ── NixOS Configurations (top-level, not per-system) ──────────
|
||||||
|
|
@ -436,22 +381,35 @@
|
||||||
sintra-installed = mkInstalledConfig "sintra" ./deploy/nixos/hardware/upboard.nix;
|
sintra-installed = mkInstalledConfig "sintra" ./deploy/nixos/hardware/upboard.nix;
|
||||||
batm3-installed = mkInstalledConfig "batm3" ./deploy/nixos/hardware/batm3.nix;
|
batm3-installed = mkInstalledConfig "batm3" ./deploy/nixos/hardware/batm3.nix;
|
||||||
|
|
||||||
# USB-bootable variants of <model>-installed (see usbBootModule for
|
# USB-bootable variant of batm3-installed. This is the config the
|
||||||
# what changes). These are the configs a flashed stick actually runs.
|
# flashed USB stick actually runs — distinct fs labels so stage-1 can't
|
||||||
# Exposed as named configs (not just inline in the disk-image targets)
|
# latch the internal drive, nofail /boot, no growPartition, autoUpgrade
|
||||||
# so their system closures can be built here and deployed in-place with
|
# off. Exposed as a named config (not just inline in the disk-image
|
||||||
# `nix copy` + `switch-to-configuration` — updating the app on a running
|
# target) so its system closure can be built here and deployed in-place
|
||||||
# stick WITHOUT reflashing (preserves pairing + /var/lib state).
|
# with `nix copy` + `switch-to-configuration` — updating the app on a
|
||||||
# disk-image-<model>-usb builds its filesystem image from the same config.
|
# running stick WITHOUT reflashing (preserves pairing + /var/lib state).
|
||||||
|
# disk-image-batm3-usb builds its filesystem image from this same config.
|
||||||
batm3-usb = self.nixosConfigurations.batm3-installed.extendModules {
|
batm3-usb = self.nixosConfigurations.batm3-installed.extendModules {
|
||||||
modules = [ usbBootModule ];
|
modules = [
|
||||||
};
|
({ lib, ... }: {
|
||||||
# douro: the production unit's internal drive is not NixOS, so the
|
fileSystems."/".device = lib.mkForce "/dev/disk/by-label/nixos-usb";
|
||||||
# label disambiguation is moot today, but the nofail /boot and the
|
fileSystems."/boot".device = lib.mkForce "/dev/disk/by-label/ESP-USB";
|
||||||
# uas/autosuspend hardening in douro.nix are what make a stick a
|
# /boot must NOT be a hard boot dependency on the USB image. The
|
||||||
# reliable boot medium on the Bay Trail box. Same in-place update flow.
|
# firmware already loaded the bootloader before Linux; without
|
||||||
douro-usb = self.nixosConfigurations.douro-installed.extendModules {
|
# nofail, a slow/late ESP-USB enumeration (BOT is slower than UAS)
|
||||||
modules = [ usbBootModule ];
|
# blows past systemd's 90s device-timeout into emergency mode with
|
||||||
|
# root locked — a dead end. nofail + short timeout lets the
|
||||||
|
# already-mounted root carry the boot; /boot mounts if/when it shows.
|
||||||
|
fileSystems."/boot".options = [ "nofail" "x-systemd.device-timeout=10s" ];
|
||||||
|
# NO growPartition/autoResize: sfdisk rewriting the partition table
|
||||||
|
# on first boot is the single most bus-stressing write, and flaky
|
||||||
|
# USB bridges drop off the bus mid-rewrite (sfdisk wedges in D-state
|
||||||
|
# and ESP-USB vanishes with the device). Persistent state is a few
|
||||||
|
# MB and the image ships ~2GB free. The internal-SATA disk-image-
|
||||||
|
# batm3 keeps growPartition (a real AHCI SSD won't drop the bus).
|
||||||
|
system.autoUpgrade.enable = lib.mkForce false;
|
||||||
|
})
|
||||||
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -585,16 +543,53 @@
|
||||||
printf 'verify ESP label: '; mlabel -i "$out/nixos.img@@$espStart" -s :: || true
|
printf 'verify ESP label: '; mlabel -i "$out/nixos.img@@$espStart" -s :: || true
|
||||||
'';
|
'';
|
||||||
|
|
||||||
# USB-bootable images (see usbBootModule / mkUsbDiskImage in the let
|
# USB-bootable BATM3 TEST image with DISTINCT partition labels
|
||||||
# block). Flash with dd or balenaEtcher, boot the stick, done — no
|
# (nixos-usb / ESP-USB). The plain disk-image-batm3 reuses the generic
|
||||||
# installer step. The plain disk-image-<model> reuses the generic
|
# nixos/ESP labels, so a USB stick carrying it, booted on a batm3 whose
|
||||||
# nixos/ESP labels, so a stick carrying it, booted on a machine whose
|
# internal SATA drive ALREADY holds a nixos/ESP-labelled install, makes
|
||||||
# internal drive ALREADY holds a nixos/ESP-labelled install, makes
|
# stage-1's by-label/nixos resolve to the internal drive (larger fs,
|
||||||
# stage-1's by-label/nixos resolve to the internal drive instead of the
|
# journal recovers) instead of the stick — the stage-2 init path baked
|
||||||
# stick — the stage-2 init path baked into the USB's boot entry isn't on
|
# into the USB's boot entry isn't on that root, so stage 1 aborts.
|
||||||
# that root, so stage 1 aborts. These variants can't hit that.
|
# Distinct labels make stage-1 pick the stick unambiguously WITHOUT
|
||||||
disk-image-batm3-usb = mkUsbDiskImage "batm3" self.nixosConfigurations.batm3-usb;
|
# touching the internal drive. Unlike disk-image-sintra-usb this keeps
|
||||||
disk-image-douro-usb = mkUsbDiskImage "douro" self.nixosConfigurations.douro-usb;
|
# systemd-boot: the batm3 firmware UEFI-USB-boots fine via the ESP's
|
||||||
|
# /EFI/BOOT/BOOTX64.EFI removable fallback, so no GRUB/hybrid-table
|
||||||
|
# change is needed — only the label disambiguation here plus the
|
||||||
|
# usb_storage/uas initrd modules (in batm3.nix). Does NOT grow to fill
|
||||||
|
# the stick (see the growPartition note below — sfdisk on first boot
|
||||||
|
# wedges flaky USB bridges); auto-upgrade off (test image, not a managed
|
||||||
|
# fleet member — also stops scheduled bootloader writes landing on the
|
||||||
|
# internal drive's ESP).
|
||||||
|
disk-image-batm3-usb =
|
||||||
|
let
|
||||||
|
# Filesystem image of the batm3-usb config (defined in
|
||||||
|
# nixosConfigurations). Same config that in-place deploys target, so
|
||||||
|
# a reflash and a `switch-to-configuration` converge on one system.
|
||||||
|
baseImage = import (nixpkgs + "/nixos/lib/make-disk-image.nix") {
|
||||||
|
inherit pkgs lib;
|
||||||
|
config = self.nixosConfigurations.batm3-usb.config;
|
||||||
|
format = "raw";
|
||||||
|
partitionTableType = "efi";
|
||||||
|
diskSize = "auto";
|
||||||
|
label = "nixos-usb"; # ext4 root label (make-disk-image -L)
|
||||||
|
};
|
||||||
|
in
|
||||||
|
pkgs.runCommand "nixos-disk-image-batm3-usb"
|
||||||
|
{ nativeBuildInputs = [ pkgs.parted pkgs.mtools ]; }
|
||||||
|
''
|
||||||
|
mkdir -p $out
|
||||||
|
cp --sparse=always ${baseImage}/nixos.img $out/nixos.img
|
||||||
|
chmod +w $out/nixos.img
|
||||||
|
# make-disk-image hardcodes the ESP FAT label to "ESP"; relabel the
|
||||||
|
# volume to ESP-USB so /boot (by-label/ESP-USB) can't resolve to an
|
||||||
|
# internal drive's ESP. Volume label only — bootloader files are
|
||||||
|
# untouched, and UEFI loads /EFI/BOOT/BOOTX64.EFI regardless.
|
||||||
|
espStart=$(parted -sm "$out/nixos.img" unit B print | awk -F: '$1==1 {gsub("B","",$2); print $2}')
|
||||||
|
echo "ESP partition starts at byte $espStart — relabelling to ESP-USB"
|
||||||
|
export MTOOLS_SKIP_CHECK=1
|
||||||
|
mlabel -i "$out/nixos.img@@$espStart" ::ESP-USB
|
||||||
|
printf 'verify ESP label: '; mlabel -i "$out/nixos.img@@$espStart" -s :: || true
|
||||||
|
'';
|
||||||
|
|
||||||
# Backwards compat
|
# Backwards compat
|
||||||
iso = self.nixosConfigurations.douro.config.system.build.isoImage;
|
iso = self.nixosConfigurations.douro.config.system.build.isoImage;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue