Andrey Smirnov 139c62d762
feat: allow upgrades in maintenance mode (only over SideroLink)
This implements a simple way to upgrade Talos node running in
maintenance mode (only if Talos is installed, i.e. if `STATE` and
`EPHEMERAL` partitions are wiped).

Upgrade is only available over SideroLink for security reasons.

Upgrade in maintenance mode doesn't support any options, and it works
without machine configuration, so proxy environment variables are not
available, registry mirrors can't be used, and extensions are not
installed.

Fixes #6224

Signed-off-by: Andrey Smirnov <andrey.smirnov@talos-systems.com>
2022-09-30 21:16:15 +04:00

163 lines
4.2 KiB
Go

// 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 runtime
import (
"fmt"
"github.com/talos-systems/talos/pkg/machinery/api/machine"
)
// Sequence represents a sequence type.
type Sequence int
const (
// SequenceNoop is the noop sequence.
SequenceNoop Sequence = iota
// SequenceBoot is the boot sequence.
SequenceBoot
// SequenceInitialize is the initialize sequence.
SequenceInitialize
// SequenceInstall is the install sequence.
SequenceInstall
// SequenceShutdown is the shutdown sequence.
SequenceShutdown
// SequenceUpgrade is the upgrade sequence.
SequenceUpgrade
// SequenceStageUpgrade is the stage upgrade sequence.
SequenceStageUpgrade
// SequenceMaintenanceUpgrade is the upgrade sequence in maintenance mode.
SequenceMaintenanceUpgrade
// SequenceReset is the reset sequence.
SequenceReset
// SequenceReboot is the reboot sequence.
SequenceReboot
)
const (
boot = "boot"
initialize = "initialize"
install = "install"
shutdown = "shutdown"
upgrade = "upgrade"
stageUpgrade = "stageUpgrade"
maintenanceUpgrade = "maintenanceUpgrade"
reset = "reset"
reboot = "reboot"
noop = "noop"
)
var sequenceTakeOver = map[Sequence]map[Sequence]struct{}{
SequenceInitialize: {
SequenceMaintenanceUpgrade: {},
},
SequenceBoot: {
SequenceReboot: {},
SequenceReset: {},
SequenceUpgrade: {},
},
SequenceReboot: {
SequenceReboot: {},
},
SequenceReset: {
SequenceReboot: {},
},
}
// String returns the string representation of a `Sequence`.
func (s Sequence) String() string {
return [...]string{noop, boot, initialize, install, shutdown, upgrade, stageUpgrade, maintenanceUpgrade, reset, reboot}[s]
}
// CanTakeOver defines sequences priority.
//
// | what is running (columns) what is requested (rows) | boot | reboot | reset | upgrade |
// |----------------------------------------------------|------|--------|-------|---------|
// | reboot | Y | Y | Y | N |
// | reset | Y | N | N | N |
// | upgrade | Y | N | N | N |.
func (s Sequence) CanTakeOver(running Sequence) bool {
if running == SequenceNoop {
return true
}
if sequences, ok := sequenceTakeOver[running]; ok {
if _, ok = sequences[s]; ok {
return true
}
}
return false
}
// ParseSequence returns a `Sequence` that matches the specified string.
//
//nolint:gocyclo
func ParseSequence(s string) (seq Sequence, err error) {
switch s {
case boot:
seq = SequenceBoot
case initialize:
seq = SequenceInitialize
case install:
seq = SequenceInstall
case shutdown:
seq = SequenceShutdown
case upgrade:
seq = SequenceUpgrade
case stageUpgrade:
seq = SequenceStageUpgrade
case reset:
seq = SequenceReset
case reboot:
seq = SequenceReboot
case noop:
seq = SequenceNoop
default:
return seq, fmt.Errorf("unknown runtime sequence: %q", s)
}
return seq, nil
}
// ResetOptions are parameters to Reset sequence.
type ResetOptions interface {
GetGraceful() bool
GetReboot() bool
GetSystemDiskTargets() []PartitionTarget
}
// PartitionTarget provides interface to the disk partition.
type PartitionTarget interface {
fmt.Stringer
Format() error
GetLabel() string
}
// Sequencer describes the set of sequences required for the lifecycle
// management of the operating system.
type Sequencer interface {
Boot(Runtime) []Phase
Initialize(Runtime) []Phase
Install(Runtime) []Phase
Reboot(Runtime) []Phase
Reset(Runtime, ResetOptions) []Phase
Shutdown(Runtime, *machine.ShutdownRequest) []Phase
StageUpgrade(Runtime, *machine.UpgradeRequest) []Phase
Upgrade(Runtime, *machine.UpgradeRequest) []Phase
MaintenanceUpgrade(Runtime, *machine.UpgradeRequest) []Phase
}
// EventSequenceStart represents the sequence start event.
type EventSequenceStart struct {
Sequence Sequence
}
// EventFatalSequencerError represents a fatal sequencer error.
type EventFatalSequencerError struct {
Error error
Sequence Sequence
}