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 <git@frezbo.dev>
This commit is contained in:
Noel Georgi 2024-08-29 18:03:21 +05:30
parent eade0a9f22
commit b6b16b35fb
No known key found for this signature in database
GPG Key ID: 21A9F444075C9E36
7 changed files with 63 additions and 0 deletions

View File

@ -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]

View File

@ -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()

View File

@ -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) {

View File

@ -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")
}

View File

@ -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"

View File

@ -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)
}

View File

@ -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.