feat: Add support for ipxe boot ephemeral systems
This commit is contained in:
committed by
Hunter Halloran
parent
1412529b0f
commit
8a4e574b90
@@ -2,6 +2,7 @@
|
|||||||
let
|
let
|
||||||
nixpkgs = inputs.nixpkgs;
|
nixpkgs = inputs.nixpkgs;
|
||||||
lib = nixpkgs.lib;
|
lib = nixpkgs.lib;
|
||||||
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
nixos-generators = inputs.nixos-generators;
|
nixos-generators = inputs.nixos-generators;
|
||||||
|
|
||||||
mkInstaller = hostName:
|
mkInstaller = hostName:
|
||||||
@@ -36,16 +37,56 @@ let
|
|||||||
inherit format;
|
inherit format;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mkNetboot = hostName:
|
||||||
|
nixpkgs.lib.nixosSystem {
|
||||||
|
inherit system;
|
||||||
|
specialArgs = { inherit inputs; };
|
||||||
|
modules = hosts.modules.${hostName} ++ [
|
||||||
|
"${nixpkgs}/nixos/modules/installer/netboot/netboot.nix"
|
||||||
|
{
|
||||||
|
disko.enableConfig = lib.mkForce false;
|
||||||
|
services.upower.enable = lib.mkForce false;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
hostNames = builtins.attrNames hosts.nixosConfigurations;
|
hostNames = builtins.attrNames hosts.nixosConfigurations;
|
||||||
|
|
||||||
installerPackages = lib.listToAttrs (lib.concatMap (name:
|
installerPackages = lib.listToAttrs (lib.concatMap (name:
|
||||||
let cfg = hosts.nixosConfigurations.${name}; in
|
let cfg = hosts.nixosConfigurations.${name}; in
|
||||||
if lib.elem "iso" cfg.config.host.buildMethods then [{
|
if lib.elem "installer-iso" cfg.config.host.buildMethods then [{
|
||||||
name = "installer-iso-${name}";
|
name = "installer-iso-${name}";
|
||||||
value = (mkInstaller name).config.system.build.isoImage;
|
value = (mkInstaller name).config.system.build.isoImage;
|
||||||
}] else []
|
}] else []
|
||||||
) hostNames);
|
) hostNames);
|
||||||
|
|
||||||
|
isoPackages = lib.listToAttrs (lib.concatMap (name:
|
||||||
|
let cfg = hosts.nixosConfigurations.${name}; in
|
||||||
|
if lib.elem "iso" cfg.config.host.buildMethods then [{
|
||||||
|
name = "iso-${name}";
|
||||||
|
value = mkGenerator name "iso";
|
||||||
|
}] else []
|
||||||
|
) hostNames);
|
||||||
|
|
||||||
|
ipxePackages = lib.listToAttrs (lib.concatMap (name:
|
||||||
|
let cfg = hosts.nixosConfigurations.${name}; in
|
||||||
|
if lib.elem "ipxe" cfg.config.host.buildMethods then [{
|
||||||
|
name = "ipxe-${name}";
|
||||||
|
value =
|
||||||
|
let
|
||||||
|
build = (mkNetboot name).config.system.build;
|
||||||
|
in
|
||||||
|
pkgs.symlinkJoin {
|
||||||
|
name = "netboot-artifacts-${name}";
|
||||||
|
paths = [
|
||||||
|
build.netbootRamdisk
|
||||||
|
build.kernel
|
||||||
|
build.netbootIpxeScript
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}] else []
|
||||||
|
) hostNames);
|
||||||
|
|
||||||
lxcPackages = lib.listToAttrs (lib.concatMap (name:
|
lxcPackages = lib.listToAttrs (lib.concatMap (name:
|
||||||
let cfg = hosts.nixosConfigurations.${name}; in
|
let cfg = hosts.nixosConfigurations.${name}; in
|
||||||
if lib.elem "lxc" cfg.config.host.buildMethods then [{
|
if lib.elem "lxc" cfg.config.host.buildMethods then [{
|
||||||
@@ -70,4 +111,4 @@ let
|
|||||||
}] else []
|
}] else []
|
||||||
) hostNames);
|
) hostNames);
|
||||||
in
|
in
|
||||||
installerPackages // lxcPackages // proxmoxPackages
|
installerPackages // isoPackages // ipxePackages // lxcPackages // proxmoxPackages
|
||||||
|
|||||||
@@ -25,8 +25,8 @@
|
|||||||
};
|
};
|
||||||
buildMethods = lib.mkOption {
|
buildMethods = lib.mkOption {
|
||||||
type = lib.types.listOf lib.types.str;
|
type = lib.types.listOf lib.types.str;
|
||||||
default = [ "iso" ];
|
default = [ "installer-iso" ];
|
||||||
description = "List of allowed build methods (iso, lxc, proxmox).";
|
description = "List of allowed build methods (installer-iso, iso, ipxe, lxc, proxmox).";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@
|
|||||||
# Hide the OS choice for bootloaders.
|
# Hide the OS choice for bootloaders.
|
||||||
# It's still possible to open the bootloader list by pressing any key
|
# It's still possible to open the bootloader list by pressing any key
|
||||||
# It will just not appear on screen unless a key is pressed
|
# It will just not appear on screen unless a key is pressed
|
||||||
loader.timeout = 0;
|
loader.timeout = lib.mkDefault 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
# Set your time zone.
|
# Set your time zone.
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
host.filesystem.swapSize = lib.mkDefault "16G";
|
host.filesystem.swapSize = lib.mkDefault "16G";
|
||||||
host.filesystem.device = lib.mkDefault "/dev/nvme0n1";
|
host.filesystem.device = lib.mkDefault "/dev/nvme0n1";
|
||||||
|
host.buildMethods = lib.mkDefault [ "installer-iso" ];
|
||||||
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||||
|
|
||||||
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||||
|
|||||||
54
hosts/types/nix-ephemeral.nix
Normal file
54
hosts/types/nix-ephemeral.nix
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
{ inputs, ... }:
|
||||||
|
[
|
||||||
|
(
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
modulesPath,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
imports = [ (modulesPath + "/installer/scan/not-detected.nix") ];
|
||||||
|
|
||||||
|
boot.initrd.availableKernelModules = [
|
||||||
|
"xhci_pci"
|
||||||
|
"nvme"
|
||||||
|
"usb_storage"
|
||||||
|
"sd_mod"
|
||||||
|
"sdhci_pci"
|
||||||
|
];
|
||||||
|
boot.initrd.kernelModules = [ ];
|
||||||
|
boot.kernelModules = [ "kvm-intel" ];
|
||||||
|
boot.extraModulePackages = [ ];
|
||||||
|
boot.kernelParams = [
|
||||||
|
"quiet"
|
||||||
|
"splash"
|
||||||
|
"boot.shell_on_fail"
|
||||||
|
"udev.log_priority=3"
|
||||||
|
"rd.systemd.show_status=auto"
|
||||||
|
];
|
||||||
|
|
||||||
|
# Ephemeral setup: No swap, no disk
|
||||||
|
host.filesystem.swapSize = lib.mkForce "0G";
|
||||||
|
host.filesystem.device = lib.mkForce "/dev/null"; # Dummy device
|
||||||
|
host.buildMethods = lib.mkDefault [ "iso" "ipxe" ];
|
||||||
|
|
||||||
|
# Disable Disko config since we are running from RAM/ISO
|
||||||
|
disko.enableConfig = lib.mkForce false;
|
||||||
|
|
||||||
|
# Define a dummy root filesystem to satisfy assertions
|
||||||
|
fileSystems."/" = {
|
||||||
|
device = "none";
|
||||||
|
fsType = "tmpfs";
|
||||||
|
options = [ "defaults" "size=50%" "mode=755" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||||
|
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
{
|
||||||
|
modules.sw.enable = true;
|
||||||
|
modules.sw.type = "stateless-kiosk";
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -37,6 +37,7 @@
|
|||||||
|
|
||||||
host.filesystem.device = lib.mkDefault "/dev/nvme0n1";
|
host.filesystem.device = lib.mkDefault "/dev/nvme0n1";
|
||||||
host.filesystem.swapSize = lib.mkDefault "34G";
|
host.filesystem.swapSize = lib.mkDefault "34G";
|
||||||
|
host.buildMethods = lib.mkDefault [ "installer-iso" ];
|
||||||
|
|
||||||
# Suspend / logind behavior
|
# Suspend / logind behavior
|
||||||
services.upower.enable = lib.mkDefault true;
|
services.upower.enable = lib.mkDefault true;
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
|
|
||||||
host.filesystem.swapSize = lib.mkDefault "8G";
|
host.filesystem.swapSize = lib.mkDefault "8G";
|
||||||
host.filesystem.device = lib.mkDefault "/dev/mmcblk0";
|
host.filesystem.device = lib.mkDefault "/dev/mmcblk0";
|
||||||
|
host.buildMethods = lib.mkDefault [ "installer-iso" ];
|
||||||
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||||
|
|
||||||
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||||
|
|||||||
@@ -60,4 +60,7 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Ephemeral Configuration (Live ISO / Netboot)
|
||||||
|
nix-ephemeral.count = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ in
|
|||||||
"desktop"
|
"desktop"
|
||||||
"tablet-kiosk"
|
"tablet-kiosk"
|
||||||
"headless"
|
"headless"
|
||||||
|
"stateless-kiosk"
|
||||||
];
|
];
|
||||||
default = "desktop";
|
default = "desktop";
|
||||||
description = "Type of system configuration: 'desktop' for normal OS, 'tablet-kiosk' for tablet/kiosk mode.";
|
description = "Type of system configuration: 'desktop' for normal OS, 'tablet-kiosk' for tablet/kiosk mode.";
|
||||||
@@ -91,7 +92,7 @@ in
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
# Import Desktop or Kiosk modules based on type
|
# Import Desktop or Kiosk modules based on type
|
||||||
(mkIf (cfg.type == "desktop") (
|
(mkIf (cfg.type == "desktop") (
|
||||||
import ./desktop {
|
import ./desktop {
|
||||||
inherit
|
inherit
|
||||||
config
|
config
|
||||||
@@ -121,5 +122,15 @@ in
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
|
(mkIf (cfg.type == "stateless-kiosk") (
|
||||||
|
import ./stateless-kiosk {
|
||||||
|
inherit
|
||||||
|
config
|
||||||
|
lib
|
||||||
|
pkgs
|
||||||
|
inputs
|
||||||
|
;
|
||||||
|
}
|
||||||
|
))
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
28
sw/stateless-kiosk/default.nix
Normal file
28
sw/stateless-kiosk/default.nix
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
inputs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
lib.mkMerge [
|
||||||
|
(import ./kiosk-browser.nix {
|
||||||
|
inherit
|
||||||
|
config
|
||||||
|
lib
|
||||||
|
pkgs
|
||||||
|
inputs
|
||||||
|
;
|
||||||
|
})
|
||||||
|
(import ./net.nix {
|
||||||
|
inherit
|
||||||
|
config
|
||||||
|
lib
|
||||||
|
pkgs
|
||||||
|
inputs
|
||||||
|
;
|
||||||
|
})
|
||||||
|
{
|
||||||
|
services.openssh.enable = false;
|
||||||
|
}
|
||||||
|
]
|
||||||
118
sw/stateless-kiosk/kiosk-browser.nix
Normal file
118
sw/stateless-kiosk/kiosk-browser.nix
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
kioskPolicies = {
|
||||||
|
DisableAppUpdate = true;
|
||||||
|
DisableFirefoxStudies = true;
|
||||||
|
DisableTelemetry = true;
|
||||||
|
DisablePocket = true;
|
||||||
|
DisableSetDesktopBackground = true;
|
||||||
|
DisableFeedbackCommands = true;
|
||||||
|
DontCheckDefaultBrowser = true;
|
||||||
|
OverrideFirstRunPage = "";
|
||||||
|
OverridePostUpdatePage = "";
|
||||||
|
NoDefaultBookmarks = true;
|
||||||
|
DisableProfileImport = true;
|
||||||
|
|
||||||
|
Permissions = {
|
||||||
|
Camera = { Allow = ["homeassistant.lan"]; };
|
||||||
|
Microphone = { Allow = ["homeassistant.lan"]; };
|
||||||
|
Location = { Allow = ["homeassistant.lan"]; };
|
||||||
|
Notifications = { Allow = ["homeassistant.lan"]; };
|
||||||
|
Clipboard = { Allow = ["homeassistant.lan"]; };
|
||||||
|
Fullscreen = { Allow = ["homeassistant.lan"]; };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
extraPrefs = pkgs.writeText "kiosk-prefs.js" ''
|
||||||
|
pref("browser.shell.checkDefaultBrowser", false);
|
||||||
|
pref("browser.startup.homepage_override.mstone", "ignore");
|
||||||
|
pref("startup.homepage_welcome_url", "");
|
||||||
|
pref("startup.homepage_welcome_url.additional", "");
|
||||||
|
pref("browser.sessionstore.resume_from_crash", false);
|
||||||
|
pref("browser.sessionstore.max_resumed_crashes", 0);
|
||||||
|
pref("network.captive-portal-service.enabled", false);
|
||||||
|
pref("network.connectivity-service.enabled", false);
|
||||||
|
pref("browser.messaging-system.whatsNewPanel.enabled", false);
|
||||||
|
pref("browser.aboutwelcome.enabled", false);
|
||||||
|
pref("privacy.popups.showBrowserMessage", false);
|
||||||
|
'';
|
||||||
|
|
||||||
|
firefoxWrapped = pkgs.wrapFirefox pkgs.firefox-unwrapped {
|
||||||
|
extraPolicies = kioskPolicies;
|
||||||
|
extraPrefsFiles = [ extraPrefs ];
|
||||||
|
};
|
||||||
|
|
||||||
|
firefoxKiosk = pkgs.writeShellScriptBin "firefoxkiosk" ''
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
BASE="http://homeassistant.lan:8123"
|
||||||
|
|
||||||
|
get_primary_mac() {
|
||||||
|
for dev in /sys/class/net/*; do
|
||||||
|
iface="$(basename "$dev")"
|
||||||
|
[ "$iface" = "lo" ] && continue
|
||||||
|
if [ -f "$dev/type" ] && [ "$(cat "$dev/type")" = "1" ]; then
|
||||||
|
cat "$dev/address"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
MAC="$(get_primary_mac 2>/dev/null || echo "")"
|
||||||
|
MAC="$(echo "$MAC" | tr '[:upper:]' '[:lower:]')"
|
||||||
|
|
||||||
|
case "$MAC" in
|
||||||
|
"00:e0:4c:46:0b:32") STATION="1" ;;
|
||||||
|
"00:e0:4c:46:07:26") STATION="2" ;;
|
||||||
|
"00:e0:4c:46:05:94") STATION="3" ;;
|
||||||
|
"00:e0:4c:46:07:11") STATION="4" ;;
|
||||||
|
"00:e0:4c:46:08:02") STATION="5" ;;
|
||||||
|
"00:e0:4c:46:08:5c") STATION="6" ;;
|
||||||
|
*) ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
DEFAULT_PATH="lovelace/0"
|
||||||
|
PATH_PART="$DEFAULT_PATH"
|
||||||
|
BROWSER_ID="" # browser_mod identifier
|
||||||
|
|
||||||
|
if [ -n "$STATION" ]; then
|
||||||
|
PATH_PART="assembly-line/$STATION"
|
||||||
|
BROWSER_ID="Station%20$STATION"
|
||||||
|
fi
|
||||||
|
|
||||||
|
URL="$BASE/$PATH_PART"
|
||||||
|
|
||||||
|
# Add BrowserID query param if we have one
|
||||||
|
if [ -n "$BROWSER_ID" ]; then
|
||||||
|
if [[ "$URL" == *"?"* ]]; then
|
||||||
|
URL="$URL&BrowserID=$BROWSER_ID"
|
||||||
|
else
|
||||||
|
URL="$URL?BrowserID=$BROWSER_ID"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
exec ${firefoxWrapped}/bin/firefox --kiosk "$URL"
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
{
|
||||||
|
environment.systemPackages = [ firefoxKiosk ];
|
||||||
|
|
||||||
|
services.xserver.enable = false;
|
||||||
|
services.seatd.enable = true;
|
||||||
|
|
||||||
|
services.cage = {
|
||||||
|
enable = true;
|
||||||
|
user = "engr-ugaif";
|
||||||
|
program = "${firefoxKiosk}/bin/firefoxkiosk";
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.cage = {
|
||||||
|
after = [ "network-online.target" ];
|
||||||
|
wants = [ "network-online.target" ];
|
||||||
|
};
|
||||||
|
}
|
||||||
43
sw/stateless-kiosk/net.nix
Normal file
43
sw/stateless-kiosk/net.nix
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
{ config, lib, pkgs, inputs, ... }:
|
||||||
|
{
|
||||||
|
# Minimal container networking (systemd-networkd)
|
||||||
|
networking = {
|
||||||
|
useNetworkd = true;
|
||||||
|
networkmanager.enable = false;
|
||||||
|
dhcpcd.enable = false;
|
||||||
|
useDHCP = false;
|
||||||
|
useHostResolvConf = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.network = {
|
||||||
|
enable = true;
|
||||||
|
wait-online.enable = true;
|
||||||
|
|
||||||
|
networks."10-wired" = {
|
||||||
|
matchConfig.Type = "ether";
|
||||||
|
networkConfig = {
|
||||||
|
LinkLocalAddressing = false;
|
||||||
|
DHCP = "no";
|
||||||
|
VLAN = [ "vlan5" ];
|
||||||
|
};
|
||||||
|
linkConfig.RequiredForOnline = "no";
|
||||||
|
};
|
||||||
|
|
||||||
|
netdevs."20-vlan5" = {
|
||||||
|
netdevConfig = {
|
||||||
|
Kind = "vlan";
|
||||||
|
Name = "vlan5";
|
||||||
|
};
|
||||||
|
vlanConfig.Id = 5;
|
||||||
|
};
|
||||||
|
|
||||||
|
networks."30-vlan5" = {
|
||||||
|
matchConfig.Name = "vlan5";
|
||||||
|
networkConfig = {
|
||||||
|
DHCP = "ipv4";
|
||||||
|
IPv6AcceptRA = true;
|
||||||
|
};
|
||||||
|
linkConfig.RequiredForOnline = "routable";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user