Skip to content

ci: split the conformance leg and build the e2e images once - #371

Merged
onedr0p merged 1 commit into
mainfrom
ci/split-e2e-legs-and-share-images
Jul 29, 2026
Merged

ci: split the conformance leg and build the e2e images once#371
onedr0p merged 1 commit into
mainfrom
ci/split-e2e-legs-and-share-images

Conversation

@onedr0p

@onedr0p onedr0p commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

The conformance leg ran miroir's Go specs and the upstream external-storage suite back to back, which made it the longest lane by about fourteen minutes. Neither suite needs the other's state, so they get a leg each.

Every leg also rebuilt all three images itself, so a shared e2e-images job now builds them once and hands them to the matrix.

Why

Timings from a green run on #364 (30453357794):

leg job total test step
conformance 38m02 33m48
zfs 28m02 23m50
replicated 22m51 18m08
rwx 8m59 5m05
serial 8m06 3m54

The conformance leg's 33m48 was 1m39 install + 13m47 Go specs + 18m09 upstream suite. Splitting those gives roughly a 20m leg and a 24m leg, so the critical path drops to about 28m and zfs becomes the new ceiling.

There is no slack left inside a leg. Sum-of-spec-time against wall clock at procs=4, from the JUnit artifacts:

leg Σ spec time wall speedup
conformance 68.7m (109 specs) 18m09 3.78× / 95%
zfs 79.4m (120 specs) 23m50 3.33× / 83%
replicated 57.6m (119 specs) 18m08 3.18× / 79%

procs cannot go higher either — the runner is 4 CPU / 15.61 GiB already hosting three VMs. More clusters is the only lever, which is what this change spends.

Changes

Splitconformance becomes specs (Go specs, conformance: "0") and local (upstream suite), both on testdriver-local.yaml with capacity on. This reuses the RUN_CONFORMANCE knob and conformance: "0" convention already in test.sh for the autodiskful leg, so test.sh is unchanged.

Shared images — a new e2e-images job builds controller/agent/gateway with load: true, exports all three in one docker save | gzip (~135MB, since gateway shares every agent layer) and uploads it as an artifact. Each leg downloads and loads it into its own runner-local registry while its VMs boot, so nodes still pull over loopback and patches/registry.yaml is untouched.

Fallout that cleaned up on its own:

  • The gateway image was built by every leg and installed by one. Building once removes that without a special case.
  • The cache-to: ${{ matrix.suite == 'replicated' && … }} ordering hack is gone. One job owns each scope, so each cache-to is unconditional and the cache cannot go unwritten if that leg is renamed or fails early.
  • setup-buildx and its network=host are gone from the legs entirely.
  • The Go module cache is now gated on matrix.specs == '1', and the e2e.test download on matrix.conformance != '0'.

Verified

The image path was run locally end to end rather than assumed: built all three, docker save of the set is 135MB, docker load restores all three localhost:5000/…:e2e tags, and pushing into a real registry:3 gives a catalog with all three.

