// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. package v1alpha1 import ( "github.com/talos-systems/go-procfs/procfs" "github.com/talos-systems/talos/internal/app/machined/pkg/runtime" machineapi "github.com/talos-systems/talos/pkg/machinery/api/machine" "github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/machine" "github.com/talos-systems/talos/pkg/machinery/constants" ) // Sequencer implements the sequencer interface. type Sequencer struct{} // NewSequencer intializes and returns a sequencer. func NewSequencer() *Sequencer { return &Sequencer{} } // PhaseList represents a list of phases. type PhaseList []runtime.Phase // Append appends a task to the phase list. func (p PhaseList) Append(name string, tasks ...runtime.TaskSetupFunc) PhaseList { p = append(p, runtime.Phase{ Name: name, Tasks: tasks, }) return p } // AppendWhen appends a task to the phase list when `when` is `true`. func (p PhaseList) AppendWhen(when bool, name string, tasks ...runtime.TaskSetupFunc) PhaseList { if when { p = p.Append(name, tasks...) } return p } // AppendList appends an additional PhaseList to the existing one. func (p PhaseList) AppendList(list PhaseList) PhaseList { return append(p, list...) } // Initialize is the initialize sequence. The primary goals of this sequence is // to load the config and enforce kernel security requirements. func (*Sequencer) Initialize(r runtime.Runtime) []runtime.Phase { phases := PhaseList{} switch r.State().Platform().Mode() { //nolint:exhaustive case runtime.ModeContainer: phases = phases.Append( "logger", SetupLogger, ).Append( "systemRequirements", SetupSystemDirectory, ).Append( "etc", CreateSystemCgroups, CreateOSReleaseFile, ).Append( "config", LoadConfig, ) default: phases = phases.Append( "logger", SetupLogger, ).Append( "systemRequirements", EnforceKSPPRequirements, SetupSystemDirectory, MountBPFFS, MountCgroups, MountPseudoFilesystems, SetRLimit, DropCapabilities, ).Append( "integrity", WriteIMAPolicy, ).Append( "etc", CreateSystemCgroups, CreateOSReleaseFile, ).AppendWhen( r.State().Machine().Installed(), "mountSystem", MountStatePartition, ).Append( "config", LoadConfig, ).AppendWhen( r.State().Machine().Installed(), "unmountSystem", UnmountStatePartition, ) } return phases } // Install is the install sequence. func (*Sequencer) Install(r runtime.Runtime) []runtime.Phase { phases := PhaseList{} switch r.State().Platform().Mode() { //nolint:exhaustive case runtime.ModeContainer: return nil default: if !r.State().Machine().Installed() || r.State().Machine().IsInstallStaged() { phases = phases.Append( "validateConfig", ValidateConfig, ).Append( "env", SetUserEnvVars, ).Append( "containerd", StartContainerd, ).Append( "install", Install, ).Append( "saveStateEncryptionConfig", SaveStateEncryptionConfig, ).Append( "mountState", MountStatePartition, ).Append( "saveConfig", SaveConfig, ).Append( "unmountState", UnmountStatePartition, ).Append( "stopEverything", StopAllServices, ).Append( "mountBoot", MountBootPartition, ).Append( "kexec", KexecPrepare, ).Append( "unmountBoot", UnmountBootPartition, ).Append( "reboot", Reboot, ) } } return phases } // Boot is the boot sequence. This primary goal if this sequence is to apply // user supplied settings and start the services for the specific machine type. // This sequence should never be reached if an installation is not found. func (*Sequencer) Boot(r runtime.Runtime) []runtime.Phase { phases := PhaseList{} wipe := procfs.ProcCmdline().Get(constants.KernelParamWipe).First() if wipe != nil && *wipe == "system" { return phases.Append("wipeSystemDisk", ResetSystemDisk).Append("reboot", Reboot) } phases = phases.AppendWhen( r.State().Platform().Mode() != runtime.ModeContainer, "saveStateEncryptionConfig", SaveStateEncryptionConfig, ).AppendWhen( r.State().Platform().Mode() != runtime.ModeContainer, "mountState", MountStatePartition, ).Append( "validateConfig", ValidateConfig, ).Append( "saveConfig", SaveConfig, ).Append( "env", SetUserEnvVars, ).Append( "containerd", StartContainerd, ).AppendWhen( r.State().Platform().Mode() == runtime.ModeContainer, "sharedFilesystems", SetupSharedFilesystems, ).AppendWhen( r.State().Platform().Mode() != runtime.ModeContainer, "ephemeral", MountEphemeralPartition, ).AppendWhen( r.State().Platform().Mode() != runtime.ModeContainer, "verifyInstall", VerifyInstallation, ).Append( "var", SetupVarDirectory, ).AppendWhen( r.State().Platform().Mode() != runtime.ModeContainer, "overlay", MountOverlayFilesystems, ).Append( "udevSetup", WriteUdevRules, ).AppendWhen( r.State().Platform().Mode() != runtime.ModeContainer, "udevd", StartUdevd, ).AppendWhen( r.State().Platform().Mode() != runtime.ModeContainer, "userDisks", MountUserDisks, ).Append( "userSetup", WriteUserFiles, ).AppendWhen( r.State().Platform().Mode() != runtime.ModeContainer, "lvm", ActivateLogicalVolumes, ).Append( "startEverything", StartAllServices, ).AppendWhen( r.Config().Machine().Type() != machine.TypeWorker, "labelMaster", LabelNodeAsMaster, ).AppendWhen( r.State().Platform().Mode() != runtime.ModeContainer, "uncordon", UncordonNode, ).AppendWhen( r.State().Platform().Mode() != runtime.ModeContainer, "bootloader", UpdateBootloader, ) return phases } // Bootstrap is the bootstrap sequence. This primary goal if this sequence is // to bootstrap Etcd and Kubernetes. func (*Sequencer) Bootstrap(r runtime.Runtime) []runtime.Phase { phases := PhaseList{} phases = phases.Append( "etcd", BootstrapEtcd, ) return phases } // Reboot is the reboot sequence. func (*Sequencer) Reboot(r runtime.Runtime) []runtime.Phase { phases := PhaseList{}.Append( "cleanup", StopAllPods, ). AppendList(stopAllPhaselist(r, true)). Append("reboot", Reboot) return phases } // Reset is the reset sequence. func (*Sequencer) Reset(r runtime.Runtime, in runtime.ResetOptions) []runtime.Phase { phases := PhaseList{} switch r.State().Platform().Mode() { //nolint:exhaustive case runtime.ModeContainer: phases = phases.AppendList(stopAllPhaselist(r, false)). Append( "shutdown", Shutdown, ) default: phases = phases.AppendWhen( in.GetGraceful(), "drain", CordonAndDrainNode, ).AppendWhen( in.GetGraceful(), "cleanup", RemoveAllPods, ).AppendWhen( !in.GetGraceful(), "cleanup", StopAllPods, ).AppendWhen( in.GetGraceful() && (r.Config().Machine().Type() != machine.TypeWorker), "leave", LeaveEtcd, ).AppendList( stopAllPhaselist(r, false), ).AppendWhen( len(in.GetSystemDiskTargets()) == 0, "reset", ResetSystemDisk, ).AppendWhen( len(in.GetSystemDiskTargets()) > 0, "resetSpec", ResetSystemDiskSpec, ).AppendWhen( in.GetReboot(), "reboot", Reboot, ).AppendWhen( !in.GetReboot(), "shutdown", Shutdown, ) } return phases } // Shutdown is the shutdown sequence. func (*Sequencer) Shutdown(r runtime.Runtime) []runtime.Phase { phases := PhaseList{}. Append( "cleanup", StopAllPods, ). AppendList(stopAllPhaselist(r, false)). Append("shutdown", Shutdown) return phases } // StageUpgrade is the stage upgrade sequence. func (*Sequencer) StageUpgrade(r runtime.Runtime, in *machineapi.UpgradeRequest) []runtime.Phase { phases := PhaseList{} switch r.State().Platform().Mode() { //nolint:exhaustive case runtime.ModeContainer: return nil default: phases = phases.Append( "cleanup", StopAllPods, ).AppendWhen( !in.GetPreserve() && (r.Config().Machine().Type() != machine.TypeWorker), "leave", LeaveEtcd, ).AppendList( stopAllPhaselist(r, true), ).Append( "reboot", Reboot, ) } return phases } // Upgrade is the upgrade sequence. func (*Sequencer) Upgrade(r runtime.Runtime, in *machineapi.UpgradeRequest) []runtime.Phase { phases := PhaseList{} switch r.State().Platform().Mode() { //nolint:exhaustive case runtime.ModeContainer: return nil default: phases = phases.Append( "drain", CordonAndDrainNode, ).AppendWhen( !in.GetPreserve(), "cleanup", RemoveAllPods, ).AppendWhen( in.GetPreserve(), "cleanup", StopAllPods, ).AppendWhen( !in.GetPreserve() && (r.Config().Machine().Type() != machine.TypeWorker), "leave", LeaveEtcd, ).Append( "stopServices", StopServicesForUpgrade, ).Append( "unmountUser", UnmountUserDisks, ).Append( "unmount", UnmountOverlayFilesystems, UnmountPodMounts, ).Append( "unmountBind", UnmountSystemDiskBindMounts, ).Append( "unmountSystem", UnmountEphemeralPartition, UnmountStatePartition, ).Append( "verifyDisk", VerifyDiskAvailability, ).Append( "upgrade", Upgrade, ).Append( "stopEverything", StopAllServices, ).Append( "mountBoot", MountBootPartition, ).Append( "kexec", KexecPrepare, ).Append( "unmountBoot", UnmountBootPartition, ).Append( "reboot", Reboot, ) } return phases } func stopAllPhaselist(r runtime.Runtime, enableKexec bool) PhaseList { phases := PhaseList{} switch r.State().Platform().Mode() { //nolint:exhaustive case runtime.ModeContainer: phases = phases.Append( "stopEverything", StopAllServices, ) default: phases = phases.Append( "stopEverything", StopAllServices, ).Append( "unmountUser", UnmountUserDisks, ).Append( "umount", UnmountOverlayFilesystems, UnmountPodMounts, ).Append( "unmountBind", UnmountSystemDiskBindMounts, ).Append( "unmountSystem", UnmountEphemeralPartition, UnmountStatePartition, ).AppendWhen( enableKexec, "mountBoot", MountBootPartition, ).AppendWhen( enableKexec, "kexec", KexecPrepare, ).AppendWhen( enableKexec, "unmountBoot", UnmountBootPartition, ) } return phases }