Files
monok8s/clitools/pkg/bootstrap/runner.go
2026-03-30 18:47:19 +08:00

168 lines
4.6 KiB
Go

package bootstrap
import (
"context"
"fmt"
monov1alpha1 "undecided.project/monok8s/pkg/apis/monok8s/v1alpha1"
"undecided.project/monok8s/pkg/node"
"undecided.project/monok8s/pkg/system"
)
type Runner struct {
NodeCtx *node.NodeContext
Registry *Registry
initSteps []StepInfo
}
type StepInfo struct {
RegKey string
Name string
Desc string
}
type StepSelection struct {
Indices []int // 1-based
}
func NewRunner(cfg *monov1alpha1.MonoKSConfig) *Runner {
runnerCfg := system.RunnerConfig{}
nctx := &node.NodeContext{
Config: cfg,
SystemRunner: system.NewRunner(runnerCfg),
}
return &Runner{
NodeCtx: nctx,
Registry: NewRegistry(nctx),
initSteps: []StepInfo{
{
RegKey: "ConfigureHostname",
Name: "Configure hostname",
Desc: "Set system hostname according to cluster configuration",
},
{
RegKey: "ConfigureMgmtInterface",
Name: "Configure management interface",
Desc: "Configure management network interface, IP address, and gateway",
},
{
RegKey: "ConfigureDNS",
Name: "Configure DNS",
Desc: "Set system DNS resolver configuration for cluster and external access",
},
{
RegKey: "EnsureIPForward",
Name: "Ensure IP forwarding",
Desc: "Enable kernel IP forwarding required for pod networking",
},
{
RegKey: "ConfigureDefaultCNI",
Name: "Configure default CNI",
Desc: "Install or configure default container networking (CNI bridge, IPAM, etc.)",
},
{
RegKey: "StartCRIO",
Name: "Start CRI-O runtime",
Desc: "Start container runtime and verify it is ready for Kubernetes workloads",
},
{
RegKey: "ValidateRequiredImagesPresent",
Name: "Validate required images",
Desc: "Ensure all required Kubernetes images are present or available locally",
},
{
RegKey: "ValidateNodeIPAndAPIServerReachability",
Name: "Validate Node IP and wether API Server is available",
Desc: "Verify the local ip address with the api server advertise address. Contact remote api server",
},
{
RegKey: "DetectLocalClusterState",
Name: "Detect local cluster state",
Desc: "Inspect local node to determine existing Kubernetes membership and configuration",
},
{
RegKey: "ClassifyBootstrapAction",
Name: "Classify bootstrap action",
Desc: "Decide whether to init, join, upgrade, or reconcile based on local state and desired version",
},
{
RegKey: "RunKubeadmInit",
Name: "Run kubeadm init",
Desc: "Initialize a new Kubernetes control plane using kubeadm",
},
{
RegKey: "RunKubeadmJoin",
Name: "Run kubeadm join",
Desc: "Join node to existing cluster as worker or control-plane",
},
{
RegKey: "WaitForExistingClusterIfNeeded",
Name: "Wait for existing cluster",
Desc: "Block until control plane is reachable when joining or reconciling an existing cluster",
},
{
RegKey: "ReconcileControlPlane",
Name: "Reconcile control plane",
Desc: "Ensure control plane components match desired state without full reinitialization",
},
{
RegKey: "ReconcileWorker",
Name: "Reconcile worker node",
Desc: "Reconcile the worker node",
},
{
RegKey: "CheckForVersionSkew",
Name: "Check for version skew",
Desc: "Validate wether version satisfy the requirements againts current cluster if any",
},
{
RegKey: "RunKubeadmUpgradeApply",
Name: "Run kubeadm upgrade apply",
Desc: "Upgrade control plane components using kubeadm",
},
{
RegKey: "RunKubeadmUpgradeNode",
Name: "Run kubeadm upgrade node",
Desc: "Upgrade node components (kubelet, config) to match control plane",
},
{
RegKey: "ApplyLocalNodeMetadataIfPossible",
Name: "Apply node metadata",
Desc: "Apply labels/annotations to the local node if API server is reachable",
},
},
}
}
func (r *Runner) RunNamedStep(ctx context.Context, name string) error {
step, err := r.Registry.Get(name)
if err != nil {
return err
}
return step(ctx, r.NodeCtx)
}
func (r *Runner) InitSteps() []StepInfo {
return r.initSteps
}
func (r *Runner) Init(ctx context.Context) error {
for i, step := range r.initSteps {
if err := r.RunNamedStep(ctx, step.RegKey); err != nil {
return fmt.Errorf("step %d (%s): %w", i+1, step.Name, err)
}
}
return nil
}
func (r *Runner) InitSelected(ctx context.Context, sel StepSelection) error {
for _, idx := range sel.Indices {
step := r.initSteps[idx-1]
if err := r.RunNamedStep(ctx, step.RegKey); err != nil {
return fmt.Errorf("step %d (%s): %w", idx, step.Name, err)
}
}
return nil
}