component

package
v0.1.24-rc.10 Latest Latest
Warning

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

Go to latest
Published: Jul 22, 2026 License: MIT Imports: 28 Imported by: 0

Documentation

Overview

Package component defines the extension contract for the unbounded operator. A component is a unit of desired state the operator reconciles for Sites. Implementations satisfy either ClusterComponent (cluster-wide singletons such as net and machina) or SiteComponent (per-Site units such as metalman and storage) and are assembled into a Registry the SiteReconciler drives. Adding a component is a matter of implementing one interface and registering it; the reconcile loop, status conditions, ordering, and the Site-less pass are all driven from the registry.

Index

Constants

View Source
const (
	// FieldOwner is the server-side apply field manager the operator uses for
	// every object it applies.
	FieldOwner = "unbounded-operator"

	// CRDKind is the Kind of a CustomResourceDefinition object in the embedded
	// manifests. The operator installs CRDs once at startup, so components skip
	// them during reconcile.
	CRDKind = "CustomResourceDefinition"

	// SiteLabelKey is the canonical node label for site membership
	// (unbounded-cloud.io/site). Per-site components node-select on it.
	SiteLabelKey = unboundedv1alpha3.MachineSiteLabelKey

	// DeprecatedSiteLabelKey is the node site-membership label used by released
	// net controllers before the switch to unbounded-cloud.io/site. Per-site
	// workloads target either key during the deprecation window so they schedule
	// before the upgraded net has converged all Nodes to the canonical label.
	DeprecatedSiteLabelKey = "net.unbounded-cloud.io/site"

	// SingletonRequestName cannot collide with a valid Site name. Managed
	// singleton resource events use it independently of Site fan-out.
	SingletonRequestName = "__singletons"

	// BuildDefaultNamespace is the namespace baked into the embedded component
	// manifests at build time. RetargetNamespace rewrites it to the operator's
	// configured namespace when they differ.
	BuildDefaultNamespace = unbounded.DefaultSystemNamespace
)
View Source
const (
	ReasonReconciled     = "Reconciled"
	ReasonDisabled       = "Disabled"
	ReasonNoSites        = "NoSites"
	ReasonReconcileError = "ReconcileError"
)

Reason strings published on Site.status.conditions. They must be CamelCase alphanumeric to satisfy metav1.Condition validation.

Variables

View Source
var DefaultNamespace = unbounded.SystemNamespace()

DefaultNamespace is the namespace the operator installs components into. It follows the operator's own namespace (unbounded.SystemNamespace()).

Functions

func ConfigMapPayloadChanged

func ConfigMapPayloadChanged(oldConfig, newConfig *corev1.ConfigMap) bool

ConfigMapPayloadChanged reports whether two ConfigMaps differ in payload.

func ConfigMapPayloadHash

func ConfigMapPayloadHash(config *corev1.ConfigMap) string

ConfigMapPayloadHash hashes the complete ConfigMap payload. JSON provides a deterministic encoding for string-keyed maps, including binary values.

func IsRBACObject

func IsRBACObject(obj *unstructured.Unstructured, nameContains string) bool

IsRBACObject reports whether obj is an RBAC object (ServiceAccount, Role, RoleBinding, ClusterRole, or ClusterRoleBinding) whose name contains nameContains. It single-sources the shared decision of which RBAC objects in a bundled manifest set belong to a given component, so a cluster component that skips another component's RBAC and the per-Site component that applies it cannot drift apart.

func SetNamedContainerImage

func SetNamedContainerImage(obj *unstructured.Unstructured, name, image string) error

SetNamedContainerImage sets the image of only the container named name in a workload pod template, searching both initContainers and containers. Unlike SetPodSpecImages it leaves every other container untouched, so a workload that mixes an operator-managed image with pinned helper images (for example a component whose pod also runs a busybox init) keeps those helper images.

func SetPodSpecImages

