Skip to content

Commit 1fbc11e

Browse files
committed
Fixes squashfs images creation (#2230)
* Fixes squashfs images creation (bsc#1233289) If upgrading from a container including the root of the host mounted in /host the upgrade process does not exclude the /host path and other stateful paths such as /run. This commit sets the default excludes used in rsync calls to also apply for mksquashfs. Signed-off-by: David Cassany <[email protected]> * Define static method for default exclude relative paths This commit defines static methods for excluded paths in sync operations. One method for relative paths and another one with the same result rooted to a given path. It also uses wildcards to only exclude certain directories content while keeping the directory itself. Signed-off-by: David Cassany <[email protected]> * Add some additional unit tests for rsync wrappers Signed-off-by: David Cassany <[email protected]> --------- Signed-off-by: David Cassany <[email protected]> (cherry picked from commit 527c12d)
1 parent a9f2291 commit 1fbc11e

File tree

4 files changed

+111
-47
lines changed

4 files changed

+111
-47
lines changed

pkg/constants/constants.go

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -204,24 +204,35 @@ const (
204204
ActionBuildDisk = "build-disk"
205205
)
206206

207-
// GetDefaultSystemEcludes returns a list of transient paths
207+
// GetDefaultSystemExcludes returns a list of paths
208208
// that are commonly present in an Elemental based running system.
209-
// Those paths are not needed or wanted in order to replicate the
210-
// root-tree as they are generated at runtime.
211-
func GetDefaultSystemExcludes(rootDir string) []string {
209+
// Those paths are not needed or wanted in order to replicate the root-tree.
210+
func GetDefaultSystemExcludes() []string {
212211
return []string{
213-
filepath.Join(rootDir, "/.snapshots"),
214-
filepath.Join(rootDir, "/mnt"),
215-
filepath.Join(rootDir, "/proc"),
216-
filepath.Join(rootDir, "/sys"),
217-
filepath.Join(rootDir, "/dev"),
218-
filepath.Join(rootDir, "/tmp"),
219-
filepath.Join(rootDir, "/run"),
220-
filepath.Join(rootDir, "/host"),
221-
filepath.Join(rootDir, "/etc/resolv.conf"),
212+
".snapshots",
213+
"mnt/*",
214+
"proc/*",
215+
"sys/*",
216+
"dev/*",
217+
"tmp/*",
218+
"run/*",
219+
"host",
220+
"etc/resolv.conf",
222221
}
223222
}
224223

224+
// GetDefaultSystemExcludes returns a list of transient paths
225+
// that are commonly present in an Elemental based running system.
226+
// Paths are rooted to the given rootDir. Those paths are not
227+
// needed or wanted in order to replicate the root-tree.
228+
func GetDefaultSystemRootedExcludes(rootDir string) []string {
229+
var list []string
230+
for _, path := range GetDefaultSystemExcludes() {
231+
list = append(list, filepath.Join(rootDir, path))
232+
}
233+
return list
234+
}
235+
225236
func GetKernelPatterns() []string {
226237
return []string{
227238
"/boot/uImage*",

pkg/elemental/elemental.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -369,13 +369,14 @@ func CreateImageFromTree(c types.Config, img *types.Image, rootDir string, prelo
369369
c.Logger.Warnf("failed SELinux labelling at %s: %v", rootDir, err)
370370
}
371371

372-
err = utils.CreateSquashFS(c.Runner, c.Logger, rootDir, img.File, c.SquashFsCompressionConfig)
372+
excludes := cnst.GetDefaultSystemExcludes()
373+
err = utils.CreateSquashFS(c.Runner, c.Logger, rootDir, img.File, c.SquashFsCompressionConfig, excludes...)
373374
if err != nil {
374375
c.Logger.Errorf("failed creating squashfs image for %s: %v", img.File, err)
375376
return err
376377
}
377378
} else {
378-
excludes := cnst.GetDefaultSystemExcludes(rootDir)
379+
excludes := cnst.GetDefaultSystemRootedExcludes(rootDir)
379380
err = CreateFileSystemImage(c, img, rootDir, preload, excludes...)
380381
if err != nil {
381382
c.Logger.Errorf("failed creating filesystem image: %v", err)
@@ -585,7 +586,7 @@ func DumpSource(
585586
}
586587
imgSrc.SetDigest(digest)
587588
} else if imgSrc.IsDir() {
588-
excludes := cnst.GetDefaultSystemExcludes(imgSrc.Value())
589+
excludes := cnst.GetDefaultSystemRootedExcludes(imgSrc.Value())
589590
err = syncFunc(c.Logger, c.Runner, c.Fs, imgSrc.Value(), target, excludes...)
590591
if err != nil {
591592
return err

pkg/utils/common.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -279,17 +279,25 @@ func CosignVerify(fs types.FS, runner types.Runner, image string, publicKey stri
279279
}
280280

281281
// CreateSquashFS creates a squash file at destination from a source, with options
282-
// TODO: Check validity of source maybe?
283-
func CreateSquashFS(runner types.Runner, logger types.Logger, source string, destination string, options []string) error {
282+
func CreateSquashFS(runner types.Runner, logger types.Logger, source string, destination string, options []string, excludes ...string) error {
284283
// create args
285284
args := []string{source, destination}
286285
// append options passed to args in order to have the correct order
287286
// protect against options passed together in the same string , i.e. "-x add" instead of "-x", "add"
288287
var optionsExpanded []string
289288
for _, op := range options {
290-
optionsExpanded = append(optionsExpanded, strings.Split(op, " ")...)
289+
opExpanded := strings.Split(op, " ")
290+
if opExpanded[0] == "-e" {
291+
logger.Warnf("Ignoring option '%s', exclude directories must be passed as excludes argument", op)
292+
continue
293+
}
294+
optionsExpanded = append(optionsExpanded, opExpanded...)
291295
}
292296
args = append(args, optionsExpanded...)
297+
if len(excludes) >= 0 {
298+
excludesOpt := append([]string{"-wildcards", "-e"}, excludes...)
299+
args = append(args, excludesOpt...)
300+
}
293301
out, err := runner.Run("mksquashfs", args...)
294302
if err != nil {
295303
logger.Debugf("Error running squashfs creation, stdout: %s", out)

pkg/utils/utils_test.go

Lines changed: 72 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -452,13 +452,18 @@ var _ = Describe("Utils", Label("utils"), func() {
452452
Expect(utils.CreateDirStructure(fs, "/my/root")).NotTo(BeNil())
453453
})
454454
})
455-
Describe("SyncData", Label("SyncData"), func() {
456-
It("Copies all files from source to target", func() {
457-
sourceDir, err := utils.TempDir(fs, "", "elementalsource")
455+
Describe("Rsync tests", Label("rsync"), func() {
456+
var sourceDir, destDir string
457+
var err error
458+
459+
BeforeEach(func() {
460+
sourceDir, err = utils.TempDir(fs, "", "elementalsource")
458461
Expect(err).ShouldNot(HaveOccurred())
459-
destDir, err := utils.TempDir(fs, "", "elementaltarget")
462+
destDir, err = utils.TempDir(fs, "", "elementaltarget")
460463
Expect(err).ShouldNot(HaveOccurred())
464+
})
461465

466+
It("Copies all files from source to target", func() {
462467
for i := 0; i < 5; i++ {
463468
_, _ = utils.TempFile(fs, sourceDir, "file*")
464469
}
@@ -479,11 +484,6 @@ var _ = Describe("Utils", Label("utils"), func() {
479484
})
480485

481486
It("Copies all files from source to target respecting excludes", func() {
482-
sourceDir, err := utils.TempDir(fs, "", "elementalsource")
483-
Expect(err).ShouldNot(HaveOccurred())
484-
destDir, err := utils.TempDir(fs, "", "elementaltarget")
485-
Expect(err).ShouldNot(HaveOccurred())
486-
487487
utils.MkdirAll(fs, filepath.Join(sourceDir, "host"), constants.DirPerm)
488488
utils.MkdirAll(fs, filepath.Join(sourceDir, "run"), constants.DirPerm)
489489

@@ -522,11 +522,6 @@ var _ = Describe("Utils", Label("utils"), func() {
522522
})
523523

524524
It("Copies all files from source to target respecting excludes with '/' prefix", func() {
525-
sourceDir, err := utils.TempDir(fs, "", "elementalsource")
526-
Expect(err).ShouldNot(HaveOccurred())
527-
destDir, err := utils.TempDir(fs, "", "elementaltarget")
528-
Expect(err).ShouldNot(HaveOccurred())
529-
530525
utils.MkdirAll(fs, filepath.Join(sourceDir, "host"), constants.DirPerm)
531526
utils.MkdirAll(fs, filepath.Join(sourceDir, "run"), constants.DirPerm)
532527
utils.MkdirAll(fs, filepath.Join(sourceDir, "var", "run"), constants.DirPerm)
@@ -536,40 +531,65 @@ var _ = Describe("Utils", Label("utils"), func() {
536531

537532
filesDest, err := fs.ReadDir(destDir)
538533
Expect(err).To(BeNil())
539-
540534
destNames := getNamesFromListFiles(filesDest)
541535

542536
filesSource, err := fs.ReadDir(sourceDir)
543537
Expect(err).To(BeNil())
544-
545-
SourceNames := getNamesFromListFiles(filesSource)
538+
sourceNames := getNamesFromListFiles(filesSource)
546539

547540
// Shouldn't be the same
548-
Expect(destNames).ToNot(Equal(SourceNames))
541+
Expect(destNames).ToNot(Equal(sourceNames))
549542

550543
Expect(utils.Exists(fs, filepath.Join(destDir, "var", "run"))).To(BeTrue())
551544
Expect(utils.Exists(fs, filepath.Join(destDir, "tmp", "host"))).To(BeTrue())
552545
Expect(utils.Exists(fs, filepath.Join(destDir, "host"))).To(BeFalse())
553546
Expect(utils.Exists(fs, filepath.Join(destDir, "run"))).To(BeFalse())
554547
})
555548

549+
It("Copies all files from source to target respecting excludes with wildcards", func() {
550+
utils.MkdirAll(fs, filepath.Join(sourceDir, "run"), constants.DirPerm)
551+
utils.MkdirAll(fs, filepath.Join(sourceDir, "var", "run"), constants.DirPerm)
552+
Expect(fs.WriteFile(filepath.Join(sourceDir, "run", "testfile"), []byte{}, constants.DirPerm)).To(Succeed())
553+
554+
Expect(utils.SyncData(logger, realRunner, fs, sourceDir, destDir, "/run/*")).To(BeNil())
555+
556+
Expect(utils.Exists(fs, filepath.Join(destDir, "var", "run"))).To(BeTrue())
557+
Expect(utils.Exists(fs, filepath.Join(destDir, "run"))).To(BeTrue())
558+
Expect(utils.Exists(fs, filepath.Join(destDir, "run", "testfile"))).To(BeFalse())
559+
})
560+
561+
It("Mirrors all files from source to destination deleting pre-existing files in destination if needed", func() {
562+
utils.MkdirAll(fs, filepath.Join(sourceDir, "run"), constants.DirPerm)
563+
utils.MkdirAll(fs, filepath.Join(sourceDir, "var", "run"), constants.DirPerm)
564+
Expect(fs.WriteFile(filepath.Join(sourceDir, "run", "testfile"), []byte{}, constants.DirPerm)).To(Succeed())
565+
Expect(fs.WriteFile(filepath.Join(destDir, "testfile"), []byte{}, constants.DirPerm)).To(Succeed())
566+
567+
Expect(utils.MirrorData(logger, realRunner, fs, sourceDir, destDir)).To(BeNil())
568+
569+
filesDest, err := fs.ReadDir(destDir)
570+
Expect(err).To(BeNil())
571+
destNames := getNamesFromListFiles(filesDest)
572+
573+
filesSource, err := fs.ReadDir(sourceDir)
574+
Expect(err).To(BeNil())
575+
sourceNames := getNamesFromListFiles(filesSource)
576+
577+
// Should be the same
578+
Expect(destNames).To(Equal(sourceNames))
579+
580+
// pre-exising file in destination deleted if this is not part of source
581+
Expect(utils.Exists(fs, filepath.Join(destDir, "testfile"))).To(BeFalse())
582+
})
583+
556584
It("should not fail if dirs are empty", func() {
557-
sourceDir, err := utils.TempDir(fs, "", "elementalsource")
558-
Expect(err).ShouldNot(HaveOccurred())
559-
destDir, err := utils.TempDir(fs, "", "elementaltarget")
560-
Expect(err).ShouldNot(HaveOccurred())
561585
Expect(utils.SyncData(logger, realRunner, fs, sourceDir, destDir)).To(BeNil())
562586
})
563587
It("should fail if destination does not exist", func() {
564-
sourceDir, err := os.MkdirTemp("", "elemental")
565-
Expect(err).To(BeNil())
566-
defer os.RemoveAll(sourceDir)
588+
fs.RemoveAll(destDir)
567589
Expect(utils.SyncData(logger, realRunner, nil, sourceDir, "/welp")).NotTo(BeNil())
568590
})
569591
It("should fail if source does not exist", func() {
570-
destDir, err := os.MkdirTemp("", "elemental")
571-
Expect(err).To(BeNil())
572-
defer os.RemoveAll(destDir)
592+
fs.RemoveAll(sourceDir)
573593
Expect(utils.SyncData(logger, realRunner, nil, "/welp", destDir)).NotTo(BeNil())
574594
})
575595
})
@@ -948,6 +968,30 @@ var _ = Describe("Utils", Label("utils"), func() {
948968
})).To(BeNil())
949969
Expect(err).ToNot(HaveOccurred())
950970
})
971+
It("ignores any '-e' option", func() {
972+
args := append(constants.GetDefaultSquashfsCompressionOptions(), "-e /some/path")
973+
err := utils.CreateSquashFS(runner, logger, "source", "dest", args)
974+
cmd := []string{"mksquashfs", "source", "dest"}
975+
cmd = append(cmd, constants.GetDefaultSquashfsCompressionOptions()...)
976+
Expect(runner.IncludesCmds([][]string{
977+
cmd,
978+
})).To(BeNil())
979+
Expect(err).ToNot(HaveOccurred())
980+
})
981+
It("excludes given paths", func() {
982+
983+
err := utils.CreateSquashFS(
984+
runner, logger, "source", "dest", constants.GetDefaultSquashfsCompressionOptions(),
985+
"some/path", "another/path",
986+
)
987+
cmd := []string{"mksquashfs", "source", "dest"}
988+
cmd = append(cmd, constants.GetDefaultSquashfsCompressionOptions()...)
989+
cmd = append(cmd, "-wildcards", "-e", "some/path", "another/path")
990+
Expect(runner.IncludesCmds([][]string{
991+
cmd,
992+
})).To(Succeed())
993+
Expect(err).ToNot(HaveOccurred())
994+
})
951995
It("returns an error if it fails", func() {
952996
runner.ReturnError = errors.New("error")
953997
err := utils.CreateSquashFS(runner, logger, "source", "dest", []string{})

0 commit comments

Comments
 (0)