diff --git a/internal/cmd/commands.go b/internal/cmd/commands.go index 0f7c66b..22b0b37 100644 --- a/internal/cmd/commands.go +++ b/internal/cmd/commands.go @@ -43,34 +43,26 @@ Sends a generic event payload with the configuration found in the scanned direct v := version.Get() log.Logger.Info().Str("commit", v.GitCommit).Str("compiled with", v.GoVersion).Str("version", v.Version).Msg("Immucore") + cmdline, _ := os.ReadFile("/proc/cmdline") + log.Logger.Debug().Msg(string(cmdline)) g := herd.DAG(herd.EnableInit) - // You can pass rd.cos.disable in the cmdline to disable the whole immutable stuff - cosDisable := len(utils.ReadCMDLineArg("rd.cos.disable")) > 0 - - img := utils.ReadCMDLineArg("cos-img/filename=") - if len(img) == 0 { - // If we boot from LIVE media or are using dry-run, we use a fake img as we still want to do things - if c.Bool("dry-run") || cosDisable { - img = []string{"fake"} - } else { - log.Logger.Fatal().Msg("Could not get the image name from cmdline (i.e. cos-img/filename=/cOS/active.img)") - } - } - log.Debug().Strs("TargetImage", img).Msg("Target image") + // Get targets and state + targetLabel, targetDevice := utils.GetTarget(c.Bool("dry-run")) s := &mount.State{ - Logger: log.Logger, - Rootdir: utils.GetRootDir(), - MountRoot: true, - TargetLabel: utils.BootStateToLabel(), - TargetImage: img[0], + Logger: log.Logger, + Rootdir: utils.GetRootDir(), + TargetLabel: targetDevice, + TargetImage: targetLabel, + RootMountMode: utils.RootRW(), } - if cosDisable { - log.Logger.Info().Msg("Stanza rd.cos.disable on the cmdline.") + if utils.DisableImmucore() { + log.Logger.Info().Msg("Stanza rd.cos.disable on the cmdline or booting from CDROM/Netboot/recovery. Disabling immucore.") err = s.RegisterLiveMedia(g) } else { + log.Logger.Info().Msg("Booting on active/passive.") err = s.RegisterNormalBoot(g) } @@ -81,6 +73,7 @@ Sends a generic event payload with the configuration found in the scanned direct log.Info().Msg(s.WriteDAG(g)) + // Once we print the dag we can exit already if c.Bool("dry-run") { return nil } diff --git a/internal/utils/common.go b/internal/utils/common.go index 79bd1bb..ebc276b 100644 --- a/internal/utils/common.go +++ b/internal/utils/common.go @@ -3,6 +3,7 @@ package utils import ( "github.com/joho/godotenv" "github.com/kairos-io/kairos/sdk/state" + "github.com/rs/zerolog/log" "os" "strings" ) @@ -18,8 +19,6 @@ func BootStateToLabel() string { return "COS_ACTIVE" case "passive_boot": return "COS_PASSIVE" - case "recovery_boot": - return "COS_SYSTEM" default: return "" } @@ -108,3 +107,44 @@ func CleanupSlice(slice []string) []string { } return cleanSlice } + +// GetTarget gets the target image and device to mount in /sysroot +func GetTarget(dryRun bool) (string, string) { + var img, label string + + label = BootStateToLabel() + + // If dry run, or we are disabled return whatever values, we won't go much further + if dryRun || DisableImmucore() { + return "fake", label + } + + img = ReadCMDLineArg("cos-img/filename=")[0] + + // If no image just panic here, we cannot longer continue + if img == "" { + log.Logger.Fatal().Msg("Could not get the image name from cmdline (i.e. cos-img/filename=/cOS/active.img)") + } + + log.Debug().Str("what", img).Msg("Target device") + log.Debug().Str("what", label).Msg("Target label") + return img, label +} + +// DisableImmucore identifies if we need to be disabled +// We disable if we boot from CD, netboot, recovery or have the rd.cos.disable stanza in cmdline +func DisableImmucore() bool { + cmdline, _ := os.ReadFile("/proc/cmdline") + cmdlineS := string(cmdline) + + return strings.Contains(cmdlineS, "live:LABEL") || strings.Contains(cmdlineS, "live:CDLABEL") || strings.Contains(cmdlineS, "netboot") || strings.Contains(cmdlineS, "rd.cos.disable") +} + +// RootRW tells us if the mode to mount root +func RootRW() string { + if len(ReadCMDLineArg("rd.cos.debugrw")) > 0 { + log.Logger.Warn().Msg("Mounting root as RW") + return "rw" + } + return "ro" +} diff --git a/pkg/mount/dag_steps.go b/pkg/mount/dag_steps.go index 1c67dd3..7240cf6 100644 --- a/pkg/mount/dag_steps.go +++ b/pkg/mount/dag_steps.go @@ -33,22 +33,16 @@ func (s *State) MountRootDagStep(g *herd.Graph) error { if err != nil { s.Logger.Debug().Err(err).Msg("runtime") } - stateName := runtime.State.Name - stateFs := runtime.State.Type - // Recovery is a different partition - if internalUtils.IsRecovery() { - stateName = runtime.Recovery.Name - stateFs = runtime.Recovery.Type - } + // 1 - mount the state partition to find the images (active/passive/recovery) err = g.Add(cnst.OpMountState, herd.WithCallback( s.MountOP( - stateName, + runtime.State.Name, s.path("/run/initramfs/cos-state"), - stateFs, + runtime.State.Type, []string{ - "ro", // or rw + s.RootMountMode, }, 60*time.Second), ), ) @@ -74,8 +68,9 @@ func (s *State) MountRootDagStep(g *herd.Graph) error { // On some systems the COS_ACTIVE/PASSIVE label is automatically shown as soon as we mount the device // But on other it seems like it won't trigger which causes the sysroot to not be mounted as we cant find // the block device by the target label. Make sure we run this after mounting so we refresh the devices. - sh, _ := utils.SH("udevadm trigger --settle") + sh, _ := utils.SH("udevadm trigger") s.Logger.Debug().Str("output", sh).Msg("udevadm trigger") + log.Logger.Debug().Str("targetImage", s.TargetImage).Str("path", s.Rootdir).Str("TargetLabel", s.TargetLabel).Msg("mount done") return err }, )) @@ -93,7 +88,7 @@ func (s *State) MountRootDagStep(g *herd.Graph) error { s.Rootdir, "ext4", // are images always ext2? []string{ - "ro", // or rw + s.RootMountMode, "suid", "dev", "exec", diff --git a/pkg/mount/state.go b/pkg/mount/state.go index 97422d8..cd3df5e 100644 --- a/pkg/mount/state.go +++ b/pkg/mount/state.go @@ -19,19 +19,19 @@ import ( ) type State struct { - Logger zerolog.Logger - Rootdir string // e.g. /sysroot inside initrd with pivot, / with nopivot - TargetImage string // e.g. /cOS/active.img - TargetLabel string // e.g. COS_ACTIVE + Logger zerolog.Logger + Rootdir string // where to mount the root partition e.g. /sysroot inside initrd with pivot, / with nopivot + TargetImage string // image from the state partition to mount as loop device e.g. /cOS/active.img + TargetLabel string // e.g. COS_ACTIVE + RootMountMode string // How to mount the root partition e.g. ro or rw // /run/cos-layout.env (different!) OverlayDirs []string // e.g. /var BindMounts []string // e.g. /etc/kubernetes CustomMounts map[string]string // e.g. diskid : mountpoint - StateDir string // e.g. "/usr/local/.state" - MountRoot bool // e.g. if true, it tries to find the image to loopback mount - fstabs []*fstab.Mount + StateDir string // e.g. "/usr/local/.state" + fstabs []*fstab.Mount } func (s *State) path(p ...string) string { diff --git a/pkg/mount/state_test.go b/pkg/mount/state_test.go index ffabcbd..651a086 100644 --- a/pkg/mount/state_test.go +++ b/pkg/mount/state_test.go @@ -28,7 +28,6 @@ var _ = Describe("mounting immutable setup", func() { Rootdir: "/", TargetImage: "/cOS/myimage.img", TargetLabel: "COS_LABEL", - MountRoot: true, } err := s.RegisterNormalBoot(g) @@ -40,7 +39,7 @@ var _ = Describe("mounting immutable setup", func() { }) It("generates normal dag with extra dirs", func() { - s := &mount.State{Rootdir: "/", MountRoot: true, + s := &mount.State{Rootdir: "/", OverlayDirs: []string{"/etc"}, BindMounts: []string{"/etc/kubernetes"}, CustomMounts: map[string]string{"COS_PERSISTENT": "/usr/local"}}