mirror of
https://github.com/kairos-io/kairos-agent.git
synced 2025-06-03 01:44:53 +00:00
parent
75edc8b146
commit
a6f34820fb
@ -13,22 +13,23 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/kairos-io/kairos-agent/v2/pkg/uki"
|
||||||
|
internalutils "github.com/kairos-io/kairos-agent/v2/pkg/utils"
|
||||||
|
|
||||||
|
fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
|
||||||
|
"github.com/sanity-io/litter"
|
||||||
|
|
||||||
qr "github.com/kairos-io/go-nodepair/qrcode"
|
qr "github.com/kairos-io/go-nodepair/qrcode"
|
||||||
"github.com/kairos-io/kairos-agent/v2/internal/bus"
|
"github.com/kairos-io/kairos-agent/v2/internal/bus"
|
||||||
"github.com/kairos-io/kairos-agent/v2/internal/cmd"
|
"github.com/kairos-io/kairos-agent/v2/internal/cmd"
|
||||||
"github.com/kairos-io/kairos-agent/v2/pkg/action"
|
"github.com/kairos-io/kairos-agent/v2/pkg/action"
|
||||||
"github.com/kairos-io/kairos-agent/v2/pkg/config"
|
"github.com/kairos-io/kairos-agent/v2/pkg/config"
|
||||||
"github.com/kairos-io/kairos-agent/v2/pkg/constants"
|
|
||||||
"github.com/kairos-io/kairos-agent/v2/pkg/uki"
|
|
||||||
internalutils "github.com/kairos-io/kairos-agent/v2/pkg/utils"
|
|
||||||
fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
|
|
||||||
events "github.com/kairos-io/kairos-sdk/bus"
|
events "github.com/kairos-io/kairos-sdk/bus"
|
||||||
"github.com/kairos-io/kairos-sdk/collector"
|
"github.com/kairos-io/kairos-sdk/collector"
|
||||||
"github.com/kairos-io/kairos-sdk/machine"
|
"github.com/kairos-io/kairos-sdk/machine"
|
||||||
"github.com/kairos-io/kairos-sdk/utils"
|
"github.com/kairos-io/kairos-sdk/utils"
|
||||||
"github.com/mudler/go-pluggable"
|
"github.com/mudler/go-pluggable"
|
||||||
"github.com/pterm/pterm"
|
"github.com/pterm/pterm"
|
||||||
"github.com/sanity-io/litter"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func displayInfo(agentConfig *Config) {
|
func displayInfo(agentConfig *Config) {
|
||||||
@ -235,13 +236,6 @@ func RunInstall(c *config.Config) error {
|
|||||||
|
|
||||||
// runInstallUki runs the UKI path install
|
// runInstallUki runs the UKI path install
|
||||||
func runInstallUki(c *config.Config) error {
|
func runInstallUki(c *config.Config) error {
|
||||||
// Check if we are running in PXE
|
|
||||||
err := internalutils.SetPXEEnv(c)
|
|
||||||
if err != nil {
|
|
||||||
c.Logger.Logger.Error().Err(err).Msg("Error setting PXE environment")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load the spec from the config
|
// Load the spec from the config
|
||||||
installSpec, err := config.ReadUkiInstallSpecFromConfig(c)
|
installSpec, err := config.ReadUkiInstallSpecFromConfig(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -264,24 +258,7 @@ func runInstallUki(c *config.Config) error {
|
|||||||
c.CloudInitPaths = append(c.CloudInitPaths, installSpec.CloudInit...)
|
c.CloudInitPaths = append(c.CloudInitPaths, installSpec.CloudInit...)
|
||||||
|
|
||||||
installAction := uki.NewInstallAction(c, installSpec)
|
installAction := uki.NewInstallAction(c, installSpec)
|
||||||
err = installAction.Run()
|
return installAction.Run()
|
||||||
|
|
||||||
if err == nil && utils.Exists(constants.PXEVarFile) {
|
|
||||||
// TODO: do we fail here?
|
|
||||||
err = internalutils.RemoveEfivarPXE(c.Logger)
|
|
||||||
if err != nil {
|
|
||||||
c.Logger.Logger.Error().Err(err).Msg("Error removing PXE Efivar")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// Now remove the boot entry
|
|
||||||
// TODO: Do we fail here?
|
|
||||||
err = internalutils.RemoveBootEntry("kairos", c.Logger)
|
|
||||||
if err != nil {
|
|
||||||
c.Logger.Logger.Error().Err(err).Msg("Error removing PXE boot entry")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// runInstall runs the non-UKI path install
|
// runInstall runs the non-UKI path install
|
||||||
|
@ -50,7 +50,6 @@ const (
|
|||||||
LinuxImgFs = "ext2"
|
LinuxImgFs = "ext2"
|
||||||
SquashFs = "squashfs"
|
SquashFs = "squashfs"
|
||||||
EfiFs = "vfat"
|
EfiFs = "vfat"
|
||||||
IsoFS = "iso9660"
|
|
||||||
EfiSize = uint(64)
|
EfiSize = uint(64)
|
||||||
OEMSize = uint(64)
|
OEMSize = uint(64)
|
||||||
PersistentSize = uint(0)
|
PersistentSize = uint(0)
|
||||||
@ -131,11 +130,6 @@ const (
|
|||||||
UpgradeRecoveryNoSourceError = "could not find a proper source for the recovery upgrade.\nThis can be configured in the cloud config files under the 'upgrade.recovery-system.uri' key or via cmdline using the '--source' flag"
|
UpgradeRecoveryNoSourceError = "could not find a proper source for the recovery upgrade.\nThis can be configured in the cloud config files under the 'upgrade.recovery-system.uri' key or via cmdline using the '--source' flag"
|
||||||
MultipleEntriesAssessmentError = "multiple boot entries found for %s"
|
MultipleEntriesAssessmentError = "multiple boot entries found for %s"
|
||||||
NoBootAssessmentWarning = "No boot assessment found in current boot entry config file"
|
NoBootAssessmentWarning = "No boot assessment found in current boot entry config file"
|
||||||
|
|
||||||
// PXEVarFile is the path to the PXE boot entry file
|
|
||||||
PXEVarFile = "/sys/firmware/efi/efivars/PXEBoot-3c909ff1-80a9-5970-94f1-fefb255c88bd"
|
|
||||||
PXEIsoFile = "/tmp/pxe-source.iso"
|
|
||||||
PXEEfiBootFile = "efiboot.img"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func UkiDefaultMenuEntries() []string {
|
func UkiDefaultMenuEntries() []string {
|
||||||
|
@ -21,8 +21,6 @@ import (
|
|||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/foxboron/go-uefi/efi/attr"
|
|
||||||
"github.com/kairos-io/kairos-agent/v2/pkg/utils/loop"
|
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
random "math/rand"
|
random "math/rand"
|
||||||
@ -35,18 +33,19 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/distribution/reference"
|
sdkTypes "github.com/kairos-io/kairos-sdk/types"
|
||||||
"github.com/foxboron/go-uefi/efi/attributes"
|
|
||||||
"github.com/foxboron/go-uefi/efivarfs"
|
|
||||||
"github.com/joho/godotenv"
|
|
||||||
agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config"
|
|
||||||
cnst "github.com/kairos-io/kairos-agent/v2/pkg/constants"
|
|
||||||
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
|
|
||||||
fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
|
|
||||||
"github.com/kairos-io/kairos-agent/v2/pkg/utils/partitions"
|
|
||||||
"github.com/kairos-io/kairos-sdk/state"
|
"github.com/kairos-io/kairos-sdk/state"
|
||||||
"github.com/kairos-io/kairos-sdk/types"
|
"github.com/kairos-io/kairos-sdk/types"
|
||||||
sdkTypes "github.com/kairos-io/kairos-sdk/types"
|
|
||||||
|
agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config"
|
||||||
|
fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
|
||||||
|
"github.com/kairos-io/kairos-agent/v2/pkg/utils/partitions"
|
||||||
|
|
||||||
|
"github.com/distribution/reference"
|
||||||
|
"github.com/joho/godotenv"
|
||||||
|
cnst "github.com/kairos-io/kairos-agent/v2/pkg/constants"
|
||||||
|
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
|
||||||
"github.com/twpayne/go-vfs/v5"
|
"github.com/twpayne/go-vfs/v5"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -708,106 +707,3 @@ func ReadAssessmentFromEntry(fs v1.FS, entry string, logger sdkTypes.KairosLogge
|
|||||||
}
|
}
|
||||||
return re.FindStringSubmatch(currentfile[0])[1], nil
|
return re.FindStringSubmatch(currentfile[0])[1], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadEfivar reads the content of an efivar file, skipping the first 4 bytes (attributes).
|
|
||||||
func ReadEfivar(path string) ([]byte, error) {
|
|
||||||
f, err := os.Open(path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
// Skip the first 4 bytes (attributes)
|
|
||||||
attr := make([]byte, 4)
|
|
||||||
_, err = io.ReadFull(f, attr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
content, err := io.ReadAll(f)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return content, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func RemoveBootEntry(entryName string, l types.KairosLogger) error {
|
|
||||||
// Remove any boot entries that match kairos
|
|
||||||
efifs := efivarfs.NewFS().CheckImmutable().UnsetImmutable().Open()
|
|
||||||
for _, entry := range efifs.GetBootOrder() {
|
|
||||||
e, err := efifs.GetBootEntry(entry)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// TODO: maybe contains? so we match any variations that migth appear in the future?
|
|
||||||
if strings.ToLower(e.Description) == strings.ToLower(entryName) {
|
|
||||||
fileName := fmt.Sprintf("/sys/firmware/efi/efivars/%s-%s", entry, attributes.EFI_GLOBAL_VARIABLE.Format())
|
|
||||||
l.Logger.Debug().Str("entry", e.Description).Str("filename", fileName).Msg("Removing boot entry")
|
|
||||||
err = os.Remove(fileName)
|
|
||||||
if err != nil {
|
|
||||||
l.Logger.Err(err).Str("entry", e.Description).Str("filename", fileName).Msg("Error removing boot entry")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func RemoveEfivarPXE(l types.KairosLogger) error {
|
|
||||||
// Disable immutability
|
|
||||||
err := attr.UnsetImmutable(cnst.PXEVarFile)
|
|
||||||
if err != nil {
|
|
||||||
l.Logger.Err(err).Str("file", cnst.PXEVarFile).Msg("Error unsetting immutable attribute")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return os.Remove(cnst.PXEVarFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetPXEEnv(c *agentConfig.Config) error {
|
|
||||||
efivar, err := ReadEfivar(cnst.PXEVarFile)
|
|
||||||
// We dont care if we fail to read it, that means its not there
|
|
||||||
if err == nil {
|
|
||||||
c.Logger.Logger.Info().Str("iso", string(efivar)).Msg("PXE boot detected, downloading and mounting the iso locally")
|
|
||||||
err = c.Client.GetURL(c.Logger, string(efivar), cnst.PXEIsoFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
isoLoop, err := loop.LoopRO(&v1.Image{File: cnst.PXEIsoFile}, c)
|
|
||||||
if err != nil {
|
|
||||||
c.Logger.Logger.Error().Err(err).Msg("Error creating loop device for iso image")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer loop.Unloop(isoLoop, c)
|
|
||||||
c.Logger.Logger.Debug().Str("iso", isoLoop).Msg("Mounted iso loop device")
|
|
||||||
|
|
||||||
// Mount the iso under /run/initramfs/live
|
|
||||||
err = c.Mounter.Mount(isoLoop, cnst.UkiCdromSource, cnst.IsoFS, nil)
|
|
||||||
if err != nil {
|
|
||||||
c.Logger.Errorf("Error mounting iso: %s", err.Error())
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
c.Logger.Infof("Mounted iso under %s", cnst.UkiCdromSource)
|
|
||||||
defer c.Mounter.Unmount(cnst.UkiCdromSource)
|
|
||||||
|
|
||||||
// Now mount the efi image inside the iso
|
|
||||||
efiLoop, err := loop.LoopRO(&v1.Image{File: filepath.Join(cnst.UkiCdromSource, cnst.PXEEfiBootFile)}, c)
|
|
||||||
if err != nil {
|
|
||||||
c.Logger.Logger.Error().Err(err).Msg("Error creating loop device for efi image")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer loop.Unloop(efiLoop, c)
|
|
||||||
c.Logger.Logger.Debug().Str("efi", efiLoop).Msg("Mounted efi loop device")
|
|
||||||
|
|
||||||
// Mount the efi image under /run/rootfsbase which is the same as to other boot paths mount it at
|
|
||||||
err = c.Mounter.Mount(efiLoop, cnst.IsoBaseTree, cnst.EfiFs, nil)
|
|
||||||
if err != nil {
|
|
||||||
c.Logger.Errorf("Error mounting iso: %s", err.Error())
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
c.Logger.Infof("Mounted Efi source under %s", cnst.IsoBaseTree)
|
|
||||||
defer c.Mounter.Unmount(cnst.IsoBaseTree)
|
|
||||||
// Now the system should have the same paths and sources as the normal install from usb/cdrom
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
@ -23,15 +23,6 @@ func errnoIsErr(err error) error {
|
|||||||
|
|
||||||
// Loop will setup a /dev/loopX device linked to the image file by using syscalls directly to set it
|
// Loop will setup a /dev/loopX device linked to the image file by using syscalls directly to set it
|
||||||
func Loop(img *v1.Image, cfg *config.Config) (loopDevice string, err error) {
|
func Loop(img *v1.Image, cfg *config.Config) (loopDevice string, err error) {
|
||||||
return loop(img, cfg, os.O_RDWR)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoopRO will setup a /dev/loopX device linked to the image file by using syscalls directly to set it. Will open it RO
|
|
||||||
func LoopRO(img *v1.Image, cfg *config.Config) (loopDevice string, err error) {
|
|
||||||
return loop(img, cfg, os.O_RDONLY)
|
|
||||||
}
|
|
||||||
|
|
||||||
func loop(img *v1.Image, cfg *config.Config, openPerm int) (loopDevice string, err error) {
|
|
||||||
log := cfg.Logger
|
log := cfg.Logger
|
||||||
log.Debugf("Opening loop control device")
|
log.Debugf("Opening loop control device")
|
||||||
fd, err := cfg.Fs.OpenFile("/dev/loop-control", os.O_RDONLY, 0o644)
|
fd, err := cfg.Fs.OpenFile("/dev/loop-control", os.O_RDONLY, 0o644)
|
||||||
@ -56,7 +47,7 @@ func loop(img *v1.Image, cfg *config.Config, openPerm int) (loopDevice string, e
|
|||||||
return loopDevice, err
|
return loopDevice, err
|
||||||
}
|
}
|
||||||
log.Logger.Debug().Str("image", img.File).Msg("Opening img file")
|
log.Logger.Debug().Str("image", img.File).Msg("Opening img file")
|
||||||
imageFile, err := cfg.Fs.OpenFile(img.File, openPerm, os.ModePerm)
|
imageFile, err := cfg.Fs.OpenFile(img.File, os.O_RDWR, os.ModePerm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("failed to open image file")
|
log.Error("failed to open image file")
|
||||||
return loopDevice, err
|
return loopDevice, err
|
||||||
|
Loading…
Reference in New Issue
Block a user