Skip to content

Commit

Permalink
changed internal/pkg/util/fs/squashfs to use internal/pkg/util/fs/squ…
Browse files Browse the repository at this point in the history
…ashfs/fuse; add ctx args as needed
  • Loading branch information
Omer Preminger committed Sep 15, 2023
1 parent 9e95416 commit 21f2008
Show file tree
Hide file tree
Showing 11 changed files with 116 additions and 119 deletions.
8 changes: 4 additions & 4 deletions internal/pkg/runtime/launcher/oci/launcher_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -765,7 +765,7 @@ func (l *Launcher) RunWrapped(ctx context.Context, containerID, bundlePath, pidF
if err := os.MkdirAll(im.GetMountPoint(), 0o755); err != nil {
return err
}
if err := im.Mount(); err != nil {
if err := im.Mount(ctx); err != nil {
return err
}
}
Expand All @@ -784,17 +784,17 @@ func (l *Launcher) RunWrapped(ctx context.Context, containerID, bundlePath, pidF
err = Run(ctx, containerID, absBundle, pidFile, systemdCgroups)

for _, im := range l.imageMountsByMountpoint {
im.Unmount()
im.Unmount(ctx)
}

return err
}

if len(l.cfg.OverlayPaths) > 0 {
return WrapWithOverlays(runFunc, absBundle, l.cfg.OverlayPaths, l.cfg.AllowSUID)
return WrapWithOverlays(ctx, runFunc, absBundle, l.cfg.OverlayPaths, l.cfg.AllowSUID)
}

return WrapWithWritableTmpFs(runFunc, absBundle, l.cfg.AllowSUID)
return WrapWithWritableTmpFs(ctx, runFunc, absBundle, l.cfg.AllowSUID)
}

// getCgroup will return a cgroup path and resources for the runtime to create.
Expand Down
23 changes: 12 additions & 11 deletions internal/pkg/runtime/launcher/oci/oci_overlay.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package oci

