plugins

package
v0.0.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 11, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewInsufficientResources added in v0.0.5

func NewInsufficientResources(msg string, cause error) *domain.AppError

NewInsufficientResources is the canonical helper for plugins to signal "scheduler / quota / cluster is full". The returned *AppError carries the kind in its Detail so callers can extract it via KindFromAppError without parsing the Message string.

cause may be nil; when non-nil it is preserved for logs but not exposed to API clients.

func NewInternal added in v0.0.5

func NewInternal(msg string, cause error) *domain.AppError

NewInternal marks a transient infrastructure failure. Equivalent to domain.NewInternal but also tags PluginErrKindInternal in Detail for explicit downstream classification.

func NewInvalidSpec added in v0.0.5

func NewInvalidSpec(msg string, cause error) *domain.AppError

NewInvalidSpec marks a plugin admission failure that won't be fixed by retrying with a smaller target (e.g. label validation, missing required field).

func Register

func Register(name string, f Factory)

Register adds a Factory under the given name. Intended to be called during host bootstrap or from an out-of-tree plugin's init().

Panics on duplicate names — extension wiring is a startup-time concern, and a silent overwrite would mask a programming error.

Types

type BasePlugin

type BasePlugin struct{}

BasePlugin provides no-op implementations for all Plugin hooks. Embed it in your plugin struct and override only the hooks you need.

func (BasePlugin) Name

func (BasePlugin) Name() string

func (BasePlugin) PreCreatePod

func (BasePlugin) PreCreatePool

func (BasePlugin) PreDeletePool

func (BasePlugin) PreUpdatePool

func (BasePlugin) Start

type Factory

type Factory func(h framework.Handle, ps providerset.Set, args framework.Args) (Plugin, error)

Factory constructs a Plugin from shared runtime dependencies (Handle), the Provider bundle (Set), and plugin-specific parameters (Args).

Plugins consume Providers from Set rather than holding their own ConfigMap watchers or API clients for cross-cutting concerns (catalog, quota, …). Passing nil args is legal for plugins that take no parameters; ps is always normalized (no nil fields) by Build before it reaches the Factory.

func Get

func Get(name string) (Factory, error)

Get looks up a registered Factory. Returns (nil, error) if the name is unknown.

type Plugin

type Plugin interface {
	// Name returns a unique identifier for this plugin (used in logs).
	Name() string

	// Start is called once during bootstrap, after the host has constructed
	// every plugin but before the reconciler begins processing. Plugins that
	// need their own informers (e.g. a ConfigMap-backed catalog) register
	// them here via the supplied framework.Handle.Cache(). A non-nil error
	// aborts program startup.
	Start(ctx context.Context, h framework.Handle) error

	// PreCreatePool is called after input validation and template resolution,
	// before the SandboxPool is persisted to Kubernetes. The plugin may:
	//   - Mutate pool.ObjectMeta / pool.Spec
	//   - Read from input for context (auth info, caller-supplied metadata)
	//   - Reject by returning an error (ideally *AdmissionError with status hint)
	//
	// Return updated=true when the plugin mutated pool. Callers are expected
	// to verify the mutation with equality.Semantic.DeepEqual against a
	// pre-call snapshot before persisting, so spurious updated=true is safe
	// (just wasteful) but missed updated=true silently loses the mutation.
	PreCreatePool(ctx context.Context, pool *agentsv1alpha1.SandboxPool) (updated bool, err *domain.AppError)

	// PreUpdatePool is called before the SandboxPool update is persisted.
	// newPool is the state that will be written; pods is the current Pod list
	// for context. The plugin may mutate newPool or reject the operation.
	// Return updated=true if newPool was mutated and must be persisted.
	PreUpdatePool(ctx context.Context, newPool *agentsv1alpha1.SandboxPool, pods []corev1.Pod) (updated bool, err *domain.AppError)

	// PreDeletePool is called before the SandboxPool is deleted from Kubernetes.
	// The plugin may reject the operation. Mutation is rarely meaningful here
	// (the object is about to be deleted); updated=true is reserved for the
	// niche case where a plugin needs to set a finalizer or annotation
	// before the delete proceeds.
	PreDeletePool(ctx context.Context, pool *agentsv1alpha1.SandboxPool) (updated bool, err *domain.AppError)

	// PreCreatePod is called after the Pod object is fully assembled but BEFORE
	// it is submitted to Kubernetes. Plugins may mutate pod.Spec (e.g. inject
	// NodeAffinity). A non-nil error aborts pod creation for this attempt;
	// the reconciler will retry on the next tick. Return updated=true when
	// the plugin mutated pod.
	PreCreatePod(ctx context.Context, pod *corev1.Pod, pool *agentsv1alpha1.SandboxPool) (updated bool, err *domain.AppError)
}