func SetPodSpecImages(obj *unstructured.Unstructured, image string) error

SetPodSpecImages replaces every init and main container image in a workload.

func SiteNodeAffinity

func SiteNodeAffinity(siteName string) *corev1.Affinity

SiteNodeAffinity matches Nodes carrying either the canonical site label or the deprecated net-prefixed site label. The OR is required during migration.

func SiteOwnerReference

func SiteOwnerReference(site *unboundedv1alpha3.Site) metav1.OwnerReference

SiteOwnerReference builds the controller owner reference used for per-site resources. Using owner references rather than a Site finalizer lets Kubernetes garbage collect per-site workloads if a Site is deleted while the operator is down.

Controller is set so controller-runtime's Owns() watch (which enqueues only via metav1.GetControllerOf) re-reconciles the Site when an owned resource drifts or is deleted. BlockOwnerDeletion is intentionally left unset: setting it triggers the OwnerReferencesPermissionEnforcement admission check for update on sites/finalizers, which the operator ServiceAccount does not hold, and would cause every owned-object apply to be rejected.

func ToUnstructured

func ToUnstructured(obj client.Object) *unstructured.Unstructured

ToUnstructured converts a client.Object into its unstructured form.

func UpsertOwnerReference

func UpsertOwnerReference(refs []metav1.OwnerReference, owner metav1.OwnerReference) ([]metav1.OwnerReference, bool)

UpsertOwnerReference adds or updates owner in refs, returning whether the slice changed. An existing reference to the same owner (matched by UID, Kind, and APIVersion) is rewritten when its Name or Controller flag differs, so a resource adopted before Controller ownership was introduced converges to a controller reference on the next reconcile.

func YamlFiles

func YamlFiles(fsys fs.FS) ([]string, error)

YamlFiles returns the sorted list of YAML files in a manifest filesystem.

Types

type ClusterComponent

type ClusterComponent interface {
	// Name is the stable, unique component identifier (for example "net"). It is
	// used in logs and must be unique within a Registry.
	Name() string

	// ConditionType is the Site status condition type published for this
	// component (for example "NetReady"). It must be CamelCase alphanumeric and
	// unique within a Registry.
	ConditionType() string

	// Reconcile drives the component to its desired state given every Site and
	// reports the outcome.
	Reconcile(ctx context.Context, env *Env, sites []unboundedv1alpha3.Site) Result
}

ClusterComponent is a cluster-wide unit of desired state (for example net or machina). It reconciles once per pass from the full set of Sites and is never tied to a single Site, so it also runs on the Site-less pass (a Site deletion or a managed singleton-resource event).

Reconcile runs on every pass and must be idempotent. A not-ready Result does not by itself schedule a retry: the driver requeues on Result.Err or after Result.RequeueAfter, otherwise the component only re-runs when one of the watches it registers via WatchProvider fires. On the Site-less pass there is no Site status to publish, so a not-ready Result there is meaningful only through its Err or RequeueAfter.

type Config

type Config struct {
	ImageRegistry string
	ImageTag      string

	// APIServerEndpoint is injected into the machina controller config and
	// advertised to metalman.
	APIServerEndpoint string
}

Config carries operator-level settings components read while reconciling.

func (Config) Image

func (c Config) Image(repository string) string

Image returns the operator-managed image for repository.

type Env

type Env struct {
	Client    client.Client
	Scheme    *runtime.Scheme
	Namespace string
	Config    Config
}

Env is the shared execution context handed to every component. It bundles the Kubernetes client, scheme, target namespace, and operator Config together with the manifest-apply and helper machinery components use to reconcile.

func (*Env) ApplyManifestFS

func (e *Env) ApplyManifestFS(ctx context.Context, manifests fs.FS, mutate func(*unstructured.Unstructured) error) error

ApplyManifestFS server-side applies every YAML object in the manifest filesystem, running mutate on each decoded object first. A mutate that nils out obj.Object skips that object.

