[lxc-devel] [lxd/master] lxd init: support all storage drivers

brauner on Github lxc-bot at linuxcontainers.org
Tue Mar 14 18:00:58 UTC 2017


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 301 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20170314/76c988a4/attachment.bin>
-------------- next part --------------
From eb6078a494ffa09e18ceef5d5e63645d0b71b898 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Tue, 14 Mar 2017 18:56:54 +0100
Subject: [PATCH 1/3] btrfs: add isBtrfsFilesystem()

Detect whether a path is a btrfs filesystem. If so, we know that calling
btrfsSubVolumesDelete() is bound to fail.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxd/storage_btrfs.go | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/lxd/storage_btrfs.go b/lxd/storage_btrfs.go
index abb1599..12dd233 100644
--- a/lxd/storage_btrfs.go
+++ b/lxd/storage_btrfs.go
@@ -300,7 +300,9 @@ func (s *storageBtrfs) StoragePoolDelete() error {
 			// This is a loop file --> simply remove it.
 			err = os.Remove(source)
 		} else {
-			err = btrfsSubVolumesDelete(source)
+			if !isBtrfsFilesystem(source) && isBtrfsSubVolume(source) {
+				err = btrfsSubVolumesDelete(source)
+			}
 		}
 		if err != nil {
 			return err
@@ -1464,13 +1466,15 @@ func btrfsSubVolumesDelete(subvol string) error {
 	sort.Sort(sort.Reverse(sort.StringSlice(subsubvols)))
 
 	for _, subsubvol := range subsubvols {
-		if err := btrfsSubVolumeDelete(path.Join(subvol, subsubvol)); err != nil {
+		err := btrfsSubVolumeDelete(path.Join(subvol, subsubvol))
+		if err != nil {
 			return err
 		}
 	}
 
 	// Delete the subvol itself
-	if err := btrfsSubVolumeDelete(subvol); err != nil {
+	err = btrfsSubVolumeDelete(subvol)
+	if err != nil {
 		return err
 	}
 
@@ -1567,6 +1571,15 @@ func isBtrfsSubVolume(subvolPath string) bool {
 	return true
 }
 
+func isBtrfsFilesystem(path string) bool {
+	_, err := shared.RunCommand("btrfs", "filesystem", "show", path)
+	if err != nil {
+		return false
+	}
+
+	return true
+}
+
 func isOnBtrfs(path string) bool {
 	fs := syscall.Statfs_t{}
 

From 45ed98e9f2f9c2733f8fd13d365410a8501aa519 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Tue, 14 Mar 2017 18:58:10 +0100
Subject: [PATCH 2/3] storage: non-functional changes

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxd/storage.go              | 2 +-
 lxd/storage_pools_config.go | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/lxd/storage.go b/lxd/storage.go
index d2b22ea..79ce072 100644
--- a/lxd/storage.go
+++ b/lxd/storage.go
@@ -149,7 +149,7 @@ const (
 	storageTypeMock
 )
 
-var supportedStorageTypes = []string{"btrfs", "zfs", "lvm", "dir"}
+var supportedStoragePoolDrivers = []string{"btrfs", "dir", "lvm", "zfs"}
 
 func storageTypeToString(sType storageType) (string, error) {
 	switch sType {
diff --git a/lxd/storage_pools_config.go b/lxd/storage_pools_config.go
index 4be75a4..65ebe29 100644
--- a/lxd/storage_pools_config.go
+++ b/lxd/storage_pools_config.go
@@ -40,7 +40,7 @@ var storagePoolConfigKeys = map[string]func(value string) error{
 
 func storagePoolValidateConfig(name string, driver string, config map[string]string) error {
 	err := func(value string) error {
-		return shared.IsOneOf(value, supportedStorageTypes)
+		return shared.IsOneOf(value, supportedStoragePoolDrivers)
 	}(driver)
 	if err != nil {
 		return err

From 2765ee9bd700572605728b866db6517e0bc9f136 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Tue, 14 Mar 2017 18:58:33 +0100
Subject: [PATCH 3/3] lxd init: support all storage drivers

Closes #2986.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxd/main_init.go | 108 ++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 75 insertions(+), 33 deletions(-)

diff --git a/lxd/main_init.go b/lxd/main_init.go
index 3bc1c49..e9e1274 100644
--- a/lxd/main_init.go
+++ b/lxd/main_init.go
@@ -5,7 +5,6 @@ import (
 	"fmt"
 	"net"
 	"os"
-	"os/exec"
 	"strconv"
 	"strings"
 	"syscall"
@@ -18,8 +17,8 @@ import (
 
 func cmdInit() error {
 	var defaultPrivileged int // controls whether we set security.privileged=true
-	var storageSetup bool     // dir or zfs
-	var storageBackend string // dir or zfs
+	var storageSetup bool     // == supportedStoragePoolDrivers
+	var storageBackend string // == supportedStoragePoolDrivers
 	var storageLoopSize int64 // Size in GB
 	var storageDevice string  // Path
 	var storagePool string    // pool name
@@ -40,17 +39,20 @@ func cmdInit() error {
 	imagesAutoUpdate = true
 
 	backendsAvailable := []string{"dir"}
-	backendsSupported := []string{"dir", "zfs"}
 
-	// Detect zfs
-	out, err := exec.LookPath("zfs")
-	if err == nil && len(out) != 0 && !runningInUserns {
-		_ = loadModule("zfs")
+	// Check available backends
+	for _, driver := range supportedStoragePoolDrivers {
+		if driver == "dir" {
+			continue
+		}
 
-		_, err := shared.RunCommand("zpool", "list")
-		if err == nil {
-			backendsAvailable = append(backendsAvailable, "zfs")
+		// Initialize a core storage interface for the given driver.
+		_, err := storageCoreInit(driver)
+		if err != nil {
+			continue
 		}
+
+		backendsAvailable = append(backendsAvailable, driver)
 	}
 
 	reader := bufio.NewReader(os.Stdin)
@@ -171,7 +173,7 @@ func cmdInit() error {
 		}
 
 		// Do a bunch of sanity checks
-		if !shared.StringInSlice(*argStorageBackend, backendsSupported) {
+		if !shared.StringInSlice(*argStorageBackend, supportedStoragePoolDrivers) {
 			return fmt.Errorf("The requested backend '%s' isn't supported by lxd init.", *argStorageBackend)
 		}
 
@@ -183,9 +185,7 @@ func cmdInit() error {
 			if *argStorageCreateLoop != -1 || *argStorageCreateDevice != "" || *argStorageDataset != "" {
 				return fmt.Errorf("None of --storage-pool, --storage-create-device or --storage-create-loop may be used with the 'dir' backend.")
 			}
-		}
-
-		if *argStorageBackend == "zfs" {
+		} else {
 			if *argStorageCreateLoop != -1 && *argStorageCreateDevice != "" {
 				return fmt.Errorf("Only one of --storage-create-device or --storage-create-loop can be specified with the 'zfs' backend.")
 			}
@@ -238,9 +238,13 @@ func cmdInit() error {
 				goto askForStorageAgain
 			}
 
-			storageBackend = askChoice(fmt.Sprintf("Name of the storage backend to use (dir or zfs) [default=%s]: ", defaultStorage), backendsSupported, defaultStorage)
+			storagePoolDriverChoiceString := backendsAvailable[0]
+			if len(backendsAvailable) > 1 {
+				storagePoolDriverChoiceString = strings.Join(backendsAvailable, ",")
+			}
+			storageBackend = askChoice(fmt.Sprintf("Name of the storage backend to use (%s) [default=%s]: ", storagePoolDriverChoiceString, defaultStorage), supportedStoragePoolDrivers, defaultStorage)
 
-			if !shared.StringInSlice(storageBackend, backendsSupported) {
+			if !shared.StringInSlice(storageBackend, supportedStoragePoolDrivers) {
 				return fmt.Errorf("The requested backend '%s' isn't supported by lxd init.", storageBackend)
 			}
 
@@ -249,9 +253,10 @@ func cmdInit() error {
 			}
 		}
 
-		if storageSetup && storageBackend == "zfs" {
+		if storageSetup && storageBackend != "dir" {
 			storageLoopSize = -1
-			if askBool("Create a new ZFS pool (yes/no) [default=yes]? ", "yes") {
+			q := fmt.Sprintf("Create a new %s pool (yes/no) [default=yes]? ", strings.ToUpper(storageBackend))
+			if askBool(q, "yes") {
 				if askBool("Would you like to use an existing block device (yes/no) [default=no]? ", "no") {
 					deviceExists := func(path string) error {
 						if !shared.IsBlockdevPath(path) {
@@ -280,7 +285,8 @@ func cmdInit() error {
 					storageLoopSize = askInt(q, 1, -1, fmt.Sprintf("%d", def))
 				}
 			} else {
-				storageDataset = askString("Name of the existing ZFS pool or dataset: ", "", nil)
+				q := fmt.Sprintf("Name of the existing %s pool or dataset: ", strings.ToUpper(storageBackend))
+				storageDataset = askString(q, "", nil)
 			}
 		}
 
@@ -380,29 +386,27 @@ they otherwise would.
 		}
 
 		// Pool configuration
-		storageConfig := map[string]string{}
+		storagePoolConfig := map[string]string{}
+
 		if storageDevice != "" {
-			storageConfig["source"] = storageDevice
-			// The user probably wants to give the storage pool a
-			// custom name.
+			storagePoolConfig["source"] = storageDevice
 			if storageDataset != "" {
 				storagePool = storageDataset
 			}
-		} else if storageDataset != "" && storageBackend == "zfs" && storageLoopSize < 0 {
-			storageConfig["source"] = storageDataset
-		}
-
-		if storageBackend != "dir" && storageLoopSize > 0 {
-			// The user probably wants to give the storage pool a
-			// custom name.
+		} else if storageLoopSize != -1 {
 			if storageDataset != "" {
 				storagePool = storageDataset
 			}
-			storageConfig["size"] = strconv.FormatInt(storageLoopSize, 10) + "GB"
+		} else {
+			storagePoolConfig["source"] = storageDataset
+		}
+
+		if storageLoopSize > 0 {
+			storagePoolConfig["size"] = strconv.FormatInt(storageLoopSize, 10) + "GB"
 		}
 
 		// Create the requested storage pool.
-		err := c.StoragePoolCreate(storagePool, storageBackend, storageConfig)
+		err := c.StoragePoolCreate(storagePool, storageBackend, storagePoolConfig)
 		if err != nil {
 			return err
 		}
@@ -417,11 +421,45 @@ they otherwise would.
 				return err
 			}
 
+			defaultProfileExists := false
 			for _, p := range profiles {
 				if p.Name != "default" {
 					continue
 				}
 
+				defaultProfileExists = true
+
+				foundRootDiskDevice := false
+				for k, v := range p.Devices {
+					if v["path"] == "/" && v["source"] == "" {
+						foundRootDiskDevice = true
+
+						// Unconditionally overwrite
+						// because if the user ends up
+						// with a clean LXD but with a
+						// pool property key existing in
+						// the default profile it must
+						// be empty otherwise it would
+						// not have been possible to
+						// delete the storage pool in
+						// the first place.
+						p.ProfilePut.Devices[k]["pool"] = storagePool
+
+						// Update profile devices.
+						err := c.PutProfile("default", p.ProfilePut)
+						if err != nil {
+							return err
+						}
+						shared.LogDebugf("Set pool property of existing root disk device \"%s\" in profile \"default\" to \"%s\".", storagePool)
+
+						break
+					}
+				}
+
+				if foundRootDiskDevice {
+					break
+				}
+
 				props := []string{"path=/", fmt.Sprintf("pool=%s", storagePool)}
 				_, err = c.ProfileDeviceAdd("default", "root", "disk", props)
 				if err != nil {
@@ -429,6 +467,10 @@ they otherwise would.
 				}
 				break
 			}
+
+			if !defaultProfileExists {
+				shared.LogWarnf("Did not find profile \"default\" so no default storage pool will be set. Manual intervention needed.")
+			}
 		}
 	}
 


More information about the lxc-devel mailing list