Merge elemental config into agent config (#102)

This commit is contained in:
Itxaka 2023-07-25 15:21:34 +02:00 committed by GitHub
parent 5b945303c9
commit f7bdba2dda
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 799 additions and 1092 deletions

2
go.mod
View File

@ -12,7 +12,7 @@ require (
github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-multierror v1.1.1
github.com/jaypipes/ghw v0.12.0 github.com/jaypipes/ghw v0.12.0
github.com/joho/godotenv v1.5.1 github.com/joho/godotenv v1.5.1
github.com/kairos-io/kairos-sdk v0.0.9 github.com/kairos-io/kairos-sdk v0.0.10
github.com/labstack/echo/v4 v4.10.2 github.com/labstack/echo/v4 v4.10.2
github.com/mitchellh/mapstructure v1.5.0 github.com/mitchellh/mapstructure v1.5.0
github.com/mudler/go-nodepair v0.0.0-20221223092639-ba399a66fdfb github.com/mudler/go-nodepair v0.0.0-20221223092639-ba399a66fdfb

2
go.sum
View File

@ -358,6 +358,8 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kairos-io/kairos-sdk v0.0.9 h1:DnuvmnCTDBQg0nr3siaXb5pspi+GUsf1rPb0MFOTdTc= github.com/kairos-io/kairos-sdk v0.0.9 h1:DnuvmnCTDBQg0nr3siaXb5pspi+GUsf1rPb0MFOTdTc=
github.com/kairos-io/kairos-sdk v0.0.9/go.mod h1:Z+1CLqMZq97bzwX2XSIArr8EoniMth3mMYkOOb8L3QY= github.com/kairos-io/kairos-sdk v0.0.9/go.mod h1:Z+1CLqMZq97bzwX2XSIArr8EoniMth3mMYkOOb8L3QY=
github.com/kairos-io/kairos-sdk v0.0.10 h1:TUgrGSGP6Z1CPfA4gjmbb+cCaJg1OR18c+LD+ZRGqMk=
github.com/kairos-io/kairos-sdk v0.0.10/go.mod h1:AK9poWisuhnzri04diXnTG8L7EkOSUArSeeDn2LYFU0=
github.com/kbinani/screenshot v0.0.0-20210720154843-7d3a670d8329 h1:qq2nCpSrXrmvDGRxW0ruW9BVEV1CN2a9YDOExdt+U0o= github.com/kbinani/screenshot v0.0.0-20210720154843-7d3a670d8329 h1:qq2nCpSrXrmvDGRxW0ruW9BVEV1CN2a9YDOExdt+U0o=
github.com/kbinani/screenshot v0.0.0-20210720154843-7d3a670d8329/go.mod h1:2VPVQDR4wO7KXHwP+DAypEy67rXf+okUx2zjgpCxZw4= github.com/kbinani/screenshot v0.0.0-20210720154843-7d3a670d8329/go.mod h1:2VPVQDR4wO7KXHwP+DAypEy67rXf+okUx2zjgpCxZw4=
github.com/kendru/darwin/go/depgraph v0.0.0-20221105232959-877d6a81060c h1:eKb4PqwAMhlqwXw0W3atpKaYaPGlXE/Fwh+xpCEYaPk= github.com/kendru/darwin/go/depgraph v0.0.0-20221105232959-877d6a81060c h1:eKb4PqwAMhlqwXw0W3atpKaYaPGlXE/Fwh+xpCEYaPk=

View File

@ -10,7 +10,6 @@ type Interface interface {
} }
var AfterInstall = []Interface{ var AfterInstall = []Interface{
&RunStage{}, // Shells out to stages defined from the container image
&GrubOptions{}, // Set custom GRUB options &GrubOptions{}, // Set custom GRUB options
&BundleOption{}, &BundleOption{},
&CustomMounts{}, &CustomMounts{},

View File

@ -1,22 +0,0 @@
package hook
import (
"github.com/kairos-io/kairos-agent/v2/pkg/config"
"github.com/kairos-io/kairos-agent/v2/pkg/elementalConfig"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
"github.com/kairos-io/kairos-agent/v2/pkg/utils"
events "github.com/kairos-io/kairos-sdk/bus"
)
type RunStage struct{}
func (r RunStage) Run(c config.Config, _ v1.Spec) error {
cfg, err := elementalConfig.ReadConfigRunFromAgentConfig(&c)
if err != nil {
cfg.Logger.Errorf("Error reading config: %s\n", err)
}
_ = utils.RunStage(cfg, "kairos-install.after")
events.RunHookScript("/usr/bin/kairos-agent.install.after.hook") //nolint:errcheck
return nil
}

View File

@ -5,6 +5,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
"net/url" "net/url"
"os" "os"
"strings" "strings"
@ -16,7 +17,6 @@ import (
"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/elementalConfig"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
elementalUtils "github.com/kairos-io/kairos-agent/v2/pkg/utils" elementalUtils "github.com/kairos-io/kairos-agent/v2/pkg/utils"
events "github.com/kairos-io/kairos-sdk/bus" events "github.com/kairos-io/kairos-sdk/bus"
@ -51,17 +51,6 @@ func displayInfo(agentConfig *Config) {
} }
} }
func mergeOption(cloudConfig string, r map[string]string) {
c := &config.Config{}
yaml.Unmarshal([]byte(cloudConfig), c) //nolint:errcheck
for k, v := range c.Options {
if k == "cc" {
continue
}
r[k] = v
}
}
func ManualInstall(c, device string, reboot, poweroff, strictValidations bool) error { func ManualInstall(c, device string, reboot, poweroff, strictValidations bool) error {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
defer cancel() defer cancel()
@ -223,22 +212,21 @@ func RunInstall(c *config.Config) error {
c.Install.Device = detectDevice() c.Install.Device = detectDevice()
} }
// Load the installation Config from the system // Load the installation spec from the Config
installConfig, installSpec, err := elementalConfig.ReadInstallConfigFromAgentConfig(c) installSpec, err := config.ReadInstallSpecFromConfig(c)
if err != nil { if err != nil {
return err return err
} }
f, err := elementalUtils.TempFile(installConfig.Fs, "", "kairos-install-config-xxx.yaml") f, err := fsutils.TempFile(c.Fs, "", "kairos-install-config-xxx.yaml")
if err != nil { if err != nil {
installConfig.Logger.Error("Error creating temporal file for install config: %s\n", err.Error()) c.Logger.Error("Error creating temporary file for install config: %s\n", err.Error())
return err return err
} }
defer os.RemoveAll(f.Name()) defer os.RemoveAll(f.Name())
ccstring, err := c.String() ccstring, err := c.String()
if err != nil { if err != nil {
installConfig.Logger.Error("Error creating temporary file for install config: %s\n", err.Error())
return err return err
} }
err = os.WriteFile(f.Name(), []byte(ccstring), os.ModePerm) err = os.WriteFile(f.Name(), []byte(ccstring), os.ModePerm)
@ -247,6 +235,7 @@ func RunInstall(c *config.Config) error {
return err return err
} }
// TODO: This should not be neccessary
installSpec.NoFormat = c.Install.NoFormat installSpec.NoFormat = c.Install.NoFormat
// Set our cloud-init to the file we just created // Set our cloud-init to the file we just created
@ -267,18 +256,20 @@ func RunInstall(c *config.Config) error {
} }
// Add user's cloud-config (to run user defined "before-install" stages) // Add user's cloud-config (to run user defined "before-install" stages)
installConfig.CloudInitPaths = append(installConfig.CloudInitPaths, installSpec.CloudInit...) c.CloudInitPaths = append(c.CloudInitPaths, installSpec.CloudInit...)
// Run pre-install stage // Run pre-install stage
_ = elementalUtils.RunStage(installConfig, "kairos-install.pre") _ = elementalUtils.RunStage(c, "kairos-install.pre")
events.RunHookScript("/usr/bin/kairos-agent.install.pre.hook") //nolint:errcheck events.RunHookScript("/usr/bin/kairos-agent.install.pre.hook") //nolint:errcheck
// Create the action // Create the action
installAction := action.NewInstallAction(installConfig, installSpec) installAction := action.NewInstallAction(c, installSpec)
// Run it // Run it
if err := installAction.Run(); err != nil { if err := installAction.Run(); err != nil {
fmt.Println(err) fmt.Println(err)
os.Exit(1) os.Exit(1)
} }
_ = elementalUtils.RunStage(c, "kairos-install.after")
events.RunHookScript("/usr/bin/kairos-agent.install.after.hook") //nolint:errcheck
return hook.Run(*c, installSpec, hook.AfterInstall...) return hook.Run(*c, installSpec, hook.AfterInstall...)
} }

View File

