Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: expose MountFUSE / UnmountFUSE API #209

Merged
merged 1 commit into from
Apr 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 4 additions & 4 deletions internal/app/siftool/mount.go
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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