func (*Env) ApplyManifestFiles

func (e *Env) ApplyManifestFiles(ctx context.Context, manifests fs.FS, files []string, mutate func(*unstructured.Unstructured) error) error

ApplyManifestFiles applies a specific list of YAML manifest files from the filesystem. Callers use it to apply a curated subset (for example excluding an examples/ subtree that YamlFiles would otherwise include).

func (*Env) ApplyObject

func (e *Env) ApplyObject(ctx context.Context, obj client.Object) error

ApplyObject server-side applies a single object with the operator field owner.

func (*Env) DefaultConfigMap

func (e *Env) DefaultConfigMap(manifests fs.FS, name, component string) (*corev1.ConfigMap, error)

DefaultConfigMap extracts the named ConfigMap from a manifest filesystem and retargets it to the operator namespace. component names the manifest set for error messages.

func (*Env) DeleteIfExists

func (e *Env) DeleteIfExists(ctx context.Context, obj client.Object) error

DeleteIfExists deletes an object, treating an already-absent object as success.

func (*Env) InNamespaceNamed

func (e *Env) InNamespaceNamed(names ...string) func(client.Object) bool

InNamespaceNamed returns a matcher for objects in the operator namespace whose name is one of names.

func (*Env) InNamespaceWithPrefix

func (e *Env) InNamespaceWithPrefix(prefix string) func(client.Object) bool

InNamespaceWithPrefix returns a matcher for objects in the operator namespace whose name carries prefix followed by a non-empty suffix (a per-site config).

func (*Env) ListSites

func (e *Env) ListSites(ctx context.Context) ([]unboundedv1alpha3.Site, error)

ListSites returns every Site in the cluster.

func (*Env) ManagedConfigPredicate

func (e *Env) ManagedConfigPredicate(match func(client.Object) bool) predicate.Predicate

ManagedConfigPredicate fires for create and delete of ConfigMaps that match, and for updates only when the ConfigMap payload actually changed. It filters out status/metadata-only churn so a component is not re-applied on every event.

func (*Env) ManagedWorkloadPredicate

func (e *Env) ManagedWorkloadPredicate(match func(client.Object) bool) predicate.Predicate

ManagedWorkloadPredicate fires for create and delete of workloads that match, and for updates only when the workload generation changed.

func (*Env) OwnedWorkloadPredicate

func (e *Env) OwnedWorkloadPredicate() predicate.Predicate

OwnedWorkloadPredicate fires for create and delete of owned workloads, and for updates only when the generation changed. It carries no name match because the Owns() enqueue handler already scopes events to resources owned by the Site; the predicate exists only to drop status-only churn (pod counts) so drift and deletion self-heal without re-applying on every status update.

func (*Env) RequestSingleton

func (e *Env) RequestSingleton() handler.EventHandler

RequestSingleton enqueues the synthetic singleton request. Cluster components use it to map events on their managed singleton workloads back to a reconcile that reconciles cluster-wide state without any specific Site.

func (*Env) RequestSingletonAndAllSites

func (e *Env) RequestSingletonAndAllSites() handler.EventHandler

RequestSingletonAndAllSites enqueues the singleton request plus every Site, so a change to a shared cluster config re-reconciles cluster state and refreshes each Site's status conditions.

func (*Env) RequestSiteFromConfigName

func (e *Env) RequestSiteFromConfigName(prefix string) handler.EventHandler

RequestSiteFromConfigName maps a per-site ConfigMap named "<prefix><site>" back to a reconcile request for that Site. Names without the prefix, or with an empty site suffix, are ignored.

func (*Env) RetargetNamespace

func (e *Env) RetargetNamespace(obj *unstructured.Unstructured)

RetargetNamespace rewrites embedded-manifest references from the build-time default namespace (BuildDefaultNamespace) to the operator's configured namespace. It is a no-op in the default install where the two are identical.

type Registry