import (
"context"
"fmt"

"github.com/sylabs/singularity/v4/internal/pkg/util/fs/overlay"
Expand All @@ -18,8 +19,8 @@ import (
// tmpfs. This tmpfs is always writable so that the launcher and runtime are
// able to add content to the container. Whether it is writable from inside the
// container is controlled by the runtime config.
func WrapWithWritableTmpFs(f func() error, bundleDir string, allowSetuid bool) error {
overlayDir, err := prepareWritableTmpfs(bundleDir, allowSetuid)
func WrapWithWritableTmpFs(ctx context.Context, f func() error, bundleDir string, allowSetuid bool) error {
overlayDir, err := prepareWritableTmpfs(ctx, bundleDir, allowSetuid)
sylog.Debugf("Done with prepareWritableTmpfs; overlayDir is: %q", overlayDir)
if err != nil {
return err
Expand All @@ -28,7 +29,7 @@ func WrapWithWritableTmpFs(f func() error, bundleDir string, allowSetuid bool) e
err = f()

// Cleanup actions log errors, but don't return - so we get as much cleanup done as possible.
if cleanupErr := cleanupWritableTmpfs(bundleDir, overlayDir); cleanupErr != nil {
if cleanupErr := cleanupWritableTmpfs(ctx, bundleDir, overlayDir); cleanupErr != nil {
sylog.Errorf("While cleaning up writable tmpfs: %v", cleanupErr)
}

Expand All @@ -37,7 +38,7 @@ func WrapWithWritableTmpFs(f func() error, bundleDir string, allowSetuid bool) e
}

// WrapWithOverlays runs a function wrapped with prep / cleanup steps for overlays.
func WrapWithOverlays(f func() error, bundleDir string, overlayPaths []string, allowSetuid bool) error {
func WrapWithOverlays(ctx context.Context, f func() error, bundleDir string, overlayPaths []string, allowSetuid bool) error {
writableOverlayFound := false
s := overlay.Set{}
for _, p := range overlayPaths {
Expand All @@ -64,36 +65,36 @@ func WrapWithOverlays(f func() error, bundleDir string, overlayPaths []string, a
}

rootFsDir := tools.RootFs(bundleDir).Path()
err := s.Mount(rootFsDir)
err := s.Mount(ctx, rootFsDir)
if err != nil {
return err
}

if writableOverlayFound {
err = f()
} else {
err = WrapWithWritableTmpFs(f, bundleDir, allowSetuid)
err = WrapWithWritableTmpFs(ctx, f, bundleDir, allowSetuid)
}

// Cleanup actions log errors, but don't return - so we get as much cleanup done as possible.
if cleanupErr := s.Unmount(rootFsDir); cleanupErr != nil {
if cleanupErr := s.Unmount(ctx, rootFsDir); cleanupErr != nil {
sylog.Errorf("While unmounting rootfs overlay: %v", cleanupErr)
}

// Return any error from the actual container payload - preserve exit code.
return err
}

func prepareWritableTmpfs(bundleDir string, allowSetuid bool) (string, error) {
func prepareWritableTmpfs(ctx context.Context, bundleDir string, allowSetuid bool) (string, error) {
sylog.Debugf("Configuring writable tmpfs overlay for %s", bundleDir)
c := singularityconf.GetCurrentConfig()
if c == nil {
return "", fmt.Errorf("singularity configuration is not initialized")
}
return tools.CreateOverlayTmpfs(bundleDir, int(c.SessiondirMaxSize), allowSetuid)
return tools.CreateOverlayTmpfs(ctx, bundleDir, int(c.SessiondirMaxSize), allowSetuid)
}

func cleanupWritableTmpfs(bundleDir, overlayDir string) error {
func cleanupWritableTmpfs(ctx context.Context, bundleDir, overlayDir string) error {
sylog.Debugf("Cleaning up writable tmpfs overlay for %s", bundleDir)
return tools.DeleteOverlayTmpfs(bundleDir, overlayDir)
return tools.DeleteOverlayTmpfs(ctx, bundleDir, overlayDir)
}
18 changes: 12 additions & 6 deletions internal/pkg/util/fs/fuse/fuse_mount_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package fuse

import (
"context"
"fmt"
"os"
"os/exec"
Expand Down Expand Up @@ -43,11 +44,15 @@ type ImageMount struct {

// AllowOther is set to true to mount the image with the "allow_other" option.
AllowOther bool

// ExtraMountOpts are options to be passed to the mount command (in the "-o"
// argument) beyond the ones autogenerated from other ImageMount fields.
ExtraMountOpts []string
}

// Mount mounts an image to a temporary directory. It also verifies that
// the fusermount utility is present before performing the mount.
func (i *ImageMount) Mount() (err error) {
func (i *ImageMount) Mount(ctx context.Context) (err error) {
fuseMountCmd, err := i.determineMountCmd()
if err != nil {
return err
Expand All @@ -60,7 +65,7 @@ func (i *ImageMount) Mount() (err error) {

fuseCmdLine := fmt.Sprintf("%s %s", fuseMountCmd, strings.Join(args, " "))
sylog.Debugf("Executing FUSE mount command: %q", fuseCmdLine)
execCmd := exec.Command(fuseMountCmd, args...)
execCmd := exec.CommandContext(ctx, fuseMountCmd, args...)
execCmd.Stderr = os.Stderr
_, err = execCmd.Output()
if err != nil {
Expand Down Expand Up @@ -142,6 +147,7 @@ func (i *ImageMount) generateCmdArgs() ([]string, error) {
if i.AllowOther {
opts = append(opts, "allow_other")
}
opts = append(opts, i.ExtraMountOpts...)

if len(opts) > 0 {
args = append(args, "-o", strings.Join(opts, ","))
Expand All @@ -161,21 +167,21 @@ func (i *ImageMount) SetMountPoint(mountpoint string) {
i.mountpoint = mountpoint
}

func (i ImageMount) Unmount() error {
return UnmountWithFuse(i.GetMountPoint())
func (i ImageMount) Unmount(ctx context.Context) error {
return UnmountWithFuse(ctx, i.GetMountPoint())
}

// UnmountWithFuse performs an unmount on the specified directory using
// fusermount -u.
func UnmountWithFuse(dir string) error {
func UnmountWithFuse(ctx context.Context, dir string) error {
fusermountCmd, err := bin.FindBin("fusermount")
if err != nil {
// We should not be creating FUSE-based mounts in the first place
// without checking that fusermount is available.
return fmt.Errorf("fusermount not available while trying to perform unmount: %w", err)
}
sylog.Debugf("Executing FUSE unmount command: %s -u %s", fusermountCmd, dir)
execCmd := exec.Command(fusermountCmd, "-u", dir)
execCmd := exec.CommandContext(ctx, fusermountCmd, "-u", dir)
execCmd.Stderr = os.Stderr
_, err = execCmd.Output()
return err
Expand Down
23 changes: 12 additions & 11 deletions internal/pkg/util/fs/overlay/overlay_item_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package overlay

import (
"context"
"fmt"
"os"
"path/filepath"
Expand Down Expand Up @@ -143,14 +144,14 @@ func (i *Item) GetParentDir() (string, error) {
// Mount performs the necessary steps to mount an individual Item. Note that
// this method does not mount the assembled overlay itself. That happens in
// Set.Mount().
func (i *Item) Mount() error {
func (i *Item) Mount(ctx context.Context) error {
var err error
switch i.Type {
case image.SANDBOX:
err = i.mountDir()

case image.SQUASHFS, image.EXT3:
err = i.mountWithFuse()
err = i.mountWithFuse(ctx)

default:
return fmt.Errorf("internal error: unrecognized image type in overlay.Item.Mount() (type: %v)", i.Type)
Expand Down Expand Up @@ -236,7 +237,7 @@ func (i *Item) mountDir() error {
}

// mountWithFuse mounts an image to a temporary directory
func (i *Item) mountWithFuse() error {
func (i *Item) mountWithFuse(ctx context.Context) error {
parentDir, err := i.GetParentDir()
if err != nil {
return err
Expand All @@ -251,7 +252,7 @@ func (i *Item) mountWithFuse() error {
AllowDev: i.allowDev,
}

if err := im.Mount(); err != nil {
if err := im.Mount(ctx); err != nil {
return err
}

Expand All @@ -263,28 +264,28 @@ func (i *Item) mountWithFuse() error {
// Unmount performs the necessary steps to unmount an individual Item. Note that
// this method does not unmount the overlay itself. That happens in
// Set.Unmount().
func (i Item) Unmount() error {
func (i Item) Unmount(ctx context.Context) error {
switch i.Type {
case image.SANDBOX:
return i.unmountDir()
return i.unmountDir(ctx)

case image.SQUASHFS, image.EXT3:
return i.unmountFuse()
return i.unmountFuse(ctx)

default:
return fmt.Errorf("internal error: unrecognized image type in overlay.Item.Unmount() (type: %v)", i.Type)
}
}

// unmountDir unmounts directory-based Items.
func (i Item) unmountDir() error {
return DetachMount(i.StagingDir)
func (i Item) unmountDir(ctx context.Context) error {
return DetachMount(ctx, i.StagingDir)
}

// unmountFuse unmounts FUSE-based Items.
func (i Item) unmountFuse() error {
func (i Item) unmountFuse(ctx context.Context) error {
defer os.Remove(i.StagingDir)
err := fsfuse.UnmountWithFuse(i.StagingDir)
err := fsfuse.UnmountWithFuse(ctx, i.StagingDir)
if err != nil {
return fmt.Errorf("error while trying to unmount image %q from %s: %w", i.SourcePath, i.StagingDir, err)
}
Expand Down
17 changes: 11 additions & 6 deletions internal/pkg/util/fs/overlay/overlay_item_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package overlay

import (
"context"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -189,6 +190,8 @@ func TestUpperAndWorkCreation(t *testing.T) {
}

func TestDirMounts(t *testing.T) {
ctx := context.Background()

tests := []struct {
name string
olStr string
Expand Down Expand Up @@ -243,13 +246,13 @@ func TestDirMounts(t *testing.T) {
item.SetAllowSetuid(tt.allowSetUID)
item.SetAllowDev(tt.allowDev)

if err := item.Mount(); err != nil {
if err := item.Mount(ctx); err != nil {
t.Fatalf("while trying to mount dir %q: %s", tt.olStr, err)
}

checkMountOpts(t, item.StagingDir, tt.expectMountOpts)

if err := item.Unmount(); err != nil {
if err := item.Unmount(ctx); err != nil {
t.Errorf("while trying to unmount dir %q: %s", tt.olStr, err)
}
})
Expand All @@ -258,6 +261,7 @@ func TestDirMounts(t *testing.T) {

func TestImageRO(t *testing.T) {
require.Command(t, "fusermount")
ctx := context.Background()

tests := []struct {
name string
Expand Down Expand Up @@ -340,11 +344,11 @@ func TestImageRO(t *testing.T) {
t.Errorf("item.Type is %v (should be %v)", item.Type, tt.typeCode)
}

if err := item.Mount(); err != nil {
if err := item.Mount(ctx); err != nil {
t.Fatalf("unable to mount image for reading: %s", err)
}
t.Cleanup(func() {
item.Unmount()
item.Unmount(ctx)
})

testFileStagedPath := filepath.Join(item.GetMountDir(), testFilePath)
Expand All @@ -359,6 +363,7 @@ func TestExtfsRW(t *testing.T) {
require.Command(t, "fuse-overlayfs")
require.Command(t, "fusermount")
tmpDir := mkTempDirOrFatal(t)
ctx := context.Background()

// Create a copy of the extfs test image to be used for testing writable
// extfs image overlays
Expand All @@ -377,11 +382,11 @@ func TestExtfsRW(t *testing.T) {
t.Errorf("item.Type is %v (should be %v)", item.Type, image.EXT3)
}

if err := item.Mount(); err != nil {
if err := item.Mount(ctx); err != nil {
t.Fatalf("unable to mount extfs image for reading & writing: %s", err)
}
t.Cleanup(func() {
item.Unmount()
item.Unmount(ctx)
})

testFileStagedPath := filepath.Join(item.GetMountDir(), testFilePath)
Expand Down
5 changes: 4 additions & 1 deletion internal/pkg/util/fs/overlay/overlay_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package overlay

import (
"context"
"errors"
"fmt"
"os"
Expand Down Expand Up @@ -281,7 +282,9 @@ func DetachAndDelete(overlayDir string) error {
}

// DetachMount performs an unmount system call on the specified directory.
func DetachMount(dir string) error {
//
//nolint:revive,nolintlint
func DetachMount(ctx context.Context, dir string) error {
sylog.Debugf("Calling syscall.Unmount() to detach %q", dir)
if err := syscall.Unmount(dir, syscall.MNT_DETACH); err != nil {
return fmt.Errorf("failed to detach %s: %w", dir, err)
Expand Down
Loading

0 comments on commit 21f2008

Please sign in to comment.