[lxc-devel] [lxd/master] Storage LVM utils - create pool

tomponline on Github lxc-bot at linuxcontainers.org
Tue Dec 17 11:35:19 UTC 2019


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 412 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20191217/81580585/attachment-0001.bin>
-------------- next part --------------
From d8097a52c38000d7ec4d2b65889fb5b04926997c Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Fri, 13 Dec 2019 11:40:08 +0000
Subject: [PATCH 01/18] lxd/storage/drivers/interface: Comments on pool
 mount/unmount definitions

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage/drivers/interface.go | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/lxd/storage/drivers/interface.go b/lxd/storage/drivers/interface.go
index c5f7d063ec..1ecc052068 100644
--- a/lxd/storage/drivers/interface.go
+++ b/lxd/storage/drivers/interface.go
@@ -28,7 +28,12 @@ type Driver interface {
 	// Pool.
 	Create() error
 	Delete(op *operations.Operation) error
+	// Mount mounts a storage pool if needed, returns true if we caused a new mount, false if
+	// already mounted.
 	Mount() (bool, error)
+
+	// Unmount unmounts a storage pool if needed, returns true if unmounted, false if was not
+	// mounted.
 	Unmount() (bool, error)
 	GetResources() (*api.ResourcesStoragePool, error)
 	Validate(config map[string]string) error

From e2f4052dcf7242716f61dc7dfbc54229fc4ee886 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Fri, 13 Dec 2019 14:13:29 +0000
Subject: [PATCH 02/18] shared/util: Adds comment to TryRunCommand

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 shared/util.go | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/shared/util.go b/shared/util.go
index e307f985fe..0a80f5dd7e 100644
--- a/shared/util.go
+++ b/shared/util.go
@@ -861,6 +861,8 @@ func RunCommandWithFds(stdin io.Reader, stdout io.Writer, name string, arg ...st
 	return nil
 }
 
+// TryRunCommand runs the specified command up to 20 times with a 500ms delay between each call
+// until it runs without an error. If after 20 times it is still failing then returns the error.
 func TryRunCommand(name string, arg ...string) (string, error) {
 	var err error
 	var output string

From c399ff35a6d226088a3e4ef7b1d0b66b845afab7 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 17 Dec 2019 11:22:34 +0000
Subject: [PATCH 03/18] lxd/storage/drivers/utils/lvm: Adds LVM util functions
 for creating pools

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage/drivers/utils_lvm.go | 262 +++++++++++++++++++++++++++++++
 1 file changed, 262 insertions(+)
 create mode 100644 lxd/storage/drivers/utils_lvm.go

diff --git a/lxd/storage/drivers/utils_lvm.go b/lxd/storage/drivers/utils_lvm.go
new file mode 100644
index 0000000000..e9f1088e72
--- /dev/null
+++ b/lxd/storage/drivers/utils_lvm.go
@@ -0,0 +1,262 @@
+package drivers
+
+import (
+	"fmt"
+	"os/exec"
+	"strconv"
+	"strings"
+	"syscall"
+
+	"github.com/lxc/lxd/lxd/project"
+	"github.com/lxc/lxd/shared"
+	"github.com/lxc/lxd/shared/units"
+	"github.com/lxc/lxd/shared/version"
+)
+
+// LVMPysicalVolumeExists checks if an LVM Physical Volume exists.
+func LVMPysicalVolumeExists(pvName string) (bool, error) {
+	_, err := shared.RunCommand("pvs", "--noheadings", "-o", "lv_attr", pvName)
+	if err != nil {
+		runErr, ok := err.(shared.RunError)
+		if ok {
+			exitError, ok := runErr.Err.(*exec.ExitError)
+			if ok {
+				waitStatus := exitError.Sys().(syscall.WaitStatus)
+				if waitStatus.ExitStatus() == 5 {
+					// physical volume not found
+					return false, nil
+				}
+			}
+		}
+		return false, fmt.Errorf("error checking for physical volume \"%s\"", pvName)
+	}
+
+	return true, nil
+}
+
+// LVMVolumeGroupExists checks if an LVM Volume Group exists.
+func LVMVolumeGroupExists(vgName string) (bool, error) {
+	_, err := shared.RunCommand("vgs", "--noheadings", "-o", "lv_attr", vgName)
+	if err != nil {
+		runErr, ok := err.(shared.RunError)
+		if ok {
+			exitError, ok := runErr.Err.(*exec.ExitError)
+			if ok {
+				waitStatus := exitError.Sys().(syscall.WaitStatus)
+				if waitStatus.ExitStatus() == 5 {
+					// volume group not found
+					return false, nil
+				}
+			}
+		}
+
+		return false, fmt.Errorf("error checking for volume group \"%s\"", vgName)
+	}
+
+	return true, nil
+}
+
+// LVMGetLVCount gets the count of volumes in a volume group.
+func LVMGetLVCount(vgName string) (int, error) {
+	output, err := shared.TryRunCommand("vgs", "--noheadings", "-o", "lv_count", vgName)
+	if err != nil {
+		return -1, err
+	}
+
+	output = strings.TrimSpace(output)
+	return strconv.Atoi(output)
+}
+
+// LVMThinpoolExists checks whether the specified thinpool exists in a volume group.
+func LVMThinpoolExists(vgName string, poolName string) (bool, error) {
+	output, err := shared.RunCommand("vgs", "--noheadings", "-o", "lv_attr", fmt.Sprintf("%s/%s", vgName, poolName))
+	if err != nil {
+		runErr, ok := err.(shared.RunError)
+		if ok {
+			exitError, ok := runErr.Err.(*exec.ExitError)
+			if ok {
+				waitStatus := exitError.Sys().(syscall.WaitStatus)
+				if waitStatus.ExitStatus() == 5 {
+					// pool LV was not found
+					return false, nil
+				}
+			}
+		}
+
+		return false, fmt.Errorf("error checking for pool \"%s\"", poolName)
+	}
+	// Found LV named poolname, check type:
+	attrs := strings.TrimSpace(string(output[:]))
+	if strings.HasPrefix(attrs, "t") {
+		return true, nil
+	}
+
+	return false, fmt.Errorf("pool named \"%s\" exists but is not a thin pool", poolName)
+}
+
+// LVMDevPath returns the path to the LVM volume device.
+func LVMDevPath(projectName, lvmPool string, volumeDBTypeName string, lvmVolume string) string {
+	lvmVolume = project.Prefix(projectName, lvmVolume)
+	if volumeDBTypeName == "" {
+		return fmt.Sprintf("/dev/%s/%s", lvmPool, lvmVolume)
+	}
+
+	return fmt.Sprintf("/dev/%s/%s_%s", lvmPool, volumeDBTypeName, lvmVolume)
+}
+
+// LVMVolumeExists checks whether the specified logical volume exists.
+func LVMVolumeExists(lvDevPath string) (bool, error) {
+	_, err := shared.RunCommand("lvs", "--noheadings", "-o", "lv_attr", lvDevPath)
+	if err != nil {
+		runErr, ok := err.(shared.RunError)
+		if ok {
+			exitError, ok := runErr.Err.(*exec.ExitError)
+			if ok {
+				waitStatus := exitError.Sys().(syscall.WaitStatus)
+				if waitStatus.ExitStatus() == 5 {
+					// logical volume not found.
+					return false, nil
+				}
+			}
+		}
+
+		return false, fmt.Errorf("error checking for logical volume \"%s\"", lvDevPath)
+	}
+
+	return true, nil
+}
+
+// LVMCreateThinpool creates a thin pool logical volume.
+func LVMCreateThinpool(lvmVersion string, vgName string, thinPoolName string) error {
+	exists, err := LVMThinpoolExists(vgName, thinPoolName)
+	if err != nil {
+		return err
+	}
+
+	if exists {
+		return nil
+	}
+
+	err = lvmCreateDefaultThinPool(lvmVersion, vgName, thinPoolName)
+	if err != nil {
+		return err
+	}
+
+	poolExists, err := LVMThinpoolExists(vgName, thinPoolName)
+	if err != nil {
+		return fmt.Errorf("Error checking for thin pool \"%s\" in \"%s\": %v", thinPoolName, vgName, err)
+	}
+
+	if !poolExists {
+		return fmt.Errorf("Thin pool \"'%s\" does not exist in Volume Group \"%s\"", thinPoolName, vgName)
+	}
+
+	return nil
+}
+
+func lvmCreateDefaultThinPool(lvmVersion string, vgName string, thinPoolName string) error {
+	isRecent, err := LVMVersionIsAtLeast(lvmVersion, "2.02.99")
+	if err != nil {
+		return fmt.Errorf("Error checking LVM version: %s", err)
+	}
+
+	// Create the thin pool
+	lvmThinPool := fmt.Sprintf("%s/%s", vgName, thinPoolName)
+	if isRecent {
+		_, err = shared.TryRunCommand(
+			"lvcreate",
+			"-Wy", "--yes",
+			"--poolmetadatasize", "1G",
+			"-l", "100%FREE",
+			"--thinpool", lvmThinPool)
+	} else {
+		_, err = shared.TryRunCommand(
+			"lvcreate",
+			"-Wy", "--yes",
+			"--poolmetadatasize", "1G",
+			"-L", "1G",
+			"--thinpool", lvmThinPool)
+	}
+
+	if err != nil {
+		return fmt.Errorf("Could not create LVM thin pool named %s: %v", thinPoolName, err)
+	}
+
+	if !isRecent {
+		// Grow it to the maximum VG size (two step process required by old LVM)
+		_, err = shared.TryRunCommand("lvextend", "--alloc", "anywhere", "-l", "100%FREE", lvmThinPool)
+
+		if err != nil {
+			return fmt.Errorf("Could not grow LVM thin pool named %s: %v", thinPoolName, err)
+		}
+	}
+
+	return nil
+}
+
+// LVMVersionIsAtLeast checks whether the installed version of LVM is at least the specific version.
+func LVMVersionIsAtLeast(sTypeVersion string, versionString string) (bool, error) {
+	lvmVersionString := strings.Split(sTypeVersion, "/")[0]
+
+	lvmVersion, err := version.Parse(lvmVersionString)
+	if err != nil {
+		return false, err
+	}
+
+	inVersion, err := version.Parse(versionString)
+	if err != nil {
+		return false, err
+	}
+
+	if lvmVersion.Compare(inVersion) < 0 {
+		return false, nil
+	}
+
+	return true, nil
+}
+
+// LVMCreateLogicalVolume creates a logical volume.
+func LVMCreateLogicalVolume(projectName, vgName string, thinPoolName string, lvName string, lvFsType string, lvSize string, volumeType string, makeThinLv bool) error {
+	var output string
+	var err error
+
+	// Round the size to closest 512 bytes
+	lvSizeInt, err := units.ParseByteSizeString(lvSize)
+	if err != nil {
+		return err
+	}
+
+	lvSizeInt = int64(lvSizeInt/512) * 512
+	lvSizeString := units.GetByteSizeString(lvSizeInt, 0)
+
+	lvmPoolVolumeName := lvmFullVolumeName(projectName, volumeType, lvName)
+	if makeThinLv {
+		targetVg := fmt.Sprintf("%s/%s", vgName, thinPoolName)
+		_, err = shared.TryRunCommand("lvcreate", "-Wy", "--yes", "--thin", "-n", lvmPoolVolumeName, "--virtualsize", lvSizeString, targetVg)
+	} else {
+		_, err = shared.TryRunCommand("lvcreate", "-Wy", "--yes", "-n", lvmPoolVolumeName, "--size", lvSizeString, vgName)
+	}
+	if err != nil {
+		return fmt.Errorf("Could not create thin LV named %s: %v", lvmPoolVolumeName, err)
+	}
+
+	fsPath := LVMDevPath(projectName, vgName, volumeType, lvName)
+
+	output, err = MakeFSType(fsPath, lvFsType, nil)
+	if err != nil {
+		return fmt.Errorf("Error making filesystem on image LV: %v (%s)", err, output)
+	}
+
+	return nil
+}
+
+// lvmFullVolumeName returns the logical volume's full name with project and volume type prefix.
+func lvmFullVolumeName(projectName, volumeType string, lvmVolume string) string {
+	storageName := project.Prefix(projectName, lvmVolume)
+
+	if volumeType != "" {
+		storageName = fmt.Sprintf("%s_%s", volumeType, storageName)
+	}
+
+	return storageName
+}

From a9a5f082446224da11f2ddace9486403ba7cf057 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 17 Dec 2019 11:23:02 +0000
Subject: [PATCH 04/18] lxd/api/internal: LVMVolumeExists usage

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/api_internal.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lxd/api_internal.go b/lxd/api_internal.go
index 4a5e8e6d3f..949f0a5e89 100644
--- a/lxd/api_internal.go
+++ b/lxd/api_internal.go
@@ -752,7 +752,7 @@ func internalImport(d *Daemon, r *http.Request) response.Response {
 			ctLvName := getLVName(poolName,
 				storagePoolVolumeAPIEndpointContainers,
 				ctLvmName)
-			exists, err := storageLVExists(ctLvName)
+			exists, err := storageDrivers.LVMVolumeExists(ctLvName)
 			if err != nil {
 				return response.InternalError(err)
 			}

From 03439cd6a3921a83f4942205805f2e64682f2e33 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 17 Dec 2019 11:23:36 +0000
Subject: [PATCH 05/18] lxd/patches: LVMVolumeExists usage

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/patches.go | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/lxd/patches.go b/lxd/patches.go
index 3049b08896..81826071f2 100644
--- a/lxd/patches.go
+++ b/lxd/patches.go
@@ -20,6 +20,7 @@ import (
 	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/rsync"
 	driver "github.com/lxc/lxd/lxd/storage"
+	storageDrivers "github.com/lxc/lxd/lxd/storage/drivers"
 	"github.com/lxc/lxd/shared"
 	log "github.com/lxc/lxd/shared/log15"
 	"github.com/lxc/lxd/shared/logger"
@@ -162,7 +163,7 @@ func patchRenameCustomVolumeLVs(name string, d *Daemon) error {
 			oldName := fmt.Sprintf("%s/custom_%s", vgName, volume)
 			newName := fmt.Sprintf("%s/custom_%s", vgName, containerNameToLVName(volume))
 
-			exists, err := storageLVExists(newName)
+			exists, err := storageDrivers.LVMVolumeExists(newName)
 			if err != nil {
 				return err
 			}

From 6c59543e1ccf81759b7582d1caeb4958bac55b65 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 17 Dec 2019 11:23:50 +0000
Subject: [PATCH 06/18] lxd/patches: LVMDevPath usage

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/patches.go | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/lxd/patches.go b/lxd/patches.go
index 81826071f2..c9bde13539 100644
--- a/lxd/patches.go
+++ b/lxd/patches.go
@@ -1109,7 +1109,7 @@ func upgradeFromStorageTypeLvm(name string, d *Daemon, defaultPoolName string, d
 		newContainerMntPoint := driver.GetContainerMountPoint("default", defaultPoolName, ct)
 		ctLvName := containerNameToLVName(ct)
 		newContainerLvName := fmt.Sprintf("%s_%s", storagePoolVolumeAPIEndpointContainers, ctLvName)
-		containerLvDevPath := getLvmDevPath("default", defaultPoolName, storagePoolVolumeAPIEndpointContainers, ctLvName)
+		containerLvDevPath := storageDrivers.LVMDevPath("default", defaultPoolName, storagePoolVolumeAPIEndpointContainers, ctLvName)
 		if !shared.PathExists(containerLvDevPath) {
 			oldLvDevPath := fmt.Sprintf("/dev/%s/%s", defaultPoolName, ctLvName)
 			// If the old LVM device path for the logical volume
@@ -1265,7 +1265,7 @@ func upgradeFromStorageTypeLvm(name string, d *Daemon, defaultPoolName string, d
 			// Make sure we use a valid lv name.
 			csLvName := containerNameToLVName(cs)
 			newSnapshotLvName := fmt.Sprintf("%s_%s", storagePoolVolumeAPIEndpointContainers, csLvName)
-			snapshotLvDevPath := getLvmDevPath("default", defaultPoolName, storagePoolVolumeAPIEndpointContainers, csLvName)
+			snapshotLvDevPath := storageDrivers.LVMDevPath("default", defaultPoolName, storagePoolVolumeAPIEndpointContainers, csLvName)
 			if !shared.PathExists(snapshotLvDevPath) {
 				oldLvDevPath := fmt.Sprintf("/dev/%s/%s", defaultPoolName, csLvName)
 				if shared.PathExists(oldLvDevPath) {
@@ -1445,7 +1445,7 @@ func upgradeFromStorageTypeLvm(name string, d *Daemon, defaultPoolName string, d
 
 		// Rename the logical volume device.
 		newImageLvName := fmt.Sprintf("%s_%s", storagePoolVolumeAPIEndpointImages, img)
-		imageLvDevPath := getLvmDevPath("default", defaultPoolName, storagePoolVolumeAPIEndpointImages, img)
+		imageLvDevPath := storageDrivers.LVMDevPath("default", defaultPoolName, storagePoolVolumeAPIEndpointImages, img)
 		oldLvDevPath := fmt.Sprintf("/dev/%s/%s", defaultPoolName, img)
 		// Only create logical volumes for images that have a logical
 		// volume on the pre-storage-api LXD instance. If not, we don't
@@ -2422,7 +2422,7 @@ func patchStorageApiDetectLVSize(name string, d *Daemon) error {
 			// exist in the db, so it's safe to ignore the error.
 			volumeTypeApiEndpoint, _ := storagePoolVolumeTypeNameToAPIEndpoint(volume.Type)
 			lvmName := containerNameToLVName(volume.Name)
-			lvmLvDevPath := getLvmDevPath("default", poolName, volumeTypeApiEndpoint, lvmName)
+			lvmLvDevPath := storageDrivers.LVMDevPath("default", poolName, volumeTypeApiEndpoint, lvmName)
 			size, err := lvmGetLVSize(lvmLvDevPath)
 			if err != nil {
 				logger.Errorf("Failed to detect size of logical volume: %s", err)

From e0ba747e5de9fedbad78e1da1a4c755c94430f41 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 17 Dec 2019 11:25:57 +0000
Subject: [PATCH 07/18] lxd/storage/lvm: LVMVolumeGroupExists usage

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage_lvm.go | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/lxd/storage_lvm.go b/lxd/storage_lvm.go
index e4cab25c5e..0224323299 100644
--- a/lxd/storage_lvm.go
+++ b/lxd/storage_lvm.go
@@ -95,7 +95,7 @@ func (s *storageLvm) StoragePoolInit() error {
 	}
 
 	if source != "" && !filepath.IsAbs(source) {
-		ok, err := storageVGExists(source)
+		ok, err := drivers.LVMVolumeGroupExists(source)
 		if err != nil {
 			// Internal error.
 			return err
@@ -210,7 +210,7 @@ func (s *storageLvm) StoragePoolCreate() error {
 		}
 
 		// Check if the volume group already exists.
-		vgExisted, globalErr = storageVGExists(poolName)
+		vgExisted, globalErr = drivers.LVMVolumeGroupExists(poolName)
 		if globalErr != nil {
 			return globalErr
 		}
@@ -236,7 +236,7 @@ func (s *storageLvm) StoragePoolCreate() error {
 			}
 
 			// Check if the volume group already exists.
-			vgExisted, globalErr = storageVGExists(poolName)
+			vgExisted, globalErr = drivers.LVMVolumeGroupExists(poolName)
 			if globalErr != nil {
 				return globalErr
 			}
@@ -252,7 +252,7 @@ func (s *storageLvm) StoragePoolCreate() error {
 			s.pool.Config["lvm.vg_name"] = vgName
 			s.vgName = vgName
 
-			vgExisted, globalErr = storageVGExists(vgName)
+			vgExisted, globalErr = drivers.LVMVolumeGroupExists(vgName)
 			if globalErr != nil {
 				return globalErr
 			}
@@ -359,15 +359,15 @@ func (s *storageLvm) StoragePoolDelete() error {
 	}
 
 	poolName := s.getOnDiskPoolName()
-	poolExists, _ := storageVGExists(poolName)
+	poolExists, _ := drivers.LVMVolumeGroupExists(poolName)
 
 	// Delete the thinpool.
 	if s.useThinpool && poolExists {
 		// Check that the thinpool actually exists. For example, it
 		// won't when the user has never created a storage volume in the
 		// storage pool.
-		devPath := getLvmDevPath("default", poolName, "", s.thinPoolName)
-		ok, _ := storageLVExists(devPath)
+		devPath := drivers.LVMDevPath("default", poolName, "", s.thinPoolName)
+		ok, _ := drivers.LVMVolumeExists(devPath)
 		if ok {
 			msg, err := shared.TryRunCommand("lvremove", "-f", devPath)
 			if err != nil {

From e9b7a66bc9614f7a811b29e58cb902e431c3e2e1 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 17 Dec 2019 11:26:36 +0000
Subject: [PATCH 08/18] lxd/storage/lvm: LVMPysicalVolumeExists usage

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage_lvm.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lxd/storage_lvm.go b/lxd/storage_lvm.go
index 0224323299..c629987a6c 100644
--- a/lxd/storage_lvm.go
+++ b/lxd/storage_lvm.go
@@ -204,7 +204,7 @@ func (s *storageLvm) StoragePoolCreate() error {
 
 		// Check if the physical volume already exists.
 		pvName = s.loopInfo.Name()
-		pvExisted, globalErr = storagePVExists(pvName)
+		pvExisted, globalErr = drivers.LVMPysicalVolumeExists(pvName)
 		if globalErr != nil {
 			return globalErr
 		}
@@ -230,7 +230,7 @@ func (s *storageLvm) StoragePoolCreate() error {
 			s.pool.Config["source"] = poolName
 
 			// Check if the physical volume already exists.
-			pvExisted, globalErr = storagePVExists(pvName)
+			pvExisted, globalErr = drivers.LVMPysicalVolumeExists(pvName)
 			if globalErr != nil {
 				return globalErr
 			}

From e624ff5450fecea8aa807e779a04bd95b18d6a45 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 17 Dec 2019 11:27:13 +0000
Subject: [PATCH 09/18] lxd/storage/lvm: LVMGetLVCount usage

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage_lvm.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lxd/storage_lvm.go b/lxd/storage_lvm.go
index c629987a6c..044f77d98a 100644
--- a/lxd/storage_lvm.go
+++ b/lxd/storage_lvm.go
@@ -285,7 +285,7 @@ func (s *storageLvm) StoragePoolCreate() error {
 	if vgExisted {
 		// Check that the volume group is empty.
 		// Otherwise we will refuse to use it.
-		count, err := lvmGetLVCount(poolName)
+		count, err := drivers.LVMGetLVCount(poolName)
 		if err != nil {
 			logger.Errorf("Failed to determine whether the volume group \"%s\" is empty", poolName)
 			return err
@@ -381,7 +381,7 @@ func (s *storageLvm) StoragePoolDelete() error {
 	// assume that other users are using the volume group, so don't remove
 	// it. This actually goes against policy since we explicitly state: our
 	// pool, and nothing but our pool but still, let's not hurt users.
-	count, err := lvmGetLVCount(poolName)
+	count, err := drivers.LVMGetLVCount(poolName)
 	if err != nil {
 		return err
 	}

From 7aff5a90fa0904e2da23255c09cb31d7ebd0407b Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 17 Dec 2019 11:28:00 +0000
Subject: [PATCH 10/18] lxd/storage/lvm: LVMThinpoolExists usage

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage_lvm.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lxd/storage_lvm.go b/lxd/storage_lvm.go
index 044f77d98a..f3a169c4e8 100644
--- a/lxd/storage_lvm.go
+++ b/lxd/storage_lvm.go
@@ -297,7 +297,7 @@ func (s *storageLvm) StoragePoolCreate() error {
 		}
 
 		if count > 0 && s.useThinpool {
-			ok, err := storageLVMThinpoolExists(poolName, s.thinPoolName)
+			ok, err := drivers.LVMThinpoolExists(poolName, s.thinPoolName)
 			if err != nil {
 				logger.Errorf("Failed to determine whether thinpool \"%s\" exists in volume group \"%s\": %s", poolName, s.thinPoolName, err)
 				return err

From 8b6704a10826479c52f131e22b097d4f817bc1ef Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 17 Dec 2019 11:28:44 +0000
Subject: [PATCH 11/18] lxd/storage/lvm: LVMCreateThinpool usage

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage_lvm.go | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/lxd/storage_lvm.go b/lxd/storage_lvm.go
index f3a169c4e8..122e2689fd 100644
--- a/lxd/storage_lvm.go
+++ b/lxd/storage_lvm.go
@@ -508,7 +508,7 @@ func (s *storageLvm) StoragePoolVolumeCreate() error {
 	}
 
 	if s.useThinpool {
-		err = lvmCreateThinpool(s.s, s.sTypeVersion, poolName, thinPoolName, lvFsType)
+		err = drivers.LVMCreateThinpool(s.sTypeVersion, poolName, thinPoolName)
 		if err != nil {
 			return err
 		}
@@ -1833,7 +1833,7 @@ func (s *storageLvm) doContainerBackupLoad(projectName, containerName string, pr
 
 	poolName := s.getOnDiskPoolName()
 	if s.useThinpool {
-		err = lvmCreateThinpool(s.s, s.sTypeVersion, poolName, thinPoolName, lvFsType)
+		err = drivers.LVMCreateThinpool(s.sTypeVersion, poolName, thinPoolName)
 		if err != nil {
 			return "", err
 		}
@@ -1921,7 +1921,7 @@ func (s *storageLvm) ImageCreate(fingerprint string, tracker *ioprogress.Progres
 	}()
 
 	if s.useThinpool {
-		err = lvmCreateThinpool(s.s, s.sTypeVersion, poolName, thinPoolName, lvFsType)
+		err = drivers.LVMCreateThinpool(s.sTypeVersion, poolName, thinPoolName)
 		if err != nil {
 			return err
 		}

From 5844672725204ad398d2ecb656a7a19ba4ea69d0 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 17 Dec 2019 11:29:22 +0000
Subject: [PATCH 12/18] lxd/storage/lvm: LVMCreateLogicalVolume usage

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage_lvm.go | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/lxd/storage_lvm.go b/lxd/storage_lvm.go
index 122e2689fd..19c53c67e9 100644
--- a/lxd/storage_lvm.go
+++ b/lxd/storage_lvm.go
@@ -514,7 +514,7 @@ func (s *storageLvm) StoragePoolVolumeCreate() error {
 		}
 	}
 
-	err = lvmCreateLv("default", poolName, thinPoolName, volumeLvmName, lvFsType, lvSize, volumeType, s.useThinpool)
+	err = drivers.LVMCreateLogicalVolume("default", poolName, thinPoolName, volumeLvmName, lvFsType, lvSize, volumeType, s.useThinpool)
 	if err != nil {
 		return fmt.Errorf("Error Creating LVM LV for new image: %v", err)
 	}
@@ -950,13 +950,13 @@ func (s *storageLvm) ContainerCreate(container instance.Instance) error {
 
 	poolName := s.getOnDiskPoolName()
 	if s.useThinpool {
-		err = lvmCreateThinpool(s.s, s.sTypeVersion, poolName, thinPoolName, lvFsType)
+		err = drivers.LVMCreateThinpool(s.sTypeVersion, poolName, thinPoolName)
 		if err != nil {
 			return err
 		}
 	}
 
-	err = lvmCreateLv(container.Project(), poolName, thinPoolName, containerLvmName, lvFsType, lvSize, storagePoolVolumeAPIEndpointContainers, s.useThinpool)
+	err = drivers.LVMCreateLogicalVolume(container.Project(), poolName, thinPoolName, containerLvmName, lvFsType, lvSize, storagePoolVolumeAPIEndpointContainers, s.useThinpool)
 	if err != nil {
 		return err
 	}
@@ -1840,7 +1840,7 @@ func (s *storageLvm) doContainerBackupLoad(projectName, containerName string, pr
 	}
 
 	if !snapshot {
-		err = lvmCreateLv(projectName, poolName, thinPoolName, containerLvmName, lvFsType, lvSize,
+		err = drivers.LVMCreateLogicalVolume(projectName, poolName, thinPoolName, containerLvmName, lvFsType, lvSize,
 			storagePoolVolumeAPIEndpointContainers, s.useThinpool)
 	} else {
 		cname, _, _ := shared.InstanceGetParentAndSnapshotName(containerName)
@@ -1926,7 +1926,7 @@ func (s *storageLvm) ImageCreate(fingerprint string, tracker *ioprogress.Progres
 			return err
 		}
 
-		err = lvmCreateLv("default", poolName, thinPoolName, fingerprint, lvFsType, lvSize, storagePoolVolumeAPIEndpointImages, true)
+		err = drivers.LVMCreateLogicalVolume("default", poolName, thinPoolName, fingerprint, lvFsType, lvSize, storagePoolVolumeAPIEndpointImages, true)
 		if err != nil {
 			return fmt.Errorf("Error Creating LVM LV for new image: %v", err)
 		}

From 7162baf9b0e1a31abd809405c7c3ed900266e9aa Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 17 Dec 2019 11:30:06 +0000
Subject: [PATCH 13/18] lxd/storage/lvm: LVMDevPath usage

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage_lvm.go | 30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/lxd/storage_lvm.go b/lxd/storage_lvm.go
index 19c53c67e9..7f24cd04b5 100644
--- a/lxd/storage_lvm.go
+++ b/lxd/storage_lvm.go
@@ -554,7 +554,7 @@ func (s *storageLvm) StoragePoolVolumeDelete() error {
 
 	volumeLvmName := containerNameToLVName(s.volume.Name)
 	poolName := s.getOnDiskPoolName()
-	customLvmDevPath := getLvmDevPath("default", poolName,
+	customLvmDevPath := drivers.LVMDevPath("default", poolName,
 		storagePoolVolumeAPIEndpointCustom, volumeLvmName)
 	lvExists, _ := storageLVExists(customLvmDevPath)
 
@@ -609,7 +609,7 @@ func (s *storageLvm) StoragePoolVolumeMount() (bool, error) {
 	if err != nil {
 		return false, err
 	}
-	lvmVolumePath := getLvmDevPath("default", poolName, volumeType, volumeLvmName)
+	lvmVolumePath := drivers.LVMDevPath("default", poolName, volumeType, volumeLvmName)
 
 	customMountLockID := getCustomMountLockID(s.pool.Name, s.volume.Name)
 	lxdStorageMapLock.Lock()
@@ -929,8 +929,8 @@ func (s *storageLvm) StoragePoolVolumeRename(newName string) error {
 func (s *storageLvm) ContainerStorageReady(container instance.Instance) bool {
 	containerLvmName := containerNameToLVName(container.Name())
 	poolName := s.getOnDiskPoolName()
-	containerLvmPath := getLvmDevPath(container.Project(), poolName, storagePoolVolumeAPIEndpointContainers, containerLvmName)
-	ok, _ := storageLVExists(containerLvmPath)
+	containerLvmPath := drivers.LVMDevPath(container.Project(), poolName, storagePoolVolumeAPIEndpointContainers, containerLvmName)
+	ok, _ := drivers.LVMVolumeExists(containerLvmPath)
 	return ok
 }
 
@@ -1035,7 +1035,7 @@ func (s *storageLvm) ContainerCreateFromImage(container instance.Instance, finge
 	}
 
 	poolName := s.getOnDiskPoolName()
-	containerLvDevPath := getLvmDevPath(container.Project(), poolName, storagePoolVolumeAPIEndpointContainers, containerLvmName)
+	containerLvDevPath := drivers.LVMDevPath(container.Project(), poolName, storagePoolVolumeAPIEndpointContainers, containerLvmName)
 	// Generate a new xfs's UUID
 	lvFsType := s.getLvmFilesystem()
 	msg, err := driver.FSGenerateNewUUID(lvFsType, containerLvDevPath)
@@ -1086,7 +1086,7 @@ func lvmContainerDeleteInternal(projectName, poolName string, ctName string, isS
 		}
 	}
 
-	containerLvmDevPath := getLvmDevPath(projectName, vgName,
+	containerLvmDevPath := drivers.LVMDevPath(projectName, vgName,
 		storagePoolVolumeAPIEndpointContainers, containerLvmName)
 
 	lvExists, _ := storageLVExists(containerLvmDevPath)
@@ -1247,7 +1247,7 @@ func (s *storageLvm) doContainerMount(project, name string, snap bool) (bool, er
 	containerLvmName := containerNameToLVName(name)
 	lvFsType := s.getLvmFilesystem()
 	poolName := s.getOnDiskPoolName()
-	containerLvmPath := getLvmDevPath(project, poolName, storagePoolVolumeAPIEndpointContainers, containerLvmName)
+	containerLvmPath := drivers.LVMDevPath(project, poolName, storagePoolVolumeAPIEndpointContainers, containerLvmName)
 	containerMntPoint := driver.GetContainerMountPoint(project, s.pool.Name, name)
 	if shared.IsSnapshot(name) {
 		containerMntPoint = driver.GetSnapshotMountPoint(project, s.pool.Name, name)
@@ -1583,7 +1583,7 @@ func (s *storageLvm) ContainerSnapshotStart(container instance.Instance) (bool,
 	poolName := s.getOnDiskPoolName()
 	containerName := container.Name()
 	containerLvmName := containerNameToLVName(containerName)
-	containerLvmPath := getLvmDevPath(container.Project(), poolName, storagePoolVolumeAPIEndpointContainers, containerLvmName)
+	containerLvmPath := drivers.LVMDevPath(container.Project(), poolName, storagePoolVolumeAPIEndpointContainers, containerLvmName)
 
 	wasWritableAtCheck, err := lvmLvIsWritable(containerLvmPath)
 	if err != nil {
@@ -1642,7 +1642,7 @@ func (s *storageLvm) ContainerSnapshotStop(container instance.Instance) (bool, e
 		}
 	}
 
-	containerLvmPath := getLvmDevPath(container.Project(), poolName, storagePoolVolumeAPIEndpointContainers, containerNameToLVName(containerName))
+	containerLvmPath := drivers.LVMDevPath(container.Project(), poolName, storagePoolVolumeAPIEndpointContainers, containerNameToLVName(containerName))
 	wasWritableAtCheck, err := lvmLvIsWritable(containerLvmPath)
 	if err != nil {
 		return false, err
@@ -1973,7 +1973,7 @@ func (s *storageLvm) ImageDelete(fingerprint string) error {
 
 	if s.useThinpool {
 		poolName := s.getOnDiskPoolName()
-		imageLvmDevPath := getLvmDevPath("default", poolName,
+		imageLvmDevPath := drivers.LVMDevPath("default", poolName,
 			storagePoolVolumeAPIEndpointImages, fingerprint)
 		lvExists, _ := storageLVExists(imageLvmDevPath)
 
@@ -2022,7 +2022,7 @@ func (s *storageLvm) ImageMount(fingerprint string) (bool, error) {
 	}
 
 	poolName := s.getOnDiskPoolName()
-	lvmVolumePath := getLvmDevPath("default", poolName, storagePoolVolumeAPIEndpointImages, fingerprint)
+	lvmVolumePath := drivers.LVMDevPath("default", poolName, storagePoolVolumeAPIEndpointImages, fingerprint)
 	mountFlags, mountOptions := drivers.ResolveMountOptions(s.getLvmMountOptions())
 	err := driver.TryMount(lvmVolumePath, imageMntPoint, lvmFstype, mountFlags, mountOptions)
 	if err != nil {
@@ -2092,11 +2092,11 @@ func (s *storageLvm) StorageEntitySetQuota(volumeType int, size int64, data inte
 		}
 
 		ctLvmName := containerNameToLVName(ctName)
-		lvDevPath = getLvmDevPath("default", poolName, storagePoolVolumeAPIEndpointContainers, ctLvmName)
+		lvDevPath = drivers.LVMDevPath("default", poolName, storagePoolVolumeAPIEndpointContainers, ctLvmName)
 		mountpoint = driver.GetContainerMountPoint(c.Project(), s.pool.Name, ctName)
 	default:
 		customLvmName := containerNameToLVName(s.volume.Name)
-		lvDevPath = getLvmDevPath("default", poolName, storagePoolVolumeAPIEndpointCustom, customLvmName)
+		lvDevPath = drivers.LVMDevPath("default", poolName, storagePoolVolumeAPIEndpointCustom, customLvmName)
 		mountpoint = driver.GetStoragePoolVolumeMountPoint(s.pool.Name, s.volume.Name)
 	}
 
@@ -2306,8 +2306,8 @@ func (s *storageLvm) StoragePoolVolumeSnapshotDelete() error {
 	}
 
 	poolName := s.getOnDiskPoolName()
-	snapshotLVDevPath := getLvmDevPath("default", poolName, storagePoolVolumeAPIEndpointCustom, snapshotLVName)
-	lvExists, _ := storageLVExists(snapshotLVDevPath)
+	snapshotLVDevPath := drivers.LVMDevPath("default", poolName, storagePoolVolumeAPIEndpointCustom, snapshotLVName)
+	lvExists, _ := drivers.LVMVolumeExists(snapshotLVDevPath)
 	if lvExists {
 		err := removeLV("default", poolName, storagePoolVolumeAPIEndpointCustom, snapshotLVName)
 		if err != nil {

From f8d6eade0ecd52b9bf5807b86a2818534797ce10 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 17 Dec 2019 11:30:23 +0000
Subject: [PATCH 14/18] lxd/storage/lvm: LVMVolumeExists usage

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage_lvm.go | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/lxd/storage_lvm.go b/lxd/storage_lvm.go
index 7f24cd04b5..36f21f52c6 100644
--- a/lxd/storage_lvm.go
+++ b/lxd/storage_lvm.go
@@ -556,7 +556,7 @@ func (s *storageLvm) StoragePoolVolumeDelete() error {
 	poolName := s.getOnDiskPoolName()
 	customLvmDevPath := drivers.LVMDevPath("default", poolName,
 		storagePoolVolumeAPIEndpointCustom, volumeLvmName)
-	lvExists, _ := storageLVExists(customLvmDevPath)
+	lvExists, _ := drivers.LVMVolumeExists(customLvmDevPath)
 
 	if lvExists {
 		_, err := s.StoragePoolVolumeUmount()
@@ -1089,7 +1089,7 @@ func lvmContainerDeleteInternal(projectName, poolName string, ctName string, isS
 	containerLvmDevPath := drivers.LVMDevPath(projectName, vgName,
 		storagePoolVolumeAPIEndpointContainers, containerLvmName)
 
-	lvExists, _ := storageLVExists(containerLvmDevPath)
+	lvExists, _ := drivers.LVMVolumeExists(containerLvmDevPath)
 	if lvExists {
 		err := removeLV(projectName, vgName, storagePoolVolumeAPIEndpointContainers, containerLvmName)
 		if err != nil {
@@ -1975,7 +1975,7 @@ func (s *storageLvm) ImageDelete(fingerprint string) error {
 		poolName := s.getOnDiskPoolName()
 		imageLvmDevPath := drivers.LVMDevPath("default", poolName,
 			storagePoolVolumeAPIEndpointImages, fingerprint)
-		lvExists, _ := storageLVExists(imageLvmDevPath)
+		lvExists, _ := drivers.LVMVolumeExists(imageLvmDevPath)
 
 		if lvExists {
 			_, err := s.ImageUmount(fingerprint)

From a76b5e515c266a76bd60d08e201903a4417da22e Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 17 Dec 2019 11:31:37 +0000
Subject: [PATCH 15/18] lxd/storage/lvm/utils: Removes LVM utils moved to
 storage pkg

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage_lvm_utils.go | 232 ---------------------------------------
 1 file changed, 232 deletions(-)

diff --git a/lxd/storage_lvm_utils.go b/lxd/storage_lvm_utils.go
index ae3085f8e6..ca71f7df5b 100644
--- a/lxd/storage_lvm_utils.go
+++ b/lxd/storage_lvm_utils.go
@@ -3,10 +3,8 @@ package main
 import (
 	"fmt"
 	"os"
-	"os/exec"
 	"strconv"
 	"strings"
-	"syscall"
 
 	"github.com/pkg/errors"
 
@@ -22,7 +20,6 @@ import (
 	"github.com/lxc/lxd/shared/api"
 	"github.com/lxc/lxd/shared/logger"
 	"github.com/lxc/lxd/shared/units"
-	"github.com/lxc/lxd/shared/version"
 )
 
 func (s *storageLvm) lvExtend(lvPath string, lvSize int64, fsType string, fsMntPoint string, volumeType int, data interface{}) error {
@@ -577,16 +574,6 @@ func (s *storageLvm) containerCreateFromImageThinLv(c instance.Instance, fp stri
 	return nil
 }
 
-func lvmGetLVCount(vgName string) (int, error) {
-	output, err := shared.TryRunCommand("vgs", "--noheadings", "-o", "lv_count", vgName)
-	if err != nil {
-		return -1, err
-	}
-
-	output = strings.TrimSpace(output)
-	return strconv.Atoi(output)
-}
-
 func lvmLvIsWritable(lvName string) (bool, error) {
 	output, err := shared.TryRunCommand("lvs", "--noheadings", "-o", "lv_attr", lvName)
 	if err != nil {
@@ -615,68 +602,6 @@ func storageLVActivate(lvmVolumePath string) error {
 	return nil
 }
 
-func storagePVExists(pvName string) (bool, error) {
-	_, err := shared.RunCommand("pvs", "--noheadings", "-o", "lv_attr", pvName)
-	if err != nil {
-		runErr, ok := err.(shared.RunError)
-		if ok {
-			exitError, ok := runErr.Err.(*exec.ExitError)
-			if ok {
-				waitStatus := exitError.Sys().(syscall.WaitStatus)
-				if waitStatus.ExitStatus() == 5 {
-					// physical volume not found
-					return false, nil
-				}
-			}
-		}
-		return false, fmt.Errorf("error checking for physical volume \"%s\"", pvName)
-	}
-
-	return true, nil
-}
-
-func storageVGExists(vgName string) (bool, error) {
-	_, err := shared.RunCommand("vgs", "--noheadings", "-o", "lv_attr", vgName)
-	if err != nil {
-		runErr, ok := err.(shared.RunError)
-		if ok {
-			exitError, ok := runErr.Err.(*exec.ExitError)
-			if ok {
-				waitStatus := exitError.Sys().(syscall.WaitStatus)
-				if waitStatus.ExitStatus() == 5 {
-					// volume group not found
-					return false, nil
-				}
-			}
-		}
-
-		return false, fmt.Errorf("error checking for volume group \"%s\"", vgName)
-	}
-
-	return true, nil
-}
-
-func storageLVExists(lvName string) (bool, error) {
-	_, err := shared.RunCommand("lvs", "--noheadings", "-o", "lv_attr", lvName)
-	if err != nil {
-		runErr, ok := err.(shared.RunError)
-		if ok {
-			exitError, ok := runErr.Err.(*exec.ExitError)
-			if ok {
-				waitStatus := exitError.Sys().(syscall.WaitStatus)
-				if waitStatus.ExitStatus() == 5 {
-					// logical volume not found
-					return false, nil
-				}
-			}
-		}
-
-		return false, fmt.Errorf("error checking for logical volume \"%s\"", lvName)
-	}
-
-	return true, nil
-}
-
 func lvmGetLVSize(lvPath string) (string, error) {
 	msg, err := shared.TryRunCommand("lvs", "--noheadings", "-o", "size", "--nosuffix", "--units", "b", lvPath)
 	if err != nil {
@@ -695,32 +620,6 @@ func lvmGetLVSize(lvPath string) (string, error) {
 	return detectedSize, nil
 }
 
-func storageLVMThinpoolExists(vgName string, poolName string) (bool, error) {
-	output, err := shared.RunCommand("vgs", "--noheadings", "-o", "lv_attr", fmt.Sprintf("%s/%s", vgName, poolName))
-	if err != nil {
-		runErr, ok := err.(shared.RunError)
-		if ok {
-			exitError, ok := runErr.Err.(*exec.ExitError)
-			if ok {
-				waitStatus := exitError.Sys().(syscall.WaitStatus)
-				if waitStatus.ExitStatus() == 5 {
-					// pool LV was not found
-					return false, nil
-				}
-			}
-		}
-
-		return false, fmt.Errorf("error checking for pool \"%s\"", poolName)
-	}
-	// Found LV named poolname, check type:
-	attrs := strings.TrimSpace(string(output[:]))
-	if strings.HasPrefix(attrs, "t") {
-		return true, nil
-	}
-
-	return false, fmt.Errorf("pool named \"%s\" exists but is not a thin pool", poolName)
-}
-
 func storageLVMGetThinPoolUsers(s *state.State) ([]string, error) {
 	results := []string{}
 
@@ -808,15 +707,6 @@ func containerNameToLVName(containerName string) string {
 	return strings.Replace(lvName, shared.SnapshotDelimiter, "-", -1)
 }
 
-func getLvmDevPath(projectName, lvmPool string, volumeType string, lvmVolume string) string {
-	lvmVolume = project.Prefix(projectName, lvmVolume)
-	if volumeType == "" {
-		return fmt.Sprintf("/dev/%s/%s", lvmPool, lvmVolume)
-	}
-
-	return fmt.Sprintf("/dev/%s/%s_%s", lvmPool, volumeType, lvmVolume)
-}
-
 func getLVName(lvmPool string, volumeType string, lvmVolume string) string {
 	if volumeType == "" {
 		return fmt.Sprintf("%s/%s", lvmPool, lvmVolume)
@@ -830,128 +720,6 @@ func getPrefixedLvName(projectName, volumeType string, lvmVolume string) string
 	return fmt.Sprintf("%s_%s", volumeType, lvmVolume)
 }
 
-func lvmCreateLv(projectName, vgName string, thinPoolName string, lvName string, lvFsType string, lvSize string, volumeType string, makeThinLv bool) error {
-	var output string
-	var err error
-
-	// Round the size to closest 512 bytes
-	lvSizeInt, err := units.ParseByteSizeString(lvSize)
-	if err != nil {
-		return err
-	}
-
-	lvSizeInt = int64(lvSizeInt/512) * 512
-	lvSizeString := units.GetByteSizeString(lvSizeInt, 0)
-
-	lvmPoolVolumeName := getPrefixedLvName(projectName, volumeType, lvName)
-	if makeThinLv {
-		targetVg := fmt.Sprintf("%s/%s", vgName, thinPoolName)
-		_, err = shared.TryRunCommand("lvcreate", "-Wy", "--yes", "--thin", "-n", lvmPoolVolumeName, "--virtualsize", lvSizeString, targetVg)
-	} else {
-		_, err = shared.TryRunCommand("lvcreate", "-Wy", "--yes", "-n", lvmPoolVolumeName, "--size", lvSizeString, vgName)
-	}
-	if err != nil {
-		logger.Errorf("Could not create LV \"%s\": %v", lvmPoolVolumeName, err)
-		return fmt.Errorf("Could not create thin LV named %s: %v", lvmPoolVolumeName, err)
-	}
-
-	fsPath := getLvmDevPath(projectName, vgName, volumeType, lvName)
-
-	output, err = storageDrivers.MakeFSType(fsPath, lvFsType, nil)
-	if err != nil {
-		logger.Errorf("Filesystem creation failed: %v (%s)", err, output)
-		return fmt.Errorf("Error making filesystem on image LV: %v (%s)", err, output)
-	}
-
-	return nil
-}
-
-func lvmCreateThinpool(s *state.State, sTypeVersion string, vgName string, thinPoolName string, lvFsType string) error {
-	exists, err := storageLVMThinpoolExists(vgName, thinPoolName)
-	if err != nil {
-		return err
-	}
-
-	if exists {
-		return nil
-	}
-
-	err = createDefaultThinPool(sTypeVersion, vgName, thinPoolName, lvFsType)
-	if err != nil {
-		return err
-	}
-
-	err = storageLVMValidateThinPoolName(s, vgName, thinPoolName)
-	if err != nil {
-		logger.Errorf("Setting thin pool name: %s", err)
-		return fmt.Errorf("Error setting LVM thin pool config: %v", err)
-	}
-
-	return nil
-}
-
-func createDefaultThinPool(sTypeVersion string, vgName string, thinPoolName string, lvFsType string) error {
-	isRecent, err := lvmVersionIsAtLeast(sTypeVersion, "2.02.99")
-	if err != nil {
-		return fmt.Errorf("Error checking LVM version: %s", err)
-	}
-
-	// Create the thin pool
-	lvmThinPool := fmt.Sprintf("%s/%s", vgName, thinPoolName)
-	if isRecent {
-		_, err = shared.TryRunCommand(
-			"lvcreate",
-			"-Wy", "--yes",
-			"--poolmetadatasize", "1G",
-			"-l", "100%FREE",
-			"--thinpool", lvmThinPool)
-	} else {
-		_, err = shared.TryRunCommand(
-			"lvcreate",
-			"-Wy", "--yes",
-			"--poolmetadatasize", "1G",
-			"-L", "1G",
-			"--thinpool", lvmThinPool)
-	}
-
-	if err != nil {
-		logger.Errorf("Could not create thin pool \"%s\": %v", thinPoolName, err)
-		return fmt.Errorf("Could not create LVM thin pool named %s: %v", thinPoolName, err)
-	}
-
-	if !isRecent {
-		// Grow it to the maximum VG size (two step process required by old LVM)
-		_, err = shared.TryRunCommand("lvextend", "--alloc", "anywhere", "-l", "100%FREE", lvmThinPool)
-
-		if err != nil {
-			logger.Errorf("Could not grow thin pool: \"%s\": %v", thinPoolName, err)
-			return fmt.Errorf("Could not grow LVM thin pool named %s: %v", thinPoolName, err)
-		}
-	}
-
-	return nil
-}
-
-func lvmVersionIsAtLeast(sTypeVersion string, versionString string) (bool, error) {
-	lvmVersionString := strings.Split(sTypeVersion, "/")[0]
-
-	lvmVersion, err := version.Parse(lvmVersionString)
-	if err != nil {
-		return false, err
-	}
-
-	inVersion, err := version.Parse(versionString)
-	if err != nil {
-		return false, err
-	}
-
-	if lvmVersion.Compare(inVersion) < 0 {
-		return false, nil
-	}
-
-	return true, nil
-}
-
 // Copy an LVM custom volume.
 func (s *storageLvm) copyVolume(sourcePool string, source string) error {
 	targetMntPoint := driver.GetStoragePoolVolumeMountPoint(s.pool.Name, s.volume.Name)

From b766478db727e3378766fb285e679984330db118 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 17 Dec 2019 11:32:14 +0000
Subject: [PATCH 16/18] lxd/storage/lvm/utils: LVMDevPath usage

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage_lvm_utils.go | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/lxd/storage_lvm_utils.go b/lxd/storage_lvm_utils.go
index ca71f7df5b..dba9888a6a 100644
--- a/lxd/storage_lvm_utils.go
+++ b/lxd/storage_lvm_utils.go
@@ -177,7 +177,7 @@ func (s *storageLvm) renameLVByPath(project, oldName string, newName string, vol
 }
 
 func removeLV(project, vgName string, volumeType string, lvName string) error {
-	lvmVolumePath := getLvmDevPath(project, vgName, volumeType, lvName)
+	lvmVolumePath := storageDrivers.LVMDevPath(project, vgName, volumeType, lvName)
 
 	_, err := shared.TryRunCommand("lvremove", "-f", lvmVolumePath)
 	if err != nil {
@@ -195,8 +195,8 @@ func (s *storageLvm) createSnapshotLV(project, vgName string, origLvName string,
 		sourceProject = "default"
 	}
 
-	sourceLvmVolumePath := getLvmDevPath(sourceProject, vgName, origVolumeType, origLvName)
-	isRecent, err := lvmVersionIsAtLeast(s.sTypeVersion, "2.02.99")
+	sourceLvmVolumePath := storageDrivers.LVMDevPath(sourceProject, vgName, origVolumeType, origLvName)
+	isRecent, err := storageDrivers.LVMVersionIsAtLeast(s.sTypeVersion, "2.02.99")
 	if err != nil {
 		return "", fmt.Errorf("Error checking LVM version: %v", err)
 	}
@@ -241,7 +241,7 @@ func (s *storageLvm) createSnapshotLV(project, vgName string, origLvName string,
 		return "", fmt.Errorf("Could not create snapshot LV named %s: %v", lvName, err)
 	}
 
-	targetLvmVolumePath := getLvmDevPath(project, vgName, volumeType, lvName)
+	targetLvmVolumePath := storageDrivers.LVMDevPath(project, vgName, volumeType, lvName)
 	if makeThinLv {
 		// Snapshots of thin logical volumes can be directly activated.
 		// Normal snapshots will complain about changing the origin
@@ -315,7 +315,7 @@ func (s *storageLvm) copyContainerThinpool(target instance.Instance, source inst
 	poolName := s.getOnDiskPoolName()
 	containerName := target.Name()
 	containerLvmName := containerNameToLVName(containerName)
-	containerLvDevPath := getLvmDevPath(target.Project(), poolName,
+	containerLvDevPath := storageDrivers.LVMDevPath(target.Project(), poolName,
 		storagePoolVolumeAPIEndpointContainers, containerLvmName)
 
 	// If btrfstune sees two btrfs filesystems with the same UUID it
@@ -518,7 +518,7 @@ func (s *storageLvm) containerCreateFromImageLv(c instance.Instance, fp string)
 func (s *storageLvm) containerCreateFromImageThinLv(c instance.Instance, fp string) error {
 	poolName := s.getOnDiskPoolName()
 	// Check if the image already exists.
-	imageLvmDevPath := getLvmDevPath("default", poolName, storagePoolVolumeAPIEndpointImages, fp)
+	imageLvmDevPath := storageDrivers.LVMDevPath("default", poolName, storagePoolVolumeAPIEndpointImages, fp)
 
 	imageStoragePoolLockID := getImageCreateLockID(poolName, fp)
 	lxdStorageMapLock.Lock()
@@ -847,7 +847,7 @@ func (s *storageLvm) copyVolumeThinpool(source string, target string, readOnly b
 		return err
 	}
 
-	lvDevPath := getLvmDevPath("default", poolName, storagePoolVolumeAPIEndpointCustom, targetLvmName)
+	lvDevPath := storageDrivers.LVMDevPath("default", poolName, storagePoolVolumeAPIEndpointCustom, targetLvmName)
 
 	msg, err := driver.FSGenerateNewUUID(lvFsType, lvDevPath)
 	if err != nil {

From 695324fe7d32e87e05eb449488efba6d0054526a Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 17 Dec 2019 11:32:33 +0000
Subject: [PATCH 17/18] lxd/storage/lvm/utils: LVMVolumeExists usage

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage_lvm_utils.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lxd/storage_lvm_utils.go b/lxd/storage_lvm_utils.go
index dba9888a6a..e0ae2c3329 100644
--- a/lxd/storage_lvm_utils.go
+++ b/lxd/storage_lvm_utils.go
@@ -371,7 +371,7 @@ func (s *storageLvm) copySnapshot(target instance.Instance, source instance.Inst
 
 // Copy a container on a storage pool that does not use a thinpool.
 func (s *storageLvm) copyContainerLv(target instance.Instance, source instance.Instance, readonly bool, refresh bool) error {
-	exists, err := storageLVExists(getLvmDevPath(target.Project(), s.getOnDiskPoolName(),
+	exists, err := storageDrivers.LVMVolumeExists(storageDrivers.LVMDevPath(target.Project(), s.getOnDiskPoolName(),
 		storagePoolVolumeAPIEndpointContainers, containerNameToLVName(target.Name())))
 	if err != nil {
 		return err
@@ -532,7 +532,7 @@ func (s *storageLvm) containerCreateFromImageThinLv(c instance.Instance, fp stri
 		lxdStorageMapLock.Unlock()
 
 		var imgerr error
-		ok, _ := storageLVExists(imageLvmDevPath)
+		ok, _ := storageDrivers.LVMVolumeExists(imageLvmDevPath)
 		if ok {
 			_, volume, err := s.s.Cluster.StoragePoolNodeVolumeGetType(fp, db.StoragePoolVolumeTypeImage, s.poolID)
 			if err != nil {

From 998e2a7846647fe9dca7a6783221e2473ba6712a Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 17 Dec 2019 11:32:54 +0000
Subject: [PATCH 18/18] lxd/storage/lvm/utils: LVMThinpoolExists usage

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage_lvm_utils.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lxd/storage_lvm_utils.go b/lxd/storage_lvm_utils.go
index e0ae2c3329..a7d52ad7eb 100644
--- a/lxd/storage_lvm_utils.go
+++ b/lxd/storage_lvm_utils.go
@@ -671,7 +671,7 @@ func storageLVMValidateThinPoolName(s *state.State, vgName string, value string)
 			return fmt.Errorf("can not set lvm.thinpool_name without lvm.vg_name set")
 		}
 
-		poolExists, err := storageLVMThinpoolExists(vgName, value)
+		poolExists, err := storageDrivers.LVMThinpoolExists(vgName, value)
 		if err != nil {
 			return fmt.Errorf("error checking for thin pool \"%s\" in \"%s\": %v", value, vgName, err)
 		}


More information about the lxc-devel mailing list