Skip to content

Commit 3d509bc

Browse files
ticpuk8s-infra-cherrypick-robot
authored andcommitted
core/mount/manager: add tests for WithTemporary option
Add tests for the WithTemporary mount activation used by `ctr images mount`. Covers bind mount and overlay scenarios to catch regressions like #12549. Signed-off-by: Jérôme Poulin <[email protected]>
1 parent e7a0ac9 commit 3d509bc

1 file changed

Lines changed: 156 additions & 1 deletion

File tree

core/mount/manager/manager_linux_test.go

Lines changed: 156 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,161 @@ func TestLoopbackOverlay(t *testing.T) {
314314
}
315315
}
316316

317+
// TestTemporaryMountActivation tests the WithTemporary option used by
318+
// `ctr images mount`. This verifies the bind mount returned in info.System
319+
// points to a valid, mounted directory.
320+
func TestTemporaryMountActivation(t *testing.T) {
321+
testutil.RequiresRoot(t)
322+
ctx := logtest.WithT(context.Background(), t)
323+
ctx = namespaces.WithNamespace(ctx, "test")
324+
td := t.TempDir()
325+
metadb := filepath.Join(td, "mounts.db")
326+
targetdir := filepath.Join(td, "m")
327+
db, err := bolt.Open(metadb, 0600, nil)
328+
require.NoError(t, err)
329+
defer db.Close()
330+
331+
sourcedir := filepath.Join(td, "source")
332+
require.NoError(t, os.MkdirAll(sourcedir, 0755))
333+
334+
a := fstest.Apply(
335+
fstest.CreateFile("/testfile.txt", []byte("test content\n"), 0644),
336+
fstest.CreateDir("/testdir", 0755),
337+
)
338+
require.NoError(t, a.Apply(sourcedir))
339+
340+
mounts := []mount.Mount{
341+
{
342+
Type: "bind",
343+
Source: sourcedir,
344+
Options: []string{"rbind", "ro"},
345+
},
346+
}
347+
348+
m, err := NewManager(db, targetdir)
349+
require.NoError(t, err)
350+
351+
ainfo, err := m.Activate(ctx, "temp-mount-test", mounts, mount.WithTemporary)
352+
require.NoError(t, err)
353+
defer func() {
354+
assert.NoError(t, m.Deactivate(ctx, "temp-mount-test"))
355+
}()
356+
357+
require.NotEmpty(t, ainfo.System, "Expected system mounts to be returned")
358+
359+
require.Len(t, ainfo.System, 1, "Expected exactly one system mount")
360+
systemMount := ainfo.System[0]
361+
assert.Equal(t, "bind", systemMount.Type, "Expected bind mount type")
362+
363+
sourceInfo, err := os.Stat(systemMount.Source)
364+
require.NoError(t, err, "Bind mount source %q should exist", systemMount.Source)
365+
assert.True(t, sourceInfo.IsDir(), "Bind mount source should be a directory")
366+
367+
testFile := filepath.Join(systemMount.Source, "testfile.txt")
368+
content, err := os.ReadFile(testFile)
369+
require.NoError(t, err, "Should be able to read test file from bind mount source")
370+
assert.Equal(t, "test content\n", string(content), "Test file content should match")
371+
372+
targetMount := filepath.Join(td, "target")
373+
require.NoError(t, os.MkdirAll(targetMount, 0755))
374+
375+
err = mount.All(ainfo.System, targetMount)
376+
require.NoError(t, err, "Should be able to mount system mounts to target")
377+
defer testutil.Unmount(t, targetMount)
378+
379+
targetTestFile := filepath.Join(targetMount, "testfile.txt")
380+
targetContent, err := os.ReadFile(targetTestFile)
381+
require.NoError(t, err, "Should be able to read test file from target mount")
382+
assert.Equal(t, "test content\n", string(targetContent), "Target test file content should match")
383+
}
384+
385+
// TestTemporaryOverlayMountActivation tests WithTemporary with overlay mounts,
386+
// which is the more common case for `ctr images mount` with overlay snapshotter.
387+
func TestTemporaryOverlayMountActivation(t *testing.T) {
388+
testutil.RequiresRoot(t)
389+
ctx := logtest.WithT(context.Background(), t)
390+
ctx = namespaces.WithNamespace(ctx, "test")
391+
td := t.TempDir()
392+
metadb := filepath.Join(td, "mounts.db")
393+
targetdir := filepath.Join(td, "m")
394+
db, err := bolt.Open(metadb, 0600, nil)
395+
require.NoError(t, err)
396+
defer db.Close()
397+
398+
lower1 := filepath.Join(td, "lower1")
399+
lower2 := filepath.Join(td, "lower2")
400+
upper := filepath.Join(td, "upper")
401+
work := filepath.Join(td, "work")
402+
403+
require.NoError(t, os.MkdirAll(lower1, 0755))
404+
require.NoError(t, os.MkdirAll(lower2, 0755))
405+
require.NoError(t, os.MkdirAll(upper, 0755))
406+
require.NoError(t, os.MkdirAll(work, 0755))
407+
408+
require.NoError(t, os.WriteFile(filepath.Join(lower1, "file1.txt"), []byte("layer1\n"), 0644))
409+
require.NoError(t, os.WriteFile(filepath.Join(lower2, "file2.txt"), []byte("layer2\n"), 0644))
410+
411+
mounts := []mount.Mount{
412+
{
413+
Type: "overlay",
414+
Source: "overlay",
415+
Options: []string{
416+
fmt.Sprintf("lowerdir=%s:%s", lower2, lower1),
417+
fmt.Sprintf("upperdir=%s", upper),
418+
fmt.Sprintf("workdir=%s", work),
419+
},
420+
},
421+
}
422+
423+
m, err := NewManager(db, targetdir)
424+
require.NoError(t, err)
425+
426+
ainfo, err := m.Activate(ctx, "temp-overlay-test", mounts, mount.WithTemporary)
427+
require.NoError(t, err)
428+
defer func() {
429+
assert.NoError(t, m.Deactivate(ctx, "temp-overlay-test"))
430+
}()
431+
432+
require.NotEmpty(t, ainfo.System, "Expected system mounts to be returned")
433+
434+
require.Len(t, ainfo.System, 1, "Expected exactly one system mount")
435+
systemMount := ainfo.System[0]
436+
assert.Equal(t, "bind", systemMount.Type, "Expected bind mount type")
437+
438+
sourceInfo, err := os.Stat(systemMount.Source)
439+
require.NoError(t, err, "Bind mount source %q should exist", systemMount.Source)
440+
assert.True(t, sourceInfo.IsDir(), "Bind mount source should be a directory")
441+
442+
file1 := filepath.Join(systemMount.Source, "file1.txt")
443+
file2 := filepath.Join(systemMount.Source, "file2.txt")
444+
445+
content1, err := os.ReadFile(file1)
446+
require.NoError(t, err, "Should be able to read file1 from overlay via bind source")
447+
assert.Equal(t, "layer1\n", string(content1))
448+
449+
content2, err := os.ReadFile(file2)
450+
require.NoError(t, err, "Should be able to read file2 from overlay via bind source")
451+
assert.Equal(t, "layer2\n", string(content2))
452+
453+
targetMount := filepath.Join(td, "target")
454+
require.NoError(t, os.MkdirAll(targetMount, 0755))
455+
456+
err = mount.All(ainfo.System, targetMount)
457+
require.NoError(t, err, "Should be able to mount system mounts to target")
458+
defer testutil.Unmount(t, targetMount)
459+
460+
targetFile1 := filepath.Join(targetMount, "file1.txt")
461+
targetFile2 := filepath.Join(targetMount, "file2.txt")
462+
463+
targetContent1, err := os.ReadFile(targetFile1)
464+
require.NoError(t, err)
465+
assert.Equal(t, "layer1\n", string(targetContent1))
466+
467+
targetContent2, err := os.ReadFile(targetFile2)
468+
require.NoError(t, err)
469+
assert.Equal(t, "layer2\n", string(targetContent2))
470+
}
471+
317472
func initalizeBlockDevice(td string, a fstest.Applier) (string, error) {
318473
file, err := os.CreateTemp(td, "fs-")
319474
if err != nil {
@@ -342,7 +497,7 @@ func initalizeBlockDevice(td string, a fstest.Applier) (string, error) {
342497

343498
m := mount.Mount{
344499
Type: "ext4",
345-
Source: dpath, // previous mount
500+
Source: dpath,
346501
Options: []string{"loop"},
347502
}
348503
target, err := os.MkdirTemp(td, "mount-")

0 commit comments

Comments
 (0)