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
- Variables
- func ConfigMapPayloadChanged(oldConfig, newConfig *corev1.ConfigMap) bool
- func ConfigMapPayloadHash(config *corev1.ConfigMap) string
- func IsRBACObject(obj *unstructured.Unstructured, nameContains string) bool
- func SetPodSpecImages(obj *unstructured.Unstructured, image string) error
- func SiteNodeAffinity(siteName string) *corev1.Affinity
- func SiteOwnerReference(site *unboundedv1alpha3.Site) metav1.OwnerReference
- func ToUnstructured(obj client.Object) *unstructured.Unstructured
- func UpsertOwnerReference(refs []metav1.OwnerReference, owner metav1.OwnerReference) ([]metav1.OwnerReference, bool)
- func YamlFiles(fsys fs.FS) ([]string, error)
- type ClusterComponent
- type Config
- type Env
- func (e *Env) ApplyManifestFS(ctx context.Context, manifests fs.FS, ...) error
- func (e *Env) ApplyObject(ctx context.Context, obj client.Object) error
- func (e *Env) DefaultConfigMap(manifests fs.FS, name, component string) (*corev1.ConfigMap, error)
- func (e *Env) DeleteIfExists(ctx context.Context, obj client.Object) error
- func (e *Env) InNamespaceNamed(names ...string) func(client.Object) bool
- func (e *Env) InNamespaceWithPrefix(prefix string) func(client.Object) bool
- func (e *Env) ListSites(ctx context.Context) ([]unboundedv1alpha3.Site, error)
- func (e *Env) ManagedConfigPredicate(match func(client.Object) bool) predicate.Predicate
- func (e *Env) ManagedWorkloadPredicate(match func(client.Object) bool) predicate.Predicate
- func (e *Env) OwnedWorkloadPredicate() predicate.Predicate
- func (e *Env) RequestSingleton() handler.EventHandler
- func (e *Env) RequestSingletonAndAllSites() handler.EventHandler
- func (e *Env) RequestSiteFromConfigName(prefix string) handler.EventHandler
- func (e *Env) RetargetNamespace(obj *unstructured.Unstructured)
- type Registry
- type Result
- type SiteComponent
- type WatchProvider
Constants ¶
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 )
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 ¶
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 ¶
ConfigMapPayloadChanged reports whether two ConfigMaps differ in payload.
func ConfigMapPayloadHash ¶
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 SetPodSpecImages ¶
func SetPodSpecImages(obj *unstructured.Unstructured, image string) error
SetPodSpecImages replaces every init and main container image in a workload.
func SiteNodeAffinity ¶
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.
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.
type Env ¶
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) ApplyObject ¶
ApplyObject server-side applies a single object with the operator field owner.
func (*Env) DefaultConfigMap ¶
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 ¶
DeleteIfExists deletes an object, treating an already-absent object as success.
func (*Env) InNamespaceNamed ¶
InNamespaceNamed returns a matcher for objects in the operator namespace whose name is one of names.
func (*Env) InNamespaceWithPrefix ¶
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) ManagedConfigPredicate ¶
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 ¶
ManagedWorkloadPredicate fires for create and delete of workloads that match, and for updates only when the workload generation changed.
func (*Env) OwnedWorkloadPredicate ¶
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.
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 Failed ¶
Failed reports a component reconcile error. The error is surfaced both as the condition message and as the aggregated reconcile error.
func NotReady ¶
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 ¶
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).
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 ¶
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.