Skip to content

Commit 8396170

Browse files
committed
Make persistent volume a nested structure of persistent data
Signed-off-by: David Cassany <dcassany@suse.com>
1 parent 5f75d14 commit 8396170

5 files changed

Lines changed: 96 additions & 76 deletions

File tree

config.yaml.example

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,11 +124,7 @@ upgrade:
124124
mount:
125125
sysroot: /sysroot # Path to mount system to
126126
write-fstab: true # Write fstab into sysroot/etc/fstab
127-
volumes:
128-
- mountpoint: /run/elemental/persistent
129-
device: PARTLABEL=persistent
130-
options: ["defaults"]
131-
persisent: true
127+
extra-volumes:
132128
- mountpoint: /run/elemental/efi
133129
device: PARTLABEL=efi
134130
options: ["ro", "defaults"]
@@ -145,6 +141,10 @@ mount:
145141
- /srv
146142
persistent:
147143
mode: overlay # overlay|bind
144+
volume:
145+
mountpoint: /run/elemental/persistent
146+
device: PARTLABEL=persistent
147+
options: ["defaults"]
148148
paths:
149149
- /etc/systemd
150150
- /etc/ssh

pkg/action/mount.go

Lines changed: 58 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"fmt"
2222
"path/filepath"
2323
"regexp"
24+
"sort"
2425
"strings"
2526

2627
"github.com/hashicorp/go-multierror"
@@ -57,7 +58,7 @@ func RunMount(cfg *v1.RunConfig, spec *v1.MountSpec) error {
5758
}
5859

