2023-01-12 19:10:10 +01:00
|
|
|
package mount
|
|
|
|
|
|
|
|
import (
|
2023-02-01 18:01:58 +01:00
|
|
|
"context"
|
2023-01-12 19:10:10 +01:00
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
2023-02-03 12:37:12 +01:00
|
|
|
"strings"
|
2023-02-01 18:01:58 +01:00
|
|
|
"time"
|
2023-01-12 19:10:10 +01:00
|
|
|
|
|
|
|
"github.com/containerd/containerd/mount"
|
|
|
|
"github.com/deniswernert/go-fstab"
|
2023-02-03 12:37:12 +01:00
|
|
|
"github.com/hashicorp/go-multierror"
|
|
|
|
"github.com/joho/godotenv"
|
2023-02-06 15:41:52 +01:00
|
|
|
internalUtils "github.com/kairos-io/immucore/internal/utils"
|
2023-02-01 18:01:58 +01:00
|
|
|
"github.com/kairos-io/kairos/pkg/utils"
|
2023-02-06 17:46:45 +01:00
|
|
|
"github.com/kairos-io/kairos/sdk/state"
|
|
|
|
"github.com/rs/zerolog"
|
|
|
|
"github.com/rs/zerolog/log"
|
2023-02-01 18:01:58 +01:00
|
|
|
"github.com/spectrocloud-labs/herd"
|
2023-01-12 19:10:10 +01:00
|
|
|
)
|
|
|
|
|
2023-02-01 18:01:58 +01:00
|
|
|
type State struct {
|
2023-02-04 10:33:58 +01:00
|
|
|
Logger zerolog.Logger
|
2023-02-03 12:37:12 +01:00
|
|
|
Rootdir string // e.g. /sysroot inside initrd with pivot, / with nopivot
|
|
|
|
TargetImage string // e.g. /cOS/active.img
|
|
|
|
TargetLabel string // e.g. COS_ACTIVE
|
|
|
|
|
|
|
|
// /run/cos-layout.env (different!)
|
2023-02-08 22:54:17 +01:00
|
|
|
OverlayDirs []string // e.g. /var
|
2023-02-02 14:00:44 +01:00
|
|
|
BindMounts []string // e.g. /etc/kubernetes
|
2023-02-01 19:06:51 +01:00
|
|
|
CustomMounts map[string]string // e.g. diskid : mountpoint
|
|
|
|
|
2023-02-03 12:37:12 +01:00
|
|
|
StateDir string // e.g. "/usr/local/.state"
|
|
|
|
MountRoot bool // e.g. if true, it tries to find the image to loopback mount
|
2023-02-01 19:27:01 +01:00
|
|
|
|
2023-02-09 08:54:16 +01:00
|
|
|
fstabs []*fstab.Mount
|
2023-02-01 19:27:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
2023-02-03 12:37:12 +01:00
|
|
|
opCustomMounts = "custom-mount"
|
|
|
|
opDiscoverState = "discover-state"
|
|
|
|
opMountState = "mount-state"
|
|
|
|
opMountBind = "mount-bind"
|
|
|
|
|
2023-02-02 14:00:44 +01:00
|
|
|
opMountRoot = "mount-root"
|
|
|
|
opOverlayMount = "overlay-mount"
|
|
|
|
opWriteFstab = "write-fstab"
|
|
|
|
opMountBaseOverlay = "mount-base-overlay"
|
2023-02-02 15:12:33 +01:00
|
|
|
opMountOEM = "mount-oem"
|
2023-02-03 12:37:12 +01:00
|
|
|
|
|
|
|
opRootfsHook = "rootfs-hook"
|
|
|
|
opLoadConfig = "load-config"
|
2023-02-01 19:27:01 +01:00
|
|
|
)
|
|
|
|
|
2023-02-02 14:00:44 +01:00
|
|
|
func (s *State) path(p ...string) string {
|
|
|
|
return filepath.Join(append([]string{s.Rootdir}, p...)...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *State) WriteFstab(fstabFile string) func(context.Context) error {
|
2023-02-08 14:14:37 +01:00
|
|
|
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).With().Logger()
|
2023-02-02 14:00:44 +01:00
|
|
|
return func(ctx context.Context) error {
|
|
|
|
for _, fst := range s.fstabs {
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
default:
|
|
|
|
f, err := os.OpenFile(fstabFile,
|
|
|
|
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer f.Close()
|
2023-02-08 11:49:03 +01:00
|
|
|
// As we mount on /sysroot during initramfs but the fstab file is for the real init process, we need to remove
|
|
|
|
// Any mentions to /sysroot from the fstab lines, otherwise they wont work
|
|
|
|
fstCleaned := strings.ReplaceAll(fst.String(), "/sysroot", "")
|
|
|
|
toWrite := fmt.Sprintf("%s\n", fstCleaned)
|
2023-02-04 10:33:58 +01:00
|
|
|
if _, err := f.WriteString(toWrite); err != nil {
|
2023-02-02 14:00:44 +01:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-03 12:37:12 +01:00
|
|
|
func (s *State) RunStageOp(stage string) func(context.Context) error {
|
|
|
|
return func(ctx context.Context) error {
|
2023-02-08 14:14:37 +01:00
|
|
|
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).With().Logger()
|
2023-02-07 20:16:02 +01:00
|
|
|
if stage == "rootfs" {
|
2023-02-08 10:32:11 +01:00
|
|
|
if _, err := os.Stat("/system"); os.IsNotExist(err) {
|
|
|
|
err = os.Symlink("/sysroot/system", "/system")
|
|
|
|
if err != nil {
|
|
|
|
s.Logger.Err(err).Msg("creating symlink")
|
|
|
|
return err
|
|
|
|
}
|
2023-02-07 20:16:02 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-04 10:33:58 +01:00
|
|
|
cmd := fmt.Sprintf("elemental run-stage %s", stage)
|
2023-02-08 23:27:53 +01:00
|
|
|
// If we set the level to debug, also call elemental with debug
|
|
|
|
if log.Logger.GetLevel() == zerolog.DebugLevel {
|
|
|
|
cmd = fmt.Sprintf("%s --debug", cmd)
|
|
|
|
}
|
2023-02-06 22:06:31 +01:00
|
|
|
output, err := utils.SH(cmd)
|
2023-02-08 23:27:53 +01:00
|
|
|
log.Debug().Msg(output)
|
2023-02-03 12:37:12 +01:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-02 14:00:44 +01:00
|
|
|
func (s *State) MountOP(what, where, t string, options []string, timeout time.Duration) func(context.Context) error {
|
2023-02-08 14:14:37 +01:00
|
|
|
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).With().Logger()
|
2023-02-06 16:20:18 +01:00
|
|
|
|
2023-02-02 14:00:44 +01:00
|
|
|
return func(c context.Context) error {
|
2023-02-04 15:24:39 +01:00
|
|
|
cc := time.After(timeout)
|
2023-02-02 14:00:44 +01:00
|
|
|
for {
|
|
|
|
select {
|
|
|
|
default:
|
2023-02-06 16:20:18 +01:00
|
|
|
if _, err := os.Stat(where); os.IsNotExist(err) {
|
|
|
|
err = os.MkdirAll(where, os.ModeDir|os.ModePerm)
|
|
|
|
if err != nil {
|
2023-02-08 12:21:05 +01:00
|
|
|
log.Logger.Debug().Str("what", what).Str("where", where).Str("type", t).Strs("options", options).Err(err).Msg("Creating dir")
|
2023-02-06 16:20:18 +01:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
2023-02-02 14:00:44 +01:00
|
|
|
time.Sleep(1 * time.Second)
|
|
|
|
mountPoint := mount.Mount{
|
|
|
|
Type: t,
|
|
|
|
Source: what,
|
|
|
|
Options: options,
|
|
|
|
}
|
2023-02-04 10:33:58 +01:00
|
|
|
tmpFstab := mountToStab(mountPoint)
|
|
|
|
tmpFstab.File = where
|
2023-02-02 14:00:44 +01:00
|
|
|
op := mountOperation{
|
|
|
|
MountOption: mountPoint,
|
2023-02-04 10:33:58 +01:00
|
|
|
FstabEntry: *tmpFstab,
|
2023-02-02 14:00:44 +01:00
|
|
|
Target: where,
|
|
|
|
}
|
|
|
|
|
|
|
|
err := op.run()
|
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2023-02-04 10:33:58 +01:00
|
|
|
s.fstabs = append(s.fstabs, tmpFstab)
|
2023-02-02 14:00:44 +01:00
|
|
|
return nil
|
|
|
|
case <-c.Done():
|
2023-02-06 16:20:18 +01:00
|
|
|
e := fmt.Errorf("context canceled")
|
2023-02-08 12:21:05 +01:00
|
|
|
log.Logger.Debug().Str("what", what).Str("where", where).Str("type", t).Strs("options", options).Err(e).Msg("mount canceled")
|
2023-02-06 16:20:18 +01:00
|
|
|
return e
|
2023-02-04 15:24:39 +01:00
|
|
|
case <-cc:
|
2023-02-06 16:20:18 +01:00
|
|
|
e := fmt.Errorf("timeout exhausted")
|
2023-02-08 12:21:05 +01:00
|
|
|
log.Logger.Debug().Str("what", what).Str("where", where).Str("type", t).Strs("options", options).Err(e).Msg("Mount timeout")
|
2023-02-06 16:20:18 +01:00
|
|
|
return e
|
2023-02-02 14:00:44 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-02 15:12:33 +01:00
|
|
|
func (s *State) WriteDAG(g *herd.Graph) (out string) {
|
|
|
|
for i, layer := range g.Analyze() {
|
|
|
|
out += fmt.Sprintf("%d.\n", (i + 1))
|
|
|
|
for _, op := range layer {
|
|
|
|
if op.Error != nil {
|
|
|
|
out += fmt.Sprintf(" <%s> (error: %s) (background: %t) (weak: %t)\n", op.Name, op.Error.Error(), op.Background, op.WeakDeps)
|
|
|
|
} else {
|
|
|
|
out += fmt.Sprintf(" <%s> (background: %t) (weak: %t)\n", op.Name, op.Background, op.WeakDeps)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-02-03 12:37:12 +01:00
|
|
|
func readEnv(file string) (map[string]string, error) {
|
|
|
|
var envMap map[string]string
|
|
|
|
var err error
|
|
|
|
|
|
|
|
f, err := os.Open(file)
|
|
|
|
if err != nil {
|
|
|
|
return envMap, err
|
|
|
|
}
|
2023-02-09 08:54:16 +01:00
|
|
|
defer func(f *os.File) {
|
|
|
|
_ = f.Close()
|
|
|
|
}(f)
|
2023-02-03 12:37:12 +01:00
|
|
|
|
|
|
|
envMap, err = godotenv.Parse(f)
|
|
|
|
if err != nil {
|
|
|
|
return envMap, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return envMap, err
|
|
|
|
}
|
|
|
|
|
2023-02-01 18:01:58 +01:00
|
|
|
func (s *State) Register(g *herd.Graph) error {
|
2023-02-04 11:18:13 +01:00
|
|
|
var err error
|
2023-02-01 18:01:58 +01:00
|
|
|
|
2023-02-08 22:54:17 +01:00
|
|
|
// Default RW_PATHS to mount ALWAYS
|
|
|
|
s.OverlayDirs = []string{"/etc", "/root", "/home", "/opt", "/srv", "/usr/local", "/var"}
|
|
|
|
|
2023-02-06 16:20:18 +01:00
|
|
|
runtime, err := state.NewRuntime()
|
|
|
|
if err != nil {
|
2023-02-06 22:06:31 +01:00
|
|
|
s.Logger.Debug().Err(err).Msg("")
|
2023-02-06 16:20:18 +01:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-02-03 12:37:12 +01:00
|
|
|
// TODO: add hooks, fstab (might have missed some), systemd compat
|
|
|
|
// TODO: We should also set tmpfs here (not -related)
|
2023-02-01 19:27:01 +01:00
|
|
|
|
2023-02-03 12:37:12 +01:00
|
|
|
// All of this below need to run after rootfs stage runs (so the layout file is created)
|
2023-02-01 22:51:31 +01:00
|
|
|
// This is legacy - in UKI we don't need to found the img, this needs to run in a conditional
|
|
|
|
if s.MountRoot {
|
2023-02-03 12:37:12 +01:00
|
|
|
// setup loopback mount for the image target for booting
|
2023-02-04 11:18:13 +01:00
|
|
|
err = g.Add(opDiscoverState,
|
2023-02-01 22:51:31 +01:00
|
|
|
herd.WithDeps(opMountState),
|
|
|
|
herd.WithCallback(
|
|
|
|
func(ctx context.Context) error {
|
2023-02-08 14:14:37 +01:00
|
|
|
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).With().Logger()
|
2023-02-08 22:54:17 +01:00
|
|
|
// Check if loop device is mounted by checking the existance of the target label
|
|
|
|
if internalUtils.IsMountedByLabel(s.TargetLabel) {
|
|
|
|
log.Logger.Debug().Str("targetImage", s.TargetImage).Str("path", s.Rootdir).Str("TargetLabel", s.TargetLabel).Msg("Not mounting loop, already mounted")
|
|
|
|
return nil
|
|
|
|
}
|
2023-02-06 16:29:49 +01:00
|
|
|
cmd := fmt.Sprintf("losetup --show -f %s", s.path("/run/initramfs/cos-state", s.TargetImage))
|
2023-02-06 16:20:18 +01:00
|
|
|
_, err := utils.SH(cmd)
|
2023-02-06 17:24:50 +01:00
|
|
|
if err != nil {
|
|
|
|
log.Logger.Debug().Err(err).Msg("")
|
|
|
|
}
|
2023-02-01 22:51:31 +01:00
|
|
|
return err
|
|
|
|
},
|
|
|
|
))
|
2023-02-04 11:18:13 +01:00
|
|
|
if err != nil {
|
|
|
|
s.Logger.Err(err)
|
|
|
|
}
|
2023-02-01 18:01:58 +01:00
|
|
|
|
2023-02-03 12:37:12 +01:00
|
|
|
// mount the state partition so to find the loopback device
|
2023-02-08 18:24:28 +01:00
|
|
|
stateName := runtime.State.Name
|
|
|
|
stateFs := runtime.State.Type
|
|
|
|
// Recovery is a different partition
|
2023-02-09 08:54:16 +01:00
|
|
|
if internalUtils.IsRecovery() {
|
2023-02-08 18:24:28 +01:00
|
|
|
stateName = runtime.Recovery.Name
|
|
|
|
stateFs = runtime.Recovery.Type
|
|
|
|
}
|
2023-02-04 11:18:13 +01:00
|
|
|
err = g.Add(opMountState,
|
2023-02-01 22:51:31 +01:00
|
|
|
herd.WithCallback(
|
|
|
|
s.MountOP(
|
2023-02-08 18:24:28 +01:00
|
|
|
stateName,
|
2023-02-01 22:51:31 +01:00
|
|
|
s.path("/run/initramfs/cos-state"),
|
2023-02-08 18:24:28 +01:00
|
|
|
stateFs,
|
2023-02-01 22:51:31 +01:00
|
|
|
[]string{
|
|
|
|
"ro", // or rw
|
|
|
|
}, 60*time.Second),
|
|
|
|
),
|
|
|
|
)
|
2023-02-04 11:18:13 +01:00
|
|
|
if err != nil {
|
|
|
|
s.Logger.Err(err)
|
|
|
|
}
|
2023-02-01 22:51:31 +01:00
|
|
|
|
2023-02-03 12:37:12 +01:00
|
|
|
// mount the loopback device as root of the fs
|
2023-02-04 11:18:13 +01:00
|
|
|
err = g.Add(opMountRoot,
|
2023-02-01 22:51:31 +01:00
|
|
|
herd.WithDeps(opDiscoverState),
|
|
|
|
herd.WithCallback(
|
|
|
|
s.MountOP(
|
|
|
|
fmt.Sprintf("/dev/disk/by-label/%s", s.TargetLabel),
|
|
|
|
s.Rootdir,
|
2023-02-06 17:24:50 +01:00
|
|
|
"ext4", // are images always ext2?
|
2023-02-01 22:51:31 +01:00
|
|
|
[]string{
|
|
|
|
"ro", // or rw
|
|
|
|
"suid",
|
|
|
|
"dev",
|
|
|
|
"exec",
|
2023-02-06 17:46:45 +01:00
|
|
|
// "auto",
|
2023-02-06 17:24:50 +01:00
|
|
|
//"nouser",
|
2023-02-01 22:51:31 +01:00
|
|
|
"async",
|
2023-02-06 22:06:31 +01:00
|
|
|
}, 10*time.Second),
|
2023-02-01 22:51:31 +01:00
|
|
|
),
|
|
|
|
)
|
2023-02-04 11:18:13 +01:00
|
|
|
if err != nil {
|
|
|
|
s.Logger.Err(err)
|
|
|
|
}
|
2023-02-01 22:51:31 +01:00
|
|
|
|
|
|
|
}
|
2023-02-02 15:12:33 +01:00
|
|
|
|
2023-02-03 12:37:12 +01:00
|
|
|
// depending on /run/cos-layout.env
|
|
|
|
// This is building the mountRoot dependendency if it was enabled
|
2023-02-08 19:35:13 +01:00
|
|
|
mountRootCondition := herd.ConditionalOption(func() bool { return s.MountRoot }, herd.WithDeps(opMountRoot))
|
2023-02-02 15:12:33 +01:00
|
|
|
|
2023-02-09 08:54:16 +01:00
|
|
|
// this needs to be run after sysroot, so we can link to /sysroot/system/oem and after /oem mounted
|
2023-02-07 21:52:40 +01:00
|
|
|
err = g.Add(opRootfsHook, mountRootCondition, herd.WithDeps(opMountRoot, opMountOEM), herd.WithCallback(s.RunStageOp("rootfs")))
|
2023-02-04 11:18:13 +01:00
|
|
|
if err != nil {
|
2023-02-07 21:52:40 +01:00
|
|
|
s.Logger.Err(err).Msg("running rootfs stage")
|
2023-02-04 11:18:13 +01:00
|
|
|
}
|
2023-02-03 12:37:12 +01:00
|
|
|
|
2023-02-07 21:52:40 +01:00
|
|
|
// /run/cos/cos-layout.env
|
2023-02-03 12:37:12 +01:00
|
|
|
// populate state bindmounts, overlaymounts, custommounts
|
2023-02-04 11:18:13 +01:00
|
|
|
err = g.Add(opLoadConfig,
|
2023-02-03 12:37:12 +01:00
|
|
|
herd.WithDeps(opRootfsHook),
|
|
|
|
herd.WithCallback(func(ctx context.Context) error {
|
2023-02-08 14:14:37 +01:00
|
|
|
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).With().Logger()
|
2023-02-07 22:12:37 +01:00
|
|
|
if s.CustomMounts == nil {
|
|
|
|
s.CustomMounts = map[string]string{}
|
|
|
|
}
|
2023-02-08 21:19:57 +01:00
|
|
|
|
2023-02-07 21:52:40 +01:00
|
|
|
env, err := readEnv("/run/cos/cos-layout.env")
|
2023-02-03 12:37:12 +01:00
|
|
|
if err != nil {
|
2023-02-07 22:12:37 +01:00
|
|
|
log.Logger.Err(err).Msg("Reading env")
|
2023-02-03 12:37:12 +01:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
// populate from env here
|
2023-02-08 22:54:17 +01:00
|
|
|
s.OverlayDirs = append(s.OverlayDirs, strings.Split(env["RW_PATHS"], " ")...)
|
|
|
|
// Remove any duplicates
|
|
|
|
s.OverlayDirs = internalUtils.UniqueSlice(s.OverlayDirs)
|
2023-02-03 12:37:12 +01:00
|
|
|
|
|
|
|
// TODO: PERSISTENT_STATE_TARGET /usr/local/.state
|
|
|
|
s.BindMounts = strings.Split(env["PERSISTENT_STATE_PATHS"], " ")
|
2023-02-08 22:54:17 +01:00
|
|
|
// Remove any duplicates
|
|
|
|
s.BindMounts = internalUtils.UniqueSlice(s.BindMounts)
|
2023-02-03 12:37:12 +01:00
|
|
|
|
2023-02-06 15:41:52 +01:00
|
|
|
s.StateDir = env["PERSISTENT_STATE_TARGET"]
|
|
|
|
if s.StateDir == "" {
|
|
|
|
s.StateDir = "/usr/local/.state"
|
|
|
|
}
|
|
|
|
|
|
|
|
// s.CustomMounts is special:
|
|
|
|
// It gets parsed by the cmdline (TODO)
|
|
|
|
// and from the env var
|
|
|
|
// https://github.com/kairos-io/packages/blob/7c3581a8ba6371e5ce10c3a98bae54fde6a505af/packages/system/dracut/immutable-rootfs/30cos-immutable-rootfs/cos-generator.sh#L71
|
|
|
|
// https://github.com/kairos-io/packages/blob/7c3581a8ba6371e5ce10c3a98bae54fde6a505af/packages/system/dracut/immutable-rootfs/30cos-immutable-rootfs/cos-mount-layout.sh#L80
|
|
|
|
|
2023-02-06 16:02:18 +01:00
|
|
|
addLine := func(d string) {
|
|
|
|
dat := strings.Split(d, ":")
|
2023-02-06 15:41:52 +01:00
|
|
|
if len(dat) == 2 {
|
|
|
|
disk := dat[0]
|
|
|
|
path := dat[1]
|
|
|
|
s.CustomMounts[disk] = path
|
|
|
|
}
|
|
|
|
}
|
2023-02-06 16:02:18 +01:00
|
|
|
for _, v := range append(internalUtils.ReadCMDLineArg("rd.cos.mount="), strings.Split(env["VOLUMES"], " ")...) {
|
|
|
|
addLine(internalUtils.ParseMount(v))
|
|
|
|
}
|
2023-02-06 15:41:52 +01:00
|
|
|
|
2023-02-03 12:37:12 +01:00
|
|
|
return nil
|
|
|
|
}))
|
2023-02-04 11:18:13 +01:00
|
|
|
if err != nil {
|
|
|
|
s.Logger.Err(err)
|
|
|
|
}
|
2023-02-01 22:51:31 +01:00
|
|
|
// end sysroot mount
|
2023-02-01 18:01:58 +01:00
|
|
|
|
2023-02-01 22:33:44 +01:00
|
|
|
// overlay mount start
|
|
|
|
if rootFSType(s.Rootdir) != "overlay" {
|
2023-02-04 11:18:13 +01:00
|
|
|
err = g.Add(opMountBaseOverlay,
|
2023-02-01 22:33:44 +01:00
|
|
|
herd.WithCallback(
|
|
|
|
func(ctx context.Context) error {
|
2023-02-06 15:28:22 +01:00
|
|
|
op, err := baseOverlay(Overlay{
|
2023-02-01 22:33:44 +01:00
|
|
|
Base: "/run/overlay",
|
|
|
|
BackingBase: "tmpfs:20%",
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
s.fstabs = append(s.fstabs, &op.FstabEntry)
|
|
|
|
return op.run()
|
|
|
|
},
|
|
|
|
),
|
|
|
|
)
|
2023-02-04 11:18:13 +01:00
|
|
|
if err != nil {
|
|
|
|
s.Logger.Err(err)
|
|
|
|
}
|
2023-02-01 22:33:44 +01:00
|
|
|
}
|
|
|
|
|
2023-02-08 19:35:13 +01:00
|
|
|
overlayCondition := herd.ConditionalOption(func() bool { return rootFSType(s.Rootdir) != "overlay" }, herd.WithDeps(opMountBaseOverlay))
|
2023-02-01 19:06:51 +01:00
|
|
|
// TODO: Add fsck
|
|
|
|
// mount overlay
|
2023-02-04 11:18:13 +01:00
|
|
|
err = g.Add(
|
2023-02-03 12:37:12 +01:00
|
|
|
opOverlayMount,
|
|
|
|
overlayCondition,
|
|
|
|
herd.WithDeps(opLoadConfig),
|
|
|
|
mountRootCondition,
|
|
|
|
herd.WithCallback(
|
|
|
|
func(ctx context.Context) error {
|
|
|
|
var err error
|
2023-02-08 22:54:17 +01:00
|
|
|
for _, p := range s.OverlayDirs {
|
2023-02-01 19:06:51 +01:00
|
|
|
op, err := mountWithBaseOverlay(p, s.Rootdir, "/run/overlay")
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
s.fstabs = append(s.fstabs, &op.FstabEntry)
|
2023-02-03 12:37:12 +01:00
|
|
|
err = multierror.Append(err, op.run())
|
|
|
|
}
|
2023-02-01 19:06:51 +01:00
|
|
|
|
2023-02-03 12:37:12 +01:00
|
|
|
return err
|
|
|
|
},
|
|
|
|
),
|
|
|
|
)
|
2023-02-04 11:18:13 +01:00
|
|
|
if err != nil {
|
|
|
|
s.Logger.Err(err)
|
|
|
|
}
|
|
|
|
err = g.Add(
|
2023-02-03 12:37:12 +01:00
|
|
|
opCustomMounts,
|
|
|
|
mountRootCondition,
|
|
|
|
overlayCondition,
|
|
|
|
herd.WithDeps(opLoadConfig),
|
|
|
|
herd.WithCallback(func(ctx context.Context) error {
|
2023-02-08 15:40:18 +01:00
|
|
|
var err *multierror.Error
|
2023-02-03 12:37:12 +01:00
|
|
|
|
2023-02-08 11:01:21 +01:00
|
|
|
for what, where := range s.CustomMounts {
|
2023-02-08 11:49:03 +01:00
|
|
|
// TODO: scan for the custom mount disk to know the underlying fs and set it proper
|
2023-02-08 19:35:13 +01:00
|
|
|
fstype := "ext4"
|
2023-02-08 15:51:21 +01:00
|
|
|
mountOptions := []string{"ro"}
|
2023-02-08 11:01:21 +01:00
|
|
|
// Translate label to disk for COS_PERSISTENT
|
2023-02-08 15:51:21 +01:00
|
|
|
// Persistent needs to be RW
|
2023-02-08 11:49:03 +01:00
|
|
|
if strings.Contains(what, "COS_PERSISTENT") {
|
2023-02-08 11:33:11 +01:00
|
|
|
fstype = runtime.Persistent.Type
|
2023-02-08 15:51:21 +01:00
|
|
|
mountOptions = []string{"rw"}
|
2023-02-08 11:01:21 +01:00
|
|
|
}
|
2023-02-03 12:37:12 +01:00
|
|
|
err = multierror.Append(err, s.MountOP(
|
2023-02-08 11:01:21 +01:00
|
|
|
what,
|
|
|
|
s.path(where),
|
2023-02-08 11:33:11 +01:00
|
|
|
fstype,
|
2023-02-08 15:51:21 +01:00
|
|
|
mountOptions,
|
2023-02-06 22:06:31 +01:00
|
|
|
10*time.Second,
|
2023-02-03 12:37:12 +01:00
|
|
|
)(ctx))
|
|
|
|
|
|
|
|
}
|
2023-02-08 22:03:45 +01:00
|
|
|
s.Logger.Err(err.ErrorOrNil()).Send()
|
2023-02-08 15:40:18 +01:00
|
|
|
|
|
|
|
return err.ErrorOrNil()
|
2023-02-03 12:37:12 +01:00
|
|
|
}),
|
|
|
|
)
|
2023-02-04 11:18:13 +01:00
|
|
|
if err != nil {
|
|
|
|
s.Logger.Err(err)
|
|
|
|
}
|
2023-02-01 19:06:51 +01:00
|
|
|
|
2023-02-01 19:27:01 +01:00
|
|
|
// mount state is defined over a custom mount (/usr/local/.state for instance, needs to be mounted over a device)
|
2023-02-04 11:18:13 +01:00
|
|
|
err = g.Add(
|
2023-02-03 12:37:12 +01:00
|
|
|
opMountBind,
|
|
|
|
overlayCondition,
|
|
|
|
mountRootCondition,
|
|
|
|
herd.WithDeps(opCustomMounts, opLoadConfig),
|
|
|
|
herd.WithCallback(
|
|
|
|
func(ctx context.Context) error {
|
2023-02-08 23:27:53 +01:00
|
|
|
var err *multierror.Error
|
2023-02-03 12:37:12 +01:00
|
|
|
for _, p := range s.BindMounts {
|
2023-02-08 16:23:13 +01:00
|
|
|
// TODO: Check why p can be empty, Example:
|
|
|
|
/*
|
|
|
|
3:12PM DBG Mounting bind binds=[
|
|
|
|
"/etc/systemd","/etc/modprobe.d",
|
|
|
|
"/etc/rancher","/etc/sysconfig",
|
|
|
|
"/etc/runlevels","/etc/ssh",
|
|
|
|
"/etc/ssl/certs","/etc/iscsi",
|
|
|
|
"", <----- HERE
|
|
|
|
"/etc/cni","/etc/kubernetes",
|
|
|
|
"/home","/opt","/root","/snap",
|
|
|
|
"/var/snap","/usr/libexec",
|
|
|
|
"/var/log","/var/lib/rancher",
|
|
|
|
"/var/lib/kubelet","/var/lib/snapd"
|
|
|
|
,"/var/lib/wicked","/var/lib/longhorn"
|
|
|
|
,"/var/lib/cni","/usr/share/pki/trust"
|
|
|
|
,"/usr/share/pki/trust/anchors",
|
|
|
|
"/var/lib/ca-certificates"]
|
|
|
|
*/
|
|
|
|
if p == "" {
|
|
|
|
continue
|
|
|
|
}
|
2023-02-08 14:43:58 +01:00
|
|
|
op := mountBind(p, s.Rootdir, s.StateDir)
|
2023-02-08 16:36:12 +01:00
|
|
|
err2 := op.run()
|
|
|
|
if err2 != nil {
|
|
|
|
log.Logger.Err(err2).Send()
|
|
|
|
err = multierror.Append(err, err2)
|
|
|
|
} else {
|
|
|
|
// Only append to fstabs if there was no error, otherwise we will try to mount it after switch_root
|
|
|
|
s.fstabs = append(s.fstabs, &op.FstabEntry)
|
|
|
|
}
|
2023-02-03 12:37:12 +01:00
|
|
|
}
|
2023-02-08 23:27:53 +01:00
|
|
|
log.Logger.Err(err.ErrorOrNil()).Send()
|
|
|
|
return err.ErrorOrNil()
|
2023-02-03 12:37:12 +01:00
|
|
|
},
|
|
|
|
),
|
|
|
|
)
|
2023-02-04 11:18:13 +01:00
|
|
|
if err != nil {
|
|
|
|
s.Logger.Err(err)
|
|
|
|
}
|
2023-02-01 22:33:44 +01:00
|
|
|
|
|
|
|
// overlay mount end
|
2023-02-04 11:18:13 +01:00
|
|
|
err = g.Add(opMountOEM,
|
2023-02-02 15:12:33 +01:00
|
|
|
overlayCondition,
|
|
|
|
mountRootCondition,
|
2023-02-01 18:01:58 +01:00
|
|
|
herd.WithCallback(
|
|
|
|
s.MountOP(
|
2023-02-06 22:06:31 +01:00
|
|
|
runtime.OEM.Name,
|
2023-02-01 22:33:44 +01:00
|
|
|
s.path("/oem"),
|
2023-02-06 16:20:18 +01:00
|
|
|
runtime.OEM.Type,
|
2023-02-01 18:01:58 +01:00
|
|
|
[]string{
|
|
|
|
"rw",
|
|
|
|
"suid",
|
|
|
|
"dev",
|
|
|
|
"exec",
|
2023-02-06 22:06:31 +01:00
|
|
|
//"noauto",
|
|
|
|
//"nouser",
|
2023-02-01 18:01:58 +01:00
|
|
|
"async",
|
2023-02-06 16:20:18 +01:00
|
|
|
}, 10*time.Second),
|
2023-02-01 18:01:58 +01:00
|
|
|
),
|
|
|
|
)
|
2023-02-04 11:18:13 +01:00
|
|
|
if err != nil {
|
|
|
|
s.Logger.Err(err)
|
|
|
|
}
|
|
|
|
err = g.Add(opWriteFstab,
|
2023-02-02 14:00:44 +01:00
|
|
|
overlayCondition,
|
2023-02-03 12:37:12 +01:00
|
|
|
mountRootCondition,
|
|
|
|
herd.WithDeps(opMountOEM, opCustomMounts, opMountBind, opOverlayMount),
|
2023-02-02 15:12:33 +01:00
|
|
|
herd.WeakDeps,
|
2023-02-06 16:29:49 +01:00
|
|
|
herd.WithCallback(s.WriteFstab(s.path("/etc/fstab"))))
|
2023-02-04 11:18:13 +01:00
|
|
|
if err != nil {
|
|
|
|
s.Logger.Err(err)
|
|
|
|
}
|
|
|
|
return err
|
2023-02-01 18:01:58 +01:00
|
|
|
}
|