[lxc-devel] [lxd/master] patches: detect logical volume size

brauner on Github lxc-bot at linuxcontainers.org
Tue Mar 7 23:44:12 UTC 2017


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 384 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20170307/7a8dab66/attachment.bin>
-------------- next part --------------
From fa23309bb02473491c7be5db9e8220b786df614a Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Wed, 8 Mar 2017 00:42:59 +0100
Subject: [PATCH] patches: detect logical volume size

Addresses #3036.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxd/patches.go     | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 lxd/storage_lvm.go | 18 +++++++++++
 2 files changed, 110 insertions(+)

diff --git a/lxd/patches.go b/lxd/patches.go
index 3c527ba..4105ebe 100644
--- a/lxd/patches.go
+++ b/lxd/patches.go
@@ -40,6 +40,7 @@ var patches = []patch{
 	{name: "storage_api_keys", run: patchStorageApiKeys},
 	{name: "storage_api_update_storage_configs", run: patchStorageApiUpdateStorageConfigs},
 	{name: "storage_api_lxd_on_btrfs", run: patchStorageApiLxdOnBtrfs},
+	{name: "storage_api_lvm_detect_lv_size", run: patchStorageApiDetectLVSize},
 }
 
 type patch struct {
@@ -2130,3 +2131,94 @@ func patchStorageApiLxdOnBtrfs(name string, d *Daemon) error {
 
 	return nil
 }
+
+func patchStorageApiDetectLVSize(name string, d *Daemon) error {
+	pools, err := dbStoragePools(d.db)
+	if err != nil {
+		if err == NoSuchObjectError {
+			return nil
+		}
+		shared.LogErrorf("Failed to query database: %s", err)
+		return err
+	}
+
+	for _, poolName := range pools {
+		poolID, pool, err := dbStoragePoolGet(d.db, poolName)
+		if err != nil {
+			shared.LogErrorf("Failed to query database: %s", err)
+			return err
+		}
+
+		// Make sure that config is not empty.
+		if pool.Config == nil {
+			pool.Config = map[string]string{}
+
+			// Insert default values.
+			err = storagePoolFillDefault(poolName, pool.Driver, pool.Config)
+			if err != nil {
+				return err
+			}
+		}
+
+		// We're only interested in LVM pools.
+		if pool.Driver != "lvm" {
+			continue
+		}
+
+		// Get all storage volumes on the storage pool.
+		volumes, err := dbStoragePoolVolumesGet(d.db, poolID, supportedVolumeTypes)
+		if err != nil {
+			if err == NoSuchObjectError {
+				continue
+			}
+			return err
+		}
+
+		poolName := pool.Config["lvm.vg_name"]
+		if poolName == "" {
+			shared.LogErrorf("The \"lvm.vg_name\" key should not be empty.")
+			return fmt.Errorf("The \"lvm.vg_name\" key should not be empty.")
+		}
+
+		for _, volume := range volumes {
+			// Make sure that config is not empty.
+			if volume.Config == nil {
+				volume.Config = map[string]string{}
+
+				// Insert default values.
+				err := storageVolumeFillDefault(volume.Name, volume.Config, pool)
+				if err != nil {
+					return err
+				}
+			}
+
+			// It shouldn't be possible that false volume types
+			// exist in the db, so it's safe to ignore the error.
+			volumeTypeApiEndpoint, _ := storagePoolVolumeTypeNameToApiEndpoint(volume.Type)
+			lvmName := containerNameToLVName(volume.Name)
+			lvmLvDevPath := getLvmDevPath(poolName, volumeTypeApiEndpoint, lvmName)
+			size, err := lvmGetLVSize(lvmLvDevPath)
+			if err != nil {
+				shared.LogErrorf("Failed to detect size of logical volume: %s.", err)
+				return err
+			}
+
+			if volume.Config["size"] == size {
+				continue
+			}
+
+			volume.Config["size"] = size
+
+			// It shouldn't be possible that false volume types
+			// exist in the db, so it's safe to ignore the error.
+			volumeType, _ := storagePoolVolumeTypeNameToType(volume.Type)
+			// Update the volume config.
+			err = dbStoragePoolVolumeUpdate(d.db, volume.Name, volumeType, poolID, volume.Config)
+			if err != nil {
+				return err
+			}
+		}
+	}
+
+	return nil
+}
diff --git a/lxd/storage_lvm.go b/lxd/storage_lvm.go
index 60ecaa5..2784156 100644
--- a/lxd/storage_lvm.go
+++ b/lxd/storage_lvm.go
@@ -88,6 +88,24 @@ func storageLVExists(lvName string) (bool, error) {
 	return true, nil
 }
 
+func lvmGetLVSize(lvPath string) (string, error) {
+	msg, err := shared.TryRunCommand("lvs", "--noheadings", "-o", "size", "--nosuffix", "--units", "b", lvPath)
+	if err != nil {
+		return "", fmt.Errorf("Failed to retrieve size of logical volume: %s: %s.", string(msg), err)
+	}
+
+	sizeString := string(msg)
+	sizeString = strings.TrimSpace(sizeString)
+	size, err := strconv.ParseInt(sizeString, 10, 64)
+	if err != nil {
+		return "", err
+	}
+
+	detectedSize := shared.GetByteSizeString(size, 0)
+
+	return detectedSize, nil
+}
+
 func storageLVMThinpoolExists(vgName string, poolName string) (bool, error) {
 	output, err := exec.Command("vgs", "--noheadings", "-o", "lv_attr", fmt.Sprintf("%s/%s", vgName, poolName)).Output()
 	if err != nil {


More information about the lxc-devel mailing list