5960
cfg.Logger.Debug("Mounting volumes")
60-
if err = MountVolumes(cfg, spec.Sysroot, spec.Volumes); err != nil {
61+
if err = MountVolumes(cfg, spec); err != nil {
6162
cfg.Logger.Errorf("Error mounting volumes: %s", err.Error())
6263
return err
6364
}
@@ -69,7 +70,7 @@ func RunMount(cfg *v1.RunConfig, spec *v1.MountSpec) error {
6970
}
7071

7172
cfg.Logger.Debugf("Mounting persistent directories")
72-
if err = MountPersistent(cfg, spec.Sysroot, spec.Persistent, spec.Volumes); err != nil {
73+
if err = MountPersistent(cfg, spec.Sysroot, spec.Persistent); err != nil {
7374
cfg.Logger.Errorf("Error mounting persistent overlays: %s", err.Error())
7475
return err
7576
}
@@ -84,28 +85,42 @@ func RunMount(cfg *v1.RunConfig, spec *v1.MountSpec) error {
8485
return nil
8586
}
8687

87-
func MountVolumes(cfg *v1.RunConfig, sysroot string, volumes []*v1.VolumeMount) error {
88+
func MountVolumes(cfg *v1.RunConfig, spec *v1.MountSpec) error {
8889
var errs error
8990

90-
for _, vol := range volumes {
91+
volumes := map[string]*v1.VolumeMount{}
92+
keys := []string{}
93+
if spec.HasPersistent() {
94+
volumes[spec.Persistent.Volume.Mountpoint] = &spec.Persistent.Volume
95+
keys = append(keys, spec.Persistent.Volume.Mountpoint)
96+
}
97+
98+
for _, v := range spec.Volumes {
99+
volumes[v.Mountpoint] = v
100+
keys = append(keys, v.Mountpoint)
101+
}
102+
103+
sort.Strings(keys)
104+
105+
for _, k := range keys {
91106
var dev string
92107
switch {
93-
case strings.HasPrefix(vol.Device, labelPref):
94-
dev = filepath.Join(diskByLabel, strings.TrimPrefix(vol.Device, labelPref))
95-
case strings.HasPrefix(vol.Device, partLabelPref):
96-
dev = filepath.Join(diskByPartLabel, strings.TrimPrefix(vol.Device, partLabelPref))
97-
case strings.HasPrefix(vol.Device, uuidPref):
98-
dev = filepath.Join(diskByUUID, strings.TrimPrefix(vol.Device, uuidPref))
99-
case strings.HasPrefix(vol.Device, devPref):
100-
dev = vol.Device
108+
case strings.HasPrefix(volumes[k].Device, labelPref):
109+
dev = filepath.Join(diskByLabel, strings.TrimPrefix(volumes[k].Device, labelPref))
110+
case strings.HasPrefix(volumes[k].Device, partLabelPref):
111+
dev = filepath.Join(diskByPartLabel, strings.TrimPrefix(volumes[k].Device, partLabelPref))
112+
case strings.HasPrefix(volumes[k].Device, uuidPref):
113+
dev = filepath.Join(diskByUUID, strings.TrimPrefix(volumes[k].Device, uuidPref))
114+
case strings.HasPrefix(volumes[k].Device, devPref):
115+
dev = volumes[k].Device
101116
default:
102117
cfg.Logger.Errorf("Unknown device reference, it should be LABEL, PARTLABEL, UUID or a /dev/* path")
103-
errs = multierror.Append(errs, fmt.Errorf("Unkown device reference: %s", vol.Device))
118+
errs = multierror.Append(errs, fmt.Errorf("Unkown device reference: %s", volumes[k].Device))
104119
continue
105120
}
106-
mountpoint := vol.Mountpoint
121+
mountpoint := volumes[k].Mountpoint
107122
if !strings.HasPrefix(mountpoint, runPath) {
108-
mountpoint = filepath.Join(sysroot, mountpoint)
123+
mountpoint = filepath.Join(spec.Sysroot, mountpoint)
109124
}
110125

111126
err := utils.MkdirAll(cfg.Fs, mountpoint, constants.DirPerm)
@@ -115,7 +130,13 @@ func MountVolumes(cfg *v1.RunConfig, sysroot string, volumes []*v1.VolumeMount)
115130
continue
116131
}
117132

118-
err = cfg.Mounter.Mount(dev, mountpoint, "auto", vol.Options)
133+
fstype := volumes[k].FSType
134+
if fstype == "" {
135+
fstype = "auto"
136+
}
137+
138+
cfg.Logger.Debugf("Mounting %s to %s", dev, mountpoint)
139+
err = cfg.Mounter.Mount(dev, mountpoint, fstype, volumes[k].Options)
119140
if err != nil {
120141
cfg.Logger.Errorf("failed mounting device %s to %s", dev, mountpoint)
121142
errs = multierror.Append(errs, err)
@@ -165,29 +186,21 @@ func MountEphemeral(cfg *v1.RunConfig, sysroot string, overlay v1.EphemeralMount
165186
return nil
166187
}
167188

168-
func MountPersistent(cfg *v1.RunConfig, sysroot string, persistent v1.PersistentMounts, volumes []*v1.VolumeMount) error {
169-
var vol *v1.VolumeMount
170-
189+
func MountPersistent(cfg *v1.RunConfig, sysroot string, persistent v1.PersistentMounts) error {
171190
mountFunc := MountOverlayPath
172191
if persistent.Mode == "bind" {
173192
mountFunc = MountBindPath
174193
}
175194

176-
for _, v := range volumes {
177-
if v.Persistent {
178-
vol = v
179-
break
180-
}
181-
}
182-
if vol == nil {
195+
if persistent.Volume.Device == "" || persistent.Volume.Mountpoint == "" {
183196
cfg.Logger.Debug("No persistent device defined, omitting persistent paths mounts")
184197
return nil
185198
}
186199

187200
for _, path := range persistent.Paths {
188201
cfg.Logger.Debugf("Mounting path %s into %s", path, sysroot)
189202

190-
target := filepath.Join(vol.Mountpoint, constants.PersistentStateDir)
203+
target := filepath.Join(persistent.Volume.Mountpoint, constants.PersistentStateDir)
191204
if err := mountFunc(cfg, sysroot, target, path); err != nil {
192205
cfg.Logger.Errorf("Error mounting path %s: %s", path, err.Error())
193206
return err
@@ -268,38 +281,30 @@ func MountOverlayPath(cfg *v1.RunConfig, sysroot, overlayDir, path string) error
268281

269282
func WriteFstab(cfg *v1.RunConfig, spec *v1.MountSpec, data string) error {
270283
var errs error
271-
var persistentVol *v1.VolumeMount
272284

273285
if !spec.WriteFstab {
274286
cfg.Logger.Debug("Skipping writing fstab")
275287
return nil
276288
}
277289

278-
data += fstab("tmpfs", constants.OverlayDir, "tmpfs", []string{"defaults", fmt.Sprintf("size=%s", spec.Ephemeral.Size)})
279-
280290
for _, vol := range spec.Volumes {
281-
if vol.Persistent {
282-
persistentVol = vol
283-
}
284-
285-
data = data + fstab(vol.Device, vol.Mountpoint, "auto", vol.Options)
291+
data += fstab(vol.Device, vol.Mountpoint, vol.FSType, vol.Options)
286292
}
287293

288-
for _, rw := range spec.Ephemeral.Paths {
289-
data += overlayLine(rw, constants.OverlayDir, constants.OverlayDir)
290-
}
294+
if spec.HasPersistent() {
295+
pVol := spec.Persistent.Volume
296+
data += fstab(pVol.Device, pVol.Mountpoint, pVol.FSType, pVol.Options)
291297

292-
if persistentVol != nil {
293298
for _, path := range spec.Persistent.Paths {
294299
if spec.Persistent.Mode == constants.OverlayMode {
295-
data += overlayLine(path, filepath.Join(persistentVol.Mountpoint, constants.PersistentStateDir), constants.PersistentDir)
300+
data += overlayLine(path, filepath.Join(pVol.Mountpoint, constants.PersistentStateDir), constants.PersistentDir)
296301
continue
297302
}
298303

299304
if spec.Persistent.Mode == constants.BindMode {
300305
trimmed := strings.TrimPrefix(path, "/")
301306
pathName := strings.ReplaceAll(trimmed, "/", "-") + ".bind"
302-
stateDir := filepath.Join(persistentVol.Mountpoint, constants.PersistentStateDir, pathName)
307+
stateDir := filepath.Join(pVol.Mountpoint, constants.PersistentStateDir, pathName)
303308

304309
data = data + fstab(stateDir, path, "none", []string{"defaults", "bind"})
305310
continue
@@ -308,6 +313,11 @@ func WriteFstab(cfg *v1.RunConfig, spec *v1.MountSpec, data string) error {
308313
}
309314
}
310315

316+
data += fstab("tmpfs", constants.OverlayDir, "tmpfs", []string{"defaults", fmt.Sprintf("size=%s", spec.Ephemeral.Size)})
317+
for _, rw := range spec.Ephemeral.Paths {
318+
data += overlayLine(rw, constants.OverlayDir, constants.OverlayDir)
319+
}
320+
311321
return cfg.Config.Fs.WriteFile(filepath.Join(spec.Sysroot, "/etc/fstab"), []byte(data), 0644)
312322
}
313323

@@ -322,11 +332,11 @@ func InitialFstabData(runner v1.Runner, sysroot string) (string, error) {
322332
if mnt.Mountpoint == sysroot {
323333
data += fstab(mnt.Device, "/", "auto", mnt.Options)
324334
} else if strings.HasPrefix(mnt.Mountpoint, sysroot) {
325-
data += fstab(mnt.Device, strings.TrimPrefix(mnt.Mountpoint, sysroot), "auto", mnt.Options)
335+
data += fstab(mnt.Device, strings.TrimPrefix(mnt.Mountpoint, sysroot), mnt.FSType, mnt.Options)
326336
} else if strings.HasPrefix(mnt.Mountpoint, constants.RunElementalDir) {
327-
data += fstab(mnt.Device, mnt.Mountpoint, "auto", mnt.Options)
337+
data += fstab(mnt.Device, mnt.Mountpoint, mnt.FSType, mnt.Options)
328338
} else if mnt.Mountpoint == constants.RunningStateDir {
329-
data += fstab(mnt.Device, mnt.Mountpoint, "auto", mnt.Options)
339+
data += fstab(mnt.Device, mnt.Mountpoint, mnt.FSType, mnt.Options)
330340
}
331341
}
332342

@@ -337,6 +347,10 @@ func fstab(device, path, fstype string, flags []string) string {
337347
if len(flags) == 0 {
338348
flags = []string{"defaults"}
339349
}
350+
351+
if fstype == "" {
352+
fstype = "auto"
353+
}
340354
return fmt.Sprintf("%s\t%s\t%s\t%s\t0\t0\n", device, path, fstype, strings.Join(flags, ","))
341355
}
342356

pkg/action/mount_test.go

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,17 @@ var _ = Describe("Mount Action", func() {
8282
Persistent: v1.PersistentMounts{
8383
Mode: constants.BindMode,
8484
Paths: []string{"/some/path"},
85+
Volume: v1.VolumeMount{
86+
Mountpoint: constants.PersistentDir,
87+
Device: "/dev/persistentdev",
88+
},
8589
},
8690
Volumes: []*v1.VolumeMount{
8791
{
88-
Mountpoint: constants.PersistentDir,
92+
Mountpoint: "/run/elemental",
8993
Device: "/dev/somedevice",
90-
Persistent: true,
9194
Options: []string{"rw", "defaults"},
95+
FSType: "vfat",
9296
},
9397
},
9498
}
@@ -102,9 +106,10 @@ var _ = Describe("Mount Action", func() {
102106
fstab, err := cfg.Config.Fs.ReadFile(filepath.Join(spec.Sysroot, "/etc/fstab"))
103107
Expect(err).To(BeNil())
104108
expectedFstab := "/dev/loop0\t/\tauto\tro,relatime\t0\t0\n"
105-
expectedFstab += "tmpfs\t/run/elemental/overlay\ttmpfs\tdefaults,size=30%\t0\t0\n"
106-
expectedFstab += "/dev/somedevice\t/run/elemental/persistent\tauto\trw,defaults\t0\t0\n"
109+
expectedFstab += "/dev/somedevice\t/run/elemental\tvfat\trw,defaults\t0\t0\n"
110+
expectedFstab += "/dev/persistentdev\t/run/elemental/persistent\tauto\tdefaults\t0\t0\n"
107111
expectedFstab += "/run/elemental/persistent/.state/some-path.bind\t/some/path\tnone\tdefaults,bind\t0\t0\n"
112+
expectedFstab += "tmpfs\t/run/elemental/overlay\ttmpfs\tdefaults,size=30%\t0\t0\n"
108113
Expect(string(fstab)).To(Equal(expectedFstab))
109114
})
110115

@@ -118,13 +123,17 @@ var _ = Describe("Mount Action", func() {
118123
Persistent: v1.PersistentMounts{
119124
Mode: constants.OverlayMode,
120125
Paths: []string{"/some/path"},
126+
Volume: v1.VolumeMount{
127+
Mountpoint: constants.PersistentDir,
128+
Device: "/dev/persistentdev",
129+
},
121130
},
122131
Volumes: []*v1.VolumeMount{
123132
{
124-
Mountpoint: constants.PersistentDir,
133+
Mountpoint: constants.PersistentDir + "/somedir",
125134
Device: "/dev/somedevice",
126-
Persistent: true,
127135
Options: []string{"rw", "defaults"},
136+
FSType: "vfat",
128137
},
129138
},
130139
}
@@ -137,10 +146,11 @@ var _ = Describe("Mount Action", func() {
137146
fstab, err := cfg.Config.Fs.ReadFile(filepath.Join(spec.Sysroot, "/etc/fstab"))
138147
Expect(err).To(BeNil())
139148
expectedFstab := "/dev/loop0\t/\tauto\tro,relatime\t0\t0\n"
140-
expectedFstab += "tmpfs\t/run/elemental/overlay\ttmpfs\tdefaults,size=30%\t0\t0\n"
141-
expectedFstab += "/dev/somedevice\t/run/elemental/persistent\tauto\trw,defaults\t0\t0\n"
149+
expectedFstab += "/dev/somedevice\t/run/elemental/persistent/somedir\tvfat\trw,defaults\t0\t0\n"
150+
expectedFstab += "/dev/persistentdev\t/run/elemental/persistent\tauto\tdefaults\t0\t0\n"
142151
expectedFstab += "overlay\t/some/path\toverlay\t"
143152
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"
153+
expectedFstab += "tmpfs\t/run/elemental/overlay\ttmpfs\tdefaults,size=30%\t0\t0\n"
144154

145155
Expect(string(fstab)).To(Equal(expectedFstab))
146156
})

pkg/config/config.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -226,11 +226,6 @@ func NewMountSpec() *v1.MountSpec {
226226
WriteFstab: true,
227227
Volumes: []*v1.VolumeMount{
228228
{
229-
Mountpoint: constants.PersistentDir,
230-
Device: fmt.Sprintf("PARTLABEL=%s", constants.PersistentPartName),
231-
Options: []string{"rw", "defaults"},
232-
Persistent: true,
233-
}, {
234229
Mountpoint: constants.OEMPath,
235230
Device: fmt.Sprintf("PARTLABEL=%s", constants.OEMPartName),
236231
Options: []string{"rw", "defaults"},
@@ -248,6 +243,11 @@ func NewMountSpec() *v1.MountSpec {
248243
Persistent: v1.PersistentMounts{
249244
Mode: constants.OverlayMode,
250245
Paths: []string{"/etc/systemd", "/etc/ssh", "/home", "/opt", "/root", "/var/log"},
246+
Volume: v1.VolumeMount{
247+
Mountpoint: constants.PersistentDir,
248+
Device: fmt.Sprintf("PARTLABEL=%s", constants.PersistentPartName),
249+
Options: []string{"rw", "defaults"},
250+
},
251251
},
252252
}
253253
}

pkg/types/v1/config.go

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ type MountSpec struct {
255255
Disable bool `yaml:"disable,omitempty" mapstructure:"disable"`
256256
Sysroot string `yaml:"sysroot,omitempty" mapstructure:"sysroot"`
257257
Mode string `yaml:"mode,omitempty" mapstructure:"mode"`
258-
Volumes []*VolumeMount `yaml:"volumes,omitempty" mapstructure:"volumes"`
258+
Volumes []*VolumeMount `yaml:"extra-volumes,omitempty" mapstructure:"extra-volumes"`
259259
Ephemeral EphemeralMounts `yaml:"ephemeral,omitempty" mapstructure:"ephemeral"`
260260
Persistent PersistentMounts `yaml:"persistent,omitempty" mapstructure:"persistent"`
261261
}
@@ -264,14 +264,15 @@ type VolumeMount struct {
264264
Mountpoint string `yaml:"mountpoint,omitempty" mapstructure:"mountpoint"`
265265
Device string `yaml:"device,omitempty" mapstructure:"device"`
266266
Options []string `yaml:"options,omitempty" mapstructure:"options"`
267-
Persistent bool `yaml:"persistent,omitempty" mapstructure:"persistent"`
267+
FSType string `yaml:"fs,omitempty" mapstructure:"fs"`
268268
}
269269

270270
// PersistentMounts struct contains settings for which paths to mount as
271271
// persistent
272272
type PersistentMounts struct {
273-
Mode string `yaml:"mode,omitempty" mapstructure:"mode"`
274-
Paths []string `yaml:"paths,omitempty" mapstructure:"paths"`
273+
Mode string `yaml:"mode,omitempty" mapstructure:"mode"`
274+
Paths []string `yaml:"paths,omitempty" mapstructure:"paths"`
275+
Volume VolumeMount `yaml:"volume,omitempty" mapstructure:"volume"`
275276
}
276277

277278
// EphemeralMounts contains information about the RW overlay mounted over the
@@ -314,19 +315,14 @@ func (spec *MountSpec) Sanitize() error {
314315
})
315316
}
316317

317-
// Ignore the volume used for persistent paths in recovery mode
318-
if spec.Mode == constants.RecoveryImgName {
319-
for i, v := range spec.Volumes {
320-
if v.Persistent {
321-
spec.Volumes = append(spec.Volumes[:i], spec.Volumes[i+1:]...)
322-
break
323-
}
324-
}
325-
}
326-
327318
return nil
328319
}
329320

321+
func (spec *MountSpec) HasPersistent() bool {
322+
return spec.Mode != constants.RecoveryImgName &&
323+
spec.Persistent.Volume.Device != "" && spec.Persistent.Volume.Mountpoint != ""
324+
}
325+
330326
// ResetSpec struct represents all the reset action details
331327
type ResetSpec struct {
332328
FormatPersistent bool `yaml:"reset-persistent,omitempty" mapstructure:"reset-persistent"`

0 commit comments

Comments
 (0)