Skip to content

staging: add mission-control - execute the ISO permutation matrix - #317

Open
dcasota wants to merge 2 commits into
masterfrom
staging/mission-control
Open

staging: add mission-control - execute the ISO permutation matrix#317
dcasota wants to merge 2 commits into
masterfrom
staging/mission-control

Conversation

@dcasota

@dcasota dcasota commented Aug 31, 2026

Copy link
Copy Markdown
Owner

ISO-PERMUTATION-MATRIX.md says of itself: "No builds were run." Fourteen of its sixteen rows are dependency-resolution predictions or code reading; only two were ever installed. This is the execution layer it lacks.

It reuses vm-lab's mechanics — VMX discipline, thin disks, stash-never-delete teardown, the serial-log liveness instrument — and drops everything specific to the SPAGAT-Librarian appliance, which is out of scope. In particular it does not need spagat-vm-orchestrator, which is a cargo artifact of a repo this project does not have; vmrun plus VMX edits cover everything it did except install-completion detection, which is done here by watching the boot source change in the serial log.

What makes 34 permutations cost 4 builds

POI's isoInstaller does not only read ks= from the kernel cmdline — _load_ks_config_vmware() reads guestinfo.kickstart.data through vmtoolsd. I verified the mechanism is actually present, not merely coded for:

usr/bin/vmtoolsd        78024 bytes   <- in the installer initrd
usr/bin/vmware-rpctool  32872 bytes
"open-vm-tools"                       <- in packages_installer_initrd.json

So a per-permutation kickstart is one line in the VMX. No ISO remaster, no HTTP server, no typing at a boot menu. That separates the axes cleanly:

Layer Axes Cost
Build time ISO type × installer version 4 ISOs, cached
Install time STIG × filesystem × kickstart-vs-UI free

Why both install paths are driven

Not thoroughness — each has a failure mode the other cannot reach.

  • The STIG menu is UI-only (stigenable.py is reached solely from the curses configurator), so a kickstart can never answer it and must list KS_STIG_PACKAGES by hand.
  • The security: key failure is kickstart-only on POI 2.8, and security: {fips: …} is reachable exclusively from a kickstart on either version. Rows s01/s02 cover it.
  • The same failure surfaces differently: UI mode reduces a missing package to InstallerError("Installer failed") on screen with the cause only in /var/log/installer. An oracle calibrated on one path misreads the other.

How a PR regression is identified

Every assertion names the PR it proves, so the report names the culprit rather than saying something broke:

ID     ISO      POI   STIG  FS    MODE  DOC     RESULT   PRs implicated
p03    minimal  2.8   yes   ext4  ui    fails   FAIL(2)  POI#11

DOC is the verdict the matrix recorded before the PRs. A row reproducing DOC's fails is the regression signal. Covers PR#9, PR#21, PR#22, PR#24, POI#9, POI#10, POI#11.

Results land in $MC_RESULTS_DIR/<perm>/: checks.jsonl (one JSON object per assertion), the generated kickstart.json, and logs/ with dmesg, journalctl -b, journalctl -p err, failed units, rpm -qa, /proc/cmdline, mounts, /var/log/{installer,ansible-stig,messages}, the mkinitrd log and the POI manifest. The matrix supplies a resolution oracle only — it gives no dmesg/journalctl//var/log criteria at all, so that layer is new.

Verified on this host, not assumed

  • vmrun and vmware-vdiskmanager execute from WSL; mc-preflight.sh passes
  • A real VM was created end to end: 4.1 MB thin disk for a 32 GB volume, unique MAC/UUID, correct Windows paths, kickstart injected as guestinfo
  • The interactive variant emits no active guestinfo line at all — which is what selects the curses configurator
  • Teardown stashed the chain and preserved the VMX and serial logs
  • Generated kickstarts validate against POI's own known_keys for all four variants, so none can abort the install on an unknown key
  • The oracle ran against a live Photon guest and reported correctly

Four portability traps found while building it

grep -a does not work here. In a non-interactive shell /usr/bin/grep is toybox, which has no -a and returns zero matches on a NUL-bearing serial log instead of erroring — the same silent-zero trap vm-lab's README documents, reached by a different route. Interactively grep is ugrep, which supports both -a and -P, so anything verified at a prompt can still be wrong inside a script. mc_grep_count strips NULs first and trusts neither.

grep -P and sed \U are GNU extensions and absent for the same reason; mc_win_path uses tr.

vmrun output is CRLF — every parse strips \r. My own preflight reported "0 VMs running" against vmrun's "Total running VMs: 2" until I did.

A hashed permutation index collides. A cksum-based index collided on this very matrix — k04/k16 and k09/s02 would have shared a MAC, a UUID and an IP — and could reach .240, inside VMnet8's DHCP range of .128–.254. The index is now the ordinal in permutations.tsv: unique by construction, addresses confined to .41–.74.

Operational notes

Runs are sequential: every ISO build shares $PHOTON_TREE/stage, and C: has ~138 GB free, so VMs are torn down after verification rather than kept. Nothing ever blanket-stops VMs — this host runs other VMs including live CI runners, so every operation targets mc-<perm> by name. VMs live at C:\photon-mc\vm, deliberately not under OneDrive: the hand-made test VM lived under OneDrive\Dokumente\Virtual Machines and vanished mid-session.

