Documentation
¶
Index ¶
- Variables
- func IsTerminal(err error) bool
- type Error
- func DependencyFailed(scheme *runtime.Scheme, o client.Object) *Error
- func DependencyNotFound(scheme *runtime.Scheme, o client.Object) *Error
- func DependencyNotReady(scheme *runtime.Scheme, o client.Object) *Error
- func Terminal(reason unikornv1.ProvisioningConditionReason, message string) *Error
- func UserActionRequired(reason unikornv1.ProvisioningConditionReason, message string) *Error
- func Yield(reason unikornv1.ProvisioningConditionReason, message string) *Error
- type ManagerProvisioner
- type Metadata
- type Provisioner
- type RemoteCluster
Constants ¶
This section is empty.
Variables ¶
var ( // ErrYield is raised when a provision/deprovision optation could // block for a long time, in particular the bits that wait for apllication // available status. This will trigger a controller to requeue the request. // The key things are that workers are unblocked, allowing other reconciles // to be triggered, and we can pick up an modifications (e.g. the cluster is // gubbed - thanks CAPO - and we can delete it without waiting for 10m as the // case used to be in the old world. ErrYield = errors.New("controller timeout yield") // ErrNotFound is when a resource is not found. ErrNotFound = errors.New("resource not found") // ErrTerminal marks a provisioning failure that will not self-heal and must // stop being requeued. // // WHY: today a provisioner that returns any error other than ErrYield is // requeued at a fixed interval forever (see reconcileNormal). There is no // way to say "give up". That is correct for transient faults but wrong for // permanent ones: a server whose provider create has been retried to // exhaustion, or a request that can never succeed, will otherwise spin the // workqueue indefinitely (observed in the wild: a counter climbing into the // hundreds against a cap of 3). Revival of an ErrTerminal resource is an // operator concern only — nothing the owning user can do to their own spec // will unstick it; see ErrUserActionRequired for the recoverable variant. // // This sentinel is intentionally a disposition, not a message. It is meant // to be matched with errors.Is so the manager can branch on it (stop // requeuing, write a terminal condition) rather than parsing prose. ErrTerminal = errors.New("provisioning terminally failed") // ErrUserActionRequired marks a provisioning failure that is terminal *for // now* but that the owning user can clear by changing the resource spec. // // WHY: a deterministic, user-caused failure (an invalid flavour, image, or // configuration) should not retry forever — retrying identical bad input is // pointless and hides the real problem — but it is also not a support case. // The remedy is in the user's hands: edit the spec. Controllers already wake // on a generation bump, so an ErrUserActionRequired resource naturally // resumes when (and only when) the spec changes. Splitting this from // ErrTerminal keeps "you can fix this" distinct from "call an operator", // which are different things to tell a user and different recovery paths. // // NOTE: making this disposition actually recoverable requires the owning // controller to clear any retry bookkeeping (e.g. attempt counters) on a // generation change; the sentinel alone does not do that. ErrUserActionRequired = errors.New("provisioning requires user action") )
Functions ¶
func IsTerminal ¶ added in v1.18.0
IsTerminal reports whether an error is a terminal provisioning disposition, i.e. one that must NOT be requeued.
WHY: the manager's requeue decision needs a single, authoritative test for "stop retrying this" rather than open-coding the set of terminal sentinels at each call site (and drifting when a new one is added). Both ErrTerminal and ErrUserActionRequired are terminal in the requeue sense — neither will be helped by another immediate reconcile. They differ only in how they are revived (operator vs spec change), which is a concern for the watch/predicate layer, not for the requeue decision.
Types ¶
type Error ¶ added in v1.18.0
type Error struct {
// contains filtered or unexported fields
}
Error is a provisioning error that pairs a disposition with a user-safe, machine-classifiable surface.
The manager funnels every provisioner error through a single condition message. Stringifying a raw error there is a fail-open leak of internal detail (CWE-209); at the same time, a bare code is unhelpful to the human reading it. Error separates the pieces that serve the different audiences:
- disposition: the machine-switchable outcome (ErrTerminal, ErrUserActionRequired, ErrYield), exposed via Unwrap so errors.Is keeps working. Lives in the type system, never in prose.
- reason: a closed-vocabulary ProvisioningConditionReason, machine-classifiable and written straight onto the Available condition's Reason field, e.g. DependencyFailed.
- message: user-safe human detail, written onto the condition's Message field, e.g. Network "prod-net" (a1b2) is not ready. It IS shown to the user, so it must be safe — name the user's own resources, never internal topology.
The manager surfaces reason and message directly onto the condition via SetProvisioningCondition (see Reason/Message); there is no flattening into a single string. Genuinely operator-only detail (provider internals, raw upstream errors) does NOT go in message: wrap the Error with fmt.Errorf instead. Error() embeds the wrapping for logs, and the manager's errors.As recovers the typed reason/message so the unsafe wrapping never reaches the user surface.
func DependencyFailed ¶ added in v1.19.0
DependencyFailed signals a wait on a dependency that is itself in an error state. It still yields (the dependency may recover), but names the failure so the wait is not mistaken for progress.
func DependencyNotFound ¶ added in v1.19.0
DependencyNotFound signals a referenced dependency that does not exist. It is terminal: waiting cannot resolve it. A referenced, finalized dependency that is nonetheless gone is a consistency violation, not a transient wait.
func DependencyNotReady ¶ added in v1.19.0
DependencyNotReady is the sanctioned way to signal a wait on a dependency that exists but is not yet provisioned. It binds the reason, the yield disposition, and a safe description together so a caller cannot mis-pair them.
func Terminal ¶ added in v1.18.0
func Terminal(reason unikornv1.ProvisioningConditionReason, message string) *Error
Terminal returns an ErrTerminal-dispositioned error: permanent, operator-only recovery. See ErrTerminal.
func UserActionRequired ¶ added in v1.18.0
func UserActionRequired(reason unikornv1.ProvisioningConditionReason, message string) *Error
UserActionRequired returns an ErrUserActionRequired-dispositioned error: terminal until the user changes the spec. See ErrUserActionRequired.
func Yield ¶ added in v1.19.0
func Yield(reason unikornv1.ProvisioningConditionReason, message string) *Error
Yield returns an ErrYield-dispositioned error carrying a reason code and user-safe message while still requeuing. It is the ErrYield sibling of Terminal and UserActionRequired.
func (*Error) Error ¶ added in v1.18.0
Error implements the error interface, embedding the reason and message so existing, unmodified logging surfaces them for free.
func (*Error) Message ¶ added in v1.19.0
Message returns the user-safe human detail to write onto the condition's Message field.
func (*Error) Reason ¶ added in v1.18.0
func (e *Error) Reason() unikornv1.ProvisioningConditionReason
Reason returns the closed-vocabulary provisioning reason to write onto the Available condition's Reason field.
type ManagerProvisioner ¶
type ManagerProvisioner interface {
Provisioner
// Object returns a reference to the generic object type, internally
// the provisioner will have a type specific version.
Object() unikornv1.ManagableResourceInterface
}
ManagerProvisioner top-level manager provisioners hook directly into the controller runtime layer, and are a little special in that they abstract away type specific things.
type Metadata ¶
type Metadata struct {
// Name is the name of the provisioner.
Name string
}
Metadata is a container for geneirc provisioner metadata.
func (*Metadata) ProvisionerName ¶
ProvisionerName implements the Provisioner interface.
type Provisioner ¶
type Provisioner interface {
// ProvisionerName returns the provisioner name.
ProvisionerName() string
// Provision deploys the requested package.
// Implementations should ensure this receiver is idempotent.
Provision(ctx context.Context) error
// Deprovision does any special handling of resource/component
// removal. In the general case, you should rely on cascading
// deletion i.e. kill the namespace, use owner references.
// Deprovisioners should be gating, waiting for their resources
// to be removed before indicating success.
Deprovision(ctx context.Context) error
}
Provisioner is an abstract type that allows provisioning of Kubernetes packages in a technology agnostic way. For example some things may be installed as a raw set of resources, a YAML manifest, Helm etc.
type RemoteCluster ¶
type RemoteCluster interface {
// ID is the unique resource identifier for this remote cluster.
ID() *cd.ResourceIdentifier
// Config returns the client configuration (aka parsed Kubeconfig.)
Config(ctx context.Context) (*clientcmdapi.Config, error)
}
Generator is an abstraction around the sources of remote clusters e.g. a cluster API or vcluster Kubernetes instance.