package utils_test import ( "github.com/containerd/containerd/mount" "github.com/jaypipes/ghw/pkg/block" "github.com/kairos-io/immucore/internal/utils" "github.com/kairos-io/immucore/tests/mocks" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/twpayne/go-vfs" "github.com/twpayne/go-vfs/vfst" "os" "path/filepath" ) var _ = Describe("mount utils", func() { var fs vfs.FS var cleanup func() BeforeEach(func() { fs, cleanup, _ = vfst.NewTestFS(map[string]interface{}{ "/proc/cmdline": "", }) _, err := fs.Stat("/proc/cmdline") Expect(err).ToNot(HaveOccurred()) fakeCmdline, _ := fs.RawPath("/proc/cmdline") err = os.Setenv("HOST_PROC_CMDLINE", fakeCmdline) Expect(err).ToNot(HaveOccurred()) }) AfterEach(func() { cleanup() }) Context("ReadCMDLineArg", func() { BeforeEach(func() { err := fs.WriteFile("/proc/cmdline", []byte("test/key=value1 rd.immucore.debug rd.immucore.uki rd.cos.oemlabel=FAKE_LABEL empty=\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) }) It("splits arguments from cmdline", func() { value := utils.ReadCMDLineArg("test/key=") Expect(len(value)).To(Equal(1)) Expect(value[0]).To(Equal("value1")) value = utils.ReadCMDLineArg("rd.cos.oemlabel=") Expect(len(value)).To(Equal(1)) Expect(value[0]).To(Equal("FAKE_LABEL")) // This is mostly wrong, it should return and empty value, not a []string of 1 empty value // Requires refactoring value = utils.ReadCMDLineArg("empty=") Expect(len(value)).To(Equal(1)) Expect(value[0]).To(Equal("")) }) It("returns properly for stanzas without value", func() { Expect(len(utils.ReadCMDLineArg("rd.immucore.debug"))).To(Equal(1)) Expect(len(utils.ReadCMDLineArg("rd.immucore.uki"))).To(Equal(1)) }) }) Context("GetRootDir", func() { It("Returns / for uki", func() { err := fs.WriteFile("/proc/cmdline", []byte("rd.immucore.uki"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) Expect(utils.GetRootDir()).To(Equal("/")) }) It("Returns /sysroot", func() { Expect(utils.GetRootDir()).To(Equal("/sysroot")) }) }) Context("UniqueSlice", func() { It("Removes duplicates", func() { dups := []string{"a", "b", "c", "d", "b", "a"} dupsRemoved := utils.UniqueSlice(dups) Expect(len(dupsRemoved)).To(Equal(4)) }) }) Context("ReadEnv", func() { It("Parses correctly an env file", func() { tmpDir, err := os.MkdirTemp("", "") Expect(err).ToNot(HaveOccurred()) defer os.RemoveAll(tmpDir) err = os.WriteFile(filepath.Join(tmpDir, "layout.env"), []byte("OVERLAY=\"tmpfs:25%\"\nPERSISTENT_STATE_BIND=\"true\"\nPERSISTENT_STATE_PATHS=\"/home /opt /root\"\nRW_PATHS=\"/var /etc /srv\"\nVOLUMES=\"LABEL=COS_OEM:/oem LABEL=COS_PERSISTENT:/usr/local\""), os.ModePerm) Expect(err).ToNot(HaveOccurred()) env, err := utils.ReadEnv(filepath.Join(tmpDir, "layout.env")) Expect(err).ToNot(HaveOccurred()) Expect(env).To(HaveKey("OVERLAY")) Expect(env).To(HaveKey("PERSISTENT_STATE_BIND")) Expect(env).To(HaveKey("PERSISTENT_STATE_PATHS")) Expect(env).To(HaveKey("RW_PATHS")) Expect(env).To(HaveKey("VOLUMES")) Expect(env["OVERLAY"]).To(Equal("tmpfs:25%")) Expect(env["PERSISTENT_STATE_BIND"]).To(Equal("true")) Expect(env["PERSISTENT_STATE_PATHS"]).To(Equal("/home /opt /root")) Expect(env["RW_PATHS"]).To(Equal("/var /etc /srv")) Expect(env["VOLUMES"]).To(Equal("LABEL=COS_OEM:/oem LABEL=COS_PERSISTENT:/usr/local")) }) }) Context("CleanupSlice", func() { It("Cleans up the slice of empty values", func() { slice := []string{"", " "} sliceCleaned := utils.CleanupSlice(slice) Expect(len(sliceCleaned)).To(Equal(0)) }) }) Context("GetTarget", func() { It("Returns a fake target if called with dry run", func() { target, label, err := utils.GetTarget(true) Expect(err).ToNot(HaveOccurred()) Expect(target).To(Equal("fake")) // We cant manipulate runtime, so it will return an empty label as it cant identify where are we Expect(label).To(Equal("")) }) It("Returns a fake target if immucore is disabled", func() { err := fs.WriteFile("/proc/cmdline", []byte("rd.immucore.disabled\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) target, label, err := utils.GetTarget(false) Expect(err).ToNot(HaveOccurred()) Expect(target).To(Equal("fake")) // We cant manipulate runtime, so it will return an empty label as it cant identify where are we Expect(label).To(Equal("")) }) It("Returns the proper target from cmdline", func() { err := fs.WriteFile("/proc/cmdline", []byte("cos-img/filename=active.img\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) target, label, err := utils.GetTarget(false) Expect(err).ToNot(HaveOccurred()) Expect(target).To(Equal("active.img")) // We cant manipulate runtime, so it will return an empty label as it cant identify where are we Expect(label).To(Equal("")) }) It("Returns an empty target if we are on UKI", func() { err := fs.WriteFile("/proc/cmdline", []byte("rd.immucore.uki\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) target, label, err := utils.GetTarget(false) Expect(err).ToNot(HaveOccurred()) Expect(target).To(Equal("")) // We cant manipulate runtime, so it will return an empty label as it cant identify where are we Expect(label).To(Equal("")) }) It("Returns an error if we dont have the target in the cmdline", func() { target, label, err := utils.GetTarget(false) Expect(err).To(HaveOccurred()) Expect(target).To(Equal("")) Expect(label).To(Equal("")) }) }) Context("DisableImmucore", func() { It("Disables immucore if cmdline contains live:LABEL", func() { err := fs.WriteFile("/proc/cmdline", []byte("root=live:LABEL=COS_LIVE\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) Expect(utils.DisableImmucore()).To(BeTrue()) }) It("Disables immucore if cmdline contains live:CDLABEL", func() { err := fs.WriteFile("/proc/cmdline", []byte("root=live:CDLABEL=COS_LIVE\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) Expect(utils.DisableImmucore()).To(BeTrue()) }) It("Disables immucore if cmdline contains netboot", func() { err := fs.WriteFile("/proc/cmdline", []byte("netboot\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) Expect(utils.DisableImmucore()).To(BeTrue()) }) It("Disables immucore if cmdline contains rd.cos.disable", func() { err := fs.WriteFile("/proc/cmdline", []byte("rd.cos.disable\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) Expect(utils.DisableImmucore()).To(BeTrue()) }) It("Disables immucore if cmdline contains rd.immucore.disable", func() { err := fs.WriteFile("/proc/cmdline", []byte("rd.immucore.disable\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) Expect(utils.DisableImmucore()).To(BeTrue()) }) It("Enables immucore by default", func() { Expect(utils.DisableImmucore()).To(BeFalse()) }) }) Context("RootRW", func() { It("Defaults to RO", func() { Expect(utils.RootRW()).To(Equal("ro")) }) It("Sets RW if set via cmdline with rd.cos.debugrw", func() { err := fs.WriteFile("/proc/cmdline", []byte("rd.cos.debugrw\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) Expect(utils.RootRW()).To(Equal("rw")) }) It("Sets RW if set via cmdline with rd.immucore.debugrw", func() { err := fs.WriteFile("/proc/cmdline", []byte("rd.immucore.debugrw\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) Expect(utils.RootRW()).To(Equal("rw")) }) It("Sets RW if set via cmdline with both rd.cos.debugrw and rd.immucore.debugrw at the same time", func() { err := fs.WriteFile("/proc/cmdline", []byte("rd.cos.debugrw rd.immucore.debugrw\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) Expect(utils.RootRW()).To(Equal("rw")) }) }) Context("IsUKI", func() { It("Returns false in a normal boot", func() { Expect(utils.IsUKI()).To(BeFalse()) }) It("Returns true if set via cmdline with rd.immucore.uki", func() { err := fs.WriteFile("/proc/cmdline", []byte("rd.immucore.uki\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) Expect(utils.IsUKI()).To(BeTrue()) }) }) Context("ParseMount", func() { It("Returns disk path by LABEL", func() { Expect(utils.ParseMount("LABEL=MY_LABEL")).To(Equal("/dev/disk/by-label/MY_LABEL")) }) It("Returns disk path by UUID", func() { Expect(utils.ParseMount("UUID=9999")).To(Equal("/dev/disk/by-uuid/9999")) }) }) Context("AppendSlash", func() { It("Appends a slash if it doesnt have one", func() { noSlash := "/noslash" Expect(utils.AppendSlash(noSlash)).To(Equal("/noslash/")) }) It("Does not append a slash if it already has one", func() { slash := "/yesslash/" Expect(utils.AppendSlash(slash)).To(Equal("/yesslash/")) }) }) Context("MountToFstab", func() { It("Generates teh proper fstab config", func() { m := mount.Mount{ Type: "fakefs", Source: "/dev/fake", Options: []string{"option1", "option=2"}, } fstab := utils.MountToFstab(m) fstab.File = "/mnt/fake" // Options can be shown in whatever order, so regexp that Expect(fstab.String()).To(MatchRegexp("/dev/fake /mnt/fake fakefs (option1|option=2),(option=2|option1) 0 0")) Expect(fstab.Spec).To(Equal("/dev/fake")) Expect(fstab.VfsType).To(Equal("fakefs")) Expect(fstab.MntOps).To(HaveKey("option1")) Expect(fstab.MntOps).To(HaveKey("option")) Expect(fstab.MntOps["option1"]).To(Equal("")) Expect(fstab.MntOps["option"]).To(Equal("2")) }) }) Context("CleanSysrootForFstab", func() { It("Removes /sysroot", func() { Expect(utils.CleanSysrootForFstab("/sysroot/dev")).To(Equal("/dev")) Expect(utils.CleanSysrootForFstab("/sysroot/sysroot/dev")).To(Equal("/dev")) Expect(utils.CleanSysrootForFstab("sysroot/dev")).To(Equal("sysroot/dev")) Expect(utils.CleanSysrootForFstab("/dev/sysroot/dev")).To(Equal("/dev/dev")) Expect(utils.CleanSysrootForFstab("/dev/")).To(Equal("/dev/")) Expect(utils.CleanSysrootForFstab("/dev")).To(Equal("/dev")) Expect(utils.CleanSysrootForFstab("//sysroot/dev")).To(Equal("//dev")) Expect(utils.CleanSysrootForFstab("/sysroot//dev")).To(Equal("//dev")) }) }) Context("GetOemTimeout", func() { It("Gets timeout from rd.cos.oemtimeout", func() { err := fs.WriteFile("/proc/cmdline", []byte("rd.cos.oemtimeout=100\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) Expect(utils.GetOemTimeout()).To(Equal(100)) }) It("Gets timeout from rd.immucore.oemtimeout", func() { err := fs.WriteFile("/proc/cmdline", []byte("rd.immucore.oemtimeout=200\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) Expect(utils.GetOemTimeout()).To(Equal(200)) }) It("Gets timeout from both rd.cos.oemtimeout and rd.immucore.oemtimeout(immucore has precedence)", func() { err := fs.WriteFile("/proc/cmdline", []byte("rd.cos.oemtimeout=100 rd.immucore.oemtimeout=200\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) Expect(utils.GetOemTimeout()).To(Equal(200)) }) It("Fails to parse from cmdline and gets default", func() { err := fs.WriteFile("/proc/cmdline", []byte("rd.immucore.oemtimeout=really\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) Expect(utils.GetOemTimeout()).To(Equal(5)) err = fs.WriteFile("/proc/cmdline", []byte("rd.immucore.oemtimeout=\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) Expect(utils.GetOemTimeout()).To(Equal(5)) }) It("Gets default timeout", func() { Expect(utils.GetOemTimeout()).To(Equal(5)) }) }) Context("GetOverlayBase", func() { It("Gets overlay from rd.cos.overlay", func() { err := fs.WriteFile("/proc/cmdline", []byte("rd.cos.overlay=tmpfs:100%\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) Expect(utils.GetOverlayBase()).To(Equal("tmpfs:100%")) }) It("Gets overlay from rd.immucore.overlay", func() { err := fs.WriteFile("/proc/cmdline", []byte("rd.immucore.overlay=tmpfs:200%\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) Expect(utils.GetOverlayBase()).To(Equal("tmpfs:200%")) }) It("Gets overlay from both rd.cos.overlay and rd.immucore.overlay(immucore has precedence)", func() { err := fs.WriteFile("/proc/cmdline", []byte("rd.cos.overlay=tmpfs:100% rd.immucore.overlay=tmpfs:200%\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) Expect(utils.GetOverlayBase()).To(Equal("tmpfs:200%")) }) It("Fails to parse from cmdline and gets default", func() { err := fs.WriteFile("/proc/cmdline", []byte("rd.immucore.overlay=\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) Expect(utils.GetOverlayBase()).To(Equal("tmpfs:20%")) err = fs.WriteFile("/proc/cmdline", []byte("rd.immucore.overlay=\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) Expect(utils.GetOverlayBase()).To(Equal("tmpfs:20%")) }) It("Gets default overlay", func() { Expect(utils.GetOverlayBase()).To(Equal("tmpfs:20%")) }) }) Context("GetOemLabel", func() { It("Gets label from rd.cos.oemlabel", func() { err := fs.WriteFile("/proc/cmdline", []byte("rd.cos.oemlabel=COS_LABEL\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) Expect(utils.GetOemLabel()).To(Equal("COS_LABEL")) }) It("Gets label from rd.immucore.oemlabel", func() { err := fs.WriteFile("/proc/cmdline", []byte("rd.immucore.oemlabel=IMMUCORE_LABEL\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) Expect(utils.GetOemLabel()).To(Equal("IMMUCORE_LABEL")) }) It("Gets label from both rd.cos.oemlabel and rd.immucore.oemlabel(immucore has precedence)", func() { err := fs.WriteFile("/proc/cmdline", []byte("rd.cos.oemlabel=COS_LABEL rd.immucore.oemlabel=IMMUCORE_LABEL\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) Expect(utils.GetOemLabel()).To(Equal("IMMUCORE_LABEL")) }) It("Fails to parse from cmdline and gets default from runtime", func() { mainDisk := block.Disk{ Name: "device", Partitions: []*block.Partition{ { Name: "device2", FilesystemLabel: "COS_OEM", Type: "ext4", MountPoint: "/oem", }, }, } ghwTest := mocks.GhwMock{} ghwTest.AddDisk(mainDisk) ghwTest.CreateDevices() defer ghwTest.Clean() err := fs.WriteFile("/proc/cmdline", []byte("rd.cos.oemlabel=\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) Expect(utils.GetOemLabel()).To(Equal("COS_OEM")) err = fs.WriteFile("/proc/cmdline", []byte("rd.immucore.oemlabel=\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) Expect(utils.GetOemLabel()).To(Equal("COS_OEM")) }) }) })