Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions cmd/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,11 @@ func ReadInitSpec(r *v1.RunConfig, flags *pflag.FlagSet) (*v1.InitSpec, error) {
}

func ReadMountSpec(r *v1.RunConfig, flags *pflag.FlagSet) (*v1.MountSpec, error) {
mount := config.NewMountSpec()
mount, err := config.NewMountSpec(r.Config)
if err != nil {
r.Logger.Errorf("Failed preparing mount configuration: %s", err)
return nil, err
}
vp := viper.Sub("mount")
if vp == nil {
vp = viper.New()
Expand All @@ -264,7 +268,7 @@ func ReadMountSpec(r *v1.RunConfig, flags *pflag.FlagSet) (*v1.MountSpec, error)
// Bind mount env vars
viperReadEnv(vp, "MOUNT", constants.GetMountKeyEnvMap())

err := vp.Unmarshal(mount, setDecoder, decodeHook)
err = vp.Unmarshal(mount, setDecoder, decodeHook)
if err != nil {
r.Logger.Warnf("error unmarshalling MountSpec: %s", err)
return mount, err
Expand Down
28 changes: 28 additions & 0 deletions cmd/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,34 @@ var _ = Describe("Config", Label("config"), func() {
})
})
Describe("Read MountSpec", Label("mount"), func() {
var ghwTest v1mock.GhwMock
BeforeEach(func() {
mainDisk := block.Disk{
Name: "device",
Partitions: []*block.Partition{
{
Name: "device2",
FilesystemLabel: "COS_STATE",
Type: "ext4",
MountPoint: constants.RunningStateDir,
},
{
Name: "device3",
FilesystemLabel: "COS_RECOVERY",
Type: "ext4",
MountPoint: constants.RunningStateDir,
},
},
}
ghwTest = v1mock.GhwMock{}
ghwTest.AddDisk(mainDisk)
ghwTest.CreateDevices()
})

AfterEach(func() {
ghwTest.Clean()
})

It("inits a mount spec according to given configs", func() {
err := os.Setenv("ELEMENTAL_MOUNT_SYSROOT", "/newroot")
spec, err := ReadMountSpec(cfg, nil)
Expand Down
2 changes: 1 addition & 1 deletion pkg/action/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ func (i InstallAction) Run() (err error) {
return err
}

err = elemental.MountPartitions(i.cfg.Config, i.spec.Partitions.PartitionsByMountPoint(false))
err = elemental.MountPartitions(i.cfg.Config, i.spec.Partitions.PartitionsByMountPoint(false), "rw")
if err != nil {
return elementalError.NewFromError(err, elementalError.MountPartitions)
}
Expand Down
94 changes: 49 additions & 45 deletions pkg/action/mount.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"strings"

"github.com/rancher/elemental-toolkit/pkg/constants"
"github.com/rancher/elemental-toolkit/pkg/elemental"
v1 "github.com/rancher/elemental-toolkit/pkg/types/v1"
"github.com/rancher/elemental-toolkit/pkg/utils"
)
Expand All @@ -31,16 +32,26 @@ const overlaySuffix = ".overlay"
func RunMount(cfg *v1.RunConfig, spec *v1.MountSpec) error {
cfg.Logger.Info("Running mount command")

cfg.Logger.Debug("Mounting elemental partitions")
if err := elemental.MountPartitions(cfg.Config, spec.Partitions.PartitionsByMountPoint(false)); err != nil {
cfg.Logger.Errorf("Error mounting elemental partitions: %s", err.Error())
return err
}

cfg.Logger.Debugf("Mounting ephemeral directories")
if err := MountEphemeral(cfg, spec.Sysroot, spec.Ephemeral); err != nil {
cfg.Logger.Errorf("Error mounting overlays: %s", err.Error())
return err
}

cfg.Logger.Debugf("Mounting persistent directories")
if err := MountPersistent(cfg, spec.Sysroot, spec.Persistent); err != nil {
cfg.Logger.Errorf("Error mounting persistent overlays: %s", err.Error())
return err
if ok, _ := elemental.IsMounted(cfg.Config, spec.Partitions.Persistent); ok {
cfg.Logger.Debugf("Mounting persistent directories")
if err := MountPersistent(cfg, spec.Sysroot, spec.Persistent); err != nil {
cfg.Logger.Errorf("Error mounting persistent overlays: %s", err.Error())
return err
}
} else {
cfg.Logger.Warn("No persistent partition defined or mounted, omitting any persistent paths configuration")
}

cfg.Logger.Debugf("Writing fstab")
Expand Down Expand Up @@ -202,64 +213,57 @@ func WriteFstab(cfg *v1.RunConfig, spec *v1.MountSpec) error {

for _, part := range spec.Partitions.PartitionsByMountPoint(false) {
if part.Path == "" {
// Lets error out only after 10 attempts to find the device
device, err := utils.GetDeviceByLabel(cfg.Runner, part.FilesystemLabel, 10)
if err != nil {
cfg.Logger.Errorf("Could not find a device with label %s", part.FilesystemLabel)
return err
}
part.Path = device
cfg.Logger.Warnf("Partition '%s' has undefined device, can't be included in fstab", part.Name)
continue
}

data = data + fstab(part.Path, part.MountPoint, "auto", part.Flags)
}

for _, rw := range spec.Ephemeral.Paths {
trimmed := strings.TrimPrefix(rw, "/")
pathName := strings.ReplaceAll(trimmed, "/", "-") + overlaySuffix
upper := fmt.Sprintf("%s/%s/upper", constants.OverlayDir, pathName)
work := fmt.Sprintf("%s/%s/work", constants.OverlayDir, pathName)

options := []string{"defaults"}
options = append(options, fmt.Sprintf("lowerdir=%s", rw))
options = append(options, fmt.Sprintf("upperdir=%s", upper))
options = append(options, fmt.Sprintf("workdir=%s", work))
options = append(options, fmt.Sprintf("x-systemd.requires-mounts-for=%s", constants.OverlayDir))
data = data + fstab("overlay", rw, "overlay", options)
data += overlayLine(rw, constants.OverlayDir, constants.OverlayDir)
}

for _, path := range spec.Persistent.Paths {
if spec.Persistent.Mode == constants.OverlayMode {
trimmed := strings.TrimPrefix(path, "/")
pathName := strings.ReplaceAll(trimmed, "/", "-") + overlaySuffix
upper := fmt.Sprintf("%s/%s/upper", constants.PersistentStateDir, pathName)
work := fmt.Sprintf("%s/%s/work", constants.PersistentStateDir, pathName)

options := []string{"defaults"}
options = append(options, fmt.Sprintf("lowerdir=%s", path))
options = append(options, fmt.Sprintf("upperdir=%s", upper))
options = append(options, fmt.Sprintf("workdir=%s", work))
options = append(options, fmt.Sprintf("x-systemd.requires-mounts-for=%s", constants.PersistentDir))
data = data + fstab("overlay", path, "overlay", options)
if ok, _ := elemental.IsMounted(cfg.Config, spec.Partitions.Persistent); ok {
for _, path := range spec.Persistent.Paths {
if spec.Persistent.Mode == constants.OverlayMode {
data += overlayLine(path, constants.PersistentStateDir, constants.PersistentDir)
continue
}

continue
}
if spec.Persistent.Mode == constants.BindMode {
trimmed := strings.TrimPrefix(path, "/")
pathName := strings.ReplaceAll(trimmed, "/", "-") + ".bind"
stateDir := fmt.Sprintf("%s/%s", constants.PersistentStateDir, pathName)

if spec.Persistent.Mode == constants.BindMode {
trimmed := strings.TrimPrefix(path, "/")
pathName := strings.ReplaceAll(trimmed, "/", "-") + ".bind"
stateDir := fmt.Sprintf("%s/%s", constants.PersistentStateDir, pathName)
data = data + fstab(stateDir, path, "none", []string{"defaults", "bind"})
continue
}

data = data + fstab(stateDir, path, "none", []string{"defaults", "bind"})
continue
return fmt.Errorf("Unknown persistent mode '%s'", spec.Persistent.Mode)
}

return fmt.Errorf("Unknown persistent mode '%s'", spec.Persistent.Mode)
}

return cfg.Config.Fs.WriteFile(filepath.Join(spec.Sysroot, "/etc/fstab"), []byte(data), 0644)
}

func fstab(device, path, fstype string, flags []string) string {
if len(flags) == 0 {
flags = []string{"defaults"}
}
return fmt.Sprintf("%s\t%s\t%s\t%s\t0\t0\n", device, path, fstype, strings.Join(flags, ","))
}

func overlayLine(path, upperPath, requriedMount string) string {
trimmed := strings.TrimPrefix(path, "/")
pathName := strings.ReplaceAll(trimmed, "/", "-") + overlaySuffix
upper := fmt.Sprintf("%s/%s/upper", upperPath, pathName)
work := fmt.Sprintf("%s/%s/work", upperPath, pathName)

options := []string{"defaults"}
options = append(options, fmt.Sprintf("lowerdir=%s", path))
options = append(options, fmt.Sprintf("upperdir=%s", upper))
options = append(options, fmt.Sprintf("workdir=%s", work))
options = append(options, fmt.Sprintf("x-systemd.requires-mounts-for=%s", requriedMount))
return fstab("overlay", path, "overlay", options)
}
65 changes: 64 additions & 1 deletion pkg/action/mount_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/rancher/elemental-toolkit/pkg/action"
"github.com/rancher/elemental-toolkit/pkg/config"
"github.com/rancher/elemental-toolkit/pkg/constants"
"github.com/rancher/elemental-toolkit/pkg/elemental"
v1mock "github.com/rancher/elemental-toolkit/pkg/mocks"
v1 "github.com/rancher/elemental-toolkit/pkg/types/v1"
"github.com/rancher/elemental-toolkit/pkg/utils"
Expand Down Expand Up @@ -78,14 +79,76 @@ var _ = Describe("Mount Action", func() {
Ephemeral: v1.EphemeralMounts{
Size: "30%",
},
Persistent: v1.PersistentMounts{
Mode: constants.BindMode,
Paths: []string{"/some/path"},
},
Partitions: v1.ElementalPartitions{
Persistent: &v1.Partition{
Path: "/some/device",
MountPoint: "/mnt",
},
},
}
Expect(elemental.MountPartition(cfg.Config, spec.Partitions.Persistent)).To(Succeed())
utils.MkdirAll(fs, filepath.Join(spec.Sysroot, "/etc"), constants.DirPerm)
err := action.WriteFstab(cfg, spec)
Expect(err).To(BeNil())

fstab, err := cfg.Config.Fs.ReadFile(filepath.Join(spec.Sysroot, "/etc/fstab"))
Expect(err).To(BeNil())
Expect(string(fstab)).To(Equal("/dev/loop0\t/\text2\tro,relatime\t0\t0\ntmpfs\t/run/elemental/overlay\ttmpfs\tdefaults,size=30%\t0\t0\n"))
expectedFstab := "/dev/loop0\t/\text2\tro,relatime\t0\t0\n"
expectedFstab += "tmpfs\t/run/elemental/overlay\ttmpfs\tdefaults,size=30%\t0\t0\n"
expectedFstab += "/some/device\t/mnt\tauto\tdefaults\t0\t0\n"
expectedFstab += "/run/elemental/persistent/.state/some-path.bind\t/some/path\tnone\tdefaults,bind\t0\t0\n"
Expect(string(fstab)).To(Equal(expectedFstab))
})

It("Writes a simple fstab with overlay mode", func() {
spec := &v1.MountSpec{
WriteFstab: true,
Ephemeral: v1.EphemeralMounts{
Size: "30%",
},
Persistent: v1.PersistentMounts{
Mode: constants.OverlayMode,
Paths: []string{"/some/path"},
},
Partitions: v1.ElementalPartitions{
Persistent: &v1.Partition{
Path: "/some/device",
MountPoint: "/mnt",
},
},
}
Expect(elemental.MountPartition(cfg.Config, spec.Partitions.Persistent)).To(Succeed())
utils.MkdirAll(fs, filepath.Join(spec.Sysroot, "/etc"), constants.DirPerm)
err := action.WriteFstab(cfg, spec)
Expect(err).To(BeNil())

fstab, err := cfg.Config.Fs.ReadFile(filepath.Join(spec.Sysroot, "/etc/fstab"))
Expect(err).To(BeNil())
expectedFstab := "/dev/loop0\t/\text2\tro,relatime\t0\t0\n"
expectedFstab += "tmpfs\t/run/elemental/overlay\ttmpfs\tdefaults,size=30%\t0\t0\n"
expectedFstab += "/some/device\t/mnt\tauto\tdefaults\t0\t0\n"
expectedFstab += "overlay\t/some/path\toverlay\t"
expectedFstab += "defaults,lowerdir=/some/path,upperdir=/run/elemental/persistent/.state/some-path.overlay/upper,workdir=/run/elemental/persistent/.state/some-path.overlay/work,x-systemd.requires-mounts-for=/run/elemental/persistent\t0\t0\n"
Expect(string(fstab)).To(Equal(expectedFstab))
})

It("Does not write fstab if not requested", func() {
spec := &v1.MountSpec{
WriteFstab: false,
Ephemeral: v1.EphemeralMounts{
Size: "30%",
},
}
utils.MkdirAll(fs, filepath.Join(spec.Sysroot, "/etc"), constants.DirPerm)
err := action.WriteFstab(cfg, spec)
Expect(err).To(BeNil())

ok, _ := utils.Exists(fs, filepath.Join(spec.Sysroot, "/etc/fstab"))
Expect(ok).To(BeFalse())
})
})
})
2 changes: 1 addition & 1 deletion pkg/action/reset.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ func (r ResetAction) Run() (err error) {
}
}
// Mount configured partitions
err = elemental.MountPartitions(r.cfg.Config, r.spec.Partitions.PartitionsByMountPoint(false, r.spec.Partitions.Recovery))
err = elemental.MountPartitions(r.cfg.Config, r.spec.Partitions.PartitionsByMountPoint(false, r.spec.Partitions.Recovery), "rw")
if err != nil {
return elementalError.NewFromError(err, elementalError.MountPartitions)
}
Expand Down
78 changes: 36 additions & 42 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,52 +222,46 @@ func NewInitSpec() *v1.InitSpec {
}
}

func NewMountSpec() *v1.MountSpec {
partitions := v1.ElementalPartitions{
EFI: &v1.Partition{
FilesystemLabel: constants.EfiLabel,
Size: constants.EfiSize,
Name: constants.EfiPartName,
FS: constants.EfiFs,
MountPoint: constants.EfiDir,
Flags: []string{"ro"},
},
State: &v1.Partition{
FilesystemLabel: constants.StateLabel,
Size: constants.StateSize,
Name: constants.StatePartName,
FS: constants.LinuxFs,
Flags: []string{"defaults"},
},
Persistent: &v1.Partition{
FilesystemLabel: constants.PersistentLabel,
Size: constants.PersistentSize,
Name: constants.PersistentPartName,
FS: constants.LinuxFs,
MountPoint: constants.PersistentDir,
Flags: []string{"defaults"},
},
OEM: &v1.Partition{
FilesystemLabel: constants.OEMLabel,
Size: constants.OEMSize,
Name: constants.OEMPartName,
FS: constants.LinuxFs,
MountPoint: constants.OEMPath,
Flags: []string{"defaults"},
},
Recovery: &v1.Partition{
FilesystemLabel: constants.RecoveryLabel,
Size: constants.RecoverySize,
Name: constants.RecoveryPartName,
FS: constants.LinuxFs,
Flags: []string{"defaults"},
},
func NewMountSpec(cfg v1.Config) (*v1.MountSpec, error) {
// Check current installed system setup and discover partitions
installState, err := cfg.LoadInstallState()
if err != nil {
cfg.Logger.Warnf("failed reading installation state: %s", err.Error())
}

// Lists detected partitions on current system including mountpoint if mounted
parts, err := utils.GetAllPartitions()
if err != nil {
return nil, fmt.Errorf("could not read host partitions")
}

ep := v1.NewElementalPartitionsFromList(parts, installState)

if ep.EFI != nil && ep.EFI.MountPoint == "" {
ep.EFI.MountPoint = constants.EfiDir
ep.EFI.Flags = []string{"ro", "defaults"}
}
if ep.OEM != nil && ep.OEM.MountPoint == "" {
ep.OEM.MountPoint = constants.OEMDir
}
if ep.Persistent != nil && ep.Persistent.MountPoint == "" {
ep.Persistent.MountPoint = constants.PersistentDir
}
if ep.Recovery != nil {
ep.Recovery.Flags = []string{"ro", "defaults"}
}
if ep.State != nil {
ep.State.Flags = []string{"ro", "defaults"}
}
if (ep.Recovery == nil || ep.Recovery.MountPoint == "") &&
(ep.State == nil || ep.State.MountPoint == "") {
return nil, fmt.Errorf("neither state or recovery partitions are mounted")
}

return &v1.MountSpec{
Sysroot: "/sysroot",
WriteFstab: true,
Partitions: partitions,
Partitions: ep,
Ephemeral: v1.EphemeralMounts{
Type: constants.Tmpfs,
Size: "25%",
Expand All @@ -277,7 +271,7 @@ func NewMountSpec() *v1.MountSpec {
Mode: constants.OverlayMode,
Paths: []string{"/etc/systemd", "/etc/ssh", "/home", "/opt", "/root", "/var/log"},
},
}
}, nil
}

func NewInstallElementalPartitions() v1.ElementalPartitions {
Expand Down
Loading