Documentation
¶
Overview ¶
Package cluster assembles a SKE node: the declarative cluster config, the persisted per-node state, the component processes the supervisor runs, and the bring-up/join flows around them.
The shape is one API-versioned config file rather than flag soup, component configs generated from it, and the control plane as kubelet-managed static pods rendered by internal/staticpod, with the host-process roster in processes.go.
Index ¶
- Constants
- Variables
- func ImportImages(ctx context.Context, dir string) error
- func ImportImagesWithWriter(ctx context.Context, w io.Writer, dir string) error
- func LoadSnapshotConfig() (etcdsnap.Config, error)
- func LoadSnapshotDir() string
- func NodeSELinuxOptions() (selinux.Options, error)
- func Processes(st *NodeState, operator bool) []supervisor.Process
- func RunController(ctx context.Context, cfg *ClusterConfig, st *NodeState) error
- func RunWorker(ctx context.Context, st *NodeState) error
- func UpArgv(exe string, worker bool, configPath string, profileName string) []string
- func WorkerSELinux(path string) (optOut, set bool, err error)
- type Cilium
- type ClusterConfig
- func (c *ClusterConfig) CertRenewEnabled() bool
- func (c *ClusterConfig) DashboardEnabled() bool
- func (c *ClusterConfig) DashboardSettings() addons.DashboardSettings
- func (c *ClusterConfig) OperatorEnabled() bool
- func (c *ClusterConfig) ProfileName() string
- func (c *ClusterConfig) SELinuxOptOut() bool
- func (c *ClusterConfig) SetProfile(name string)
- func (c *ClusterConfig) SnapshotBase() etcdsnap.Config
- func (c *ClusterConfig) SnapshotDir() string
- type Dashboard
- type Network
- type NodeState
- func PrepareController(cfg *ClusterConfig, nodeIPFlag string, releaseDataLock func()) (*NodeState, error)
- func PrepareControllerContext(ctx context.Context, cfg *ClusterConfig, nodeIPFlag string, ...) (*NodeState, error)
- func PrepareControllerWithLease(ctx context.Context, cfg *ClusterConfig, nodeIPFlag string, ...) (*NodeState, error)
- func PrepareWorker(ctx context.Context, o WorkerOptions) (*NodeState, error)
- type S3
- type Snapshot
- type Spec
- type StackContext
- type Storage
- type VIP
- type WorkerConfig
- type WorkerOptions
Constants ¶
const DefaultConfigPath = "/etc/stratum/config.yaml"
DefaultConfigPath is the declarative config file `stratum up` reads.
Variables ¶
var ( SaveState = nodestate.SaveState LoadState = nodestate.LoadState StatePath = nodestate.StatePath )
var ImporterStacks func(StackContext) (map[string][]byte, error)
ImporterStacks, when set, returns an importer's stacks as "stack/file.yaml" to contents; writeBundles stages them beside the bundled add-ons. Unset, a start removes the files an earlier start staged for an importer.
Functions ¶
func ImportImages ¶
ImportImages is importPayloadImages pointed at an explicit archive dir — the per-node upgrade (internal/upgrade) imports the upgrade binary's staged images from it before re-rendering the static pod manifests.
func ImportImagesWithWriter ¶
ImportImagesWithWriter imports payload images and reports progress to w.
func LoadSnapshotConfig ¶
LoadSnapshotConfig is the effective snapshot config for the CLI and the MCP server, resolved the way the scheduled loop resolves it: from the cluster config the controller was started with (`stratum up --config`), with snapshot.conf winning when it exists. The resolved settings carry the directory too (Config.Dir): spec.snapshots.dir, else the default, so both front ends act in the directory the scheduled loop owns. An unreadable cluster config, or a recorded one that has since been deleted, falls back to the built-in defaults, as these callers did before the cluster config was consulted at all; that is warned about on stderr, since it can make a manual save prune to the default retention or `schedule` persist a local-only config.
func LoadSnapshotDir ¶
func LoadSnapshotDir() string
LoadSnapshotDir is the directory the scheduled loop writes to, for the commands that read or prune what it wrote. It reads the same cluster config as LoadSnapshotConfig; an unreadable one yields the default dir, and LoadSnapshotConfig has already warned about it.
func NodeSELinuxOptions ¶
NodeSELinuxOptions reads this node's SELinux settings from disk, for the upgrade preflight: whether its profile requires SELinux and whether the node opted out of SELinux labelling. Each is resolved the way the node's own next start resolves it: a control plane reads the config file its start recorded and the profile that config names; a worker keeps the profile its join recorded, and the opt-out it saved unless its config file sets spec.selinux now. An unreadable node state or config, or a profile this binary does not register, is an error: the caller cannot tell what the node runs with and warns instead of deciding.
func Processes ¶
func Processes(st *NodeState, operator bool) []supervisor.Process
Processes renders the supervised host-process roster for this node. Since the control plane runs as kubelet-managed static pods (internal/staticpod), so the supervisor's roster is down to what has to be a host process: containerd, kubelet, and the operator on controllers. Ordering/readiness is expressed with WaitFor gates rather than After=/Requires=.
operator is the cluster's spec.operator switch, the only cluster setting the roster reads. It is a bool rather than the whole ClusterConfig because a nil spec.operator means on: a caller that passed an empty config would have run the operator on a cluster that turned it off. A worker never runs the operator, whatever the switch.
func RunController ¶
func RunController(ctx context.Context, cfg *ClusterConfig, st *NodeState) error
func UpArgv ¶
UpArgv is the steady-state `stratum up` command line run from exe: what the reboot-persistence unit runs, and what a supervisor re-execs into after an upgrade. It never carries --join/--token/--certificate-key: those are one-shot join credentials, valid only for the join that consumed them. A worker's restart needs nothing but --worker, because PrepareWorker's restart path resumes from the persisted NodeState, its profile included. A control plane's carries its profile, so a restart keeps the one the node was brought up with.
The cis profile is spelled --cis, not --profile cis: an upgrade rollback restores the previous binary and re-execs it with this argv, and a binary that predates --profile rejects the flag it does not know, which would leave a rolled-back CIS control plane unable to start. Every binary reads --cis. Any other profile is spelled --profile <name>; no earlier binary could have run it.
func WorkerSELinux ¶
WorkerSELinux reads spec.selinux from a worker's config file on a restart, which reads nothing else from it. set is false when the file is missing or does not set spec.selinux, and the worker keeps the setting it saved. Other fields are not checked here: a worker's join already refused a file that set them.
Types ¶
type Cilium ¶
type Cilium struct {
MTU int `json:"mtu,omitempty"`
Devices []string `json:"devices,omitempty"`
BGPControlPlane *bool `json:"bgpControlPlane,omitempty"`
RoutingMode string `json:"routingMode,omitempty"` // tunnel (default) or native
IPv4NativeRoutingCIDR string `json:"ipv4NativeRoutingCIDR,omitempty"`
IPv6NativeRoutingCIDR string `json:"ipv6NativeRoutingCIDR,omitempty"`
AutoDirectNodeRoutes *bool `json:"autoDirectNodeRoutes,omitempty"`
}
Cilium is spec.network.cilium: the cluster's Cilium options. Every field is optional, and an absent block is the shipped configuration. It is cluster-wide, so every control plane's file must carry the same block.
func (*Cilium) CheckStack ¶
CheckStack checks the parts of the block that depend on the cluster's network: native routing on a dual-stack cluster needs the IPv6 range too, and a single-stack one has no use for it.
func (*Cilium) Settings ¶
func (c *Cilium) Settings() addons.CiliumSettings
Settings is the block as the render and the join check take it; a nil block is the shipped configuration.
type ClusterConfig ¶
type ClusterConfig struct {
APIVersion string `json:"apiVersion,omitempty"`
Kind string `json:"kind,omitempty"`
Spec Spec `json:"spec"`
// contains filtered or unexported fields
}
ClusterConfig is the user-facing declarative config (/etc/stratum/config.yaml). CRD-shaped even though it is consumed locally, so the same document can later live in-cluster.
func LoadConfig ¶
func LoadConfig(path string) (*ClusterConfig, error)
LoadConfig reads the cluster config; a missing file yields pure defaults, so `stratum up` with no config at all still brings up a sane single node.
func (*ClusterConfig) CertRenewEnabled ¶
func (c *ClusterConfig) CertRenewEnabled() bool
func (*ClusterConfig) DashboardEnabled ¶
func (c *ClusterConfig) DashboardEnabled() bool
DashboardEnabled reports whether the cluster runs its dashboard: on unless spec.dashboard.enabled is false or the operator is off.
func (*ClusterConfig) DashboardSettings ¶
func (c *ClusterConfig) DashboardSettings() addons.DashboardSettings
DashboardSettings is spec.dashboard as the render takes it.
func (*ClusterConfig) OperatorEnabled ¶
func (c *ClusterConfig) OperatorEnabled() bool
OperatorEnabled/CertRenewEnabled default to on; a *bool distinguishes "unset" from "explicitly false".
func (*ClusterConfig) ProfileName ¶
func (c *ClusterConfig) ProfileName() string
ProfileName is the node profile the config selects: spec.profile, or the legacy spec.cis: true as "cis"; empty for none.
func (*ClusterConfig) SELinuxOptOut ¶
func (c *ClusterConfig) SELinuxOptOut() bool
SELinuxOptOut reports spec.selinux: false.
func (*ClusterConfig) SetProfile ¶
func (c *ClusterConfig) SetProfile(name string)
SetProfile selects a profile from outside the file (the --profile flag) and keeps spec.profile and the legacy spec.cis in step.
func (*ClusterConfig) SnapshotBase ¶
func (c *ClusterConfig) SnapshotBase() etcdsnap.Config
SnapshotBase is the snapshot config this cluster config asks for: what applies when no snapshot.conf exists. Credentials never live in config.yaml; they come from the environment (stratum.env) via etcdsnap.
func (*ClusterConfig) SnapshotDir ¶
func (c *ClusterConfig) SnapshotDir() string
SnapshotDir is the local directory this cluster config writes scheduled snapshots to: spec.snapshots.dir, else defaultSnapshotDir. A relative dir is ignored, not resolved: it would name a different place for every process with a different working directory, and one starting with "-" would reach etcdutl as a flag. A dir with a ".." element is ignored too: the kernel resolves ".." after symlinks and filepath.Clean before them, so the callers would not agree on which directory it names. Other unclean forms ("/a//b", "/a/./b", "/a/") mean the same to both and are cleaned.
type Dashboard ¶
type Dashboard struct {
Enabled *bool `json:"enabled,omitempty"`
NodePort *int `json:"nodePort,omitempty"` // default 30443; 0 serves on a ClusterIP only
PublicURL string `json:"publicURL,omitempty"`
TLSSecretName string `json:"tlsSecretName,omitempty"`
EnableNodeShell *bool `json:"enableNodeShell,omitempty"` // the privileged host shell (default on, off under cis)
TokenSecrets *bool `json:"tokenSecrets,omitempty"` // admin and viewer sign-in tokens as Secrets (default on)
}
Dashboard is spec.dashboard: the dashboard the cluster runs for itself. It is on by default whenever the operator is.
type Network ¶
type Network struct {
PodCIDR string `json:"podCIDR,omitempty"` // default 10.245.0.0/16; "v4,v6" for dual-stack; set at first boot, a join must match
ServiceCIDR string `json:"serviceCIDR,omitempty"` // default 10.96.0.0/12; set at first boot, a join must match
ClusterDomain string `json:"clusterDomain,omitempty"`
NodeIP string `json:"nodeIP,omitempty"` // override autodetection
Cilium *Cilium `json:"cilium,omitempty"`
}
Network is spec.network. A control plane never reads its pod and service ranges or cluster domain from flags: the cluster's first controller boot takes podCIDR, serviceCIDR and clusterDomain from this block and records them, a joining control plane inherits the recorded values and refuses a different one set here, and every later start keeps the recorded values. A worker reads only nodeIP and takes the cluster's network from --pod-cidr, --service-cidr and --cluster-domain, which `stratum up` refuses without --worker.
type NodeState ¶
Aliases: the state types live in internal/nodestate (a leaf package shared with internal/ha); cluster is their primary consumer.
func PrepareController ¶
func PrepareController(cfg *ClusterConfig, nodeIPFlag string, releaseDataLock func()) (*NodeState, error)
PrepareController does everything a fresh first controller needs before the supervisor starts: dirs, prereqs, PKI, kubeconfigs, component configs, node state. Idempotent — a restarted controller re-runs it cheaply.
The common node steps run through the ONE shared assembly the HA join runs (assembleNode, internal/ha/join.go): the controller-specific steps hang off it at the points the two paths' pinned orders fix — the netconfig resolution as ResolveNet, the IP-move refusal and node-state completion as BeforeCerts.
nodeIPFlag is --node-ip from the command line ("" when not given); it outranks spec.network.nodeIP (host.ResolveNodeIP has the whole precedence). releaseDataLock is the release of the etcd data lock the caller holds across preparation (`stratum up` takes it before it calls this and releases it after); the node-state save writes under that held lock. A caller not holding the lock passes nil, and the save refuses rather than write unlocked.
func PrepareControllerContext ¶
func PrepareControllerContext(ctx context.Context, cfg *ClusterConfig, nodeIPFlag string, releaseDataLock func()) (*NodeState, error)
PrepareControllerContext stops preparation between steps when its caller cancels: the entry check refuses a run that arrived already stopped, and the shared assembly checks the context before each step, so a step in flight finishes before the next mutation is considered. releaseDataLock is as PrepareController's: the release of the held etcd data lock; nil makes the final node-state save refuse.
func PrepareControllerWithLease ¶
func PrepareControllerWithLease(ctx context.Context, cfg *ClusterConfig, nodeIPFlag string, lease *k8sutil.MaintenanceLease, releaseDataLock func()) (*NodeState, error)
PrepareControllerWithLease carries the CLI's CIS-key maintenance fence through host preparation so the eventual key write can confirm ownership again. releaseDataLock is as PrepareController's: the release of the held etcd data lock; nil makes the final node-state save refuse.
func PrepareWorker ¶
func PrepareWorker(ctx context.Context, o WorkerOptions) (*NodeState, error)
PrepareWorker runs the worker join flow: discover + pin the CA, write the bootstrap kubeconfig, persist the node state. RunWorker, which follows, writes the kubelet and containerd configs. The kubelet does TLS bootstrap; the operator's CSR approver signs its serving cert. A worker that already has worker state and is given no Server takes the restart fast path instead, which reuses that state.
ctx is the run's interrupt context, created by the caller before its preflight: a signal received before the join began stops it here, before any host write, and the caller stops the run at its boundary once the join returns.
type S3 ¶
type S3 struct {
Bucket string `json:"bucket"`
Prefix string `json:"prefix,omitempty"`
Region string `json:"region,omitempty"`
Endpoint string `json:"endpoint,omitempty"`
// PathStyle selects path-style addressing, which MinIO, Ceph and most
// non-AWS endpoints need.
PathStyle bool `json:"pathStyle,omitzero"`
}
type Spec ¶
type Spec struct {
Network Network `json:"network,omitempty"`
VIP VIP `json:"vip,omitempty"`
Storage Storage `json:"storage,omitempty"`
Operator *bool `json:"operator,omitempty"` // HelmChart + manifest-deployer controller (default on)
Profile string `json:"profile,omitempty"` // the node profile, by name; "" for none
CIS bool `json:"cis,omitempty"` // legacy spelling of profile: cis; LoadConfig folds it into Profile
Snapshot Snapshot `json:"snapshots,omitempty"` //
CertRenew *bool `json:"certRenew,omitempty"` // rotate expiring leaves automatically (default on)
SELinux *bool `json:"selinux,omitempty"` // label Stratum's files for container-selinux (default on)
Dashboard *Dashboard `json:"dashboard,omitempty"`
}
type StackContext ¶
StackContext is the cluster an importer's stacks are rendered for.
type Storage ¶
type Storage struct {
// Default StorageClass backend: "local-path" (default) or "none".
Default string `json:"default,omitempty"`
}
type VIP ¶
Aliases: the state types live in internal/nodestate (a leaf package shared with internal/ha); cluster is their primary consumer.
type WorkerConfig ¶
type WorkerConfig struct {
NodeIP string // spec.network.nodeIP
SELinuxOptOut bool // spec.selinux: false
}
WorkerConfig is what a --worker reads from its config file.
func LoadWorkerConfig ¶
func LoadWorkerConfig(path string) (WorkerConfig, error)
LoadWorkerConfig is the config a --worker honours: spec.network.nodeIP and spec.selinux, and nothing else. The file is parsed as strictly as a control plane parses it, and any other field that is set is an error naming it: a worker has no use for it, and a setting that appears to apply and does not is worse than a refusal. A missing file yields the zero WorkerConfig.
type WorkerOptions ¶
type WorkerOptions struct {
// Server is the control-plane or VIP URL to join (--server); empty on a
// restart.
Server string
// Token is the bootstrap token the join authenticates with.
Token string
// CAHash is the "sha256:<hex>" pin of the cluster CA
// (--discovery-token-ca-cert-hash).
CAHash string
// NodeIP is --node-ip; empty leaves spec.network.nodeIP, $NODE_IP and
// detection to the join, and the saved address, else $NODE_IP and
// detection, to a restart. A restart given one that differs moves the
// worker to it and saves it, once it is an address the worker can
// register: an IPv4 address on a single-stack worker, its v4,v6 pair on a
// dual-stack one.
NodeIP string
// ConfigNodeIP is spec.network.nodeIP from the config file, which only a
// join reads. It is kept apart from NodeIP, which outranks it, so the join
// names the source its address came from.
ConfigNodeIP string
// ServiceCIDR, PodCIDR and ClusterDomain describe a cluster that does not
// use the defaults. A restart reads only PodCIDR, to record the range a
// legacy worker, or one joined without --pod-cidr, never saved, or to
// replace the default an earlier release saved for such a join.
ServiceCIDR string
PodCIDR string
ClusterDomain string
// Profile selects the named node profile on a join.
Profile string
// SELinuxOptOut is spec.selinux: false from the config file, nil when a
// restart's file does not set it; a restart saves a changed setting.
SELinuxOptOut *bool
// DualStack registers a v4,v6 node IP pair on a join (--dual-stack).
DualStack bool
}
WorkerOptions are the inputs of a worker start, as `stratum up --worker` resolves them from its flags and config file. A restart passes no join credentials: it resumes from the saved node state.