install

package
v0.0.0-...-9c8e2d0 Latest Latest
Warning

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

Go to latest
Published: Aug 11, 2026 License: AGPL-3.0 Imports: 53 Imported by: 0

Documentation

Overview

Package install holds the shared control-plane bootstrap engine used by both `clrk dev` (against a local k3d cluster) and `clrk install`/`clrk upgrade` (against a customer's existing cluster). It owns the typed-object manifest builders, the cluster-agnostic apply/verify helpers, the cluster preflight, the plan/diff/confirm flow, the progress orchestration, the readiness gate, cert wiring, and the upgrade version gate.

The package is deliberately k3d-free: it imports only controller-runtime and the leaf constant packages (internal/clickhouse, internal/nats, internal/ports, internal/otelemit, internal/eg, internal/crds, api/clrk/v1alpha1). The dependency edge points one way — internal/drivers (which pulls the heavy k3d v5 tree) imports internal/install, never the reverse — so the install/upgrade code path links and tests without any docker/k3d toolchain.

Index

Constants

View Source
const (
	// ControllerManagerName is shared by the cm ServiceAccount,
	// (Cluster)RoleBinding, Deployment, and Service.
	ControllerManagerName = "clrk-controller-manager"
	// WorkerAccountName is the ServiceAccount the worker Pods run under. It
	// aliases the API package's constant so the value is defined once (the pod
	// builder defaults spec.template.serviceAccountName to it).
	WorkerAccountName = clrkv1alpha1.WorkerServiceAccountName
	// EnvoyGatewayServiceName fronts the cm's in-process envoy-gateway xDS
	// listener under the well-known name the EG data-plane bootstrap dials.
	EnvoyGatewayServiceName = "envoy-gateway"
	// ConsoleServiceName fronts the cm's embedded web console port. It's a
	// dedicated single-port Service (not a port on the cm Service) so the
	// `clrk dev` auto-forwarder — which forwards a Service's first TCP port —
	// targets the console rather than the apiserver.
	ConsoleServiceName = "clrk-console"
	// APIServiceName is the aggregated APIService routing
	// clrk.apoxy.dev/v1alpha1 to the cm.
	APIServiceName = "v1alpha1.clrk.apoxy.dev"
	// MetricsAPIServiceName is the aggregated APIService routing the
	// Tier-1 metrics group (metrics.clrk.apoxy.dev/v1alpha1) to the cm.
	// Served by the same apiserver as APIServiceName; kube-aggregator
	// keys one APIService per group, so the metrics group needs its own.
	MetricsAPIServiceName = "v1alpha1.metrics.clrk.apoxy.dev"
	// DefaultWorkerPoolName is the name of the WorkerPool the installer creates
	// (its Deployment is WorkerDeploymentName, "default-workers").
	DefaultWorkerPoolName = "default"

	// DefaultNamespace is the control-plane namespace used by both `clrk dev`
	// and `clrk install` when none is specified. Same name in dev + prod.
	DefaultNamespace = "clrk"
)

Canonical object names shared by every component of the control plane. Kept here as the single source of truth so the cm Service/APIService/Deployment wiring and the downstream advertise URIs can't drift, and so callers outside this package (e.g. dev.go waiting on the cm Deployment) reference one name.

View Source
const WorkerDeploymentName = "default-workers"

WorkerDeploymentName is the Deployment WorkerPoolDeploymentReconciler creates for the `default` WorkerPool.

Variables

This section is empty.

Functions

func ApplyAndVerify

func ApplyAndVerify[T client.Object](ctx context.Context, a Applier, obj T, verify func(got T) error) error

ApplyAndVerify SSAs obj through the Applier (so it inherits the implementation's field manager), then re-GETs the stored object and runs verify against it. Returns nil iff the apply succeeded *and* verify saw the field it cares about. This catches the "SSA returned 200 but the spec didn't change" case that left a stale WorkerPool image in kine across multiple applies — the embedded apiserver (kine) is the failure surface, which is why the WorkerPool apply goes through here.

A free function with a type parameter (Go forbids generic methods) so the verify callback is typed at the call site. The freshly-zeroed verify target is built via the registered scheme rather than reusing obj, because SSA mutates obj (clears TypeMeta) in ways that confuse a subsequent GET.

func ApplyControllerManager

func ApplyControllerManager(ctx context.Context, a Applier, p Profile) error

ApplyControllerManager applies the cm control-plane objects through a, then applies-and-verifies the cm Deployment (env-count/image stripping guard). Mirrors the previous dev bootstrap: plain SSA for SA/RBAC/Services/APIService/ PVCs, ApplyAndVerify for the Deployment. Idempotent.

func ApplyWorkerPool

func ApplyWorkerPool(ctx context.Context, a Applier, p Profile) error

ApplyWorkerPool applies the worker SA + ClusterRoleBinding, then applies-and-verifies the `default` WorkerPool CR (image + privileged SecurityContext stripping guard). WorkerPoolDeploymentReconciler in the cm turns the CR into the worker Deployment + Service. Idempotent.

func BuildControllerManager

func BuildControllerManager(p Profile) []client.Object

BuildControllerManager returns the full ordered control-plane object set (SA, RBAC, Services, APIService, PVCs, Deployment) for rendering/planning. The Deployment is last so callers that apply-and-verify it can split the slice if they prefer; ApplyControllerManager does that split internally.

func BuildWorkerPool

func BuildWorkerPool(p Profile) []client.Object

BuildWorkerPool returns the worker RBAC + WorkerPool CR for rendering/planning.

func CurrentWorkerCount

func CurrentWorkerCount(ctx context.Context, c client.Client, ns, name string) (count int, ok bool, err error)

CurrentWorkerCount returns the replica count of the existing default WorkerPool in ns so `clrk upgrade` can carry it forward instead of resetting the fleet to the --workers flag default. ForceOwnership SSA would otherwise overwrite spec.replicas back to the default, silently scaling down an operator's fleet (set at install or scaled later). ok is false when the WorkerPool is absent or carries no explicit replica count, in which case the caller keeps its default.

func DeriveAPIServerCIDRs

func DeriveAPIServerCIDRs(ctx context.Context, c client.Client) ([]string, error)

DeriveAPIServerCIDRs collects the host-network source CIDRs the aggregation proxy can originate from: the kube-apiserver Endpoint addresses (default/ kubernetes) plus every node InternalIP, each as a single-host CIDR (/32 or /128). Aggregation requests reach the cm SNAT'd to one of these, so admitting them keeps the API reachable while excluding the pod network. Returns the (deduplicated) CIDRs; an error only if neither source can be read.

func DetectCertManager

func DetectCertManager(disco discovery.DiscoveryInterface) bool

DetectCertManager reports whether the cert-manager.io API group is served, which selects the cert-manager TLS path over the self-signed one.

func DetectInstall

func DetectInstall(ctx context.Context, c client.Client, ns string) (exists bool, version string, err error)

DetectInstall reports whether a clrk control plane already exists in namespace ns and, if so, the version stamped on its controller-manager Deployment (empty if unstamped). Used by preflight (install-vs-upgrade hint) and by the upgrade version gate.

func LoadRESTConfig

func LoadRESTConfig(kubeconfigPath, contextName string) (cfg *rest.Config, resolvedContext string, err error)

LoadRESTConfig resolves a *rest.Config for a customer cluster from an operator-supplied kubeconfig + context. Precedence for the kubeconfig file: explicit kubeconfigPath, else the KUBECONFIG env var, else ~/.kube/config — the standard client-go loading rules. contextName, when set, overrides the kubeconfig's current-context. Returns the config and the resolved context name (so the installer can show the operator exactly which cluster it is about to touch).

func PrepareTLS

func PrepareTLS(ctx context.Context, c client.Client, p *Profile) ([]client.Object, error)

PrepareTLS produces the serving-cert objects for the chosen TLS mode and configures p so the builders wire the APIService caBundle (or cert-manager CA-injection annotation) and the cm cert mount. It reads the cluster to reuse an existing self-signed CA, so re-runs don't rotate the cert.

  • TLSCertManager: returns a selfSigned Issuer + a Certificate; cert-manager mints servingCertSecretName and injects the CA into the APIService via the cert-manager.io/inject-ca-from annotation (p.CertManagerCertRef).
  • TLSSelfSigned: mints (or reuses) a CA + serving cert, returns the serving Secret + the CA Secret, and sets p.CABundle for APIService.caBundle.
  • TLSInsecureSkipVerify: no objects (dev posture).

func RenderManifests

func RenderManifests(in RenderInput) ([]byte, error)

RenderManifests serializes the full ordered control-plane manifest set to a multi-document YAML stream for `clrk install/upgrade --dry-run -o yaml`. It is the GitOps/audit counterpart to the live apply: the same objects the orchestration would lay down, in the same order — namespaces, serving-cert objects, the Gateway-API + Envoy-Gateway CRDs, the controller-manager set, and the WorkerPool set — emitted as `kubectl apply -f -`-able YAML.

It is pure (no cluster access): every object is already built from the resolved Profile, so the output is deterministic except for the self-signed key material PrepareTLS minted (the CA + serving-cert Secrets). For that posture the stream is prefixed with a sensitive-material warning, since the emitted Secrets carry private keys.

func Rollout

func Rollout(ctx context.Context, c client.Client, ns, name string) (int64, error)

Rollout bumps the clrk.apoxy.dev/restartedAt annotation on a Deployment's pod template, triggering the same rolling restart as `kubectl rollout restart`. A strategic-merge patch (no Get+Update) means concurrent reconciles can't lose the rollout to a 409. Returns the Deployment's post-patch metadata.generation so the caller can wait for status.observedGeneration to catch up (WaitDeploymentRolledOut) instead of racing a stale Available condition. Ported from drivers.ClusterDriver.Rollout so the install/upgrade path can roll the controller-manager through its RemoteCluster client without pulling in the k3d driver.

func RolloutWorkerPool

func RolloutWorkerPool(ctx context.Context, c client.Client, ns, name string) (int64, error)

RolloutWorkerPool triggers a rolling restart of a WorkerPool's worker Deployment by bumping RestartedAtAnnotation on the WorkerPool's spec.template.metadata.annotations — NOT on the Deployment. The Deployment is controller-owned: WorkerPoolDeploymentReconciler rebuilds its pod template from wp.spec.template every reconcile, so an annotation patched straight onto the Deployment is wiped on the next pass and the rollout silently no-ops. Patching the WorkerPool makes the controller propagate the annotation into the Deployment template itself. Returns the WorkerPool's post-patch metadata.generation so the caller can wait for status.observedGeneration to catch up (WaitWorkerPoolConverged). Ported from drivers.ClusterDriver.RolloutWorkerPool.

func RunSteps

func RunSteps(ctx context.Context, steps []Step, log StepLogger) error

RunSteps executes steps in order, emitting lifecycle events. It stops on the first error (the control plane is a dependency chain — a failed cm makes the WorkerPool apply meaningless).

func StepNames

func StepNames(steps []Step) []string

StepNames returns the ordered Step.Name values, for seeding the TUI sidebar so it matches the steps actually run (including the conditional serving-cert).

func WaitAPIDiscoverable

func WaitAPIDiscoverable(ctx context.Context, cfg *rest.Config, timeout time.Duration) error

WaitAPIDiscoverable polls discovery until clrk.apoxy.dev/v1alpha1 appears. The aggregated APIService is registered as soon as the cm is up, but kube-aggregator still has to probe the backend's TLS and mark the service Available before REST mappings for clrk kinds resolve.

func WaitDeploymentRolledOut

func WaitDeploymentRolledOut(ctx context.Context, c client.Client, ns, name string, wantGeneration int64, timeout time.Duration) error

WaitDeploymentRolledOut blocks until ns/name has reconciled at least wantGeneration and its pods are fully rolled over to the new ReplicaSet (updated == replicas == available == spec.replicas). Gating on observedGeneration is what makes this safe after a Rollout: immediately after the restartedAt patch the Deployment's Available condition still reflects the OLD generation, so a bare Available=True poll would return before the Recreate even begins (reporting an upgrade "done" while the old cm pod is still up). The updated==replicas==available equality also closes the Recreate gap, where the old pod is torn down (replicas drops to 0) before the new one is created.

func WaitReady

func WaitReady(ctx context.Context, cfg *rest.Config, p Profile, interval time.Duration, log func(string)) error

WaitReady blocks until every post-install signal on the target cluster has flipped green, or ctx is cancelled. Adapted from `clrk dev wait-ready`: drops the k3s-specific /livez probe and adds the controller-manager + worker Deployment Available checks the dev path did inline. log receives one line per state transition (green tick or pending) so the caller can route it to stdout or a TUI pane.

Signals (all required, each monotonic once green):

  • clrk.apoxy.dev/v1alpha1 APIService is Available
  • the ClickHouse-backed Invocation store answers a List
  • Gateway API CRDs are installed
  • <namespace>/envoy-gateway Secret exists (EG certgen ran)
  • controller-manager Deployment is Available
  • worker Deployment is Available

func WaitServingSecret

func WaitServingSecret(ctx context.Context, a Applier, ns string, timeout time.Duration) error

WaitServingSecret blocks until the cm serving-cert Secret carries a tls.crt, or timeout elapses. Used on the cert-manager path, where the Secret is minted asynchronously after the Certificate is applied; the cm pod can't mount it (or pass its readiness probe) until it exists.

func WaitWorkerPoolConverged

func WaitWorkerPoolConverged(ctx context.Context, c client.Client, ns, name string, wantGeneration int64, timeout time.Duration) error

WaitWorkerPoolConverged blocks until the WorkerPool has reconciled at least wantGeneration and reports its workers rolled out and ready (Available=True and Progressing=False). Waiting on the WorkerPool's status — which the controller derives from the Deployment — rather than polling the Deployment directly can't observe the pre-reconcile converged state; the observedGeneration floor ensures we read the controller's verdict on THIS rollout. Ported from drivers.ClusterDriver.WaitWorkerPoolConverged.

Types

type Action

type Action int

Action is the effect applying an object will have on the cluster.

const (
	ActionCreate Action = iota
	ActionUpdate
	ActionUnchanged
	ActionUnknown
)

func (Action) String

func (a Action) String() string

type Applier

type Applier interface {
	// ApplyObjects server-side-applies one or more typed objects with
	// ForceOwnership under the implementation's field manager.
	ApplyObjects(ctx context.Context, objs ...client.Object) error
	// KubeClient returns the underlying controller-runtime client (and its
	// scheme) for Get/List/Watch outside the SSA-only path.
	KubeClient(ctx context.Context) (client.Client, error)
	// EnsureNamespace idempotently applies a Namespace.
	EnsureNamespace(ctx context.Context, ns string) error
	// WaitDeploymentAvailable blocks until ns/name reports
	// DeploymentAvailable=True or timeout elapses.
	WaitDeploymentAvailable(ctx context.Context, ns, name string, timeout time.Duration) error
}

Applier is the cluster-agnostic surface the bootstrap engine needs to apply and wait on Kubernetes objects. It is satisfied by both *drivers.ClusterDriver (dev/k3d) and *install.RemoteCluster (customer cluster), so the same builders + orchestration run against either. The implementation owns the server-side-apply field manager (dev uses "clrk-dev", install uses "clrk-install"), so callers never thread it through.

type Level

type Level int

Level is the severity of a preflight result. FAIL aborts the install; WARN is confirmable (auto-accepted under --yes with a logged warning); PASS is informational.

const (
	LevelPass Level = iota
	LevelWarn
	LevelFail
)

func (Level) String

func (l Level) String() string

type Orchestration

type Orchestration struct {
	Applier Applier
	Config  *rest.Config
	Profile Profile
	CRDMode crds.Mode

	// CertObjects are the serving-cert objects (cert-manager Issuer+Certificate,
	// or self-signed CA+serving Secret) applied before the cm so its --cert-dir
	// mount and the APIService caBundle are satisfied. Empty for the insecure
	// (dev-equivalent) posture, which skips the serving-cert step.
	CertObjects []client.Object
	// WaitCertSecret waits for the serving-cert Secret to be populated after
	// applying CertObjects. Needed on the cert-manager path (the Secret is minted
	// asynchronously); the self-signed path applies the Secret directly.
	WaitCertSecret bool

	// Upgrade marks an in-place upgrade (vs a fresh install). It makes the
	// worker-pool step force a WorkerPool rollout and wait for convergence, so
	// the workers reliably pick up a new image even when only the image digest
	// (not the tag) moved. `clrk install` leaves it false.
	Upgrade bool

	WaitTimeout   time.Duration
	ReadyInterval time.Duration
	Log           func(string)
}

Orchestration carries everything the install/upgrade bring-up needs. Bundled in a struct (rather than a long parameter list) because the serving-cert step is conditional and the cluster path threads cert objects + an async wait through it. The TUI derives its sidebar from Steps(), so a conditional step is reflected in the rendered component list without a parallel hardcoded slice.

func (Orchestration) Steps

func (o Orchestration) Steps() []Step

Steps builds the ordered bring-up: namespaces -> [serving-cert] -> CRDs -> controller-manager (apply + wait Available) -> aggregated-api (wait discoverable) -> WorkerPool -> readiness. The cm must be Available and its aggregated API discoverable before the WorkerPool apply, which goes through that API. The serving-cert step is present only when CertObjects is non-empty.

type PreflightResult

type PreflightResult struct {
	Name   string
	Level  Level
	Detail string
	Hint   string
}

PreflightResult is one cluster-readiness finding. Detail says what was found; Hint is the actionable fix (empty on PASS).

func Preflight

func Preflight(ctx context.Context, c client.Client, disco discovery.DiscoveryInterface, p Profile, upgrade bool) []PreflightResult

Preflight runs every cluster-readiness check against the target cluster and returns the findings (collect-all-then-report). The caller decides policy: any LevelFail aborts; LevelWarn is confirmable. upgrade flips the existing- install check from a WARN ("an install exists; use `clrk upgrade`") to an informational PASS, since on the upgrade path an existing install is exactly what is expected. The Profile shapes namespace-scoped checks (worker-ns PSA, RBAC on the install namespace, named StorageClass).

type Profile

type Profile struct {
	// Namespace holds the control-plane objects (cm Deployment/Service/
	// APIService/PVCs/RBAC). WorkerNamespace holds the WorkerPool + worker
	// RBAC.
	Namespace       string
	WorkerNamespace string

	// Images + pull behaviour.
	ControllerImage string
	WorkerImage     string
	PullPolicy      string // "always" | "missing" | "never"; "" => IfNotPresent
	// ImagePullSecret, when set, is attached to the cm + worker PodSpecs.
	// Cluster-only (M4).
	ImagePullSecret string

	// Sizing.
	Replicas int32 // cm replicas; v1 is always 1 (single-writer embedded stores).
	Workers  int32 // worker replicas.

	// StorageClass for the three cm PVCs. Empty => the cluster default
	// (k3d local-path in dev).
	StorageClass string

	// RBACScoped selects a scoped ClusterRole (cluster) vs the cluster-admin
	// dev shortcut. Cluster-only (M4).
	RBACScoped bool

	// APIServerCIDRs, when non-empty, emits a NetworkPolicy admitting the
	// unauthenticated aggregated API (cm:8443) only from these CIDRs — the
	// host-network sources the aggregation proxy can originate from (the
	// kube-apiserver Endpoint IPs plus node InternalIPs, since aggregation
	// requests are commonly SNAT'd to a node IP). Pods live on the pod network,
	// so they are excluded. Derived by DeriveAPIServerCIDRs with an
	// --apiserver-cidr override; empty (dev, or undetected, or --network-policy=
	// false) emits no policy. Cluster-only (M4).
	APIServerCIDRs []string

	// TLS holds the APIService serving-cert posture. CABundle is the PEM the
	// installer sets on APIService.spec.caBundle for TLSSelfSigned;
	// CertManagerCertRef ("<ns>/<name>") drives the inject-ca-from annotation
	// for TLSCertManager. Cluster cert objects are built in M4.
	TLS                TLSMode
	CABundle           []byte
	CertManagerCertRef string

	// Version is stamped onto the cm Deployment + namespace for upgrade
	// gating (M5). Empty in dev.
	Version string

	// Console gates the embedded web console: its clrk-console Service, the
	// cm containerPort, and the --console-addr arg. nil/true installs it
	// (the default); false disables it entirely (--console-addr= empty, no
	// Service/port). The console proxies the unauthenticated apiserver, so an
	// operator who doesn't want that surface sets --console=false. Reached in
	// prod via `kubectl port-forward` -- the NetworkPolicy deliberately does
	// not open 8086 (see controllerManagerNetworkPolicy).
	Console *bool

	// Dev marks the local k3d profile and gates the dev-only knobs below.
	Dev bool
	// HostAliasIP, when set, plants a host.docker.internal HostAlias on the cm
	// pod (dev: k3d-nested pods don't inherit Docker Desktop's /etc/hosts).
	HostAliasIP string
	// OTLPFallbackEndpoint, when set, becomes --dev-otlp-fallback-endpoint so
	// every captured signal is mirrored to the dev TUI receiver.
	OTLPFallbackEndpoint string
	// EnableTestWrites opens the header-gated Invocation Create/Update door
	// (--enable-invocation-test-writes). Dev/CI only.
	EnableTestWrites bool
	// EgressBackendHost, when set, becomes --dev-egress-backend-host (k3d
	// NodePort routing). Empty on a cluster (in-cluster Service DNS).
	EgressBackendHost string
}

Profile is the single parameterization the manifest builders consume. The same struct drives `clrk dev` (Dev=true reproduces today's dev bootstrap byte-for-byte) and `clrk install`/`upgrade` (Dev=false, cluster-shaped fields set). Dev-only knobs are zero-valued and inert on a cluster profile.

type RemoteCluster

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

RemoteCluster is the customer-cluster implementation of Applier: it server- side-applies and waits on objects through a controller-runtime client built from an operator-supplied kubeconfig + context. It holds no k3d state, so the install/upgrade code path links and tests without the k3d toolchain.

func NewRemoteCluster

func NewRemoteCluster(kubeconfigPath, contextName string) (*RemoteCluster, error)

NewRemoteCluster resolves the kubeconfig + context and builds the typed client. The returned RemoteCluster satisfies Applier.

func (*RemoteCluster) ApplyObjects

func (r *RemoteCluster) ApplyObjects(ctx context.Context, objs ...client.Object) error

ApplyObjects server-side-applies one or more typed objects with ForceOwnership under the install field manager. Same semantics as the dev driver, so the shared builders + ApplyAndVerify behave identically against either.

func (*RemoteCluster) Context

func (r *RemoteCluster) Context() string

Context returns the resolved kubeconfig context name (for operator-facing "about to install into <context>" messaging).

func (*RemoteCluster) Discovery

Discovery returns a memory-cached discovery client for the target cluster, used by preflight to detect API groups, CRDs, and the aggregation layer.

func (*RemoteCluster) EnsureNamespace

func (r *RemoteCluster) EnsureNamespace(ctx context.Context, ns string) error

EnsureNamespace idempotently applies a Namespace.

func (*RemoteCluster) KubeClient

func (r *RemoteCluster) KubeClient(ctx context.Context) (client.Client, error)

KubeClient returns the controller-runtime client.

func (*RemoteCluster) RESTConfig

func (r *RemoteCluster) RESTConfig() *rest.Config

RESTConfig returns the resolved rest.Config (e.g. for crds.Install, discovery, or SelfSubjectAccessReview clients).

func (*RemoteCluster) RESTMapper

RESTMapper returns a deferred discovery REST mapper, used by the plan engine to resolve REST mappings for arbitrary objects.

func (*RemoteCluster) WaitDeploymentAvailable

func (r *RemoteCluster) WaitDeploymentAvailable(ctx context.Context, ns, name string, timeout time.Duration) error

WaitDeploymentAvailable blocks until ns/name reports DeploymentAvailable=True or timeout elapses.

type RenderInput

type RenderInput struct {
	Profile     Profile
	CertObjects []client.Object
	CRDMode     crds.Mode
}

RenderInput parameterizes RenderManifests. Profile is the fully resolved install/upgrade profile (TLS posture, version stamp, NetworkPolicy CIDRs, and for the cert-manager path CertManagerCertRef / for self-signed CABundle all already set by PrepareTLS + the CIDR derivation). CertObjects are the serving-cert objects PrepareTLS produced for that posture (empty for the insecure/dev posture). CRDMode mirrors the apply path: ModeSkip emits no CRD documents, otherwise the embedded Gateway-API + Envoy-Gateway bundle is included.

type ResourcePlan

type ResourcePlan struct {
	Kind   string
	Name   string // "<ns>/<name>" or "<name>" for cluster-scoped
	Action Action
	Diff   string
	Risky  bool
	Why    string
	Note   string
}

ResourcePlan is the planned effect of applying one object, computed by a server-side-apply dry-run diffed against the live object. Risky flags cluster-wide or destructive changes the operator should see before confirming; Why explains it. Note carries a caveat (e.g. an API not yet served at plan time).

func BuildPlan

func BuildPlan(ctx context.Context, c client.Client, fieldManager string, objs []client.Object) []ResourcePlan

BuildPlan computes, for each object, what applying it would do — via an SSA dry-run compared against the live object. It never mutates the cluster. Objects whose API isn't served yet at plan time (e.g. the WorkerPool before the controller-manager is up) can't be dry-run-applied; they're reported as creates with a note rather than failing the whole plan.

type Step

type Step struct {
	Name  string
	Why   string
	Risky bool
	Run   func(ctx context.Context) error
}

Step is one unit of the install/upgrade bring-up. Why is a one-line rationale rendered before Run executes, so the operator always understands what is about to happen and why. Risky marks steps that mutate cluster-wide or existing state (gated behind confirmation by the caller).

type StepLogger

type StepLogger func(step Step, status string, err error)

StepLogger receives lifecycle events for a step. status is one of "start", "done", "error". Callers route this to stdout or a TUI pane.

type TLSMode

type TLSMode int

TLSMode selects how the aggregated APIService verifies the cm's serving cert.

const (
	// TLSInsecureSkipVerify sets APIService.spec.insecureSkipTLSVerify=true and
	// lets the cm serve a self-signed in-memory cert (empty --cert-dir). The
	// dev default; never used on a customer cluster.
	TLSInsecureSkipVerify TLSMode = iota
	// TLSSelfSigned mounts an installer-minted serving-cert Secret at
	// --cert-dir and sets APIService.spec.caBundle to the installer CA.
	TLSSelfSigned
	// TLSCertManager mounts a cert-manager-issued serving-cert Secret at
	// --cert-dir and annotates the APIService with
	// cert-manager.io/inject-ca-from so the CA injector fills caBundle.
	TLSCertManager
)

type UpgradeDecision

type UpgradeDecision struct {
	Verdict UpgradeVerdict
	Reason  string
}

UpgradeDecision is GateUpgrade's verdict plus an operator-facing reason.

func GateUpgrade

func GateUpgrade(installed, target string, allowDowngrade, force bool) UpgradeDecision

GateUpgrade decides whether an in-place upgrade from the installed version to the target version may proceed. `installed` is the version stamped on the existing control plane (DetectInstall; may be "" when an older install never recorded one); `target` is the version being applied (the upgrading binary's version.Current(), or an explicit --version).

When both are valid semver they are ordered with golang.org/x/mod/semver: equal is a repair re-apply, newer proceeds (a major jump asks for an extra confirm), older is refused unless --allow-downgrade. When either side isn't orderable semver the gate degrades to equal/not-equal and any change requires --force. --force overrides every refusal and confirm.

type UpgradeVerdict

type UpgradeVerdict int

UpgradeVerdict is GateUpgrade's top-level decision.

const (
	// VerdictProceed: apply under the normal plan + single confirm gate; no
	// extra acknowledgement is required.
	VerdictProceed UpgradeVerdict = iota
	// VerdictConfirm: proceed only after an explicit acknowledgement beyond the
	// plan confirm (a major-version jump, or an install whose version can't be
	// read/ordered). The caller auto-accepts this under --yes/--force.
	VerdictConfirm
	// VerdictRefuse: do not proceed (a downgrade without --allow-downgrade, or a
	// non-orderable version change without --force).
	VerdictRefuse
)

func (UpgradeVerdict) String

func (v UpgradeVerdict) String() string

Jump to

Keyboard shortcuts

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