Skip to content

Commit

Permalink
Merge pull request #209 from dtrudg/issue206
Browse files Browse the repository at this point in the history
feat: expose MountFUSE / UnmountFUSE API
  • Loading branch information
tri-adam committed Apr 22, 2022
2 parents 3e8948f + 1ab2364 commit fd71e8a
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 65 deletions.
8 changes: 4 additions & 4 deletions internal/app/siftool/mount.go
Expand Up @@ -8,13 +8,13 @@ package siftool
import (
"context"

"github.com/sylabs/sif/v2/internal/pkg/exp"
"github.com/sylabs/sif/v2/pkg/sif"
)

// Mount mounts the primary system partition of the SIF file at path into mountPath.
func (a *App) Mount(ctx context.Context, path, mountPath string) error {
return exp.Mount(ctx, path, mountPath,
exp.OptMountStdout(a.opts.out),
exp.OptMountStderr(a.opts.err),
return sif.MountFUSE(ctx, path, mountPath,
sif.OptMountFUSEStdout(a.opts.out),
sif.OptMountFUSEStderr(a.opts.err),
)
}
8 changes: 4 additions & 4 deletions internal/app/siftool/unmount.go
Expand Up @@ -8,13 +8,13 @@ package siftool
import (
"context"

"github.com/sylabs/sif/v2/internal/pkg/exp"
"github.com/sylabs/sif/v2/pkg/sif"
)

// Unmounts the FUSE mounted filesystem at mountPath.
func (a *App) Unmount(ctx context.Context, mountPath string) error {
return exp.Unmount(ctx, mountPath,
exp.OptUnmountStdout(a.opts.out),
exp.OptUnmountStderr(a.opts.err),
return sif.UnmountFUSE(ctx, mountPath,
sif.OptUnmountFUSEStdout(a.opts.out),
sif.OptUnmountFUSEStderr(a.opts.err),
)
}
48 changes: 22 additions & 26 deletions internal/pkg/exp/mount.go → pkg/sif/mount.go
Expand Up @@ -3,9 +3,7 @@
// LICENSE file distributed with the sources of this project regarding your
// rights to use or distribute this software.

// Package exp contains experimental functionality that is not sufficiently mature to be exported
// as part of the module API.
package exp
package sif

import (
"context"
Expand All @@ -15,12 +13,10 @@ import (
"os"
"os/exec"
"path/filepath"

"github.com/sylabs/sif/v2/pkg/sif"
)

// mountSquashFS mounts the SquashFS filesystem from path at offset into mountPath.
func mountSquashFS(ctx context.Context, offset int64, path, mountPath string, mo mountOpts) error {
func mountSquashFS(ctx context.Context, offset int64, path, mountPath string, mo mountFUSEOpts) error {
args := []string{
"-o", fmt.Sprintf("ro,offset=%d", offset),
filepath.Clean(path),
Expand All @@ -38,38 +34,38 @@ func mountSquashFS(ctx context.Context, offset int64, path, mountPath string, mo
return nil
}

// mountOpts accumulates mount options.
type mountOpts struct {
// mountFUSEOpts accumulates mount options.
type mountFUSEOpts struct {
stdout io.Writer
stderr io.Writer
squashfusePath string
}

// MountOpt are used to specify mount options.
type MountOpt func(*mountOpts) error
// MountFUSEOpt are used to specify mount options.
type MountFUSEOpt func(*mountFUSEOpts) error

// OptMountStdout writes standard output to w.
func OptMountStdout(w io.Writer) MountOpt {
return func(mo *mountOpts) error {
func OptMountFUSEStdout(w io.Writer) MountFUSEOpt {
return func(mo *mountFUSEOpts) error {
mo.stdout = w
return nil
}
}

// OptMountStderr writes standard error to w.
func OptMountStderr(w io.Writer) MountOpt {
return func(mo *mountOpts) error {
// OptMountFUSEStderr writes standard error to w.
func OptMountFUSEStderr(w io.Writer) MountFUSEOpt {
return func(mo *mountFUSEOpts) error {
mo.stderr = w
return nil
}
}

var errSquashfusePathInvalid = errors.New("squashfuse path must be relative or absolute")

// OptMountSquashfusePath sets an explicit path to the squashfuse binary. The path must be an
// OptMountFUSESquashfusePath sets an explicit path to the squashfuse binary. The path must be an
// absolute or relative path.
func OptMountSquashfusePath(path string) MountOpt {
return func(mo *mountOpts) error {
func OptMountFUSESquashfusePath(path string) MountFUSEOpt {
return func(mo *mountFUSEOpts) error {
if filepath.Base(path) == path {
return errSquashfusePathInvalid
}
Expand All @@ -80,16 +76,16 @@ func OptMountSquashfusePath(path string) MountOpt {

var errUnsupportedFSType = errors.New("unrecognized filesystem type")

// Mount mounts the primary system partition of the SIF file at path into mountPath.
// MountFUSE mounts the primary system partition of the SIF file at path into mountPath.
//
// Mount may start one or more underlying processes. By default, stdout and stderr of these
// MountFUSE may start one or more underlying processes. By default, stdout and stderr of these
// processes is discarded. To modify this behavior, consider using OptMountStdout and/or
// OptMountStderr.
//
// By default, Mount searches for a squashfuse binary in the directories named by the PATH
// By default, MountFUSE searches for a squashfuse binary in the directories named by the PATH
// environment variable. To override this behavior, consider using OptMountSquashfusePath().
func Mount(ctx context.Context, path, mountPath string, opts ...MountOpt) error {
mo := mountOpts{
func MountFUSE(ctx context.Context, path, mountPath string, opts ...MountFUSEOpt) error {
mo := mountFUSEOpts{
squashfusePath: "squashfuse",
}

Expand All @@ -99,13 +95,13 @@ func Mount(ctx context.Context, path, mountPath string, opts ...MountOpt) error
}
}

f, err := sif.LoadContainerFromPath(path, sif.OptLoadWithFlag(os.O_RDONLY))
f, err := LoadContainerFromPath(path, OptLoadWithFlag(os.O_RDONLY))
if err != nil {
return fmt.Errorf("failed to load image: %w", err)
}
defer func() { _ = f.UnloadContainer() }()

d, err := f.GetDescriptor(sif.WithPartitionType(sif.PartPrimSys))
d, err := f.GetDescriptor(WithPartitionType(PartPrimSys))
if err != nil {
return fmt.Errorf("failed to get partition descriptor: %w", err)
}
Expand All @@ -116,7 +112,7 @@ func Mount(ctx context.Context, path, mountPath string, opts ...MountOpt) error
}

switch fs {
case sif.FsSquash:
case FsSquash:
return mountSquashFS(ctx, d.Offset(), path, mountPath, mo)
default:
return errUnsupportedFSType
Expand Down
40 changes: 20 additions & 20 deletions internal/pkg/exp/unmount.go → pkg/sif/unmount.go
Expand Up @@ -3,7 +3,7 @@
// LICENSE file distributed with the sources of this project regarding your
// rights to use or distribute this software.

package exp
package sif

import (
"context"
Expand All @@ -15,7 +15,7 @@ import (
)

// unmountSquashFS unmounts the filesystem at mountPath.
func unmountSquashFS(ctx context.Context, mountPath string, uo unmountOpts) error {
func unmountSquashFS(ctx context.Context, mountPath string, uo unmountFUSEOpts) error {
args := []string{
"-u",
filepath.Clean(mountPath),
Expand All @@ -31,37 +31,37 @@ func unmountSquashFS(ctx context.Context, mountPath string, uo unmountOpts) erro
return nil
}

// unmountOpts accumulates unmount options.
type unmountOpts struct {
// unmountFUSEOpts accumulates unmount options.
type unmountFUSEOpts struct {
stdout io.Writer
stderr io.Writer
fusermountPath string
}

// UnmountOpt are used to specify unmount options.
type UnmountOpt func(*unmountOpts) error
// UnmountFUSEOpt are used to specify unmount options.
type UnmountFUSEOpt func(*unmountFUSEOpts) error

// OptUnmountStdout writes standard output to w.
func OptUnmountStdout(w io.Writer) UnmountOpt {
return func(mo *unmountOpts) error {
// OptUnmountFUSEStdout writes standard output to w.
func OptUnmountFUSEStdout(w io.Writer) UnmountFUSEOpt {
return func(mo *unmountFUSEOpts) error {
mo.stdout = w
return nil
}
}

// OptUnmountStderr writes standard error to w.
func OptUnmountStderr(w io.Writer) UnmountOpt {
return func(mo *unmountOpts) error {
// OptUnmountFUSEStderr writes standard error to w.
func OptUnmountFUSEStderr(w io.Writer) UnmountFUSEOpt {
return func(mo *unmountFUSEOpts) error {
mo.stderr = w
return nil
}
}

var errFusermountPathInvalid = errors.New("fusermount path must be relative or absolute")

// OptUnmountFusermountPath sets the path to the fusermount binary.
func OptUnmountFusermountPath(path string) UnmountOpt {
return func(mo *unmountOpts) error {
// OptUnmountFUSEFusermountPath sets the path to the fusermount binary.
func OptUnmountFUSEFusermountPath(path string) UnmountFUSEOpt {
return func(mo *unmountFUSEOpts) error {
if filepath.Base(path) == path {
return errFusermountPathInvalid
}
Expand All @@ -70,16 +70,16 @@ func OptUnmountFusermountPath(path string) UnmountOpt {
}
}

// Unmount the FUSE mounted filesystem at mountPath.
// UnmountFUSE unmounts the FUSE mounted filesystem at mountPath.
//
// Unmount may start one or more underlying processes. By default, stdout and stderr of these
// UnmountFUSE may start one or more underlying processes. By default, stdout and stderr of these
// processes is discarded. To modify this behavior, consider using OptUnmountStdout and/or
// OptUnmountStderr.
//
// By default, Unmount searches for a fusermount binary in the directories named by the PATH
// By default, UnmountFUSE searches for a fusermount binary in the directories named by the PATH
// environment variable. To override this behavior, consider using OptUnmountFusermountPath().
func Unmount(ctx context.Context, mountPath string, opts ...UnmountOpt) error {
uo := unmountOpts{
func UnmountFUSE(ctx context.Context, mountPath string, opts ...UnmountFUSEOpt) error {
uo := unmountFUSEOpts{
fusermountPath: "fusermount",
}

Expand Down
16 changes: 7 additions & 9 deletions internal/pkg/exp/unmount_test.go → pkg/sif/unmount_test.go
Expand Up @@ -3,7 +3,7 @@
// LICENSE file distributed with the sources of this project regarding your
// rights to use or distribute this software.

package exp
package sif

import (
"bufio"
Expand All @@ -17,9 +17,7 @@ import (
"testing"
)

var corpus = filepath.Join("..", "..", "..", "test", "images")

func Test_Unmount(t *testing.T) {
func Test_UnmountFUSE(t *testing.T) {
if _, err := exec.LookPath("squashfuse"); err != nil {
t.Skip(" not found, skipping mount tests")
}
Expand All @@ -40,7 +38,7 @@ func Test_Unmount(t *testing.T) {
name string
mountSIF string
mountPath string
opts []UnmountOpt
opts []UnmountFUSEOpt
wantErr bool
wantUnmounted bool
}{
Expand All @@ -67,28 +65,28 @@ func Test_Unmount(t *testing.T) {
name: "FusermountBare",
mountSIF: "",
mountPath: path,
opts: []UnmountOpt{OptUnmountFusermountPath("fusermount")},
opts: []UnmountFUSEOpt{OptUnmountFUSEFusermountPath("fusermount")},
wantErr: true,
},
{
name: "FusermountValid",
mountSIF: filepath.Join(corpus, "one-group.sif"),
mountPath: path,
opts: []UnmountOpt{OptUnmountFusermountPath(fusermountPath)},
opts: []UnmountFUSEOpt{OptUnmountFUSEFusermountPath(fusermountPath)},
wantErr: false,
wantUnmounted: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.mountSIF != "" {
err := Mount(context.Background(), tt.mountSIF, path)
err := MountFUSE(context.Background(), tt.mountSIF, path)
if err != nil {
t.Fatal(err)
}
}

err := Unmount(context.Background(), tt.mountPath, tt.opts...)
err := UnmountFUSE(context.Background(), tt.mountPath, tt.opts...)

if err != nil && !tt.wantErr {
t.Errorf("Unexpected error: %s", err)
Expand Down
4 changes: 2 additions & 2 deletions pkg/siftool/unmount_test.go
Expand Up @@ -12,7 +12,7 @@ import (
"path/filepath"
"testing"

"github.com/sylabs/sif/v2/internal/pkg/exp"
"github.com/sylabs/sif/v2/pkg/sif"
)

func Test_command_getUnmount(t *testing.T) {
Expand All @@ -32,7 +32,7 @@ func Test_command_getUnmount(t *testing.T) {
})

testSIF := filepath.Join(corpus, "one-group.sif")
if err := exp.Mount(context.Background(), testSIF, path); err != nil {
if err := sif.MountFUSE(context.Background(), testSIF, path); err != nil {
t.Fatal(err)
}

Expand Down

0 comments on commit fd71e8a

Please sign in to comment.