Skip to content

feat(custodian): add the Cloud Custodian exemplar image - #149

Draft
castrojo wants to merge 1 commit into
mainfrom
feat/custodian-exemplar
Draft

feat(custodian): add the Cloud Custodian exemplar image#149
castrojo wants to merge 1 commit into
mainfrom
feat/custodian-exemplar

Conversation

@castrojo

Copy link
Copy Markdown
Contributor

Refs #123, #113. Draft — the image is wired but not yet built. See Blocked on below.

Image #1 of the catalog, chosen in #117 because upstream ships c7n on ubuntu:24.04 with apt and a named user (which Kubernetes runAsNonRoot rejects), it is a Python app so it rides this repo's existing python lane, and it is five images from one upstream generator — so it can demonstrate the marginal-cost collapse directly.

The reusable output: offline Python packaging

This is the part worth reviewing, because every future Python rider inherits it. The grid has no network during the build phase, so pip install is not available:

  • pyproject (community plugin) builds PyPI sdists with --no-isolation against declared build-depends. This is the pattern FSDK's own python3-* components already use — reused deliberately rather than invented.
  • zip source for c7n itself, because cloud-custodian publishes a wheel and no sdist.
  • cargo2 for rpds-py, jsonschema's compiled Rust dependency, vendoring crates from Cargo.lock. Without it the tree cannot be built offline at all.

The 8-site diff (this is what Wave 3 templatises)

# Site Change
1 elements/custodian/custodian-stack.bst new
2 elements/custodian/custodian-runtime.bst new
3 elements/custodian/c7n.bst + 16 python3-* dependency elements new
4 elements/oci/custodian.bst new (113 lines)
5 elements/targets.json +6 lines
6–8 Justfile (DESC, size, smoke) + .github/workflows/oci-images.yml (smoke) edited

Plus project.conf (+13: three plugin registrations) and include/aliases.yml (+1: crates).

The 16 hand-declared dependency elements are the headline cost — that is what no-network builds cost per Python image today, and precisely what Wave 3's generator exists to stop paying repeatedly.

Blocked on: grid admission

The chain builds green through botocore (8m19s), boto3, s3transfer, dateutil. Then rpds-py uploads its input root and sits in the scheduler queue while both workers idle at ~7–14m CPU — nothing is compiling.

Neither node carries the lab.projectbluefin.io/usb4-link=up label that projectbluefin/lab docs/skills/cluster-tooling/buildstream.md documents as a hard BuildStream admission requirement:

When the ghost↔exo-0 USB4 link is down … no BuildStream build may run.

So this is an infrastructure gate, not an element defect. Worth noting the failure mode is a silent indefinite queue rather than a clear rejection.

Not done yet

Deliberately not hand-writing the other four c7n images: #113 is explicit that five hand-written trees is a failed exemplar.

Image #1 of the catalog (#123, chosen in #117), wired by hand through all
eight sites so Wave 3 has a concrete diff to templatise. Upstream ships c7n on
ubuntu:24.04 with apt and a named user, which Kubernetes runAsNonRoot rejects;
this rides the existing python lane instead.

The substantive problem this solves is offline Python packaging, and the
answer generalises to every future Python rider:

  pyproject (community plugin) builds PyPI sdists with --no-isolation against
  declared build-depends, which is what FSDK's own python3-* components do.
  Reusing that pattern rather than inventing one is the whole point.

  zip source for c7n itself, because cloud-custodian publishes a wheel and no
  sdist.

  cargo2 for rpds-py, jsonschema's compiled Rust dependency, vendoring crates
  from Cargo.lock. Without it the dependency tree cannot be built offline at
  all, since the grid has no network during the build phase.

Sixteen dependency elements are declared explicitly rather than resolved at
build time; that is the cost of no-network builds and it is exactly the cost
Wave 3's generator exists to stop paying per image.

NOT YET BUILT. The dependency chain builds green as far as botocore (8m19s),
boto3, s3transfer and dateutil, then rpds-py stalls: the action uploads its
input root and sits in the scheduler queue while both workers idle at ~7-14m
CPU. Neither node carries the lab.projectbluefin.io/usb4-link=up label that
lab's cluster-tooling skill documents as a hard BuildStream admission
requirement, so this is an infrastructure gate, not an element defect. Commit
the work rather than lose it; verification follows once the grid admits builds.

Refs #123, #113

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@castrojo

Copy link
Copy Markdown
Contributor Author

Code review of this branch (main...HEAD), verified against the pinned sources:

Critical — elements/custodian/c7n.bst: kind: zip is a staging source — it extracts the wheel (base-dir '*') into the build root, so c7n-0.9.51-py3-none-any.whl does not exist when python3 -P -minstaller <whl> runs. Use kind: remote with filename: so installer gets a real .whl.

Critical — elements/oci/custodian.bst: the prune of botocore/docs removes a runtime-imported package: botocore/client.py does from botocore.docs.docstring import ... at module load (also handlers.py, waiter.py). Every AWS call breaks. The real bulk is botocore/data (114 MiB of 116) — prune unused service models there instead.

High — python3-rpds-py.bst: build-args-local: rpds_py yields two positional args to python -m build (argparse: unrecognized arguments). Stage the sdist at build root or override build-commands to cd.

Medium: c7n 0.9.51 pins cryptography ==46.0.7 and urllib3 ==2.7.0 exactly; FSDK's 49.0.0 does not satisfy the pin — the element comment claims it does. Either verify compatibility and fix the comment, or pin rider-local copies.

Medium — Justfile: the 192 MiB verify ceiling is ~3x under the real size: botocore alone unpacks to 116 MiB before boto3/jsonschema/cryptography/c7n. Set from the first measured build.

Also: elements/custodian/*.bst and project.conf reference docs/skills/python-rider.md, which does not exist — this PR should add it (skill-improvement loop).

@castrojo

Copy link
Copy Markdown
Contributor Author

Code review (batch review pass 2026-08-24):

REQUEST-CHANGES — not merging.

  1. Red CI / self-declared incomplete: pr-build-oci (custodian, x86_64) and (aarch64) both failed (run 31351383254), and the PR body lists just verify, the size report, the linkage check, and the What is the non-root user contract for catalog images? #120 non-root verification as outstanding. just verify is the merge contract.
  2. Superseded by feat(catalog): make adding an image cost one declarative record #194 (catalog): once the catalog model lands, this PR breaks it: custodian is in targets.json with no catalog/custodian.yaml, so the conformance test, just export, and just verify all fail; the hand-written Justfile case arms conflict with feat(catalog): make adding an image cost one declarative record #194's deletions. Recommended path: rebase onto the catalog model — this image should become a single catalog/custodian.yaml record plus the hand-written elements/custodian/python3-* dependency tree (which the generator does not produce).

Design-wise the non-root /etc/passwd approach and the compose-time passwd write were reviewed and are sound — the work is good, it just needs to land on the new model with green CI.

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