Plugin defines lifecycle hooks for SandboxPool operations. Implement only the hooks you need; embed BasePlugin for no-op defaults.

func Build

func Build(name string, h framework.Handle, ps providerset.Set, args framework.Args) (Plugin, error)

Build is a convenience helper: look up a Factory by name and invoke it. Equivalent to Get(name) followed by f(h, ps, args). The Set is normalized (nil fields → Noop) before the Factory sees it, so plugins can dereference any Provider field without a nil check.

type PluginErrorKind added in v0.0.5

type PluginErrorKind string

PluginErrorKind classifies the reason a plugin admission (PreUpdatePool, PreCreatePool, ...) failed. The SandboxEnv autoscaler uses it to decide whether to binary-search for a smaller acceptable target (cluster ran out of resources, but some smaller replicas count might fit) or back off entirely (the failure is transient infrastructure or invalid spec).

Plugins should populate this via NewInsufficientResources / NewInvalidSpec / NewInternal so callers can switch on the kind without parsing the AppError message. Plugins that do not classify themselves are mapped to a best-effort kind by KindFromAppError based on the HTTP-mapped error code.

const (
	// PluginErrKindUnknown is the default for plugin errors that did not
	// explicitly classify themselves. Treated by callers as Internal —
	// retry later, do not binary-search.
	PluginErrKindUnknown PluginErrorKind = ""

	// PluginErrKindInsufficientResources means the cluster, scheduler, or
	// quota system cannot satisfy the requested replica count, but a
	// smaller count might be admittable. The autoscaler reacts by
	// binary-searching the [current, candidate] range for the largest
	// admit-able value.
	PluginErrKindInsufficientResources PluginErrorKind = "InsufficientResources"

	// PluginErrKindInternal is a transient infrastructure failure (RPC
	// timeout, scheduler unavailable, etc.). The autoscaler does NOT
	// binary-search; it backs off and retries on the next reconcile cycle.
	PluginErrKindInternal PluginErrorKind = "Internal"

	// PluginErrKindInvalidSpec means the pool spec itself is wrong (bad
	// labels, missing fields, validation failure). Retrying with a smaller
	// replicas count would still fail; the autoscaler parks the pool in
	// Saturated/Misconfigured until the spec changes.
	PluginErrKindInvalidSpec PluginErrorKind = "InvalidSpec"
)

func KindFromAppError added in v0.0.5

func KindFromAppError(err *domain.AppError) PluginErrorKind

KindFromAppError extracts the PluginErrorKind from an *AppError.

Lookup order:

  1. err.Detail is a PluginErrorKind — return it directly (plugin opted in).
  2. Fall back to mapping err.Code: - 503 ServiceUnavailable / 429 TooManyRequests → InsufficientResources - 400 BadRequest / 422 UnprocessableEntity → InvalidSpec - anything else (including 500 Internal) → Internal

The fallback exists so existing plugins that don't yet use the typed constructors still produce reasonable classification — closed-source schedulers using domain.NewServiceUnavailable for "quota exhausted" are automatically picked up as InsufficientResources.

type PluginManager

type PluginManager struct {
	// contains filtered or unexported fields
}

PluginManager holds an ordered list of plugins and executes them sequentially for each lifecycle hook.

A nil *PluginManager is safe to use — all Run* methods are no-ops. This is the expected state for the open-source build (no plugins registered).

func NewPluginManager

func NewPluginManager(plugins ...Plugin) *PluginManager

NewPluginManager creates a PluginManager with the given plugins. Returns nil if no plugins are provided, enabling the nil-safe fast path.

func (*PluginManager) PreCreatePodHooks

func (m *PluginManager) PreCreatePodHooks(ctx context.Context, pod *corev1.Pod, pool *agentsv1alpha1.SandboxPool) (bool, *domain.AppError)

