Phase 8: smoke clusters as an ecosystem facility¶
This is a sub-plan of PLAN-remove-primary.md.
Phase 6 authored the reusable smoke-cluster.yml workflow in
shakenfist/actions and cut shakenfist's own CI over to it. Phase 8
turns the smoke cluster into a facility any ecosystem repo can use to
answer one question cheaply: have I completely and hilariously broken
things? — and retires the last copies of the getsf-era cluster CI.
Context¶
The master plan scoped phase 8 as replacing each downstream repo's
copy-pasted cluster-build workflow with a few-line workflow_call,
naming client-python, library-python and kerbside. Surveying the
ecosystem while drafting found a smaller migration but a broader
design question.
The landscape:
- client-python is the only downstream repo with a copy-pasted
nested-SF-cluster CI. Its
functional_matrix(debian-12,localhost,cluster-ci.conf) has been hard-broken since phase 6 deleted getsf; its getsfansible-modulesjob was removed in phase 6 step 5. - library-python does not exist; the master plan mention is stale.
- kerbside / kerbside-patches use SF as under-cloud infrastructure via bespoke tooling (already collection-migrated during the phase 6/7 fallout fixes). They have no nested-SF-cluster CI to migrate — but kerbside has SF-facing code (VDI console integration) that a cheap SF smoke check would protect.
- agent-python has no cluster CI. Note for later: the getsf-era
agent-from-checkout deploy path (
GETSF_AGENT_PACKAGE) did not survive into the collection — guests get their agent from the CI images — so agent-python smoke CI would not currently exercise an agent PR's code. Restoring that path is a prerequisite for meaningful agent-python adoption and is out of scope here. - No other org repo has cluster-shaped CI.
The design question: there are two kinds of consumer.
- Repos whose "not broken" check is SF's own smoke suite with their
component swapped into the cluster. client-python is the archetype:
setup-test-environmentchecks out the triggering repo at the PR sha and the others at develop, and the collection deploy builds the client wheel from that checkout — so a client PR is deployed into the cluster and the standard smoke suite exercises it. Theworkflow_callform fits these directly. - Repos whose "not broken" check is their own tests against a live SF
cluster. kerbside is the archetype. A reusable workflow cannot
serve them: it runs as a separate job, and cluster access (the
under-cloud namespace, inventory, ssh key,
/etc/sfcredentials) does not transfer between jobs. What they need is a composite action that deploys the smoke cluster inside their own job and leaves it usable by subsequent steps.
Both modes should share one deploy implementation, or we recreate the copy-paste drift this phase exists to end.
One reusable-workflow wart to fix before rollout: every bundle
uploads under the fixed name bundle-functional-cluster-smoke, so a
multi-entry run produces indistinguishable artifacts.
Decisions (phase-local)¶
- Extract the deploy into a
build-smoke-clustercomposite action. It performs: under-cloud topology → BYO MariaDB → Loki → generated inventory → collection deploy (server/client wheels from the checkouts) → wait-schedulable → base image import, and exposes the cluster's coordinates (primary address, inventory path, namespace) as action outputs.smoke-cluster.ymlbecomes a consumer of the action (deploy via the action, then its stestr/module-test/teardown steps as today), so there is exactly one deploy implementation. workflow_callconsumers use the smoke defaults. For a did-I-break-it check the right shape istier: smoke,localhosttopology,smoke-ci.conf— what shakenfist's own PR gate uses. client-python's oldcluster-ci.confover-paid; the server repo already runs the full suites on its own merges.- client-python adopts the workflow; kerbside gets the action.
client-python's caller replaces its broken job (keeping the
functional_matrixjob id; the operator flips the required status check at merge). A kerbside SF-integration smoke leg via the action is designed here but lands as its own kerbside PR when wanted — the facility existing is this phase's deliverable, the kerbside test content is kerbside's. - Artifact names become
bundle-<component>-<tier>[-<key>]. - The released/upgrade topologies stay, for now. Code review of
this phase found the "dead"
ci-topology-*-released.yml/-upgrade.ymlplaybooks are consumed from actions@main by nine workflows on shakenfist's v0.6-releases and v0.7-releases branches (backport pushes and PRs run them). They are retained until those release branches' CI is formally retired; the lesson recorded here is that actions-repo grep gates must include release branches, not just default-branch checkouts. - Document the recipe. A short "adding SF smoke CI to your repo" section in the actions README covering both modes, so the next repo is a copy of six lines rather than six hundred.
Steps¶
| # | Repo | Description |
|---|---|---|
| 1 | this | Plan. This document. |
| 2 | actions | Extract build-smoke-cluster. New composite action containing the deploy sequence currently inlined in smoke-cluster.yml; the workflow consumes it. Outputs: primary address, inventory path, under-cloud namespace. Artifact-name parameterisation and the component-selection documentation fix ride along. Validated by a shakenfist workflow_dispatch run (behaviourally unchanged, distinct artifact names). |
| 3 | client-python | Adopt the workflow. Replace the broken functional_matrix body with a uses: shakenfist/actions/.github/workflows/smoke-cluster.yml@main caller: component: client-python, component_ref: ${{ github.sha }}, smoke defaults otherwise, secrets: inherit. Un-breaks the repo's CI. Prepared as a branch; operator pushes, PRs, and updates the required status check (new context: "functional_matrix / Smoke tests (collection)"). |
| 4 | actions | Kerbside-mode worked example. Add the README recipe for both modes, including a concrete build-smoke-cluster example job (deploy, then run-your-own-tests against the outputs). Coordinate with kerbside on an actual SF-integration smoke leg as a follow-on kerbside PR (out of this phase's gate). |
| 5 | actions | ~~Delete the dead getsf-era topologies~~ Retained: the review's release-branch grep found live consumers on v0.6/v0.7-releases (see Decisions). Deletion is deferred to whenever those branches' CI is retired. |
| 6 | this | Bookkeeping. Flip the phase 8 row in PLAN-remove-primary.md and correct its stale repo list; code review of the phase and address findings. |
Risks¶
- Deploy extraction regression. Moving ~120 lines of workflow steps
into a composite action risks subtle env/step-context differences
(
$GITHUB_ENVpropagation,inputs.*vs${{ inputs }}scoping). Mitigated by validating shakenfist's own CI on the extracted form before any downstream adoption. - Required-check rename in client-python. Merge-then-flip sequence documented in step 3; the repo has no merge queue, so it is one setting.
- Cross-repo skew. A client-python PR depending on an unmerged shakenfist change cannot pass (cluster deploys develop server) — the pre-existing land-in-order policy, newly visible after the CI dark period.
- Composite-action mode tempts long-lived clusters. The action deploys into the caller's job on a shared under-cloud; the recipe must state the cluster's lifetime is the job and teardown is the under-cloud reaper's, mirroring today's behaviour.
Validation¶
- shakenfist workflow_dispatch run green on the extracted action, with per-job distinct bundle names.
- client-python PR run green end-to-end (develop server + PR client, smoke suite) via the reusable workflow.
- The README recipe's example job deploys and reaches the cluster in a scratch run.
- Grep gates: no getsf reference in live (non-release-branch) CI paths; gates over the actions repo must sweep release branches too.
Out of scope¶
- agent-python adoption (needs an agent-from-checkout deploy path in the collection first — recorded above).
- The kerbside SF-integration smoke leg's test content (kerbside's own PR, using the facility this phase provides).
- Collection publication to galaxy; the phase 7 deferred-removal PR; the node-lifecycle in-guest-kill flake.
- Released-version / upgrade testing redesign.
Cross-repo / operator actions¶
- Push actions/main for steps 2, 4 and 5.
- Push and PR the client-python branch (step 3), updating its required status check at merge time.
- After phase 8, the remove-primary master plan is complete; consider a v0.8 release to start the phase-7 deprecation clock.