[lxc-devel] [lxd/master] Storage Create Instance From Image

tomponline on Github lxc-bot at linuxcontainers.org
Fri Nov 1 16:07:31 UTC 2019


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/20191101/042f95d4/attachment.bin>
-------------- next part --------------
From 6e54f64ca62105e1a344d7e2a11d58ae81595164 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Fri, 1 Nov 2019 10:21:43 +0000
Subject: [PATCH 01/13] lxd/storage/load: Adds GetPoolByInstanceName

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

diff --git a/lxd/storage/load.go b/lxd/storage/load.go
index 1c134d75d6..eb7fa6e1a2 100644
--- a/lxd/storage/load.go
+++ b/lxd/storage/load.go
@@ -128,3 +128,13 @@ func GetPoolByName(state *state.State, name string) (Pool, error) {
 
 	return &pool, nil
 }
+
+// GetPoolByInstanceName retrieves the pool from the database using the instance's project and name.
+func GetPoolByInstanceName(s *state.State, projectName, instanceName string) (Pool, error) {
+	poolName, err := s.Cluster.ContainerPool(projectName, instanceName)
+	if err != nil {
+		return nil, err
+	}
+
+	return GetPoolByName(s, poolName)
+}

From a98656fd1a12dbfc6c2be5b7b40eed10ae35808b Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Fri, 1 Nov 2019 14:36:18 +0000
Subject: [PATCH 02/13] lxd/container: Links containerCreateFromImage to new
 storage layer

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

