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
51 lines
2.3 KiB
Nix
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 ]; }
|