mirror of
https://github.com/kairos-io/immucore.git
synced 2025-04-27 11:12:30 +00:00
Uki Support (#67)
Signed-off-by: Itxaka <itxaka.garcia@spectrocloud.com>
This commit is contained in:
parent
de9ed759eb
commit
086227d672
4
go.mod
4
go.mod
@ -9,11 +9,13 @@ require (
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/kairos-io/kairos v1.5.0
|
||||
github.com/moby/sys/mountinfo v0.6.2
|
||||
github.com/mudler/go-kdetect v0.0.0-20210802130128-dd92e121bed8
|
||||
github.com/onsi/ginkgo/v2 v2.8.4
|
||||
github.com/onsi/gomega v1.27.2
|
||||
github.com/rs/zerolog v1.29.0
|
||||
github.com/spectrocloud-labs/herd v0.4.2
|
||||
github.com/urfave/cli/v2 v2.24.4
|
||||
golang.org/x/sys v0.5.0
|
||||
)
|
||||
|
||||
require (
|
||||
@ -49,6 +51,7 @@ require (
|
||||
github.com/mattn/go-runewidth v0.0.14 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
|
||||
github.com/pilebones/go-udev v0.0.0-20210126000448-a3c2a7a4afb7 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pterm/pterm v0.12.54 // indirect
|
||||
github.com/qeesung/image2ascii v1.0.1 // indirect
|
||||
@ -62,7 +65,6 @@ require (
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 // indirect
|
||||
golang.org/x/net v0.7.0 // indirect
|
||||
golang.org/x/sys v0.5.0 // indirect
|
||||
golang.org/x/term v0.5.0 // indirect
|
||||
golang.org/x/text v0.7.0 // indirect
|
||||
golang.org/x/tools v0.6.0 // indirect
|
||||
|
12
go.sum
12
go.sum
@ -68,8 +68,6 @@ github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2
|
||||
github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00=
|
||||
github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600=
|
||||
github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
|
||||
github.com/Microsoft/hcsshim v0.9.6 h1:VwnDOgLeoi2du6dAznfmspNqTiwczvjv4K7NxuY9jsY=
|
||||
github.com/Microsoft/hcsshim v0.9.6/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc=
|
||||
github.com/Microsoft/hcsshim v0.9.7 h1:mKNHW/Xvv1aFH87Jb6ERDzXTJTLPlmzfZ28VBFD/bfg=
|
||||
github.com/Microsoft/hcsshim v0.9.7/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc=
|
||||
github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU=
|
||||
@ -166,8 +164,6 @@ github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09Zvgq
|
||||
github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s=
|
||||
github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g=
|
||||
github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c=
|
||||
github.com/containerd/containerd v1.6.18 h1:qZbsLvmyu+Vlty0/Ex5xc0z2YtKpIsb5n45mAMI+2Ns=
|
||||
github.com/containerd/containerd v1.6.18/go.mod h1:1RdCUu95+gc2v9t3IL+zIlpClSmew7/0YS8O5eQZrOw=
|
||||
github.com/containerd/containerd v1.6.19 h1:F0qgQPrG0P2JPgwpxWxYavrVeXAG0ezUIB9Z/4FTUAU=
|
||||
github.com/containerd/containerd v1.6.19/go.mod h1:HZCDMn4v/Xl2579/MvtOC2M206i+JJ6VxFWU/NetrGY=
|
||||
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||
@ -543,6 +539,8 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
|
||||
github.com/mudler/go-kdetect v0.0.0-20210802130128-dd92e121bed8 h1:+g0budy5fEFMX5+ChzEhXbb7YnNWNveQgHF/iQ/UXmE=
|
||||
github.com/mudler/go-kdetect v0.0.0-20210802130128-dd92e121bed8/go.mod h1:826dAJvIa3X5kfBoxSupdQbIFO4egt+hoUiw4BfPKdI=
|
||||
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
@ -564,8 +562,6 @@ github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+
|
||||
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo/v2 v2.8.3 h1:RpbK1G8nWPNaCVFBWsOGnEQQGgASi6b8fxcWBvDYjxQ=
|
||||
github.com/onsi/ginkgo/v2 v2.8.3/go.mod h1:6OaUA8BCi0aZfmzYT/q9AacwTzDpNbxILUT+TlBq6MY=
|
||||
github.com/onsi/ginkgo/v2 v2.8.4 h1:gf5mIQ8cLFieruNLAdgijHF1PYfLphKm2dxxcUtcqK0=
|
||||
github.com/onsi/ginkgo/v2 v2.8.4/go.mod h1:427dEDQZkDKsBvCjc2A/ZPefhKxsTTrsQegMlayL730=
|
||||
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
@ -575,8 +571,6 @@ github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa
|
||||
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.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
|
||||
github.com/onsi/gomega v1.27.1 h1:rfztXRbg6nv/5f+Raen9RcGoSecHIFgBBLQK3Wdj754=
|
||||
github.com/onsi/gomega v1.27.1/go.mod h1:aHX5xOykVYzWOV4WqQy0sy8BQptgukenXpCXfadcIAw=
|
||||
github.com/onsi/gomega v1.27.2 h1:SKU0CXeKE/WVgIV1T61kSa3+IRE8Ekrv9rdXDwwTqnY=
|
||||
github.com/onsi/gomega v1.27.2/go.mod h1:5mR3phAHpkAVIDkHEUBY6HGVsU+cpcEscrGPB4oPlZI=
|
||||
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
@ -606,6 +600,8 @@ github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xA
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||
github.com/pilebones/go-udev v0.0.0-20210126000448-a3c2a7a4afb7 h1:1If5vu3Qy1ZL3NshlsrSQMsdRhujenaVFbHcFM9XQUk=
|
||||
github.com/pilebones/go-udev v0.0.0-20210126000448-a3c2a7a4afb7/go.mod h1:T2eI2tUSK0hA2WS5QLjXJUfQkluZQu+18Cqvem3CaXI=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
|
@ -10,22 +10,22 @@ func DefaultRWPaths() []string {
|
||||
var ErrAlreadyMounted = errors.New("already mounted")
|
||||
|
||||
const (
|
||||
OpCustomMounts = "custom-mount"
|
||||
OpDiscoverState = "discover-state"
|
||||
OpMountState = "mount-state"
|
||||
OpMountBind = "mount-bind"
|
||||
|
||||
OpMountRoot = "mount-root"
|
||||
OpOverlayMount = "overlay-mount"
|
||||
OpWriteFstab = "write-fstab"
|
||||
OpMountBaseOverlay = "mount-base-overlay"
|
||||
OpMountOEM = "mount-oem"
|
||||
|
||||
OpRootfsHook = "rootfs-hook"
|
||||
OpLoadConfig = "load-config"
|
||||
OpMountTmpfs = "mount-tmpfs"
|
||||
|
||||
OpSentinel = "create-sentinel"
|
||||
|
||||
OpCustomMounts = "custom-mount"
|
||||
OpDiscoverState = "discover-state"
|
||||
OpMountState = "mount-state"
|
||||
OpMountBind = "mount-bind"
|
||||
OpMountRoot = "mount-root"
|
||||
OpOverlayMount = "overlay-mount"
|
||||
OpWriteFstab = "write-fstab"
|
||||
OpMountBaseOverlay = "mount-base-overlay"
|
||||
OpMountOEM = "mount-oem"
|
||||
OpRootfsHook = "rootfs-hook"
|
||||
OpInitramfsHook = "initramfs-hook"
|
||||
OpLoadConfig = "load-config"
|
||||
OpMountTmpfs = "mount-tmpfs"
|
||||
OpRemountRootRO = "remount-ro"
|
||||
OpUkiInit = "uki-init"
|
||||
OpSentinel = "create-sentinel"
|
||||
OpUkiUdev = "uki-udev"
|
||||
PersistentStateTarget = "/usr/local/.state"
|
||||
)
|
||||
|
@ -3,8 +3,8 @@ package utils
|
||||
import (
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/kairos-io/kairos/sdk/state"
|
||||
"github.com/rs/zerolog/log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
@ -32,7 +32,7 @@ func BootStateToLabelDevice() string {
|
||||
func GetRootDir() string {
|
||||
cmdline, _ := os.ReadFile("/proc/cmdline")
|
||||
switch {
|
||||
case strings.Contains(string(cmdline), "IMMUCORE_NOPIVOT"):
|
||||
case strings.Contains(string(cmdline), "rd.immucore.uki"):
|
||||
return "/"
|
||||
default:
|
||||
// Default is sysroot for normal no-pivot boot
|
||||
@ -99,7 +99,7 @@ func CleanupSlice(slice []string) []string {
|
||||
|
||||
// GetTarget gets the target image and device to mount in /sysroot
|
||||
func GetTarget(dryRun bool) (string, string) {
|
||||
var img, label string
|
||||
var label string
|
||||
|
||||
label = BootStateToLabelDevice()
|
||||
|
||||
@ -108,16 +108,20 @@ func GetTarget(dryRun bool) (string, string) {
|
||||
return "fake", label
|
||||
}
|
||||
|
||||
img = ReadCMDLineArg("cos-img/filename=")[0]
|
||||
imgs := ReadCMDLineArg("cos-img/filename=")
|
||||
|
||||
// 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)")
|
||||
if len(imgs) == 0 {
|
||||
if IsUKI() {
|
||||
imgs = []string{""}
|
||||
} else {
|
||||
Log.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
|
||||
Log.Debug().Str("what", imgs[0]).Msg("Target device")
|
||||
Log.Debug().Str("what", label).Msg("Target label")
|
||||
return imgs[0], label
|
||||
}
|
||||
|
||||
// DisableImmucore identifies if we need to be disabled
|
||||
@ -132,7 +136,7 @@ func DisableImmucore() bool {
|
||||
// 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")
|
||||
Log.Warn().Msg("Mounting root as RW")
|
||||
return "rw"
|
||||
}
|
||||
return "ro"
|
||||
@ -152,6 +156,24 @@ func GetState() string {
|
||||
case state.Recovery:
|
||||
label = filepath.Join("/dev/disk/by-label/", runtime.Recovery.Label)
|
||||
}
|
||||
log.Logger.Debug().Str("what", label).Msg("Get state label")
|
||||
Log.Debug().Str("what", label).Msg("Get state label")
|
||||
return label
|
||||
}
|
||||
|
||||
func IsUKI() bool {
|
||||
if len(ReadCMDLineArg("rd.immucore.uki")) > 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// CommandWithPath runs a command adding the usual PATH to environment
|
||||
// Useful under UKI as there is nothing setting the PATH
|
||||
func CommandWithPath(c string) (string, error) {
|
||||
cmd := exec.Command("/bin/sh", "-c", c)
|
||||
cmd.Env = os.Environ()
|
||||
// TODO: extract PATH from env and append to existing instead of overwriting
|
||||
cmd.Env = append(cmd.Env, "PATH=/usr/bin:/usr/sbin")
|
||||
o, err := cmd.CombinedOutput()
|
||||
return string(o), err
|
||||
}
|
||||
|
45
internal/utils/log.go
Normal file
45
internal/utils/log.go
Normal file
@ -0,0 +1,45 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"github.com/rs/zerolog"
|
||||
"golang.org/x/sys/unix"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
var Log zerolog.Logger
|
||||
var devKmsgFile *os.File
|
||||
var logFile *os.File
|
||||
|
||||
func CloseLogFiles() {
|
||||
devKmsgFile.Close()
|
||||
logFile.Close()
|
||||
}
|
||||
|
||||
func SetLogger() {
|
||||
var loggers []io.Writer
|
||||
devKmsgFile, err := os.OpenFile("/dev/kmsg", unix.O_WRONLY, 0o600)
|
||||
if err == nil {
|
||||
loggers = append(loggers, zerolog.ConsoleWriter{Out: devKmsgFile})
|
||||
}
|
||||
logFile, err := os.Create("/run/immucore.log")
|
||||
if err == nil {
|
||||
loggers = append(loggers, zerolog.ConsoleWriter{Out: logFile})
|
||||
}
|
||||
|
||||
// No loggers? Then stdout ¯\_(ツ)_/¯
|
||||
if len(loggers) == 0 {
|
||||
loggers = append(loggers, zerolog.ConsoleWriter{Out: os.Stderr})
|
||||
}
|
||||
multi := zerolog.MultiLevelWriter(loggers...)
|
||||
Log = zerolog.New(multi).With().Logger()
|
||||
Log.WithLevel(zerolog.InfoLevel)
|
||||
|
||||
// Set debug logger
|
||||
debug := len(ReadCMDLineArg("rd.immucore.debug")) > 0
|
||||
debugFromEnv := os.Getenv("IMMUCORE_DEBUG") != ""
|
||||
if debug || debugFromEnv {
|
||||
Log = zerolog.New(multi).With().Caller().Logger()
|
||||
Log.WithLevel(zerolog.DebugLevel)
|
||||
}
|
||||
}
|
@ -4,11 +4,9 @@ import (
|
||||
"fmt"
|
||||
"github.com/containerd/containerd/mount"
|
||||
"github.com/deniswernert/go-fstab"
|
||||
"github.com/kairos-io/kairos/pkg/utils"
|
||||
"github.com/rs/zerolog/log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// https://github.com/kairos-io/packages/blob/7c3581a8ba6371e5ce10c3a98bae54fde6a505af/packages/system/dracut/immutable-rootfs/30cos-immutable-rootfs/cos-mount-layout.sh#L58
|
||||
@ -54,7 +52,7 @@ func ReadCMDLineArg(arg string) []string {
|
||||
|
||||
// IsMounted lets us know if the given device is currently mounted
|
||||
func IsMounted(dev string) bool {
|
||||
_, err := utils.SH(fmt.Sprintf("findmnt %s", dev))
|
||||
_, err := CommandWithPath(fmt.Sprintf("findmnt %s", dev))
|
||||
return err == nil
|
||||
}
|
||||
|
||||
@ -62,18 +60,19 @@ func IsMounted(dev string) bool {
|
||||
// Does NOT need to be mounted
|
||||
// Needs full path so either /dev/sda1 or /dev/disk/by-{label,uuid}/{label,uuid}
|
||||
func DiskFSType(s string) string {
|
||||
out, e := utils.SH(fmt.Sprintf("blkid %s -s TYPE -o value", s))
|
||||
out, e := CommandWithPath(fmt.Sprintf("blkid %s -s TYPE -o value", s))
|
||||
if e != nil {
|
||||
log.Logger.Err(e).Msg("blkid")
|
||||
Log.Err(e).Msg("blkid")
|
||||
}
|
||||
out = strings.Trim(strings.Trim(out, " "), "\n")
|
||||
log.Logger.Debug().Str("what", s).Str("type", out).Msg("Partition FS type")
|
||||
Log.Debug().Str("what", s).Str("type", out).Msg("Partition FS type")
|
||||
return out
|
||||
}
|
||||
|
||||
// SyncState will rsync source into destination. Useful for Bind mounts.
|
||||
func SyncState(src, dst string) error {
|
||||
return exec.Command("rsync", "-aqAX", src, dst).Run()
|
||||
_, err := CommandWithPath(fmt.Sprintf("rsync -aqAX %s %s", src, dst))
|
||||
return err
|
||||
}
|
||||
|
||||
// AppendSlash it's in the name. Appends a slash.
|
||||
@ -113,6 +112,9 @@ func MountToFstab(m mount.Mount) *fstab.Mount {
|
||||
// Special care for the root (/sysroot) path as we can't just simple remove that path and call it a day
|
||||
// as that will return an empty mountpoint which will break fstab mounting
|
||||
func CleanSysrootForFstab(path string) string {
|
||||
if IsUKI() {
|
||||
return path
|
||||
}
|
||||
cleaned := strings.ReplaceAll(path, "/sysroot", "")
|
||||
if cleaned == "" {
|
||||
cleaned = "/"
|
||||
@ -161,11 +163,41 @@ func Fsck(device string) error {
|
||||
args = append(args, "-n")
|
||||
}
|
||||
cmd := strings.Join(args, " ")
|
||||
log.Logger.Debug().Str("cmd", cmd).Msg("fsck command")
|
||||
out, e := utils.SH(cmd)
|
||||
log.Logger.Debug().Str("output", out).Msg("fsck output")
|
||||
Log.Debug().Str("cmd", cmd).Msg("fsck command")
|
||||
out, e := CommandWithPath(cmd)
|
||||
Log.Debug().Str("output", out).Msg("fsck output")
|
||||
if e != nil {
|
||||
log.Logger.Warn().Str("error", e.Error()).Str("what", device).Msg("fsck")
|
||||
Log.Warn().Str("error", e.Error()).Str("what", device).Msg("fsck")
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
// MinimalMounts will set the minimal mounts needed for immucore
|
||||
// For now only proc is needed to read the cmdline fully in uki mode
|
||||
// in normal modes this should already be done by the initramfs process, so we can ignore errors
|
||||
// Just mount dev, tmp and sys just in case
|
||||
func MinimalMounts() {
|
||||
type m struct {
|
||||
source string
|
||||
target string
|
||||
t string
|
||||
flags int
|
||||
data string
|
||||
}
|
||||
toMount := []m{
|
||||
{"dev", "/dev", "devtmpfs", syscall.MS_NOSUID, "mode=755"},
|
||||
{"proc", "/proc", "proc", syscall.MS_NOSUID | syscall.MS_NODEV | syscall.MS_NOEXEC | syscall.MS_RELATIME, ""},
|
||||
{"sys", "/sys", "sysfs", syscall.MS_NOSUID | syscall.MS_NODEV | syscall.MS_NOEXEC | syscall.MS_RELATIME, ""},
|
||||
{"tmp", "/tmp", "tmpfs", syscall.MS_NOSUID | syscall.MS_NODEV, ""},
|
||||
{"run", "/run", "tmpfs", syscall.MS_NOSUID | syscall.MS_NODEV | syscall.MS_NOEXEC | syscall.MS_RELATIME, "mode=755"},
|
||||
}
|
||||
for _, mnt := range toMount {
|
||||
_ = os.MkdirAll(mnt.target, 0755)
|
||||
if !IsMounted(mnt.target) {
|
||||
err := syscall.Mount(mnt.source, mnt.target, mnt.t, uintptr(mnt.flags), mnt.data)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import "runtime"
|
||||
var (
|
||||
version = "v0.0.1"
|
||||
// gitCommit is the git sha1 + dirty if build from a dirty git
|
||||
gitCommit = ""
|
||||
gitCommit = "none"
|
||||
)
|
||||
|
||||
func GetVersion() string {
|
||||
|
44
main.go
44
main.go
@ -6,8 +6,6 @@ import (
|
||||
"github.com/kairos-io/immucore/internal/utils"
|
||||
"github.com/kairos-io/immucore/internal/version"
|
||||
"github.com/kairos-io/immucore/pkg/mount"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/spectrocloud-labs/herd"
|
||||
"github.com/urfave/cli/v2"
|
||||
"os"
|
||||
@ -20,27 +18,23 @@ func main() {
|
||||
app.Authors = []*cli.Author{{Name: "Kairos authors"}}
|
||||
app.Copyright = "kairos authors"
|
||||
app.Action = func(c *cli.Context) (err error) {
|
||||
debug := len(utils.ReadCMDLineArg("rd.immucore.debug")) > 0
|
||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).With().Logger()
|
||||
zerolog.SetGlobalLevel(zerolog.InfoLevel)
|
||||
debugFromEnv := os.Getenv("IMMUCORE_DEBUG") != ""
|
||||
if debug || debugFromEnv {
|
||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).With().Caller().Logger()
|
||||
zerolog.SetGlobalLevel(zerolog.DebugLevel)
|
||||
}
|
||||
var targetDevice, targetImage string
|
||||
var state *mount.State
|
||||
|
||||
utils.MinimalMounts()
|
||||
utils.SetLogger()
|
||||
|
||||
v := version.Get()
|
||||
log.Logger.Info().Str("commit", v.GitCommit).Str("compiled with", v.GoVersion).Str("version", v.Version).Msg("Immucore")
|
||||
utils.Log.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))
|
||||
utils.Log.Debug().Str("content", string(cmdline)).Msg("cmdline")
|
||||
g := herd.DAG(herd.EnableInit)
|
||||
|
||||
// Get targets and state
|
||||
targetImage, targetDevice := utils.GetTarget(c.Bool("dry-run"))
|
||||
targetImage, targetDevice = utils.GetTarget(c.Bool("dry-run"))
|
||||
|
||||
s := &mount.State{
|
||||
Logger: log.Logger,
|
||||
state = &mount.State{
|
||||
Rootdir: utils.GetRootDir(),
|
||||
TargetDevice: targetDevice,
|
||||
TargetImage: targetImage,
|
||||
@ -48,19 +42,21 @@ func main() {
|
||||
}
|
||||
|
||||
if utils.DisableImmucore() {
|
||||
log.Logger.Info().Msg("Stanza rd.cos.disable on the cmdline or booting from CDROM/Netboot/Squash recovery. Disabling immucore.")
|
||||
err = s.RegisterLiveMedia(g)
|
||||
utils.Log.Info().Msg("Stanza rd.cos.disable on the cmdline or booting from CDROM/Netboot/Squash recovery. Disabling immucore.")
|
||||
err = state.RegisterLiveMedia(g)
|
||||
} else if utils.IsUKI() {
|
||||
utils.Log.Info().Msg("UKI booting!")
|
||||
err = state.RegisterUKI(g)
|
||||
} else {
|
||||
log.Logger.Info().Msg("Booting on active/passive/recovery.")
|
||||
err = s.RegisterNormalBoot(g)
|
||||
utils.Log.Info().Msg("Booting on active/passive/recovery.")
|
||||
err = state.RegisterNormalBoot(g)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
s.Logger.Err(err)
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info().Msg(s.WriteDAG(g))
|
||||
utils.Log.Info().Msg(state.WriteDAG(g))
|
||||
|
||||
// Once we print the dag we can exit already
|
||||
if c.Bool("dry-run") {
|
||||
@ -68,7 +64,7 @@ func main() {
|
||||
}
|
||||
|
||||
err = g.Run(context.Background())
|
||||
log.Info().Msg(s.WriteDAG(g))
|
||||
utils.Log.Info().Msg(state.WriteDAG(g))
|
||||
return err
|
||||
}
|
||||
app.Flags = []cli.Flag{
|
||||
@ -81,10 +77,8 @@ func main() {
|
||||
Name: "version",
|
||||
Usage: "version",
|
||||
Action: func(c *cli.Context) error {
|
||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).With().Logger()
|
||||
zerolog.SetGlobalLevel(zerolog.InfoLevel)
|
||||
v := version.Get()
|
||||
log.Logger.Info().Str("commit", v.GitCommit).Str("compiled with", v.GoVersion).Str("version", v.Version).Msg("Immucore")
|
||||
utils.Log.Info().Str("commit", v.GitCommit).Str("compiled with", v.GoVersion).Str("version", v.Version).Msg("Immucore")
|
||||
return nil
|
||||
},
|
||||
},
|
||||
|
@ -1,6 +1,7 @@
|
||||
package mount
|
||||
|
||||
import (
|
||||
internalUtils "github.com/kairos-io/immucore/internal/utils"
|
||||
"github.com/spectrocloud-labs/herd"
|
||||
)
|
||||
|
||||
@ -10,5 +11,6 @@ func (s *State) RegisterLiveMedia(g *herd.Graph) error {
|
||||
var err error
|
||||
// Maybe LogIfErrorAndPanic ? If no sentinel, a lot of config files are not going to run
|
||||
err = s.LogIfErrorAndReturn(s.WriteSentinelDagStep(g), "write sentinel")
|
||||
internalUtils.CloseLogFiles()
|
||||
return err
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package mount
|
||||
|
||||
import (
|
||||
cnst "github.com/kairos-io/immucore/internal/constants"
|
||||
internalUtils "github.com/kairos-io/immucore/internal/utils"
|
||||
"github.com/spectrocloud-labs/herd"
|
||||
)
|
||||
|
||||
@ -31,7 +32,7 @@ func (s *State) RegisterNormalBoot(g *herd.Graph) error {
|
||||
|
||||
// Populate state bind mounts, overlay mounts, custom-mounts from /run/cos/cos-layout.env
|
||||
// Requires stage rootfs to have run, which usually creates the cos-layout.env file
|
||||
s.LogIfError(s.LoadEnvLayoutDagStep(g), "loading cos-layout.env")
|
||||
s.LogIfError(s.LoadEnvLayoutDagStep(g, cnst.OpRootfsHook), "loading cos-layout.env")
|
||||
|
||||
// Mount base overlay under /run/overlay
|
||||
s.LogIfError(s.MountBaseOverlayDagStep(g), "base overlay mount")
|
||||
@ -51,6 +52,6 @@ func (s *State) RegisterNormalBoot(g *herd.Graph) error {
|
||||
|
||||
// Write fstab file
|
||||
s.LogIfError(s.WriteFstabDagStep(g), "write fstab")
|
||||
|
||||
internalUtils.CloseLogFiles()
|
||||
return err
|
||||
}
|
||||
|
@ -9,12 +9,13 @@ import (
|
||||
internalUtils "github.com/kairos-io/immucore/internal/utils"
|
||||
"github.com/kairos-io/kairos/pkg/utils"
|
||||
"github.com/kairos-io/kairos/sdk/state"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/mudler/go-kdetect"
|
||||
"github.com/spectrocloud-labs/herd"
|
||||
"golang.org/x/sys/unix"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -43,7 +44,7 @@ func (s *State) MountRootDagStep(g *herd.Graph) error {
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
s.Logger.Err(err).Send()
|
||||
internalUtils.Log.Err(err).Send()
|
||||
}
|
||||
|
||||
// 2 - mount the image as a loop device
|
||||
@ -53,7 +54,7 @@ func (s *State) MountRootDagStep(g *herd.Graph) error {
|
||||
func(ctx context.Context) error {
|
||||
// Check if loop device is mounted already
|
||||
if internalUtils.IsMounted(s.TargetDevice) {
|
||||
log.Logger.Debug().Str("targetImage", s.TargetImage).Str("path", s.Rootdir).Str("TargetDevice", s.TargetDevice).Msg("Not mounting loop, already mounted")
|
||||
internalUtils.Log.Debug().Str("targetImage", s.TargetImage).Str("path", s.Rootdir).Str("TargetDevice", s.TargetDevice).Msg("Not mounting loop, already mounted")
|
||||
return nil
|
||||
}
|
||||
_ = internalUtils.Fsck(s.path("/run/initramfs/cos-state", s.TargetImage))
|
||||
@ -65,13 +66,13 @@ func (s *State) MountRootDagStep(g *herd.Graph) error {
|
||||
// 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")
|
||||
s.Logger.Debug().Str("output", sh).Msg("udevadm trigger")
|
||||
log.Logger.Debug().Str("targetImage", s.TargetImage).Str("path", s.Rootdir).Str("TargetDevice", s.TargetDevice).Msg("mount done")
|
||||
internalUtils.Log.Debug().Str("output", sh).Msg("udevadm trigger")
|
||||
internalUtils.Log.Debug().Str("targetImage", s.TargetImage).Str("path", s.Rootdir).Str("TargetDevice", s.TargetDevice).Msg("mount done")
|
||||
return err
|
||||
},
|
||||
))
|
||||
if err != nil {
|
||||
s.Logger.Err(err).Send()
|
||||
internalUtils.Log.Err(err).Send()
|
||||
}
|
||||
|
||||
// 3 - Mount the labels as Rootdir
|
||||
@ -94,7 +95,7 @@ func (s *State) MountRootDagStep(g *herd.Graph) error {
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
s.Logger.Err(err).Send()
|
||||
internalUtils.Log.Err(err).Send()
|
||||
}
|
||||
return err
|
||||
}
|
||||
@ -104,19 +105,23 @@ func (s *State) RootfsStageDagStep(g *herd.Graph, deps ...string) error {
|
||||
return g.Add(cnst.OpRootfsHook, herd.WithDeps(deps...), herd.WithCallback(s.RunStageOp("rootfs")))
|
||||
}
|
||||
|
||||
// InitramfsStageDagStep will add the rootfs stage.
|
||||
func (s *State) InitramfsStageDagStep(g *herd.Graph, deps ...string) error {
|
||||
return g.Add(cnst.OpInitramfsHook, herd.WithDeps(deps...), herd.WeakDeps, herd.WithCallback(s.RunStageOp("initramfs")))
|
||||
}
|
||||
|
||||
// LoadEnvLayoutDagStep will add the stage to load from cos-layout.env and fill the proper CustomMounts, OverlayDirs and BindMounts
|
||||
func (s *State) LoadEnvLayoutDagStep(g *herd.Graph) error {
|
||||
func (s *State) LoadEnvLayoutDagStep(g *herd.Graph, deps ...string) error {
|
||||
return g.Add(cnst.OpLoadConfig,
|
||||
herd.WithDeps(cnst.OpRootfsHook),
|
||||
herd.WithDeps(deps...),
|
||||
herd.WithCallback(func(ctx context.Context) error {
|
||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).With().Logger()
|
||||
if s.CustomMounts == nil {
|
||||
s.CustomMounts = map[string]string{}
|
||||
}
|
||||
|
||||
env, err := internalUtils.ReadEnv("/run/cos/cos-layout.env")
|
||||
if err != nil {
|
||||
log.Logger.Err(err).Msg("Reading env")
|
||||
internalUtils.Log.Err(err).Msg("Reading env")
|
||||
return err
|
||||
}
|
||||
// populate from env here
|
||||
@ -162,7 +167,7 @@ func (s *State) LoadEnvLayoutDagStep(g *herd.Graph) error {
|
||||
func (s *State) MountOemDagStep(g *herd.Graph, deps ...string) error {
|
||||
runtime, err := state.NewRuntime()
|
||||
if err != nil {
|
||||
s.Logger.Debug().Err(err).Msg("runtime")
|
||||
internalUtils.Log.Debug().Err(err).Msg("runtime")
|
||||
}
|
||||
return g.Add(cnst.OpMountOEM,
|
||||
herd.WithDeps(deps...),
|
||||
@ -220,13 +225,13 @@ func (s *State) MountCustomOverlayDagStep(g *herd.Graph) error {
|
||||
herd.WithCallback(
|
||||
func(ctx context.Context) error {
|
||||
var multierr *multierror.Error
|
||||
s.Logger.Debug().Strs("dirs", s.OverlayDirs).Msg("Mounting overlays")
|
||||
internalUtils.Log.Debug().Strs("dirs", s.OverlayDirs).Msg("Mounting overlays")
|
||||
for _, p := range s.OverlayDirs {
|
||||
op := mountWithBaseOverlay(p, s.Rootdir, "/run/overlay")
|
||||
err := op.run()
|
||||
// Append to errors only if it's not an already mounted error
|
||||
if err != nil && !errors.Is(err, cnst.ErrAlreadyMounted) {
|
||||
log.Logger.Err(err).Msg("overlay mount")
|
||||
internalUtils.Log.Err(err).Msg("overlay mount")
|
||||
multierr = multierror.Append(multierr, err)
|
||||
continue
|
||||
}
|
||||
@ -249,20 +254,25 @@ func (s *State) MountCustomMountsDagStep(g *herd.Graph) error {
|
||||
// TODO: scan for the custom mount disk to know the underlying fs and set it proper
|
||||
fstype := "ext4"
|
||||
mountOptions := []string{"ro"}
|
||||
// TODO: Are custom mounts always rw?ro?depends? Clarify.
|
||||
// Persistent needs to be RW
|
||||
if strings.Contains(what, "COS_PERSISTENT") {
|
||||
mountOptions = []string{"rw"}
|
||||
}
|
||||
err = multierror.Append(err, s.MountOP(
|
||||
err2 := s.MountOP(
|
||||
what,
|
||||
s.path(where),
|
||||
fstype,
|
||||
mountOptions,
|
||||
10*time.Second,
|
||||
)(ctx))
|
||||
3*time.Second,
|
||||
)(ctx)
|
||||
|
||||
// If its COS_OEM and it fails then we can safely ignore, as it's not mandatory to have COS_OEM
|
||||
if err2 != nil && !strings.Contains(what, "COS_OEM") {
|
||||
err = multierror.Append(err, err2)
|
||||
}
|
||||
}
|
||||
s.Logger.Err(err.ErrorOrNil()).Send()
|
||||
internalUtils.Log.Err(err.ErrorOrNil()).Send()
|
||||
|
||||
return err.ErrorOrNil()
|
||||
}),
|
||||
@ -277,7 +287,7 @@ func (s *State) MountCustomBindsDagStep(g *herd.Graph) error {
|
||||
herd.WithCallback(
|
||||
func(ctx context.Context) error {
|
||||
var err *multierror.Error
|
||||
s.Logger.Debug().Strs("mounts", s.BindMounts).Msg("Mounting binds")
|
||||
internalUtils.Log.Debug().Strs("mounts", s.BindMounts).Msg("Mounting binds")
|
||||
|
||||
for _, p := range s.BindMounts {
|
||||
op := mountBind(p, s.Rootdir, s.StateDir)
|
||||
@ -288,11 +298,11 @@ func (s *State) MountCustomBindsDagStep(g *herd.Graph) error {
|
||||
}
|
||||
// Append to errors only if it's not an already mounted error
|
||||
if err2 != nil && !errors.Is(err2, cnst.ErrAlreadyMounted) {
|
||||
log.Logger.Err(err2).Send()
|
||||
internalUtils.Log.Err(err2).Send()
|
||||
err = multierror.Append(err, err2)
|
||||
}
|
||||
}
|
||||
log.Logger.Err(err.ErrorOrNil()).Send()
|
||||
internalUtils.Log.Err(err.ErrorOrNil()).Send()
|
||||
return err.ErrorOrNil()
|
||||
},
|
||||
),
|
||||
@ -345,11 +355,111 @@ func (s *State) WriteSentinelDagStep(g *herd.Graph) error {
|
||||
sentinel = "live_mode"
|
||||
}
|
||||
|
||||
s.Logger.Info().Str("to", sentinel).Msg("Setting sentinel file")
|
||||
internalUtils.Log.Info().Str("to", sentinel).Msg("Setting sentinel file")
|
||||
err = os.WriteFile(filepath.Join("/run/cos/", sentinel), []byte("1"), os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Lets add a uki sentinel as well!
|
||||
if strings.Contains(cmdlineS, "rd.immucore.uki") {
|
||||
err = os.WriteFile("/run/cos/uki_mode", []byte("1"), os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}))
|
||||
}
|
||||
|
||||
// UKIBootInitDagStep tries to launch /sbin/init in root and pass over the system
|
||||
// booting to the real init process
|
||||
// Drops to emergency if not able to. Panic if it cant even launch emergency
|
||||
func (s *State) UKIBootInitDagStep(g *herd.Graph, deps ...string) error {
|
||||
return g.Add(cnst.OpUkiInit,
|
||||
herd.WithDeps(deps...),
|
||||
herd.WeakDeps,
|
||||
herd.WithCallback(func(ctx context.Context) error {
|
||||
// Print dag before exit, otherwise its never printed as we never exit the program
|
||||
internalUtils.Log.Info().Msg(s.WriteDAG(g))
|
||||
internalUtils.Log.Debug().Msg("Executing init callback!")
|
||||
internalUtils.CloseLogFiles()
|
||||
if err := unix.Exec("/sbin/init", []string{"/sbin/init", "--system"}, os.Environ()); err != nil {
|
||||
internalUtils.Log.Err(err).Msg("running init")
|
||||
// drop to emergency shell
|
||||
if err := unix.Exec("/bin/bash", []string{"/bin/bash"}, os.Environ()); err != nil {
|
||||
internalUtils.Log.Fatal().Msg("Could not drop to emergency shell")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}))
|
||||
}
|
||||
|
||||
// UKIRemountRootRODagStep remount root read only
|
||||
func (s *State) UKIRemountRootRODagStep(g *herd.Graph, deps ...string) error {
|
||||
return g.Add(cnst.OpRemountRootRO,
|
||||
herd.WithDeps(deps...),
|
||||
herd.WithCallback(func(ctx context.Context) error {
|
||||
return syscall.Mount("/", "/", "rootfs", syscall.MS_REMOUNT|syscall.MS_RDONLY, "")
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
// UKIUdevDaemon launches the udevd daemon and triggers+settles in order to discover devices
|
||||
// Needed if we expect to find devices by label...
|
||||
func (s *State) UKIUdevDaemon(g *herd.Graph) error {
|
||||
return g.Add(cnst.OpUkiUdev,
|
||||
herd.WithCallback(func(ctx context.Context) error {
|
||||
// Should probably figure out other udevd binaries....
|
||||
var udevBin string
|
||||
if _, err := os.Stat("/usr/lib/systemd/systemd-udevd"); !os.IsNotExist(err) {
|
||||
udevBin = "/usr/lib/systemd/systemd-udevd"
|
||||
}
|
||||
cmd := fmt.Sprintf("%s --daemon", udevBin)
|
||||
out, err := internalUtils.CommandWithPath(cmd)
|
||||
internalUtils.Log.Debug().Str("out", out).Str("cmd", cmd).Msg("Udev daemon")
|
||||
if err != nil {
|
||||
internalUtils.Log.Err(err).Msg("Udev daemon")
|
||||
return err
|
||||
}
|
||||
out, err = internalUtils.CommandWithPath("udevadm trigger")
|
||||
internalUtils.Log.Debug().Str("out", out).Msg("Udev trigger")
|
||||
if err != nil {
|
||||
internalUtils.Log.Err(err).Msg("Udev trigger")
|
||||
return err
|
||||
}
|
||||
|
||||
out, err = internalUtils.CommandWithPath("udevadm settle")
|
||||
internalUtils.Log.Debug().Str("out", out).Msg("Udev settle")
|
||||
if err != nil {
|
||||
internalUtils.Log.Err(err).Msg("Udev settle")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
// LoadKernelModules loads kernel modules needed during uki boot to load the disks for.
|
||||
// Mainly block devices and net devices
|
||||
// probably others down the line
|
||||
func (s *State) LoadKernelModules(g *herd.Graph) error {
|
||||
return g.Add("kernel-modules",
|
||||
herd.WithCallback(func(ctx context.Context) error {
|
||||
drivers, err := kdetect.ProbeKernelModules("")
|
||||
if err != nil {
|
||||
internalUtils.Log.Err(err).Msg("Detecting needed modules")
|
||||
}
|
||||
internalUtils.Log.Debug().Strs("drivers", drivers).Msg("Detecting needed modules")
|
||||
for _, driver := range drivers {
|
||||
cmd := fmt.Sprintf("modprobe %s", driver)
|
||||
out, err := internalUtils.CommandWithPath(cmd)
|
||||
if err != nil {
|
||||
internalUtils.Log.Err(err).Str("out", out).Msg("modprobe")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
52
pkg/mount/dag_uki_boot.go
Normal file
52
pkg/mount/dag_uki_boot.go
Normal file
@ -0,0 +1,52 @@
|
||||
package mount
|
||||
|
||||
import (
|
||||
cnst "github.com/kairos-io/immucore/internal/constants"
|
||||
"github.com/spectrocloud-labs/herd"
|
||||
)
|
||||
|
||||
// RegisterUKI registers the dag for booting from UKI
|
||||
func (s *State) RegisterUKI(g *herd.Graph) error {
|
||||
// Write sentinel
|
||||
s.LogIfError(s.WriteSentinelDagStep(g), "sentinel")
|
||||
|
||||
s.LogIfError(s.LoadKernelModules(g), "kernel modules")
|
||||
|
||||
// Udev for devices discovery
|
||||
s.LogIfError(s.UKIUdevDaemon(g), "udev")
|
||||
|
||||
// Run rootfs stage
|
||||
s.LogIfError(s.RootfsStageDagStep(g, cnst.OpSentinel), "uki rootfs")
|
||||
|
||||
// Remount root RO
|
||||
s.LogIfError(s.UKIRemountRootRODagStep(g, cnst.OpRootfsHook), "remount root")
|
||||
|
||||
// Mount base overlay under /run/overlay
|
||||
s.LogIfError(s.MountBaseOverlayDagStep(g), "base overlay")
|
||||
|
||||
// Populate state bind mounts, overlay mounts, custom-mounts from /run/cos/cos-layout.env
|
||||
// Requires stage rootfs to have run, which usually creates the cos-layout.env file
|
||||
s.LogIfError(s.LoadEnvLayoutDagStep(g, cnst.OpRootfsHook), "loading cos-layout.env")
|
||||
|
||||
// Mount custom overlays loaded from the /run/cos/cos-layout.env file
|
||||
s.LogIfError(s.MountCustomOverlayDagStep(g), "custom overlays mount")
|
||||
|
||||
// Mount custom mounts loaded from the /run/cos/cos-layout.env file
|
||||
s.LogIfError(s.MountCustomMountsDagStep(g), "custom mounts mount")
|
||||
|
||||
// Mount custom binds loaded from the /run/cos/cos-layout.env file
|
||||
// Depends on mount binds as that usually mounts COS_PERSISTENT
|
||||
s.LogIfError(s.MountCustomBindsDagStep(g), "custom binds mount")
|
||||
|
||||
// run initramfs stage
|
||||
s.LogIfError(s.InitramfsStageDagStep(g, cnst.OpMountBind), "uki initramfs")
|
||||
|
||||
s.LogIfError(g.Add(cnst.OpWriteFstab,
|
||||
herd.WithDeps(cnst.OpLoadConfig, cnst.OpCustomMounts, cnst.OpMountBind, cnst.OpOverlayMount),
|
||||
herd.WeakDeps,
|
||||
herd.WithCallback(s.WriteFstab(s.path("/etc/fstab")))), "fstab")
|
||||
|
||||
// Handover to /sbin/init
|
||||
_ = s.UKIBootInitDagStep(g, cnst.OpRemountRootRO, cnst.OpRootfsHook, cnst.OpInitramfsHook)
|
||||
return nil
|
||||
}
|
@ -62,14 +62,13 @@ func mountBind(mountpoint, root, stateTarget string) mountOperation {
|
||||
Type: "overlay",
|
||||
Source: stateDir,
|
||||
Options: []string{
|
||||
//"defaults",
|
||||
"bind",
|
||||
},
|
||||
}
|
||||
|
||||
internalUtils.Log.Debug().Str("mountpoint", mountpoint).Str("root", root).Str("bindMountPath", bindMountPath).Msg("BIND")
|
||||
tmpFstab := internalUtils.MountToFstab(tmpMount)
|
||||
tmpFstab.File = internalUtils.CleanSysrootForFstab(fmt.Sprintf("/%s", mountpoint))
|
||||
tmpFstab.Spec = strings.ReplaceAll(tmpFstab.Spec, root, "")
|
||||
tmpFstab.Spec = internalUtils.CleanSysrootForFstab(tmpFstab.Spec)
|
||||
return mountOperation{
|
||||
MountOption: tmpMount,
|
||||
FstabEntry: *tmpFstab,
|
||||
|
@ -4,10 +4,8 @@ import (
|
||||
"github.com/containerd/containerd/mount"
|
||||
"github.com/deniswernert/go-fstab"
|
||||
"github.com/kairos-io/immucore/internal/constants"
|
||||
internalUtils "github.com/kairos-io/immucore/internal/utils"
|
||||
"github.com/moby/sys/mountinfo"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
"os"
|
||||
)
|
||||
|
||||
type mountOperation struct {
|
||||
@ -18,23 +16,23 @@ type mountOperation struct {
|
||||
}
|
||||
|
||||
func (m mountOperation) run() error {
|
||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).With().Str("what", m.MountOption.Source).Str("where", m.Target).Str("type", m.MountOption.Type).Strs("options", m.MountOption.Options).Logger()
|
||||
internalUtils.Log.With().Str("what", m.MountOption.Source).Str("where", m.Target).Str("type", m.MountOption.Type).Strs("options", m.MountOption.Options).Logger()
|
||||
if m.PrepareCallback != nil {
|
||||
if err := m.PrepareCallback(); err != nil {
|
||||
log.Logger.Err(err).Msg("executing mount callback")
|
||||
internalUtils.Log.Err(err).Msg("executing mount callback")
|
||||
return err
|
||||
}
|
||||
}
|
||||
//TODO: not only check if mounted but also if the type,options and source are the same?
|
||||
mounted, err := mountinfo.Mounted(m.Target)
|
||||
if err != nil {
|
||||
log.Logger.Err(err).Msg("checking mount status")
|
||||
internalUtils.Log.Err(err).Msg("checking mount status")
|
||||
return err
|
||||
}
|
||||
if mounted {
|
||||
log.Logger.Debug().Msg("Already mounted")
|
||||
internalUtils.Log.Debug().Msg("Already mounted")
|
||||
return constants.ErrAlreadyMounted
|
||||
}
|
||||
log.Logger.Debug().Msg("mount ready")
|
||||
internalUtils.Log.Debug().Msg("mount ready")
|
||||
return mount.All([]mount.Mount{m.MountOption}, m.Target)
|
||||
}
|
||||
|
@ -12,14 +12,11 @@ import (
|
||||
"github.com/deniswernert/go-fstab"
|
||||
"github.com/kairos-io/immucore/internal/constants"
|
||||
internalUtils "github.com/kairos-io/immucore/internal/utils"
|
||||
"github.com/kairos-io/kairos/pkg/utils"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/spectrocloud-labs/herd"
|
||||
)
|
||||
|
||||
type State struct {
|
||||
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
|
||||
TargetDevice string // e.g. /dev/disk/by-label/COS_ACTIVE
|
||||
@ -39,7 +36,6 @@ func (s *State) path(p ...string) string {
|
||||
}
|
||||
|
||||
func (s *State) WriteFstab(fstabFile string) func(context.Context) error {
|
||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).With().Logger()
|
||||
return func(ctx context.Context) error {
|
||||
for _, fst := range s.fstabs {
|
||||
select {
|
||||
@ -62,37 +58,38 @@ func (s *State) WriteFstab(fstabFile string) func(context.Context) error {
|
||||
}
|
||||
|
||||
// RunStageOp runs elemental run-stage stage. If its rootfs its special as it needs som symlinks
|
||||
// If its uki we don't symlink as we already have everything in the sysroot
|
||||
func (s *State) RunStageOp(stage string) func(context.Context) error {
|
||||
return func(ctx context.Context) error {
|
||||
if stage == "rootfs" {
|
||||
if stage == "rootfs" && !internalUtils.IsUKI() {
|
||||
if _, err := os.Stat("/system"); os.IsNotExist(err) {
|
||||
err = os.Symlink("/sysroot/system", "/system")
|
||||
if err != nil {
|
||||
s.Logger.Err(err).Msg("creating symlink")
|
||||
internalUtils.Log.Err(err).Msg("creating symlink")
|
||||
}
|
||||
}
|
||||
if _, err := os.Stat("/oem"); os.IsNotExist(err) {
|
||||
err = os.Symlink("/sysroot/oem", "/oem")
|
||||
if err != nil {
|
||||
s.Logger.Err(err).Msg("creating symlink")
|
||||
internalUtils.Log.Err(err).Msg("creating symlink")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cmd := fmt.Sprintf("elemental run-stage %s", stage)
|
||||
cmd := fmt.Sprintf("/usr/bin/elemental run-stage %s", stage)
|
||||
// If we set the level to debug, also call elemental with debug
|
||||
if s.Logger.GetLevel() == zerolog.DebugLevel {
|
||||
if internalUtils.Log.GetLevel() == zerolog.DebugLevel {
|
||||
cmd = fmt.Sprintf("%s --debug", cmd)
|
||||
}
|
||||
output, err := utils.SH(cmd)
|
||||
s.Logger.Debug().Msg(output)
|
||||
output, err := internalUtils.CommandWithPath(cmd)
|
||||
internalUtils.Log.Debug().Msg(output)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// MountOP creates and executes a mount operation
|
||||
func (s *State) MountOP(what, where, t string, options []string, timeout time.Duration) func(context.Context) error {
|
||||
log.Logger.With().Str("what", what).Str("where", where).Str("type", t).Strs("options", options).Logger()
|
||||
internalUtils.Log.With().Str("what", what).Str("where", where).Str("type", t).Strs("options", options).Logger()
|
||||
|
||||
return func(c context.Context) error {
|
||||
cc := time.After(timeout)
|
||||
@ -101,7 +98,7 @@ func (s *State) MountOP(what, where, t string, options []string, timeout time.Du
|
||||
default:
|
||||
err := internalUtils.CreateIfNotExists(where)
|
||||
if err != nil {
|
||||
log.Logger.Err(err).Msg("Creating dir")
|
||||
internalUtils.Log.Err(err).Msg("Creating dir")
|
||||
continue
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
@ -130,18 +127,18 @@ func (s *State) MountOP(what, where, t string, options []string, timeout time.Du
|
||||
|
||||
// only continue the loop if it's an error and not an already mounted error
|
||||
if err != nil && !errors.Is(err, constants.ErrAlreadyMounted) {
|
||||
s.Logger.Err(err).Send()
|
||||
internalUtils.Log.Err(err).Send()
|
||||
continue
|
||||
}
|
||||
log.Logger.Debug().Msg("mount done")
|
||||
internalUtils.Log.Debug().Msg("mount done")
|
||||
return nil
|
||||
case <-c.Done():
|
||||
e := fmt.Errorf("context canceled")
|
||||
log.Logger.Err(e).Msg("mount canceled")
|
||||
internalUtils.Log.Err(e).Msg("mount canceled")
|
||||
return e
|
||||
case <-cc:
|
||||
e := fmt.Errorf("timeout exhausted")
|
||||
log.Logger.Err(e).Msg("Mount timeout")
|
||||
internalUtils.Log.Err(e).Msg("Mount timeout")
|
||||
return e
|
||||
}
|
||||
}
|
||||
@ -167,7 +164,7 @@ func (s *State) WriteDAG(g *herd.Graph) (out string) {
|
||||
// Context can be empty
|
||||
func (s *State) LogIfError(e error, msgContext string) {
|
||||
if e != nil {
|
||||
s.Logger.Err(e).Msg(msgContext)
|
||||
internalUtils.Log.Err(e).Msg(msgContext)
|
||||
}
|
||||
}
|
||||
|
||||
@ -176,7 +173,7 @@ func (s *State) LogIfError(e error, msgContext string) {
|
||||
// Will also return the error
|
||||
func (s *State) LogIfErrorAndReturn(e error, msgContext string) error {
|
||||
if e != nil {
|
||||
s.Logger.Err(e).Msg(msgContext)
|
||||
internalUtils.Log.Err(e).Msg(msgContext)
|
||||
}
|
||||
return e
|
||||
}
|
||||
@ -186,7 +183,7 @@ func (s *State) LogIfErrorAndReturn(e error, msgContext string) error {
|
||||
// Will also panic
|
||||
func (s *State) LogIfErrorAndPanic(e error, msgContext string) {
|
||||
if e != nil {
|
||||
s.Logger.Err(e).Msg(msgContext)
|
||||
s.Logger.Fatal().Msg(e.Error())
|
||||
internalUtils.Log.Err(e).Msg(msgContext)
|
||||
internalUtils.Log.Fatal().Msg(e.Error())
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,6 @@ package mount_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/kairos-io/immucore/pkg/mount"
|
||||
@ -24,7 +21,6 @@ var _ = Describe("mounting immutable setup", func() {
|
||||
Context("simple invocation", func() {
|
||||
It("generates normal dag", func() {
|
||||
s := &mount.State{
|
||||
Logger: log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).With().Logger(),
|
||||
Rootdir: "/",
|
||||
TargetImage: "/cOS/myimage.img",
|
||||
TargetDevice: "/dev/disk/by-label/COS_LABEL",
|
||||
@ -73,17 +69,10 @@ var _ = Describe("mounting immutable setup", func() {
|
||||
func checkLiveCDDag(dag [][]herd.GraphEntry, actualDag string) {
|
||||
Expect(len(dag)).To(Equal(2), actualDag)
|
||||
Expect(len(dag[0])).To(Equal(1), actualDag)
|
||||
Expect(len(dag[1])).To(Equal(2), actualDag)
|
||||
Expect(len(dag[1])).To(Equal(1), actualDag)
|
||||
|
||||
Expect(dag[0][0].Name).To(Equal("init"))
|
||||
Expect(dag[1][0].Name).To(Or(
|
||||
Equal("mount-tmpfs"),
|
||||
Equal("create-sentinel"),
|
||||
), actualDag)
|
||||
Expect(dag[1][1].Name).To(Or(
|
||||
Equal("mount-tmpfs"),
|
||||
Equal("create-sentinel"),
|
||||
), actualDag)
|
||||
Expect(dag[1][0].Name).To(Equal("create-sentinel"))
|
||||
|
||||
}
|
||||
func checkDag(dag [][]herd.GraphEntry, actualDag string) {
|
||||
|
Loading…
Reference in New Issue
Block a user