diff --git a/lxd/container.go b/lxd/container.go
index f4cfe3fe44..589525ce5e 100644
--- a/lxd/container.go
+++ b/lxd/container.go
@@ -24,6 +24,8 @@ import (
 	"github.com/lxc/lxd/lxd/instance/instancetype"
 	"github.com/lxc/lxd/lxd/operations"
 	"github.com/lxc/lxd/lxd/state"
+	storagePools "github.com/lxc/lxd/lxd/storage"
+	storageDrivers "github.com/lxc/lxd/lxd/storage/drivers"
 	"github.com/lxc/lxd/lxd/sys"
 	"github.com/lxc/lxd/lxd/task"
 	"github.com/lxc/lxd/shared"
@@ -356,7 +358,7 @@ func containerCreateEmptySnapshot(s *state.State, args db.InstanceArgs) (contain
 	return c, nil
 }
 
-func containerCreateFromImage(d *Daemon, args db.InstanceArgs, hash string, tracker *ioprogress.ProgressTracker) (container, error) {
+func containerCreateFromImage(d *Daemon, args db.InstanceArgs, hash string, op *operations.Operation) (container, error) {
 	s := d.State()
 
 	// Get the image properties
@@ -424,11 +426,34 @@ func containerCreateFromImage(d *Daemon, args db.InstanceArgs, hash string, trac
 		return nil, fmt.Errorf("Error updating image last use date: %s", err)
 	}
 
-	// Now create the storage from an image
-	err = c.Storage().ContainerCreateFromImage(c, hash, tracker)
-	if err != nil {
-		c.Delete()
-		return nil, errors.Wrap(err, "Create container from image")
+	// Check if we can load new storage layer for pool driver type.
+	pool, err := storagePools.GetPoolByInstanceName(d.State(), c.Project(), c.Name())
+	if err != storageDrivers.ErrUnknownDriver {
+		if err != nil {
+			return nil, errors.Wrap(err, "Load instance storage pool")
+		}
+
+		err = pool.CreateInstanceFromImage(c, hash, op)
+		if err != nil {
+			return nil, errors.Wrap(err, "Create instance from image")
+		}
+	} else {
+		metadata := make(map[string]interface{})
+		var tracker *ioprogress.ProgressTracker
+		if op != nil {
+			tracker = &ioprogress.ProgressTracker{
+				Handler: func(percent, speed int64) {
+					shared.SetProgressMetadata(metadata, "create_container_from_image_unpack", "Unpack", percent, 0, speed)
+					op.UpdateMetadata(metadata)
+				}}
+		}
+
+		// Now create the storage from an image
+		err = c.Storage().ContainerCreateFromImage(c, hash, tracker)
+		if err != nil {
+			c.Delete()
+			return nil, errors.Wrap(err, "Create container from image")
+		}
 	}
 
 	// Apply any post-storage configuration

From 7ca2b7f4121ffe10a09a1a1a92deb57f222f1bde Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Fri, 1 Nov 2019 14:36:48 +0000
Subject: [PATCH 03/13] lxd/containers/post: Moves progress tracker into
 containerCreateFromImage

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

diff --git a/lxd/containers_post.go b/lxd/containers_post.go
index 02f05b6c79..0fd29b04b1 100644
--- a/lxd/containers_post.go
+++ b/lxd/containers_post.go
@@ -27,7 +27,6 @@ import (
 	"github.com/lxc/lxd/lxd/response"
 	"github.com/lxc/lxd/shared"
 	"github.com/lxc/lxd/shared/api"
-	"github.com/lxc/lxd/shared/ioprogress"
 	log "github.com/lxc/lxd/shared/log15"
 	"github.com/lxc/lxd/shared/logger"
 	"github.com/lxc/lxd/shared/osarch"
@@ -137,12 +136,7 @@ func createFromImage(d *Daemon, project string, req *api.InstancesPost) response
 			return err
 		}
 
-		metadata := make(map[string]interface{})
-		_, err = containerCreateFromImage(d, args, info.Fingerprint, &ioprogress.ProgressTracker{
-			Handler: func(percent, speed int64) {
-				shared.SetProgressMetadata(metadata, "create_container_from_image_unpack", "Unpack", percent, 0, speed)
-				op.UpdateMetadata(metadata)
-			}})
+		_, err = containerCreateFromImage(d, args, info.Fingerprint, op)
 		return err
 	}
 

From c3be23b19bc70bbe5709d6ab00d0b28b83e8eff6 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Fri, 1 Nov 2019 14:37:09 +0000
Subject: [PATCH 04/13] lxd/images: Removes old unpackImage

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

diff --git a/lxd/images.go b/lxd/images.go
index 77b543cd06..c43e2c4345 100644
--- a/lxd/images.go
+++ b/lxd/images.go
@@ -107,38 +107,6 @@ var imageAliasCmd = APIEndpoint{
    end for whichever finishes last. */
 var imagePublishLock sync.Mutex
 
-func unpackImage(imagefname string, destpath string, sType storageType, runningInUserns bool, tracker *ioprogress.ProgressTracker) error {
-	blockBackend := false
-
-	if sType == storageTypeLvm || sType == storageTypeCeph {
-		blockBackend = true
-	}
-
-	err := shared.Unpack(imagefname, destpath, blockBackend, runningInUserns, tracker)
-	if err != nil {
-		return err
-	}
-
-	rootfsPath := fmt.Sprintf("%s/rootfs", destpath)
-	if shared.PathExists(imagefname + ".rootfs") {
-		err = os.MkdirAll(rootfsPath, 0755)
-		if err != nil {
-			return fmt.Errorf("Error creating rootfs directory")
-		}
-
-		err = shared.Unpack(imagefname+".rootfs", rootfsPath, blockBackend, runningInUserns, tracker)
-		if err != nil {
-			return err
-		}
-	}
-
-	if !shared.PathExists(rootfsPath) {
-		return fmt.Errorf("Image is missing a rootfs: %s", imagefname)
-	}
-
-	return nil
-}
-
 func compressFile(compress string, infile io.Reader, outfile io.Writer) error {
 	reproducible := []string{"gzip"}
 

From fe2b8ec35ae8410bfcf6c2458699221162b3a52c Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Fri, 1 Nov 2019 14:37:38 +0000
Subject: [PATCH 05/13] lxd/storage/backend/lxd: Implements
 CreateInstanceFromImage

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

diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go
index 3a51642a92..3ac4a05a11 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -11,11 +11,13 @@ import (
 	"github.com/lxc/lxd/lxd/instance/instancetype"
 	"github.com/lxc/lxd/lxd/migration"
 	"github.com/lxc/lxd/lxd/operations"
+	"github.com/lxc/lxd/lxd/project"
 	"github.com/lxc/lxd/lxd/state"
 	"github.com/lxc/lxd/lxd/storage/drivers"
 	"github.com/lxc/lxd/lxd/storage/memorypipe"
 	"github.com/lxc/lxd/shared"
 	"github.com/lxc/lxd/shared/api"
+	"github.com/lxc/lxd/shared/ioprogress"
 	log "github.com/lxc/lxd/shared/log15"
 	"github.com/lxc/lxd/shared/logger"
 	"github.com/lxc/lxd/shared/logging"
@@ -171,8 +173,75 @@ func (b *lxdBackend) CreateInstanceFromCopy(inst Instance, src Instance, snapsho
 	return ErrNotImplemented
 }
 
+// createInstanceSymlink creates a symlink in the instance directory to the instance's mount path.
+func (b *lxdBackend) createInstanceSymlink(inst Instance, mountPath string) error {
+	symlinkPath := inst.Path()
+	if !shared.PathExists(symlinkPath) {
+		err := os.Symlink(mountPath, symlinkPath)
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+// CreateInstanceFromImage creates a new volume for an instance populated with the image requested.
 func (b *lxdBackend) CreateInstanceFromImage(inst Instance, fingerprint string, op *operations.Operation) error {
-	return ErrNotImplemented
+	logger := logging.AddContext(b.logger, log.Ctx{"project": inst.Project(), "instance": inst.Name()})
+	logger.Debug("CreateInstanceFromImage started")
+	defer logger.Debug("CreateInstanceFromImage finished")
+
+	volType, err := InstanceTypeToVolumeType(inst.Type())
+	if err != nil {
+		return err
+	}
+
+	revert := true
+	defer func() {
+		if !revert {
+			return
+		}
+		b.DeleteInstance(inst, op)
+	}()
+
+	filler := func(instanceMountPath string) error {
+		var tracker *ioprogress.ProgressTracker
+		if op != nil { // Not passed when being done as part of pre-migration setup.
+			metadata := make(map[string]interface{})
+			tracker = &ioprogress.ProgressTracker{
+				Handler: func(percent, speed int64) {
+					shared.SetProgressMetadata(metadata, "create_instance_from_image_unpack", "Unpack", percent, 0, speed)
+					op.UpdateMetadata(metadata)
+				}}
+		}
+
+		imagePath := shared.VarPath("images", fingerprint)
+
+		// tomp TODO currently passing false to isBlockBackend argument, which only affects
+		// user hint on how to increase disk space if not enough to unpack image. Ask about
+		// removing this argument entirely.
+		return ImageUnpack(imagePath, instanceMountPath, false, b.state.OS.RunningInUserNS, tracker)
+	}
+
+	vol := b.newVolume(volType, drivers.ContentTypeFS, project.Prefix(inst.Project(), inst.Name()), nil)
+	err = b.driver.CreateVolume(vol, filler, op)
+	if err != nil {
+		return err
+	}
+
+	err = b.createInstanceSymlink(inst, vol.MountPath())
+	if err != nil {
+		return err
+	}
+
+	err = inst.TemplateApply("create")
+	if err != nil {
+		return err
+	}
+
+	revert = false
+	return nil
 }
 
 func (b *lxdBackend) CreateInstanceFromMigration(inst Instance, conn io.ReadWriteCloser, args migration.SinkArgs, op *operations.Operation) error {
@@ -184,6 +253,10 @@ func (b *lxdBackend) RenameInstance(inst Instance, newName string, op *operation
 }
 
 func (b *lxdBackend) DeleteInstance(inst Instance, op *operations.Operation) error {
+	logger := logging.AddContext(b.logger, log.Ctx{"project": inst.Project(), "instance": inst.Name()})
+	logger.Debug("DeleteInstance started")
+	defer logger.Debug("DeleteInstance finished")
+
 	return ErrNotImplemented
 }
 
@@ -201,7 +274,7 @@ func (b *lxdBackend) BackupInstance(inst Instance, targetPath string, optimized
 
 // GetInstanceUsage returns the disk usage of the Instance's root device.
 func (b *lxdBackend) GetInstanceUsage(inst Instance) (int64, error) {
-	logger := logging.AddContext(b.logger, log.Ctx{"instance": inst.Name()})
+	logger := logging.AddContext(b.logger, log.Ctx{"project": inst.Project(), "instance": inst.Name()})
 	logger.Debug("GetInstanceUsage started")
 	defer logger.Debug("GetInstanceUsage finished")
 

From 5b00064598537b4f791f16312542f9bbfed6416e Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Fri, 1 Nov 2019 14:38:18 +0000
Subject: [PATCH 06/13] lxd/storage/drivers/driver/dir: Switches to using
 volume.CreateMounthPath()

To ensure perms are applied consistently and correctly across all drivers.

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

diff --git a/lxd/storage/drivers/driver_dir.go b/lxd/storage/drivers/driver_dir.go
index f50ee8ceef..816664c420 100644
--- a/lxd/storage/drivers/driver_dir.go
+++ b/lxd/storage/drivers/driver_dir.go
@@ -172,9 +172,10 @@ func (d *dir) CreateVolume(vol Volume, filler func(path string) error, op *opera
 	volID, err := d.getVolID(vol.volType, vol.name)
 	if err != nil {
 		return err
+
 	}
 
-	err = os.MkdirAll(volPath, 0711)
+	err = vol.CreateMountPath()
 	if err != nil {
 		return err
 	}
@@ -286,7 +287,7 @@ func (d *dir) CreateVolumeFromMigration(vol Volume, conn io.ReadWriteCloser, vol
 		}
 
 		snapPath := snapshot.MountPath()
-		err = os.MkdirAll(snapPath, 0711)
+		err = snapshot.CreateMountPath()
 		if err != nil {
 			return err
 		}
@@ -317,7 +318,7 @@ func (d *dir) CreateVolumeFromMigration(vol Volume, conn io.ReadWriteCloser, vol
 	volPath := vol.MountPath()
 
 	// Finally the actual volume is sent by sender, so create that last.
-	err = os.MkdirAll(volPath, 0711)
+	err = vol.CreateMountPath()
 	if err != nil {
 		return err
 	}
@@ -393,7 +394,7 @@ func (d *dir) CreateVolumeFromCopy(vol Volume, srcVol Volume, copySnapshots bool
 			}
 
 			dstSnapPath := dstSnapshot.MountPath()
-			err = os.MkdirAll(dstSnapPath, 0711)
+			err = dstSnapshot.CreateMountPath()
 			if err != nil {
 				return err
 			}
@@ -416,7 +417,7 @@ func (d *dir) CreateVolumeFromCopy(vol Volume, srcVol Volume, copySnapshots bool
 	}
 
 	volPath := vol.MountPath()
-	err = os.MkdirAll(volPath, 0711)
+	err = vol.CreateMountPath()
 	if err != nil {
 		return err
 	}
@@ -513,6 +514,7 @@ func (d *dir) RenameVolume(volType VolumeType, volName string, newVolName string
 		return err
 	}
 
+	// tomp TODO check old snapshots dir is removed.
 	err = os.MkdirAll(snapshotDir, 0711)
 	if err != nil {
 		return err
@@ -761,10 +763,12 @@ func (d *dir) CreateVolumeSnapshot(volType VolumeType, volName string, newSnapsh
 	}
 
 	srcPath := GetVolumeMountPath(d.name, volType, volName)
-	snapPath := GetVolumeMountPath(d.name, volType, GetSnapshotVolumeName(volName, newSnapshotName))
+	fullSnapName := GetSnapshotVolumeName(volName, newSnapshotName)
+	snapVol := NewVolume(d, d.name, volType, ContentTypeFS, fullSnapName, nil)
+	snapPath := snapVol.MountPath()
 
 	// Create snapshot directory.
-	err = os.MkdirAll(snapPath, 0711)
+	err = snapVol.CreateMountPath()
 	if err != nil {
 		return err
 	}

From 4e69206d98ac48286cd241bfed55526f039b7d02 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Fri, 1 Nov 2019 14:39:02 +0000
Subject: [PATCH 07/13] lxd/storage/drivers/volume: Adds CreateMountPath

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

diff --git a/lxd/storage/drivers/volume.go b/lxd/storage/drivers/volume.go
index 5dd78a91fa..a9dacb955c 100644
--- a/lxd/storage/drivers/volume.go
+++ b/lxd/storage/drivers/volume.go
@@ -2,6 +2,7 @@ package drivers
 
 import (
 	"fmt"
+	"os"
 
 	"github.com/lxc/lxd/lxd/operations"
 	"github.com/lxc/lxd/shared"
@@ -74,6 +75,28 @@ func (v Volume) MountPath() string {
 	return GetVolumeMountPath(v.pool, v.volType, v.name)
 }
 
+// CreateMountPath creates the volume's mount path and sets the correct permission for the type.
+func (v Volume) CreateMountPath() error {
+	volPath := v.MountPath()
+
+	// Create volume's mount path, with any created directories set to 0711.
+	err := os.MkdirAll(volPath, 0711)
+	if err != nil {
+		return err
+	}
+
+	// Set very restrictive mode 0100 for non-custom and non-image volumes.
+	if v.volType != VolumeTypeCustom && v.volType != VolumeTypeImage {
+		// Set mode of actual volume's mount path.
+		err = os.Chmod(volPath, 0100)
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
 // MountTask runs the supplied task after mounting the volume if needed. If the volume was mounted
 // for this then it is unmounted when the task finishes.
 func (v Volume) MountTask(task func(mountPath string, op *operations.Operation) error, op *operations.Operation) error {

From b3f97536789205579bee4320b18ecec75b0e9cc5 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Fri, 1 Nov 2019 14:39:24 +0000
Subject: [PATCH 08/13] lxd/storage/load: Improves getVolID error when volume
 not found

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

diff --git a/lxd/storage/load.go b/lxd/storage/load.go
index eb7fa6e1a2..6db6f2834a 100644
--- a/lxd/storage/load.go
+++ b/lxd/storage/load.go
@@ -32,7 +32,7 @@ func volIDFuncMake(state *state.State, poolID int64) func(volType drivers.Volume
 		volID, _, err := state.Cluster.StoragePoolNodeVolumeGetTypeByProject("default", volName, volTypeID, poolID)
 		if err != nil {
 			if err == db.ErrNoSuchObject {
-				return -1, fmt.Errorf("Volume doesn't exist")
+				return -1, fmt.Errorf("Failed to get volume ID, volume '%s' of type '%s' doesn't exist", volName, volType)
 			}
 
 			return -1, err

From a4cf41b9f00bb7b08bafe0fa735f553bb8b3ff85 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Fri, 1 Nov 2019 14:40:11 +0000
Subject: [PATCH 09/13] lxd/storage/utils: Adds InstanceTypeToVolumeType

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

diff --git a/lxd/storage/utils.go b/lxd/storage/utils.go
index b22e8c1ada..14a40f3e32 100644
--- a/lxd/storage/utils.go
+++ b/lxd/storage/utils.go
@@ -10,6 +10,7 @@ import (
 	"golang.org/x/sys/unix"
 
 	"github.com/lxc/lxd/lxd/db"
+	"github.com/lxc/lxd/lxd/instance/instancetype"
 	"github.com/lxc/lxd/lxd/state"
 	"github.com/lxc/lxd/lxd/storage/drivers"
 	"github.com/lxc/lxd/shared"
@@ -417,6 +418,18 @@ func VolumeTypeToDBType(volType drivers.VolumeType) (int, error) {
 	return -1, fmt.Errorf("Invalid storage volume type")
 }
 
+// InstanceTypeToVolumeType converts instance type to volume type.
+func InstanceTypeToVolumeType(instType instancetype.Type) (drivers.VolumeType, error) {
+	switch instType {
+	case instancetype.Container:
+		return drivers.VolumeTypeContainer, nil
+	case instancetype.VM:
+		return drivers.VolumeTypeVM, nil
+	}
+
+	return "", fmt.Errorf("Invalid instance type")
+}
+
 // VolumeDBCreate creates a volume in the database.
 func VolumeDBCreate(s *state.State, poolName string, volumeName, volumeDescription string, volumeTypeName string, snapshot bool, volumeConfig map[string]string) error {
 	// Convert the volume type name to our internal integer representation.

From b98393ed76969622849b564db154480893cc2387 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Fri, 1 Nov 2019 14:40:22 +0000
Subject: [PATCH 10/13] lxd/storage/utils: Adds ImageUnpack

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

diff --git a/lxd/storage/utils.go b/lxd/storage/utils.go
index 14a40f3e32..c71f69f980 100644
--- a/lxd/storage/utils.go
+++ b/lxd/storage/utils.go
@@ -15,6 +15,7 @@ import (
 	"github.com/lxc/lxd/lxd/storage/drivers"
 	"github.com/lxc/lxd/shared"
 	"github.com/lxc/lxd/shared/api"
+	"github.com/lxc/lxd/shared/ioprogress"
 	"github.com/lxc/lxd/shared/logger"
 	"github.com/lxc/lxd/shared/units"
 )
@@ -696,3 +697,30 @@ func validateVolumeCommonRules() map[string]func(string) error {
 		},
 	}
 }
+
+// ImageUnpack unpacks a filesystem image into the destination path.
+func ImageUnpack(imageFile string, destPath string, blockBackend bool, runningInUserns bool, tracker *ioprogress.ProgressTracker) error {
+	err := shared.Unpack(imageFile, destPath, blockBackend, runningInUserns, tracker)
+	if err != nil {
+		return err
+	}
+
+	rootfsPath := fmt.Sprintf("%s/rootfs", destPath)
+	if shared.PathExists(imageFile + ".rootfs") {
+		err = os.MkdirAll(rootfsPath, 0755)
+		if err != nil {
+			return fmt.Errorf("Error creating rootfs directory")
+		}
+
+		err = shared.Unpack(imageFile+".rootfs", rootfsPath, blockBackend, runningInUserns, tracker)
+		if err != nil {
+			return err
+		}
+	}
+
+	if !shared.PathExists(rootfsPath) {
+		return fmt.Errorf("Image is missing a rootfs: %s", imageFile)
+	}
+
+	return nil
+}

From 0432f3521ec39ca3d47386ddced3172ee6dbbf82 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Fri, 1 Nov 2019 14:40:39 +0000
Subject: [PATCH 11/13] test/suites/basic: Updates tests to take into account
 more secure volume perms

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 test/suites/basic.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/suites/basic.sh b/test/suites/basic.sh
index 29dfe6d64b..a3f7334f9e 100644
--- a/test/suites/basic.sh
+++ b/test/suites/basic.sh
@@ -423,7 +423,7 @@ test_basic_usage() {
   lxc profile create unconfined
   lxc profile set unconfined security.privileged true
   lxc init testimage foo2 -p unconfined -s "lxdtest-$(basename "${LXD_DIR}")"
-  [ "$(stat -L -c "%a" "${LXD_DIR}/containers/foo2")" = "700" ]
+  [ "$(stat -L -c "%a" "${LXD_DIR}/containers/foo2")" = "100" ]
   lxc delete foo2
   lxc profile delete unconfined
 

From e93175747e743d0dcbf7adfe7a06e9d66ffa64ee Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Fri, 1 Nov 2019 14:41:11 +0000
Subject: [PATCH 12/13] lxd: Updates use of driver.ImageUnpack

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage_btrfs.go     | 2 +-
 lxd/storage_ceph.go      | 2 +-
 lxd/storage_dir.go       | 2 +-
 lxd/storage_lvm.go       | 2 +-
 lxd/storage_lvm_utils.go | 2 +-
 lxd/storage_zfs.go       | 2 +-
 6 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/lxd/storage_btrfs.go b/lxd/storage_btrfs.go
index 85a73b8f7c..ff1eb628f6 100644
--- a/lxd/storage_btrfs.go
+++ b/lxd/storage_btrfs.go
@@ -2008,7 +2008,7 @@ func (s *storageBtrfs) ImageCreate(fingerprint string, tracker *ioprogress.Progr
 
 	// Unpack the image in imageMntPoint.
 	imagePath := shared.VarPath("images", fingerprint)
-	err = unpackImage(imagePath, tmpImageSubvolumeName, storageTypeBtrfs, s.s.OS.RunningInUserNS, tracker)
+	err = driver.ImageUnpack(imagePath, tmpImageSubvolumeName, false, s.s.OS.RunningInUserNS, tracker)
 	if err != nil {
 		return err
 	}
diff --git a/lxd/storage_ceph.go b/lxd/storage_ceph.go
index 526a02f1a6..846cc91155 100644
--- a/lxd/storage_ceph.go
+++ b/lxd/storage_ceph.go
@@ -2102,7 +2102,7 @@ func (s *storageCeph) ImageCreate(fingerprint string, tracker *ioprogress.Progre
 
 		// rsync contents into image
 		imagePath := shared.VarPath("images", fingerprint)
-		err = unpackImage(imagePath, imageMntPoint, storageTypeCeph, s.s.OS.RunningInUserNS, nil)
+		err = driver.ImageUnpack(imagePath, imageMntPoint, true, s.s.OS.RunningInUserNS, nil)
 		if err != nil {
 			logger.Errorf(`Failed to unpack image for RBD storage volume for image "%s" on storage pool "%s": %s`, fingerprint, s.pool.Name, err)
 
diff --git a/lxd/storage_dir.go b/lxd/storage_dir.go
index e005c880d6..844849ae0f 100644
--- a/lxd/storage_dir.go
+++ b/lxd/storage_dir.go
@@ -572,7 +572,7 @@ func (s *storageDir) ContainerCreateFromImage(container Instance, imageFingerpri
 	}
 
 	imagePath := shared.VarPath("images", imageFingerprint)
-	err = unpackImage(imagePath, containerMntPoint, storageTypeDir, s.s.OS.RunningInUserNS, nil)
+	err = driver.ImageUnpack(imagePath, containerMntPoint, false, s.s.OS.RunningInUserNS, nil)
 	if err != nil {
 		return errors.Wrap(err, "Unpack image")
 	}
diff --git a/lxd/storage_lvm.go b/lxd/storage_lvm.go
index 763c0c5de1..4a05f07206 100644
--- a/lxd/storage_lvm.go
+++ b/lxd/storage_lvm.go
@@ -1939,7 +1939,7 @@ func (s *storageLvm) ImageCreate(fingerprint string, tracker *ioprogress.Progres
 		}
 
 		imagePath := shared.VarPath("images", fingerprint)
-		err = unpackImage(imagePath, imageMntPoint, storageTypeLvm, s.s.OS.RunningInUserNS, nil)
+		err = driver.ImageUnpack(imagePath, imageMntPoint, true, s.s.OS.RunningInUserNS, nil)
 		if err != nil {
 			return err
 		}
diff --git a/lxd/storage_lvm_utils.go b/lxd/storage_lvm_utils.go
index f782366ad2..56a60c8d11 100644
--- a/lxd/storage_lvm_utils.go
+++ b/lxd/storage_lvm_utils.go
@@ -504,7 +504,7 @@ func (s *storageLvm) containerCreateFromImageLv(c Instance, fp string) error {
 
 	imagePath := shared.VarPath("images", fp)
 	containerMntPoint := driver.GetContainerMountPoint(c.Project(), s.pool.Name, containerName)
-	err = unpackImage(imagePath, containerMntPoint, storageTypeLvm, s.s.OS.RunningInUserNS, nil)
+	err = driver.ImageUnpack(imagePath, containerMntPoint, true, s.s.OS.RunningInUserNS, nil)
 	if err != nil {
 		logger.Errorf(`Failed to unpack image "%s" into non-thinpool LVM storage volume "%s" for container "%s" on storage pool "%s": %s`, imagePath, containerMntPoint, containerName, s.pool.Name, err)
 		return err
diff --git a/lxd/storage_zfs.go b/lxd/storage_zfs.go
index 0e5d7d3cc9..139fbba671 100644
--- a/lxd/storage_zfs.go
+++ b/lxd/storage_zfs.go
@@ -2406,7 +2406,7 @@ func (s *storageZfs) ImageCreate(fingerprint string, tracker *ioprogress.Progres
 	}
 
 	// Unpack the image into the temporary mountpoint.
-	err = unpackImage(imagePath, tmpImageDir, storageTypeZfs, s.s.OS.RunningInUserNS, nil)
+	err = driver.ImageUnpack(imagePath, tmpImageDir, false, s.s.OS.RunningInUserNS, nil)
 	if err != nil {
 		return err
 	}

From db021c9bfc1761babaed53919fc92b2d43a430ba Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Fri, 1 Nov 2019 16:06:03 +0000
Subject: [PATCH 13/13] lxd/storage/load: Makes volIDFuncMake project aware

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

diff --git a/lxd/storage/load.go b/lxd/storage/load.go
index 6db6f2834a..725a0bf2b7 100644
--- a/lxd/storage/load.go
+++ b/lxd/storage/load.go
@@ -2,6 +2,7 @@ package storage
 
 import (
 	"fmt"
+	"strings"
 
 	"github.com/lxc/lxd/lxd/db"
 	"github.com/lxc/lxd/lxd/operations"
@@ -28,11 +29,21 @@ func volIDFuncMake(state *state.State, poolID int64) func(volType drivers.Volume
 			return -1, err
 		}
 
-		// TODO add project support in the future by splitting the volName by "_".
-		volID, _, err := state.Cluster.StoragePoolNodeVolumeGetTypeByProject("default", volName, volTypeID, poolID)
+		// It is possible for the project name to be encoded into the volume name in the
+		// format <project>_<volume>. However not all volume types currently use this
+		// encoding format, so if there is no underscore in the volume name then we assume
+		// the project is default.
+		project := "default"
+		volParts := strings.SplitN(volName, "_", 2)
+		if len(volParts) > 1 {
+			project = volParts[0]
+			volName = volParts[1]
+		}
+
+		volID, _, err := state.Cluster.StoragePoolNodeVolumeGetTypeByProject(project, volName, volTypeID, poolID)
 		if err != nil {
 			if err == db.ErrNoSuchObject {
-				return -1, fmt.Errorf("Failed to get volume ID, volume '%s' of type '%s' doesn't exist", volName, volType)
+				return -1, fmt.Errorf("Failed to get volume ID for project '%s', volume '%s', type '%s': Volume doesn't exist", project, volName, volType)
 			}
 
 			return -1, err


More information about the lxc-devel mailing list