[unbounded-system] Operator owns CRD lifecycle and config; harden migration#464
Merged
Merged
Conversation
…ration Make the unbounded-operator self-sufficient for CRD lifecycle and move environment-specific settings off Deployment args into a ConfigMap, then harden the legacy migration gates. Operator-owned CRDs: - Add operator.BootstrapCRDs: at startup the operator server-side applies every CRD embedded in the machina and net manifests and waits for each to become Established, before the manager starts (the typed Site informer cannot sync until the Site CRD is served). Idempotent on every start. - `kubectl unbounded install` no longer applies CRDs or takes --skip-crds; it bootstraps the operator and waits for its rollout, then for the CRDs. The reconcile loop skips CRD objects when applying net manifests. Config via ConfigMap: - Add deploy/unbounded-operator/04-configmap.yaml.tmpl (unbounded-operator-config), surfaced to the Deployment via envFrom. --api-server-endpoint and --reap-legacy-resources now default from UNBOUNDED_API_SERVER_ENDPOINT and UNBOUNDED_REAP_LEGACY_RESOURCES (an explicit flag still overrides). install writes api-server-endpoint into the ConfigMap instead of a Deployment arg. Migration hardening: - Detect legacy per-site metalman by Deployment name or canonical/deprecated site label, not a single label match. - Gate metalman reaping on the per-site replacement Deployment existing (presence gate, like net: hostNetwork host-port ownership). - Require storage DaemonSets to actually schedule (DesiredNumberScheduled >= 1 and observed generation current) before reaping the legacy supervisor, so a zero-desired DaemonSet no longer reads as ready. - Delete the legacy net-group Site CRD only after the new net controller is Available, so the GC does not transiently drop SiteNodeSlices mid-cutover. - Warn and emit an Event when a drained legacy namespace still holds non-operator workloads before the whole-namespace delete. - Reconcile Sites on generation changes only, so net/machina manifests are not re-applied on status-only Site updates. - Retarget the namespace as a substring (SA usernames, flag values), not just on exact-value equality. Tests: CRD bootstrap, env-var flag defaults, metalman detection/presence gate, storage readiness gates, net-controller CRD gate, foreign-workload detection; extend the upgrade e2e to assert the operator (not install) established and owns the Site CRD and that the operator-config ConfigMap is present.
de4a233 to
4071d64
Compare
Fixes from PR review of the operator CRD-lifecycle/config work. 1. install no longer reports success against an unavailable operator. waitForOperator gated on AvailableReplicas>=desired, which the old ReplicaSet satisfies while a new crash-looping pod surges in during an upgrade. Replace it with a full rollout-complete check (ObservedGeneration current and Replicas == UpdatedReplicas == AvailableReplicas == desired), the same condition `kubectl rollout status` waits on. 2. Liveness no longer kills the operator mid-bootstrap. BootstrapCRDs runs before the manager starts the health server, so /healthz is unserved for up to crdEstablishedTimeout (~2m) while liveness (10s + 3x15s) would restart at ~40s. Add a startupProbe with a 150s budget (30 x 5s) that exceeds the bootstrap timeout and suppresses liveness until the health server binds. 3. Re-install with a changed endpoint now rolls the operator. install wrote the endpoint only into the ConfigMap, but envFrom is read once at pod start and the pod template was unchanged, so no rollout occurred. Stamp a config-hash annotation (sha256 of the endpoint) onto the Deployment pod template; a changed endpoint changes the template and triggers a rollout that the strengthened waitForOperator waits on. 4. The make/GitOps render path can set the endpoint again. Restore .APIServerEndpoint into the operator-config ConfigMap and re-add the UNBOUNDED_OPERATOR_API_SERVER_ENDPOINT Makefile variable / --set. The Deployment template stamps the same config-hash (sprig sha256sum) so raw `kubectl apply` of re-rendered manifests also rolls on an endpoint change. --skip-crds stays removed (CRDs are operator-owned); documented as a breaking change in the CLI reference. Tests: rollout-complete table + waitForOperator upgrade/complete cases; config-hash stamped and endpoint-sensitive; BootstrapCRDs applies all 12 embedded CRDs and blocks until Established; a render test asserting the ConfigMap endpoint and the matching Deployment hash annotation stay in sync.
jveski
approved these changes
Jul 13, 2026
| # cannot be derived in-cluster. Set this before enabling machina provisioning. | ||
| # Rendered from .APIServerEndpoint so make/GitOps deploys can set it via | ||
| # --set APIServerEndpoint=; `kubectl unbounded install` overrides it in place. | ||
| UNBOUNDED_API_SERVER_ENDPOINT: {{ default "" .APIServerEndpoint | quote }} |
Contributor
There was a problem hiding this comment.
We discover this from kube-public in metalman, might be worth aligning on. I'm indifferent as to which approach we take as long as it's consistent.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Follow-up to #386 that was meant to land there. Targets the
feature/unbounded-systemintegration branch as part of umbrella #388.Makes
unbounded-operatorself-sufficient for CRD lifecycle, moves environment-specific settings into a ConfigMap, and hardens reconciliation and legacy migration against rollout, ownership, readiness, and configuration races.Operator owns CRDs
operator.BootstrapCRDs: at startup the operator server-side applies all 12 CRDs embedded in the machina and net manifests before starting the manager.kubectl unbounded installno longer applies CRDs or exposes--skip-crds; the breaking CLI change is documented.installwaits for a complete operator rollout, rejecting the old-ReplicaSet-available/new-pod-failing upgrade case, and then waits for CRD establishment.Config via ConfigMap
unbounded-operator-config, surfaced to the Deployment throughenvFrom.--api-server-endpointand--reap-legacy-resourcesdefault fromUNBOUNDED_API_SERVER_ENDPOINTandUNBOUNDED_REAP_LEGACY_RESOURCES; explicit flags retain precedence.UNBOUNDED_REAP_LEGACY_RESOURCESvalues now fail startup rather than silently enabling destructive migration.installand rendered-manifest workflows.UNBOUNDED_OPERATOR_API_SERVER_ENDPOINTto the Make/render path and make endpoint forwarding and YAML rendering safe for shell- and YAML-sensitive values.Machina config propagation
machina-configwhile preserving all other custom settings and comments.config.yamland stamp it on the Machina Deployment so configuration changes roll Machina, which reads its subPath-mounted config only at startup.machina-configchanges and enqueue Sites without re-enabling status-only Site reconciliation.Reconciliation reliability
GenerationChangedPredicatefiltering status-only updates.Migration hardening
--dhcp-auto-interfacesetting in the translated Site; malformed or conflicting values fail closed.events.k8s.iowrite access for the modern event recorder.Tests
Added or extended coverage for:
The kind-based operator reaper e2e now validates the migration against a real Kubernetes API server, including preserved Metalman mode and the Machina config rollout gate.
Verification
make fmtmake buildmake lintmake testgo test -tags=e2e ./e2e/operator/... -run TestOperatorReaperMigration -count=1 -v