Two ISOs the matrix needs (minimal/latest, full/latest) cannot be built until the installer version bump lands — mc-build-iso.sh refuses with a clear message rather than silently building the wrong thing.

ISO-PERMUTATION-MATRIX.md states of itself "No builds were run." Fourteen of
its sixteen rows are dependency-resolution predictions or code reading; only
two were ever installed. This is the execution layer it lacks: build the ISOs,
stage the VMs, drive the installs, verify against an oracle that names the PR
behind every failure.

Reuses the mechanics of vm-lab - VMX discipline, thin disks, stash-never-delete
teardown, the serial-log liveness instrument - and drops everything specific to
the SPAGAT-Librarian appliance, which is out of scope.

What makes it tractable: POI's isoInstaller reads guestinfo.kickstart.data via
vmtoolsd, and /usr/bin/vmtoolsd is in the installer initrd (open-vm-tools is in
packages_installer_initrd.json). A per-permutation kickstart is therefore one
line in the VMX - no ISO remaster, no HTTP server, no boot-menu typing. That
separates the build-time axes (ISO type, installer version -> 4 cached ISOs)
from the install-time axes (STIG, filesystem, kickstart vs UI -> free), so 34
permutations need only 4 builds.

Both install paths are driven, because each has a failure mode the other
cannot reach: the STIG menu is UI-only, so a kickstart must list
KS_STIG_PACKAGES by hand; the security: key failure is kickstart-only on POI
2.8, and security: {fips} is reachable exclusively from a kickstart on either
version. The same underlying failure also surfaces differently on the two
paths, so one oracle calibrated on one path would misread the other.

Every assertion names the PR it proves, so a failing row reports "POI#11"
rather than "something broke". Currently covers PR#9, PR#21, PR#22, PR#24,
POI#9, POI#10 and POI#11.

Verified on this host rather than assumed:
  - vmrun and vmware-vdiskmanager execute from WSL; preflight passes
  - a real VM was created end to end: 4.1 MB thin disk for a 32 GB volume,
    unique MAC/UUID, correct Windows paths, kickstart injected as guestinfo
  - the interactive variant emits no active guestinfo line at all, which is
    what selects the curses configurator
  - teardown stashed the chain and preserved the VMX and serial logs
  - generated kickstarts validate against POI's own known_keys for all four
    variants, so none can abort the install on an unknown key
  - the oracle ran against a live Photon guest and reported correctly

Four portability traps found and handled while building it:
  - /usr/bin/grep is toybox in a non-interactive shell and has NO -a: it
    returns zero matches on a NUL-bearing serial log instead of erroring.
    Interactively grep is ugrep, which supports -a and -P. mc_grep_count
    strips NULs first rather than trusting either.
  - grep -P and sed \U are GNU extensions, absent here for the same reason.
  - vmrun output is CRLF; every parse strips \r.
  - a cksum-based permutation index collided on this very matrix (k04/k16 and
    k09/s02 shared a MAC, UUID and IP) and could reach .240, inside VMnet8's
    DHCP range. The index is now the ordinal in permutations.tsv.

Signed-off-by: Daniel Casota <dcasota@gmail.com>
Two corrections after first contact with the real host.

The poi=latest rows do not need anything merged.
  Requiring dcasota/photon#26 to land before its own rows could run inverted
  the point of the harness: you would be merging untested code to be able to
  test it. Each installer variant now gets its own patch, assembled by
  cherry-picking the PR branches onto a pristine 5.0 in a throwaway clone:

    poi-2.8.patch     5.0 + #9 #19 #21 #22 #23 #24    27 files
    poi-latest.patch  5.0 + #9 #21 #22 #23 #24 #26    26 files

  #19 and #26 are alternatives - #19 adds patches to 2.8, #26 moves to v2.9
  where three of them are already upstream - so exactly one is in each.
  Both are verified to apply to a pristine 5.0 before use.

  The variant is selected by staging a script directory, not by editing the
  build script: runPh5_normal.sh resolves its patch relative to its own
  location and uses SCRIPT_DIR for nothing else (:75, :163).

The UI rows now hand the operator a generated instruction card.
  mc-operator-card.sh prints exactly what to enter - partition sizes and
  filesystem, hostname, root password, and the STIG answer - built from
  permutations.tsv so it cannot drift from the matrix it exercises.
  mc-install.sh --no-wait starts the VM and returns instead of polling, so
  the caller can surface the card and verify when the human is done.

Also fixed: a path bug that cost two failed builds.
  runPh5_normal.sh resolves downstream-fixes.patch relative to ITSELF, and
  this host has two copies of both. The scripts-repo copy carried a stale
  8-file patch that no longer applies while /root carried the live 27-file
  one, so the build died with "does not apply" on linux.spec:77 - which
  reads like a rebase problem rather than a path problem. PHOTON_SCRIPTS now
  points at the live pair, and mc-preflight.sh asserts that the patch the
  build will resolve is the same file preflight validated.

Signed-off-by: Daniel Casota <dcasota@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant