From 75eda111cd58537cd34c8b757c2c121ad0351ba5 Mon Sep 17 00:00:00 2001 From: Dimitris Karakasilis Date: Mon, 12 Feb 2024 10:19:17 +0200 Subject: [PATCH 1/6] Handle error and extract code to function Signed-off-by: Dimitris Karakasilis --- pkg/uki/install.go | 63 +++++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/pkg/uki/install.go b/pkg/uki/install.go index 89071b20..73f1cb87 100644 --- a/pkg/uki/install.go +++ b/pkg/uki/install.go @@ -81,8 +81,13 @@ func (i *InstallAction) Run() (err error) { // Remove entries // Read all confs + // TODO: suffix _active etc i.cfg.Logger.Debugf("Checking for entries to remove") err = fsutils.WalkDirFs(i.cfg.Fs, filepath.Join(i.spec.Partitions.EFI.MountPoint, "loader/entries/"), func(path string, info os.DirEntry, err error) error { + if err != nil { + return err + } + i.cfg.Logger.Debugf("Checking file %s", path) if info.IsDir() { return nil @@ -90,6 +95,7 @@ func (i *InstallAction) Run() (err error) { if filepath.Ext(info.Name()) != ".conf" { return nil } + // Extract the values conf, err := utils.SystemdBootConfReader(path) if err != nil { @@ -100,32 +106,8 @@ func (i *InstallAction) Run() (err error) { if len(conf["cmdline"]) == 0 { return nil } - // Check if the cmdline matches any of the entries in the skip list - for _, entry := range i.spec.SkipEntries { - // Match the cmdline key against the entry - if strings.Contains(conf["cmdline"], entry) { - i.cfg.Logger.Debugf("Found match for %s in %s", entry, path) - // If match, get the efi file and remove it - if conf["efi"] != "" { - i.cfg.Logger.Debugf("Removing efi file %s", conf["efi"]) - // First remove the efi file - err = i.cfg.Fs.Remove(filepath.Join(i.spec.Partitions.EFI.MountPoint, conf["efi"])) - if err != nil { - i.cfg.Logger.Errorf("Error removing efi file %s: %s", conf["efi"], err) - return err - } - // Then remove the conf file - i.cfg.Logger.Debugf("Removing conf file %s", path) - err = i.cfg.Fs.Remove(path) - if err != nil { - i.cfg.Logger.Errorf("Error removing conf file %s: %s", path, err) - return err - } - // Do not continue checking the conf file, we already done all we needed - } - } - } - return err + + return i.SkipEntryIfNeeded(path, conf) }) if err != nil { @@ -147,6 +129,35 @@ func (i *InstallAction) Run() (err error) { return hook.Run(*i.cfg, i.spec, hook.AfterUkiInstall...) } +func (i *InstallAction) SkipEntryIfNeeded(path string, conf map[string]string) (err error) { + // Check if the cmdline matches any of the entries in the skip list + for _, entry := range i.spec.SkipEntries { + // Match the cmdline key against the entry + if strings.Contains(conf["cmdline"], entry) { + i.cfg.Logger.Debugf("Found match for %s in %s", entry, path) + // If match, get the efi file and remove it + if conf["efi"] != "" { + i.cfg.Logger.Debugf("Removing efi file %s", conf["efi"]) + // First remove the efi file + err = i.cfg.Fs.Remove(filepath.Join(i.spec.Partitions.EFI.MountPoint, conf["efi"])) + if err != nil { + i.cfg.Logger.Errorf("Error removing efi file %s: %s", conf["efi"], err) + return err + } + // Then remove the conf file + i.cfg.Logger.Debugf("Removing conf file %s", path) + err = i.cfg.Fs.Remove(path) + if err != nil { + i.cfg.Logger.Errorf("Error removing conf file %s: %s", path, err) + return err + } + // Do not continue checking the conf file, we already done all we needed + } + } + } + return err +} + // Hook is RunStage wrapper that only adds logic to ignore errors // in case v1.Config.Strict is set to false func Hook(config *config.Config, hook string) error { From d9816567155fa8001c3586dda76170f1645aa5d7 Mon Sep 17 00:00:00 2001 From: Dimitris Karakasilis Date: Mon, 12 Feb 2024 19:20:45 +0200 Subject: [PATCH 2/6] Install efi files in uki mode using naming convention replace "artifact" with "active" in conf files and in filenames Signed-off-by: Dimitris Karakasilis --- go.mod | 2 + go.sum | 23 ++----- internal/agent/install.go | 5 +- pkg/config/spec.go | 9 ++- pkg/uki/install.go | 135 ++++++++++++++++++++++++++------------ pkg/utils/common.go | 32 +-------- 6 files changed, 114 insertions(+), 92 deletions(-) diff --git a/go.mod b/go.mod index 8aab7e82..d71583b9 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.20 // This versions require go1.20 replace ( + github.com/kairos-io/kairos-sdk => /home/dimitris/workspace/kairos/kairos-sdk github.com/onsi/ginkgo/v2 v2.15.0 => github.com/onsi/ginkgo/v2 v2.12.1 github.com/onsi/gomega v1.31.1 => github.com/onsi/gomega v1.28.0 ) @@ -152,6 +153,7 @@ require ( github.com/qeesung/image2ascii v1.0.1 // indirect github.com/rancher-sandbox/linuxkit v1.0.2 // indirect github.com/rivo/uniseg v0.4.4 // indirect + github.com/rs/zerolog v1.32.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/samber/lo v1.37.0 // indirect github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect diff --git a/go.sum b/go.sum index 20dab617..96862920 100644 --- a/go.sum +++ b/go.sum @@ -141,6 +141,7 @@ github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkE github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= @@ -230,6 +231,7 @@ github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEe github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -304,7 +306,6 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10 h1:CqYfpuYIjnlNxM3msdyPRKabhXZWbKjf3Q8BWROFBso= github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= @@ -367,10 +368,6 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/kairos-io/kairos-sdk v0.0.23 h1:2osQaqIPDB0Tj0a0v8NGOPrgQWve3D6r8nHRf7NKe3I= -github.com/kairos-io/kairos-sdk v0.0.23/go.mod h1:17dpFG2d3Q/TcT86DlLK5nNXEjlSrkYl7bsvO2cpYGE= -github.com/kairos-io/kairos-sdk v0.0.24 h1:BhOPrn8Hf8SVEX3eQKS+oJi2UFVL4BYNIl6FjYlni9U= -github.com/kairos-io/kairos-sdk v0.0.24/go.mod h1:17dpFG2d3Q/TcT86DlLK5nNXEjlSrkYl7bsvO2cpYGE= github.com/kairos-io/kcrypt v0.9.1 h1:bMDXZ8MiPY/fgLe5CXQPfUIRchzxErlJ8nfZM/JPfEU= github.com/kairos-io/kcrypt v0.9.1/go.mod h1:odsVL3ab2GJUgDnvDGJi54jrWUe6tjfW9875knT/ltU= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= @@ -422,6 +419,7 @@ github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlW github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= @@ -485,25 +483,15 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108 github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/ginkgo/v2 v2.12.0/go.mod h1:ZNEzXISYlqpb8S36iN71ifqLi3vVD1rVJGvWRCJOUpQ= github.com/onsi/ginkgo/v2 v2.12.1 h1:uHNEO1RP2SpuZApSkel9nEh1/Mu+hmQe7Q+Pepg5OYA= github.com/onsi/ginkgo/v2 v2.12.1/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= -github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY= -github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= -github.com/onsi/gomega v1.1.0/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= -github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= -github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= github.com/onsi/gomega v1.28.0 h1:i2rg/p9n/UqIDAMFUJ6qIUUMcsqOuUHgbpbu235Vr1c= github.com/onsi/gomega v1.28.0/go.mod h1:A1H2JE76sI14WIP57LMKj7FVfCHx3g3BcZVjJG8bjX8= -github.com/onsi/gomega v1.28.1/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= -github.com/onsi/gomega v1.31.1 h1:KYppCUK+bUgAZwHOu7EXVBKyQA6ILvOESHkn/tgoqvo= -github.com/onsi/gomega v1.31.1/go.mod h1:y40C95dwAD1Nz36SsEnxvfFe8FFfNxzI5eJ0EYGyAy0= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc3 h1:fzg1mXZFj8YdPeNkRXMg+zb88BFV0Ys52cJydRwBkb8= @@ -566,6 +554,9 @@ github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUc github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0= +github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -893,7 +884,6 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -906,6 +896,7 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= diff --git a/internal/agent/install.go b/internal/agent/install.go index 034a6121..2e99cc01 100644 --- a/internal/agent/install.go +++ b/internal/agent/install.go @@ -5,14 +5,15 @@ import ( "encoding/json" "errors" "fmt" - "github.com/kairos-io/kairos-agent/v2/pkg/uki" - internalutils "github.com/kairos-io/kairos-agent/v2/pkg/utils" "net/url" "os" "strings" "syscall" "time" + "github.com/kairos-io/kairos-agent/v2/pkg/uki" + internalutils "github.com/kairos-io/kairos-agent/v2/pkg/utils" + fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs" "github.com/sanity-io/litter" diff --git a/pkg/config/spec.go b/pkg/config/spec.go index f954fcc1..4044c0a0 100644 --- a/pkg/config/spec.go +++ b/pkg/config/spec.go @@ -18,14 +18,15 @@ package config import ( "fmt" - "github.com/google/go-containerregistry/pkg/crane" - "golang.org/x/sys/unix" "io/fs" "os" "path/filepath" "reflect" "strings" + "github.com/google/go-containerregistry/pkg/crane" + "golang.org/x/sys/unix" + "github.com/kairos-io/kairos-agent/v2/internal/common" "github.com/kairos-io/kairos-agent/v2/pkg/constants" v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" @@ -656,7 +657,9 @@ func ReadUkiInstallSpecFromConfig(c *Config) (*v1.InstallUkiSpec, error) { func NewUkiUpgradeSpec(cfg *Config) (*v1.UpgradeUkiSpec, error) { spec := &v1.UpgradeUkiSpec{} - err := unmarshallFullSpec(cfg, "upgrade", spec) + if err := unmarshallFullSpec(cfg, "upgrade", spec); err != nil { + return nil, fmt.Errorf("failed unmarshalling full spec: %w", err) + } // TODO: Use this everywhere? cfg.Logger.Infof("Checking if OCI image %s exists", spec.Active.Source.Value()) if spec.Active.Source.IsDocker() { diff --git a/pkg/uki/install.go b/pkg/uki/install.go index 73f1cb87..a201f86f 100644 --- a/pkg/uki/install.go +++ b/pkg/uki/install.go @@ -1,6 +1,7 @@ package uki import ( + "fmt" "os" "path/filepath" "strings" @@ -13,6 +14,7 @@ import ( "github.com/kairos-io/kairos-agent/v2/pkg/utils" fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs" events "github.com/kairos-io/kairos-sdk/bus" + sdkutils "github.com/kairos-io/kairos-sdk/utils" "github.com/sanity-io/litter" ) @@ -81,10 +83,11 @@ func (i *InstallAction) Run() (err error) { // Remove entries // Read all confs - // TODO: suffix _active etc - i.cfg.Logger.Debugf("Checking for entries to remove") - err = fsutils.WalkDirFs(i.cfg.Fs, filepath.Join(i.spec.Partitions.EFI.MountPoint, "loader/entries/"), func(path string, info os.DirEntry, err error) error { + i.cfg.Logger.Debugf("Parsing efi partition files (skip SkipEntries, replace placeholders etc)") + err = fsutils.WalkDirFs(i.cfg.Fs, filepath.Join(i.spec.Partitions.EFI.MountPoint), func(path string, info os.DirEntry, err error) error { + filename := info.Name() if err != nil { + i.cfg.Logger.Errorf("Error walking path: %s, %s", filename, err.Error()) return err } @@ -92,28 +95,55 @@ func (i *InstallAction) Run() (err error) { if info.IsDir() { return nil } - if filepath.Ext(info.Name()) != ".conf" { - return nil - } - // Extract the values - conf, err := utils.SystemdBootConfReader(path) - if err != nil { - i.cfg.Logger.Errorf("Error reading conf file %s: %s", path, err) - return err - } - i.cfg.Logger.Debugf("Conf file %s has values %v", path, litter.Sdump(conf)) - if len(conf["cmdline"]) == 0 { - return nil + if filepath.Ext(filename) == ".conf" { + // Extract the values + conf, err := sdkutils.SystemdBootConfReader(path) + if err != nil { + i.cfg.Logger.Errorf("Error reading conf file to extract values %s: %s", path, err) + return err + } + if len(conf["cmdline"]) == 0 { + return nil + } + + // Check if the cmdline matches any of the entries in the skip list + skip := false + for _, entry := range i.spec.SkipEntries { + if strings.Contains(conf["cmdline"], entry) { + i.cfg.Logger.Debugf("Found match for %s in %s", entry, path) + skip = true + break + } + } + if skip { + return i.SkipEntry(path, conf) + } + + if !strings.Contains(filename, "artifact") { + return nil + } + + if err := i.replacePlaceholders(path, "efi", "active"); err != nil { + return fmt.Errorf("replacing placeholders in %s: %w", filename, err) + } + + return i.replaceFilenamePlaceholder(path, "active") + } else if filepath.Ext(filename) == ".efi" && strings.Contains(filename, "artifact") { + return i.replaceFilenamePlaceholder(path, "active") } - return i.SkipEntryIfNeeded(path, conf) + return nil }) - if err != nil { return err } + loaderConfPath := filepath.Join(i.spec.Partitions.EFI.MountPoint, "loader", "loader.conf") + if err = i.replacePlaceholders(loaderConfPath, "default", "active"); err != nil { + return err + } + // after install hook happens after install (this is for compatibility with normal install, so users can reuse their configs) err = Hook(i.cfg, constants.AfterInstallHook) if err != nil { @@ -129,35 +159,58 @@ func (i *InstallAction) Run() (err error) { return hook.Run(*i.cfg, i.spec, hook.AfterUkiInstall...) } -func (i *InstallAction) SkipEntryIfNeeded(path string, conf map[string]string) (err error) { - // Check if the cmdline matches any of the entries in the skip list - for _, entry := range i.spec.SkipEntries { - // Match the cmdline key against the entry - if strings.Contains(conf["cmdline"], entry) { - i.cfg.Logger.Debugf("Found match for %s in %s", entry, path) - // If match, get the efi file and remove it - if conf["efi"] != "" { - i.cfg.Logger.Debugf("Removing efi file %s", conf["efi"]) - // First remove the efi file - err = i.cfg.Fs.Remove(filepath.Join(i.spec.Partitions.EFI.MountPoint, conf["efi"])) - if err != nil { - i.cfg.Logger.Errorf("Error removing efi file %s: %s", conf["efi"], err) - return err - } - // Then remove the conf file - i.cfg.Logger.Debugf("Removing conf file %s", path) - err = i.cfg.Fs.Remove(path) - if err != nil { - i.cfg.Logger.Errorf("Error removing conf file %s: %s", path, err) - return err - } - // Do not continue checking the conf file, we already done all we needed - } +func (i *InstallAction) SkipEntry(path string, conf map[string]string) (err error) { + // If match, get the efi file and remove it + if conf["efi"] != "" { + i.cfg.Logger.Debugf("Removing efi file %s", conf["efi"]) + // First remove the efi file + err = i.cfg.Fs.Remove(filepath.Join(i.spec.Partitions.EFI.MountPoint, conf["efi"])) + if err != nil { + i.cfg.Logger.Errorf("Error removing efi file %s: %s", conf["efi"], err) + return err } + // Then remove the conf file + i.cfg.Logger.Debugf("Removing conf file %s", path) + err = i.cfg.Fs.Remove(path) + if err != nil { + i.cfg.Logger.Errorf("Error removing conf file %s: %s", path, err) + return err + } + // Do not continue checking the conf file, we already done all we needed } return err } +func (i *InstallAction) replaceFilenamePlaceholder(path, replaceString string) (err error) { + newName := strings.ReplaceAll(path, "artifact", replaceString) + + return os.Rename(path, newName) +} + +func (i *InstallAction) replacePlaceholders(path, key, replaceString string) (err error) { + // Extract the values + conf, err := sdkutils.SystemdBootConfReader(path) + if err != nil { + i.cfg.Logger.Errorf("Error reading conf file %s: %s", path, err) + return err + } + i.cfg.Logger.Debugf("Conf file %s has values %v", path, litter.Sdump(conf)) + + _, hasKey := conf[key] + if !hasKey { + return fmt.Errorf("no %s entry in .conf file", key) + } + + conf[key] = strings.ReplaceAll(conf[key], "artifact", replaceString) + newContents := "" + for k, v := range conf { + newContents = fmt.Sprintf("%s%s %s\n", newContents, k, v) + } + i.cfg.Logger.Debugf("Conf file %s new values %v", path, litter.Sdump(conf)) + + return os.WriteFile(path, []byte(newContents), os.ModePerm) +} + // Hook is RunStage wrapper that only adds logic to ignore errors // in case v1.Config.Strict is set to false func Hook(config *config.Config, hook string) error { diff --git a/pkg/utils/common.go b/pkg/utils/common.go index 565e9337..a6a8f021 100644 --- a/pkg/utils/common.go +++ b/pkg/utils/common.go @@ -17,11 +17,9 @@ limitations under the License. package utils import ( - "bufio" "crypto/sha256" "errors" "fmt" - "github.com/kairos-io/kairos-sdk/state" "io" random "math/rand" "net/url" @@ -32,6 +30,8 @@ import ( "strings" "time" + "github.com/kairos-io/kairos-sdk/state" + agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config" fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs" "github.com/kairos-io/kairos-agent/v2/pkg/utils/partitions" @@ -528,31 +528,3 @@ func UkiBootMode() state.Boot { } return state.Unknown } - -// SystemdBootConfReader reads a systemd-boot conf file and returns a map with the key/value pairs -func SystemdBootConfReader(filePath string) (map[string]string, error) { - file, err := os.Open(filePath) - if err != nil { - return nil, err - } - defer file.Close() - - result := make(map[string]string) - scanner := bufio.NewScanner(file) - for scanner.Scan() { - line := scanner.Text() - parts := strings.SplitN(line, " ", 2) - if len(parts) == 2 { - result[parts[0]] = parts[1] - } - if len(parts) == 1 { - result[parts[0]] = "" - } - } - - if err := scanner.Err(); err != nil { - return nil, err - } - - return result, nil -} From bf8e2ba3b0703b93f48d4fb0668d5faa439714b4 Mon Sep 17 00:00:00 2001 From: Mauro Morales Date: Thu, 15 Feb 2024 17:48:12 +0100 Subject: [PATCH 3/6] Make copies for active/passive/recovery Signed-off-by: Mauro Morales --- pkg/uki/install.go | 97 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 80 insertions(+), 17 deletions(-) diff --git a/pkg/uki/install.go b/pkg/uki/install.go index a201f86f..7684df10 100644 --- a/pkg/uki/install.go +++ b/pkg/uki/install.go @@ -2,6 +2,7 @@ package uki import ( "fmt" + "io" "os" "path/filepath" "strings" @@ -119,18 +120,6 @@ func (i *InstallAction) Run() (err error) { if skip { return i.SkipEntry(path, conf) } - - if !strings.Contains(filename, "artifact") { - return nil - } - - if err := i.replacePlaceholders(path, "efi", "active"); err != nil { - return fmt.Errorf("replacing placeholders in %s: %w", filename, err) - } - - return i.replaceFilenamePlaceholder(path, "active") - } else if filepath.Ext(filename) == ".efi" && strings.Contains(filename, "artifact") { - return i.replaceFilenamePlaceholder(path, "active") } return nil @@ -139,11 +128,21 @@ func (i *InstallAction) Run() (err error) { return err } + for _, entry := range []string{"active", "passive", "recovery"} { + if err = installArtifactSet(i.cfg.Fs, i.spec.Partitions.EFI.MountPoint, entry, i.cfg.Logger); err != nil { + return fmt.Errorf("installing artifact set %s: %w", entry, err) + } + } + loaderConfPath := filepath.Join(i.spec.Partitions.EFI.MountPoint, "loader", "loader.conf") - if err = i.replacePlaceholders(loaderConfPath, "default", "active"); err != nil { + if err = replacePlaceholders(loaderConfPath, "default", "active", i.cfg.Logger); err != nil { return err } + if err = removeArtifactSet(i.cfg.Fs, i.spec.Partitions.EFI.MountPoint); err != nil { + return fmt.Errorf("removing artifact set: %w", err) + } + // after install hook happens after install (this is for compatibility with normal install, so users can reuse their configs) err = Hook(i.cfg, constants.AfterInstallHook) if err != nil { @@ -158,6 +157,70 @@ func (i *InstallAction) Run() (err error) { return hook.Run(*i.cfg, i.spec, hook.AfterUkiInstall...) } +func copy(src, dst string) error { + sourceFile, err := os.Open(src) + if err != nil { + panic(err) + } + defer sourceFile.Close() + + destinationFile, err := os.Create(dst) + if err != nil { + panic(err) + } + defer destinationFile.Close() + + if _, err = io.Copy(destinationFile, sourceFile); err != nil { + return err + } + + // Flushes any buffered data to the destination file + if err = destinationFile.Sync(); err != nil { + return err + } + + if err = sourceFile.Close(); err != nil { + return err + } + + return destinationFile.Close() +} + +// copy the source file but ranme the base name to as +func copyArtifact(source string, as string) (string, error) { + newName := strings.ReplaceAll(source, "artifact", as) + return newName, copy(source, newName) +} + +func removeArtifactSet(fs v1.FS, artifactDir string) error { + return fsutils.WalkDirFs(fs, artifactDir, func(path string, info os.DirEntry, err error) error { + if !info.IsDir() && strings.HasPrefix(info.Name(), "artifact") { + return os.Remove(path) + } + + return nil + }) +} + +func installArtifactSet(fs v1.FS, artifactDir, as string, logger v1.Logger) error { + return fsutils.WalkDirFs(fs, artifactDir, func(path string, info os.DirEntry, err error) error { + if !strings.HasPrefix(info.Name(), "artifact") { + return nil + } + + newPath, err := copyArtifact(path, as) + if err != nil { + return fmt.Errorf("copying artifact from %s to %s: %w", path, newPath, err) + } + if strings.HasSuffix(path, ".conf") { + if err := replacePlaceholders(newPath, "efi", as, logger); err != nil { + return err + } + } + + return nil + }) +} func (i *InstallAction) SkipEntry(path string, conf map[string]string) (err error) { // If match, get the efi file and remove it @@ -187,14 +250,14 @@ func (i *InstallAction) replaceFilenamePlaceholder(path, replaceString string) ( return os.Rename(path, newName) } -func (i *InstallAction) replacePlaceholders(path, key, replaceString string) (err error) { +func replacePlaceholders(path, key, replaceString string, logger v1.Logger) (err error) { // Extract the values conf, err := sdkutils.SystemdBootConfReader(path) if err != nil { - i.cfg.Logger.Errorf("Error reading conf file %s: %s", path, err) + logger.Errorf("Error reading conf file %s: %s", path, err) return err } - i.cfg.Logger.Debugf("Conf file %s has values %v", path, litter.Sdump(conf)) + logger.Debugf("Conf file %s has values %v", path, litter.Sdump(conf)) _, hasKey := conf[key] if !hasKey { @@ -206,7 +269,7 @@ func (i *InstallAction) replacePlaceholders(path, key, replaceString string) (er for k, v := range conf { newContents = fmt.Sprintf("%s%s %s\n", newContents, k, v) } - i.cfg.Logger.Debugf("Conf file %s new values %v", path, litter.Sdump(conf)) + logger.Debugf("Conf file %s new values %v", path, litter.Sdump(conf)) return os.WriteFile(path, []byte(newContents), os.ModePerm) } From b88d1a70b8ad5e0de06bf9e7423dc2385aa6ba4f Mon Sep 17 00:00:00 2001 From: Mauro Morales Date: Fri, 16 Feb 2024 17:37:40 +0200 Subject: [PATCH 4/6] Refactor methods and implement uki upgrade Signed-off-by: Dimitris Karakasilis --- pkg/uki/common.go | 121 +++++++++++++++++++++++++++++++++++++++++++++ pkg/uki/install.go | 111 ++++------------------------------------- pkg/uki/upgrade.go | 77 ++++++++++------------------- 3 files changed, 157 insertions(+), 152 deletions(-) create mode 100644 pkg/uki/common.go diff --git a/pkg/uki/common.go b/pkg/uki/common.go new file mode 100644 index 00000000..e3844d61 --- /dev/null +++ b/pkg/uki/common.go @@ -0,0 +1,121 @@ +package uki + +import ( + "fmt" + "io" + "os" + "strings" + + v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" + fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs" + sdkutils "github.com/kairos-io/kairos-sdk/utils" + "github.com/sanity-io/litter" +) + +const UnassignedArtifactRole = "norole" + +// overwriteArtifactSetRole first deletes all artifacts prefixed with newRole +// (because they are going to be replaced, e.g. old "passive") and then installs +// the artifacts prefixed with oldRole as newRole. +// E.g. removes "passive" and moved "active" to "passive" +// This is a step that should happen before a new passive is installed on upgrades. +func overwriteArtifactSetRole(fs v1.FS, dir, oldRole, newRole string, logger v1.Logger) error { + if err := removeArtifactSetWithRole(fs, dir, newRole); err != nil { + return fmt.Errorf("deleting role %s: %w", newRole, err) + } + + if err := copyArtifactSetRole(fs, dir, oldRole, newRole, logger); err != nil { + return fmt.Errorf("copying artifact set role from %s to %s: %w", oldRole, newRole, err) + } + + return nil +} + +// copy the source file but rename the base name to as +func copyArtifact(source, oldRole, newRole string) (string, error) { + newName := strings.ReplaceAll(source, oldRole, newRole) + return newName, copyFile(source, newName) +} + +func removeArtifactSetWithRole(fs v1.FS, artifactDir, role string) error { + return fsutils.WalkDirFs(fs, artifactDir, func(path string, info os.DirEntry, err error) error { + if !info.IsDir() && strings.HasPrefix(info.Name(), role) { + return os.Remove(path) + } + + return nil + }) +} + +func copyArtifactSetRole(fs v1.FS, artifactDir, oldRole, newRole string, logger v1.Logger) error { + return fsutils.WalkDirFs(fs, artifactDir, func(path string, info os.DirEntry, err error) error { + if !strings.HasPrefix(info.Name(), oldRole) { + return nil + } + + newPath, err := copyArtifact(path, oldRole, newRole) + if err != nil { + return fmt.Errorf("copying artifact from %s to %s: %w", path, newPath, err) + } + if strings.HasSuffix(path, ".conf") { + if err := replaceRoleInKey(newPath, "efi", oldRole, newRole, logger); err != nil { + return err + } + } + + return nil + }) +} + +func replaceRoleInKey(path, key, oldRole, newRole string, logger v1.Logger) (err error) { + // Extract the values + conf, err := sdkutils.SystemdBootConfReader(path) + if err != nil { + logger.Errorf("Error reading conf file %s: %s", path, err) + return err + } + logger.Debugf("Conf file %s has values %v", path, litter.Sdump(conf)) + + _, hasKey := conf[key] + if !hasKey { + return fmt.Errorf("no %s entry in .conf file", key) + } + + conf[key] = strings.ReplaceAll(conf[key], oldRole, newRole) + newContents := "" + for k, v := range conf { + newContents = fmt.Sprintf("%s%s %s\n", newContents, k, v) + } + logger.Debugf("Conf file %s new values %v", path, litter.Sdump(conf)) + + return os.WriteFile(path, []byte(newContents), os.ModePerm) +} + +func copyFile(src, dst string) error { + sourceFile, err := os.Open(src) + if err != nil { + panic(err) + } + defer sourceFile.Close() + + destinationFile, err := os.Create(dst) + if err != nil { + panic(err) + } + defer destinationFile.Close() + + if _, err = io.Copy(destinationFile, sourceFile); err != nil { + return err + } + + // Flushes any buffered data to the destination file + if err = destinationFile.Sync(); err != nil { + return err + } + + if err = sourceFile.Close(); err != nil { + return err + } + + return destinationFile.Close() +} diff --git a/pkg/uki/install.go b/pkg/uki/install.go index 7684df10..66a69f40 100644 --- a/pkg/uki/install.go +++ b/pkg/uki/install.go @@ -2,7 +2,6 @@ package uki import ( "fmt" - "io" "os" "path/filepath" "strings" @@ -16,7 +15,6 @@ import ( fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs" events "github.com/kairos-io/kairos-sdk/bus" sdkutils "github.com/kairos-io/kairos-sdk/utils" - "github.com/sanity-io/litter" ) type InstallAction struct { @@ -76,6 +74,9 @@ func (i *InstallAction) Run() (err error) { return err } + // TODO: Check if the size of the files we are going to copy, will fit in the + // partition. If not stop here. + // Copy the efi file into the proper dir _, err = e.DumpSource(i.spec.Partitions.EFI.MountPoint, i.spec.Active.Source) if err != nil { @@ -128,19 +129,19 @@ func (i *InstallAction) Run() (err error) { return err } - for _, entry := range []string{"active", "passive", "recovery"} { - if err = installArtifactSet(i.cfg.Fs, i.spec.Partitions.EFI.MountPoint, entry, i.cfg.Logger); err != nil { - return fmt.Errorf("installing artifact set %s: %w", entry, err) + for _, role := range []string{"active", "passive", "recovery"} { + if err = copyArtifactSetRole(i.cfg.Fs, i.spec.Partitions.EFI.MountPoint, UnassignedArtifactRole, role, i.cfg.Logger); err != nil { + return fmt.Errorf("installing the new artifact set as %s: %w", role, err) } } loaderConfPath := filepath.Join(i.spec.Partitions.EFI.MountPoint, "loader", "loader.conf") - if err = replacePlaceholders(loaderConfPath, "default", "active", i.cfg.Logger); err != nil { + if err = replaceRoleInKey(loaderConfPath, "default", UnassignedArtifactRole, "active", i.cfg.Logger); err != nil { return err } - if err = removeArtifactSet(i.cfg.Fs, i.spec.Partitions.EFI.MountPoint); err != nil { - return fmt.Errorf("removing artifact set: %w", err) + if err = removeArtifactSetWithRole(i.cfg.Fs, i.spec.Partitions.EFI.MountPoint, UnassignedArtifactRole); err != nil { + return fmt.Errorf("removing artifact set with role %s: %w", UnassignedArtifactRole, err) } // after install hook happens after install (this is for compatibility with normal install, so users can reuse their configs) @@ -157,70 +158,6 @@ func (i *InstallAction) Run() (err error) { return hook.Run(*i.cfg, i.spec, hook.AfterUkiInstall...) } -func copy(src, dst string) error { - sourceFile, err := os.Open(src) - if err != nil { - panic(err) - } - defer sourceFile.Close() - - destinationFile, err := os.Create(dst) - if err != nil { - panic(err) - } - defer destinationFile.Close() - - if _, err = io.Copy(destinationFile, sourceFile); err != nil { - return err - } - - // Flushes any buffered data to the destination file - if err = destinationFile.Sync(); err != nil { - return err - } - - if err = sourceFile.Close(); err != nil { - return err - } - - return destinationFile.Close() -} - -// copy the source file but ranme the base name to as -func copyArtifact(source string, as string) (string, error) { - newName := strings.ReplaceAll(source, "artifact", as) - return newName, copy(source, newName) -} - -func removeArtifactSet(fs v1.FS, artifactDir string) error { - return fsutils.WalkDirFs(fs, artifactDir, func(path string, info os.DirEntry, err error) error { - if !info.IsDir() && strings.HasPrefix(info.Name(), "artifact") { - return os.Remove(path) - } - - return nil - }) -} - -func installArtifactSet(fs v1.FS, artifactDir, as string, logger v1.Logger) error { - return fsutils.WalkDirFs(fs, artifactDir, func(path string, info os.DirEntry, err error) error { - if !strings.HasPrefix(info.Name(), "artifact") { - return nil - } - - newPath, err := copyArtifact(path, as) - if err != nil { - return fmt.Errorf("copying artifact from %s to %s: %w", path, newPath, err) - } - if strings.HasSuffix(path, ".conf") { - if err := replacePlaceholders(newPath, "efi", as, logger); err != nil { - return err - } - } - - return nil - }) -} func (i *InstallAction) SkipEntry(path string, conf map[string]string) (err error) { // If match, get the efi file and remove it @@ -244,36 +181,6 @@ func (i *InstallAction) SkipEntry(path string, conf map[string]string) (err erro return err } -func (i *InstallAction) replaceFilenamePlaceholder(path, replaceString string) (err error) { - newName := strings.ReplaceAll(path, "artifact", replaceString) - - return os.Rename(path, newName) -} - -func replacePlaceholders(path, key, replaceString string, logger v1.Logger) (err error) { - // Extract the values - conf, err := sdkutils.SystemdBootConfReader(path) - if err != nil { - logger.Errorf("Error reading conf file %s: %s", path, err) - return err - } - logger.Debugf("Conf file %s has values %v", path, litter.Sdump(conf)) - - _, hasKey := conf[key] - if !hasKey { - return fmt.Errorf("no %s entry in .conf file", key) - } - - conf[key] = strings.ReplaceAll(conf[key], "artifact", replaceString) - newContents := "" - for k, v := range conf { - newContents = fmt.Sprintf("%s%s %s\n", newContents, k, v) - } - logger.Debugf("Conf file %s new values %v", path, litter.Sdump(conf)) - - return os.WriteFile(path, []byte(newContents), os.ModePerm) -} - // Hook is RunStage wrapper that only adds logic to ignore errors // in case v1.Config.Strict is set to false func Hook(config *config.Config, hook string) error { diff --git a/pkg/uki/upgrade.go b/pkg/uki/upgrade.go index ee293a01..4e2a243b 100644 --- a/pkg/uki/upgrade.go +++ b/pkg/uki/upgrade.go @@ -1,7 +1,9 @@ package uki import ( - "github.com/Masterminds/semver/v3" + "fmt" + "path/filepath" + "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/elemental" @@ -9,11 +11,6 @@ import ( elementalUtils "github.com/kairos-io/kairos-agent/v2/pkg/utils" events "github.com/kairos-io/kairos-sdk/bus" "github.com/kairos-io/kairos-sdk/utils" - "github.com/sanity-io/litter" - "os" - "path/filepath" - "sort" - "strings" ) type UpgradeAction struct { @@ -39,61 +36,41 @@ func (i *UpgradeAction) Run() (err error) { return err } cleanup.Push(umount) - // TODO: Check number of existing UKI files - efiFiles, err := i.getEfiFiles() + + // TODO: Get the size of the efi partition and decide if the images can fit + // before trying the upgrade. + // If we decide to first copy and then rotate, we need ~4 times the size of + // the artifact set [TBD] + + // Dump artifact to efi dir + _, err = e.DumpSource(constants.UkiEfiDir, i.spec.Active.Source) if err != nil { return err } - i.cfg.Logger.Infof("Found %d UKI files", len(efiFiles)) - if len(efiFiles) > i.cfg.UkiMaxEntries && i.cfg.UkiMaxEntries > 0 { - i.cfg.Logger.Infof("Found %d UKI files, which is over max entries allowed(%d) removing the oldest one", len(efiFiles), i.cfg.UkiMaxEntries) - versionList := semver.Collection{} - for _, f := range efiFiles { - versionList = append(versionList, semver.MustParse(f)) - } - // Sort it so the oldest one is first - sort.Sort(versionList) - i.cfg.Logger.Debugf("All versions found: %s", litter.Sdump(versionList)) - // Remove the oldest one - i.cfg.Logger.Infof("Removing: %s", filepath.Join(i.spec.EfiPartition.MountPoint, "EFI", "kairos", versionList[0].Original())) - err = i.cfg.Fs.Remove(filepath.Join(i.spec.EfiPartition.MountPoint, "EFI", "kairos", versionList[0].Original())) - if err != nil { - return err - } - // Remove the conf file as well - i.cfg.Logger.Infof("Removing: %s", filepath.Join(i.spec.EfiPartition.MountPoint, "loader", "entries", versionList[0].String()+".conf")) - // Don't care about errors here, systemd-boot will ignore any configs if it cant find the efi file mentioned in it - e := i.cfg.Fs.Remove(filepath.Join(i.spec.EfiPartition.MountPoint, "loader", "entries", versionList[0].String()+".conf")) - if e != nil { - i.cfg.Logger.Warnf("Failed to remove conf file: %s", e) - } - } else { - i.cfg.Logger.Infof("Found %d UKI files, which is under max entries allowed(%d) not removing any", len(efiFiles), i.cfg.UkiMaxEntries) + + // Rotate first + err = overwriteArtifactSetRole(i.cfg.Fs, constants.UkiEfiDir, "active", "passive", i.cfg.Logger) + if err != nil { + return fmt.Errorf("rotating active to passive: %w", err) } - // Dump artifact to efi dir - _, err = e.DumpSource(constants.UkiEfiDir, i.spec.Active.Source) + // Install the new artifacts as "active" + err = overwriteArtifactSetRole(i.cfg.Fs, constants.UkiEfiDir, UnassignedArtifactRole, "active", i.cfg.Logger) if err != nil { + return fmt.Errorf("installing the new artifacts as active: %w", err) + } + + loaderConfPath := filepath.Join(constants.UkiEfiDir, "loader", "loader.conf") + if err = replaceRoleInKey(loaderConfPath, "default", UnassignedArtifactRole, "active", i.cfg.Logger); err != nil { return err } + if err = removeArtifactSetWithRole(i.cfg.Fs, constants.UkiEfiDir, UnassignedArtifactRole); err != nil { + return fmt.Errorf("removing artifact set: %w", err) + } + _ = elementalUtils.RunStage(i.cfg, "kairos-uki-upgrade.after") _ = events.RunHookScript("/usr/bin/kairos-agent.uki.upgrade.after.hook") //nolint:errcheck return nil } - -func (i *UpgradeAction) getEfiFiles() ([]string, error) { - var efiFiles []string - files, err := os.ReadDir(filepath.Join(i.spec.EfiPartition.MountPoint, "EFI", "kairos")) - if err != nil { - return efiFiles, err - } - - for _, file := range files { - if !file.IsDir() && strings.HasSuffix(file.Name(), ".efi") { - efiFiles = append(efiFiles, file.Name()) - } - } - return efiFiles, nil -} From 78a240d9c53e57d2975ab522ad21967bb9bbc9e8 Mon Sep 17 00:00:00 2001 From: Dimitris Karakasilis Date: Fri, 16 Feb 2024 17:39:08 +0200 Subject: [PATCH 5/6] Handle the filesystem walk error Signed-off-by: Dimitris Karakasilis --- pkg/uki/common.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/uki/common.go b/pkg/uki/common.go index e3844d61..1b6b9e9d 100644 --- a/pkg/uki/common.go +++ b/pkg/uki/common.go @@ -49,6 +49,9 @@ func removeArtifactSetWithRole(fs v1.FS, artifactDir, role string) error { func copyArtifactSetRole(fs v1.FS, artifactDir, oldRole, newRole string, logger v1.Logger) error { return fsutils.WalkDirFs(fs, artifactDir, func(path string, info os.DirEntry, err error) error { + if err != nil { + return err + } if !strings.HasPrefix(info.Name(), oldRole) { return nil } From c369187e4880d4f035f09b33039f7c3a471546b1 Mon Sep 17 00:00:00 2001 From: Dimitris Karakasilis Date: Mon, 19 Feb 2024 13:43:43 +0200 Subject: [PATCH 6/6] Remove "replace" directive from go.mod and use released tag Signed-off-by: Dimitris Karakasilis --- go.mod | 3 +-- go.sum | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index d71583b9..6e35ed38 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ go 1.20 // This versions require go1.20 replace ( - github.com/kairos-io/kairos-sdk => /home/dimitris/workspace/kairos/kairos-sdk github.com/onsi/ginkgo/v2 v2.15.0 => github.com/onsi/ginkgo/v2 v2.12.1 github.com/onsi/gomega v1.31.1 => github.com/onsi/gomega v1.28.0 ) @@ -20,7 +19,7 @@ require ( github.com/hashicorp/go-multierror v1.1.1 github.com/jaypipes/ghw v0.12.0 github.com/joho/godotenv v1.5.1 - github.com/kairos-io/kairos-sdk v0.0.24 + github.com/kairos-io/kairos-sdk v0.0.25 github.com/kairos-io/kcrypt v0.9.1 github.com/labstack/echo/v4 v4.11.4 github.com/mitchellh/mapstructure v1.5.0 diff --git a/go.sum b/go.sum index 96862920..6087f6a6 100644 --- a/go.sum +++ b/go.sum @@ -368,6 +368,8 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kairos-io/kairos-sdk v0.0.25 h1:/wQ8lHmmqJgKPaxzLllTgMQNWRje80XKdj8F0XlFXl0= +github.com/kairos-io/kairos-sdk v0.0.25/go.mod h1:btSB2QAds/WSyIyPxnQ3jueMbkkZ75pHUUCj+yHpthQ= github.com/kairos-io/kcrypt v0.9.1 h1:bMDXZ8MiPY/fgLe5CXQPfUIRchzxErlJ8nfZM/JPfEU= github.com/kairos-io/kcrypt v0.9.1/go.mod h1:odsVL3ab2GJUgDnvDGJi54jrWUe6tjfW9875knT/ltU= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=