From f6f113128d7579b58c65a8b7db1bd54ff1459fc7 Mon Sep 17 00:00:00 2001 From: Itxaka Date: Fri, 26 Jan 2024 17:41:23 +0100 Subject: [PATCH] Remove entries on install (#213) --- pkg/config/spec.go | 2 ++ pkg/constants/constants.go | 4 +++ pkg/types/v1/config.go | 1 + pkg/uki/install.go | 59 ++++++++++++++++++++++++++++++++++++-- pkg/utils/common.go | 29 +++++++++++++++++++ 5 files changed, 93 insertions(+), 2 deletions(-) diff --git a/pkg/config/spec.go b/pkg/config/spec.go index 91d33a1..0f92187 100644 --- a/pkg/config/spec.go +++ b/pkg/config/spec.go @@ -571,6 +571,8 @@ func NewUkiInstallSpec(cfg *Config) (*v1.InstallUkiSpec, error) { // TODO: Which key to use? install or install-uki? err := unmarshallFullSpec(cfg, "install", spec) // TODO: Get the actual source size to calculate the image size and partitions size for at least 3 UKI images + // Add default values for the skip partitions for our default entries + spec.SkipEntries = append(spec.SkipEntries, constants.UkiDefaultSkipEntries()...) return spec, err } diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index 46cac34..511ba3b 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -114,6 +114,10 @@ const ( UkiMaxEntries = 3 ) +func UkiDefaultSkipEntries() []string { + return []string{"interactive-install", "manual-install"} +} + func GetCloudInitPaths() []string { return []string{"/system/oem", "/oem/", "/usr/local/cloud-config/"} } diff --git a/pkg/types/v1/config.go b/pkg/types/v1/config.go index c3ea08a..906d670 100644 --- a/pkg/types/v1/config.go +++ b/pkg/types/v1/config.go @@ -510,6 +510,7 @@ type InstallUkiSpec struct { Partitions ElementalPartitions `yaml:"partitions,omitempty" mapstructure:"partitions"` ExtraPartitions PartitionList `yaml:"extra-partitions,omitempty" mapstructure:"extra-partitions"` CloudInit []string `yaml:"cloud-init,omitempty" mapstructure:"cloud-init"` + SkipEntries []string `yaml:"skip-entries,omitempty" mapstructure:"skip-entries"` } func (i *InstallUkiSpec) Sanitize() error { diff --git a/pkg/uki/install.go b/pkg/uki/install.go index b28c97e..1b9a8d4 100644 --- a/pkg/uki/install.go +++ b/pkg/uki/install.go @@ -1,6 +1,10 @@ package uki import ( + "os" + "path/filepath" + "strings" + hook "github.com/kairos-io/kairos-agent/v2/internal/agent/hooks" "github.com/kairos-io/kairos-agent/v2/pkg/config" "github.com/kairos-io/kairos-agent/v2/pkg/constants" @@ -9,8 +13,7 @@ import ( "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" - "os" - "path/filepath" + "github.com/sanity-io/litter" ) type InstallAction struct { @@ -120,6 +123,58 @@ func (i *InstallAction) Run() (err error) { return err } + // Remove entries + // Read all confs + err = fsutils.WalkDirFs(i.cfg.Fs, filepath.Join(i.spec.Partitions.EFI.MountPoint, "loader/entries/"), func(path string, info os.DirEntry, err error) error { + i.cfg.Logger.Debugf("Checking file %s", path) + if info.IsDir() { + return nil + } + if filepath.Ext(info.Name()) != ".conf" { + return nil + } + // Extract the values + conf, err := utils.SystemdBootConfReader(path) + if err != nil { + i.cfg.Logger.Errorf("Error reading conf file %s: %s", path, err) + return err + } + i.cfg.Logger.Debugf("Conf file %s has values %v", path, litter.Sdump(conf)) + if len(conf["cmdline"]) == 0 { + return nil + } + // Check if the cmdline matches any of the entries in the skip list + for _, entry := range i.spec.SkipEntries { + // Match the cmdline key against the entry + if strings.Contains(conf["cmdline"], entry) { + i.cfg.Logger.Debugf("Found match for %s in %s", entry, path) + // If match, get the efi file and remove it + if conf["efi"] != "" { + i.cfg.Logger.Debugf("Removing efi file %s", conf["efi"]) + // First remove the efi file + err = i.cfg.Fs.Remove(filepath.Join(i.spec.Partitions.EFI.MountPoint, conf["efi"])) + if err != nil { + i.cfg.Logger.Errorf("Error removing efi file %s: %s", conf["efi"], err) + return err + } + // Then remove the conf file + i.cfg.Logger.Debugf("Removing conf file %s", path) + err = i.cfg.Fs.Remove(path) + if err != nil { + i.cfg.Logger.Errorf("Error removing conf file %s: %s", path, err) + return err + } + // Do not continue checking the conf file, we already done all we needed + } + } + } + return err + }) + + if err != nil { + return err + } + // after install hook happens after install (this is for compatibility with normal install, so users can reuse their configs) err = Hook(i.cfg, constants.AfterInstallHook) if err != nil { diff --git a/pkg/utils/common.go b/pkg/utils/common.go index 0502f23..565e933 100644 --- a/pkg/utils/common.go +++ b/pkg/utils/common.go @@ -17,6 +17,7 @@ limitations under the License. package utils import ( + "bufio" "crypto/sha256" "errors" "fmt" @@ -527,3 +528,31 @@ func UkiBootMode() state.Boot { } return state.Unknown } + +// SystemdBootConfReader reads a systemd-boot conf file and returns a map with the key/value pairs +func SystemdBootConfReader(filePath string) (map[string]string, error) { + file, err := os.Open(filePath) + if err != nil { + return nil, err + } + defer file.Close() + + result := make(map[string]string) + scanner := bufio.NewScanner(file) + for scanner.Scan() { + line := scanner.Text() + parts := strings.SplitN(line, " ", 2) + if len(parts) == 2 { + result[parts[0]] = parts[1] + } + if len(parts) == 1 { + result[parts[0]] = "" + } + } + + if err := scanner.Err(); err != nil { + return nil, err + } + + return result, nil +}