@ -5,11 +5,11 @@ import (
"fmt" "fmt"
"github.com/jaypipes/ghw/pkg/block" "github.com/jaypipes/ghw/pkg/block"
"github.com/kairos-io/kairos-agent/v2/pkg/constants" "github.com/kairos-io/kairos-agent/v2/pkg/constants"
"github.com/kairos-io/kairos-agent/v2/pkg/utils"
"os" "os"
"path/filepath" "path/filepath"
"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/utils/fs"
v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks" v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks"
"github.com/twpayne/go-vfs" "github.com/twpayne/go-vfs"
"github.com/twpayne/go-vfs/vfst" "github.com/twpayne/go-vfs/vfst"
@ -84,10 +84,10 @@ var _ = Describe("RunInstall", func() {
fs, cleanup, err = vfst.NewTestFS(map[string]interface{}{"/proc/cmdline": ""}) fs, cleanup, err = vfst.NewTestFS(map[string]interface{}{"/proc/cmdline": ""})
Expect(err).Should(BeNil()) Expect(err).Should(BeNil())
// Create tmp dir // Create tmp dir
utils.MkdirAll(fs, "/tmp", constants.DirPerm) fsutils.MkdirAll(fs, "/tmp", constants.DirPerm)
// Create grub confg // Create grub confg
grubCfg := filepath.Join(constants.ActiveDir, constants.GrubConf) grubCfg := filepath.Join(constants.ActiveDir, constants.GrubConf)
err = utils.MkdirAll(fs, filepath.Dir(grubCfg), constants.DirPerm) err = fsutils.MkdirAll(fs, filepath.Dir(grubCfg), constants.DirPerm)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
_, err = fs.Create(grubCfg) _, err = fs.Create(grubCfg)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
@ -133,7 +133,7 @@ var _ = Describe("RunInstall", func() {
} }
device := "/some/device" device := "/some/device"
err = utils.MkdirAll(fs, filepath.Dir(device), constants.DirPerm) err = fsutils.MkdirAll(fs, filepath.Dir(device), constants.DirPerm)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
_, err = fs.Create(device) _, err = fs.Create(device)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())

View File

@ -12,7 +12,6 @@ import (
"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/elementalConfig"
sdk "github.com/kairos-io/kairos-sdk/bus" sdk "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"
@ -78,7 +77,7 @@ func Reset(dir ...string) error {
utils.SetEnv(c.Env) utils.SetEnv(c.Env)
// Load the installation Config from the cloud-config data // Load the installation Config from the cloud-config data
resetConfig, resetSpec, err := elementalConfig.ReadResetConfigFromAgentConfig(c) resetSpec, err := config.ReadResetSpecFromConfig(c)
if err != nil { if err != nil {
return err return err
} }
@ -92,11 +91,11 @@ func Reset(dir ...string) error {
resetSpec.FormatOEM = o == "true" resetSpec.FormatOEM = o == "true"
} }
if s := optionsFromEvent["strict"]; s != "" { if s := optionsFromEvent["strict"]; s != "" {
resetConfig.Strict = s == "true" c.Strict = s == "true"
} }
} }
resetAction := action.NewResetAction(resetConfig, resetSpec) resetAction := action.NewResetAction(c, resetSpec)
if err := resetAction.Run(); err != nil { if err := resetAction.Run(); err != nil {
fmt.Println(err) fmt.Println(err)
os.Exit(1) os.Exit(1)

View File

@ -11,7 +11,6 @@ import (
"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/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/elementalConfig"
"github.com/kairos-io/kairos-agent/v2/pkg/github" "github.com/kairos-io/kairos-agent/v2/pkg/github"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
events "github.com/kairos-io/kairos-sdk/bus" events "github.com/kairos-io/kairos-sdk/bus"
@ -100,7 +99,7 @@ func Upgrade(
utils.SetEnv(c.Env) utils.SetEnv(c.Env)
// Load the upgrade Config from the system // Load the upgrade Config from the system
upgradeConfig, upgradeSpec, err := elementalConfig.ReadUpgradeConfigFromAgentConfig(c) upgradeSpec, err := config.ReadUpgradeSpecFromConfig(c)
if err != nil { if err != nil {
return err return err
} }
@ -118,7 +117,7 @@ func Upgrade(
return err return err
} }
upgradeAction := action.NewUpgradeAction(upgradeConfig, upgradeSpec) upgradeAction := action.NewUpgradeAction(c, upgradeSpec)
err = upgradeAction.Run() err = upgradeAction.Run()
if err != nil { if err != nil {

37
main.go
View File

@ -15,8 +15,7 @@ import (
"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/common" "github.com/kairos-io/kairos-agent/v2/internal/common"
"github.com/kairos-io/kairos-agent/v2/internal/webui" "github.com/kairos-io/kairos-agent/v2/internal/webui"
"github.com/kairos-io/kairos-agent/v2/pkg/config" agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config"
"github.com/kairos-io/kairos-agent/v2/pkg/elementalConfig"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
"github.com/kairos-io/kairos-sdk/bundles" "github.com/kairos-io/kairos-sdk/bundles"
"github.com/kairos-io/kairos-sdk/collector" "github.com/kairos-io/kairos-sdk/collector"
@ -279,7 +278,7 @@ E.g. kairos-agent install-bundle container:quay.io/kairos/kairos...
Description: "Show the runtime configuration of the machine. It will scan the machine for all the configuration and will return the config file processed and found.", Description: "Show the runtime configuration of the machine. It will scan the machine for all the configuration and will return the config file processed and found.",
Aliases: []string{"s"}, Aliases: []string{"s"},
Action: func(c *cli.Context) error { Action: func(c *cli.Context) error {
config, err := config.Scan(collector.Directories(configScanDir...), collector.NoLogs) config, err := agentConfig.Scan(collector.Directories(configScanDir...), collector.NoLogs)
if err != nil { if err != nil {
return err return err
} }
@ -308,7 +307,7 @@ enabled: true`,
Description: "It allows to navigate the YAML config file by searching with 'yq' style keywords as `config get k3s` to retrieve the k3s config block", Description: "It allows to navigate the YAML config file by searching with 'yq' style keywords as `config get k3s` to retrieve the k3s config block",
Aliases: []string{"g"}, Aliases: []string{"g"},
Action: func(c *cli.Context) error { Action: func(c *cli.Context) error {
config, err := config.Scan(collector.Directories(configScanDir...), collector.NoLogs, collector.StrictValidation(c.Bool("strict-validation"))) config, err := agentConfig.Scan(collector.Directories(configScanDir...), collector.NoLogs, collector.StrictValidation(c.Bool("strict-validation")))
if err != nil { if err != nil {
return err return err
} }
@ -527,24 +526,20 @@ The validate command expects a configuration file as its only argument. Local fi
}, },
Action: func(c *cli.Context) error { Action: func(c *cli.Context) error {
stage := c.Args().First() stage := c.Args().First()
config, err := config.Scan(collector.Directories(configScanDir...), collector.NoLogs) config, err := agentConfig.Scan(collector.Directories(configScanDir...), collector.NoLogs)
if err != nil { config.Strict = c.Bool("strict")
return err
}
cfg, err := elementalConfig.ReadConfigRunFromAgentConfig(config)
cfg.Strict = c.Bool("strict")
if len(c.StringSlice("cloud-init-paths")) > 0 { if len(c.StringSlice("cloud-init-paths")) > 0 {
cfg.CloudInitPaths = append(cfg.CloudInitPaths, c.StringSlice("cloud-init-paths")...) config.CloudInitPaths = append(config.CloudInitPaths, c.StringSlice("cloud-init-paths")...)
} }
if c.Bool("debug") { if c.Bool("debug") {
cfg.Logger.SetLevel(logrus.DebugLevel) config.Logger.SetLevel(logrus.DebugLevel)
} }
if err != nil { if err != nil {
cfg.Logger.Errorf("Error reading config: %s\n", err) config.Logger.Errorf("Error reading config: %s\n", err)
} }
return utils.RunStage(cfg, stage) return utils.RunStage(config, stage)
}, },
}, },
{ {
@ -578,24 +573,16 @@ The validate command expects a configuration file as its only argument. Local fi
if err != nil { if err != nil {
return fmt.Errorf("invalid path %s", destination) return fmt.Errorf("invalid path %s", destination)
} }
config, err := config.Scan(collector.Directories(configScanDir...), collector.NoLogs) config, err := agentConfig.Scan(collector.Directories(configScanDir...), collector.NoLogs)
if err != nil { if err != nil {
return err return err
} }
cfg, err := elementalConfig.ReadConfigRunFromAgentConfig(config) config.Logger.Infof("Starting download and extraction for image %s to %s\n", image, destination)
if err != nil {
return err
}
if c.Bool("debug") {
cfg.Logger.SetLevel(logrus.DebugLevel)
}
cfg.Logger.Infof("Starting download and extraction for image %s to %s\n", image, destination)
e := v1.OCIImageExtractor{} e := v1.OCIImageExtractor{}
if err = e.ExtractImage(image, destination, c.String("platform")); err != nil { if err = e.ExtractImage(image, destination, c.String("platform")); err != nil {
return err return err
} }
cfg.Logger.Infof("Image %s downloaded and extracted to %s correctly\n", image, destination) config.Logger.Infof("Image %s downloaded and extracted to %s correctly\n", image, destination)
return nil return nil
}, },
}, },

View File

@ -17,13 +17,13 @@ limitations under the License.
package action package action
import ( import (
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" config "github.com/kairos-io/kairos-agent/v2/pkg/config"
"github.com/kairos-io/kairos-agent/v2/pkg/utils" "github.com/kairos-io/kairos-agent/v2/pkg/utils"
) )
// Hook is RunStage wrapper that only adds logic to ignore errors // Hook is RunStage wrapper that only adds logic to ignore errors
// in case v1.Config.Strict is set to false // in case v1.Config.Strict is set to false
func Hook(config *v1.Config, hook string) error { func Hook(config *config.Config, hook string) error {
config.Logger.Infof("Running %s hook", hook) config.Logger.Infof("Running %s hook", hook)
err := utils.RunStage(config, hook) err := utils.RunStage(config, hook)
if !config.Strict { if !config.Strict {
@ -33,7 +33,7 @@ func Hook(config *v1.Config, hook string) error {
} }
// ChrootHook executes Hook inside a chroot environment // ChrootHook executes Hook inside a chroot environment
func ChrootHook(config *v1.Config, hook string, chrootDir string, bindMounts map[string]string) (err error) { func ChrootHook(config *config.Config, hook string, chrootDir string, bindMounts map[string]string) (err error) {
callback := func() error { callback := func() error {
return Hook(config, hook) return Hook(config, hook)
} }

View File

@ -18,7 +18,9 @@ package action
import ( import (
"fmt" "fmt"
"github.com/kairos-io/kairos-agent/v2/pkg/config"
"path/filepath" "path/filepath"
"strings"
"time" "time"
cnst "github.com/kairos-io/kairos-agent/v2/pkg/constants" cnst "github.com/kairos-io/kairos-agent/v2/pkg/constants"
@ -107,11 +109,11 @@ func (i *InstallAction) createInstallStateYaml(sysMeta, recMeta interface{}) err
} }
type InstallAction struct { type InstallAction struct {
cfg *v1.Config cfg *config.Config
spec *v1.InstallSpec spec *v1.InstallSpec
} }
func NewInstallAction(cfg *v1.Config, spec *v1.InstallSpec) *InstallAction { func NewInstallAction(cfg *config.Config, spec *v1.InstallSpec) *InstallAction {
return &InstallAction{cfg: cfg, spec: spec} return &InstallAction{cfg: cfg, spec: spec}
} }
@ -259,7 +261,10 @@ func (i InstallAction) Run() (err error) {
} }
// If we want to eject the cd, create the required executable so the cd is ejected at shutdown // If we want to eject the cd, create the required executable so the cd is ejected at shutdown
if i.cfg.EjectCD && utils.BootedFrom(i.cfg.Runner, "cdroot") { out, _ := i.cfg.Runner.Run("cat", "/proc/cmdline")
bootedFromCD := strings.Contains(string(out), "cdroot")
if i.cfg.EjectCD && bootedFromCD {
i.cfg.Logger.Infof("Writing eject script") i.cfg.Logger.Infof("Writing eject script")
err = i.cfg.Fs.WriteFile("/usr/lib/systemd/system-shutdown/eject", []byte(cnst.EjectScript), 0744) err = i.cfg.Fs.WriteFile("/usr/lib/systemd/system-shutdown/eject", []byte(cnst.EjectScript), 0744)
if err != nil { if err != nil {

View File

@ -20,13 +20,14 @@ import (
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config"
"github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
"path/filepath" "path/filepath"
"regexp" "regexp"
"github.com/jaypipes/ghw/pkg/block" "github.com/jaypipes/ghw/pkg/block"
"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/constants" "github.com/kairos-io/kairos-agent/v2/pkg/constants"
conf "github.com/kairos-io/kairos-agent/v2/pkg/elementalConfig"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
"github.com/kairos-io/kairos-agent/v2/pkg/utils" "github.com/kairos-io/kairos-agent/v2/pkg/utils"
v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks" v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks"
@ -42,7 +43,7 @@ const partTmpl = `
%d:%ss:%ss:2048s:ext4::type=83;` %d:%ss:%ss:2048s:ext4::type=83;`
var _ = Describe("Install action tests", func() { var _ = Describe("Install action tests", func() {
var config *v1.Config var config *agentConfig.Config
var runner *v1mock.FakeRunner var runner *v1mock.FakeRunner
var fs vfs.FS var fs vfs.FS
var logger v1.Logger var logger v1.Logger
@ -69,15 +70,15 @@ var _ = Describe("Install action tests", func() {
Expect(err).Should(BeNil()) Expect(err).Should(BeNil())
cloudInit = &v1mock.FakeCloudInitRunner{} cloudInit = &v1mock.FakeCloudInitRunner{}
config = conf.NewConfig( config = agentConfig.NewConfig(
conf.WithFs(fs), agentConfig.WithFs(fs),
conf.WithRunner(runner), agentConfig.WithRunner(runner),
conf.WithLogger(logger), agentConfig.WithLogger(logger),
conf.WithMounter(mounter), agentConfig.WithMounter(mounter),
conf.WithSyscall(syscall), agentConfig.WithSyscall(syscall),
conf.WithClient(client), agentConfig.WithClient(client),
conf.WithCloudInitRunner(cloudInit), agentConfig.WithCloudInitRunner(cloudInit),
conf.WithImageExtractor(extractor), agentConfig.WithImageExtractor(extractor),
) )
}) })
@ -94,7 +95,7 @@ var _ = Describe("Install action tests", func() {
BeforeEach(func() { BeforeEach(func() {
device = "/some/device" device = "/some/device"
err = utils.MkdirAll(fs, filepath.Dir(device), constants.DirPerm) err = fsutils.MkdirAll(fs, filepath.Dir(device), constants.DirPerm)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
_, err = fs.Create(device) _, err = fs.Create(device)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
@ -143,14 +144,14 @@ var _ = Describe("Install action tests", func() {
} }
} }
// Need to create the IsoBaseTree, like if we are booting from iso // Need to create the IsoBaseTree, like if we are booting from iso
err = utils.MkdirAll(fs, constants.IsoBaseTree, constants.DirPerm) err = fsutils.MkdirAll(fs, constants.IsoBaseTree, constants.DirPerm)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
spec = conf.NewInstallSpec(config) spec = agentConfig.NewInstallSpec(config)
spec.Active.Size = 16 spec.Active.Size = 16
grubCfg := filepath.Join(spec.Active.MountPoint, constants.GrubConf) grubCfg := filepath.Join(spec.Active.MountPoint, constants.GrubConf)
err = utils.MkdirAll(fs, filepath.Dir(grubCfg), constants.DirPerm) err = fsutils.MkdirAll(fs, filepath.Dir(grubCfg), constants.DirPerm)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
_, err = fs.Create(grubCfg) _, err = fs.Create(grubCfg)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
@ -215,7 +216,7 @@ var _ = Describe("Install action tests", func() {
}) })
It("Sets the executable /run/cos/ejectcd so systemd can eject the cd on restart", func() { It("Sets the executable /run/cos/ejectcd so systemd can eject the cd on restart", func() {
_ = utils.MkdirAll(fs, "/usr/lib/systemd/system-shutdown", constants.DirPerm) _ = fsutils.MkdirAll(fs, "/usr/lib/systemd/system-shutdown", constants.DirPerm)
_, err := fs.Stat("/usr/lib/systemd/system-shutdown/eject") _, err := fs.Stat("/usr/lib/systemd/system-shutdown/eject")
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
// Override cmdline to return like we are booting from cd // Override cmdline to return like we are booting from cd
@ -233,7 +234,7 @@ var _ = Describe("Install action tests", func() {
}) })
It("ejectcd does nothing if we are not booting from cd", func() { It("ejectcd does nothing if we are not booting from cd", func() {
_ = utils.MkdirAll(fs, "/usr/lib/systemd/system-shutdown", constants.DirPerm) _ = fsutils.MkdirAll(fs, "/usr/lib/systemd/system-shutdown", constants.DirPerm)
_, err := fs.Stat("/usr/lib/systemd/system-shutdown/eject") _, err := fs.Stat("/usr/lib/systemd/system-shutdown/eject")
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
spec.Target = device spec.Target = device
@ -265,7 +266,7 @@ var _ = Describe("Install action tests", func() {
It("Successfully installs and adds remote cloud-config", Label("cloud-config"), func() { It("Successfully installs and adds remote cloud-config", Label("cloud-config"), func() {
spec.Target = device spec.Target = device
spec.CloudInit = []string{"http://my.config.org"} spec.CloudInit = []string{"http://my.config.org"}
utils.MkdirAll(fs, constants.OEMDir, constants.DirPerm) fsutils.MkdirAll(fs, constants.OEMDir, constants.DirPerm)
_, err := fs.Create(filepath.Join(constants.OEMDir, "90_custom.yaml")) _, err := fs.Create(filepath.Join(constants.OEMDir, "90_custom.yaml"))
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
Expect(installer.Run()).To(BeNil()) Expect(installer.Run()).To(BeNil())

View File

@ -18,6 +18,7 @@ package action
import ( import (
"fmt" "fmt"
agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config"
"path/filepath" "path/filepath"
"time" "time"
@ -44,11 +45,11 @@ func (r *ResetAction) resetHook(hook string, chroot bool) error {
} }
type ResetAction struct { type ResetAction struct {
cfg *v1.Config cfg *agentConfig.Config
spec *v1.ResetSpec spec *v1.ResetSpec
} }
func NewResetAction(cfg *v1.Config, spec *v1.ResetSpec) *ResetAction { func NewResetAction(cfg *agentConfig.Config, spec *v1.ResetSpec) *ResetAction {
return &ResetAction{cfg: cfg, spec: spec} return &ResetAction{cfg: cfg, spec: spec}
} }

View File

@ -20,13 +20,14 @@ import (
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config"
"github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
"path/filepath" "path/filepath"
"regexp" "regexp"
"github.com/jaypipes/ghw/pkg/block" "github.com/jaypipes/ghw/pkg/block"
"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/constants" "github.com/kairos-io/kairos-agent/v2/pkg/constants"
conf "github.com/kairos-io/kairos-agent/v2/pkg/elementalConfig"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
"github.com/kairos-io/kairos-agent/v2/pkg/utils" "github.com/kairos-io/kairos-agent/v2/pkg/utils"
v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks" v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks"
@ -37,7 +38,7 @@ import (
) )
var _ = Describe("Reset action tests", func() { var _ = Describe("Reset action tests", func() {
var config *v1.Config var config *agentConfig.Config
var runner *v1mock.FakeRunner var runner *v1mock.FakeRunner
var fs vfs.FS var fs vfs.FS
var logger v1.Logger var logger v1.Logger
@ -63,15 +64,15 @@ var _ = Describe("Reset action tests", func() {
Expect(err).Should(BeNil()) Expect(err).Should(BeNil())
cloudInit = &v1mock.FakeCloudInitRunner{} cloudInit = &v1mock.FakeCloudInitRunner{}
config = conf.NewConfig( config = agentConfig.NewConfig(
conf.WithFs(fs), agentConfig.WithFs(fs),
conf.WithRunner(runner), agentConfig.WithRunner(runner),
conf.WithLogger(logger), agentConfig.WithLogger(logger),
conf.WithMounter(mounter), agentConfig.WithMounter(mounter),
conf.WithSyscall(syscall), agentConfig.WithSyscall(syscall),
conf.WithClient(client), agentConfig.WithClient(client),
conf.WithCloudInitRunner(cloudInit), agentConfig.WithCloudInitRunner(cloudInit),
conf.WithImageExtractor(extractor), agentConfig.WithImageExtractor(extractor),
) )
}) })
@ -87,7 +88,7 @@ var _ = Describe("Reset action tests", func() {
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
cmdFail = "" cmdFail = ""
recoveryImg := filepath.Join(constants.RunningStateDir, "cOS", constants.RecoveryImgFile) recoveryImg := filepath.Join(constants.RunningStateDir, "cOS", constants.RecoveryImgFile)
err = utils.MkdirAll(fs, filepath.Dir(recoveryImg), constants.DirPerm) err = fsutils.MkdirAll(fs, filepath.Dir(recoveryImg), constants.DirPerm)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
_, err = fs.Create(recoveryImg) _, err = fs.Create(recoveryImg)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
@ -140,14 +141,14 @@ var _ = Describe("Reset action tests", func() {
} }
} }
spec, err = conf.NewResetSpec(config) spec, err = agentConfig.NewResetSpec(config)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
Expect(spec.Active.Source.IsEmpty()).To(BeFalse()) Expect(spec.Active.Source.IsEmpty()).To(BeFalse())
spec.Active.Size = 16 spec.Active.Size = 16
grubCfg := filepath.Join(spec.Active.MountPoint, spec.GrubConf) grubCfg := filepath.Join(spec.Active.MountPoint, spec.GrubConf)
err = utils.MkdirAll(fs, filepath.Dir(grubCfg), constants.DirPerm) err = fsutils.MkdirAll(fs, filepath.Dir(grubCfg), constants.DirPerm)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
_, err = fs.Create(grubCfg) _, err = fs.Create(grubCfg)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
@ -175,7 +176,7 @@ var _ = Describe("Reset action tests", func() {
Expect(reset.Run()).To(BeNil()) Expect(reset.Run()).To(BeNil())
}) })
It("Successfully resets from a squashfs recovery image", Label("channel"), func() { It("Successfully resets from a squashfs recovery image", Label("channel"), func() {
err := utils.MkdirAll(config.Fs, constants.IsoBaseTree, constants.DirPerm) err := fsutils.MkdirAll(config.Fs, constants.IsoBaseTree, constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
spec.Active.Source = v1.NewDirSrc(constants.IsoBaseTree) spec.Active.Source = v1.NewDirSrc(constants.IsoBaseTree)
Expect(reset.Run()).To(BeNil()) Expect(reset.Run()).To(BeNil())

View File

@ -18,6 +18,8 @@ package action
import ( import (
"fmt" "fmt"
agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config"
"github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
"path/filepath" "path/filepath"
"time" "time"
@ -29,11 +31,11 @@ import (
// UpgradeAction represents the struct that will run the upgrade from start to finish // UpgradeAction represents the struct that will run the upgrade from start to finish
type UpgradeAction struct { type UpgradeAction struct {
config *v1.Config config *agentConfig.Config
spec *v1.UpgradeSpec spec *v1.UpgradeSpec
} }
func NewUpgradeAction(config *v1.Config, spec *v1.UpgradeSpec) *UpgradeAction { func NewUpgradeAction(config *agentConfig.Config, spec *v1.UpgradeSpec) *UpgradeAction {
return &UpgradeAction{config: config, spec: spec} return &UpgradeAction{config: config, spec: spec}
} }
@ -154,7 +156,7 @@ func (u *UpgradeAction) Run() (err error) {
persistentPart := u.spec.Partitions.Persistent persistentPart := u.spec.Partitions.Persistent
if persistentPart != nil { if persistentPart != nil {
// Create the dir otherwise the check for mounted dir fails // Create the dir otherwise the check for mounted dir fails
_ = utils.MkdirAll(u.config.Fs, persistentPart.MountPoint, constants.DirPerm) _ = fsutils.MkdirAll(u.config.Fs, persistentPart.MountPoint, constants.DirPerm)
if mnt, err := utils.IsMounted(u.config, persistentPart); !mnt && err == nil { if mnt, err := utils.IsMounted(u.config, persistentPart); !mnt && err == nil {
u.Debug("mounting persistent partition") u.Debug("mounting persistent partition")
umount, err = e.MountRWPartition(persistentPart) umount, err = e.MountRWPartition(persistentPart)
@ -281,7 +283,7 @@ func (u *UpgradeAction) Run() (err error) {
// remove attempts to remove the given path. Does nothing if it doesn't exist // remove attempts to remove the given path. Does nothing if it doesn't exist
func (u *UpgradeAction) remove(path string) error { func (u *UpgradeAction) remove(path string) error {
if exists, _ := utils.Exists(u.config.Fs, path); exists { if exists, _ := fsutils.Exists(u.config.Fs, path); exists {
u.Debug("[Cleanup] Removing %s", path) u.Debug("[Cleanup] Removing %s", path)
return u.config.Fs.RemoveAll(path) return u.config.Fs.RemoveAll(path)
} }

View File

@ -19,14 +19,14 @@ package action_test
import ( import (
"bytes" "bytes"
"fmt" "fmt"
agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config"
"github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
"path/filepath" "path/filepath"
"github.com/jaypipes/ghw/pkg/block" "github.com/jaypipes/ghw/pkg/block"
"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/constants" "github.com/kairos-io/kairos-agent/v2/pkg/constants"
conf "github.com/kairos-io/kairos-agent/v2/pkg/elementalConfig"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
"github.com/kairos-io/kairos-agent/v2/pkg/utils"
v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks" v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks"
. "github.com/onsi/ginkgo/v2" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
@ -36,7 +36,7 @@ import (
) )
var _ = Describe("Runtime Actions", func() { var _ = Describe("Runtime Actions", func() {
var config *v1.Config var config *agentConfig.Config
var runner *v1mock.FakeRunner var runner *v1mock.FakeRunner
var fs vfs.FS var fs vfs.FS
var logger v1.Logger var logger v1.Logger
@ -63,16 +63,16 @@ var _ = Describe("Runtime Actions", func() {
Expect(err).Should(BeNil()) Expect(err).Should(BeNil())
cloudInit = &v1mock.FakeCloudInitRunner{} cloudInit = &v1mock.FakeCloudInitRunner{}
config = conf.NewConfig( config = agentConfig.NewConfig(
conf.WithFs(fs), agentConfig.WithFs(fs),
conf.WithRunner(runner), agentConfig.WithRunner(runner),
conf.WithLogger(logger), agentConfig.WithLogger(logger),
conf.WithMounter(mounter), agentConfig.WithMounter(mounter),
conf.WithSyscall(syscall), agentConfig.WithSyscall(syscall),
conf.WithClient(client), agentConfig.WithClient(client),
conf.WithCloudInitRunner(cloudInit), agentConfig.WithCloudInitRunner(cloudInit),
conf.WithImageExtractor(extractor), agentConfig.WithImageExtractor(extractor),
conf.WithPlatform("linux/amd64"), agentConfig.WithPlatform("linux/amd64"),
) )
}) })
@ -98,8 +98,8 @@ var _ = Describe("Runtime Actions", func() {
logger.SetLevel(logrus.DebugLevel) logger.SetLevel(logrus.DebugLevel)
// Create paths used by tests // Create paths used by tests
utils.MkdirAll(fs, fmt.Sprintf("%s/cOS", constants.RunningStateDir), constants.DirPerm) fsutils.MkdirAll(fs, fmt.Sprintf("%s/cOS", constants.RunningStateDir), constants.DirPerm)
utils.MkdirAll(fs, fmt.Sprintf("%s/cOS", constants.LiveDir), constants.DirPerm) fsutils.MkdirAll(fs, fmt.Sprintf("%s/cOS", constants.LiveDir), constants.DirPerm)
mainDisk := block.Disk{ mainDisk := block.Disk{
Name: "device", Name: "device",
@ -143,10 +143,10 @@ var _ = Describe("Runtime Actions", func() {
Describe(fmt.Sprintf("Booting from %s", constants.ActiveLabel), Label("active_label"), func() { Describe(fmt.Sprintf("Booting from %s", constants.ActiveLabel), Label("active_label"), func() {
var err error var err error
BeforeEach(func() { BeforeEach(func() {
spec, err = conf.NewUpgradeSpec(config) spec, err = agentConfig.NewUpgradeSpec(config)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
err = utils.MkdirAll(config.Fs, filepath.Join(spec.Active.MountPoint, "etc"), constants.DirPerm) err = fsutils.MkdirAll(config.Fs, filepath.Join(spec.Active.MountPoint, "etc"), constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
err = fs.WriteFile( err = fs.WriteFile(
@ -303,7 +303,7 @@ var _ = Describe("Runtime Actions", func() {
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
}) })
It("Successfully upgrades from directory", Label("directory"), func() { It("Successfully upgrades from directory", Label("directory"), func() {
dirSrc, _ := utils.TempDir(fs, "", "elementalupgrade") dirSrc, _ := fsutils.TempDir(fs, "", "elementalupgrade")
// Create the dir on real os as rsync works on the real os // Create the dir on real os as rsync works on the real os
defer fs.RemoveAll(dirSrc) defer fs.RemoveAll(dirSrc)
spec.Active.Source = v1.NewDirSrc(dirSrc) spec.Active.Source = v1.NewDirSrc(dirSrc)
@ -346,10 +346,10 @@ var _ = Describe("Runtime Actions", func() {
Describe(fmt.Sprintf("Booting from %s", constants.PassiveLabel), Label("passive_label"), func() { Describe(fmt.Sprintf("Booting from %s", constants.PassiveLabel), Label("passive_label"), func() {
var err error var err error
BeforeEach(func() { BeforeEach(func() {
spec, err = conf.NewUpgradeSpec(config) spec, err = agentConfig.NewUpgradeSpec(config)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
err = utils.MkdirAll(config.Fs, filepath.Join(spec.Active.MountPoint, "etc"), constants.DirPerm) err = fsutils.MkdirAll(config.Fs, filepath.Join(spec.Active.MountPoint, "etc"), constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
err = fs.WriteFile( err = fs.WriteFile(
@ -428,7 +428,7 @@ var _ = Describe("Runtime Actions", func() {
err = fs.WriteFile(recoveryImgSquash, []byte("recovery"), constants.FilePerm) err = fs.WriteFile(recoveryImgSquash, []byte("recovery"), constants.FilePerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
spec, err = conf.NewUpgradeSpec(config) spec, err = agentConfig.NewUpgradeSpec(config)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
spec.Active.Size = 10 spec.Active.Size = 10
spec.Passive.Size = 10 spec.Passive.Size = 10
@ -484,7 +484,7 @@ var _ = Describe("Runtime Actions", func() {
}) })
It("Successfully upgrades recovery from directory", Label("directory"), func() { It("Successfully upgrades recovery from directory", Label("directory"), func() {
srcDir, _ := utils.TempDir(fs, "", "elemental") srcDir, _ := fsutils.TempDir(fs, "", "elemental")
// create a random file on it // create a random file on it
_ = fs.WriteFile(fmt.Sprintf("%s/file.file", srcDir), []byte("something"), constants.FilePerm) _ = fs.WriteFile(fmt.Sprintf("%s/file.file", srcDir), []byte("something"), constants.FilePerm)
@ -513,7 +513,7 @@ var _ = Describe("Runtime Actions", func() {
err = fs.WriteFile(recoveryImg, []byte("recovery"), constants.FilePerm) err = fs.WriteFile(recoveryImg, []byte("recovery"), constants.FilePerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
spec, err = conf.NewUpgradeSpec(config) spec, err = agentConfig.NewUpgradeSpec(config)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
spec.Active.Size = 10 spec.Active.Size = 10
@ -569,7 +569,7 @@ var _ = Describe("Runtime Actions", func() {
} }
}) })
It("Successfully upgrades recovery from directory", Label("directory"), func() { It("Successfully upgrades recovery from directory", Label("directory"), func() {
srcDir, _ := utils.TempDir(fs, "", "elemental") srcDir, _ := fsutils.TempDir(fs, "", "elemental")
// create a random file on it // create a random file on it
_ = fs.WriteFile(fmt.Sprintf("%s/file.file", srcDir), []byte("something"), constants.FilePerm) _ = fs.WriteFile(fmt.Sprintf("%s/file.file", srcDir), []byte("something"), constants.FilePerm)

View File

@ -20,6 +20,7 @@ import (
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
"github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
"io/ioutil" "io/ioutil"
"log" "log"
"os" "os"
@ -29,7 +30,6 @@ import (
. "github.com/kairos-io/kairos-agent/v2/pkg/cloudinit" . "github.com/kairos-io/kairos-agent/v2/pkg/cloudinit"
"github.com/kairos-io/kairos-agent/v2/pkg/constants" "github.com/kairos-io/kairos-agent/v2/pkg/constants"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
"github.com/kairos-io/kairos-agent/v2/pkg/utils"
v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks" v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks"
"github.com/twpayne/go-vfs/vfst" "github.com/twpayne/go-vfs/vfst"
@ -110,9 +110,9 @@ stages:
logger = v1.NewBufferLogger(logs) logger = v1.NewBufferLogger(logs)
afs, cleanup, _ = vfst.NewTestFS(nil) afs, cleanup, _ = vfst.NewTestFS(nil)
err := utils.MkdirAll(afs, "/some/yip", constants.DirPerm) err := fsutils.MkdirAll(afs, "/some/yip", constants.DirPerm)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
_ = utils.MkdirAll(afs, "/dev", constants.DirPerm) _ = fsutils.MkdirAll(afs, "/dev", constants.DirPerm)
device = "/dev/device" device = "/dev/device"
_, err = afs.Create(device) _, err = afs.Create(device)
Expect(err).To(BeNil()) Expect(err).To(BeNil())

View File

@ -2,17 +2,24 @@ package config
import ( import (
"fmt" "fmt"
"github.com/spf13/viper"
"os" "os"
"path/filepath" "path/filepath"
"runtime"
"strings" "strings"
"unicode" "unicode"
"github.com/kairos-io/kairos-agent/v2/pkg/cloudinit"
"github.com/kairos-io/kairos-agent/v2/pkg/constants"
"github.com/kairos-io/kairos-agent/v2/pkg/http"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
"github.com/kairos-io/kairos-sdk/bundles" "github.com/kairos-io/kairos-sdk/bundles"
"github.com/kairos-io/kairos-sdk/collector" "github.com/kairos-io/kairos-sdk/collector"
"github.com/kairos-io/kairos-sdk/schema" "github.com/kairos-io/kairos-sdk/schema"
yip "github.com/mudler/yip/pkg/schema" yip "github.com/mudler/yip/pkg/schema"
"github.com/twpayne/go-vfs"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
"k8s.io/mount-utils"
) )
const ( const (
@ -36,6 +43,60 @@ type Install struct {
BindMounts []string `yaml:"bind_mounts,omitempty"` BindMounts []string `yaml:"bind_mounts,omitempty"`
} }
func NewConfig(opts ...GenericOptions) *Config {
log := v1.NewLogger()
hostPlatform, err := v1.NewPlatformFromArch(runtime.GOARCH)
if err != nil {
log.Errorf("error parsing default platform (%s): %s", runtime.GOARCH, err.Error())
return nil
}
arch, err := golangArchToArch(runtime.GOARCH)
if err != nil {
log.Errorf("invalid arch: %s", err.Error())
return nil
}
c := &Config{
Fs: vfs.OSFS,
Logger: log,
Syscall: &v1.RealSyscall{},
Client: http.NewClient(),
Arch: arch,
Platform: hostPlatform,
SquashFsCompressionConfig: constants.GetDefaultSquashfsCompressionOptions(),
ImageExtractor: v1.OCIImageExtractor{},
}
for _, o := range opts {
o(c)
}
// delay runner creation after we have run over the options in case we use WithRunner
if c.Runner == nil {
c.Runner = &v1.RealRunner{Logger: c.Logger}
}
// Now check if the runner has a logger inside, otherwise point our logger into it
// This can happen if we set the WithRunner option as that doesn't set a logger
if c.Runner.GetLogger() == nil {
c.Runner.SetLogger(c.Logger)
}
// Delay the yip runner creation, so we set the proper logger instead of blindly setting it to the logger we create
// at the start of NewConfig, as WithLogger can be passed on init, and that would result in 2 different logger
// instances, on the config.Logger and the other on config.CloudInitRunner
if c.CloudInitRunner == nil {
c.CloudInitRunner = cloudinit.NewYipCloudInitRunner(c.Logger, c.Runner, vfs.OSFS)
}
if c.Mounter == nil {
c.Mounter = mount.New(constants.MountBinary)
}
return c
}
type Config struct { type Config struct {
Install *Install `yaml:"install,omitempty"` Install *Install `yaml:"install,omitempty"`
collector.Config `yaml:"-"` collector.Config `yaml:"-"`
@ -46,6 +107,148 @@ type Config struct {
Bundles Bundles `yaml:"bundles,omitempty"` Bundles Bundles `yaml:"bundles,omitempty"`
GrubOptions map[string]string `yaml:"grub_options,omitempty"` GrubOptions map[string]string `yaml:"grub_options,omitempty"`
Env []string `yaml:"env,omitempty"` Env []string `yaml:"env,omitempty"`
// From elemental
Debug bool `yaml:"debug,omitempty" mapstructure:"debug"`
Strict bool `yaml:"strict,omitempty" mapstructure:"strict"`
CloudInitPaths []string `yaml:"cloud-init-paths,omitempty" mapstructure:"cloud-init-paths"`
EjectCD bool `yaml:"eject-cd,omitempty" mapstructure:"eject-cd"`
Logger v1.Logger
Fs v1.FS
Mounter mount.Interface
Runner v1.Runner
Syscall v1.SyscallInterface
CloudInitRunner v1.CloudInitRunner
ImageExtractor v1.ImageExtractor
Client v1.HTTPClient
Platform *v1.Platform `yaml:"platform,omitempty" mapstructure:"platform"`
Cosign bool `yaml:"cosign,omitempty" mapstructure:"cosign"`
Verify bool `yaml:"verify,omitempty" mapstructure:"verify"`
CosignPubKey string `yaml:"cosign-key,omitempty" mapstructure:"cosign-key"`
Arch string `yaml:"arch,omitempty" mapstructure:"arch"`
SquashFsCompressionConfig []string `yaml:"squash-compression,omitempty" mapstructure:"squash-compression"`
SquashFsNoCompression bool `yaml:"squash-no-compression,omitempty" mapstructure:"squash-no-compression"`
}
// WriteInstallState writes the state.yaml file to the given state and recovery paths
func (c Config) WriteInstallState(i *v1.InstallState, statePath, recoveryPath string) error {
data, err := yaml.Marshal(i)
if err != nil {
return err
}
data = append([]byte("# Autogenerated file by elemental client, do not edit\n\n"), data...)
err = c.Fs.WriteFile(statePath, data, constants.FilePerm)
if err != nil {
return err
}
err = c.Fs.WriteFile(recoveryPath, data, constants.FilePerm)
if err != nil {
return err
}
return nil
}
// LoadInstallState loads the state.yaml file and unmarshals it to an InstallState object
func (c Config) LoadInstallState() (*v1.InstallState, error) {
installState := &v1.InstallState{}
data, err := c.Fs.ReadFile(filepath.Join(constants.RunningStateDir, constants.InstallStateFile))
if err != nil {
return nil, err
}
err = yaml.Unmarshal(data, installState)
if err != nil {
return nil, err
}
return installState, nil
}
// Sanitize checks the consistency of the struct, returns error
// if unsolvable inconsistencies are found
func (c *Config) Sanitize() error {
// If no squashcompression is set, zero the compression parameters
// By default on NewConfig the SquashFsCompressionConfig is set to the default values, and then override
// on config unmarshall.
if c.SquashFsNoCompression {
c.SquashFsCompressionConfig = []string{}
}
if c.Arch != "" {
p, err := v1.NewPlatformFromArch(c.Arch)
if err != nil {
return err
}
c.Platform = p
}
if c.Platform == nil {
p, err := v1.NewPlatformFromArch(runtime.GOARCH)
if err != nil {
return err
}
c.Platform = p
}
return nil
}
type GenericOptions func(a *Config)
func WithFs(fs v1.FS) func(r *Config) {
return func(r *Config) {
r.Fs = fs
}
}
func WithLogger(logger v1.Logger) func(r *Config) {
return func(r *Config) {
r.Logger = logger
}
}
func WithSyscall(syscall v1.SyscallInterface) func(r *Config) {
return func(r *Config) {
r.Syscall = syscall
}
}
func WithMounter(mounter mount.Interface) func(r *Config) {
return func(r *Config) {
r.Mounter = mounter
}
}
func WithRunner(runner v1.Runner) func(r *Config) {
return func(r *Config) {
r.Runner = runner
}
}
func WithClient(client v1.HTTPClient) func(r *Config) {
return func(r *Config) {
r.Client = client
}
}
func WithCloudInitRunner(ci v1.CloudInitRunner) func(r *Config) {
return func(r *Config) {
r.CloudInitRunner = ci
}
}
func WithPlatform(platform string) func(r *Config) {
return func(r *Config) {
p, err := v1.ParsePlatform(platform)
if err == nil {
r.Platform = p
}
}
}
func WithImageExtractor(extractor v1.ImageExtractor) func(r *Config) {
return func(r *Config) {
r.ImageExtractor = extractor
}
} }
type Bundles []Bundle type Bundles []Bundle
@ -113,7 +316,8 @@ func FilterKeys(d []byte) ([]byte, error) {
} }
func Scan(opts ...collector.Option) (c *Config, err error) { func Scan(opts ...collector.Option) (c *Config, err error) {
result := &Config{} // Init new config with some default options
result := NewConfig()
o := &collector.Options{} o := &collector.Options{}
if err := o.Apply(opts...); err != nil { if err := o.Apply(opts...); err != nil {
@ -157,6 +361,13 @@ func Scan(opts ...collector.Option) (c *Config, err error) {
} }
} }
// If we got debug enabled via cloud config, set it on viper so its available everywhere
if result.Debug {
viper.Set("debug", true)
}
// Config the logger
configLogger(result.Logger, result.Fs)
return result, nil return result, nil
} }
@ -207,3 +418,16 @@ func MergeYAML(objs ...interface{}) ([]byte, error) {
func AddHeader(header, data string) string { func AddHeader(header, data string) string {
return fmt.Sprintf("%s\n%s", header, data) return fmt.Sprintf("%s\n%s", header, data)
} }
var errInvalidArch = fmt.Errorf("invalid arch")
func golangArchToArch(arch string) (string, error) {
switch strings.ToLower(arch) {
case constants.ArchAmd64:
return constants.Archx86, nil
case constants.ArchArm64:
return constants.ArchArm64, nil
default:
return "", errInvalidArch
}
}

View File

@ -17,36 +17,22 @@ package config_test
import ( import (
"fmt" "fmt"
"os" "github.com/kairos-io/kairos-agent/v2/pkg/constants"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
"github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
v1mocks "github.com/kairos-io/kairos-agent/v2/tests/mocks"
"github.com/twpayne/go-vfs"
"github.com/twpayne/go-vfs/vfst"
"path/filepath"
"reflect" "reflect"
"strings" "strings"
. "github.com/kairos-io/kairos-sdk/schema"
. "github.com/kairos-io/kairos-agent/v2/pkg/config" . "github.com/kairos-io/kairos-agent/v2/pkg/config"
. "github.com/kairos-io/kairos-sdk/schema"
. "github.com/onsi/ginkgo/v2" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
) )
type TConfig struct {
Kairos struct {
OtherKey string `yaml:"other_key"`
NetworkToken string `yaml:"network_token"`
} `yaml:"kairos"`
}
var _ = Describe("Config", func() {
var d string
BeforeEach(func() {
d, _ = os.MkdirTemp("", "xxxx")
})
AfterEach(func() {
if d != "" {
os.RemoveAll(d)
}
})
})
func getTagName(s string) string { func getTagName(s string) string {
if len(s) < 1 { if len(s) < 1 {
return "" return ""
@ -59,7 +45,12 @@ func getTagName(s string) string {
f := func(c rune) bool { f := func(c rune) bool {
return c == '"' || c == ',' return c == '"' || c == ','
} }
return s[:strings.IndexFunc(s, f)] index := strings.IndexFunc(s, f)
if index == -1 {
return s
}
return s[:index]
} }
func structContainsField(f, t string, str interface{}) bool { func structContainsField(f, t string, str interface{}) bool {
@ -118,4 +109,91 @@ var _ = Describe("Schema", func() {
structFieldsContainedInOtherStruct(Bundle{}, BundleSchema{}) structFieldsContainedInOtherStruct(Bundle{}, BundleSchema{})
}) })
}) })
Describe("Write and load installation state", func() {
var config *Config
var runner *v1mocks.FakeRunner
var fs vfs.FS
var mounter *v1mocks.ErrorMounter
var cleanup func()
var err error
var dockerState, channelState *v1.ImageState
var installState *v1.InstallState
var statePath, recoveryPath string
BeforeEach(func() {
runner = v1mocks.NewFakeRunner()
mounter = v1mocks.NewErrorMounter()
fs, cleanup, err = vfst.NewTestFS(map[string]interface{}{})
Expect(err).Should(BeNil())
config = NewConfig(
WithFs(fs),
WithRunner(runner),
WithMounter(mounter),
)
dockerState = &v1.ImageState{
Source: v1.NewDockerSrc("registry.org/my/image:tag"),
Label: "active_label",
FS: "ext2",
SourceMetadata: &v1.DockerImageMeta{
Digest: "adadgadg",
Size: 23452345,
},
}
installState = &v1.InstallState{
Date: "somedate",
Partitions: map[string]*v1.PartitionState{
"state": {
FSLabel: "state_label",
Images: map[string]*v1.ImageState{
"active": dockerState,
},
},
"recovery": {
FSLabel: "state_label",
Images: map[string]*v1.ImageState{
"recovery": channelState,
},
},
},
}
statePath = filepath.Join(constants.RunningStateDir, constants.InstallStateFile)
recoveryPath = "/recoverypart/state.yaml"
err = fsutils.MkdirAll(fs, filepath.Dir(recoveryPath), constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred())
err = fsutils.MkdirAll(fs, filepath.Dir(statePath), constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred())
})
AfterEach(func() {
cleanup()
})
It("Writes and loads an installation data", func() {
err = config.WriteInstallState(installState, statePath, recoveryPath)
Expect(err).ShouldNot(HaveOccurred())
loadedInstallState, err := config.LoadInstallState()
Expect(err).ShouldNot(HaveOccurred())
Expect(*loadedInstallState).To(Equal(*installState))
})
It("Fails writing to state partition", func() {
err = fs.RemoveAll(filepath.Dir(statePath))
Expect(err).ShouldNot(HaveOccurred())
err = config.WriteInstallState(installState, statePath, recoveryPath)
Expect(err).Should(HaveOccurred())
})
It("Fails writing to recovery partition", func() {
err = fs.RemoveAll(filepath.Dir(statePath))
Expect(err).ShouldNot(HaveOccurred())
err = config.WriteInstallState(installState, statePath, recoveryPath)
Expect(err).Should(HaveOccurred())
})
It("Fails loading state file", func() {
err = config.WriteInstallState(installState, statePath, recoveryPath)
Expect(err).ShouldNot(HaveOccurred())
err = fs.RemoveAll(filepath.Dir(statePath))
_, err = config.LoadInstallState()
Expect(err).Should(HaveOccurred())
})
})
}) })

View File

@ -14,156 +14,38 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package elementalConfig package config
import ( import (
"fmt" "fmt"
"gopkg.in/yaml.v3" "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
"github.com/kairos-io/kairos-agent/v2/pkg/utils/partitions"
"path/filepath" "path/filepath"
"reflect" "reflect"
"runtime"
"strings" "strings"
"github.com/kairos-io/kairos-agent/v2/internal/common" "github.com/kairos-io/kairos-agent/v2/internal/common"
"github.com/kairos-io/kairos-agent/v2/pkg/cloudinit"
agentConfig "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/constants"
"github.com/kairos-io/kairos-agent/v2/pkg/http"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
"github.com/kairos-io/kairos-agent/v2/pkg/utils"
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
"github.com/sanity-io/litter" "github.com/sanity-io/litter"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/spf13/viper" "github.com/spf13/viper"
"github.com/twpayne/go-vfs"
"k8s.io/mount-utils"
) )
type GenericOptions func(a *v1.Config)
func WithFs(fs v1.FS) func(r *v1.Config) {
return func(r *v1.Config) {
r.Fs = fs
}
}
func WithLogger(logger v1.Logger) func(r *v1.Config) {
return func(r *v1.Config) {
r.Logger = logger
}
}
func WithSyscall(syscall v1.SyscallInterface) func(r *v1.Config) {
return func(r *v1.Config) {
r.Syscall = syscall
}
}
func WithMounter(mounter mount.Interface) func(r *v1.Config) {
return func(r *v1.Config) {
r.Mounter = mounter
}
}
func WithRunner(runner v1.Runner) func(r *v1.Config) {
return func(r *v1.Config) {
r.Runner = runner
}
}
func WithClient(client v1.HTTPClient) func(r *v1.Config) {
return func(r *v1.Config) {
r.Client = client
}
}
func WithCloudInitRunner(ci v1.CloudInitRunner) func(r *v1.Config) {
return func(r *v1.Config) {
r.CloudInitRunner = ci
}
}
func WithPlatform(platform string) func(r *v1.Config) {
return func(r *v1.Config) {
p, err := v1.ParsePlatform(platform)
if err == nil {
r.Platform = p
}
}
}
func WithImageExtractor(extractor v1.ImageExtractor) func(r *v1.Config) {
return func(r *v1.Config) {
r.ImageExtractor = extractor
}
}
func NewConfig(opts ...GenericOptions) *v1.Config {
log := v1.NewLogger()
defaultPlatform, err := v1.NewPlatformFromArch(runtime.GOARCH)
if err != nil {
log.Errorf("error parsing default platform (%s): %s", runtime.GOARCH, err.Error())
return nil
}
arch, err := utils.GolangArchToArch(runtime.GOARCH)
if err != nil {
log.Errorf("invalid arch: %s", err.Error())
return nil
}
c := &v1.Config{
Fs: vfs.OSFS,
Logger: log,
Syscall: &v1.RealSyscall{},
Client: http.NewClient(),
Arch: arch,
Platform: defaultPlatform,
SquashFsCompressionConfig: constants.GetDefaultSquashfsCompressionOptions(),
}
for _, o := range opts {
o(c)
}
// delay runner creation after we have run over the options in case we use WithRunner
if c.Runner == nil {
c.Runner = &v1.RealRunner{Logger: c.Logger}
}
// Now check if the runner has a logger inside, otherwise point our logger into it
// This can happen if we set the WithRunner option as that doesn't set a logger
if c.Runner.GetLogger() == nil {
c.Runner.SetLogger(c.Logger)
}
// Delay the yip runner creation, so we set the proper logger instead of blindly setting it to the logger we create
// at the start of NewConfig, as WithLogger can be passed on init, and that would result in 2 different logger
// instances, on the config.Logger and the other on config.CloudInitRunner
if c.CloudInitRunner == nil {
c.CloudInitRunner = cloudinit.NewYipCloudInitRunner(c.Logger, c.Runner, vfs.OSFS)
}
if c.Mounter == nil {
c.Mounter = mount.New(constants.MountBinary)
}
return c
}
// NewInstallSpec returns an InstallSpec struct all based on defaults and basic host checks (e.g. EFI vs BIOS) // NewInstallSpec returns an InstallSpec struct all based on defaults and basic host checks (e.g. EFI vs BIOS)
func NewInstallSpec(cfg *v1.Config) *v1.InstallSpec { func NewInstallSpec(cfg *Config) *v1.InstallSpec {
var firmware string var firmware string
var recoveryImg, activeImg, passiveImg v1.Image var recoveryImg, activeImg, passiveImg v1.Image
recoveryImgFile := filepath.Join(constants.LiveDir, constants.RecoverySquashFile) recoveryImgFile := filepath.Join(constants.LiveDir, constants.RecoverySquashFile)
// Check if current host has EFI firmware // Check if current host has EFI firmware
efiExists, _ := utils.Exists(cfg.Fs, constants.EfiDevice) efiExists, _ := fsutils.Exists(cfg.Fs, constants.EfiDevice)
// Check the default ISO installation media is available // Check the default ISO installation media is available
isoRootExists, _ := utils.Exists(cfg.Fs, constants.IsoBaseTree) isoRootExists, _ := fsutils.Exists(cfg.Fs, constants.IsoBaseTree)
// Check the default ISO recovery installation media is available) // Check the default ISO recovery installation media is available)
recoveryExists, _ := utils.Exists(cfg.Fs, recoveryImgFile) recoveryExists, _ := fsutils.Exists(cfg.Fs, recoveryImgFile)
if efiExists { if efiExists {
firmware = v1.EFI firmware = v1.EFI
@ -206,7 +88,7 @@ func NewInstallSpec(cfg *v1.Config) *v1.InstallSpec {
return &v1.InstallSpec{ return &v1.InstallSpec{
Firmware: firmware, Firmware: firmware,
PartTable: v1.GPT, PartTable: v1.GPT,
Partitions: NewInstallElementalParitions(), Partitions: NewInstallElementalPartitions(),
GrubConf: constants.GrubConf, GrubConf: constants.GrubConf,
Tty: constants.DefaultTty, Tty: constants.DefaultTty,
Active: activeImg, Active: activeImg,
@ -215,9 +97,9 @@ func NewInstallSpec(cfg *v1.Config) *v1.InstallSpec {
} }
} }
func NewInstallElementalParitions() v1.ElementalPartitions { func NewInstallElementalPartitions() v1.ElementalPartitions {
partitions := v1.ElementalPartitions{} pt := v1.ElementalPartitions{}
partitions.OEM = &v1.Partition{ pt.OEM = &v1.Partition{
FilesystemLabel: constants.OEMLabel, FilesystemLabel: constants.OEMLabel,
Size: constants.OEMSize, Size: constants.OEMSize,
Name: constants.OEMPartName, Name: constants.OEMPartName,
@ -226,7 +108,7 @@ func NewInstallElementalParitions() v1.ElementalPartitions {
Flags: []string{}, Flags: []string{},
} }
partitions.Recovery = &v1.Partition{ pt.Recovery = &v1.Partition{
FilesystemLabel: constants.RecoveryLabel, FilesystemLabel: constants.RecoveryLabel,
Size: constants.RecoverySize, Size: constants.RecoverySize,
Name: constants.RecoveryPartName, Name: constants.RecoveryPartName,
@ -235,7 +117,7 @@ func NewInstallElementalParitions() v1.ElementalPartitions {
Flags: []string{}, Flags: []string{},
} }
partitions.State = &v1.Partition{ pt.State = &v1.Partition{
FilesystemLabel: constants.StateLabel, FilesystemLabel: constants.StateLabel,
Size: constants.StateSize, Size: constants.StateSize,
Name: constants.StatePartName, Name: constants.StatePartName,
@ -244,7 +126,7 @@ func NewInstallElementalParitions() v1.ElementalPartitions {
Flags: []string{}, Flags: []string{},
} }
partitions.Persistent = &v1.Partition{ pt.Persistent = &v1.Partition{
FilesystemLabel: constants.PersistentLabel, FilesystemLabel: constants.PersistentLabel,
Size: constants.PersistentSize, Size: constants.PersistentSize,
Name: constants.PersistentPartName, Name: constants.PersistentPartName,
@ -252,11 +134,11 @@ func NewInstallElementalParitions() v1.ElementalPartitions {
MountPoint: constants.PersistentDir, MountPoint: constants.PersistentDir,
Flags: []string{}, Flags: []string{},
} }
return partitions return pt
} }
// NewUpgradeSpec returns an UpgradeSpec struct all based on defaults and current host state // NewUpgradeSpec returns an UpgradeSpec struct all based on defaults and current host state
func NewUpgradeSpec(cfg *v1.Config) (*v1.UpgradeSpec, error) { func NewUpgradeSpec(cfg *Config) (*v1.UpgradeSpec, error) {
var recLabel, recFs, recMnt string var recLabel, recFs, recMnt string
var active, passive, recovery v1.Image var active, passive, recovery v1.Image
@ -265,7 +147,7 @@ func NewUpgradeSpec(cfg *v1.Config) (*v1.UpgradeSpec, error) {
cfg.Logger.Warnf("failed reading installation state: %s", err.Error()) cfg.Logger.Warnf("failed reading installation state: %s", err.Error())
} }
parts, err := utils.GetAllPartitions() parts, err := partitions.GetAllPartitions()
if err != nil { if err != nil {
return nil, fmt.Errorf("could not read host partitions") return nil, fmt.Errorf("could not read host partitions")
} }
@ -273,17 +155,17 @@ func NewUpgradeSpec(cfg *v1.Config) (*v1.UpgradeSpec, error) {
if ep.Recovery == nil { if ep.Recovery == nil {
// We could have recovery in lvm which won't appear in ghw list // We could have recovery in lvm which won't appear in ghw list
ep.Recovery = utils.GetPartitionViaDM(cfg.Fs, constants.RecoveryLabel) ep.Recovery = partitions.GetPartitionViaDM(cfg.Fs, constants.RecoveryLabel)
} }
if ep.OEM == nil { if ep.OEM == nil {
// We could have OEM in lvm which won't appear in ghw list // We could have OEM in lvm which won't appear in ghw list
ep.OEM = utils.GetPartitionViaDM(cfg.Fs, constants.OEMLabel) ep.OEM = partitions.GetPartitionViaDM(cfg.Fs, constants.OEMLabel)
} }
if ep.Persistent == nil { if ep.Persistent == nil {
// We could have persistent encrypted or in lvm which won't appear in ghw list // We could have persistent encrypted or in lvm which won't appear in ghw list
ep.Persistent = utils.GetPartitionViaDM(cfg.Fs, constants.PersistentLabel) ep.Persistent = partitions.GetPartitionViaDM(cfg.Fs, constants.PersistentLabel)
} }
if ep.Recovery != nil { if ep.Recovery != nil {
@ -291,7 +173,7 @@ func NewUpgradeSpec(cfg *v1.Config) (*v1.UpgradeSpec, error) {
ep.Recovery.MountPoint = constants.RecoveryDir ep.Recovery.MountPoint = constants.RecoveryDir
} }
squashedRec, err := utils.HasSquashedRecovery(cfg, ep.Recovery) squashedRec, err := hasSquashedRecovery(cfg, ep.Recovery)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed checking for squashed recovery") return nil, fmt.Errorf("failed checking for squashed recovery")
} }
@ -361,23 +243,23 @@ func NewUpgradeSpec(cfg *v1.Config) (*v1.UpgradeSpec, error) {
} }
// NewResetSpec returns a ResetSpec struct all based on defaults and current host state // NewResetSpec returns a ResetSpec struct all based on defaults and current host state
func NewResetSpec(cfg *v1.Config) (*v1.ResetSpec, error) { func NewResetSpec(cfg *Config) (*v1.ResetSpec, error) {
var imgSource *v1.ImageSource var imgSource *v1.ImageSource
//TODO find a way to pre-load current state values such as labels //TODO find a way to pre-load current state values such as labels
if !utils.BootedFrom(cfg.Runner, constants.RecoverySquashFile) && if !BootedFrom(cfg.Runner, constants.RecoverySquashFile) &&
!utils.BootedFrom(cfg.Runner, constants.SystemLabel) { !BootedFrom(cfg.Runner, constants.SystemLabel) {
return nil, fmt.Errorf("reset can only be called from the recovery system") return nil, fmt.Errorf("reset can only be called from the recovery system")
} }
efiExists, _ := utils.Exists(cfg.Fs, constants.EfiDevice) efiExists, _ := fsutils.Exists(cfg.Fs, constants.EfiDevice)
installState, err := cfg.LoadInstallState() installState, err := cfg.LoadInstallState()
if err != nil { if err != nil {
cfg.Logger.Warnf("failed reading installation state: %s", err.Error()) cfg.Logger.Warnf("failed reading installation state: %s", err.Error())
} }
parts, err := utils.GetAllPartitions() parts, err := partitions.GetAllPartitions()
if err != nil { if err != nil {
return nil, fmt.Errorf("could not read host partitions") return nil, fmt.Errorf("could not read host partitions")
} }
@ -403,7 +285,7 @@ func NewResetSpec(cfg *v1.Config) (*v1.ResetSpec, error) {
if ep.Recovery == nil { if ep.Recovery == nil {
// We could have recovery in lvm which won't appear in ghw list // We could have recovery in lvm which won't appear in ghw list
ep.Recovery = utils.GetPartitionViaDM(cfg.Fs, constants.RecoveryLabel) ep.Recovery = partitions.GetPartitionViaDM(cfg.Fs, constants.RecoveryLabel)
if ep.Recovery == nil { if ep.Recovery == nil {
return nil, fmt.Errorf("recovery partition not found") return nil, fmt.Errorf("recovery partition not found")
} }
@ -422,7 +304,7 @@ func NewResetSpec(cfg *v1.Config) (*v1.ResetSpec, error) {
ep.OEM.Name = constants.OEMPartName ep.OEM.Name = constants.OEMPartName
} else { } else {
// We could have oem in lvm which won't appear in ghw list // We could have oem in lvm which won't appear in ghw list
ep.OEM = utils.GetPartitionViaDM(cfg.Fs, constants.OEMLabel) ep.OEM = partitions.GetPartitionViaDM(cfg.Fs, constants.OEMLabel)
} }
if ep.OEM == nil { if ep.OEM == nil {
@ -437,7 +319,7 @@ func NewResetSpec(cfg *v1.Config) (*v1.ResetSpec, error) {
ep.Persistent.Name = constants.PersistentPartName ep.Persistent.Name = constants.PersistentPartName
} else { } else {
// We could have persistent encrypted or in lvm which won't appear in ghw list // We could have persistent encrypted or in lvm which won't appear in ghw list
ep.Persistent = utils.GetPartitionViaDM(cfg.Fs, constants.PersistentLabel) ep.Persistent = partitions.GetPartitionViaDM(cfg.Fs, constants.PersistentLabel)
} }
if ep.Persistent == nil { if ep.Persistent == nil {
cfg.Logger.Warnf("no Persistent partition found") cfg.Logger.Warnf("no Persistent partition found")
@ -446,11 +328,11 @@ func NewResetSpec(cfg *v1.Config) (*v1.ResetSpec, error) {
recoveryImg := filepath.Join(constants.RunningStateDir, "cOS", constants.RecoveryImgFile) recoveryImg := filepath.Join(constants.RunningStateDir, "cOS", constants.RecoveryImgFile)
recoveryImg2 := filepath.Join(constants.RunningRecoveryStateDir, "cOS", constants.RecoveryImgFile) recoveryImg2 := filepath.Join(constants.RunningRecoveryStateDir, "cOS", constants.RecoveryImgFile)
if exists, _ := utils.Exists(cfg.Fs, recoveryImg); exists { if exists, _ := fsutils.Exists(cfg.Fs, recoveryImg); exists {
imgSource = v1.NewFileSrc(recoveryImg) imgSource = v1.NewFileSrc(recoveryImg)
} else if exists, _ = utils.Exists(cfg.Fs, recoveryImg2); exists { } else if exists, _ = fsutils.Exists(cfg.Fs, recoveryImg2); exists {
imgSource = v1.NewFileSrc(recoveryImg2) imgSource = v1.NewFileSrc(recoveryImg2)
} else if exists, _ = utils.Exists(cfg.Fs, constants.IsoBaseTree); exists { } else if exists, _ = fsutils.Exists(cfg.Fs, constants.IsoBaseTree); exists {
imgSource = v1.NewDirSrc(constants.IsoBaseTree) imgSource = v1.NewDirSrc(constants.IsoBaseTree)
} else { } else {
imgSource = v1.NewEmptySrc() imgSource = v1.NewEmptySrc()
@ -484,35 +366,38 @@ func NewResetSpec(cfg *v1.Config) (*v1.ResetSpec, error) {
}, nil }, nil
} }
// ReadConfigRunFromAgentConfig reads the configuration directly from a given cloud config string // ReadResetSpecFromConfig will return a proper v1.ResetSpec based on an agent Config
func ReadConfigRunFromAgentConfig(c *agentConfig.Config) (*v1.Config, error) { func ReadResetSpecFromConfig(c *Config) (*v1.ResetSpec, error) {
cfg := NewConfig(WithLogger(v1.NewLogger()), WithImageExtractor(v1.OCIImageExtractor{})) sp, err := ReadSpecFromCloudConfig(c, "reset")
var err error
ccString, err := c.Config.String()
if err != nil { if err != nil {
return nil, err return &v1.ResetSpec{}, err
} }
resetSpec := sp.(*v1.ResetSpec)
return resetSpec, nil
}
// Load any cloud-config values that override our default Config // ReadInstallSpecFromConfig will return a proper v1.InstallSpec based on an agent Config
err = yaml.Unmarshal([]byte(ccString), &cfg) func ReadInstallSpecFromConfig(c *Config) (*v1.InstallSpec, error) {
sp, err := ReadSpecFromCloudConfig(c, "install")
if err != nil { if err != nil {
return nil, err return &v1.InstallSpec{}, err
} }
// If we got debug enabled via cloud config, set it on viper so its available everywhere installSpec := sp.(*v1.InstallSpec)
if cfg.Debug { return installSpec, nil
viper.Set("debug", true) }
// ReadUpgradeSpecFromConfig will return a proper v1.UpgradeSpec based on an agent Config
func ReadUpgradeSpecFromConfig(c *Config) (*v1.UpgradeSpec, error) {
sp, err := ReadSpecFromCloudConfig(c, "reset")
if err != nil {
return &v1.UpgradeSpec{}, err
} }
configLogger(cfg.Logger, cfg.Fs) upgradeSpec := sp.(*v1.UpgradeSpec)
// Store the full cloud-config in here, so we can reuse it afterward for the spec return upgradeSpec, nil
cfg.FullCloudConfig = ccString
err = cfg.Sanitize()
cfg.Logger.Debugf("Full config loaded: %s", litter.Sdump(cfg))
return cfg, err
} }
// ReadSpecFromCloudConfig returns a v1.Spec for the given spec // ReadSpecFromCloudConfig returns a v1.Spec for the given spec
func ReadSpecFromCloudConfig(r *v1.Config, spec string) (v1.Spec, error) { func ReadSpecFromCloudConfig(r *Config, spec string) (v1.Spec, error) {
var sp v1.Spec var sp v1.Spec
var err error var err error
@ -531,8 +416,12 @@ func ReadSpecFromCloudConfig(r *v1.Config, spec string) (v1.Spec, error) {
} }
// Load the config into viper from the raw cloud config string // Load the config into viper from the raw cloud config string
ccString, err := r.String()
if err != nil {
return nil, fmt.Errorf("failed initializing spec: %v", err)
}
viper.SetConfigType("yaml") viper.SetConfigType("yaml")
viper.ReadConfig(strings.NewReader(r.FullCloudConfig)) viper.ReadConfig(strings.NewReader(ccString))
vp := viper.Sub(spec) vp := viper.Sub(spec)
if vp == nil { if vp == nil {
vp = viper.New() vp = viper.New()
@ -546,47 +435,6 @@ func ReadSpecFromCloudConfig(r *v1.Config, spec string) (v1.Spec, error) {
return sp, err return sp, err
} }
// readConfigAndSpecFromAgentConfig will return the config and spec for the given action based off the agent Config
func readConfigAndSpecFromAgentConfig(c *agentConfig.Config, action string) (*v1.Config, v1.Spec, error) {
config, err := ReadConfigRunFromAgentConfig(c)
if err != nil {
return nil, nil, err
}
spec, err := ReadSpecFromCloudConfig(config, action)
if err != nil {
return nil, nil, err
}
return config, spec, nil
}
// ReadResetConfigFromAgentConfig will return a proper v1.Config and v1.ResetSpec based on an agent Config
func ReadResetConfigFromAgentConfig(c *agentConfig.Config) (*v1.Config, *v1.ResetSpec, error) {
config, spec, err := readConfigAndSpecFromAgentConfig(c, "reset")
if err != nil {
return nil, nil, err
}
resetSpec := spec.(*v1.ResetSpec)
return config, resetSpec, nil
}
func ReadInstallConfigFromAgentConfig(c *agentConfig.Config) (*v1.Config, *v1.InstallSpec, error) {
config, spec, err := readConfigAndSpecFromAgentConfig(c, "install")
if err != nil {
return nil, nil, err
}
installSpec := spec.(*v1.InstallSpec)
return config, installSpec, nil
}
func ReadUpgradeConfigFromAgentConfig(c *agentConfig.Config) (*v1.Config, *v1.UpgradeSpec, error) {
config, spec, err := readConfigAndSpecFromAgentConfig(c, "upgrade")
if err != nil {
return nil, nil, err
}
upgradeSpec := spec.(*v1.UpgradeSpec)
return config, upgradeSpec, nil
}
func configLogger(log v1.Logger, vfs v1.FS) { func configLogger(log v1.Logger, vfs v1.FS) {
// Set debug level // Set debug level
if viper.GetBool("debug") { if viper.GetBool("debug") {
@ -676,3 +524,52 @@ func setDecoder(config *mapstructure.DecoderConfig) {
// we got form configs. // we got form configs.
config.ZeroFields = true config.ZeroFields = true
} }
// BootedFrom will check if we are booting from the given label
func BootedFrom(runner v1.Runner, label string) bool {
out, _ := runner.Run("cat", "/proc/cmdline")
return strings.Contains(string(out), label)
}
// HasSquashedRecovery returns true if a squashed recovery image is found in the system
func hasSquashedRecovery(config *Config, recovery *v1.Partition) (squashed bool, err error) {
mountPoint := recovery.MountPoint
if mnt, _ := isMounted(config, recovery); !mnt {
tmpMountDir, err := fsutils.TempDir(config.Fs, "", "elemental")
if err != nil {
config.Logger.Errorf("failed creating temporary dir: %v", err)
return false, err
}
defer config.Fs.RemoveAll(tmpMountDir) // nolint:errcheck
err = config.Mounter.Mount(recovery.Path, tmpMountDir, "auto", []string{})
if err != nil {
config.Logger.Errorf("failed mounting recovery partition: %v", err)
return false, err
}
mountPoint = tmpMountDir
defer func() {
err = config.Mounter.Unmount(tmpMountDir)
if err != nil {
squashed = false
}
}()
}
return fsutils.Exists(config.Fs, filepath.Join(mountPoint, "cOS", constants.RecoverySquashFile))
}
func isMounted(config *Config, part *v1.Partition) (bool, error) {
if part == nil {
return false, fmt.Errorf("nil partition")
}
if part.MountPoint == "" {
return false, nil
}
// Using IsLikelyNotMountPoint seams to be safe as we are not checking
// for bind mounts here
notMnt, err := config.Mounter.IsLikelyNotMountPoint(part.MountPoint)
if err != nil {
return false, err
}
return !notMnt, nil
}

View File

@ -14,11 +14,14 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package elementalConfig_test package config_test
import ( import (
"github.com/kairos-io/kairos-agent/v2/pkg/config" "fmt"
config "github.com/kairos-io/kairos-agent/v2/pkg/config"
"github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
"github.com/kairos-io/kairos-sdk/collector" "github.com/kairos-io/kairos-sdk/collector"
"github.com/sanity-io/litter"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"k8s.io/mount-utils" "k8s.io/mount-utils"
"os" "os"
@ -26,9 +29,7 @@ import (
"github.com/jaypipes/ghw/pkg/block" "github.com/jaypipes/ghw/pkg/block"
"github.com/kairos-io/kairos-agent/v2/pkg/constants" "github.com/kairos-io/kairos-agent/v2/pkg/constants"
"github.com/kairos-io/kairos-agent/v2/pkg/elementalConfig"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
"github.com/kairos-io/kairos-agent/v2/pkg/utils"
v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks" v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks"
. "github.com/onsi/ginkgo/v2" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
@ -46,7 +47,7 @@ var _ = Describe("Types", Label("types", "config"), func() {
var sysc *v1mock.FakeSyscall var sysc *v1mock.FakeSyscall
var logger v1.Logger var logger v1.Logger
var ci *v1mock.FakeCloudInitRunner var ci *v1mock.FakeCloudInitRunner
var c *v1.Config var c *config.Config
BeforeEach(func() { BeforeEach(func() {
fs, cleanup, err = vfst.NewTestFS(nil) fs, cleanup, err = vfst.NewTestFS(nil)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
@ -56,15 +57,15 @@ var _ = Describe("Types", Label("types", "config"), func() {
sysc = &v1mock.FakeSyscall{} sysc = &v1mock.FakeSyscall{}
logger = v1.NewNullLogger() logger = v1.NewNullLogger()
ci = &v1mock.FakeCloudInitRunner{} ci = &v1mock.FakeCloudInitRunner{}
c = elementalConfig.NewConfig( c = config.NewConfig(
elementalConfig.WithFs(fs), config.WithFs(fs),
elementalConfig.WithMounter(mounter), config.WithMounter(mounter),
elementalConfig.WithRunner(runner), config.WithRunner(runner),
elementalConfig.WithSyscall(sysc), config.WithSyscall(sysc),
elementalConfig.WithLogger(logger), config.WithLogger(logger),
elementalConfig.WithCloudInitRunner(ci), config.WithCloudInitRunner(ci),
elementalConfig.WithClient(client), config.WithClient(client),
elementalConfig.WithPlatform("linux/arm64"), config.WithPlatform("linux/arm64"),
) )
}) })
AfterEach(func() { AfterEach(func() {
@ -87,24 +88,24 @@ var _ = Describe("Types", Label("types", "config"), func() {
fs, cleanup, err := vfst.NewTestFS(nil) fs, cleanup, err := vfst.NewTestFS(nil)
defer cleanup() defer cleanup()
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
c := elementalConfig.NewConfig( c := config.NewConfig(
elementalConfig.WithFs(fs), config.WithFs(fs),
elementalConfig.WithMounter(mounter), config.WithMounter(mounter),
) )
Expect(c.Fs).To(Equal(fs)) Expect(c.Fs).To(Equal(fs))
Expect(c.Mounter).To(Equal(mounter)) Expect(c.Mounter).To(Equal(mounter))
Expect(c.Runner).ToNot(BeNil()) Expect(c.Runner).ToNot(BeNil())
}) })
It("defaults to sane platform if the platform is broken", func() { It("defaults to sane platform if the platform is broken", func() {
c = elementalConfig.NewConfig( c = config.NewConfig(
elementalConfig.WithFs(fs), config.WithFs(fs),
elementalConfig.WithMounter(mounter), config.WithMounter(mounter),
elementalConfig.WithRunner(runner), config.WithRunner(runner),
elementalConfig.WithSyscall(sysc), config.WithSyscall(sysc),
elementalConfig.WithLogger(logger), config.WithLogger(logger),
elementalConfig.WithCloudInitRunner(ci), config.WithCloudInitRunner(ci),
elementalConfig.WithClient(client), config.WithClient(client),
elementalConfig.WithPlatform("wwwwwww"), config.WithPlatform("wwwwwww"),
) )
Expect(c.Platform.OS).To(Equal("linux")) Expect(c.Platform.OS).To(Equal("linux"))
Expect(c.Platform.Arch).To(Equal("x86_64")) Expect(c.Platform.Arch).To(Equal("x86_64"))
@ -116,41 +117,41 @@ var _ = Describe("Types", Label("types", "config"), func() {
runner := v1mock.NewFakeRunner() runner := v1mock.NewFakeRunner()
sysc := &v1mock.FakeSyscall{} sysc := &v1mock.FakeSyscall{}
logger := v1.NewNullLogger() logger := v1.NewNullLogger()
c := elementalConfig.NewConfig( c := config.NewConfig(
elementalConfig.WithRunner(runner), config.WithRunner(runner),
elementalConfig.WithSyscall(sysc), config.WithSyscall(sysc),
elementalConfig.WithLogger(logger), config.WithLogger(logger),
) )
Expect(c.Mounter).To(Equal(mount.New(constants.MountBinary))) Expect(c.Mounter).To(Equal(mount.New(constants.MountBinary)))
}) })
}) })
Describe("Config", func() { Describe("Config", func() {
cfg := elementalConfig.NewConfig(elementalConfig.WithMounter(mounter)) cfg := config.NewConfig(config.WithMounter(mounter))
Expect(cfg.Mounter).To(Equal(mounter)) Expect(cfg.Mounter).To(Equal(mounter))
Expect(cfg.Runner).NotTo(BeNil()) Expect(cfg.Runner).NotTo(BeNil())
}) })
Describe("InstallSpec", func() { Describe("InstallSpec", func() {
It("sets installation defaults from install efi media with recovery", Label("install", "efi"), func() { It("sets installation defaults from install efi media with recovery", Label("install", "efi"), func() {
// Set EFI firmware detection // Set EFI firmware detection
err = utils.MkdirAll(fs, filepath.Dir(constants.EfiDevice), constants.DirPerm) err = fsutils.MkdirAll(fs, filepath.Dir(constants.EfiDevice), constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
_, err = fs.Create(constants.EfiDevice) _, err = fs.Create(constants.EfiDevice)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
// Set ISO base tree detection // Set ISO base tree detection
err = utils.MkdirAll(fs, filepath.Dir(constants.IsoBaseTree), constants.DirPerm) err = fsutils.MkdirAll(fs, filepath.Dir(constants.IsoBaseTree), constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
_, err = fs.Create(constants.IsoBaseTree) _, err = fs.Create(constants.IsoBaseTree)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
// Set recovery image detection detection // Set recovery image detection detection
recoveryImgFile := filepath.Join(constants.LiveDir, constants.RecoverySquashFile) recoveryImgFile := filepath.Join(constants.LiveDir, constants.RecoverySquashFile)
err = utils.MkdirAll(fs, filepath.Dir(recoveryImgFile), constants.DirPerm) err = fsutils.MkdirAll(fs, filepath.Dir(recoveryImgFile), constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
_, err = fs.Create(recoveryImgFile) _, err = fs.Create(recoveryImgFile)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
spec := elementalConfig.NewInstallSpec(c) spec := config.NewInstallSpec(c)
Expect(spec.Firmware).To(Equal(v1.EFI)) Expect(spec.Firmware).To(Equal(v1.EFI))
Expect(spec.Active.Source.Value()).To(Equal(constants.IsoBaseTree)) Expect(spec.Active.Source.Value()).To(Equal(constants.IsoBaseTree))
Expect(spec.Recovery.Source.Value()).To(Equal(recoveryImgFile)) Expect(spec.Recovery.Source.Value()).To(Equal(recoveryImgFile))
@ -166,12 +167,12 @@ var _ = Describe("Types", Label("types", "config"), func() {
}) })
It("sets installation defaults from install bios media without recovery", Label("install", "bios"), func() { It("sets installation defaults from install bios media without recovery", Label("install", "bios"), func() {
// Set ISO base tree detection // Set ISO base tree detection
err = utils.MkdirAll(fs, filepath.Dir(constants.IsoBaseTree), constants.DirPerm) err = fsutils.MkdirAll(fs, filepath.Dir(constants.IsoBaseTree), constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
_, err = fs.Create(constants.IsoBaseTree) _, err = fs.Create(constants.IsoBaseTree)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
spec := elementalConfig.NewInstallSpec(c) spec := config.NewInstallSpec(c)
Expect(spec.Firmware).To(Equal(v1.BIOS)) Expect(spec.Firmware).To(Equal(v1.BIOS))
Expect(spec.Active.Source.Value()).To(Equal(constants.IsoBaseTree)) Expect(spec.Active.Source.Value()).To(Equal(constants.IsoBaseTree))
Expect(spec.Recovery.Source.Value()).To(Equal(spec.Active.File)) Expect(spec.Recovery.Source.Value()).To(Equal(spec.Active.File))
@ -186,7 +187,7 @@ var _ = Describe("Types", Label("types", "config"), func() {
Expect(spec.Partitions.BIOS).NotTo(BeNil()) Expect(spec.Partitions.BIOS).NotTo(BeNil())
}) })
It("sets installation defaults without being on installation media", Label("install"), func() { It("sets installation defaults without being on installation media", Label("install"), func() {
spec := elementalConfig.NewInstallSpec(c) spec := config.NewInstallSpec(c)
Expect(spec.Firmware).To(Equal(v1.BIOS)) Expect(spec.Firmware).To(Equal(v1.BIOS))
Expect(spec.Active.Source.IsEmpty()).To(BeTrue()) Expect(spec.Active.Source.IsEmpty()).To(BeTrue())
Expect(spec.Recovery.Source.Value()).To(Equal(spec.Active.File)) Expect(spec.Recovery.Source.Value()).To(Equal(spec.Active.File))
@ -245,18 +246,18 @@ var _ = Describe("Types", Label("types", "config"), func() {
}) })
It("sets reset defaults on efi from squashed recovery", func() { It("sets reset defaults on efi from squashed recovery", func() {
// Set EFI firmware detection // Set EFI firmware detection
err = utils.MkdirAll(fs, filepath.Dir(constants.EfiDevice), constants.DirPerm) err = fsutils.MkdirAll(fs, filepath.Dir(constants.EfiDevice), constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
_, err = fs.Create(constants.EfiDevice) _, err = fs.Create(constants.EfiDevice)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
// Set squashfs detection // Set squashfs detection
err = utils.MkdirAll(fs, filepath.Dir(constants.IsoBaseTree), constants.DirPerm) err = fsutils.MkdirAll(fs, filepath.Dir(constants.IsoBaseTree), constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
_, err = fs.Create(constants.IsoBaseTree) _, err = fs.Create(constants.IsoBaseTree)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
spec, err := elementalConfig.NewResetSpec(c) spec, err := config.NewResetSpec(c)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
Expect(spec.Active.Source.Value()).To(Equal(constants.IsoBaseTree)) Expect(spec.Active.Source.Value()).To(Equal(constants.IsoBaseTree))
Expect(spec.Partitions.EFI.MountPoint).To(Equal(constants.EfiDir)) Expect(spec.Partitions.EFI.MountPoint).To(Equal(constants.EfiDir))
@ -264,17 +265,17 @@ var _ = Describe("Types", Label("types", "config"), func() {
It("sets reset defaults on bios from non-squashed recovery", func() { It("sets reset defaults on bios from non-squashed recovery", func() {
// Set non-squashfs recovery image detection // Set non-squashfs recovery image detection
recoveryImg := filepath.Join(constants.RunningStateDir, "cOS", constants.RecoveryImgFile) recoveryImg := filepath.Join(constants.RunningStateDir, "cOS", constants.RecoveryImgFile)
err = utils.MkdirAll(fs, filepath.Dir(recoveryImg), constants.DirPerm) err = fsutils.MkdirAll(fs, filepath.Dir(recoveryImg), constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
_, err = fs.Create(recoveryImg) _, err = fs.Create(recoveryImg)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
spec, err := elementalConfig.NewResetSpec(c) spec, err := config.NewResetSpec(c)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
Expect(spec.Active.Source.Value()).To(Equal(recoveryImg)) Expect(spec.Active.Source.Value()).To(Equal(recoveryImg))
}) })
It("sets reset defaults on bios from unknown recovery", func() { It("sets reset defaults on bios from unknown recovery", func() {
spec, err := elementalConfig.NewResetSpec(c) spec, err := config.NewResetSpec(c)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
Expect(spec.Active.Source.IsEmpty()).To(BeTrue()) Expect(spec.Active.Source.IsEmpty()).To(BeTrue())
}) })
@ -312,13 +313,13 @@ var _ = Describe("Types", Label("types", "config"), func() {
ghwTest.Clean() ghwTest.Clean()
}) })
It("fails to set defaults if not booted from recovery", func() { It("fails to set defaults if not booted from recovery", func() {
_, err := elementalConfig.NewResetSpec(c) _, err := config.NewResetSpec(c)
Expect(err).Should(HaveOccurred()) Expect(err).Should(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("reset can only be called from the recovery system")) Expect(err.Error()).To(ContainSubstring("reset can only be called from the recovery system"))
}) })
It("fails to set defaults if no recovery partition detected", func() { It("fails to set defaults if no recovery partition detected", func() {
bootedFrom = constants.SystemLabel bootedFrom = constants.SystemLabel
_, err := elementalConfig.NewResetSpec(c) _, err := config.NewResetSpec(c)
Expect(err).Should(HaveOccurred()) Expect(err).Should(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("recovery partition not found")) Expect(err.Error()).To(ContainSubstring("recovery partition not found"))
}) })
@ -333,19 +334,19 @@ var _ = Describe("Types", Label("types", "config"), func() {
defer ghwTest.Clean() defer ghwTest.Clean()
bootedFrom = constants.SystemLabel bootedFrom = constants.SystemLabel
_, err := elementalConfig.NewResetSpec(c) _, err := config.NewResetSpec(c)
Expect(err).Should(HaveOccurred()) Expect(err).Should(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("state partition not found")) Expect(err.Error()).To(ContainSubstring("state partition not found"))
}) })
It("fails to set defaults if no efi partition on efi firmware", func() { It("fails to set defaults if no efi partition on efi firmware", func() {
// Set EFI firmware detection // Set EFI firmware detection
err = utils.MkdirAll(fs, filepath.Dir(constants.EfiDevice), constants.DirPerm) err = fsutils.MkdirAll(fs, filepath.Dir(constants.EfiDevice), constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
_, err = fs.Create(constants.EfiDevice) _, err = fs.Create(constants.EfiDevice)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
bootedFrom = constants.SystemLabel bootedFrom = constants.SystemLabel
_, err := elementalConfig.NewResetSpec(c) _, err := config.NewResetSpec(c)
Expect(err).Should(HaveOccurred()) Expect(err).Should(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("EFI partition not found")) Expect(err.Error()).To(ContainSubstring("EFI partition not found"))
}) })
@ -394,12 +395,12 @@ var _ = Describe("Types", Label("types", "config"), func() {
ghwTest.Clean() ghwTest.Clean()
}) })
It("sets upgrade defaults for active upgrade", func() { It("sets upgrade defaults for active upgrade", func() {
spec, err := elementalConfig.NewUpgradeSpec(c) spec, err := config.NewUpgradeSpec(c)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
Expect(spec.Active.Source.IsEmpty()).To(BeTrue()) Expect(spec.Active.Source.IsEmpty()).To(BeTrue())
}) })
It("sets upgrade defaults for non-squashed recovery upgrade", func() { It("sets upgrade defaults for non-squashed recovery upgrade", func() {
spec, err := elementalConfig.NewUpgradeSpec(c) spec, err := config.NewUpgradeSpec(c)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
Expect(spec.Recovery.Source.IsEmpty()).To(BeTrue()) Expect(spec.Recovery.Source.IsEmpty()).To(BeTrue())
Expect(spec.Recovery.FS).To(Equal(constants.LinuxImgFs)) Expect(spec.Recovery.FS).To(Equal(constants.LinuxImgFs))
@ -408,12 +409,12 @@ var _ = Describe("Types", Label("types", "config"), func() {
//Set squashed recovery detection //Set squashed recovery detection
mounter.Mount("device3", constants.LiveDir, "auto", []string{}) mounter.Mount("device3", constants.LiveDir, "auto", []string{})
img := filepath.Join(constants.LiveDir, "cOS", constants.RecoverySquashFile) img := filepath.Join(constants.LiveDir, "cOS", constants.RecoverySquashFile)
err = utils.MkdirAll(fs, filepath.Dir(img), constants.DirPerm) err = fsutils.MkdirAll(fs, filepath.Dir(img), constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
_, err = fs.Create(img) _, err = fs.Create(img)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
spec, err := elementalConfig.NewUpgradeSpec(c) spec, err := config.NewUpgradeSpec(c)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
Expect(spec.Recovery.Source.IsEmpty()).To(BeTrue()) Expect(spec.Recovery.Source.IsEmpty()).To(BeTrue())
Expect(spec.Recovery.FS).To(Equal(constants.SquashFs)) Expect(spec.Recovery.FS).To(Equal(constants.SquashFs))
@ -501,25 +502,25 @@ cloud-init-paths:
It("Reads properly the cloud config for install", func() { It("Reads properly the cloud config for install", func() {
cfg, err := config.Scan(collector.Directories([]string{dir}...), collector.NoLogs) cfg, err := config.Scan(collector.Directories([]string{dir}...), collector.NoLogs)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
installConfig, installSpec, err := elementalConfig.ReadInstallConfigFromAgentConfig(cfg) fmt.Print(litter.Sdump(cfg))
installSpec, err := config.ReadInstallSpecFromConfig(cfg)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(installConfig.Strict).To(BeTrue()) Expect(cfg.Strict).To(BeTrue())
Expect(installSpec.GrubDefEntry).To(Equal("MyCustomOS")) Expect(installSpec.GrubDefEntry).To(Equal("MyCustomOS"))
Expect(installSpec.Active.Size).To(Equal(uint(666))) Expect(installSpec.Active.Size).To(Equal(uint(666)))
Expect(installConfig.CloudInitPaths).To(ContainElement("/what")) Expect(cfg.CloudInitPaths).To(ContainElement("/what"))
}) })
It("Reads properly the cloud config for reset", func() { It("Reads properly the cloud config for reset", func() {
bootedFrom = constants.SystemLabel bootedFrom = constants.SystemLabel
cfg, err := config.Scan(collector.Directories([]string{dir}...), collector.NoLogs) cfg, err := config.Scan(collector.Directories([]string{dir}...), collector.NoLogs)
config, err := elementalConfig.ReadConfigRunFromAgentConfig(cfg)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
// Override the config with our test params // Override the config with our test params
config.Runner = runner cfg.Runner = runner
config.Fs = fs cfg.Fs = fs
config.Mounter = mounter cfg.Mounter = mounter
config.CloudInitRunner = ci cfg.CloudInitRunner = ci
spec, err := elementalConfig.ReadSpecFromCloudConfig(config, "reset") spec, err := config.ReadSpecFromCloudConfig(cfg, "reset")
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
resetSpec := spec.(*v1.ResetSpec) resetSpec := spec.(*v1.ResetSpec)
Expect(resetSpec.FormatPersistent).To(BeTrue()) Expect(resetSpec.FormatPersistent).To(BeTrue())
@ -528,32 +529,28 @@ cloud-init-paths:
}) })
It("Reads properly the cloud config for upgrade", func() { It("Reads properly the cloud config for upgrade", func() {
cfg, err := config.Scan(collector.Directories([]string{dir}...), collector.NoLogs) cfg, err := config.Scan(collector.Directories([]string{dir}...), collector.NoLogs)
config, err := elementalConfig.ReadConfigRunFromAgentConfig(cfg)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
// Override the config with our test params // Override the config with our test params
config.Runner = runner cfg.Runner = runner
config.Fs = fs cfg.Fs = fs
config.Mounter = mounter cfg.Mounter = mounter
config.CloudInitRunner = ci cfg.CloudInitRunner = ci
spec, err := elementalConfig.ReadSpecFromCloudConfig(config, "upgrade") spec, err := config.ReadSpecFromCloudConfig(cfg, "upgrade")
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
upgradeSpec := spec.(*v1.UpgradeSpec) upgradeSpec := spec.(*v1.UpgradeSpec)
Expect(upgradeSpec.RecoveryUpgrade).To(BeTrue()) Expect(upgradeSpec.RecoveryUpgrade).To(BeTrue())
}) })
It("Fails when a wrong action is read", func() { It("Fails when a wrong action is read", func() {
cfg, err := config.Scan(collector.Directories([]string{dir}...), collector.NoLogs) cfg, err := config.Scan(collector.Directories([]string{dir}...), collector.NoLogs)
config, err := elementalConfig.ReadConfigRunFromAgentConfig(cfg)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
_, err = elementalConfig.ReadSpecFromCloudConfig(config, "nope") _, err = config.ReadSpecFromCloudConfig(cfg, "nope")
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
}) })
It("Sets info level if its not on the cloud-config", func() { It("Sets info level if its not on the cloud-config", func() {
// Now again but with no config // Now again but with no config
cfg, err := config.Scan(collector.Directories([]string{""}...), collector.NoLogs) cfg, err := config.Scan(collector.Directories([]string{""}...), collector.NoLogs)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
installConfig, _, err := elementalConfig.ReadInstallConfigFromAgentConfig(cfg) Expect(cfg.Logger.GetLevel()).To(Equal(logrus.InfoLevel))
Expect(err).ToNot(HaveOccurred())
Expect(installConfig.Logger.GetLevel()).To(Equal(logrus.InfoLevel))
}) })
It("Sets debug level if its on the cloud-config", func() { It("Sets debug level if its on the cloud-config", func() {
ccdata := []byte(`#cloud-config ccdata := []byte(`#cloud-config
@ -563,11 +560,19 @@ debug: true
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
cfg, err := config.Scan(collector.Directories([]string{dir}...), collector.NoLogs) cfg, err := config.Scan(collector.Directories([]string{dir}...), collector.NoLogs)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
installConfig, _, err := elementalConfig.ReadInstallConfigFromAgentConfig(cfg) Expect(cfg.Logger.GetLevel()).To(Equal(logrus.DebugLevel))
Expect(err).ToNot(HaveOccurred())
Expect(installConfig.Logger.GetLevel()).To(Equal(logrus.DebugLevel))
}) })
}) })
Describe("TestBootedFrom", Label("BootedFrom"), func() {
It("returns true if we are booting from label FAKELABEL", func() {
runner.ReturnValue = []byte("")
Expect(config.BootedFrom(runner, "FAKELABEL")).To(BeFalse())
})
It("returns false if we are not booting from label FAKELABEL", func() {
runner.ReturnValue = []byte("FAKELABEL")
Expect(config.BootedFrom(runner, "FAKELABEL")).To(BeTrue())
})
})
}) })
}) })

View File

@ -19,21 +19,23 @@ package elemental
import ( import (
"errors" "errors"
"fmt" "fmt"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
"github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
"path/filepath" "path/filepath"
"strings" "strings"
agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config"
cnst "github.com/kairos-io/kairos-agent/v2/pkg/constants" cnst "github.com/kairos-io/kairos-agent/v2/pkg/constants"
"github.com/kairos-io/kairos-agent/v2/pkg/partitioner" "github.com/kairos-io/kairos-agent/v2/pkg/partitioner"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
"github.com/kairos-io/kairos-agent/v2/pkg/utils" "github.com/kairos-io/kairos-agent/v2/pkg/utils"
) )
// Elemental is the struct meant to self-contain most utils and actions related to Elemental, like installing or applying selinux // Elemental is the struct meant to self-contain most utils and actions related to Elemental, like installing or applying selinux
type Elemental struct { type Elemental struct {
config *v1.Config config *agentConfig.Config
} }
func NewElemental(config *v1.Config) *Elemental { func NewElemental(config *agentConfig.Config) *Elemental {
return &Elemental{ return &Elemental{
config: config, config: config,
} }
@ -177,7 +179,7 @@ func (e Elemental) MountRWPartition(part *v1.Partition) (umount func() error, er
// MountPartition mounts a partition with the given mount options // MountPartition mounts a partition with the given mount options
func (e Elemental) MountPartition(part *v1.Partition, opts ...string) error { func (e Elemental) MountPartition(part *v1.Partition, opts ...string) error {
e.config.Logger.Debugf("Mounting partition %s", part.FilesystemLabel) e.config.Logger.Debugf("Mounting partition %s", part.FilesystemLabel)
err := utils.MkdirAll(e.config.Fs, part.MountPoint, cnst.DirPerm) err := fsutils.MkdirAll(e.config.Fs, part.MountPoint, cnst.DirPerm)
if err != nil { if err != nil {
return err return err
} }
@ -211,7 +213,7 @@ func (e Elemental) UnmountPartition(part *v1.Partition) error {
// MountImage mounts an image with the given mount options // MountImage mounts an image with the given mount options
func (e Elemental) MountImage(img *v1.Image, opts ...string) error { func (e Elemental) MountImage(img *v1.Image, opts ...string) error {
e.config.Logger.Debugf("Mounting image %s", img.Label) e.config.Logger.Debugf("Mounting image %s", img.Label)
err := utils.MkdirAll(e.config.Fs, img.MountPoint, cnst.DirPerm) err := fsutils.MkdirAll(e.config.Fs, img.MountPoint, cnst.DirPerm)
if err != nil { if err != nil {
return err return err
} }
@ -251,7 +253,7 @@ func (e Elemental) UnmountImage(img *v1.Image) error {
// CreateFileSystemImage creates the image file for config.target // CreateFileSystemImage creates the image file for config.target
func (e Elemental) CreateFileSystemImage(img *v1.Image) error { func (e Elemental) CreateFileSystemImage(img *v1.Image) error {
e.config.Logger.Infof("Creating file system image %s", img.File) e.config.Logger.Infof("Creating file system image %s", img.File)
err := utils.MkdirAll(e.config.Fs, filepath.Dir(img.File), cnst.DirPerm) err := fsutils.MkdirAll(e.config.Fs, filepath.Dir(img.File), cnst.DirPerm)
if err != nil { if err != nil {
return err return err
} }
@ -298,7 +300,7 @@ func (e *Elemental) DeployImage(img *v1.Image, leaveMounted bool) (info interfac
} }
} else { } else {
target = utils.GetTempDir(e.config, "") target = utils.GetTempDir(e.config, "")
err := utils.MkdirAll(e.config.Fs, target, cnst.DirPerm) err := fsutils.MkdirAll(e.config.Fs, target, cnst.DirPerm)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -374,7 +376,7 @@ func (e *Elemental) DumpSource(target string, imgSrc *v1.ImageSource) (info inte
return nil, err return nil, err
} }
} else if imgSrc.IsFile() { } else if imgSrc.IsFile() {
err := utils.MkdirAll(e.config.Fs, filepath.Dir(target), cnst.DirPerm) err := fsutils.MkdirAll(e.config.Fs, filepath.Dir(target), cnst.DirPerm)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -412,7 +414,7 @@ func (e *Elemental) CopyCloudConfig(cloudInit []string) (err error) {
func (e *Elemental) SelinuxRelabel(rootDir string, raiseError bool) error { func (e *Elemental) SelinuxRelabel(rootDir string, raiseError bool) error {
policyFile, err := utils.FindFileWithPrefix(e.config.Fs, filepath.Join(rootDir, cnst.SELinuxTargetedPolicyPath), "policy.") policyFile, err := utils.FindFileWithPrefix(e.config.Fs, filepath.Join(rootDir, cnst.SELinuxTargetedPolicyPath), "policy.")
contextFile := filepath.Join(rootDir, cnst.SELinuxTargetedContextFile) contextFile := filepath.Join(rootDir, cnst.SELinuxTargetedContextFile)
contextExists, _ := utils.Exists(e.config.Fs, contextFile) contextExists, _ := fsutils.Exists(e.config.Fs, contextFile)
if err == nil && contextExists && utils.CommandExists("setfiles") { if err == nil && contextExists && utils.CommandExists("setfiles") {
var out []byte var out []byte
@ -452,7 +454,7 @@ func (e *Elemental) CheckActiveDeployment(labels []string) bool {
// in cnst.DownloadedIsoMnt // in cnst.DownloadedIsoMnt
func (e *Elemental) GetIso(iso string) (tmpDir string, err error) { func (e *Elemental) GetIso(iso string) (tmpDir string, err error) {
//TODO support ISO download in persistent storage? //TODO support ISO download in persistent storage?
tmpDir, err = utils.TempDir(e.config.Fs, "", "elemental") tmpDir, err = fsutils.TempDir(e.config.Fs, "", "elemental")
if err != nil { if err != nil {
return "", err return "", err
} }
@ -470,7 +472,7 @@ func (e *Elemental) GetIso(iso string) (tmpDir string, err error) {
if err != nil { if err != nil {
return "", err return "", err
} }
err = utils.MkdirAll(e.config.Fs, isoMnt, cnst.DirPerm) err = fsutils.MkdirAll(e.config.Fs, isoMnt, cnst.DirPerm)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -486,7 +488,7 @@ func (e *Elemental) GetIso(iso string) (tmpDir string, err error) {
}() }()
e.config.Logger.Infof("Mounting squashfs image from iso into %s", rootfsMnt) e.config.Logger.Infof("Mounting squashfs image from iso into %s", rootfsMnt)
err = utils.MkdirAll(e.config.Fs, rootfsMnt, cnst.DirPerm) err = fsutils.MkdirAll(e.config.Fs, rootfsMnt, cnst.DirPerm)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -505,7 +507,7 @@ func (e Elemental) UpdateSourcesFormDownloadedISO(workDir string, activeImg *v1.
} }
if recoveryImg != nil { if recoveryImg != nil {
squashedImgSource := filepath.Join(isoMnt, cnst.RecoverySquashFile) squashedImgSource := filepath.Join(isoMnt, cnst.RecoverySquashFile)
if exists, _ := utils.Exists(e.config.Fs, squashedImgSource); exists { if exists, _ := fsutils.Exists(e.config.Fs, squashedImgSource); exists {
recoveryImg.Source = v1.NewFileSrc(squashedImgSource) recoveryImg.Source = v1.NewFileSrc(squashedImgSource)
recoveryImg.FS = cnst.SquashFs recoveryImg.FS = cnst.SquashFs
} else if activeImg != nil { } else if activeImg != nil {

View File

@ -19,6 +19,8 @@ package elemental_test
import ( import (
"errors" "errors"
"fmt" "fmt"
agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config"
"github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
"os" "os"
"path/filepath" "path/filepath"
"testing" "testing"
@ -28,7 +30,6 @@ import (
"github.com/kairos-io/kairos-agent/v2/pkg/constants" "github.com/kairos-io/kairos-agent/v2/pkg/constants"
cnst "github.com/kairos-io/kairos-agent/v2/pkg/constants" cnst "github.com/kairos-io/kairos-agent/v2/pkg/constants"
"github.com/kairos-io/kairos-agent/v2/pkg/elemental" "github.com/kairos-io/kairos-agent/v2/pkg/elemental"
conf "github.com/kairos-io/kairos-agent/v2/pkg/elementalConfig"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
"github.com/kairos-io/kairos-agent/v2/pkg/utils" "github.com/kairos-io/kairos-agent/v2/pkg/utils"
v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks" v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks"
@ -49,7 +50,7 @@ func TestElementalSuite(t *testing.T) {
} }
var _ = Describe("Elemental", Label("elemental"), func() { var _ = Describe("Elemental", Label("elemental"), func() {
var config *v1.Config var config *agentConfig.Config
var runner *v1mock.FakeRunner var runner *v1mock.FakeRunner
var logger v1.Logger var logger v1.Logger
var syscall v1.SyscallInterface var syscall v1.SyscallInterface
@ -67,14 +68,14 @@ var _ = Describe("Elemental", Label("elemental"), func() {
logger = v1.NewNullLogger() logger = v1.NewNullLogger()
fs, cleanup, _ = vfst.NewTestFS(nil) fs, cleanup, _ = vfst.NewTestFS(nil)
extractor = v1mock.NewFakeImageExtractor(logger) extractor = v1mock.NewFakeImageExtractor(logger)
config = conf.NewConfig( config = agentConfig.NewConfig(
conf.WithFs(fs), agentConfig.WithFs(fs),
conf.WithRunner(runner), agentConfig.WithRunner(runner),
conf.WithLogger(logger), agentConfig.WithLogger(logger),
conf.WithMounter(mounter), agentConfig.WithMounter(mounter),
conf.WithSyscall(syscall), agentConfig.WithSyscall(syscall),
conf.WithClient(client), agentConfig.WithClient(client),
conf.WithImageExtractor(extractor), agentConfig.WithImageExtractor(extractor),
) )
}) })
AfterEach(func() { cleanup() }) AfterEach(func() { cleanup() })
@ -82,9 +83,9 @@ var _ = Describe("Elemental", Label("elemental"), func() {
var el *elemental.Elemental var el *elemental.Elemental
var parts v1.ElementalPartitions var parts v1.ElementalPartitions
BeforeEach(func() { BeforeEach(func() {
parts = conf.NewInstallElementalParitions() parts = agentConfig.NewInstallElementalPartitions()
err := utils.MkdirAll(fs, "/some", cnst.DirPerm) err := fsutils.MkdirAll(fs, "/some", cnst.DirPerm)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
_, err = fs.Create("/some/device") _, err = fs.Create("/some/device")
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
@ -146,9 +147,9 @@ var _ = Describe("Elemental", Label("elemental"), func() {
var el *elemental.Elemental var el *elemental.Elemental
var parts v1.ElementalPartitions var parts v1.ElementalPartitions
BeforeEach(func() { BeforeEach(func() {
parts = conf.NewInstallElementalParitions() parts = agentConfig.NewInstallElementalPartitions()
err := utils.MkdirAll(fs, "/some", cnst.DirPerm) err := fsutils.MkdirAll(fs, "/some", cnst.DirPerm)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
_, err = fs.Create("/some/device") _, err = fs.Create("/some/device")
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
@ -194,9 +195,9 @@ var _ = Describe("Elemental", Label("elemental"), func() {
var el *elemental.Elemental var el *elemental.Elemental
var parts v1.ElementalPartitions var parts v1.ElementalPartitions
BeforeEach(func() { BeforeEach(func() {
parts = conf.NewInstallElementalParitions() parts = agentConfig.NewInstallElementalPartitions()
err := utils.MkdirAll(fs, "/some", cnst.DirPerm) err := fsutils.MkdirAll(fs, "/some", cnst.DirPerm)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
_, err = fs.Create("/some/device") _, err = fs.Create("/some/device")
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
@ -292,7 +293,7 @@ var _ = Describe("Elemental", Label("elemental"), func() {
MountPoint: cnst.ActiveDir, MountPoint: cnst.ActiveDir,
Source: v1.NewDirSrc(cnst.IsoBaseTree), Source: v1.NewDirSrc(cnst.IsoBaseTree),
} }
_ = utils.MkdirAll(fs, cnst.IsoBaseTree, cnst.DirPerm) _ = fsutils.MkdirAll(fs, cnst.IsoBaseTree, cnst.DirPerm)
el = elemental.NewElemental(config) el = elemental.NewElemental(config)
}) })
@ -341,10 +342,10 @@ var _ = Describe("Elemental", Label("elemental"), func() {
cInit = &v1mock.FakeCloudInitRunner{ExecStages: []string{}, Error: false} cInit = &v1mock.FakeCloudInitRunner{ExecStages: []string{}, Error: false}
config.CloudInitRunner = cInit config.CloudInitRunner = cInit
el = elemental.NewElemental(config) el = elemental.NewElemental(config)
install = conf.NewInstallSpec(config) install = agentConfig.NewInstallSpec(config)
install.Target = "/some/device" install.Target = "/some/device"
err := utils.MkdirAll(fs, "/some", cnst.DirPerm) err := fsutils.MkdirAll(fs, "/some", cnst.DirPerm)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
_, err = fs.Create("/some/device") _, err = fs.Create("/some/device")
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
@ -355,7 +356,7 @@ var _ = Describe("Elemental", Label("elemental"), func() {
var efiPartCmds, partCmds, biosPartCmds [][]string var efiPartCmds, partCmds, biosPartCmds [][]string
BeforeEach(func() { BeforeEach(func() {
partNum, printOut = 0, printOutput partNum, printOut = 0, printOutput
err := utils.MkdirAll(fs, "/some", cnst.DirPerm) err := fsutils.MkdirAll(fs, "/some", cnst.DirPerm)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
efiPartCmds = [][]string{ efiPartCmds = [][]string{
{ {
@ -435,7 +436,7 @@ var _ = Describe("Elemental", Label("elemental"), func() {
Describe("Run with failures", func() { Describe("Run with failures", func() {
var runFunc func(cmd string, args ...string) ([]byte, error) var runFunc func(cmd string, args ...string) ([]byte, error)
BeforeEach(func() { BeforeEach(func() {
err := utils.MkdirAll(fs, "/some", cnst.DirPerm) err := fsutils.MkdirAll(fs, "/some", cnst.DirPerm)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
partNum, printOut = 0, printOutput partNum, printOut = 0, printOutput
runFunc = func(cmd string, args ...string) ([]byte, error) { runFunc = func(cmd string, args ...string) ([]byte, error) {
@ -486,9 +487,9 @@ var _ = Describe("Elemental", Label("elemental"), func() {
var img *v1.Image var img *v1.Image
var cmdFail string var cmdFail string
BeforeEach(func() { BeforeEach(func() {
sourceDir, err := utils.TempDir(fs, "", "elemental") sourceDir, err := fsutils.TempDir(fs, "", "elemental")
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
destDir, err := utils.TempDir(fs, "", "elemental") destDir, err := fsutils.TempDir(fs, "", "elemental")
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
cmdFail = "" cmdFail = ""
el = elemental.NewElemental(config) el = elemental.NewElemental(config)
@ -532,7 +533,7 @@ var _ = Describe("Elemental", Label("elemental"), func() {
sourceImg := "/source.img" sourceImg := "/source.img"
_, err := fs.Create(sourceImg) _, err := fs.Create(sourceImg)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
destDir, err := utils.TempDir(fs, "", "elemental") destDir, err := fsutils.TempDir(fs, "", "elemental")
Expect(err).To(BeNil()) Expect(err).To(BeNil())
img.Source = v1.NewFileSrc(sourceImg) img.Source = v1.NewFileSrc(sourceImg)
img.MountPoint = destDir img.MountPoint = destDir
@ -542,7 +543,7 @@ var _ = Describe("Elemental", Label("elemental"), func() {
sourceImg := "/source.img" sourceImg := "/source.img"
_, err := fs.Create(sourceImg) _, err := fs.Create(sourceImg)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
destDir, err := utils.TempDir(fs, "", "elemental") destDir, err := fsutils.TempDir(fs, "", "elemental")
Expect(err).To(BeNil()) Expect(err).To(BeNil())
img.Source = v1.NewFileSrc(sourceImg) img.Source = v1.NewFileSrc(sourceImg)
img.MountPoint = destDir img.MountPoint = destDir
@ -554,7 +555,7 @@ var _ = Describe("Elemental", Label("elemental"), func() {
sourceImg := "/source.img" sourceImg := "/source.img"
_, err := fs.Create(sourceImg) _, err := fs.Create(sourceImg)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
destDir, err := utils.TempDir(fs, "", "elemental") destDir, err := fsutils.TempDir(fs, "", "elemental")
Expect(err).To(BeNil()) Expect(err).To(BeNil())
img.Source = v1.NewFileSrc(sourceImg) img.Source = v1.NewFileSrc(sourceImg)
img.MountPoint = destDir img.MountPoint = destDir
@ -596,7 +597,7 @@ var _ = Describe("Elemental", Label("elemental"), func() {
BeforeEach(func() { BeforeEach(func() {
var err error var err error
e = elemental.NewElemental(config) e = elemental.NewElemental(config)
destDir, err = utils.TempDir(fs, "", "elemental") destDir, err = fsutils.TempDir(fs, "", "elemental")
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
}) })
It("Copies files from a directory source", func() { It("Copies files from a directory source", func() {
@ -682,7 +683,7 @@ var _ = Describe("Elemental", Label("elemental"), func() {
var relabelCmd []string var relabelCmd []string
BeforeEach(func() { BeforeEach(func() {
// to mock the existance of setfiles command on non selinux hosts // to mock the existance of setfiles command on non selinux hosts
err := utils.MkdirAll(fs, "/usr/sbin", constants.DirPerm) err := fsutils.MkdirAll(fs, "/usr/sbin", constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
sbin, err := fs.RawPath("/usr/sbin") sbin, err := fs.RawPath("/usr/sbin")
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
@ -696,11 +697,11 @@ var _ = Describe("Elemental", Label("elemental"), func() {
// to mock SELinux policy files // to mock SELinux policy files
policyFile = filepath.Join(constants.SELinuxTargetedPolicyPath, "policy.31") policyFile = filepath.Join(constants.SELinuxTargetedPolicyPath, "policy.31")
err = utils.MkdirAll(fs, filepath.Dir(constants.SELinuxTargetedContextFile), constants.DirPerm) err = fsutils.MkdirAll(fs, filepath.Dir(constants.SELinuxTargetedContextFile), constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
_, err = fs.Create(constants.SELinuxTargetedContextFile) _, err = fs.Create(constants.SELinuxTargetedContextFile)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
err = utils.MkdirAll(fs, constants.SELinuxTargetedPolicyPath, constants.DirPerm) err = fsutils.MkdirAll(fs, constants.SELinuxTargetedPolicyPath, constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
_, err = fs.Create(policyFile) _, err = fs.Create(policyFile)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
@ -749,12 +750,12 @@ var _ = Describe("Elemental", Label("elemental"), func() {
}) })
It("relabels the given root-tree path", func() { It("relabels the given root-tree path", func() {
contextFile := filepath.Join("/root", constants.SELinuxTargetedContextFile) contextFile := filepath.Join("/root", constants.SELinuxTargetedContextFile)
err := utils.MkdirAll(fs, filepath.Dir(contextFile), constants.DirPerm) err := fsutils.MkdirAll(fs, filepath.Dir(contextFile), constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
_, err = fs.Create(contextFile) _, err = fs.Create(contextFile)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
policyFile = filepath.Join("/root", policyFile) policyFile = filepath.Join("/root", policyFile)
err = utils.MkdirAll(fs, filepath.Join("/root", constants.SELinuxTargetedPolicyPath), constants.DirPerm) err = fsutils.MkdirAll(fs, filepath.Join("/root", constants.SELinuxTargetedPolicyPath), constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
_, err = fs.Create(policyFile) _, err = fs.Create(policyFile)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
@ -774,7 +775,7 @@ var _ = Describe("Elemental", Label("elemental"), func() {
e = elemental.NewElemental(config) e = elemental.NewElemental(config)
}) })
It("Gets the iso and returns the temporary where it is stored", func() { It("Gets the iso and returns the temporary where it is stored", func() {
tmpDir, err := utils.TempDir(fs, "", "elemental-test") tmpDir, err := fsutils.TempDir(fs, "", "elemental-test")
Expect(err).To(BeNil()) Expect(err).To(BeNil())
err = fs.WriteFile(fmt.Sprintf("%s/fake.iso", tmpDir), []byte("Hi"), cnst.FilePerm) err = fs.WriteFile(fmt.Sprintf("%s/fake.iso", tmpDir), []byte("Hi"), cnst.FilePerm)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
@ -782,7 +783,7 @@ var _ = Describe("Elemental", Label("elemental"), func() {
isoDir, err := e.GetIso(iso) isoDir, err := e.GetIso(iso)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
// Confirm that the iso is stored in isoDir // Confirm that the iso is stored in isoDir
utils.Exists(fs, filepath.Join(isoDir, "cOs.iso")) fsutils.Exists(fs, filepath.Join(isoDir, "cOs.iso"))
}) })
It("Fails if it cant find the iso", func() { It("Fails if it cant find the iso", func() {
iso := "whatever" iso := "whatever"
@ -792,7 +793,7 @@ var _ = Describe("Elemental", Label("elemental"), func() {
}) })
It("Fails if it cannot mount the iso", func() { It("Fails if it cannot mount the iso", func() {
mounter.ErrorOnMount = true mounter.ErrorOnMount = true
tmpDir, err := utils.TempDir(fs, "", "elemental-test") tmpDir, err := fsutils.TempDir(fs, "", "elemental-test")
Expect(err).To(BeNil()) Expect(err).To(BeNil())
err = fs.WriteFile(fmt.Sprintf("%s/fake.iso", tmpDir), []byte("Hi"), cnst.FilePerm) err = fs.WriteFile(fmt.Sprintf("%s/fake.iso", tmpDir), []byte("Hi"), cnst.FilePerm)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
@ -831,7 +832,7 @@ var _ = Describe("Elemental", Label("elemental"), func() {
It("updates recovery only image", func() { It("updates recovery only image", func() {
recoveryImg = &v1.Image{} recoveryImg = &v1.Image{}
isoMnt := "/some/dir/iso" isoMnt := "/some/dir/iso"
err := utils.MkdirAll(fs, isoMnt, cnst.DirPerm) err := fsutils.MkdirAll(fs, isoMnt, cnst.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
recoverySquash := filepath.Join(isoMnt, cnst.RecoverySquashFile) recoverySquash := filepath.Join(isoMnt, cnst.RecoverySquashFile)
_, err = fs.Create(recoverySquash) _, err = fs.Create(recoverySquash)
@ -883,7 +884,7 @@ var _ = Describe("Elemental", Label("elemental"), func() {
Expect(runner.CmdsMatch([][]string{{"grub2-editenv"}})).NotTo(BeNil()) Expect(runner.CmdsMatch([][]string{{"grub2-editenv"}})).NotTo(BeNil())
}) })
It("loads /etc/os-release on empty default entry", func() { It("loads /etc/os-release on empty default entry", func() {
err := utils.MkdirAll(config.Fs, "/imgMountPoint/etc", constants.DirPerm) err := fsutils.MkdirAll(config.Fs, "/imgMountPoint/etc", constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
err = config.Fs.WriteFile("/imgMountPoint/etc/os-release", []byte("GRUB_ENTRY_NAME=test"), constants.FilePerm) err = config.Fs.WriteFile("/imgMountPoint/etc/os-release", []byte("GRUB_ENTRY_NAME=test"), constants.FilePerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
@ -904,7 +905,7 @@ var _ = Describe("Elemental", Label("elemental"), func() {
}) })
Describe("FindKernelInitrd", Label("find"), func() { Describe("FindKernelInitrd", Label("find"), func() {
BeforeEach(func() { BeforeEach(func() {
err := utils.MkdirAll(fs, "/path/boot", constants.DirPerm) err := fsutils.MkdirAll(fs, "/path/boot", constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
}) })
It("finds kernel and initrd files", func() { It("finds kernel and initrd files", func() {

View File

@ -1,29 +0,0 @@
/*
Copyright © 2022 SUSE LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package elementalConfig_test
import (
"testing"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
func TestTypes(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "config initializer test suite")
}

View File

@ -19,13 +19,14 @@ package partitioner
import ( import (
"errors" "errors"
"fmt" "fmt"
"github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
"github.com/kairos-io/kairos-agent/v2/pkg/utils/partitions"
"os" "os"
"regexp" "regexp"
"strings" "strings"
"time" "time"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
"github.com/kairos-io/kairos-agent/v2/pkg/utils"
"github.com/twpayne/go-vfs" "github.com/twpayne/go-vfs"
) )
@ -327,7 +328,7 @@ func (dev Disk) FindPartitionDevice(partNum int) (string, error) {
for tries := 0; tries <= partitionTries; tries++ { for tries := 0; tries <= partitionTries; tries++ {
dev.logger.Debugf("Trying to find the partition device %d of device %s (try number %d)", partNum, dev, tries+1) dev.logger.Debugf("Trying to find the partition device %d of device %s (try number %d)", partNum, dev, tries+1)
_, _ = dev.runner.Run("udevadm", "settle") _, _ = dev.runner.Run("udevadm", "settle")
if exists, _ := utils.Exists(dev.fs, device); exists { if exists, _ := fsutils.Exists(dev.fs, device); exists {
return device, nil return device, nil
} }
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
@ -401,7 +402,7 @@ func (dev Disk) expandFilesystem(device string) (string, error) {
var out []byte var out []byte
var err error var err error
fs, err := utils.GetPartitionFS(device) fs, err := partitions.GetPartitionFS(device)
if err != nil { if err != nil {
return fs, err return fs, err
} }
@ -419,7 +420,7 @@ func (dev Disk) expandFilesystem(device string) (string, error) {
} }
case "xfs": case "xfs":
// to grow an xfs fs it needs to be mounted :/ // to grow an xfs fs it needs to be mounted :/
tmpDir, err := utils.TempDir(dev.fs, "", "partitioner") tmpDir, err := fsutils.TempDir(dev.fs, "", "partitioner")
defer func(fs v1.FS, path string) { defer func(fs v1.FS, path string) {
_ = fs.RemoveAll(path) _ = fs.RemoveAll(path)
}(dev.fs, tmpDir) }(dev.fs, tmpDir)

View File

@ -18,13 +18,13 @@ package partitioner_test
import ( import (
"errors" "errors"
"github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
"testing" "testing"
"github.com/jaypipes/ghw/pkg/block" "github.com/jaypipes/ghw/pkg/block"
"github.com/kairos-io/kairos-agent/v2/pkg/constants" "github.com/kairos-io/kairos-agent/v2/pkg/constants"
part "github.com/kairos-io/kairos-agent/v2/pkg/partitioner" part "github.com/kairos-io/kairos-agent/v2/pkg/partitioner"
"github.com/kairos-io/kairos-agent/v2/pkg/utils"
mocks "github.com/kairos-io/kairos-agent/v2/tests/mocks" mocks "github.com/kairos-io/kairos-agent/v2/tests/mocks"
. "github.com/onsi/ginkgo/v2" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
@ -211,7 +211,7 @@ var _ = Describe("Partitioner", Label("disk", "partition", "partitioner"), func(
BeforeEach(func() { BeforeEach(func() {
fs, cleanup, _ = vfst.NewTestFS(nil) fs, cleanup, _ = vfst.NewTestFS(nil)
err := utils.MkdirAll(fs, "/dev", constants.DirPerm) err := fsutils.MkdirAll(fs, "/dev", constants.DirPerm)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
_, err = fs.Create("/dev/device") _, err = fs.Create("/dev/device")
Expect(err).To(BeNil()) Expect(err).To(BeNil())

View File

@ -19,12 +19,10 @@ package v1
import ( import (
"fmt" "fmt"
"path/filepath" "path/filepath"
"runtime"
"sort" "sort"
"github.com/kairos-io/kairos-agent/v2/pkg/constants" "github.com/kairos-io/kairos-agent/v2/pkg/constants"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
"k8s.io/mount-utils"
) )
const ( const (
@ -43,94 +41,6 @@ type Spec interface {
ShouldShutdown() bool ShouldShutdown() bool
} }
// Config is the struct that includes basic and generic configuration of elemental binary runtime.
// It mostly includes the interfaces used around many methods in elemental code
type Config struct {
Debug bool `yaml:"debug,omitempty" mapstructure:"debug"`
Strict bool `yaml:"strict,omitempty" mapstructure:"strict"`
CloudInitPaths []string `yaml:"cloud-init-paths,omitempty" mapstructure:"cloud-init-paths"`
EjectCD bool `yaml:"eject-cd,omitempty" mapstructure:"eject-cd"`
FullCloudConfig string // Stores the full cloud config used to generate the spec afterwards
Logger Logger
Fs FS
Mounter mount.Interface
Runner Runner
Syscall SyscallInterface
CloudInitRunner CloudInitRunner
ImageExtractor ImageExtractor
Client HTTPClient
Platform *Platform `yaml:"platform,omitempty" mapstructure:"platform"`
Cosign bool `yaml:"cosign,omitempty" mapstructure:"cosign"`
Verify bool `yaml:"verify,omitempty" mapstructure:"verify"`
CosignPubKey string `yaml:"cosign-key,omitempty" mapstructure:"cosign-key"`
Arch string `yaml:"arch,omitempty" mapstructure:"arch"`
SquashFsCompressionConfig []string `yaml:"squash-compression,omitempty" mapstructure:"squash-compression"`
SquashFsNoCompression bool `yaml:"squash-no-compression,omitempty" mapstructure:"squash-no-compression"`
}
// WriteInstallState writes the state.yaml file to the given state and recovery paths
func (c Config) WriteInstallState(i *InstallState, statePath, recoveryPath string) error {
data, err := yaml.Marshal(i)
if err != nil {
return err
}
data = append([]byte("# Autogenerated file by elemental client, do not edit\n\n"), data...)
err = c.Fs.WriteFile(statePath, data, constants.FilePerm)
if err != nil {
return err
}
err = c.Fs.WriteFile(recoveryPath, data, constants.FilePerm)
if err != nil {
return err
}
return nil
}
// LoadInstallState loads the state.yaml file and unmarshals it to an InstallState object
func (c Config) LoadInstallState() (*InstallState, error) {
installState := &InstallState{}
data, err := c.Fs.ReadFile(filepath.Join(constants.RunningStateDir, constants.InstallStateFile))
if err != nil {
return nil, err
}
err = yaml.Unmarshal(data, installState)
if err != nil {
return nil, err
}
return installState, nil
}
// Sanitize checks the consistency of the struct, returns error
// if unsolvable inconsistencies are found
func (c *Config) Sanitize() error {
// If no squashcompression is set, zero the compression parameters
// By default on NewConfig the SquashFsCompressionConfig is set to the default values, and then override
// on config unmarshall.
if c.SquashFsNoCompression {
c.SquashFsCompressionConfig = []string{}
}
if c.Arch != "" {
p, err := NewPlatformFromArch(c.Arch)
if err != nil {
return err
}
c.Platform = p
}
if c.Platform == nil {
p, err := NewPlatformFromArch(runtime.GOARCH)
if err != nil {
return err
}
c.Platform = p
}
return nil
}
// InstallSpec struct represents all the installation action details // InstallSpec struct represents all the installation action details
type InstallSpec struct { type InstallSpec struct {
Target string `yaml:"device,omitempty" mapstructure:"device"` Target string `yaml:"device,omitempty" mapstructure:"device"`

View File

@ -17,108 +17,13 @@ limitations under the License.
package v1_test package v1_test
import ( import (
"path/filepath"
"github.com/kairos-io/kairos-agent/v2/pkg/constants"
"github.com/kairos-io/kairos-agent/v2/pkg/elementalConfig"
conf "github.com/kairos-io/kairos-agent/v2/pkg/elementalConfig"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
"github.com/kairos-io/kairos-agent/v2/pkg/utils"
v1mocks "github.com/kairos-io/kairos-agent/v2/tests/mocks"
. "github.com/onsi/ginkgo/v2" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/twpayne/go-vfs"
"github.com/twpayne/go-vfs/vfst"
) )
var _ = Describe("Types", Label("types", "config"), func() { var _ = Describe("Types", Label("types", "config"), func() {
Describe("Write and load installation state", func() {
var config *v1.Config
var runner *v1mocks.FakeRunner
var fs vfs.FS
var mounter *v1mocks.ErrorMounter
var cleanup func()
var err error
var dockerState, channelState *v1.ImageState
var installState *v1.InstallState
var statePath, recoveryPath string
BeforeEach(func() {
runner = v1mocks.NewFakeRunner()
mounter = v1mocks.NewErrorMounter()
fs, cleanup, err = vfst.NewTestFS(map[string]interface{}{})
Expect(err).Should(BeNil())
config = conf.NewConfig(
conf.WithFs(fs),
conf.WithRunner(runner),
conf.WithMounter(mounter),
)
dockerState = &v1.ImageState{
Source: v1.NewDockerSrc("registry.org/my/image:tag"),
Label: "active_label",
FS: "ext2",
SourceMetadata: &v1.DockerImageMeta{
Digest: "adadgadg",
Size: 23452345,
},
}
installState = &v1.InstallState{
Date: "somedate",
Partitions: map[string]*v1.PartitionState{
"state": {
FSLabel: "state_label",
Images: map[string]*v1.ImageState{
"active": dockerState,
},
},
"recovery": {
FSLabel: "state_label",
Images: map[string]*v1.ImageState{
"recovery": channelState,
},
},
},
}
statePath = filepath.Join(constants.RunningStateDir, constants.InstallStateFile)
recoveryPath = "/recoverypart/state.yaml"
err = utils.MkdirAll(fs, filepath.Dir(recoveryPath), constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred())
err = utils.MkdirAll(fs, filepath.Dir(statePath), constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred())
})
AfterEach(func() {
cleanup()
})
It("Writes and loads an installation data", func() {
err = config.WriteInstallState(installState, statePath, recoveryPath)
Expect(err).ShouldNot(HaveOccurred())
loadedInstallState, err := config.LoadInstallState()
Expect(err).ShouldNot(HaveOccurred())
Expect(*loadedInstallState).To(Equal(*installState))
})
It("Fails writing to state partition", func() {
err = fs.RemoveAll(filepath.Dir(statePath))
Expect(err).ShouldNot(HaveOccurred())
err = config.WriteInstallState(installState, statePath, recoveryPath)
Expect(err).Should(HaveOccurred())
})
It("Fails writing to recovery partition", func() {
err = fs.RemoveAll(filepath.Dir(statePath))
Expect(err).ShouldNot(HaveOccurred())
err = config.WriteInstallState(installState, statePath, recoveryPath)
Expect(err).Should(HaveOccurred())
})
It("Fails loading state file", func() {
err = config.WriteInstallState(installState, statePath, recoveryPath)
Expect(err).ShouldNot(HaveOccurred())
err = fs.RemoveAll(filepath.Dir(statePath))
_, err = config.LoadInstallState()
Expect(err).Should(HaveOccurred())
})
})
Describe("ElementalPartitions", func() { Describe("ElementalPartitions", func() {
var p v1.PartitionList var p v1.PartitionList
var ep v1.ElementalPartitions var ep v1.ElementalPartitions
@ -319,151 +224,4 @@ var _ = Describe("Types", Label("types", "config"), func() {
Expect(p.GetByName("nonexistent")).To(BeNil()) Expect(p.GetByName("nonexistent")).To(BeNil())
}) })
}) })
Describe("Config", func() {
It("runs sanitize method", func() {
cfg := elementalConfig.NewConfig(elementalConfig.WithMounter(v1mocks.NewErrorMounter()))
cfg.Verify = true
err := cfg.Sanitize()
Expect(err).ShouldNot(HaveOccurred())
})
})
Describe("InstallSpec", func() {
var spec *v1.InstallSpec
BeforeEach(func() {
cfg := elementalConfig.NewConfig(elementalConfig.WithMounter(v1mocks.NewErrorMounter()))
spec = elementalConfig.NewInstallSpec(cfg)
})
Describe("sanitize", func() {
It("runs method", func() {
Expect(spec.Partitions.EFI).To(BeNil())
Expect(spec.Active.Source.IsEmpty()).To(BeTrue())
// Creates firmware partitions
spec.Active.Source = v1.NewDirSrc("/dir")
spec.Firmware = v1.EFI
err := spec.Sanitize()
Expect(err).ShouldNot(HaveOccurred())
Expect(spec.Partitions.EFI).NotTo(BeNil())
// Sets recovery image file to squashfs file
spec.Recovery.FS = constants.SquashFs
err = spec.Sanitize()
Expect(err).ShouldNot(HaveOccurred())
Expect(spec.Recovery.File).To(ContainSubstring(constants.RecoverySquashFile))
// Sets recovery image file to img file
spec.Recovery.FS = constants.LinuxImgFs
err = spec.Sanitize()
Expect(err).ShouldNot(HaveOccurred())
Expect(spec.Recovery.File).To(ContainSubstring(constants.RecoveryImgFile))
// Fails without state partition
spec.Partitions.State = nil
err = spec.Sanitize()
Expect(err).Should(HaveOccurred())
// Fails without an install source
spec.Active.Source = v1.NewEmptySrc()
err = spec.Sanitize()
Expect(err).Should(HaveOccurred())
})
Describe("with extra partitions", func() {
BeforeEach(func() {
// Set a source for the install
spec.Active.Source = v1.NewDirSrc("/dir")
})
It("fails if persistent and an extra partition have size == 0", func() {
spec.ExtraPartitions = append(spec.ExtraPartitions, &v1.Partition{Size: 0})
err := spec.Sanitize()
Expect(err).Should(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("both persistent partition and extra partitions have size set to 0"))
})
It("fails if more than one extra partition has size == 0", func() {
spec.Partitions.Persistent.Size = 10
spec.ExtraPartitions = append(spec.ExtraPartitions, &v1.Partition{Name: "1", Size: 0})
spec.ExtraPartitions = append(spec.ExtraPartitions, &v1.Partition{Name: "2", Size: 0})
err := spec.Sanitize()
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("more than one extra partition has its size set to 0"))
})
It("does not fail if persistent size is > 0 and an extra partition has size == 0", func() {
spec.ExtraPartitions = append(spec.ExtraPartitions, &v1.Partition{Size: 0})
spec.Partitions.Persistent.Size = 10
err := spec.Sanitize()
Expect(err).ToNot(HaveOccurred())
})
})
})
})
Describe("ResetSpec", func() {
It("runs sanitize method", func() {
spec := &v1.ResetSpec{
Active: v1.Image{
Source: v1.NewDirSrc("/dir"),
},
Partitions: v1.ElementalPartitions{
State: &v1.Partition{
MountPoint: "mountpoint",
},
},
}
err := spec.Sanitize()
Expect(err).ShouldNot(HaveOccurred())
//Fails on missing state partition
spec.Partitions.State = nil
err = spec.Sanitize()
Expect(err).Should(HaveOccurred())
//Fails on empty source
spec.Active.Source = v1.NewEmptySrc()
err = spec.Sanitize()
Expect(err).Should(HaveOccurred())
})
})
Describe("UpgradeSpec", func() {
It("runs sanitize method", func() {
spec := &v1.UpgradeSpec{
Active: v1.Image{
Source: v1.NewDirSrc("/dir"),
},
Recovery: v1.Image{
Source: v1.NewDirSrc("/dir"),
},
Partitions: v1.ElementalPartitions{
State: &v1.Partition{
MountPoint: "mountpoint",
},
Recovery: &v1.Partition{
MountPoint: "mountpoint",
},
},
}
err := spec.Sanitize()
Expect(err).ShouldNot(HaveOccurred())
//Fails on empty source for active upgrade
spec.Active.Source = v1.NewEmptySrc()
err = spec.Sanitize()
Expect(err).Should(HaveOccurred())
//Fails on missing state partition for active upgrade
spec.Partitions.State = nil
err = spec.Sanitize()
Expect(err).Should(HaveOccurred())
//Fails on empty source for recovery upgrade
spec.RecoveryUpgrade = true
spec.Recovery.Source = v1.NewEmptySrc()
err = spec.Sanitize()
Expect(err).Should(HaveOccurred())
//Fails on missing recovery partition for recovery upgrade
spec.Partitions.Recovery = nil
err = spec.Sanitize()
Expect(err).Should(HaveOccurred())
})
})
}) })

View File

@ -19,12 +19,13 @@ package utils
import ( import (
"errors" "errors"
"fmt" "fmt"
agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config"
"github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
"os" "os"
"sort" "sort"
"strings" "strings"
"github.com/kairos-io/kairos-agent/v2/pkg/constants" "github.com/kairos-io/kairos-agent/v2/pkg/constants"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
) )
// Chroot represents the struct that will allow us to run commands inside a given chroot // Chroot represents the struct that will allow us to run commands inside a given chroot
@ -33,10 +34,10 @@ type Chroot struct {
defaultMounts []string defaultMounts []string
extraMounts map[string]string extraMounts map[string]string
activeMounts []string activeMounts []string
config *v1.Config config *agentConfig.Config
} }
func NewChroot(path string, config *v1.Config) *Chroot { func NewChroot(path string, config *agentConfig.Config) *Chroot {
return &Chroot{ return &Chroot{
path: path, path: path,
defaultMounts: []string{"/dev", "/dev/pts", "/proc", "/sys"}, defaultMounts: []string{"/dev", "/dev/pts", "/proc", "/sys"},
@ -47,7 +48,7 @@ func NewChroot(path string, config *v1.Config) *Chroot {
} }
// ChrootedCallback runs the given callback in a chroot environment // ChrootedCallback runs the given callback in a chroot environment
func ChrootedCallback(cfg *v1.Config, path string, bindMounts map[string]string, callback func() error) error { func ChrootedCallback(cfg *agentConfig.Config, path string, bindMounts map[string]string, callback func() error) error {
chroot := NewChroot(path, cfg) chroot := NewChroot(path, cfg)
chroot.SetExtraMounts(bindMounts) chroot.SetExtraMounts(bindMounts)
return chroot.RunCallback(callback) return chroot.RunCallback(callback)
@ -78,7 +79,7 @@ func (c *Chroot) Prepare() error {
for _, mnt := range c.defaultMounts { for _, mnt := range c.defaultMounts {
mountPoint := fmt.Sprintf("%s%s", strings.TrimSuffix(c.path, "/"), mnt) mountPoint := fmt.Sprintf("%s%s", strings.TrimSuffix(c.path, "/"), mnt)
err = MkdirAll(c.config.Fs, mountPoint, constants.DirPerm) err = fsutils.MkdirAll(c.config.Fs, mountPoint, constants.DirPerm)
if err != nil { if err != nil {
return err return err
} }
@ -95,7 +96,7 @@ func (c *Chroot) Prepare() error {
sort.Strings(keys) sort.Strings(keys)
for _, k := range keys { for _, k := range keys {
mountPoint := fmt.Sprintf("%s%s", strings.TrimSuffix(c.path, "/"), c.extraMounts[k]) mountPoint := fmt.Sprintf("%s%s", strings.TrimSuffix(c.path, "/"), c.extraMounts[k])
err = MkdirAll(c.config.Fs, mountPoint, constants.DirPerm) err = fsutils.MkdirAll(c.config.Fs, mountPoint, constants.DirPerm)
if err != nil { if err != nil {
return err return err
} }

View File

@ -20,6 +20,9 @@ import (
"crypto/sha256" "crypto/sha256"
"errors" "errors"
"fmt" "fmt"
agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config"
"github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
"github.com/kairos-io/kairos-agent/v2/pkg/utils/partitions"
"io" "io"
random "math/rand" random "math/rand"
"net/url" "net/url"
@ -42,12 +45,6 @@ func CommandExists(command string) bool {
return err == nil return err == nil
} }
// BootedFrom will check if we are booting from the given label
func BootedFrom(runner v1.Runner, label string) bool {
out, _ := runner.Run("cat", "/proc/cmdline")
return strings.Contains(string(out), label)
}
// GetDeviceByLabel will try to return the device that matches the given label. // GetDeviceByLabel will try to return the device that matches the given label.
// attempts value sets the number of attempts to find the device, it // attempts value sets the number of attempts to find the device, it
// waits a second between attempts. // waits a second between attempts.
@ -64,7 +61,7 @@ func GetDeviceByLabel(runner v1.Runner, label string, attempts int) (string, err
func GetFullDeviceByLabel(runner v1.Runner, label string, attempts int) (*v1.Partition, error) { func GetFullDeviceByLabel(runner v1.Runner, label string, attempts int) (*v1.Partition, error) {
for tries := 0; tries < attempts; tries++ { for tries := 0; tries < attempts; tries++ {
_, _ = runner.Run("udevadm", "settle") _, _ = runner.Run("udevadm", "settle")
parts, err := GetAllPartitions() parts, err := partitions.GetAllPartitions()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -91,7 +88,7 @@ func ConcatFiles(fs v1.FS, sources []string, target string) (err error) {
if len(sources) == 0 { if len(sources) == 0 {
return fmt.Errorf("Empty sources list") return fmt.Errorf("Empty sources list")
} }
if dir, _ := IsDir(fs, target); dir { if dir, _ := fsutils.IsDir(fs, target); dir {
target = filepath.Join(target, filepath.Base(sources[0])) target = filepath.Join(target, filepath.Base(sources[0]))
} }
@ -129,18 +126,18 @@ func ConcatFiles(fs v1.FS, sources []string, target string) (err error) {
// Copies source file to target file using Fs interface // Copies source file to target file using Fs interface
func CreateDirStructure(fs v1.FS, target string) error { func CreateDirStructure(fs v1.FS, target string) error {
for _, dir := range []string{"/run", "/dev", "/boot", "/usr/local", "/oem"} { for _, dir := range []string{"/run", "/dev", "/boot", "/usr/local", "/oem"} {
err := MkdirAll(fs, filepath.Join(target, dir), cnst.DirPerm) err := fsutils.MkdirAll(fs, filepath.Join(target, dir), cnst.DirPerm)
if err != nil { if err != nil {
return err return err
} }
} }
for _, dir := range []string{"/proc", "/sys"} { for _, dir := range []string{"/proc", "/sys"} {
err := MkdirAll(fs, filepath.Join(target, dir), cnst.NoWriteDirPerm) err := fsutils.MkdirAll(fs, filepath.Join(target, dir), cnst.NoWriteDirPerm)
if err != nil { if err != nil {
return err return err
} }
} }
err := MkdirAll(fs, filepath.Join(target, "/tmp"), cnst.DirPerm) err := fsutils.MkdirAll(fs, filepath.Join(target, "/tmp"), cnst.DirPerm)
if err != nil { if err != nil {
return err return err
} }
@ -245,7 +242,7 @@ func CosignVerify(fs v1.FS, runner v1.Runner, image string, publicKey string, de
args = append(args, image) args = append(args, image)
// Give each cosign its own tuf dir so it doesnt collide with others accessing the same files at the same time // Give each cosign its own tuf dir so it doesnt collide with others accessing the same files at the same time
tmpDir, err := TempDir(fs, "", "cosign-tuf-") tmpDir, err := fsutils.TempDir(fs, "", "cosign-tuf-")
if err != nil { if err != nil {
return "", err return "", err
} }
@ -301,7 +298,7 @@ func LoadEnvFile(fs v1.FS, file string) (map[string]string, error) {
return envMap, err return envMap, err
} }
func IsMounted(config *v1.Config, part *v1.Partition) (bool, error) { func IsMounted(config *agentConfig.Config, part *v1.Partition) (bool, error) {
if part == nil { if part == nil {
return false, fmt.Errorf("nil partition") return false, fmt.Errorf("nil partition")
} }
@ -318,37 +315,11 @@ func IsMounted(config *v1.Config, part *v1.Partition) (bool, error) {
return !notMnt, nil return !notMnt, nil
} }
// HasSquashedRecovery returns true if a squashed recovery image is found in the system
func HasSquashedRecovery(config *v1.Config, recovery *v1.Partition) (squashed bool, err error) {
mountPoint := recovery.MountPoint
if mnt, _ := IsMounted(config, recovery); !mnt {
tmpMountDir, err := TempDir(config.Fs, "", "elemental")
if err != nil {
config.Logger.Errorf("failed creating temporary dir: %v", err)
return false, err
}
defer config.Fs.RemoveAll(tmpMountDir) // nolint:errcheck
err = config.Mounter.Mount(recovery.Path, tmpMountDir, "auto", []string{})
if err != nil {
config.Logger.Errorf("failed mounting recovery partition: %v", err)
return false, err
}
mountPoint = tmpMountDir
defer func() {
err = config.Mounter.Unmount(tmpMountDir)
if err != nil {
squashed = false
}
}()
}
return Exists(config.Fs, filepath.Join(mountPoint, "cOS", cnst.RecoverySquashFile))
}
// GetTempDir returns the dir for storing related temporal files // GetTempDir returns the dir for storing related temporal files
// It will respect TMPDIR and use that if exists, fallback to try the persistent partition if its mounted // It will respect TMPDIR and use that if exists, fallback to try the persistent partition if its mounted
// and finally the default /tmp/ dir // and finally the default /tmp/ dir
// suffix is what is appended to the dir name elemental-suffix. If empty it will randomly generate a number // suffix is what is appended to the dir name elemental-suffix. If empty it will randomly generate a number
func GetTempDir(config *v1.Config, suffix string) string { func GetTempDir(config *agentConfig.Config, suffix string) string {
// if we got a TMPDIR var, respect and use that // if we got a TMPDIR var, respect and use that
if suffix == "" { if suffix == "" {
random.Seed(time.Now().UnixNano()) random.Seed(time.Now().UnixNano())
@ -360,7 +331,7 @@ func GetTempDir(config *v1.Config, suffix string) string {
config.Logger.Debugf("Got tmpdir from TMPDIR var: %s", dir) config.Logger.Debugf("Got tmpdir from TMPDIR var: %s", dir)
return filepath.Join(dir, elementalTmpDir) return filepath.Join(dir, elementalTmpDir)
} }
parts, err := GetAllPartitions() parts, err := partitions.GetAllPartitions()
if err != nil { if err != nil {
config.Logger.Debug("Could not get partitions, defaulting to /tmp") config.Logger.Debug("Could not get partitions, defaulting to /tmp")
return filepath.Join("/", "tmp", elementalTmpDir) return filepath.Join("/", "tmp", elementalTmpDir)
@ -414,7 +385,7 @@ func IsHTTPURI(uri string) (bool, error) {
// GetSource copies given source to destination, if source is a local path it simply // GetSource copies given source to destination, if source is a local path it simply
// copies files, if source is a remote URL it tries to download URL to destination. // copies files, if source is a remote URL it tries to download URL to destination.
func GetSource(config *v1.Config, source string, destination string) error { func GetSource(config *agentConfig.Config, source string, destination string) error {
local, err := IsLocalURI(source) local, err := IsLocalURI(source)
if err != nil { if err != nil {
config.Logger.Errorf("Not a valid url: %s", source) config.Logger.Errorf("Not a valid url: %s", source)
@ -484,7 +455,7 @@ func FindFileWithPrefix(fs v1.FS, path string, prefixes ...string) (string, erro
if !filepath.IsAbs(found) { if !filepath.IsAbs(found) {
found = filepath.Join(path, found) found = filepath.Join(path, found)
} }
if exists, _ := Exists(fs, found); exists { if exists, _ := fsutils.Exists(fs, found); exists {
return found, nil return found, nil
} }
} }
@ -497,19 +468,6 @@ func FindFileWithPrefix(fs v1.FS, path string, prefixes ...string) (string, erro
return "", fmt.Errorf("No file found with prefixes: %v", prefixes) return "", fmt.Errorf("No file found with prefixes: %v", prefixes)
} }
var errInvalidArch = fmt.Errorf("invalid arch")
func GolangArchToArch(arch string) (string, error) {
switch strings.ToLower(arch) {
case cnst.ArchAmd64:
return cnst.Archx86, nil
case cnst.ArchArm64:
return cnst.ArchArm64, nil
default:
return "", errInvalidArch
}
}
// CalcFileChecksum opens the given file and returns the sha256 checksum of it. // CalcFileChecksum opens the given file and returns the sha256 checksum of it.
func CalcFileChecksum(fs v1.FS, fileName string) (string, error) { func CalcFileChecksum(fs v1.FS, fileName string) (string, error) {
f, err := fs.Open(fileName) f, err := fs.Open(fileName)

View File

@ -17,7 +17,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package utils package fsutils
import ( import (
"io/fs" "io/fs"

View File

@ -18,21 +18,22 @@ package utils
import ( import (
"fmt" "fmt"
agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config"
"github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
"io/fs" "io/fs"
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/kairos-io/kairos-agent/v2/pkg/constants" "github.com/kairos-io/kairos-agent/v2/pkg/constants"
cnst "github.com/kairos-io/kairos-agent/v2/pkg/constants" cnst "github.com/kairos-io/kairos-agent/v2/pkg/constants"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
) )
// Grub is the struct that will allow us to install grub to the target device // Grub is the struct that will allow us to install grub to the target device
type Grub struct { type Grub struct {
config *v1.Config config *agentConfig.Config
} }
func NewGrub(config *v1.Config) *Grub { func NewGrub(config *agentConfig.Config) *Grub {
g := &Grub{ g := &Grub{
config: config, config: config,
} }
@ -71,7 +72,7 @@ func (g Grub) Install(target, rootDir, bootDir, grubConf, tty string, efi bool,
// Select the proper dir for grub - this assumes that we previously run a grub install command, which is not the case in EFI // Select the proper dir for grub - this assumes that we previously run a grub install command, which is not the case in EFI
// In the EFI case we default to grub2 // In the EFI case we default to grub2
if ok, _ := IsDir(g.config.Fs, filepath.Join(bootDir, "grub")); ok { if ok, _ := fsutils.IsDir(g.config.Fs, filepath.Join(bootDir, "grub")); ok {
systemgrub = "grub" systemgrub = "grub"
} }
} }
@ -86,7 +87,7 @@ func (g Grub) Install(target, rootDir, bootDir, grubConf, tty string, efi bool,
} }
// Create Needed dir under state partition to store the grub.cfg and any needed modules // Create Needed dir under state partition to store the grub.cfg and any needed modules
err = MkdirAll(g.config.Fs, filepath.Join(bootDir, fmt.Sprintf("%s/%s-efi", systemgrub, g.config.Arch)), cnst.DirPerm) err = fsutils.MkdirAll(g.config.Fs, filepath.Join(bootDir, fmt.Sprintf("%s/%s-efi", systemgrub, g.config.Arch)), cnst.DirPerm)
if err != nil { if err != nil {
return fmt.Errorf("error creating grub dir: %s", err) return fmt.Errorf("error creating grub dir: %s", err)
} }
@ -108,7 +109,7 @@ func (g Grub) Install(target, rootDir, bootDir, grubConf, tty string, efi bool,
} }
} }
ttyExists, _ := Exists(g.config.Fs, fmt.Sprintf("/dev/%s", tty)) ttyExists, _ := fsutils.Exists(g.config.Fs, fmt.Sprintf("/dev/%s", tty))
if ttyExists && tty != "" && tty != "console" && tty != constants.DefaultTty { if ttyExists && tty != "" && tty != "console" && tty != constants.DefaultTty {
// We need to add a tty to the grub file // We need to add a tty to the grub file
@ -134,7 +135,7 @@ func (g Grub) Install(target, rootDir, bootDir, grubConf, tty string, efi bool,
g.config.Logger.Infof("Generating grub files for efi on %s", target) g.config.Logger.Infof("Generating grub files for efi on %s", target)
var foundModules bool var foundModules bool
for _, m := range []string{"loopback.mod", "squash4.mod", "xzio.mod", "gzio.mod"} { for _, m := range []string{"loopback.mod", "squash4.mod", "xzio.mod", "gzio.mod"} {
err = WalkDirFs(g.config.Fs, rootDir, func(path string, d fs.DirEntry, err error) error { err = fsutils.WalkDirFs(g.config.Fs, rootDir, func(path string, d fs.DirEntry, err error) error {
if err != nil { if err != nil {
return err return err
} }
@ -159,7 +160,7 @@ func (g Grub) Install(target, rootDir, bootDir, grubConf, tty string, efi bool,
} }
} }
err = MkdirAll(g.config.Fs, filepath.Join(cnst.EfiDir, "EFI/boot/"), cnst.DirPerm) err = fsutils.MkdirAll(g.config.Fs, filepath.Join(cnst.EfiDir, "EFI/boot/"), cnst.DirPerm)
if err != nil { if err != nil {
g.config.Logger.Errorf("Error creating dirs: %s", err) g.config.Logger.Errorf("Error creating dirs: %s", err)
return err return err

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package utils package partitions
import ( import (
"fmt" "fmt"

View File

@ -18,11 +18,12 @@ package utils
import ( import (
"fmt" "fmt"
agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config"
"github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
"strings" "strings"
"github.com/hashicorp/go-multierror" "github.com/hashicorp/go-multierror"
"github.com/kairos-io/kairos-agent/v2/pkg/constants" "github.com/kairos-io/kairos-agent/v2/pkg/constants"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
"github.com/mudler/yip/pkg/schema" "github.com/mudler/yip/pkg/schema"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@ -43,7 +44,7 @@ func onlyYAMLPartialErrors(er error) bool {
return true return true
} }
func checkYAMLError(cfg *v1.Config, allErrors, err error) error { func checkYAMLError(cfg *agentConfig.Config, allErrors, err error) error {
if !onlyYAMLPartialErrors(err) { if !onlyYAMLPartialErrors(err) {
// here we absorb errors only if are related to YAML unmarshalling // here we absorb errors only if are related to YAML unmarshalling
// As cmdline is parsed out as a yaml file // As cmdline is parsed out as a yaml file
@ -57,7 +58,7 @@ func checkYAMLError(cfg *v1.Config, allErrors, err error) error {
} }
// RunStage will run yip // RunStage will run yip
func RunStage(cfg *v1.Config, stage string) error { func RunStage(cfg *agentConfig.Config, stage string) error {
var cmdLineYipURI string var cmdLineYipURI string
var allErrors error var allErrors error
var cloudInitPaths []string var cloudInitPaths []string
@ -67,7 +68,7 @@ func RunStage(cfg *v1.Config, stage string) error {
// Make sure cloud init path specified are existing in the system // Make sure cloud init path specified are existing in the system
for _, cp := range cloudInitPaths { for _, cp := range cloudInitPaths {
err := MkdirAll(cfg.Fs, cp, constants.DirPerm) err := fsutils.MkdirAll(cfg.Fs, cp, constants.DirPerm)
if err != nil { if err != nil {
cfg.Logger.Debugf("Failed creating cloud-init config path: %s %s", cp, err.Error()) cfg.Logger.Debugf("Failed creating cloud-init config path: %s %s", cp, err.Error())
} }

View File

@ -19,10 +19,11 @@ package utils_test
import ( import (
"bytes" "bytes"
"fmt" "fmt"
agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config"
"github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
"os" "os"
"github.com/kairos-io/kairos-agent/v2/pkg/cloudinit" "github.com/kairos-io/kairos-agent/v2/pkg/cloudinit"
conf "github.com/kairos-io/kairos-agent/v2/pkg/elementalConfig"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
"github.com/kairos-io/kairos-agent/v2/pkg/utils" "github.com/kairos-io/kairos-agent/v2/pkg/utils"
v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks" v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks"
@ -41,7 +42,7 @@ func writeCmdline(s string, fs v1.FS) error {
} }
var _ = Describe("run stage", Label("RunStage"), func() { var _ = Describe("run stage", Label("RunStage"), func() {
var config *v1.Config var config *agentConfig.Config
var runner *v1mock.FakeRunner var runner *v1mock.FakeRunner
var logger v1.Logger var logger v1.Logger
var syscall *v1mock.FakeSyscall var syscall *v1mock.FakeSyscall
@ -61,13 +62,13 @@ var _ = Describe("run stage", Label("RunStage"), func() {
logger.SetLevel(log.DebugLevel) logger.SetLevel(log.DebugLevel)
fs, cleanup, _ = vfst.NewTestFS(nil) fs, cleanup, _ = vfst.NewTestFS(nil)
config = conf.NewConfig( config = agentConfig.NewConfig(
conf.WithFs(fs), agentConfig.WithFs(fs),
conf.WithRunner(runner), agentConfig.WithRunner(runner),
conf.WithLogger(logger), agentConfig.WithLogger(logger),
conf.WithMounter(mounter), agentConfig.WithMounter(mounter),
conf.WithSyscall(syscall), agentConfig.WithSyscall(syscall),
conf.WithClient(client), agentConfig.WithClient(client),
) )
config.CloudInitRunner = cloudinit.NewYipCloudInitRunner(config.Logger, config.Runner, fs) config.CloudInitRunner = cloudinit.NewYipCloudInitRunner(config.Logger, config.Runner, fs)
@ -75,7 +76,7 @@ var _ = Describe("run stage", Label("RunStage"), func() {
AfterEach(func() { cleanup() }) AfterEach(func() { cleanup() })
It("fails if strict mode is enabled", Label("strict"), func() { It("fails if strict mode is enabled", Label("strict"), func() {
d, err := utils.TempDir(fs, "", "elemental") d, err := fsutils.TempDir(fs, "", "elemental")
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
_ = fs.WriteFile(fmt.Sprintf("%s/test.yaml", d), []byte("stages: [foo,bar]"), os.ModePerm) _ = fs.WriteFile(fmt.Sprintf("%s/test.yaml", d), []byte("stages: [foo,bar]"), os.ModePerm)
config.Strict = true config.Strict = true
@ -92,7 +93,7 @@ var _ = Describe("run stage", Label("RunStage"), func() {
}) })
It("Goes over extra paths", func() { It("Goes over extra paths", func() {
d, err := utils.TempDir(fs, "", "elemental") d, err := fsutils.TempDir(fs, "", "elemental")
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
config.Logger.SetLevel(log.DebugLevel) config.Logger.SetLevel(log.DebugLevel)
config.CloudInitPaths = []string{d} config.CloudInitPaths = []string{d}
@ -105,7 +106,7 @@ var _ = Describe("run stage", Label("RunStage"), func() {
}) })
It("parses cmdline uri", func() { It("parses cmdline uri", func() {
d, _ := utils.TempDir(fs, "", "elemental") d, _ := fsutils.TempDir(fs, "", "elemental")
_ = fs.WriteFile(fmt.Sprintf("%s/test.yaml", d), []byte{}, os.ModePerm) _ = fs.WriteFile(fmt.Sprintf("%s/test.yaml", d), []byte{}, os.ModePerm)
writeCmdline(fmt.Sprintf("cos.setup=%s/test.yaml", d), fs) writeCmdline(fmt.Sprintf("cos.setup=%s/test.yaml", d), fs)

View File

@ -20,6 +20,8 @@ import (
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
"github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
"github.com/kairos-io/kairos-agent/v2/pkg/utils/partitions"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
@ -27,8 +29,8 @@ import (
"github.com/jaypipes/ghw/pkg/block" "github.com/jaypipes/ghw/pkg/block"
agentConfig "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/constants"
conf "github.com/kairos-io/kairos-agent/v2/pkg/elementalConfig"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
"github.com/kairos-io/kairos-agent/v2/pkg/utils" "github.com/kairos-io/kairos-agent/v2/pkg/utils"
v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks" v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks"
@ -47,7 +49,7 @@ func getNamesFromListFiles(list []os.FileInfo) []string {
} }
var _ = Describe("Utils", Label("utils"), func() { var _ = Describe("Utils", Label("utils"), func() {
var config *v1.Config var config *agentConfig.Config
var runner *v1mock.FakeRunner var runner *v1mock.FakeRunner
var logger v1.Logger var logger v1.Logger
var syscall *v1mock.FakeSyscall var syscall *v1mock.FakeSyscall
@ -70,13 +72,13 @@ var _ = Describe("Utils", Label("utils"), func() {
fs.Mkdir("/run", constants.DirPerm) fs.Mkdir("/run", constants.DirPerm)
fs.Mkdir("/etc", constants.DirPerm) fs.Mkdir("/etc", constants.DirPerm)
config = conf.NewConfig( config = agentConfig.NewConfig(
conf.WithFs(fs), agentConfig.WithFs(fs),
conf.WithRunner(runner), agentConfig.WithRunner(runner),
conf.WithLogger(logger), agentConfig.WithLogger(logger),
conf.WithMounter(mounter), agentConfig.WithMounter(mounter),
conf.WithSyscall(syscall), agentConfig.WithSyscall(syscall),
conf.WithClient(client), agentConfig.WithClient(client),
) )
}) })
AfterEach(func() { cleanup() }) AfterEach(func() { cleanup() })
@ -176,16 +178,6 @@ var _ = Describe("Utils", Label("utils"), func() {
}) })
}) })
}) })
Describe("TestBootedFrom", Label("BootedFrom"), func() {
It("returns true if we are booting from label FAKELABEL", func() {
runner.ReturnValue = []byte("")
Expect(utils.BootedFrom(runner, "FAKELABEL")).To(BeFalse())
})
It("returns false if we are not booting from label FAKELABEL", func() {
runner.ReturnValue = []byte("FAKELABEL")
Expect(utils.BootedFrom(runner, "FAKELABEL")).To(BeTrue())
})
})
Describe("GetDeviceByLabel", Label("lsblk", "partitions"), func() { Describe("GetDeviceByLabel", Label("lsblk", "partitions"), func() {
var cmds [][]string var cmds [][]string
BeforeEach(func() { BeforeEach(func() {
@ -246,7 +238,7 @@ var _ = Describe("Utils", Label("utils"), func() {
ghwTest.Clean() ghwTest.Clean()
}) })
It("returns all found partitions", func() { It("returns all found partitions", func() {
parts, err := utils.GetAllPartitions() parts, err := partitions.GetAllPartitions()
Expect(err).To(BeNil()) Expect(err).To(BeNil())
var partNames []string var partNames []string
for _, p := range parts { for _, p := range parts {
@ -277,17 +269,17 @@ var _ = Describe("Utils", Label("utils"), func() {
ghwTest.Clean() ghwTest.Clean()
}) })
It("returns found device with plain partition device", func() { It("returns found device with plain partition device", func() {
pFS, err := utils.GetPartitionFS("device1") pFS, err := partitions.GetPartitionFS("device1")
Expect(err).To(BeNil()) Expect(err).To(BeNil())
Expect(pFS).To(Equal("xfs")) Expect(pFS).To(Equal("xfs"))
}) })
It("returns found device with full partition device", func() { It("returns found device with full partition device", func() {
pFS, err := utils.GetPartitionFS("/dev/device1") pFS, err := partitions.GetPartitionFS("/dev/device1")
Expect(err).To(BeNil()) Expect(err).To(BeNil())
Expect(pFS).To(Equal("xfs")) Expect(pFS).To(Equal("xfs"))
}) })
It("fails if no partition is found", func() { It("fails if no partition is found", func() {
_, err := utils.GetPartitionFS("device2") _, err := partitions.GetPartitionFS("device2")
Expect(err).NotTo(BeNil()) Expect(err).NotTo(BeNil())
}) })
}) })
@ -377,40 +369,40 @@ var _ = Describe("Utils", Label("utils"), func() {
}) })
Describe("CopyFile", Label("CopyFile"), func() { Describe("CopyFile", Label("CopyFile"), func() {
It("Copies source file to target file", func() { It("Copies source file to target file", func() {
err := utils.MkdirAll(fs, "/some", constants.DirPerm) err := fsutils.MkdirAll(fs, "/some", constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
_, err = fs.Create("/some/file") _, err = fs.Create("/some/file")
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
_, err = fs.Stat("/some/otherfile") _, err = fs.Stat("/some/otherfile")
Expect(err).Should(HaveOccurred()) Expect(err).Should(HaveOccurred())
Expect(utils.CopyFile(fs, "/some/file", "/some/otherfile")).ShouldNot(HaveOccurred()) Expect(utils.CopyFile(fs, "/some/file", "/some/otherfile")).ShouldNot(HaveOccurred())
e, err := utils.Exists(fs, "/some/otherfile") e, err := fsutils.Exists(fs, "/some/otherfile")
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
Expect(e).To(BeTrue()) Expect(e).To(BeTrue())
}) })
It("Copies source file to target folder", func() { It("Copies source file to target folder", func() {
err := utils.MkdirAll(fs, "/some", constants.DirPerm) err := fsutils.MkdirAll(fs, "/some", constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
err = utils.MkdirAll(fs, "/someotherfolder", constants.DirPerm) err = fsutils.MkdirAll(fs, "/someotherfolder", constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
_, err = fs.Create("/some/file") _, err = fs.Create("/some/file")
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
_, err = fs.Stat("/someotherfolder/file") _, err = fs.Stat("/someotherfolder/file")
Expect(err).Should(HaveOccurred()) Expect(err).Should(HaveOccurred())
Expect(utils.CopyFile(fs, "/some/file", "/someotherfolder")).ShouldNot(HaveOccurred()) Expect(utils.CopyFile(fs, "/some/file", "/someotherfolder")).ShouldNot(HaveOccurred())
e, err := utils.Exists(fs, "/someotherfolder/file") e, err := fsutils.Exists(fs, "/someotherfolder/file")
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
Expect(e).To(BeTrue()) Expect(e).To(BeTrue())
}) })
It("Fails to open non existing file", func() { It("Fails to open non existing file", func() {
err := utils.MkdirAll(fs, "/some", constants.DirPerm) err := fsutils.MkdirAll(fs, "/some", constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
Expect(utils.CopyFile(fs, "/some/file", "/some/otherfile")).NotTo(BeNil()) Expect(utils.CopyFile(fs, "/some/file", "/some/otherfile")).NotTo(BeNil())
_, err = fs.Stat("/some/otherfile") _, err = fs.Stat("/some/otherfile")
Expect(err).NotTo(BeNil()) Expect(err).NotTo(BeNil())
}) })
It("Fails to copy on non writable target", func() { It("Fails to copy on non writable target", func() {
err := utils.MkdirAll(fs, "/some", constants.DirPerm) err := fsutils.MkdirAll(fs, "/some", constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
fs.Create("/some/file") fs.Create("/some/file")
_, err = fs.Stat("/some/otherfile") _, err = fs.Stat("/some/otherfile")
@ -448,13 +440,13 @@ var _ = Describe("Utils", Label("utils"), func() {
}) })
Describe("SyncData", Label("SyncData"), func() { Describe("SyncData", Label("SyncData"), func() {
It("Copies all files from source to target", func() { It("Copies all files from source to target", func() {
sourceDir, err := utils.TempDir(fs, "", "elementalsource") sourceDir, err := fsutils.TempDir(fs, "", "elementalsource")
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
destDir, err := utils.TempDir(fs, "", "elementaltarget") destDir, err := fsutils.TempDir(fs, "", "elementaltarget")
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
for i := 0; i < 5; i++ { for i := 0; i < 5; i++ {
_, _ = utils.TempFile(fs, sourceDir, "file*") _, _ = fsutils.TempFile(fs, sourceDir, "file*")
} }
Expect(utils.SyncData(logger, realRunner, fs, sourceDir, destDir)).To(BeNil()) Expect(utils.SyncData(logger, realRunner, fs, sourceDir, destDir)).To(BeNil())
@ -473,19 +465,19 @@ var _ = Describe("Utils", Label("utils"), func() {
}) })
It("Copies all files from source to target respecting excludes", func() { It("Copies all files from source to target respecting excludes", func() {
sourceDir, err := utils.TempDir(fs, "", "elementalsource") sourceDir, err := fsutils.TempDir(fs, "", "elementalsource")
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
destDir, err := utils.TempDir(fs, "", "elementaltarget") destDir, err := fsutils.TempDir(fs, "", "elementaltarget")
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
utils.MkdirAll(fs, filepath.Join(sourceDir, "host"), constants.DirPerm) fsutils.MkdirAll(fs, filepath.Join(sourceDir, "host"), constants.DirPerm)
utils.MkdirAll(fs, filepath.Join(sourceDir, "run"), constants.DirPerm) fsutils.MkdirAll(fs, filepath.Join(sourceDir, "run"), constants.DirPerm)
// /tmp/run would be excluded as well, as we define an exclude without the "/" prefix // /tmp/run would be excluded as well, as we define an exclude without the "/" prefix
utils.MkdirAll(fs, filepath.Join(sourceDir, "tmp", "run"), constants.DirPerm) fsutils.MkdirAll(fs, filepath.Join(sourceDir, "tmp", "run"), constants.DirPerm)
for i := 0; i < 5; i++ { for i := 0; i < 5; i++ {
_, _ = utils.TempFile(fs, sourceDir, "file*") _, _ = fsutils.TempFile(fs, sourceDir, "file*")
} }
Expect(utils.SyncData(logger, realRunner, fs, sourceDir, destDir, "host", "run")).To(BeNil()) Expect(utils.SyncData(logger, realRunner, fs, sourceDir, destDir, "host", "run")).To(BeNil())
@ -512,19 +504,19 @@ var _ = Describe("Utils", Label("utils"), func() {
Expect(destNames).To(Equal(expected)) Expect(destNames).To(Equal(expected))
// /tmp/run is not copied over // /tmp/run is not copied over
Expect(utils.Exists(fs, filepath.Join(destDir, "tmp", "run"))).To(BeFalse()) Expect(fsutils.Exists(fs, filepath.Join(destDir, "tmp", "run"))).To(BeFalse())
}) })
It("Copies all files from source to target respecting excludes with '/' prefix", func() { It("Copies all files from source to target respecting excludes with '/' prefix", func() {
sourceDir, err := utils.TempDir(fs, "", "elementalsource") sourceDir, err := fsutils.TempDir(fs, "", "elementalsource")
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
destDir, err := utils.TempDir(fs, "", "elementaltarget") destDir, err := fsutils.TempDir(fs, "", "elementaltarget")
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
utils.MkdirAll(fs, filepath.Join(sourceDir, "host"), constants.DirPerm) fsutils.MkdirAll(fs, filepath.Join(sourceDir, "host"), constants.DirPerm)
utils.MkdirAll(fs, filepath.Join(sourceDir, "run"), constants.DirPerm) fsutils.MkdirAll(fs, filepath.Join(sourceDir, "run"), constants.DirPerm)
utils.MkdirAll(fs, filepath.Join(sourceDir, "var", "run"), constants.DirPerm) fsutils.MkdirAll(fs, filepath.Join(sourceDir, "var", "run"), constants.DirPerm)
utils.MkdirAll(fs, filepath.Join(sourceDir, "tmp", "host"), constants.DirPerm) fsutils.MkdirAll(fs, filepath.Join(sourceDir, "tmp", "host"), constants.DirPerm)
Expect(utils.SyncData(logger, realRunner, fs, sourceDir, destDir, "/host", "/run")).To(BeNil()) Expect(utils.SyncData(logger, realRunner, fs, sourceDir, destDir, "/host", "/run")).To(BeNil())
@ -541,16 +533,16 @@ var _ = Describe("Utils", Label("utils"), func() {
// Shouldn't be the same // Shouldn't be the same
Expect(destNames).ToNot(Equal(SourceNames)) Expect(destNames).ToNot(Equal(SourceNames))
Expect(utils.Exists(fs, filepath.Join(destDir, "var", "run"))).To(BeTrue()) Expect(fsutils.Exists(fs, filepath.Join(destDir, "var", "run"))).To(BeTrue())
Expect(utils.Exists(fs, filepath.Join(destDir, "tmp", "host"))).To(BeTrue()) Expect(fsutils.Exists(fs, filepath.Join(destDir, "tmp", "host"))).To(BeTrue())
Expect(utils.Exists(fs, filepath.Join(destDir, "host"))).To(BeFalse()) Expect(fsutils.Exists(fs, filepath.Join(destDir, "host"))).To(BeFalse())
Expect(utils.Exists(fs, filepath.Join(destDir, "run"))).To(BeFalse()) Expect(fsutils.Exists(fs, filepath.Join(destDir, "run"))).To(BeFalse())
}) })
It("should not fail if dirs are empty", func() { It("should not fail if dirs are empty", func() {
sourceDir, err := utils.TempDir(fs, "", "elementalsource") sourceDir, err := fsutils.TempDir(fs, "", "elementalsource")
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
destDir, err := utils.TempDir(fs, "", "elementaltarget") destDir, err := fsutils.TempDir(fs, "", "elementaltarget")
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
Expect(utils.SyncData(logger, realRunner, fs, sourceDir, destDir)).To(BeNil()) Expect(utils.SyncData(logger, realRunner, fs, sourceDir, destDir)).To(BeNil())
}) })
@ -672,7 +664,7 @@ var _ = Describe("Utils", Label("utils"), func() {
}) })
Describe("DirSize", Label("fs"), func() { Describe("DirSize", Label("fs"), func() {
BeforeEach(func() { BeforeEach(func() {
err := utils.MkdirAll(fs, "/folder/subfolder", constants.DirPerm) err := fsutils.MkdirAll(fs, "/folder/subfolder", constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
f, err := fs.Create("/folder/file") f, err := fs.Create("/folder/file")
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
@ -684,14 +676,14 @@ var _ = Describe("Utils", Label("utils"), func() {
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
}) })
It("Returns the expected size of a test folder", func() { It("Returns the expected size of a test folder", func() {
size, err := utils.DirSize(fs, "/folder") size, err := fsutils.DirSize(fs, "/folder")
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
Expect(size).To(Equal(int64(3072))) Expect(size).To(Equal(int64(3072)))
}) })
}) })
Describe("FindFileWithPrefix", Label("find"), func() { Describe("FindFileWithPrefix", Label("find"), func() {
BeforeEach(func() { BeforeEach(func() {
err := utils.MkdirAll(fs, "/path/inner", constants.DirPerm) err := fsutils.MkdirAll(fs, "/path/inner", constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
_, err = fs.Create("/path/onefile") _, err = fs.Create("/path/onefile")
@ -740,7 +732,7 @@ var _ = Describe("Utils", Label("utils"), func() {
Expect(err).Should(HaveOccurred()) Expect(err).Should(HaveOccurred())
}) })
It("doesn't find any matching file in path", func() { It("doesn't find any matching file in path", func() {
utils.MkdirAll(fs, "/path", constants.DirPerm) fsutils.MkdirAll(fs, "/path", constants.DirPerm)
_, err := utils.FindFileWithPrefix(fs, "/path", "prefix", "anotherprefix") _, err := utils.FindFileWithPrefix(fs, "/path", "prefix", "anotherprefix")
Expect(err).Should(HaveOccurred()) Expect(err).Should(HaveOccurred())
}) })
@ -773,10 +765,10 @@ var _ = Describe("Utils", Label("utils"), func() {
logger.SetLevel(v1.DebugLevel()) logger.SetLevel(v1.DebugLevel())
config.Logger = logger config.Logger = logger
err := utils.MkdirAll(fs, filepath.Join(bootDir, "grub2"), constants.DirPerm) err := fsutils.MkdirAll(fs, filepath.Join(bootDir, "grub2"), constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
err = utils.MkdirAll(fs, filepath.Dir(filepath.Join(rootDir, constants.GrubConf)), constants.DirPerm) err = fsutils.MkdirAll(fs, filepath.Dir(filepath.Join(rootDir, constants.GrubConf)), constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
err = fs.WriteFile(filepath.Join(rootDir, constants.GrubConf), []byte("console=tty1"), 0644) err = fs.WriteFile(filepath.Join(rootDir, constants.GrubConf), []byte("console=tty1"), 0644)
@ -798,17 +790,17 @@ var _ = Describe("Utils", Label("utils"), func() {
}) })
It("installs with efi firmware", Label("efi"), func() { It("installs with efi firmware", Label("efi"), func() {
err := utils.MkdirAll(fs, filepath.Join(rootDir, "/usr/share/efi/x86_64/"), constants.DirPerm) err := fsutils.MkdirAll(fs, filepath.Join(rootDir, "/usr/share/efi/x86_64/"), constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
err = fs.WriteFile(filepath.Join(rootDir, "/usr/share/efi/x86_64/", constants.SignedShim), []byte(""), constants.FilePerm) err = fs.WriteFile(filepath.Join(rootDir, "/usr/share/efi/x86_64/", constants.SignedShim), []byte(""), constants.FilePerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
err = fs.WriteFile(filepath.Join(rootDir, "/usr/share/efi/x86_64/grub.efi"), []byte(""), constants.FilePerm) err = fs.WriteFile(filepath.Join(rootDir, "/usr/share/efi/x86_64/grub.efi"), []byte(""), constants.FilePerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
err = utils.MkdirAll(fs, filepath.Join(rootDir, "/x86_64/"), constants.DirPerm) err = fsutils.MkdirAll(fs, filepath.Join(rootDir, "/x86_64/"), constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
err = fs.WriteFile(filepath.Join(rootDir, "/x86_64/loopback.mod"), []byte(""), constants.FilePerm) err = fs.WriteFile(filepath.Join(rootDir, "/x86_64/loopback.mod"), []byte(""), constants.FilePerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
err = utils.MkdirAll(fs, filepath.Join(rootDir, "/etc/"), constants.DirPerm) err = fsutils.MkdirAll(fs, filepath.Join(rootDir, "/etc/"), constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
err = fs.WriteFile(filepath.Join(rootDir, "/etc/os-release"), []byte("ID=\"suse\""), constants.FilePerm) err = fs.WriteFile(filepath.Join(rootDir, "/etc/os-release"), []byte("ID=\"suse\""), constants.FilePerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
@ -839,7 +831,7 @@ var _ = Describe("Utils", Label("utils"), func() {
Expect(err.Error()).To(ContainSubstring("modules")) Expect(err.Error()).To(ContainSubstring("modules"))
}) })
It("fails with efi if no grub files exist", Label("efi"), func() { It("fails with efi if no grub files exist", Label("efi"), func() {
err := utils.MkdirAll(fs, filepath.Join(rootDir, "/x86_64/"), constants.DirPerm) err := fsutils.MkdirAll(fs, filepath.Join(rootDir, "/x86_64/"), constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
err = fs.WriteFile(filepath.Join(rootDir, "/x86_64/loopback.mod"), []byte(""), constants.FilePerm) err = fs.WriteFile(filepath.Join(rootDir, "/x86_64/loopback.mod"), []byte(""), constants.FilePerm)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
@ -993,65 +985,6 @@ var _ = Describe("Utils", Label("utils"), func() {
Expect(mnt).To(BeFalse()) Expect(mnt).To(BeFalse())
}) })
}) })
Describe("HasSquashedRecovery", Label("squashedRec"), func() {
var squashedImg string
var part *v1.Partition
BeforeEach(func() {
squashedImg = filepath.Join(constants.LiveDir, "cOS", constants.RecoverySquashFile)
part = &v1.Partition{
MountPoint: constants.LiveDir,
Path: "/some/device",
}
})
It("has squashed image from a mounted recovery", func() {
// mount recovery
err := mounter.Mount(part.Path, constants.LiveDir, "auto", []string{})
Expect(err).ShouldNot(HaveOccurred())
// create squashfs
err = utils.MkdirAll(config.Fs, filepath.Dir(squashedImg), constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred())
_, err = config.Fs.Create(squashedImg)
Expect(err).ShouldNot(HaveOccurred())
squash, err := utils.HasSquashedRecovery(config, part)
Expect(err).ShouldNot(HaveOccurred())
Expect(squash).To(BeTrue())
})
It("does not have squashed image from a mounted recovery", func() {
// mount recovery
err := mounter.Mount(part.Path, constants.LiveDir, "auto", []string{})
Expect(err).ShouldNot(HaveOccurred())
squash, err := utils.HasSquashedRecovery(config, part)
Expect(err).ShouldNot(HaveOccurred())
Expect(squash).To(BeFalse())
})
It("has squashed image from a not mounted recovery", func() {
// squashed image on temp dir
squashedImg = filepath.Join("/tmp/elemental", "cOS", constants.RecoverySquashFile)
// create squashfs
err := utils.MkdirAll(config.Fs, filepath.Dir(squashedImg), constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred())
_, err = config.Fs.Create(squashedImg)
Expect(err).ShouldNot(HaveOccurred())
squash, err := utils.HasSquashedRecovery(config, part)
Expect(err).ShouldNot(HaveOccurred())
Expect(squash).To(BeTrue())
})
It("does not have squashed image from a not mounted recovery", func() {
squash, err := utils.HasSquashedRecovery(config, part)
Expect(err).ShouldNot(HaveOccurred())
Expect(squash).To(BeFalse())
})
It("fails to mount recovery", func() {
mounter.ErrorOnMount = true
squash, err := utils.HasSquashedRecovery(config, part)
Expect(err).Should(HaveOccurred())
Expect(squash).To(BeFalse())
})
})
Describe("CleanStack", Label("CleanStack"), func() { Describe("CleanStack", Label("CleanStack"), func() {
var cleaner *utils.CleanStack var cleaner *utils.CleanStack
BeforeEach(func() { BeforeEach(func() {