mirror of
https://github.com/siderolabs/talos.git
synced 2025-09-15 19:01:12 +02:00
This should save a lot of time on BIOS/POST time with bare metal hardware. Signed-off-by: Andrey Smirnov <andrey.smirnov@talos-systems.com>
232 lines
5.3 KiB
Go
232 lines
5.3 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 v1alpha1
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
|
|
multierror "github.com/hashicorp/go-multierror"
|
|
"github.com/talos-systems/go-blockdevice/blockdevice/probe"
|
|
|
|
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime"
|
|
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime/disk"
|
|
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader"
|
|
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/adv"
|
|
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime/v1alpha1/platform"
|
|
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime/v1alpha2"
|
|
"github.com/talos-systems/talos/pkg/machinery/constants"
|
|
)
|
|
|
|
// State implements the state interface.
|
|
type State struct {
|
|
platform runtime.Platform
|
|
machine *MachineState
|
|
cluster *ClusterState
|
|
v2 runtime.V1Alpha2State
|
|
}
|
|
|
|
// MachineState represents the machine's state.
|
|
type MachineState struct {
|
|
platform runtime.Platform
|
|
|
|
disks map[string]*probe.ProbedBlockDevice
|
|
|
|
stagedInstall bool
|
|
stagedInstallImageRef string
|
|
stagedInstallOptions []byte
|
|
|
|
kexecPrepared bool
|
|
}
|
|
|
|
// ClusterState represents the cluster's state.
|
|
type ClusterState struct{}
|
|
|
|
// NewState initializes and returns the v1alpha1 state.
|
|
func NewState() (s *State, err error) {
|
|
p, err := platform.CurrentPlatform()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
machine := &MachineState{
|
|
platform: p,
|
|
}
|
|
|
|
err = machine.probeDisks()
|
|
if err != nil {
|
|
if !errors.Is(err, os.ErrNotExist) {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
machine.probeMeta()
|
|
|
|
cluster := &ClusterState{}
|
|
|
|
v2State, err := v1alpha2.NewState()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
s = &State{
|
|
platform: p,
|
|
cluster: cluster,
|
|
machine: machine,
|
|
v2: v2State,
|
|
}
|
|
|
|
return s, nil
|
|
}
|
|
|
|
// Platform implements the state interface.
|
|
func (s *State) Platform() runtime.Platform {
|
|
return s.platform
|
|
}
|
|
|
|
// Machine implements the state interface.
|
|
func (s *State) Machine() runtime.MachineState {
|
|
return s.machine
|
|
}
|
|
|
|
// Cluster implements the state interface.
|
|
func (s *State) Cluster() runtime.ClusterState {
|
|
return s.cluster
|
|
}
|
|
|
|
// V1Alpha2 implements the state interface.
|
|
func (s *State) V1Alpha2() runtime.V1Alpha2State {
|
|
return s.v2
|
|
}
|
|
|
|
func (s *MachineState) probeDisks(labels ...string) error {
|
|
if s.platform.Mode() == runtime.ModeContainer {
|
|
return os.ErrNotExist
|
|
}
|
|
|
|
if len(labels) == 0 {
|
|
labels = []string{constants.EphemeralPartitionLabel, constants.BootPartitionLabel, constants.EFIPartitionLabel, constants.StatePartitionLabel}
|
|
}
|
|
|
|
if s.disks == nil {
|
|
s.disks = map[string]*probe.ProbedBlockDevice{}
|
|
}
|
|
|
|
for _, label := range labels {
|
|
if _, ok := s.disks[label]; ok {
|
|
continue
|
|
}
|
|
|
|
var dev *probe.ProbedBlockDevice
|
|
|
|
dev, err := probe.GetDevWithPartitionName(label)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
s.disks[label] = dev
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *MachineState) probeMeta() {
|
|
if s.platform.Mode() == runtime.ModeContainer {
|
|
return
|
|
}
|
|
|
|
meta, err := bootloader.NewMeta()
|
|
if err != nil {
|
|
// ignore missing meta
|
|
return
|
|
}
|
|
|
|
defer meta.Close() //nolint:errcheck
|
|
|
|
stagedInstallImageRef, ok1 := meta.ADV.ReadTag(adv.StagedUpgradeImageRef)
|
|
stagedInstallOptions, ok2 := meta.ADV.ReadTag(adv.StagedUpgradeInstallOptions)
|
|
|
|
s.stagedInstall = ok1 && ok2
|
|
|
|
if s.stagedInstall {
|
|
// clear the staged install flags
|
|
meta.ADV.DeleteTag(adv.StagedUpgradeImageRef)
|
|
meta.ADV.DeleteTag(adv.StagedUpgradeInstallOptions)
|
|
|
|
if err = meta.Write(); err != nil {
|
|
// failed to delete staged install tags, clear the stagedInstall to prevent boot looping
|
|
s.stagedInstall = false
|
|
}
|
|
|
|
s.stagedInstallImageRef = stagedInstallImageRef
|
|
s.stagedInstallOptions = []byte(stagedInstallOptions)
|
|
}
|
|
}
|
|
|
|
// Disk implements the machine state interface.
|
|
func (s *MachineState) Disk(options ...disk.Option) *probe.ProbedBlockDevice {
|
|
opts := &disk.Options{
|
|
Label: constants.EphemeralPartitionLabel,
|
|
}
|
|
|
|
for _, opt := range options {
|
|
opt(opts)
|
|
}
|
|
|
|
s.probeDisks(opts.Label) //nolint:errcheck
|
|
|
|
return s.disks[opts.Label]
|
|
}
|
|
|
|
// Close implements the machine state interface.
|
|
func (s *MachineState) Close() error {
|
|
var result *multierror.Error
|
|
|
|
for label, disk := range s.disks {
|
|
if err := disk.Close(); err != nil {
|
|
e := multierror.Append(result, err)
|
|
if e != nil {
|
|
return e
|
|
}
|
|
}
|
|
|
|
delete(s.disks, label)
|
|
}
|
|
|
|
return result.ErrorOrNil()
|
|
}
|
|
|
|
// Installed implements the machine state interface.
|
|
func (s *MachineState) Installed() bool {
|
|
return s.Disk(
|
|
disk.WithPartitionLabel(constants.EphemeralPartitionLabel),
|
|
) != nil
|
|
}
|
|
|
|
// IsInstallStaged implements the machine state interface.
|
|
func (s *MachineState) IsInstallStaged() bool {
|
|
return s.stagedInstall
|
|
}
|
|
|
|
// StagedInstallImageRef implements the machine state interface.
|
|
func (s *MachineState) StagedInstallImageRef() string {
|
|
return s.stagedInstallImageRef
|
|
}
|
|
|
|
// StagedInstallOptions implements the machine state interface.
|
|
func (s *MachineState) StagedInstallOptions() []byte {
|
|
return s.stagedInstallOptions
|
|
}
|
|
|
|
// KexecPrepared implements the machine state interface.
|
|
func (s *MachineState) KexecPrepared(prepared bool) {
|
|
s.kexecPrepared = prepared
|
|
}
|
|
|
|
// IsKexecPrepared implements the machine state interface.
|
|
func (s *MachineState) IsKexecPrepared() bool {
|
|
return s.kexecPrepared
|
|
}
|