diff --git a/device.go b/device.go index d5e8c53738..98a2c27f88 100644 --- a/device.go +++ b/device.go @@ -31,6 +31,7 @@ const ( driverSCSIType = "scsi" driverNvdimmType = "nvdimm" driverEphemeralType = "ephemeral" + driverLocalType = "local" ) const ( diff --git a/mount.go b/mount.go index 7b74b1f258..c5bd49fac0 100644 --- a/mount.go +++ b/mount.go @@ -11,6 +11,7 @@ import ( "fmt" "os" "path/filepath" + "strconv" "strings" "syscall" @@ -176,6 +177,19 @@ func parseMountFlagsAndOptions(optionList []string) (int, string, error) { return flags, strings.Join(options, ","), nil } +func parseOptions(optionList []string) map[string]string { + options := make(map[string]string) + for _, opt := range optionList { + idx := strings.Index(opt, "=") + if idx < 1 { + continue + } + key, val := opt[:idx], opt[idx+1:] + options[key] = val + } + return options +} + func removeMounts(mounts []string) error { for _, mount := range mounts { if err := syscall.Unmount(mount, 0); err != nil { @@ -198,6 +212,7 @@ var storageHandlerList = map[string]storageHandler{ driverMmioBlkType: virtioMmioBlkStorageHandler, driverSCSIType: virtioSCSIStorageHandler, driverEphemeralType: ephemeralStorageHandler, + driverLocalType: localStorageHandler, } func ephemeralStorageHandler(storage pb.Storage, s *sandbox) (string, error) { @@ -215,6 +230,29 @@ func ephemeralStorageHandler(storage pb.Storage, s *sandbox) (string, error) { return "", nil } +func localStorageHandler(storage pb.Storage, s *sandbox) (string, error) { + s.Lock() + defer s.Unlock() + newStorage := s.setSandboxStorage(storage.MountPoint) + if newStorage { + + // Extract and parse the mode out of the storage options. + // Default to os.ModePerm. + opts := parseOptions(storage.Options) + mode := os.ModePerm + if val, ok := opts["mode"]; ok { + m, err := strconv.ParseUint(val, 8, 32) + if err != nil { + return "", err + } + mode = os.FileMode(m) + } + + return "", os.MkdirAll(storage.MountPoint, mode) + } + return "", nil +} + // virtio9pStorageHandler handles the storage for 9p driver. func virtio9pStorageHandler(storage pb.Storage, s *sandbox) (string, error) { return commonStorageHandler(storage) diff --git a/mount_test.go b/mount_test.go index db66a3bece..2d6894f66b 100644 --- a/mount_test.go +++ b/mount_test.go @@ -48,6 +48,66 @@ func TestEphemeralStorageHandlerSuccessful(t *testing.T) { assert.Nil(t, err, "ephemeralStorageHandler() failed: %v", err) } +func TestLocalStorageHandlerSuccessful(t *testing.T) { + skipUnlessRoot(t) + + storage, err := createSafeAndFakeStorage() + if err != nil { + t.Fatal(err) + } + defer syscall.Unmount(storage.MountPoint, 0) + defer os.RemoveAll(storage.MountPoint) + + sbs := make(map[string]*sandboxStorage) + _, err = localStorageHandler(storage, &sandbox{storages: sbs}) + assert.Nil(t, err, "localStorageHandler() failed: %v", err) +} + +func TestLocalStorageHandlerPermModeSuccessful(t *testing.T) { + skipUnlessRoot(t) + + storage, err := createSafeAndFakeStorage() + if err != nil { + t.Fatal(err) + } + defer syscall.Unmount(storage.MountPoint, 0) + defer os.RemoveAll(storage.MountPoint) + + // Set the mode to be 0400 (ready only) + storage.Options = []string{ + "mode=0400", + } + + sbs := make(map[string]*sandboxStorage) + _, err = localStorageHandler(storage, &sandbox{storages: sbs}) + assert.Nil(t, err, "localStorageHandler() failed: %v", err) + + // Check the mode of the mountpoint + info, err := os.Stat(storage.MountPoint) + assert.Nil(t, err) + assert.Equal(t, 0400|os.ModeDir, info.Mode()) +} + +func TestLocalStorageHandlerPermModeFailure(t *testing.T) { + skipUnlessRoot(t) + + storage, err := createSafeAndFakeStorage() + if err != nil { + t.Fatal(err) + } + //defer syscall.Unmount(storage.MountPoint, 0) + //defer os.RemoveAll(storage.MountPoint) + + // Set the mode to something invalid + storage.Options = []string{ + "mode=abcde", + } + + sbs := make(map[string]*sandboxStorage) + _, err = localStorageHandler(storage, &sandbox{storages: sbs}) + assert.NotNil(t, err, "localStorageHandler() should have failed") +} + func TestVirtio9pStorageHandlerSuccessful(t *testing.T) { skipUnlessRoot(t)