[lxc-devel] [lxd/master] Storage cleanup preparation
monstermunchkin on Github
lxc-bot at linuxcontainers.org
Thu Aug 15 13:18:36 UTC 2019
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 311 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20190815/540d3f7f/attachment-0001.bin>
-------------- next part --------------
From 8455cc8273c0a62c3d381ae7c7c0ce1f72f40521 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Thu, 2 May 2019 15:04:28 +0200
Subject: [PATCH 1/4] lxd: Move storage cgo to storage package
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
lxd/{ => storage}/storage_cgo.go | 16 +++++++++-------
lxd/storage_btrfs.go | 3 ++-
lxd/storage_lvm.go | 7 ++++---
3 files changed, 15 insertions(+), 11 deletions(-)
rename lxd/{ => storage}/storage_cgo.go (93%)
diff --git a/lxd/storage_cgo.go b/lxd/storage/storage_cgo.go
similarity index 93%
rename from lxd/storage_cgo.go
rename to lxd/storage/storage_cgo.go
index 7edba24f92..437e67ef1b 100644
--- a/lxd/storage_cgo.go
+++ b/lxd/storage/storage_cgo.go
@@ -1,7 +1,7 @@
// +build linux
// +build cgo
-package main
+package storage
/*
#define _GNU_SOURCE
@@ -19,8 +19,8 @@ package main
#include <sys/stat.h>
#include <sys/types.h>
-#include "include/macro.h"
-#include "include/memory_utils.h"
+#include "../include/macro.h"
+#include "../include/memory_utils.h"
#define LXD_MAXPATH 4096
#define LXD_NUMSTRLEN64 21
@@ -256,10 +256,10 @@ import (
// close.
const LoFlagsAutoclear int = C.LO_FLAGS_AUTOCLEAR
-// prepareLoopDev() detects and sets up a loop device for source. It returns an
+// PrepareLoopDev detects and sets up a loop device for source. It returns an
// open file descriptor to the free loop device and the path of the free loop
// device. It's the callers responsibility to close the open file descriptor.
-func prepareLoopDev(source string, flags int) (*os.File, error) {
+func PrepareLoopDev(source string, flags int) (*os.File, error) {
cLoopDev := C.malloc(C.size_t(C.LO_NAME_SIZE))
if cLoopDev == nil {
return nil, fmt.Errorf("Failed to allocate memory in C")
@@ -285,7 +285,8 @@ func prepareLoopDev(source string, flags int) (*os.File, error) {
return os.NewFile(uintptr(loopFd), C.GoString((*C.char)(cLoopDev))), nil
}
-func setAutoclearOnLoopDev(loopFd int) error {
+// SetAutoclearOnLoopDev enables autodestruction of the provided loopback device.
+func SetAutoclearOnLoopDev(loopFd int) error {
ret, err := C.set_autoclear_loop_device(C.int(loopFd))
if ret < 0 {
if err != nil {
@@ -297,7 +298,8 @@ func setAutoclearOnLoopDev(loopFd int) error {
return nil
}
-func unsetAutoclearOnLoopDev(loopFd int) error {
+// UnsetAutoclearOnLoopDev disables autodestruction of the provided loopback device.
+func UnsetAutoclearOnLoopDev(loopFd int) error {
ret, err := C.unset_autoclear_loop_device(C.int(loopFd))
if ret < 0 {
if err != nil {
diff --git a/lxd/storage_btrfs.go b/lxd/storage_btrfs.go
index 043b2f7aad..66d541a9ab 100644
--- a/lxd/storage_btrfs.go
+++ b/lxd/storage_btrfs.go
@@ -19,6 +19,7 @@ import (
"github.com/lxc/lxd/lxd/migration"
"github.com/lxc/lxd/lxd/project"
"github.com/lxc/lxd/lxd/state"
+ driver "github.com/lxc/lxd/lxd/storage"
"github.com/lxc/lxd/lxd/util"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
@@ -422,7 +423,7 @@ func (s *storageBtrfs) StoragePoolMount() (bool, error) {
// Since we mount the loop device LO_FLAGS_AUTOCLEAR is
// fine since the loop device will be kept around for as
// long as the mount exists.
- loopF, loopErr := prepareLoopDev(source, LoFlagsAutoclear)
+ loopF, loopErr := driver.PrepareLoopDev(source, driver.LoFlagsAutoclear)
if loopErr != nil {
return false, loopErr
}
diff --git a/lxd/storage_lvm.go b/lxd/storage_lvm.go
index d805035435..97ece383c6 100644
--- a/lxd/storage_lvm.go
+++ b/lxd/storage_lvm.go
@@ -15,6 +15,7 @@ import (
"github.com/lxc/lxd/lxd/migration"
"github.com/lxc/lxd/lxd/project"
+ driver "github.com/lxc/lxd/lxd/storage"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
"github.com/lxc/lxd/shared/ioprogress"
@@ -387,7 +388,7 @@ func (s *storageLvm) StoragePoolDelete() error {
if s.loopInfo != nil {
// Set LO_FLAGS_AUTOCLEAR before we remove the loop file
// otherwise we will get EBADF.
- err = setAutoclearOnLoopDev(int(s.loopInfo.Fd()))
+ err = driver.SetAutoclearOnLoopDev(int(s.loopInfo.Fd()))
if err != nil {
logger.Warnf("Failed to set LO_FLAGS_AUTOCLEAR on loop device: %s, manual cleanup needed", err)
}
@@ -459,12 +460,12 @@ func (s *storageLvm) StoragePoolMount() (bool, error) {
if filepath.IsAbs(source) && !shared.IsBlockdevPath(source) {
// Try to prepare new loop device.
- loopF, loopErr := prepareLoopDev(source, 0)
+ loopF, loopErr := driver.PrepareLoopDev(source, 0)
if loopErr != nil {
return false, loopErr
}
// Make sure that LO_FLAGS_AUTOCLEAR is unset.
- loopErr = unsetAutoclearOnLoopDev(int(loopF.Fd()))
+ loopErr = driver.UnsetAutoclearOnLoopDev(int(loopF.Fd()))
if loopErr != nil {
return false, loopErr
}
From 3faeabb253bcbf28b08198c7a9e4508414ea69b8 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Tue, 13 Aug 2019 15:04:10 +0200
Subject: [PATCH 2/4] lxd: Move ContainerPath() to storage package
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
lxd/api_internal.go | 10 +++++-----
lxd/container.go | 8 --------
lxd/container_lxc.go | 3 ++-
lxd/container_test.go | 4 ++--
lxd/storage/storage.go | 12 ++++++++++++
lxd/storage_dir.go | 3 ++-
lxd/storage_zfs.go | 3 ++-
7 files changed, 25 insertions(+), 18 deletions(-)
create mode 100644 lxd/storage/storage.go
diff --git a/lxd/api_internal.go b/lxd/api_internal.go
index fee4d9ebfa..babac2c8d6 100644
--- a/lxd/api_internal.go
+++ b/lxd/api_internal.go
@@ -9,6 +9,7 @@ import (
"os"
"path/filepath"
"runtime"
+ runtimeDebug "runtime/debug"
"strconv"
"strings"
@@ -21,13 +22,12 @@ import (
"github.com/lxc/lxd/lxd/db/node"
"github.com/lxc/lxd/lxd/db/query"
"github.com/lxc/lxd/lxd/project"
+ driver "github.com/lxc/lxd/lxd/storage"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
+ log "github.com/lxc/lxd/shared/log15"
"github.com/lxc/lxd/shared/logger"
"github.com/lxc/lxd/shared/osarch"
-
- log "github.com/lxc/lxd/shared/log15"
- runtimeDebug "runtime/debug"
)
var apiInternal = []APIEndpoint{
@@ -680,7 +680,7 @@ func internalImport(d *Daemon, r *http.Request) Response {
onDiskPoolName = poolName
}
snapName := fmt.Sprintf("%s/%s", req.Name, od)
- snapPath := containerPath(snapName, true)
+ snapPath := driver.ContainerPath(snapName, true)
err = lvmContainerDeleteInternal(projectName, poolName, req.Name,
true, onDiskPoolName, snapPath)
case "ceph":
@@ -1022,7 +1022,7 @@ func internalImport(d *Daemon, r *http.Request) Response {
return SmartError(err)
}
- containerPath := containerPath(project.Prefix(projectName, req.Name), false)
+ containerPath := driver.ContainerPath(project.Prefix(projectName, req.Name), false)
isPrivileged := false
if backup.Container.Config["security.privileged"] == "" {
isPrivileged = true
diff --git a/lxd/container.go b/lxd/container.go
index 5b795f3d55..f01f2bc58d 100644
--- a/lxd/container.go
+++ b/lxd/container.go
@@ -75,14 +75,6 @@ func containerGetParentAndSnapshotName(name string) (string, string, bool) {
return fields[0], fields[1], true
}
-func containerPath(name string, isSnapshot bool) string {
- if isSnapshot {
- return shared.VarPath("snapshots", name)
- }
-
- return shared.VarPath("containers", name)
-}
-
func containerValidName(name string) error {
if strings.Contains(name, shared.SnapshotDelimiter) {
return fmt.Errorf(
diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index 6a97f78242..95400bdb39 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -35,6 +35,7 @@ import (
"github.com/lxc/lxd/lxd/maas"
"github.com/lxc/lxd/lxd/project"
"github.com/lxc/lxd/lxd/state"
+ driver "github.com/lxc/lxd/lxd/storage"
"github.com/lxc/lxd/lxd/template"
"github.com/lxc/lxd/lxd/util"
"github.com/lxc/lxd/shared"
@@ -7858,7 +7859,7 @@ func (c *containerLXC) State() string {
// Various container paths
func (c *containerLXC) Path() string {
name := project.Prefix(c.Project(), c.Name())
- return containerPath(name, c.IsSnapshot())
+ return driver.ContainerPath(name, c.IsSnapshot())
}
func (c *containerLXC) DevicesPath() string {
diff --git a/lxd/container_test.go b/lxd/container_test.go
index 4bbebde328..6b0d946f1c 100644
--- a/lxd/container_test.go
+++ b/lxd/container_test.go
@@ -163,7 +163,7 @@ func (suite *containerTestSuite) TestContainer_Path_Regular() {
suite.Req.False(c.IsSnapshot(), "Shouldn't be a snapshot.")
suite.Req.Equal(shared.VarPath("containers", "testFoo"), c.Path())
- suite.Req.Equal(shared.VarPath("containers", "testFoo2"), containerPath("testFoo2", false))
+ suite.Req.Equal(shared.VarPath("containers", "testFoo2"), driver.ContainerPath("testFoo2", false))
}
func (suite *containerTestSuite) TestContainer_Path_Snapshot() {
@@ -184,7 +184,7 @@ func (suite *containerTestSuite) TestContainer_Path_Snapshot() {
c.Path())
suite.Req.Equal(
shared.VarPath("snapshots", "test", "snap1"),
- containerPath("test/snap1", true))
+ driver.ContainerPath("test/snap1", true))
}
func (suite *containerTestSuite) TestContainer_LogPath() {
diff --git a/lxd/storage/storage.go b/lxd/storage/storage.go
new file mode 100644
index 0000000000..7d378ef50c
--- /dev/null
+++ b/lxd/storage/storage.go
@@ -0,0 +1,12 @@
+package storage
+
+import "github.com/lxc/lxd/shared"
+
+// ContainerPath returns the directory of a container or snapshot.
+func ContainerPath(name string, isSnapshot bool) string {
+ if isSnapshot {
+ return shared.VarPath("snapshots", name)
+ }
+
+ return shared.VarPath("containers", name)
+}
diff --git a/lxd/storage_dir.go b/lxd/storage_dir.go
index 967a4656f1..46482a01aa 100644
--- a/lxd/storage_dir.go
+++ b/lxd/storage_dir.go
@@ -14,6 +14,7 @@ import (
"github.com/lxc/lxd/lxd/migration"
"github.com/lxc/lxd/lxd/project"
+ driver "github.com/lxc/lxd/lxd/storage"
"github.com/lxc/lxd/lxd/storage/quota"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
@@ -1221,7 +1222,7 @@ func (s *storageDir) ContainerBackupLoad(info backupInfo, data io.ReadSeeker, ta
// Create mountpoints
containerMntPoint := getContainerMountPoint(info.Project, s.pool.Name, info.Name)
- err = createContainerMountpoint(containerMntPoint, containerPath(project.Prefix(info.Project, info.Name), false), info.Privileged)
+ err = createContainerMountpoint(containerMntPoint, driver.ContainerPath(project.Prefix(info.Project, info.Name), false), info.Privileged)
if err != nil {
return errors.Wrap(err, "Create container mount point")
}
diff --git a/lxd/storage_zfs.go b/lxd/storage_zfs.go
index 5d9500b9b8..d98f530956 100644
--- a/lxd/storage_zfs.go
+++ b/lxd/storage_zfs.go
@@ -16,6 +16,7 @@ import (
"github.com/lxc/lxd/lxd/migration"
"github.com/lxc/lxd/lxd/project"
+ driver "github.com/lxc/lxd/lxd/storage"
"github.com/lxc/lxd/lxd/util"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
@@ -2131,7 +2132,7 @@ func (s *storageZfs) ContainerBackupCreate(backup backup, source container) erro
func (s *storageZfs) doContainerBackupLoadOptimized(info backupInfo, data io.ReadSeeker, tarArgs []string) error {
containerName, _, _ := containerGetParentAndSnapshotName(info.Name)
containerMntPoint := getContainerMountPoint(info.Project, s.pool.Name, containerName)
- err := createContainerMountpoint(containerMntPoint, containerPath(info.Name, false), info.Privileged)
+ err := createContainerMountpoint(containerMntPoint, driver.ContainerPath(info.Name, false), info.Privileged)
if err != nil {
return err
}
From b2405f5831ae5694f742d2f3177a6e3c55218355 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Thu, 15 Aug 2019 12:16:59 +0200
Subject: [PATCH 3/4] lxd: Move storage_utils to storage/utils
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
lxd/container_test.go | 4 +-
lxd/patches.go | 18 +-
lxd/storage/utils.go | 362 ++++++++++++++++++++++++++++++++
lxd/storage_btrfs.go | 36 ++--
lxd/storage_ceph.go | 31 +--
lxd/storage_ceph_utils.go | 21 +-
lxd/storage_cephfs.go | 15 +-
lxd/storage_dir.go | 2 +-
lxd/storage_lvm.go | 34 +--
lxd/storage_lvm_utils.go | 9 +-
lxd/storage_pools_utils.go | 13 +-
lxd/storage_utils.go | 339 +-----------------------------
lxd/storage_volumes_snapshot.go | 3 +-
lxd/storage_zfs.go | 30 +--
lxd/storage_zfs_utils.go | 5 +-
15 files changed, 480 insertions(+), 442 deletions(-)
create mode 100644 lxd/storage/utils.go
diff --git a/lxd/container_test.go b/lxd/container_test.go
index 6b0d946f1c..d6698cbd16 100644
--- a/lxd/container_test.go
+++ b/lxd/container_test.go
@@ -4,12 +4,14 @@ import (
"fmt"
"testing"
+ "github.com/stretchr/testify/suite"
+
"github.com/lxc/lxd/lxd/db"
"github.com/lxc/lxd/lxd/device/config"
+ driver "github.com/lxc/lxd/lxd/storage"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
"github.com/lxc/lxd/shared/idmap"
- "github.com/stretchr/testify/suite"
)
type containerTestSuite struct {
diff --git a/lxd/patches.go b/lxd/patches.go
index f6023eab95..b876b590de 100644
--- a/lxd/patches.go
+++ b/lxd/patches.go
@@ -10,14 +10,16 @@ import (
"strings"
"syscall"
+ "github.com/pkg/errors"
+ "golang.org/x/sys/unix"
+
"github.com/lxc/lxd/lxd/cluster"
"github.com/lxc/lxd/lxd/db"
"github.com/lxc/lxd/lxd/db/query"
+ driver "github.com/lxc/lxd/lxd/storage"
"github.com/lxc/lxd/shared"
log "github.com/lxc/lxd/shared/log15"
"github.com/lxc/lxd/shared/logger"
- "github.com/pkg/errors"
- "golang.org/x/sys/unix"
)
/* Patches are one-time actions that are sometimes needed to update
@@ -1088,7 +1090,7 @@ func upgradeFromStorageTypeLvm(name string, d *Daemon, defaultPoolName string, d
// Unmount the logical volume.
oldContainerMntPoint := shared.VarPath("containers", ct)
if shared.IsMountPoint(oldContainerMntPoint) {
- err := tryUnmount(oldContainerMntPoint, unix.MNT_DETACH)
+ err := driver.TryUnmount(oldContainerMntPoint, unix.MNT_DETACH)
if err != nil {
logger.Errorf("Failed to unmount LVM logical volume \"%s\": %s", oldContainerMntPoint, err)
return err
@@ -1263,7 +1265,7 @@ func upgradeFromStorageTypeLvm(name string, d *Daemon, defaultPoolName string, d
if shared.PathExists(oldLvDevPath) {
// Unmount the logical volume.
if shared.IsMountPoint(oldSnapshotMntPoint) {
- err := tryUnmount(oldSnapshotMntPoint, unix.MNT_DETACH)
+ err := driver.TryUnmount(oldSnapshotMntPoint, unix.MNT_DETACH)
if err != nil {
logger.Errorf("Failed to unmount LVM logical volume \"%s\": %s", oldSnapshotMntPoint, err)
return err
@@ -1366,7 +1368,7 @@ func upgradeFromStorageTypeLvm(name string, d *Daemon, defaultPoolName string, d
}
if !shared.IsMountPoint(newContainerMntPoint) {
- err := tryMount(containerLvDevPath, newContainerMntPoint, lvFsType, 0, mountOptions)
+ err := driver.TryMount(containerLvDevPath, newContainerMntPoint, lvFsType, 0, mountOptions)
if err != nil {
logger.Errorf("Failed to mount LVM logical \"%s\" onto \"%s\" : %s", containerLvDevPath, newContainerMntPoint, err)
return err
@@ -1414,7 +1416,7 @@ func upgradeFromStorageTypeLvm(name string, d *Daemon, defaultPoolName string, d
// Unmount the logical volume.
oldImageMntPoint := shared.VarPath("images", img+".lv")
if shared.IsMountPoint(oldImageMntPoint) {
- err := tryUnmount(oldImageMntPoint, unix.MNT_DETACH)
+ err := driver.TryUnmount(oldImageMntPoint, unix.MNT_DETACH)
if err != nil {
return err
}
@@ -1614,7 +1616,7 @@ func upgradeFromStorageTypeZfs(name string, d *Daemon, defaultPoolName string, d
_, err := shared.TryRunCommand("zfs", "unmount", "-f", ctDataset)
if err != nil {
logger.Warnf("Failed to unmount ZFS filesystem via zfs unmount, trying lazy umount (MNT_DETACH)...")
- err := tryUnmount(oldContainerMntPoint, unix.MNT_DETACH)
+ err := driver.TryUnmount(oldContainerMntPoint, unix.MNT_DETACH)
if err != nil {
failedUpgradeEntities = append(failedUpgradeEntities, fmt.Sprintf("containers/%s: Failed to umount zfs filesystem.", ct))
continue
@@ -1762,7 +1764,7 @@ func upgradeFromStorageTypeZfs(name string, d *Daemon, defaultPoolName string, d
_, err := shared.TryRunCommand("zfs", "unmount", "-f", imageDataset)
if err != nil {
logger.Warnf("Failed to unmount ZFS filesystem via zfs unmount, trying lazy umount (MNT_DETACH)...")
- err := tryUnmount(oldImageMntPoint, unix.MNT_DETACH)
+ err := driver.TryUnmount(oldImageMntPoint, unix.MNT_DETACH)
if err != nil {
logger.Warnf("Failed to unmount ZFS filesystem: %s", err)
}
diff --git a/lxd/storage/utils.go b/lxd/storage/utils.go
new file mode 100644
index 0000000000..d23d4f4171
--- /dev/null
+++ b/lxd/storage/utils.go
@@ -0,0 +1,362 @@
+package storage
+
+import (
+ "fmt"
+ "os"
+ "strings"
+ "time"
+
+ "golang.org/x/sys/unix"
+
+ "github.com/lxc/lxd/lxd/db"
+ "github.com/lxc/lxd/shared"
+ "github.com/lxc/lxd/shared/api"
+ "github.com/lxc/lxd/shared/logger"
+)
+
+// MkfsOptions represents options for filesystem creation.
+type MkfsOptions struct {
+ Label string
+}
+
+// Export the mount options map since we might find it useful in other parts of
+// LXD.
+type mountOptions struct {
+ capture bool
+ flag uintptr
+}
+
+// MountOptions represents a list of possible mount options.
+var MountOptions = map[string]mountOptions{
+ "async": {false, unix.MS_SYNCHRONOUS},
+ "atime": {false, unix.MS_NOATIME},
+ "bind": {true, unix.MS_BIND},
+ "defaults": {true, 0},
+ "dev": {false, unix.MS_NODEV},
+ "diratime": {false, unix.MS_NODIRATIME},
+ "dirsync": {true, unix.MS_DIRSYNC},
+ "exec": {false, unix.MS_NOEXEC},
+ "lazytime": {true, unix.MS_LAZYTIME},
+ "mand": {true, unix.MS_MANDLOCK},
+ "noatime": {true, unix.MS_NOATIME},
+ "nodev": {true, unix.MS_NODEV},
+ "nodiratime": {true, unix.MS_NODIRATIME},
+ "noexec": {true, unix.MS_NOEXEC},
+ "nomand": {false, unix.MS_MANDLOCK},
+ "norelatime": {false, unix.MS_RELATIME},
+ "nostrictatime": {false, unix.MS_STRICTATIME},
+ "nosuid": {true, unix.MS_NOSUID},
+ "rbind": {true, unix.MS_BIND | unix.MS_REC},
+ "relatime": {true, unix.MS_RELATIME},
+ "remount": {true, unix.MS_REMOUNT},
+ "ro": {true, unix.MS_RDONLY},
+ "rw": {false, unix.MS_RDONLY},
+ "strictatime": {true, unix.MS_STRICTATIME},
+ "suid": {false, unix.MS_NOSUID},
+ "sync": {true, unix.MS_SYNCHRONOUS},
+}
+
+// LXDResolveMountoptions resolves the provided mount options.
+func LXDResolveMountoptions(options string) (uintptr, string) {
+ mountFlags := uintptr(0)
+ tmp := strings.SplitN(options, ",", -1)
+ for i := 0; i < len(tmp); i++ {
+ opt := tmp[i]
+ do, ok := MountOptions[opt]
+ if !ok {
+ continue
+ }
+
+ if do.capture {
+ mountFlags |= do.flag
+ } else {
+ mountFlags &= ^do.flag
+ }
+
+ copy(tmp[i:], tmp[i+1:])
+ tmp[len(tmp)-1] = ""
+ tmp = tmp[:len(tmp)-1]
+ i--
+ }
+
+ return mountFlags, strings.Join(tmp, ",")
+}
+
+// TryMount tries mounting a filesystem multiple times. This is useful for unreliable backends.
+func TryMount(src string, dst string, fs string, flags uintptr, options string) error {
+ var err error
+
+ for i := 0; i < 20; i++ {
+ err = unix.Mount(src, dst, fs, flags, options)
+ if err == nil {
+ break
+ }
+
+ time.Sleep(500 * time.Millisecond)
+ }
+
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// TryUnmount tries unmounting a filesystem multiple times. This is useful for unreliable backends.
+func TryUnmount(path string, flags int) error {
+ var err error
+
+ for i := 0; i < 20; i++ {
+ err = unix.Unmount(path, flags)
+ if err == nil {
+ break
+ }
+
+ time.Sleep(500 * time.Millisecond)
+ }
+
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// ValidName validates the provided name, and returns an error if it's not a valid storage name.
+func ValidName(value string) error {
+ if strings.Contains(value, "/") {
+ return fmt.Errorf("Invalid storage volume name \"%s\". Storage volumes cannot contain \"/\" in their name", value)
+ }
+
+ return nil
+}
+
+// ConfigDiff returns a diff of the provided configs. Additionally, it returns whether or not
+// only user properties have been changed.
+func ConfigDiff(oldConfig map[string]string, newConfig map[string]string) ([]string, bool) {
+ changedConfig := []string{}
+ userOnly := true
+ for key := range oldConfig {
+ if oldConfig[key] != newConfig[key] {
+ if !strings.HasPrefix(key, "user.") {
+ userOnly = false
+ }
+
+ if !shared.StringInSlice(key, changedConfig) {
+ changedConfig = append(changedConfig, key)
+ }
+ }
+ }
+
+ for key := range newConfig {
+ if oldConfig[key] != newConfig[key] {
+ if !strings.HasPrefix(key, "user.") {
+ userOnly = false
+ }
+
+ if !shared.StringInSlice(key, changedConfig) {
+ changedConfig = append(changedConfig, key)
+ }
+ }
+ }
+
+ // Skip on no change
+ if len(changedConfig) == 0 {
+ return nil, false
+ }
+
+ return changedConfig, userOnly
+}
+
+// StoragePoolsDirMode represents the default permissions for the storage pool directory.
+const StoragePoolsDirMode os.FileMode = 0711
+
+// ContainersDirMode represents the default permissions for the containers directory.
+const ContainersDirMode os.FileMode = 0711
+
+// CustomDirMode represents the default permissions for the custom directory.
+const CustomDirMode os.FileMode = 0711
+
+// ImagesDirMode represents the default permissions for the images directory.
+const ImagesDirMode os.FileMode = 0700
+
+// SnapshotsDirMode represents the default permissions for the snapshots directory.
+const SnapshotsDirMode os.FileMode = 0700
+
+// LXDUsesPool detect whether LXD already uses the given storage pool.
+func LXDUsesPool(dbObj *db.Cluster, onDiskPoolName string, driver string, onDiskProperty string) (bool, string, error) {
+ pools, err := dbObj.StoragePools()
+ if err != nil && err != db.ErrNoSuchObject {
+ return false, "", err
+ }
+
+ for _, pool := range pools {
+ _, pl, err := dbObj.StoragePoolGet(pool)
+ if err != nil {
+ continue
+ }
+
+ if pl.Driver != driver {
+ continue
+ }
+
+ if pl.Config[onDiskProperty] == onDiskPoolName {
+ return true, pl.Name, nil
+ }
+ }
+
+ return false, "", nil
+}
+
+// MakeFSType creates the provided filesystem.
+func MakeFSType(path string, fsType string, options *MkfsOptions) (string, error) {
+ var err error
+ var msg string
+
+ fsOptions := options
+ if fsOptions == nil {
+ fsOptions = &MkfsOptions{}
+ }
+
+ cmd := []string{fmt.Sprintf("mkfs.%s", fsType), path}
+ if fsOptions.Label != "" {
+ cmd = append(cmd, "-L", fsOptions.Label)
+ }
+
+ if fsType == "ext4" {
+ cmd = append(cmd, "-E", "nodiscard,lazy_itable_init=0,lazy_journal_init=0")
+ }
+
+ msg, err = shared.TryRunCommand(cmd[0], cmd[1:]...)
+ if err != nil {
+ return msg, err
+ }
+
+ return "", nil
+}
+
+// FSGenerateNewUUID generates a UUID for the given path for btrfs and xfs filesystems.
+func FSGenerateNewUUID(fstype string, lvpath string) (string, error) {
+ switch fstype {
+ case "btrfs":
+ return btrfsGenerateNewUUID(lvpath)
+ case "xfs":
+ return xfsGenerateNewUUID(lvpath)
+ }
+
+ return "", nil
+}
+
+func xfsGenerateNewUUID(devPath string) (string, error) {
+ // Attempt to generate a new UUID
+ msg, err := shared.RunCommand("xfs_admin", "-U", "generate", devPath)
+ if err != nil {
+ return msg, err
+ }
+
+ if msg != "" {
+ // Exit 0 with a msg usually means some log entry getting in the way
+ msg, err = shared.RunCommand("xfs_repair", "-o", "force_geometry", "-L", devPath)
+ if err != nil {
+ return msg, err
+ }
+
+ // Attempt to generate a new UUID again
+ msg, err = shared.RunCommand("xfs_admin", "-U", "generate", devPath)
+ if err != nil {
+ return msg, err
+ }
+ }
+
+ return msg, nil
+}
+
+func btrfsGenerateNewUUID(lvpath string) (string, error) {
+ msg, err := shared.RunCommand(
+ "btrfstune",
+ "-f",
+ "-u",
+ lvpath)
+ if err != nil {
+ return msg, err
+ }
+
+ return msg, nil
+}
+
+// GrowFileSystem grows a filesystem if it is supported.
+func GrowFileSystem(fsType string, devPath string, mntpoint string) error {
+ var msg string
+ var err error
+ switch fsType {
+ case "": // if not specified, default to ext4
+ fallthrough
+ case "ext4":
+ msg, err = shared.TryRunCommand("resize2fs", devPath)
+ case "xfs":
+ msg, err = shared.TryRunCommand("xfs_growfs", devPath)
+ case "btrfs":
+ msg, err = shared.TryRunCommand("btrfs", "filesystem", "resize", "max", mntpoint)
+ default:
+ return fmt.Errorf(`Growing not supported for filesystem type "%s"`, fsType)
+ }
+
+ if err != nil {
+ errorMsg := fmt.Sprintf(`Could not extend underlying %s filesystem for "%s": %s`, fsType, devPath, msg)
+ logger.Errorf(errorMsg)
+ return fmt.Errorf(errorMsg)
+ }
+
+ logger.Debugf(`extended underlying %s filesystem for "%s"`, fsType, devPath)
+ return nil
+}
+
+// ShrinkFileSystem shrinks a filesystem if it is supported.
+func ShrinkFileSystem(fsType string, devPath string, mntpoint string, byteSize int64) error {
+ strSize := fmt.Sprintf("%dK", byteSize/1024)
+
+ switch fsType {
+ case "": // if not specified, default to ext4
+ fallthrough
+ case "ext4":
+ _, err := shared.TryRunCommand("e2fsck", "-f", "-y", devPath)
+ if err != nil {
+ return err
+ }
+
+ _, err = shared.TryRunCommand("resize2fs", devPath, strSize)
+ if err != nil {
+ return err
+ }
+ case "btrfs":
+ _, err := shared.TryRunCommand("btrfs", "filesystem", "resize", strSize, mntpoint)
+ if err != nil {
+ return err
+ }
+ default:
+ return fmt.Errorf(`Shrinking not supported for filesystem type "%s"`, fsType)
+ }
+
+ return nil
+}
+
+// GetStorageResource returns the available resources of a given path.
+func GetStorageResource(path string) (*api.ResourcesStoragePool, error) {
+ st, err := shared.Statvfs(path)
+ if err != nil {
+ return nil, err
+ }
+
+ res := api.ResourcesStoragePool{}
+ res.Space.Total = st.Blocks * uint64(st.Bsize)
+ res.Space.Used = (st.Blocks - st.Bfree) * uint64(st.Bsize)
+
+ // Some filesystems don't report inodes since they allocate them
+ // dynamically e.g. btrfs.
+ if st.Files > 0 {
+ res.Inodes.Total = st.Files
+ res.Inodes.Used = st.Files - st.Ffree
+ }
+
+ return &res, nil
+}
diff --git a/lxd/storage_btrfs.go b/lxd/storage_btrfs.go
index 66d541a9ab..5be6c321a4 100644
--- a/lxd/storage_btrfs.go
+++ b/lxd/storage_btrfs.go
@@ -157,7 +157,7 @@ func (s *storageBtrfs) StoragePoolCreate() error {
return fmt.Errorf("Failed to create sparse file %s: %s", source, err)
}
- output, err := makeFSType(source, "btrfs", &mkfsOptions{label: s.pool.Name})
+ output, err := driver.MakeFSType(source, "btrfs", &driver.MkfsOptions{Label: s.pool.Name})
if err != nil {
return fmt.Errorf("Failed to create the BTRFS pool: %s", output)
}
@@ -168,7 +168,7 @@ func (s *storageBtrfs) StoragePoolCreate() error {
if filepath.IsAbs(source) {
isBlockDev = shared.IsBlockdevPath(source)
if isBlockDev {
- output, err := makeFSType(source, "btrfs", &mkfsOptions{label: s.pool.Name})
+ output, err := driver.MakeFSType(source, "btrfs", &driver.MkfsOptions{Label: s.pool.Name})
if err != nil {
return fmt.Errorf("Failed to create the BTRFS pool: %s", output)
}
@@ -208,7 +208,7 @@ func (s *storageBtrfs) StoragePoolCreate() error {
poolMntPoint := getStoragePoolMountPoint(s.pool.Name)
if !shared.PathExists(poolMntPoint) {
- err := os.MkdirAll(poolMntPoint, storagePoolsDirMode)
+ err := os.MkdirAll(poolMntPoint, driver.StoragePoolsDirMode)
if err != nil {
return err
}
@@ -216,7 +216,7 @@ func (s *storageBtrfs) StoragePoolCreate() error {
var err1 error
var devUUID string
- mountFlags, mountOptions := lxdResolveMountoptions(s.getBtrfsMountOptions())
+ mountFlags, mountOptions := driver.LXDResolveMountoptions(s.getBtrfsMountOptions())
mountFlags |= s.remount
if isBlockDev && filepath.IsAbs(source) {
devUUID, _ = shared.LookupUUIDByBlockDevPath(source)
@@ -399,7 +399,7 @@ func (s *storageBtrfs) StoragePoolMount() (bool, error) {
// Check whether the mount poolMntPoint exits.
if !shared.PathExists(poolMntPoint) {
- err := os.MkdirAll(poolMntPoint, storagePoolsDirMode)
+ err := os.MkdirAll(poolMntPoint, driver.StoragePoolsDirMode)
if err != nil {
return false, err
}
@@ -409,7 +409,7 @@ func (s *storageBtrfs) StoragePoolMount() (bool, error) {
return false, nil
}
- mountFlags, mountOptions := lxdResolveMountoptions(s.getBtrfsMountOptions())
+ mountFlags, mountOptions := driver.LXDResolveMountoptions(s.getBtrfsMountOptions())
mountSource := source
isBlockDev := shared.IsBlockdevPath(source)
if filepath.IsAbs(source) {
@@ -821,7 +821,7 @@ func (s *storageBtrfs) doContainerCreate(projectName, name string, privileged bo
// doesn't already.
containerSubvolumePath := s.getContainerSubvolumePath(s.pool.Name)
if !shared.PathExists(containerSubvolumePath) {
- err := os.MkdirAll(containerSubvolumePath, containersDirMode)
+ err := os.MkdirAll(containerSubvolumePath, driver.ContainersDirMode)
if err != nil {
return err
}
@@ -876,7 +876,7 @@ func (s *storageBtrfs) ContainerCreateFromImage(container container, fingerprint
// doesn't already.
containerSubvolumePath := s.getContainerSubvolumePath(s.pool.Name)
if !shared.PathExists(containerSubvolumePath) {
- err := os.MkdirAll(containerSubvolumePath, containersDirMode)
+ err := os.MkdirAll(containerSubvolumePath, driver.ContainersDirMode)
if err != nil {
return errors.Wrap(err, "Failed to create volume directory")
}
@@ -995,7 +995,7 @@ func (s *storageBtrfs) copyContainer(target container, source container) error {
containersPath := getContainerMountPoint("default", s.pool.Name, "")
// Ensure that the directories immediately preceding the subvolume directory exist.
if !shared.PathExists(containersPath) {
- err := os.MkdirAll(containersPath, containersDirMode)
+ err := os.MkdirAll(containersPath, driver.ContainersDirMode)
if err != nil {
return err
}
@@ -1036,7 +1036,7 @@ func (s *storageBtrfs) copySnapshot(target container, source container) error {
// Ensure that the directories immediately preceding the subvolume directory exist.
if !shared.PathExists(containersPath) {
- err := os.MkdirAll(containersPath, containersDirMode)
+ err := os.MkdirAll(containersPath, driver.ContainersDirMode)
if err != nil {
return err
}
@@ -1379,7 +1379,7 @@ func (s *storageBtrfs) doContainerSnapshotCreate(projectName string, targetName
// doesn't already.
snapshotSubvolumePath := getSnapshotSubvolumePath(projectName, s.pool.Name, sourceName)
if !shared.PathExists(snapshotSubvolumePath) {
- err := os.MkdirAll(snapshotSubvolumePath, containersDirMode)
+ err := os.MkdirAll(snapshotSubvolumePath, driver.ContainersDirMode)
if err != nil {
return err
}
@@ -1389,7 +1389,7 @@ func (s *storageBtrfs) doContainerSnapshotCreate(projectName string, targetName
snapshotMntPointSymlink := shared.VarPath("snapshots", project.Prefix(projectName, sourceName))
if !shared.PathExists(snapshotMntPointSymlink) {
if !shared.PathExists(snapshotMntPointSymlinkTarget) {
- err = os.MkdirAll(snapshotMntPointSymlinkTarget, snapshotsDirMode)
+ err = os.MkdirAll(snapshotMntPointSymlinkTarget, driver.SnapshotsDirMode)
if err != nil {
return err
}
@@ -1567,7 +1567,7 @@ func (s *storageBtrfs) ContainerSnapshotCreateEmpty(snapshotContainer container)
snapshotSubvolumePath := getSnapshotSubvolumePath(snapshotContainer.Project(), s.pool.Name, sourceName)
snapshotSubvolumeName := getSnapshotMountPoint(snapshotContainer.Project(), s.pool.Name, snapshotContainer.Name())
if !shared.PathExists(snapshotSubvolumePath) {
- err := os.MkdirAll(snapshotSubvolumePath, containersDirMode)
+ err := os.MkdirAll(snapshotSubvolumePath, driver.ContainersDirMode)
if err != nil {
return err
}
@@ -2000,7 +2000,7 @@ func (s *storageBtrfs) ImageCreate(fingerprint string, tracker *ioprogress.Progr
// doesn't already.
imageSubvolumePath := s.getImageSubvolumePath(s.pool.Name)
if !shared.PathExists(imageSubvolumePath) {
- err := os.MkdirAll(imageSubvolumePath, imagesDirMode)
+ err := os.MkdirAll(imageSubvolumePath, driver.ImagesDirMode)
if err != nil {
return err
}
@@ -2723,7 +2723,7 @@ func (s *storageBtrfs) MigrationSink(conn *websocket.Conn, op *operation, args M
_, containerPool, _ := args.Container.Storage().GetContainerPoolInfo()
containersPath := getSnapshotMountPoint(args.Container.Project(), containerPool, containerName)
if !args.ContainerOnly && len(args.Snapshots) > 0 {
- err := os.MkdirAll(containersPath, containersDirMode)
+ err := os.MkdirAll(containersPath, driver.ContainersDirMode)
if err != nil {
return err
}
@@ -2961,7 +2961,7 @@ func (s *storageBtrfs) StoragePoolResources() (*api.ResourcesStoragePool, error)
// Inode allocation is dynamic so no use in reporting them.
- return storageResource(poolMntPoint)
+ return driver.GetStorageResource(poolMntPoint)
}
func (s *storageBtrfs) StoragePoolVolumeCopy(source *api.StorageVolumeSource) error {
@@ -3037,7 +3037,7 @@ func (s *storageBtrfs) copyVolume(sourcePool string, sourceName string, targetNa
}
if !shared.PathExists(customDir) {
- err := os.MkdirAll(customDir, customDirMode)
+ err := os.MkdirAll(customDir, driver.CustomDirMode)
if err != nil {
logger.Errorf("Failed to create directory \"%s\" for storage volume \"%s\" on storage pool \"%s\": %s", customDir, s.volume.Name, s.pool.Name, err)
return err
@@ -3163,7 +3163,7 @@ func (s *storageBtrfs) doVolumeSnapshotCreate(sourcePool string, sourceName stri
customSnapshotSubvolumeName := getStoragePoolVolumeSnapshotMountPoint(s.pool.Name, s.volume.Name)
- err = os.MkdirAll(customSnapshotSubvolumeName, snapshotsDirMode)
+ err = os.MkdirAll(customSnapshotSubvolumeName, driver.SnapshotsDirMode)
if err != nil && !os.IsNotExist(err) {
return err
}
diff --git a/lxd/storage_ceph.go b/lxd/storage_ceph.go
index e603190047..76fff33607 100644
--- a/lxd/storage_ceph.go
+++ b/lxd/storage_ceph.go
@@ -15,6 +15,7 @@ import (
"github.com/lxc/lxd/lxd/db"
"github.com/lxc/lxd/lxd/project"
+ driver "github.com/lxc/lxd/lxd/storage"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
"github.com/lxc/lxd/shared/ioprogress"
@@ -358,7 +359,7 @@ func (s *storageCeph) StoragePoolVolumeCreate() error {
RBDFilesystem := s.getRBDFilesystem()
logger.Debugf(`Retrieved filesystem type "%s" of RBD storage volume "%s" on storage pool "%s"`, RBDFilesystem, s.volume.Name, s.pool.Name)
- msg, err := makeFSType(RBDDevPath, RBDFilesystem, nil)
+ msg, err := driver.MakeFSType(RBDDevPath, RBDFilesystem, nil)
if err != nil {
logger.Errorf(`Failed to create filesystem type "%s" on device path "%s" for RBD storage volume "%s" on storage pool "%s": %s`, RBDFilesystem, RBDDevPath, s.volume.Name, s.pool.Name, msg)
return err
@@ -424,7 +425,7 @@ func (s *storageCeph) StoragePoolVolumeDelete() error {
volumeMntPoint := getStoragePoolVolumeMountPoint(s.pool.Name, s.volume.Name)
if shared.IsMountPoint(volumeMntPoint) {
- err := tryUnmount(volumeMntPoint, unix.MNT_DETACH)
+ err := driver.TryUnmount(volumeMntPoint, unix.MNT_DETACH)
if err != nil {
logger.Errorf(`Failed to unmount RBD storage volume "%s" on storage pool "%s": %s`, s.volume.Name, s.pool.Name, err)
}
@@ -508,8 +509,8 @@ func (s *storageCeph) StoragePoolVolumeMount() (bool, error) {
RBDDevPath, ret = getRBDMappedDevPath(s.ClusterName, s.OSDPoolName,
storagePoolVolumeTypeNameCustom, s.volume.Name, true,
s.UserName)
- mountFlags, mountOptions := lxdResolveMountoptions(s.getRBDMountOptions())
- customerr = tryMount(
+ mountFlags, mountOptions := driver.LXDResolveMountoptions(s.getRBDMountOptions())
+ customerr = driver.TryMount(
RBDDevPath,
volumeMntPoint,
RBDFilesystem,
@@ -560,7 +561,7 @@ func (s *storageCeph) StoragePoolVolumeUmount() (bool, error) {
var customerr error
ourUmount := false
if shared.IsMountPoint(volumeMntPoint) {
- customerr = tryUnmount(volumeMntPoint, unix.MNT_DETACH)
+ customerr = driver.TryUnmount(volumeMntPoint, unix.MNT_DETACH)
ourUmount = true
}
@@ -1366,7 +1367,7 @@ func (s *storageCeph) ContainerUmount(c container, path string) (bool, error) {
var mounterr error
ourUmount := false
if shared.IsMountPoint(containerMntPoint) {
- mounterr = tryUnmount(containerMntPoint, 0)
+ mounterr = driver.TryUnmount(containerMntPoint, 0)
ourUmount = true
}
@@ -1804,7 +1805,7 @@ func (s *storageCeph) ContainerSnapshotStart(c container) (bool, error) {
containerMntPoint := getSnapshotMountPoint(c.Project(), s.pool.Name, containerName)
RBDFilesystem := s.getRBDFilesystem()
- mountFlags, mountOptions := lxdResolveMountoptions(s.getRBDMountOptions())
+ mountFlags, mountOptions := driver.LXDResolveMountoptions(s.getRBDMountOptions())
if RBDFilesystem == "xfs" {
idx := strings.Index(mountOptions, "nouuid")
if idx < 0 {
@@ -1812,7 +1813,7 @@ func (s *storageCeph) ContainerSnapshotStart(c container) (bool, error) {
}
}
- err = tryMount(
+ err = driver.TryMount(
RBDDevPath,
containerMntPoint,
RBDFilesystem,
@@ -1845,7 +1846,7 @@ func (s *storageCeph) ContainerSnapshotStop(c container) (bool, error) {
}
// Unmount
- err := tryUnmount(containerMntPoint, unix.MNT_DETACH)
+ err := driver.TryUnmount(containerMntPoint, unix.MNT_DETACH)
if err != nil {
logger.Errorf("Failed to unmount %s: %s", containerMntPoint, err)
return false, err
@@ -2103,7 +2104,7 @@ func (s *storageCeph) ImageCreate(fingerprint string, tracker *ioprogress.Progre
// get filesystem
RBDFilesystem := s.getRBDFilesystem()
- msg, err := makeFSType(RBDDevPath, RBDFilesystem, nil)
+ msg, err := driver.MakeFSType(RBDDevPath, RBDFilesystem, nil)
if err != nil {
logger.Errorf(`Failed to create filesystem "%s" for RBD storage volume for image "%s" on storage pool "%s": %s`, RBDFilesystem, fingerprint,
s.pool.Name, msg)
@@ -2339,7 +2340,7 @@ func (s *storageCeph) ImageMount(fingerprint string) (bool, error) {
RBDFilesystem := s.getRBDFilesystem()
RBDMountOptions := s.getRBDMountOptions()
- mountFlags, mountOptions := lxdResolveMountoptions(RBDMountOptions)
+ mountFlags, mountOptions := driver.LXDResolveMountoptions(RBDMountOptions)
RBDDevPath, ret := getRBDMappedDevPath(s.ClusterName, s.OSDPoolName,
storagePoolVolumeTypeNameImage, fingerprint, true, s.UserName)
errMsg := fmt.Sprintf("Failed to mount RBD device %s onto %s",
@@ -2349,7 +2350,7 @@ func (s *storageCeph) ImageMount(fingerprint string) (bool, error) {
return false, fmt.Errorf(errMsg)
}
- err := tryMount(RBDDevPath, imageMntPoint, RBDFilesystem, mountFlags, mountOptions)
+ err := driver.TryMount(RBDDevPath, imageMntPoint, RBDFilesystem, mountFlags, mountOptions)
if err != nil || ret < 0 {
return false, err
}
@@ -2366,7 +2367,7 @@ func (s *storageCeph) ImageUmount(fingerprint string) (bool, error) {
return false, nil
}
- err := tryUnmount(imageMntPoint, 0)
+ err := driver.TryUnmount(imageMntPoint, 0)
if err != nil {
return false, err
}
@@ -2633,7 +2634,7 @@ func (s *storageCeph) StoragePoolVolumeCopy(source *api.StorageVolumeSource) err
// create snapshot mountpoint
newTargetName := fmt.Sprintf("%s/%s", s.volume.Name, snapOnlyName)
targetPath := getStoragePoolVolumeSnapshotMountPoint(s.pool.Name, newTargetName)
- err = os.MkdirAll(targetPath, snapshotsDirMode)
+ err = os.MkdirAll(targetPath, driver.SnapshotsDirMode)
if err != nil {
logger.Errorf("Failed to create mountpoint \"%s\" for RBD storage volume \"%s\" on storage pool \"%s\": %s", targetPath, s.volume.Name, s.pool.Name, err)
return err
@@ -2718,7 +2719,7 @@ func (s *storageCeph) StoragePoolVolumeSnapshotCreate(target *api.StorageVolumeS
}
targetPath := getStoragePoolVolumeSnapshotMountPoint(s.pool.Name, target.Name)
- err = os.MkdirAll(targetPath, snapshotsDirMode)
+ err = os.MkdirAll(targetPath, driver.SnapshotsDirMode)
if err != nil {
logger.Errorf("Failed to create mountpoint \"%s\" for RBD storage volume \"%s\" on storage pool \"%s\": %s", targetPath, s.volume.Name, s.pool.Name, err)
return err
diff --git a/lxd/storage_ceph_utils.go b/lxd/storage_ceph_utils.go
index 9c458ad929..dacfec3b30 100644
--- a/lxd/storage_ceph_utils.go
+++ b/lxd/storage_ceph_utils.go
@@ -16,6 +16,7 @@ import (
"github.com/lxc/lxd/lxd/db"
"github.com/lxc/lxd/lxd/project"
+ driver "github.com/lxc/lxd/lxd/storage"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
"github.com/lxc/lxd/shared/logger"
@@ -705,7 +706,7 @@ func (s *storageCeph) getRBDFilesystem() string {
// getRBDMountOptions returns the mount options the storage volume is supposed
// to be mounted with
// The option string that is returned needs to be passed to the approriate
-// helper (currently named "lxdResolveMountoptions") which will take on the job
+// helper (currently named "LXDResolveMountoptions") which will take on the job
// of splitting it into appropriate flags and string options.
func (s *storageCeph) getRBDMountOptions() string {
if s.volume.Config["block.mount_options"] != "" {
@@ -1556,7 +1557,7 @@ func (s *storageCeph) rbdGrow(path string, size int64, fsType string,
}
// Grow the filesystem
- return growFileSystem(fsType, path, fsMntPoint)
+ return driver.GrowFileSystem(fsType, path, fsMntPoint)
}
// copyWithSnapshots creates a non-sparse copy of a container including its
@@ -1647,7 +1648,7 @@ func (s *storageCeph) cephRBDVolumeBackupCreate(tmpPath string, backup backup, s
// Generate a new UUID if needed
RBDFilesystem := s.getRBDFilesystem()
- msg, err := fsGenerateNewUUID(RBDFilesystem, RBDDevPath)
+ msg, err := driver.FSGenerateNewUUID(RBDFilesystem, RBDDevPath)
if err != nil {
logger.Errorf("Failed to create new UUID for filesystem \"%s\": %s: %s", RBDFilesystem, msg, err)
return err
@@ -1666,14 +1667,14 @@ func (s *storageCeph) cephRBDVolumeBackupCreate(tmpPath string, backup backup, s
}
// Mount the volume
- mountFlags, mountOptions := lxdResolveMountoptions(s.getRBDMountOptions())
- err = tryMount(RBDDevPath, tmpContainerMntPoint, RBDFilesystem, mountFlags, mountOptions)
+ mountFlags, mountOptions := driver.LXDResolveMountoptions(s.getRBDMountOptions())
+ err = driver.TryMount(RBDDevPath, tmpContainerMntPoint, RBDFilesystem, mountFlags, mountOptions)
if err != nil {
logger.Errorf("Failed to mount RBD device %s onto %s: %s", RBDDevPath, tmpContainerMntPoint, err)
return err
}
logger.Debugf("Mounted RBD device %s onto %s", RBDDevPath, tmpContainerMntPoint)
- defer tryUnmount(tmpContainerMntPoint, unix.MNT_DETACH)
+ defer driver.TryUnmount(tmpContainerMntPoint, unix.MNT_DETACH)
// Figure out the target name
targetName := sourceContainerName
@@ -1753,7 +1754,7 @@ func (s *storageCeph) doContainerCreate(projectName, name string, privileged boo
// get filesystem
RBDFilesystem := s.getRBDFilesystem()
- msg, err := makeFSType(RBDDevPath, RBDFilesystem, nil)
+ msg, err := driver.MakeFSType(RBDDevPath, RBDFilesystem, nil)
if err != nil {
logger.Errorf(`Failed to create filesystem type "%s" on device path "%s" for RBD storage volume for container "%s" on storage pool "%s": %s`, RBDFilesystem, RBDDevPath, name, s.pool.Name, msg)
return err
@@ -1820,8 +1821,8 @@ func (s *storageCeph) doContainerMount(projectName string, name string) (bool, e
s.OSDPoolName, storagePoolVolumeTypeNameContainer,
volumeName, true, s.UserName)
if ret >= 0 {
- mountFlags, mountOptions := lxdResolveMountoptions(s.getRBDMountOptions())
- mounterr = tryMount(RBDDevPath, containerMntPoint,
+ mountFlags, mountOptions := driver.LXDResolveMountoptions(s.getRBDMountOptions())
+ mounterr = driver.TryMount(RBDDevPath, containerMntPoint,
RBDFilesystem, mountFlags, mountOptions)
ourMount = true
}
@@ -2060,7 +2061,7 @@ func (s *storageCeph) cephRBDGenerateUUID(volumeName string, volumeType string)
defer cephRBDVolumeUnmap(s.ClusterName, s.OSDPoolName, volumeName, volumeType, s.UserName, true)
// Update the UUID
- msg, err := fsGenerateNewUUID(s.getRBDFilesystem(), RBDDevPath)
+ msg, err := driver.FSGenerateNewUUID(s.getRBDFilesystem(), RBDDevPath)
if err != nil {
return fmt.Errorf("Failed to regenerate UUID for '%v': %v: %v", volumeName, err, msg)
}
diff --git a/lxd/storage_cephfs.go b/lxd/storage_cephfs.go
index 7f4d5f86ec..58651befec 100644
--- a/lxd/storage_cephfs.go
+++ b/lxd/storage_cephfs.go
@@ -15,6 +15,7 @@ import (
"github.com/lxc/lxd/lxd/migration"
"github.com/lxc/lxd/lxd/state"
+ driver "github.com/lxc/lxd/lxd/storage"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
"github.com/lxc/lxd/shared/ioprogress"
@@ -151,13 +152,13 @@ func (s *storageCephFs) StoragePoolCreate() error {
connected := false
for _, monAddress := range monAddresses {
uri := fmt.Sprintf("%s:6789:/", monAddress)
- err = tryMount(uri, mountPoint, "ceph", 0, fmt.Sprintf("name=%v,secret=%v,mds_namespace=%v", s.UserName, userSecret, fsName))
+ err = driver.TryMount(uri, mountPoint, "ceph", 0, fmt.Sprintf("name=%v,secret=%v,mds_namespace=%v", s.UserName, userSecret, fsName))
if err != nil {
continue
}
connected = true
- defer tryUnmount(mountPoint, syscall.MNT_DETACH)
+ defer driver.TryUnmount(mountPoint, syscall.MNT_DETACH)
break
}
@@ -227,13 +228,13 @@ func (s *storageCephFs) StoragePoolDelete() error {
connected := false
for _, monAddress := range monAddresses {
uri := fmt.Sprintf("%s:6789:/", monAddress)
- err = tryMount(uri, mountPoint, "ceph", 0, fmt.Sprintf("name=%v,secret=%v,mds_namespace=%v", s.UserName, userSecret, fsName))
+ err = driver.TryMount(uri, mountPoint, "ceph", 0, fmt.Sprintf("name=%v,secret=%v,mds_namespace=%v", s.UserName, userSecret, fsName))
if err != nil {
continue
}
connected = true
- defer tryUnmount(mountPoint, syscall.MNT_DETACH)
+ defer driver.TryUnmount(mountPoint, syscall.MNT_DETACH)
break
}
@@ -340,7 +341,7 @@ func (s *storageCephFs) StoragePoolMount() (bool, error) {
connected := false
for _, monAddress := range monAddresses {
uri := fmt.Sprintf("%s:6789:/%s", monAddress, fsPath)
- err = tryMount(uri, poolMntPoint, "ceph", 0, fmt.Sprintf("name=%v,secret=%v,mds_namespace=%v", s.UserName, secret, fsName))
+ err = driver.TryMount(uri, poolMntPoint, "ceph", 0, fmt.Sprintf("name=%v,secret=%v,mds_namespace=%v", s.UserName, secret, fsName))
if err != nil {
continue
}
@@ -395,7 +396,7 @@ func (s *storageCephFs) StoragePoolUmount() (bool, error) {
}
// Unmount
- err := tryUnmount(poolMntPoint, syscall.MNT_DETACH)
+ err := driver.TryUnmount(poolMntPoint, syscall.MNT_DETACH)
if err != nil {
return false, err
}
@@ -756,7 +757,7 @@ func (s *storageCephFs) StoragePoolResources() (*api.ResourcesStoragePool, error
}
poolMntPoint := getStoragePoolMountPoint(s.pool.Name)
- return storageResource(poolMntPoint)
+ return driver.GetStorageResource(poolMntPoint)
}
func (s *storageCephFs) StoragePoolVolumeCopy(source *api.StorageVolumeSource) error {
diff --git a/lxd/storage_dir.go b/lxd/storage_dir.go
index 46482a01aa..edd26d8686 100644
--- a/lxd/storage_dir.go
+++ b/lxd/storage_dir.go
@@ -1386,7 +1386,7 @@ func (s *storageDir) StoragePoolResources() (*api.ResourcesStoragePool, error) {
poolMntPoint := getStoragePoolMountPoint(s.pool.Name)
- return storageResource(poolMntPoint)
+ return driver.GetStorageResource(poolMntPoint)
}
func (s *storageDir) StoragePoolVolumeCopy(source *api.StorageVolumeSource) error {
diff --git a/lxd/storage_lvm.go b/lxd/storage_lvm.go
index 97ece383c6..c168697b33 100644
--- a/lxd/storage_lvm.go
+++ b/lxd/storage_lvm.go
@@ -302,7 +302,7 @@ func (s *storageLvm) StoragePoolCreate() error {
}
// Check that we don't already use this volume group.
- inUse, user, err := lxdUsesPool(s.s.Cluster, poolName, s.pool.Driver, "lvm.vg_name")
+ inUse, user, err := driver.LXDUsesPool(s.s.Cluster, poolName, s.pool.Driver, "lvm.vg_name")
if err != nil {
return err
}
@@ -619,8 +619,8 @@ func (s *storageLvm) StoragePoolVolumeMount() (bool, error) {
var customerr error
ourMount := false
if !shared.IsMountPoint(customPoolVolumeMntPoint) {
- mountFlags, mountOptions := lxdResolveMountoptions(s.getLvmMountOptions())
- customerr = tryMount(lvmVolumePath, customPoolVolumeMntPoint, lvFsType, mountFlags, mountOptions)
+ mountFlags, mountOptions := driver.LXDResolveMountoptions(s.getLvmMountOptions())
+ customerr = driver.TryMount(lvmVolumePath, customPoolVolumeMntPoint, lvFsType, mountFlags, mountOptions)
ourMount = true
}
@@ -662,7 +662,7 @@ func (s *storageLvm) StoragePoolVolumeUmount() (bool, error) {
var customerr error
ourUmount := false
if shared.IsMountPoint(customPoolVolumeMntPoint) {
- customerr = tryUnmount(customPoolVolumeMntPoint, 0)
+ customerr = driver.TryUnmount(customPoolVolumeMntPoint, 0)
ourUmount = true
}
@@ -1028,7 +1028,7 @@ func (s *storageLvm) ContainerCreateFromImage(container container, fingerprint s
containerLvDevPath := getLvmDevPath(container.Project(), poolName, storagePoolVolumeAPIEndpointContainers, containerLvmName)
// Generate a new xfs's UUID
lvFsType := s.getLvmFilesystem()
- msg, err := fsGenerateNewUUID(lvFsType, containerLvDevPath)
+ msg, err := driver.FSGenerateNewUUID(lvFsType, containerLvDevPath)
if err != nil {
logger.Errorf("Failed to create new \"%s\" UUID for container \"%s\" on storage pool \"%s\": %s", lvFsType, containerName, s.pool.Name, msg)
return err
@@ -1073,7 +1073,7 @@ func lvmContainerDeleteInternal(projectName, poolName string, ctName string, isS
}
if shared.IsMountPoint(containerMntPoint) {
- err := tryUnmount(containerMntPoint, 0)
+ err := driver.TryUnmount(containerMntPoint, 0)
if err != nil {
return fmt.Errorf(`Failed to unmount container path `+
`"%s": %s`, containerMntPoint, err)
@@ -1265,7 +1265,7 @@ func (s *storageLvm) doContainerMount(project, name string, snap bool) (bool, er
var mounterr error
ourMount := false
if !shared.IsMountPoint(containerMntPoint) {
- mountFlags, mountOptions := lxdResolveMountoptions(s.getLvmMountOptions())
+ mountFlags, mountOptions := driver.LXDResolveMountoptions(s.getLvmMountOptions())
if snap && lvFsType == "xfs" {
idx := strings.Index(mountOptions, "nouuid")
if idx < 0 {
@@ -1273,7 +1273,7 @@ func (s *storageLvm) doContainerMount(project, name string, snap bool) (bool, er
}
}
- mounterr = tryMount(containerLvmPath, containerMntPoint, lvFsType, mountFlags, mountOptions)
+ mounterr = driver.TryMount(containerLvmPath, containerMntPoint, lvFsType, mountFlags, mountOptions)
ourMount = true
}
@@ -1321,7 +1321,7 @@ func (s *storageLvm) umount(project, name string, path string) (bool, error) {
var imgerr error
ourUmount := false
if shared.IsMountPoint(containerMntPoint) {
- imgerr = tryUnmount(containerMntPoint, 0)
+ imgerr = driver.TryUnmount(containerMntPoint, 0)
ourUmount = true
}
@@ -1585,7 +1585,7 @@ func (s *storageLvm) ContainerSnapshotStart(container container) (bool, error) {
containerMntPoint := getSnapshotMountPoint(container.Project(), s.pool.Name, containerName)
if !shared.IsMountPoint(containerMntPoint) {
mntOptString := s.getLvmMountOptions()
- mountFlags, mountOptions := lxdResolveMountoptions(mntOptString)
+ mountFlags, mountOptions := driver.LXDResolveMountoptions(mntOptString)
if lvFsType == "xfs" {
idx := strings.Index(mountOptions, "nouuid")
@@ -1594,7 +1594,7 @@ func (s *storageLvm) ContainerSnapshotStart(container container) (bool, error) {
}
}
- err = tryMount(containerLvmPath, containerMntPoint, lvFsType, mountFlags, mountOptions)
+ err = driver.TryMount(containerLvmPath, containerMntPoint, lvFsType, mountFlags, mountOptions)
if err != nil {
logger.Errorf(`Failed to mount LVM snapshot "%s" with filesystem "%s" options "%s" onto "%s": %s`, s.volume.Name, lvFsType, mntOptString, containerMntPoint, err)
return false, err
@@ -1619,7 +1619,7 @@ func (s *storageLvm) ContainerSnapshotStop(container container) (bool, error) {
poolName := s.getOnDiskPoolName()
if shared.IsMountPoint(snapshotMntPoint) {
- err := tryUnmount(snapshotMntPoint, 0)
+ err := driver.TryUnmount(snapshotMntPoint, 0)
if err != nil {
return false, err
}
@@ -2028,8 +2028,8 @@ func (s *storageLvm) ImageMount(fingerprint string) (bool, error) {
poolName := s.getOnDiskPoolName()
lvmVolumePath := getLvmDevPath("default", poolName, storagePoolVolumeAPIEndpointImages, fingerprint)
- mountFlags, mountOptions := lxdResolveMountoptions(s.getLvmMountOptions())
- err := tryMount(lvmVolumePath, imageMntPoint, lvmFstype, mountFlags, mountOptions)
+ mountFlags, mountOptions := driver.LXDResolveMountoptions(s.getLvmMountOptions())
+ err := driver.TryMount(lvmVolumePath, imageMntPoint, lvmFstype, mountFlags, mountOptions)
if err != nil {
logger.Errorf(fmt.Sprintf("Error mounting image LV for unpacking: %s", err))
return false, fmt.Errorf("Error mounting image LV: %v", err)
@@ -2047,7 +2047,7 @@ func (s *storageLvm) ImageUmount(fingerprint string) (bool, error) {
return false, nil
}
- err := tryUnmount(imageMntPoint, 0)
+ err := driver.TryUnmount(imageMntPoint, 0)
if err != nil {
return false, err
}
@@ -2287,7 +2287,7 @@ func (s *storageLvm) StoragePoolVolumeSnapshotCreate(target *api.StorageVolumeSn
}
targetPath := getStoragePoolVolumeSnapshotMountPoint(s.pool.Name, target.Name)
- err = os.MkdirAll(targetPath, snapshotsDirMode)
+ err = os.MkdirAll(targetPath, driver.SnapshotsDirMode)
if err != nil {
logger.Errorf("Failed to create mountpoint \"%s\" for RBD storage volume \"%s\" on storage pool \"%s\": %s", targetPath, s.volume.Name, s.pool.Name, err)
return err
@@ -2303,7 +2303,7 @@ func (s *storageLvm) StoragePoolVolumeSnapshotDelete() error {
snapshotLVName := containerNameToLVName(s.volume.Name)
storageVolumeSnapshotPath := getStoragePoolVolumeSnapshotMountPoint(s.pool.Name, s.volume.Name)
if shared.IsMountPoint(storageVolumeSnapshotPath) {
- err := tryUnmount(storageVolumeSnapshotPath, 0)
+ err := driver.TryUnmount(storageVolumeSnapshotPath, 0)
if err != nil {
return fmt.Errorf("Failed to unmount snapshot path \"%s\": %s", storageVolumeSnapshotPath, err)
}
diff --git a/lxd/storage_lvm_utils.go b/lxd/storage_lvm_utils.go
index c35e66bcca..297813efa2 100644
--- a/lxd/storage_lvm_utils.go
+++ b/lxd/storage_lvm_utils.go
@@ -13,6 +13,7 @@ import (
"github.com/lxc/lxd/lxd/db"
"github.com/lxc/lxd/lxd/project"
"github.com/lxc/lxd/lxd/state"
+ driver "github.com/lxc/lxd/lxd/storage"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
"github.com/lxc/lxd/shared/logger"
@@ -58,7 +59,7 @@ func (s *storageLvm) lvExtend(lvPath string, lvSize int64, fsType string, fsMntP
`volume type %d`, volumeType)
}
- return growFileSystem(fsType, lvPath, fsMntPoint)
+ return driver.GrowFileSystem(fsType, lvPath, fsMntPoint)
}
func (s *storageLvm) lvReduce(lvPath string, lvSize int64, fsType string, fsMntPoint string, volumeType int, data interface{}) error {
@@ -331,7 +332,7 @@ func (s *storageLvm) copyContainerThinpool(target container, source container, r
}
}
- msg, err := fsGenerateNewUUID(LVFilesystem, containerLvDevPath)
+ msg, err := driver.FSGenerateNewUUID(LVFilesystem, containerLvDevPath)
if err != nil {
logger.Errorf("Failed to create new \"%s\" UUID for container \"%s\" on storage pool \"%s\": %s", LVFilesystem, containerName, s.pool.Name, msg)
return err
@@ -853,7 +854,7 @@ func lvmCreateLv(projectName, vgName string, thinPoolName string, lvName string,
fsPath := getLvmDevPath(projectName, vgName, volumeType, lvName)
- output, err = makeFSType(fsPath, lvFsType, nil)
+ output, err = driver.MakeFSType(fsPath, lvFsType, nil)
if err != nil {
logger.Errorf("Filesystem creation failed: %s", output)
return fmt.Errorf("Error making filesystem on image LV: %v", err)
@@ -1078,7 +1079,7 @@ func (s *storageLvm) copyVolumeThinpool(source string, target string, readOnly b
lvDevPath := getLvmDevPath("default", poolName, storagePoolVolumeAPIEndpointCustom, targetLvmName)
- msg, err := fsGenerateNewUUID(lvFsType, lvDevPath)
+ msg, err := driver.FSGenerateNewUUID(lvFsType, lvDevPath)
if err != nil {
logger.Errorf("Failed to create new UUID for filesystem \"%s\" for RBD storage volume \"%s\" on storage pool \"%s\": %s: %s", lvFsType, s.volume.Name, s.pool.Name, msg, err)
return err
diff --git a/lxd/storage_pools_utils.go b/lxd/storage_pools_utils.go
index 5b52dc5aa9..1831ea5970 100644
--- a/lxd/storage_pools_utils.go
+++ b/lxd/storage_pools_utils.go
@@ -7,6 +7,7 @@ import (
"github.com/lxc/lxd/lxd/db"
"github.com/lxc/lxd/lxd/state"
+ driver "github.com/lxc/lxd/lxd/storage"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/version"
)
@@ -41,7 +42,7 @@ func storagePoolUpdate(state *state.State, name, newDescription string, newConfi
}
}()
- changedConfig, userOnly := storageConfigDiff(oldConfig, newConfig)
+ changedConfig, userOnly := driver.ConfigDiff(oldConfig, newConfig)
// Apply config changes if there are any
if len(changedConfig) != 0 {
newWritable.Description = newDescription
@@ -191,15 +192,15 @@ func storagePoolDBCreate(s *state.State, poolName, poolDescription string, drive
return nil
}
-func storagePoolValidate(poolName string, driver string, config map[string]string) error {
+func storagePoolValidate(poolName string, driverName string, config map[string]string) error {
// Check if the storage pool name is valid.
- err := storageValidName(poolName)
+ err := driver.ValidName(poolName)
if err != nil {
return err
}
// Validate the requested storage pool configuration.
- err = storagePoolValidateConfig(poolName, driver, config, nil)
+ err = storagePoolValidateConfig(poolName, driverName, config, nil)
if err != nil {
return err
}
@@ -229,7 +230,7 @@ func storagePoolCreateInternal(state *state.State, poolName, poolDescription str
}
// This performs all non-db related work needed to create the pool.
-func doStoragePoolCreateInternal(state *state.State, poolName, poolDescription string, driver string, config map[string]string, isNotification bool) error {
+func doStoragePoolCreateInternal(state *state.State, poolName, poolDescription string, driverName string, config map[string]string, isNotification bool) error {
tryUndo := true
s, err := storagePoolInit(state, poolName)
if err != nil {
@@ -263,7 +264,7 @@ func doStoragePoolCreateInternal(state *state.State, poolName, poolDescription s
// callback. So diff the config here to see if something like this has
// happened.
postCreateConfig := s.GetStoragePoolWritable().Config
- configDiff, _ := storageConfigDiff(config, postCreateConfig)
+ configDiff, _ := driver.ConfigDiff(config, postCreateConfig)
if len(configDiff) > 0 {
// Create the database entry for the storage pool.
err = state.Cluster.StoragePoolUpdate(poolName, poolDescription, postCreateConfig)
diff --git a/lxd/storage_utils.go b/lxd/storage_utils.go
index 76daed4da1..fd4ecf11bd 100644
--- a/lxd/storage_utils.go
+++ b/lxd/storage_utils.go
@@ -2,326 +2,11 @@ package main
import (
"fmt"
- "os"
- "strings"
- "time"
- "golang.org/x/sys/unix"
-
- "github.com/lxc/lxd/lxd/db"
- "github.com/lxc/lxd/shared"
- "github.com/lxc/lxd/shared/api"
+ driver "github.com/lxc/lxd/lxd/storage"
"github.com/lxc/lxd/shared/logger"
)
-// Options for filesystem creation
-type mkfsOptions struct {
- label string
-}
-
-// Export the mount options map since we might find it useful in other parts of
-// LXD.
-type mountOptions struct {
- capture bool
- flag uintptr
-}
-
-var MountOptions = map[string]mountOptions{
- "async": {false, unix.MS_SYNCHRONOUS},
- "atime": {false, unix.MS_NOATIME},
- "bind": {true, unix.MS_BIND},
- "defaults": {true, 0},
- "dev": {false, unix.MS_NODEV},
- "diratime": {false, unix.MS_NODIRATIME},
- "dirsync": {true, unix.MS_DIRSYNC},
- "exec": {false, unix.MS_NOEXEC},
- "lazytime": {true, unix.MS_LAZYTIME},
- "mand": {true, unix.MS_MANDLOCK},
- "noatime": {true, unix.MS_NOATIME},
- "nodev": {true, unix.MS_NODEV},
- "nodiratime": {true, unix.MS_NODIRATIME},
- "noexec": {true, unix.MS_NOEXEC},
- "nomand": {false, unix.MS_MANDLOCK},
- "norelatime": {false, unix.MS_RELATIME},
- "nostrictatime": {false, unix.MS_STRICTATIME},
- "nosuid": {true, unix.MS_NOSUID},
- "rbind": {true, unix.MS_BIND | unix.MS_REC},
- "relatime": {true, unix.MS_RELATIME},
- "remount": {true, unix.MS_REMOUNT},
- "ro": {true, unix.MS_RDONLY},
- "rw": {false, unix.MS_RDONLY},
- "strictatime": {true, unix.MS_STRICTATIME},
- "suid": {false, unix.MS_NOSUID},
- "sync": {true, unix.MS_SYNCHRONOUS},
-}
-
-func lxdResolveMountoptions(options string) (uintptr, string) {
- mountFlags := uintptr(0)
- tmp := strings.SplitN(options, ",", -1)
- for i := 0; i < len(tmp); i++ {
- opt := tmp[i]
- do, ok := MountOptions[opt]
- if !ok {
- continue
- }
-
- if do.capture {
- mountFlags |= do.flag
- } else {
- mountFlags &= ^do.flag
- }
-
- copy(tmp[i:], tmp[i+1:])
- tmp[len(tmp)-1] = ""
- tmp = tmp[:len(tmp)-1]
- i--
- }
-
- return mountFlags, strings.Join(tmp, ",")
-}
-
-// Useful functions for unreliable backends
-func tryMount(src string, dst string, fs string, flags uintptr, options string) error {
- var err error
-
- for i := 0; i < 20; i++ {
- err = unix.Mount(src, dst, fs, flags, options)
- if err == nil {
- break
- }
-
- time.Sleep(500 * time.Millisecond)
- }
-
- if err != nil {
- return err
- }
-
- return nil
-}
-
-func tryUnmount(path string, flags int) error {
- var err error
-
- for i := 0; i < 20; i++ {
- err = unix.Unmount(path, flags)
- if err == nil {
- break
- }
-
- time.Sleep(500 * time.Millisecond)
- }
-
- if err != nil {
- return err
- }
-
- return nil
-}
-
-func storageValidName(value string) error {
- if strings.Contains(value, "/") {
- return fmt.Errorf("Invalid storage volume name \"%s\". Storage volumes cannot contain \"/\" in their name", value)
- }
-
- return nil
-}
-
-func storageConfigDiff(oldConfig map[string]string, newConfig map[string]string) ([]string, bool) {
- changedConfig := []string{}
- userOnly := true
- for key := range oldConfig {
- if oldConfig[key] != newConfig[key] {
- if !strings.HasPrefix(key, "user.") {
- userOnly = false
- }
-
- if !shared.StringInSlice(key, changedConfig) {
- changedConfig = append(changedConfig, key)
- }
- }
- }
-
- for key := range newConfig {
- if oldConfig[key] != newConfig[key] {
- if !strings.HasPrefix(key, "user.") {
- userOnly = false
- }
-
- if !shared.StringInSlice(key, changedConfig) {
- changedConfig = append(changedConfig, key)
- }
- }
- }
-
- // Skip on no change
- if len(changedConfig) == 0 {
- return nil, false
- }
-
- return changedConfig, userOnly
-}
-
-// Default permissions for folders in ${LXD_DIR}
-const storagePoolsDirMode os.FileMode = 0711
-const containersDirMode os.FileMode = 0711
-const customDirMode os.FileMode = 0711
-const imagesDirMode os.FileMode = 0700
-const snapshotsDirMode os.FileMode = 0700
-
-// Detect whether LXD already uses the given storage pool.
-func lxdUsesPool(dbObj *db.Cluster, onDiskPoolName string, driver string, onDiskProperty string) (bool, string, error) {
- pools, err := dbObj.StoragePools()
- if err != nil && err != db.ErrNoSuchObject {
- return false, "", err
- }
-
- for _, pool := range pools {
- _, pl, err := dbObj.StoragePoolGet(pool)
- if err != nil {
- continue
- }
-
- if pl.Driver != driver {
- continue
- }
-
- if pl.Config[onDiskProperty] == onDiskPoolName {
- return true, pl.Name, nil
- }
- }
-
- return false, "", nil
-}
-
-func makeFSType(path string, fsType string, options *mkfsOptions) (string, error) {
- var err error
- var msg string
-
- fsOptions := options
- if fsOptions == nil {
- fsOptions = &mkfsOptions{}
- }
-
- cmd := []string{fmt.Sprintf("mkfs.%s", fsType), path}
- if fsOptions.label != "" {
- cmd = append(cmd, "-L", fsOptions.label)
- }
-
- if fsType == "ext4" {
- cmd = append(cmd, "-E", "nodiscard,lazy_itable_init=0,lazy_journal_init=0")
- }
-
- msg, err = shared.TryRunCommand(cmd[0], cmd[1:]...)
- if err != nil {
- return msg, err
- }
-
- return "", nil
-}
-
-func fsGenerateNewUUID(fstype string, lvpath string) (string, error) {
- switch fstype {
- case "btrfs":
- return btrfsGenerateNewUUID(lvpath)
- case "xfs":
- return xfsGenerateNewUUID(lvpath)
- }
-
- return "", nil
-}
-
-func xfsGenerateNewUUID(devPath string) (string, error) {
- // Attempt to generate a new UUID
- msg, err := shared.RunCommand("xfs_admin", "-U", "generate", devPath)
- if err != nil {
- return msg, err
- }
-
- if msg != "" {
- // Exit 0 with a msg usually means some log entry getting in the way
- msg, err = shared.RunCommand("xfs_repair", "-o", "force_geometry", "-L", devPath)
- if err != nil {
- return msg, err
- }
-
- // Attempt to generate a new UUID again
- msg, err = shared.RunCommand("xfs_admin", "-U", "generate", devPath)
- if err != nil {
- return msg, err
- }
- }
-
- return msg, nil
-}
-
-func btrfsGenerateNewUUID(lvpath string) (string, error) {
- msg, err := shared.RunCommand(
- "btrfstune",
- "-f",
- "-u",
- lvpath)
- if err != nil {
- return msg, err
- }
-
- return msg, nil
-}
-
-func growFileSystem(fsType string, devPath string, mntpoint string) error {
- var msg string
- var err error
- switch fsType {
- case "": // if not specified, default to ext4
- fallthrough
- case "ext4":
- msg, err = shared.TryRunCommand("resize2fs", devPath)
- case "xfs":
- msg, err = shared.TryRunCommand("xfs_growfs", devPath)
- case "btrfs":
- msg, err = shared.TryRunCommand("btrfs", "filesystem", "resize", "max", mntpoint)
- default:
- return fmt.Errorf(`Growing not supported for filesystem type "%s"`, fsType)
- }
-
- if err != nil {
- errorMsg := fmt.Sprintf(`Could not extend underlying %s filesystem for "%s": %s`, fsType, devPath, msg)
- logger.Errorf(errorMsg)
- return fmt.Errorf(errorMsg)
- }
-
- logger.Debugf(`extended underlying %s filesystem for "%s"`, fsType, devPath)
- return nil
-}
-
-func shrinkFileSystem(fsType string, devPath string, mntpoint string, byteSize int64) error {
- strSize := fmt.Sprintf("%dK", byteSize/1024)
-
- switch fsType {
- case "": // if not specified, default to ext4
- fallthrough
- case "ext4":
- _, err := shared.TryRunCommand("e2fsck", "-f", "-y", devPath)
- if err != nil {
- return err
- }
-
- _, err = shared.TryRunCommand("resize2fs", devPath, strSize)
- if err != nil {
- return err
- }
- case "btrfs":
- _, err := shared.TryRunCommand("btrfs", "filesystem", "resize", strSize, mntpoint)
- if err != nil {
- return err
- }
- default:
- return fmt.Errorf(`Shrinking not supported for filesystem type "%s"`, fsType)
- }
-
- return nil
-}
-
func shrinkVolumeFilesystem(s storage, volumeType int, fsType string, devPath string, mntpoint string, byteSize int64, data interface{}) (func() (bool, error), error) {
var cleanupFunc func() (bool, error)
switch fsType {
@@ -359,26 +44,6 @@ func shrinkVolumeFilesystem(s storage, volumeType int, fsType string, devPath st
return nil, fmt.Errorf(`Shrinking not supported for filesystem type "%s"`, fsType)
}
- err := shrinkFileSystem(fsType, devPath, mntpoint, byteSize)
+ err := driver.ShrinkFileSystem(fsType, devPath, mntpoint, byteSize)
return cleanupFunc, err
}
-
-func storageResource(path string) (*api.ResourcesStoragePool, error) {
- st, err := shared.Statvfs(path)
- if err != nil {
- return nil, err
- }
-
- res := api.ResourcesStoragePool{}
- res.Space.Total = st.Blocks * uint64(st.Bsize)
- res.Space.Used = (st.Blocks - st.Bfree) * uint64(st.Bsize)
-
- // Some filesystems don't report inodes since they allocate them
- // dynamically e.g. btrfs.
- if st.Files > 0 {
- res.Inodes.Total = st.Files
- res.Inodes.Used = st.Files - st.Ffree
- }
-
- return &res, nil
-}
diff --git a/lxd/storage_volumes_snapshot.go b/lxd/storage_volumes_snapshot.go
index 8e87a6e925..6de54b156b 100644
--- a/lxd/storage_volumes_snapshot.go
+++ b/lxd/storage_volumes_snapshot.go
@@ -9,6 +9,7 @@ import (
"github.com/gorilla/mux"
"github.com/lxc/lxd/lxd/db"
+ driver "github.com/lxc/lxd/lxd/storage"
"github.com/lxc/lxd/lxd/util"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
@@ -66,7 +67,7 @@ func storagePoolVolumeSnapshotsTypePost(d *Daemon, r *http.Request) Response {
}
// Validate the name
- err = storageValidName(req.Name)
+ err = driver.ValidName(req.Name)
if err != nil {
return BadRequest(err)
}
diff --git a/lxd/storage_zfs.go b/lxd/storage_zfs.go
index d98f530956..cabdc2f993 100644
--- a/lxd/storage_zfs.go
+++ b/lxd/storage_zfs.go
@@ -273,14 +273,14 @@ func (s *storageZfs) zfsPoolCreate() error {
}
fixperms := shared.VarPath("storage-pools", s.pool.Name, "containers")
- err = os.MkdirAll(fixperms, containersDirMode)
+ err = os.MkdirAll(fixperms, driver.ContainersDirMode)
if err != nil && !os.IsNotExist(err) {
return err
}
- err = os.Chmod(fixperms, containersDirMode)
+ err = os.Chmod(fixperms, driver.ContainersDirMode)
if err != nil {
- logger.Warnf("Failed to chmod \"%s\" to \"0%s\": %s", fixperms, strconv.FormatInt(int64(containersDirMode), 8), err)
+ logger.Warnf("Failed to chmod \"%s\" to \"0%s\": %s", fixperms, strconv.FormatInt(int64(driver.ContainersDirMode), 8), err)
}
dataset = fmt.Sprintf("%s/images", poolName)
@@ -291,13 +291,13 @@ func (s *storageZfs) zfsPoolCreate() error {
}
fixperms = shared.VarPath("storage-pools", s.pool.Name, "images")
- err = os.MkdirAll(fixperms, imagesDirMode)
+ err = os.MkdirAll(fixperms, driver.ImagesDirMode)
if err != nil && !os.IsNotExist(err) {
return err
}
- err = os.Chmod(fixperms, imagesDirMode)
+ err = os.Chmod(fixperms, driver.ImagesDirMode)
if err != nil {
- logger.Warnf("Failed to chmod \"%s\" to \"0%s\": %s", fixperms, strconv.FormatInt(int64(imagesDirMode), 8), err)
+ logger.Warnf("Failed to chmod \"%s\" to \"0%s\": %s", fixperms, strconv.FormatInt(int64(driver.ImagesDirMode), 8), err)
}
dataset = fmt.Sprintf("%s/custom", poolName)
@@ -308,13 +308,13 @@ func (s *storageZfs) zfsPoolCreate() error {
}
fixperms = shared.VarPath("storage-pools", s.pool.Name, "custom")
- err = os.MkdirAll(fixperms, customDirMode)
+ err = os.MkdirAll(fixperms, driver.CustomDirMode)
if err != nil && !os.IsNotExist(err) {
return err
}
- err = os.Chmod(fixperms, customDirMode)
+ err = os.Chmod(fixperms, driver.CustomDirMode)
if err != nil {
- logger.Warnf("Failed to chmod \"%s\" to \"0%s\": %s", fixperms, strconv.FormatInt(int64(customDirMode), 8), err)
+ logger.Warnf("Failed to chmod \"%s\" to \"0%s\": %s", fixperms, strconv.FormatInt(int64(driver.CustomDirMode), 8), err)
}
dataset = fmt.Sprintf("%s/deleted", poolName)
@@ -332,13 +332,13 @@ func (s *storageZfs) zfsPoolCreate() error {
}
fixperms = shared.VarPath("storage-pools", s.pool.Name, "containers-snapshots")
- err = os.MkdirAll(fixperms, snapshotsDirMode)
+ err = os.MkdirAll(fixperms, driver.SnapshotsDirMode)
if err != nil && !os.IsNotExist(err) {
return err
}
- err = os.Chmod(fixperms, snapshotsDirMode)
+ err = os.Chmod(fixperms, driver.SnapshotsDirMode)
if err != nil {
- logger.Warnf("Failed to chmod \"%s\" to \"0%s\": %s", fixperms, strconv.FormatInt(int64(snapshotsDirMode), 8), err)
+ logger.Warnf("Failed to chmod \"%s\" to \"0%s\": %s", fixperms, strconv.FormatInt(int64(driver.SnapshotsDirMode), 8), err)
}
dataset = fmt.Sprintf("%s/custom-snapshots", poolName)
@@ -349,13 +349,13 @@ func (s *storageZfs) zfsPoolCreate() error {
}
fixperms = shared.VarPath("storage-pools", s.pool.Name, "custom-snapshots")
- err = os.MkdirAll(fixperms, snapshotsDirMode)
+ err = os.MkdirAll(fixperms, driver.SnapshotsDirMode)
if err != nil && !os.IsNotExist(err) {
return err
}
- err = os.Chmod(fixperms, snapshotsDirMode)
+ err = os.Chmod(fixperms, driver.SnapshotsDirMode)
if err != nil {
- logger.Warnf("Failed to chmod \"%s\" to \"0%s\": %s", fixperms, strconv.FormatInt(int64(snapshotsDirMode), 8), err)
+ logger.Warnf("Failed to chmod \"%s\" to \"0%s\": %s", fixperms, strconv.FormatInt(int64(driver.SnapshotsDirMode), 8), err)
}
return nil
diff --git a/lxd/storage_zfs_utils.go b/lxd/storage_zfs_utils.go
index 7e42cab87c..6bd0403d59 100644
--- a/lxd/storage_zfs_utils.go
+++ b/lxd/storage_zfs_utils.go
@@ -14,6 +14,7 @@ import (
"golang.org/x/sys/unix"
"github.com/lxc/lxd/lxd/project"
+ driver "github.com/lxc/lxd/lxd/storage"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/logger"
)
@@ -519,7 +520,7 @@ func zfsUmount(poolName string, path string, mountpoint string) error {
fmt.Sprintf("%s/%s", poolName, path))
if err != nil {
logger.Warnf("Failed to unmount ZFS filesystem via zfs unmount: %s. Trying lazy umount (MNT_DETACH)...", output)
- err := tryUnmount(mountpoint, unix.MNT_DETACH)
+ err := driver.TryUnmount(mountpoint, unix.MNT_DETACH)
if err != nil {
logger.Warnf("Failed to unmount ZFS filesystem via lazy umount (MNT_DETACH)...")
return err
@@ -682,7 +683,7 @@ func (s *storageZfs) doContainerMount(projectName, name string, privileged bool)
if !shared.IsMountPoint(containerPoolVolumeMntPoint) {
source := fmt.Sprintf("%s/%s", s.getOnDiskPoolName(), fs)
zfsMountOptions := fmt.Sprintf("rw,zfsutil,mntpoint=%s", containerPoolVolumeMntPoint)
- mounterr := tryMount(source, containerPoolVolumeMntPoint, "zfs", 0, zfsMountOptions)
+ mounterr := driver.TryMount(source, containerPoolVolumeMntPoint, "zfs", 0, zfsMountOptions)
if mounterr != nil {
if mounterr != unix.EBUSY {
logger.Errorf("Failed to mount ZFS dataset \"%s\" onto \"%s\": %v", source, containerPoolVolumeMntPoint, mounterr)
From 30ac4707cec720a8f3b25b3558f37295a35b2061 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Thu, 15 Aug 2019 15:17:01 +0200
Subject: [PATCH 4/4] test: Lint storage package
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
test/suites/static_analysis.sh | 1 +
1 file changed, 1 insertion(+)
diff --git a/test/suites/static_analysis.sh b/test/suites/static_analysis.sh
index 1c601e9019..cd2da54018 100644
--- a/test/suites/static_analysis.sh
+++ b/test/suites/static_analysis.sh
@@ -82,6 +82,7 @@ test_static_analysis() {
#golint -set_exit_status lxd/migration
golint -set_exit_status lxd/node
golint -set_exit_status lxd/state
+ golint -set_exit_status lxd/storage
golint -set_exit_status lxd/sys
golint -set_exit_status lxd/task
golint -set_exit_status lxd/template
More information about the lxc-devel
mailing list