staging: add vm-lab - Photon OS VM provisioning for VMware Workstation - #316
staging: add vm-lab - Photon OS VM provisioning for VMware Workstation#316dcasota wants to merge 2 commits into
Conversation
b55c253 to
5c597ee
Compare
End-to-end: VMX template, boot VMDK, kickstart, unattended install, SSH
access, teardown, and the verification scripts that say whether each stage
actually did what it claims.
Defaults: 2 vCPU, 4 GB RAM, 50 GB thin disk in a SINGLE FILE
(monolithicSparse). Verified by creating one - a fresh 50 GB disk is one file
of 6,619,136 bytes with the extent line RW 104857600 SPARSE referencing
itself. The size is a ceiling, not an allocation.
Two things the README documents because each has cost a day elsewhere:
* SSH access is decided at ISO BUILD time. SPAGAT_OPERATOR_AUTHORIZED_KEY
and IPHASE6_TEST_SSH_PUBKEY both default to empty and the root hash to
'*', so a build where neither was exported ships an empty
authorized_keys and a locked root - the serial console is the only way
in, with no post-install fix.
* The install CDROM must be on SATA: the linux-mok kernel has no IDE CDROM
driver, so on ide1:0 the installer boots but mount /mnt/media finds no
/dev/sr0, which reads like a corrupt ISO.
Every script was executed, not just written. Four defects were found and
fixed in the process, all the same family - a check that looked like it
passed while proving nothing:
1. Both .ps1 files were unrunnable under Windows PowerShell 5.1. They
parsed under pwsh 7 (UTF-8); 5.1 reads .ps1 as ANSI without a BOM, so an
em-dash corrupted a string literal. Now ASCII-only.
2. The env parser kept trailing comments, so BOOT_DISK_ADAPTER resolved to
'lsilogic" # what the initrd expects' and would have been passed to
vmware-vdiskmanager verbatim. bash strips those for free, which is why
the WSL-side test passed and hid it.
3. A config that could not be loaded did not stop the script - it printed a
healthy-looking first section then died on unbound variables. Now fails
closed with exit 78.
4. grep -c PAT || echo 0 emitted "0\n0" (grep prints 0 AND exits 1).
Replaced with n=$(grep -c ...) || n=0.
Snapshot of deploy/vm-lab/ from dcasota/SpagatLibrarian-Appliance @ b7ec6954;
see staging/vm-lab/PROVENANCE.md. kickstart/check-drift.sh works in both homes
and states which mode it used.
5c597ee to
afad115
Compare
The documented per-run overrides did not work.
config/vm-lab.env assigned every variable unconditionally
(VM_NAME="spagat-smoke"), and every .sh script sources it after startup, so
an exported value was overwritten. README's own examples - VM_NAME=my-lab
./scripts/00-preflight.sh and GUEST_VCPUS=4 powershell -File
scripts/10-create-vm.ps1 - therefore did nothing. Converted all 24
assignments to : "${VAR:=default}" form; values are byte-identical to
before, including the backslash-bearing Windows paths.
The PowerShell side could not be overridden at all.
Both .ps1 files parse the .env into a hashtable and never consulted $env:.
Their shared parser now accepts the new form (and still the old one, so a
stale copy keeps working) and prefers an environment value. Verified by
running the parser: VM_NAME=perm-p03 now yields
VM_DIR_WIN=C:\spagat-iso-build\vm\perm-p03.
The BIOS UUID was hardcoded in the VMX template, not a placeholder.
Every VM built from the template shared one UUID - and because
ethernet0.addressType is "generated", VMware derives the MAC from it, so
they also shared one MAC and one DHCP lease. It is now @@UUID_BIOS@@ fed
from GUEST_UUID_BIOS, defaulting to the previous value so existing VMs are
unaffected, and 10-create-vm.ps1 warns when the last three bytes of MAC and
UUID disagree.
90-teardown.ps1 enumerated the snapshot chain by name.
The fixed list covered exactly two deltas and two .vmsn files, so a VM that
had reached -000003.vmdk left an orphan - which defeats the file's own
stated rationale, since UEFI's removable-media fallback then finds the
surviving ESP and boots the previous image. Now globbed by pattern.
50-verify-boot.sh:87 had a broken ANSI strip.
s/\x1b\[[0-9;]*g//g - trailing g where line 83 correctly uses m, so SGR
sequences were not stripped from the failed-units section.
20-make-ssh-key.sh did not notice a failed ssh-keygen.
No set -e, so it fell through to cat "$KEY.pub" and reported a missing
file instead of the real cause. Now exits 5.
Also documented, not changed: GUEST_GATEWAY is read by nothing, because the
gateway and DNS are hardcoded inside the kickstart template even though the
address is templated. That file is byte-exact and policed by check-drift.sh,
so the fix belongs upstream; the variable now says so.
Verified: bash -n clean on all 7 shell scripts, both .ps1 parse under pwsh
and the shared parser was executed against the real .env, kickstart sha256
unchanged so check-drift.sh still passes, both .ps1 still ASCII-only with
CRLF endings.
Signed-off-by: Daniel Casota <dcasota@gmail.com>
|
Pushed The documented per-run overrides did not work
VM_NAME=my-lab BOOT_DISK_SIZE=30GB ./scripts/00-preflight.sh # README:326
GUEST_VCPUS=4 powershell -File scripts/10-create-vm.ps1 # README:341All 24 assignments converted to The PowerShell side could not be overridden at allBoth The BIOS UUID was hardcoded, not a placeholder
Now
|
Adds
staging/vm-lab/— everything needed to go from nothing to a running,verified, SSH-reachable Photon OS VM on VMware Workstation.
What is in it
config/vm-lab.envconfig/spagat-smoke.vmx.templatekickstart/scripts/00-preflight.shscripts/10-create-vm.ps1scripts/20-make-ssh-key.shscripts/30-install-from-iso.shscripts/40-check-staging.shscripts/50-verify-boot.shscripts/60-ssh.shscripts/90-teardown.ps1Defaults: 2 vCPU, 4 GB RAM, 50 GB thin disk in a SINGLE FILE.
The disk is
monolithicSparse(vmware-vdiskmanager -t 0), so 50 GB is aceiling rather than an allocation. Verified by creating one: a fresh 50 GB
disk is one file of 6,619,136 bytes, with the extent line
RW 104857600 SPARSE "single.vmdk"referencing itself.-t 1would store thesame data across 2 GB extents (
-s001.vmdk,-s002.vmdk, ...) - more filesfor the same bytes, and the split form is the one that tends to leave orphaned
extents behind after a teardown.
Every value is overridable per run:
The two things most likely to cost a day
SSH access is decided at ISO build time.
SPAGAT_OPERATOR_AUTHORIZED_KEYand
IPHASE6_TEST_SSH_PUBKEYboth default to empty, and the root passwordhash defaults to
*. A build where neither was exported ships an appliancewith correct
0600permissions on an emptyauthorized_keysand no rootpassword — the serial console is the only way in, and there is no post-install
fix.
40-check-staging.sh --iso <path>extracts the kickstart out of thefinished ISO and prints the keys it actually contains, so this is verifiable
rather than hopeful.
The install CDROM must be on SATA. The
linux-mokkernel has no IDE CDROMdriver, so on
ide1:0the installer boots but userspacemount /mnt/mediafinds no
/dev/sr0and fails looking for the volume label — which reads likea corrupt ISO.
The VMX template also pins the BIOS UUID next to the MAC on purpose: with
ethernet0.addressType="generated"VMware derives the MAC from the UUID, sodropping it regenerates both and moves the guest's IP.
Verification
Every script was executed, not just written:
bash -nclean on all 7 shell scripts; both.ps1parse and run underWindows PowerShell 5.1
00-preflight.sh,50-verify-boot.sh,40-check-staging.shandcheck-drift.shrun against real artifactsvalue contains a stray
#/tmpwith no way to find its config, a script exits 78 withinstructions rather than half-running
Four defects were found and fixed during that testing, all of the same family
— a check that looked like it passed while proving nothing:
.ps1files were unrunnable under Windows PowerShell 5.1. Theyparsed fine under
pwsh7, which decodes UTF-8; 5.1 reads.ps1as ANSIwithout a BOM, so an em-dash corrupted a string literal and produced a
cascade of misleading brace errors. Both files are now ASCII-only.
BOOT_DISK_ADAPTERresolvedto
"lsilogic" # what the initrd expectsand would have been handed tovmware-vdiskmanagerverbatim. bash strips those for free, which is whythe WSL-side test passed and hid it.
a healthy-looking first section and then died on unbound variables. Now
fails closed.
grep -c PAT || echo 0emitted"0\n0"(grep prints0and exits1), so counters rendered as two lines. Replaced with
n=$(grep -c …) || n=0.Provenance
vm-lab/is a snapshot ofdeploy/vm-lab/fromdcasota/SpagatLibrarian-Appliance@b7ec6954.PROVENANCE.mdrecords thecommit and the kickstart hash.
kickstart/check-drift.shworks in both homes and says which mode it used: itdiffs against the live canonical template when a SPAGAT checkout is reachable
(
SPAGAT_REPO=…), and otherwise falls back to the recordedEXPECTED-SHA256— which catches an edited local copy but cannot see upstream moving, a limit
it states rather than glossing over. If neither is available it exits non-zero,
because "cannot check" must never read as "fine".
🤖 Generated with Claude Code