Commit Graph

426 Commits

Author SHA1 Message Date
goodolclint-claude[bot] d5678284bc docs: full macOS recipe for the integration flow, and the shared VMID hazard
Expands the Rosetta note into a working recipe, after running the whole
provision -> test -> cleanup lifecycle on an Apple Silicon Mac against the real
parent cluster.

Compose is the wrong entry point on a Mac: its dev-infra service builds rather
than pulls, and bind-mounts /opt/pve-integration, which does not exist there.
The macOS path pulls the image CI already built and drives run-integration.sh
with docker run. Records that GHCR needs a classic PAT, since fine-grained
tokens cannot reach it at all and the failure gives no hint why.

Restores the x86 compose instructions, which the previous commit's rewrite
consumed, and hoists the fixed-VMID warning out of the macOS section — 5080,
5091 and 5092 are shared with CI on the same parent cluster whatever host you
run from, so a local run during a CI run collides, and a skipped force-cleanup
fails the next run's headroom guard.

Also warns that emulation runs the suite ~40% slower and so loses the
qemu-server flock race (#113) that CI wins: Reset-PveVm, clone and
Set-PveVmConfig fail locally on a tree that is green in CI. Provisioning and
cleanup are unaffected.
2026-09-01 17:36:26 -05:00
goodolclint-claude[bot] 439a691516 docs: the dev-infra image needs Rosetta on Apple Silicon
"x86 only" was too strong. The image is amd64-only — proxmox-auto-install-assistant
and the HashiCorp apt repo publish no arm64 — but it builds and runs on Apple Silicon
once Docker Desktop's Rosetta emulation is on.

Under the default qemu translation pwsh starts and reports its version, then segfaults
on module discovery (uncaught target signal 11), which fails the build at
Install-Module Pester and would fail Pester at test time. With Rosetta enabled the same
Dockerfile builds to within 150 bytes of the image CI pushed for this commit, and
Invoke-Pester runs.

Worth stating explicitly because the failure is silent: the build step exits 1 with no
diagnostic output, which reads as a Dockerfile defect rather than an emulation problem.
2026-09-01 16:53:54 -05:00
goodolclint-claude[bot] 08ee3ae249 chore: repair the local dev path and delete its dead scaffolding
The local dev environment had drifted badly from CI. Remove the parts that no
longer describe anything real, and make the rest match how CI actually runs.

Delete tests/dev.ps1. It wrapped run-integration.sh, which CI calls directly,
and duplicated the module build that script already performs internally. As a
second entry point it drifted: it still offered the PVE 8 leg retired in #88,
mounted the Docker socket for storage containers replaced by the storage VM in
#87, and pointed its remote-host examples at a runner decommissioned in the ARC
migration. All four documents describing it used a positional syntax that bound
the bare word to -Tests and then fell through to -Shell, so every documented
command silently opened a container shell. Recorded as D019.

Delete tests/infrastructure/runner/, a self-hosted-runner-in-Docker superseded
by Actions Runner Controller.

Make disk_storage and iso_storage required. Their defaults named a NAS that the
lab replaced with Ceph, and CI overrides both from repository variables, so the
defaults only ever misled local runs. require_env now fails at the top of a run
rather than at terraform apply, and the descriptions point at tests/.env.test
because cmd_provision deletes terraform.tfvars before applying.

preflight-cleanup.sh no longer falls back to the literal "local" storage. An
unset TF_VAR_iso_storage now skips only the ISO branch, leaving VM destroy and
state cleanup intact, and emits a workflow annotation: force-cleanup is the
only cleanup CI runs and it wipes Terraform state, so a silent skip strands the
uploaded ISO with nothing left to reclaim it.

Drop docker-ce-cli and the /var/run/docker.sock mount. Nothing in the container
has called docker since #87 moved storage into a VM; the remaining docker calls
run inside that VM over SSH. The CI job image is built from the same target, so
this also removes a third-party apt repository from its supply chain.

Rewrite tests/.env.test.example against what the code now requires, and fix the
documented commands in CLAUDE.md, README.md, copilot-instructions.md and the
integration README.
2026-09-01 16:27:10 -05:00
goodolclint-claude[bot] 1a848ff2d8 Merge pull request #109 from GoodOlClint/docs/lane2-decisions
docs: record D017 and D018 for the two-lane CI split
2026-09-01 20:34:50 +00:00
goodolclint-claude[bot] c115863e07 docs: record D017 and D018 for the two-lane CI split 2026-09-01 15:29:32 -05:00
goodolclint-claude[bot] f95f08deb9 Merge pull request #108 from GoodOlClint/ci/lane2-reporting
ci: report package currency to a rolling issue and a data branch
2026-09-01 20:28:18 +00:00
goodolclint-claude[bot] e7f8460ff7 ci: report package currency to a rolling issue and a data branch
Acts on pre-push review findings from codex + correctness/security subagents.
2026-09-01 15:21:48 -05:00
goodolclint-claude[bot] 618e787650 Merge pull request #107 from GoodOlClint/chore/pre-push-review-discipline
docs: review before pushing, not after
2026-09-01 19:36:55 +00:00
goodolclint-claude[bot] 561c55ec57 docs: review before pushing, not after 2026-09-01 19:29:38 +00:00
goodolclint-claude[bot] 416fa70781 Merge pull request #106 from GoodOlClint/ci/lane2-workflow
ci: add the package-currency workflow (lane 2)
2026-09-01 19:28:48 +00:00
goodolclint-claude[bot] e5fa905ee2 ci: verify the reboot, split machinery failures from test failures
Acts on pre-push review findings from codex + correctness/security subagents.
2026-09-01 14:22:43 -05:00
goodolclint-claude[bot] a5dab58592 ci: add the package-currency workflow (lane 2) 2026-09-01 14:09:58 -05:00
goodolclint-claude[bot] fb778c17df Merge pull request #104 from GoodOlClint/ci/lane2-dist-upgrade
ci: opt-in dist-upgrade and reboot for the currency lane
2026-09-01 19:07:28 +00:00
goodolclint-claude[bot] 7e66dfc051 ci: opt-in dist-upgrade and reboot for the currency lane 2026-09-01 14:02:15 -05:00
goodolclint-claude[bot] c52d2e40e8 Merge pull request #103 from GoodOlClint/chore/bot-git-identity
chore: bot git identity for the large-push fallback
2026-09-01 18:56:06 +00:00
goodolclint-claude[bot] 593a7e116d Merge branch 'main' into chore/bot-git-identity 2026-09-01 18:52:27 +00:00
goodolclint-claude[bot] 88010048d1 Merge pull request #102 from GoodOlClint/test/cluster-asserts-node-b
test: assert node B joined by name, not an online-node count
2026-09-01 18:46:46 +00:00
goodolclint-claude[bot] 8f9f546b7a docs: env block takes effect immediately, not at next session start 2026-09-01 13:45:13 -05:00
goodolclint-claude[bot] 89a5a34337 docs: prefer MCP push_files; git push is the unverified large-push fallback
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-01 13:43:55 -05:00
goodolclint-claude[bot] c706315483 chore: attribute agent commits to the bot identity
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-01 13:42:10 -05:00
goodolclint-claude[bot] bdbd5eeb4d Revert CLAUDE.md push-convention note (claim was unverified) 2026-09-01 18:38:15 +00:00
goodolclint-claude[bot] 959b62c86f test: assert node B joined by name, not an online-node count
Closes #94
2026-09-01 18:37:22 +00:00
GoodOlClint f96511bbe0 Merge pull request #101 from GoodOlClint/ci/review-fail-closed
ci: fail the review job when no review actually ran
2026-09-01 13:35:21 -05:00
Clint Branham ae3b14fe47 ci: fail the review job when no review actually ran
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-01 13:33:06 -05:00
goodolclint-claude[bot] f6a0d547b3 Merge pull request #100 from GoodOlClint/ci/iso-name-hash-followup
ci: hash first-boot.sh into the cached auto-install ISO name
2026-09-01 18:29:51 +00:00
Clint Branham c15820b5aa ci: hash first-boot.sh into the cached auto-install ISO name
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-01 13:24:36 -05:00
GoodOlClint 5b1493e968 Merge pull request #99 from GoodOlClint/ci/review-bot-submits-verdict
ci: review bot submits a formal review verdict
2026-09-01 13:24:17 -05:00
Clint Branham 1edb9d6d74 ci: review bot submits a formal review verdict
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-01 13:20:52 -05:00
GoodOlClint 2c9f3d45a3 Merge pull request #98 from GoodOlClint/fix/restart-uses-native-reboot
fix: Restart-PveVm uses PVE's native reboot endpoint
2026-09-01 12:57:30 -05:00
goodolclint-claude[bot] d94cebae14 feat: VmService.RebootVm calls PVE's native reboot endpoint 2026-09-01 17:52:19 +00:00
goodolclint-claude[bot] b51a5a9352 docs: supersede D015, record D016 - native reboot avoids the cleanup race 2026-09-01 17:48:52 +00:00
goodolclint-claude[bot] b78d2423ff docs: changelog for the native reboot fix; correct the D015 entry 2026-09-01 17:47:17 +00:00
goodolclint-claude[bot] c5e73f4fc9 fix: Restart-PveVm uses PVE's native reboot endpoint (cmdlet + tests) 2026-09-01 17:46:21 +00:00
GoodOlClint 2846395662 Merge pull request #97 from GoodOlClint/fix/vm-config-lock-wait
fix: lifecycle -Wait blocks until the guest config lock clears
2026-09-01 11:54:18 -05:00
GoodOlClint fc5b2eb46b Merge branch 'main' into fix/vm-config-lock-wait 2026-09-01 11:53:12 -05:00
goodolclint-claude[bot] 27d12d8736 docs: D015 states the fallback tests the latest observation 2026-09-01 16:49:02 +00:00
goodolclint-claude[bot] 70c147b47d fix: post-loop fallback tests the latest poll, not "ever matched"
Review finding on #97: `statusReached` was sticky, so a guest that reached the
expected status once and then drifted away from it would still be reported as a
success at the deadline, contradicting the fallback's own meaning.

Track the most recent observation instead. A guest that drifts away and never
re-matches now raises PveTaskTimeoutException as it should. A failed poll leaves
the previous observation standing, so an API blip is not read as divergence.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-01 16:47:41 +00:00
goodolclint-claude[bot] 56578e7d1c Merge pull request #96 from GoodOlClint/ci/pve-9.2-iso
ci: test against the PVE 9.2 ISO

The nested nodes were pinned to proxmox-ve_9.1-1.iso while production runs 9.2.
Validated by runs 183/184; the cluster suite passed in both, and run 184 was
fully green at 148 passed / 0 failed / 5 skipped.
2026-09-01 16:37:31 +00:00
goodolclint-claude[bot] 7e8cda9328 docs: record D015 - lifecycle -Wait blocks until the guest config lock clears 2026-09-01 16:36:51 +00:00
goodolclint-claude[bot] 8cb1457ff2 docs: changelog entry and D015 for the config-lock wait 2026-09-01 16:35:36 +00:00
goodolclint-claude[bot] 5f1feb8b32 fix: wait for the config lock in WaitForStatusTransition; record D015 2026-09-01 16:34:27 +00:00
goodolclint-claude[bot] 3f63ddcad8 fix: lifecycle -Wait blocks until the guest config lock clears
PVE publishes a guest's new status while the operation still holds
/var/lock/qemu-server/lock-<vmid>.conf, so WaitForStatusTransition could return
while the guest was still locked and the caller's next request would fail with
"can't lock file ... got timeout".

Integration run 183 failed four tests from this one cause: Restart-PveVm -Wait
returned after 4.1s having seen "running", the following Stop-PveVm spent exactly
10.0s failing to take the lock, and that cascaded into the template convert,
clone, and remove tests. Run 184 - same commit, re-run - passed because its status
poll happened to take 10.1s, by which point the lock had cleared. The same
settling happens either way; the only variable is whether the wait absorbs it or
the next caller does.

The check goes in WaitForStatusTransition because all nine lifecycle call sites
(Start/Stop/Restart/Reset/Resume across VMs and containers) route through it.
`lock` comes from the status/current response the poll already fetches - present
on both qemu and lxc since PVE 5.4, below the module's 7.0 floor - so it costs no
extra request.

If the status is reached but the lock outlasts -Timeout the cmdlet still returns
success, so a call that succeeded before this change cannot become an exception
after it.

Recorded as D015, the guest-lock sibling of D014.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-01 16:33:47 +00:00
GoodOlClint 845628711b Merge pull request #95 from GoodOlClint/ci/pin-nested-pve-packages
ci: stop half-upgrading the nested PVE nodes
2026-09-01 10:14:30 -05:00
goodolclint-claude[bot] e549052348 Merge pull request #93 from GoodOlClint/test/cluster-join-link0
fix: New-PveCluster -Wait blocks until quorate; make cluster failures diagnosable

Adds ClusterConfigService.WaitForQuorum with a -Timeout parameter (D014), so
Add-PveClusterMember no longer hits "cluster not ready - no quorum?" after a
completed create task. Adds diagnose-cluster.sh, which captures corosync and
pmxcfs state plus PVE task logs from both nodes before cleanup destroys them.
2026-09-01 14:57:59 +00:00
goodolclint-claude[bot] e2bbe1224f ci: test against the PVE 9.2 ISO
The nested nodes were pinned to proxmox-ve_9.1-1.iso while production runs
9.2, so the suite was validating a PVE nobody uses. run-integration.sh already
reads PVE9_ISO with the 9.1 name only as a fallback, so this needs no script
change; setting it at the workflow level keeps provision and cleanup agreeing
on the ISO name, which force-cleanup needs to find the right file to delete.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-01 14:32:33 +00:00
goodolclint-claude[bot] 5e046e3d31 ci: stop half-upgrading the nested nodes
`apt-get upgrade` holds back any package whose upgrade needs new dependencies,
so it neither pins nor updates — it produces whatever partial set the
dependency graph allows that day. On these nodes it upgraded pve-cluster to
9.1.6 while leaving libpve-cluster-api-perl at 9.1.0.

Those two ship the halves of the join: cfs_backup_database() in
PVE/Cluster.pm (pve-cluster) and finish_join() in PVE/Cluster/Setup.pm
(libpve-cluster-api-perl). Upstream removed `return $dbfile` from the former
and stopped relying on it in the latter, both at 9.1.1 — 9.1.6's finish_join
calls cfs_unlink_db_unsafe() instead. The 9.1.0 caller against the 9.1.6
callee unlinks an empty string, so the standalone config.db survives the join,
pmxcfs restarts in local mode, and the node reports online=0 forever while
corosync forms a healthy 2-node membership. That is the "2 nodes online"
failure, and it is not reachable on any coherent install.

The ISO is the pin, so drop the upgrade and install only what the harness
needs. Upgrades belong in a separate currency lane that records the package
set it tested.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-01 14:25:50 +00:00
goodolclint-claude[bot] 1eb5b0f28d docs: changelog entry for the New-PveCluster quorum fix
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-01 13:59:38 +00:00
goodolclint-claude[bot] 5c6cd7f40f ci: probe whether pmxcfs came up clustered or in local mode
Run 173 left node B with healthy corosync (2-member primary component, both
links connected) but no /etc/pve/corosync.conf, no dcdb/status journal lines,
and pvecm status reporting it is not part of a cluster. That file is
database-backed: pmxcfs creates it only when it starts with no config.db and
imports /etc/corosync/corosync.conf, so a surviving standalone config.db would
mean silent local mode.

Capture the package versions, pmxcfs command line, /etc/pve mount, .members,
the config.db and its backup dir, whether the database holds a corosync.conf
row, and the CPG group membership. Read-only; the sqlite3 CLI is not guaranteed
on a PVE node, so fall back to strings.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-01 07:27:31 +00:00
goodolclint-claude[bot] 73d7978c64 docs: record D014 — New-PveCluster -Wait blocks until quorate
Also documents the two distinct timeout conventions in the module so the
-Wait vs HTTP-client distinction does not have to be re-derived.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-01 06:25:42 +00:00
goodolclint-claude[bot] 1df1b05876 test: drop the fixed sleep and the link0 pin from the cluster tests
New-PveCluster -Wait now guarantees quorum, so the Start-Sleep -Seconds 5
that lost the race is replaced by an assertion on the new contract.

The link0 pin is dropped: the join-abort and the never-a-member modes both
occurred with and without it, so it was never implicated, and -Links is
already covered at the service level.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-01 06:24:11 +00:00