feat(serviceactivation): shared, status-keyed service-enablement SDK#242
Closed
scotwells wants to merge 7 commits into
Closed
feat(serviceactivation): shared, status-keyed service-enablement SDK#242scotwells wants to merge 7 commits into
scotwells wants to merge 7 commits into
Conversation
Turn a project's ServiceEntitlement into an honest CLI experience with a service-agnostic package that plugins and datumctl core can adopt instead of forking the flow. It provides a pure classifier for the eight activation states (not requested, processing, pending approval, active, denied, revoked, unavailable, catalog unavailable), an interactive/non-interactive preflight gate, explicit request/renew/wait primitives, a shared status renderer, and a documented exit-code contract (10-13 for not-enabled / denied-or-revoked / pending / unavailable). Consumers configure it per service (object name, canonical name, display noun, and their own access verb) and inject a client and IO streams, so every consumer gets consistent wording and exit codes. Adds the go.miloapis.com/service-catalog dependency; the dependency-free plugin package is left untouched.
…ed clientset Swap the SDK's EntitlementClient implementation from a hand-built controller-runtime client to the generated services clientset (go.miloapis.com/service-catalog/pkg/generated). The public surface is unchanged — same EntitlementClient interface, Gate, Requester, and typed errors — so consumers are unaffected. The flow tests now run against the generated fake clientset, exercising the real adapter path. controller-runtime is no longer imported by this package; it remains a direct datumctl dependency only because core (internal/discovery, internal/client) still uses it.
…rviceName service-catalog stamps the controller-resolved canonical identifier onto status.serviceName (added in f03704c, tagged v0.3.0 — already present in the service-catalog version this branch pins). spec.serviceRef.name is only the Service object's k8s name, which does not generally equal the reverse-DNS canonical name; the two coincided in existing test fixtures by chance. canonicalNameOf now prefers status.serviceName and falls back to the spec reference only for entitlements the controller hasn't reconciled yet.
…tset's real error shape catalogAbsent used apimeta.IsNoMatchError, which only recognizes meta.NoResourceMatchError/NoKindMatchError — errors a RESTMapper-backed client produces. EntitlementClient is the generated typed clientset (gentype.ClientWithList over a fixed REST path, no RESTMapper), so a missing services.miloapis.com API group actually surfaces as a plain 404 apierrors.StatusError. The old check silently never matched in production, so the catalog-absent path (and its exit-13 Unavailable classification) was dead code — masked by a test fixture that manufactured the wrong error type. Also drop the SDK's local Ready-condition-type/reason string mirrors now that service-catalog exports them (servicesv1alpha1.ConditionTypeReady, Reason*) — same stale-assumption shape as the canonical-name fix, just not yet silently wrong since the literal values still matched.
Contributor
|
I've run into this too. Makes sense to formalize the flow. |
Contributor
Author
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.
What this enables
Datum services are enabled per project through a
ServiceEntitlement, and for a gated service (like compute) that request awaits a human approval on the provider side. Every CLI plugin that gates on enablement has had to hand-roll the same flow — and has gotten it wrong the same way: request access, wait a fixed 15 seconds, then printError:and "try again in a moment" no matter what actually happened, pointing atdatumctl services …commands that don't exist.This PR adds a shared, service-agnostic
serviceactivationpackage so plugins stop forking that flow and instead get one honest experience. It re-keys everything off the entitlement's own status, so the CLI tells the truth in every state.Before (what a user sees today, verbatim):
After (compute, the first consumer):
The request no longer reads as an error, pending approval is a legible waiting state, and every printed command exists. Scripts get deterministic, documented exit codes instead of a blanket exit 1.
What's in the package
serviceactivationis configured per service (object name, canonical name, display noun, and the plugin's own access verb) and takes an injected client plus IO streams:entitledAt;ServiceNotPublishedmaps to unavailable; transient relay reasons never drive control flow.--waitthat states up front that approval is a manual provider step with no time bound.EntitlementClientis backed by the generated typed clientset from feat(client): generated typed clientset for services.miloapis.com/v1alpha1 milo-os/service-catalog#50, not a hand-built client.The dependency-free
pluginpackage is deliberately left untouched; this package is its sibling and takes thego.miloapis.com/service-catalogdependency on its own.Follow-ups (not in this PR)
datumctl servicescommand group on these same internals, and ipam adopting the shared exit codes) are separate proposals.Design/rationale: the compute repo RFC
docs/compute/development/rfcs/cli-service-activation.md.Related
Depends on milo-os/service-catalog#50 (the generated clientset above) — pinned by pseudo-version, must be re-pinned to a tagged/merged release before this merges.
The compute plugin PR datum-cloud/compute#113 is the first consumer and depends on this PR. It currently pins this branch by pseudo-version for CI; it must be re-pinned to a tagged/merged datumctl version before merge.
Merge order: milo-os/service-catalog#50 → this PR → datum-cloud/compute#113.