vmix.nix/lib/images/windows/helpers/makeConfigMedium.nix
Git Sagar 702f723e6d windows: seal mode -- generic OOBE-deferred base, per-VM data on a config CD
A sealed image bakes no per-VM data. generalize.nix gains a gated
configMedium flag (false path byte-identical, so the shared macOS
generalize path is untouched): the baked answer file stays generic and
the target's first boot reads hostname/static-IP/timezone/tint off a
small removable CD via a finder (vmix-load-config.cmd) + applier
(vmix-apply-config.ps1), with the static-IP script dot-sourcing the same
config. templates.seal is a thin preset (delayOobeRun + configMedium +
D:\Users profiles + a data disk); images gain a .seal leaf next to
.generalize; makeConfigMedium renders the per-VM ISO.

So one sealed store path is shared by every VM, each mints its own SID
on first boot and builds the whole profile on D:, and only a cheap ISO
is per-VM. Also folds in the delayOobeRun reconcile: extraDisk (and the
audit-mode data-disk init) are gated off under deferral, so a sealed
image ships with no throwaway `data` output -- the target's specialize
formats the host zvol instead.

vms: disks.config.file attaches the config medium as a second CD-ROM.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0117qMyjpuXsjpVAcpJbFD8g
2026-09-16 13:01:12 -03:00

51 lines
2.3 KiB
Nix

# Per-VM config medium for a sealed Windows image (see templates.seal).
#
# A sealed image carries no per-VM data. The values that differ between VMs --
# hostname, the static address the guest asserts, timezone, desktop tint -- are
# written here as a PowerShell data file and packed into a tiny ISO. config.nix
# attaches it as a read-only CD-ROM; the image's baked first-boot scripts
# (vmix-load-config.cmd finds it, then dot-source it) apply the values. So one
# sealed store path is shared by every VM, and only this cheap ISO is per-VM.
#
# Usage:
# makeConfigMedium {
# name = "win-config";
# hostname = "panda-win";
# staticIP = { address = "10.10.10.26"; prefixLength = 24;
# gateway = "10.10.10.1"; dns = [ "10.10.10.1" ]; };
# timezone = "E. South America Standard Time";
# bgColor = "#856558";
# }
{ pkgs, lib, makeFilesISO, ... }:
{
name ? "vmix-config",
hostname ? "",
# { address; prefixLength; gateway; dns = [ ... ]; }
staticIP ? null,
timezone ? null,
# Solid desktop background as a hex string, e.g. "#856558". Converted to the
# registry's decimal "R G B" on the target, in vmix-apply-config.ps1.
bgColor ? null,
}:
let
dnsList = lib.optionalString (staticIP != null)
(lib.concatMapStringsSep "," (s: "'${s}'") staticIP.dns);
# Consumed by dot-sourcing (. C:\vmix-config.ps1), so it only assigns
# variables. Anything not set here is simply absent, and the baked scripts
# guard on that ($VmixIpAddress being null skips the static-IP assignment).
configPs1 = pkgs.writeText "vmix-config.ps1" ''
# vmix per-VM config -- generated, read by the sealed image's baked scripts.
$VmixHostname = '${hostname}'
${lib.optionalString (staticIP != null) ''
$VmixIpAddress = '${staticIP.address}'
$VmixPrefixLength = ${toString staticIP.prefixLength}
$VmixGateway = '${staticIP.gateway}'
$VmixDns = @(${dnsList})''}
${lib.optionalString (timezone != null) "$VmixTimeZone = '${timezone}'"}
${lib.optionalString (bgColor != null) "$VmixBgColor = '${bgColor}'"}
'';
in
# makeFilesISO strips the store-hash prefix, so this lands at the ISO root as
# exactly vmix-config.ps1 -- which is what vmix-load-config.cmd scans for.
makeFilesISO { inherit name; files = [ configPs1 ]; }