type Registry struct {
	Cluster []ClusterComponent
	Site    []SiteComponent
}

Registry is the ordered set of components the SiteReconciler drives. Cluster components run in every pass; Site components run only when a Site is present. Conditions are published Cluster-first then Site, so the order of these slices is the stable condition order on the Site status.

func (*Registry) Validate

func (r *Registry) Validate() error

Validate rejects an empty registry and duplicate Name or ConditionType values across both lists, so a misconfigured registry fails fast at startup rather than silently dropping or double-publishing a condition.

type Result

type Result struct {
	Ready   bool
	Reason  string
	Message string
	Err     error

	// RequeueAfter, when positive, asks the driver to re-run the Site after the
	// given duration even without an error or a watch event. The driver uses the
	// smallest positive RequeueAfter across all components in a pass.
	RequeueAfter time.Duration
}

Result is the outcome of reconciling a single component for one pass. The SiteReconciler translates it into a Site status condition (Ready -> ConditionTrue/False, Reason, Message) and aggregates Err into the reconcile error so a failing component requeues the Site.

A not-ready Result without an Err does not by itself trigger a retry: the driver requeues on Err (with backoff) or after the smallest positive RequeueAfter across components. A component that is waiting on state it does not watch should set RequeueAfter (see NotReadyAfter) so it is re-checked; otherwise it only re-runs when one of its watches fires.

func Disabled

func Disabled(message string) Result

Disabled reports a component that is intentionally not running.

func Failed

func Failed(err error) Result

Failed reports a component reconcile error. The error is surfaced both as the condition message and as the aggregated reconcile error.

func NoSites

func NoSites(message string) Result

NoSites reports a cluster component retained while no Sites exist.

func NotReady

func NotReady(reason, message string) Result

NotReady reports a component that is not yet ready for a caller-supplied reason without treating it as a reconcile error. It does not schedule a retry on its own; use NotReadyAfter, set Err, or rely on a watch to re-trigger.

func NotReadyAfter

func NotReadyAfter(reason, message string, after time.Duration) Result

NotReadyAfter reports a not-ready component and asks the driver to re-check the Site after the given duration, for readiness that depends on state the component does not watch (for example polling an external resource).

func Reconciled

func Reconciled() Result

Reconciled reports a successfully reconciled component.

type SiteComponent

type SiteComponent interface {
	// Name is the stable, unique component identifier (for example "metalman").
	Name() string

	// ConditionType is the Site status condition type published for this
	// component (for example "MetalmanReady").
	ConditionType() string

	// Enabled reports whether the component should run for the Site.
	Enabled(site *unboundedv1alpha3.Site) bool

	// Reconcile applies the component's desired state for the Site.
	Reconcile(ctx context.Context, env *Env, site *unboundedv1alpha3.Site) Result

	// Cleanup removes the component's per-Site resources when it is disabled.
	Cleanup(ctx context.Context, env *Env, site *unboundedv1alpha3.Site) error
}

SiteComponent is a per-Site unit of desired state (for example metalman or storage). The SiteReconciler runs it only when a Site is present, so Reconcile and Cleanup always receive a non-nil Site. The driver owns the enable/disable branch: it calls Reconcile when Enabled reports true and Cleanup when it reports false (or the Site is deleted via owner-reference garbage collection).

Reconcile runs on every Site event and must be idempotent. To self-heal owned resources on drift or deletion, set a controller owner reference (see Env.SiteOwnerReference) and register Owns via WatchProvider; a not-ready Result requeues only through Result.Err or Result.RequeueAfter.

type WatchProvider

type WatchProvider interface {
	SetupWatches(b *builder.Builder, env *Env)
}

WatchProvider is implemented by a ClusterComponent or SiteComponent that owns or watches resources whose churn should re-trigger its reconcile. The SiteReconciler calls SetupWatches on every component that implements it when wiring the controller.

Jump to

Keyboard shortcuts

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