[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