actionlint (with the shared workflow-lint action's own ignore flags), zizmor, shellcheck, go vet -tags e2e and golangci-lint are clean.

One bug caught while writing it: GitHub's implicit run shell is bash -e {0} with no pipefail, so a failed docker save would have exited 0 via gzip and handed every leg a truncated tarball. That step sets shell: bash.

Tradeoff

The shared build job adds its own duration to the front of every leg, since the per-leg builds were previously hidden behind the cluster boot. The wall-clock win here comes from the split; the build job buys identical bytes across legs and the cache-scope cleanup. It also scales — the more the matrix shards, the more a single build amortises.

Next

Sharding the heavy upstream legs by [Testpattern: …] should take the critical path to roughly 14-16m. run.sh already reads FOCUS/SKIP from env, so it is matrix-only work — but setting SKIP in a matrix row overrides run.sh's default \[Disruptive\]|\[Serial\]|…, which would re-admit Serial specs into a parallel shard. That wants append semantics first.

The conformance leg ran miroir's Go specs and the upstream external-storage
suite back to back, which made it the longest lane by about fourteen minutes
(38m against the next-longest 28m). Neither suite needs the other's state, so
they get a leg each -- specs and local -- both against the miroir-local class.
A fresh cluster costs about six minutes, so the split is a clear win.

Every leg also rebuilt all three images itself, which meant six builds racing
one GHA cache scope apiece and an ordering hack where only the replicated leg
wrote each scope back. A new e2e-images job builds them once, exports all
three in a single docker save (~135MB, since gateway shares every agent
layer), and hands them to the matrix as an artifact. Each leg loads it into
its own runner-local registry while its VMs boot, so the nodes still pull over
loopback and every leg now installs identical bytes.

The gateway image was being built by every leg and installed by one; building
once removes that without a special case. Export uses shell: bash for the
pipefail the implicit `bash -e` default lacks, or a failed save would pass the
step on gzip's exit status and hand every leg a truncated tarball.

Signed-off-by: Devin Buhl <devin@buhl.casa>
@onedr0p
onedr0p merged commit 3d58054 into main Jul 29, 2026
23 of 26 checks passed
@onedr0p
onedr0p deleted the ci/split-e2e-legs-and-share-images branch July 29, 2026 15:31
gabrielcosi pushed a commit to gabrielcosi/home-ops that referenced this pull request Jul 29, 2026
….11.12 ➔ 0.11.13) (#185)

This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [ghcr.io/home-operations/charts/miroir](https://github.com/home-operations/miroir) | patch | `0.11.12` → `0.11.13` |

---

### Release Notes

<details>
<summary>home-operations/miroir (ghcr.io/home-operations/charts/miroir)</summary>

### [`v0.11.13`](https://github.com/home-operations/miroir/blob/HEAD/CHANGELOG.md#01113-2026-07-29)

[Compare Source](home-operations/miroir@0.11.12...0.11.13)

##### Bug Fixes

- **csi:** refuse to reformat a restore whose device reads blank ([#&#8203;373](home-operations/miroir#373)) ([b7ab14b](home-operations/miroir@b7ab14b))

##### Continuous Integration

- split the conformance leg and build the e2e images once ([#&#8203;371](home-operations/miroir#371)) ([3d58054](home-operations/miroir@3d58054))

</details>

---

### Configuration

📅 **Schedule**: (in timezone Europe/Berlin)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4wLjAiLCJ1cGRhdGVkSW5WZXIiOiI0NC4wLjAiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbInJlbm92YXRlL2NvbnRhaW5lciIsInR5cGUvcGF0Y2giXX0=-->

Reviewed-on: https://git.xcd.dev/gabrielcosi/home-ops/pulls/185
doonga pushed a commit to greyrock-labs/home-ops that referenced this pull request Jul 30, 2026
….11.12 ➔ 0.11.13) (#211)

This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [ghcr.io/home-operations/charts/miroir](https://github.com/home-operations/miroir) | patch | `0.11.12` → `0.11.13` |

---

### Release Notes

<details>
<summary>home-operations/miroir (ghcr.io/home-operations/charts/miroir)</summary>

### [`v0.11.13`](https://github.com/home-operations/miroir/blob/HEAD/CHANGELOG.md#01113-2026-07-29)

[Compare Source](home-operations/miroir@0.11.12...0.11.13)

##### Bug Fixes

- **csi:** refuse to reformat a restore whose device reads blank ([#&#8203;373](home-operations/miroir#373)) ([b7ab14b](home-operations/miroir@b7ab14b))

##### Continuous Integration

- split the conformance leg and build the e2e images once ([#&#8203;371](home-operations/miroir#371)) ([3d58054](home-operations/miroir@3d58054))

</details>

---

### Configuration

📅 **Schedule**: (in timezone America/New_York)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4wLjAiLCJ1cGRhdGVkSW5WZXIiOiI0NC4wLjAiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbInJlbm92YXRlL2NvbnRhaW5lciIsInR5cGUvcGF0Y2giXX0=-->

Reviewed-on: https://git.greyrock.io/greyrock-labs/home-ops/pulls/211
eleboucher pushed a commit to eleboucher/homelab that referenced this pull request Jul 31, 2026
….11.12 ➔ 0.11.15) (#1764)

This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [ghcr.io/home-operations/charts/miroir](https://github.com/home-operations/miroir) | patch | `0.11.12` → `0.11.15` |

---

### Release Notes

<details>
<summary>home-operations/miroir (ghcr.io/home-operations/charts/miroir)</summary>

### [`v0.11.15`](https://github.com/home-operations/miroir/blob/HEAD/CHANGELOG.md#01115-2026-07-31)

[Compare Source](home-operations/miroir@0.11.14...0.11.15)

##### Bug Fixes

- **csi:** log retryable status codes below error level ([#&#8203;380](home-operations/miroir#380)) ([4774d21](home-operations/miroir@4774d21))
- **snapshot:** lift possibly-set barrier on failed suspend-io and sweep mid-runtime ([#&#8203;382](home-operations/miroir#382)) ([09e3aa7](home-operations/miroir@09e3aa7))

### [`v0.11.14`](https://github.com/home-operations/miroir/blob/HEAD/CHANGELOG.md#01114-2026-07-30)

[Compare Source](home-operations/miroir@0.11.13...0.11.14)

##### Features

- **go:** update module google.golang.org/grpc (v1.82.1 → v1.83.0) ([#&#8203;375](home-operations/miroir#375)) ([572e629](home-operations/miroir@572e629))

##### Bug Fixes

- **ci:** key the lint cache on the toolchain and drop the prefix fallback ([#&#8203;374](home-operations/miroir#374)) ([789e990](home-operations/miroir@789e990))

### [`v0.11.13`](https://github.com/home-operations/miroir/blob/HEAD/CHANGELOG.md#01113-2026-07-29)

[Compare Source](home-operations/miroir@0.11.12...0.11.13)

##### Bug Fixes

- **csi:** refuse to reformat a restore whose device reads blank ([#&#8203;373](home-operations/miroir#373)) ([b7ab14b](home-operations/miroir@b7ab14b))

##### Continuous Integration

- split the conformance leg and build the e2e images once ([#&#8203;371](home-operations/miroir#371)) ([3d58054](home-operations/miroir@3d58054))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xMDEuMSIsInVwZGF0ZWRJblZlciI6IjQzLjEwMS4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZS9jb250YWluZXIiLCJ0eXBlL3BhdGNoIl19-->

Reviewed-on: https://git.erwanleboucher.dev/eleboucher/homelab/pulls/1764
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