PreCreatePodHooks calls PreCreatePod on every registered plugin in order. Returns updated=true if any plugin mutated pod, and the first error encountered (short-circuits).

func (*PluginManager) PreCreatePool

func (m *PluginManager) PreCreatePool(ctx context.Context, pool *agentsv1alpha1.SandboxPool) (bool, *domain.AppError)

PreCreatePool calls PreCreate on every registered plugin in order. Returns updated=true if any plugin mutated pool, and the first error encountered (short-circuits).

func (*PluginManager) PreDeletePool

func (m *PluginManager) PreDeletePool(ctx context.Context, pool *agentsv1alpha1.SandboxPool) (bool, *domain.AppError)

PreDeletePool calls PreDelete on every registered plugin in order. Returns updated=true if any plugin mutated pool, and the first error encountered (short-circuits).

func (*PluginManager) PreUpdatePool

func (m *PluginManager) PreUpdatePool(ctx context.Context, newPool *agentsv1alpha1.SandboxPool, pods []corev1.Pod) (bool, *domain.AppError)

PreUpdatePool calls PreUpdate on every registered plugin in order. Returns updated=true if any plugin mutated newPool, and the first error encountered (short-circuits).

func (*PluginManager) Start

Start invokes Start on every registered plugin in order. If any plugin returns an error, Start stops and returns immediately — the caller should treat this as a fatal bootstrap failure.

Safe to call on a nil receiver (no-op).

type ProbeResult added in v0.0.5

type ProbeResult struct {
	Kind     ProbeResultKind
	Accepted int32
	Err      *domain.AppError
}

ProbeResult is the outcome of ProbeAcceptedReplicas.

Kind describes which branch terminated the search; Accepted is the largest replicas value the plugin admitted in [current, candidate] (always >= current); Err is the most recent non-OK *AppError, useful for surfacing diagnostic info on Env.Status.ObservedMember.

func ProbeAcceptedReplicas added in v0.0.5

func ProbeAcceptedReplicas(
	ctx context.Context,
	pm *PluginManager,
	pool *agentsv1alpha1.SandboxPool,
	pods []corev1.Pod,
	current, candidate int32,
) ProbeResult

ProbeAcceptedReplicas finds the largest replicas count in [current, candidate] that PluginManager.PreUpdatePool admits.

Algorithm:

  • Probe `candidate` first. If accepted, return ProbeOK{Accepted: candidate} (the common case — scheduler / quota has full headroom).
  • On InsufficientResources, binary-search the [current+1, candidate-1] range. The largest mid that admits becomes Accepted.
  • On Internal or InvalidSpec at any probe, abort immediately and return the corresponding kind. Internal errors must not look like saturation (transient infra problem); InvalidSpec must surface a Condition.

PreUpdatePool MUST be side-effect-free / idempotent — the existing plugin framework treats it as admission only, but plugin authors should be aware that ProbeAcceptedReplicas may call it O(log(candidate-current)) times.

pm may be nil (no plugins registered) — in that case every probe trivially succeeds and the function returns ProbeOK{Accepted: candidate} without allocating.

type ProbeResultKind added in v0.0.5

type ProbeResultKind int

ProbeResultKind enumerates outcomes from ProbeAcceptedReplicas. It tracks the *reason* the search terminated, in addition to the numeric Accepted value, so the autoscaler can decide whether to consider the candidate member saturated, surface an InvalidSpec condition, or simply retry later.

const (
	// ProbeOK — the full candidate replicas value was admitted; no binary
	// search was needed. Accepted == candidate.
	ProbeOK ProbeResultKind = iota
	// ProbeInsufficientResources — at least one probe in the search range
	// returned PluginErrKindInsufficientResources. Accepted is the largest
	// value that admitted (>= current; <= candidate). When Accepted > current
	// the autoscaler may still apply a partial scale-up.
	ProbeInsufficientResources
	// ProbeInternalError — a probe returned PluginErrKindInternal. The
	// search aborts immediately; Accepted is the best admitted value seen
	// so far (commonly current). The autoscaler should NOT mark the member
	// as saturated — the next reconcile will retry.
	ProbeInternalError
	// ProbeInvalidSpec — a probe returned PluginErrKindInvalidSpec. The
	// search aborts; the autoscaler should park the pool with an explicit
	// Condition rather than retrying with smaller targets.
	ProbeInvalidSpec
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL