From b6b16b35fbccc861410f53bc29ad4cade962f1d6 Mon Sep 17 00:00:00 2001 From: Noel Georgi Date: Thu, 29 Aug 2024 18:03:21 +0530 Subject: [PATCH] chore: pause sequencer when talos installed and iso booted Pause sequencer till the boot timeout if talos is booted from ISO/PXE, but an existing talos is installed to disk and `talos.iso.boot.halt_if_installed` kernel argument is set. Fixes: #9232 Signed-off-by: Noel Georgi --- hack/release.toml | 10 ++++++++++ .../runtime/v1alpha1/v1alpha1_sequencer.go | 9 +++++++++ .../v1alpha1/v1alpha1_sequencer_tasks.go | 19 +++++++++++++++++++ pkg/imager/imager.go | 4 ++++ pkg/machinery/constants/constants.go | 3 +++ pkg/machinery/imager/quirks/quirks.go | 13 +++++++++++++ website/content/v1.8/reference/kernel.md | 5 +++++ 7 files changed, 63 insertions(+) diff --git a/hack/release.toml b/hack/release.toml index 6ed4ec1ba5..3b2766055e 100644 --- a/hack/release.toml +++ b/hack/release.toml @@ -208,6 +208,16 @@ Starting with Talos 1.8, `console=ttyS0` kernel argument is removed from the met This should fix slow boot or no console output issues on most bare metal hardware. """ + [notes.kernel-args] + title = "`talos.halt_if_installed` kernel argument" + description = """\ +Starting with Talos 1.8, ISO's generated from Boot Assets would have a new kernel argument `talos.halt_if_installed` which would pause the boot sequence until boot timeout if Talos is already installed on the disk. +ISO generated for pre 1.8 versions would not have this kernel argument. + +This can be also explicitly enabled by setting `talos.halt_if_installed=1` in kernel argument. +""" + + [make_deps] [make_deps.tools] diff --git a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer.go b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer.go index 00beac3ebd..f3d156d753 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer.go @@ -131,6 +131,15 @@ func (*Sequencer) Initialize(r runtime.Runtime) []runtime.Phase { }, "wipeDisks", ResetSystemDiskPartitions, + ).AppendWithDeferredCheck( + func() bool { + haltIfInstalledStr := procfs.ProcCmdline().Get(constants.KernelParamHaltIfInstalled).First() + haltIfInstalled, _ := strconv.ParseBool(pointer.SafeDeref(haltIfInstalledStr)) //nolint:errcheck + + return r.State().Machine().Installed() && haltIfInstalled + }, + "haltIfInstalled", + haltIfInstalled, ).AppendWithDeferredCheck( func() bool { return r.State().Machine().Installed() diff --git a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go index ab4fe1b6c0..c55cef69d4 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go @@ -1924,6 +1924,25 @@ func UnmountEFIPartition(runtime.Sequence, any) (runtime.TaskExecutionFunc, stri }, "unmountEFIPartition" } +// haltIfInstalled halts the boot process if Talos is installed to disk but booted from ISO. +func haltIfInstalled(seq runtime.Sequence, _ any) (runtime.TaskExecutionFunc, string) { + return func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error { + ctx, cancel := context.WithTimeout(ctx, constants.BootTimeout) + defer cancel() + + timer := time.NewTicker(30 * time.Second) + defer timer.Stop() + + select { + case <-timer.C: + logger.Printf("Talos is already installed to disk but booted from another media and %s kernel parameter is set. Please reboot from the disk.", constants.KernelParamHaltIfInstalled) + case <-ctx.Done(): + } + + return nil + }, "haltIfInstalled" +} + // MountStatePartition mounts the system partition. func MountStatePartition(seq runtime.Sequence, _ any) (runtime.TaskExecutionFunc, string) { return func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) { diff --git a/pkg/imager/imager.go b/pkg/imager/imager.go index 13fc85b3e9..48ac007aac 100644 --- a/pkg/imager/imager.go +++ b/pkg/imager/imager.go @@ -336,6 +336,10 @@ func (i *Imager) buildCmdline() error { // platform kernel args cmdline.Append(constants.KernelParamPlatform, p.Name()) + if quirks.New(i.prof.Version).SupportsHaltIfInstalled() && i.prof.Output.Kind == profile.OutKindISO { + cmdline.Append(constants.KernelParamHaltIfInstalled, "1") + } + if quirks.New(i.prof.Version).SupportsMetalPlatformConsoleTTYS0() && i.prof.Platform == constants.PlatformMetal { cmdline.Append("console", "ttyS0") } diff --git a/pkg/machinery/constants/constants.go b/pkg/machinery/constants/constants.go index 335545a5d9..769e1c1498 100644 --- a/pkg/machinery/constants/constants.go +++ b/pkg/machinery/constants/constants.go @@ -84,6 +84,9 @@ const ( // KernelParamNetIfnames is the kernel parameter name to control predictable network interface names. KernelParamNetIfnames = "net.ifnames" + // KernelParamHaltIfInstalled is the kernel parameter name to control if Talos should pause if booting from boot media while Talos is already installed. + KernelParamHaltIfInstalled = "talos.halt_if_installed" + // BoardNone indicates that the install is not for a specific board. BoardNone = "none" diff --git a/pkg/machinery/imager/quirks/quirks.go b/pkg/machinery/imager/quirks/quirks.go index fb2ebbc514..8684b82270 100644 --- a/pkg/machinery/imager/quirks/quirks.go +++ b/pkg/machinery/imager/quirks/quirks.go @@ -111,3 +111,16 @@ func (q Quirks) SupportsMetalPlatformConsoleTTYS0() bool { return q.v.LT(maxVersionMetalPlatformConsoleTTYS0Dropped) } + +// minVersionSupportsHalfIfInstalled is the version that supports half if installed. +var minVersionSupportsHalfIfInstalled = semver.MustParse("1.8.0") + +// SupportsHaltIfInstalled returns true if the Talos version supports half if installed. +func (q Quirks) SupportsHaltIfInstalled() bool { + // if the version doesn't parse, we assume it's latest Talos + if q.v == nil { + return true + } + + return q.v.GTE(minVersionSupportsHalfIfInstalled) +} diff --git a/website/content/v1.8/reference/kernel.md b/website/content/v1.8/reference/kernel.md index 6dbd4acf84..8c961f14ae 100644 --- a/website/content/v1.8/reference/kernel.md +++ b/website/content/v1.8/reference/kernel.md @@ -259,3 +259,8 @@ Example: ```text talos.device.settle_time=3m ``` + +#### `talos.halt_if_installed` + +If set to `1`, Talos will pause the boot sequence and keeps printing a message until the boot timeout is reached if it detects that it is already installed. +This is useful if booting from ISO/PXE and you want to prevent the machine accidentally booting from the ISO/PXE after installation to the disk.