[lxc-devel] [lxd/master] Pre VM function renames

tomponline on Github lxc-bot at linuxcontainers.org
Thu Nov 7 09:30:55 UTC 2019


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 413 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20191107/3467ab20/attachment-0001.bin>
-------------- next part --------------
From bf38ffa62fc0014da3e03528e4dcfb7e5b5888ae Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 6 Nov 2019 10:56:01 +0000
Subject: [PATCH 01/27] lxd/api/internal: Updates use of renamed functions

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

diff --git a/lxd/api_internal.go b/lxd/api_internal.go
index cdf6dbc1b9..392b30f81f 100644
--- a/lxd/api_internal.go
+++ b/lxd/api_internal.go
@@ -871,7 +871,7 @@ func internalImport(d *Daemon, r *http.Request) response.Response {
 	if containerErr == nil {
 		// Remove the storage volume db entry for the container since
 		// force was specified.
-		err := d.cluster.ContainerRemove(projectName, req.Name)
+		err := d.cluster.InstanceRemove(projectName, req.Name)
 		if err != nil {
 			return response.SmartError(err)
 		}
@@ -916,7 +916,7 @@ func internalImport(d *Daemon, r *http.Request) response.Response {
 	if err != nil {
 		return response.SmartError(err)
 	}
-	_, err = containerCreateInternal(d.State(), db.InstanceArgs{
+	_, err = instanceCreateInternal(d.State(), db.InstanceArgs{
 		Project:      projectName,
 		Architecture: arch,
 		BaseImage:    baseImage,
@@ -982,7 +982,7 @@ func internalImport(d *Daemon, r *http.Request) response.Response {
 		}
 
 		if snapErr == nil {
-			err := d.cluster.ContainerRemove(projectName, snap.Name)
+			err := d.cluster.InstanceRemove(projectName, snap.Name)
 			if err != nil {
 				return response.SmartError(err)
 			}
@@ -1022,7 +1022,7 @@ func internalImport(d *Daemon, r *http.Request) response.Response {
 			snap.Devices[rootDevName] = rootDev
 		}
 
-		_, err = containerCreateInternal(d.State(), db.InstanceArgs{
+		_, err = instanceCreateInternal(d.State(), db.InstanceArgs{
 			Project:      projectName,
 			Architecture: arch,
 			BaseImage:    baseImage,

From 14d712908d862a74bf64775d010869a532772fa2 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 6 Nov 2019 10:58:31 +0000
Subject: [PATCH 02/27] lxd/container: Updates return values of instance create
 and load functions

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

diff --git a/lxd/container.go b/lxd/container.go
index 0fcb2fdea6..d3ecf525ef 100644
--- a/lxd/container.go
+++ b/lxd/container.go
@@ -255,9 +255,9 @@ type container interface {
 }
 
 // containerCreateAsEmpty creates an empty instance.
-func containerCreateAsEmpty(d *Daemon, args db.InstanceArgs) (container, error) {
+func containerCreateAsEmpty(d *Daemon, args db.InstanceArgs) (Instance, error) {
 	// Create the container.
-	c, err := containerCreateInternal(d.State(), args)
+	c, err := instanceCreateInternal(d.State(), args)
 	if err != nil {
 		return nil, err
 	}
@@ -402,9 +402,9 @@ func containerCreateFromBackup(s *state.State, info backup.Info, data io.ReadSee
 	return pool, nil
 }
 
-func containerCreateEmptySnapshot(s *state.State, args db.InstanceArgs) (container, error) {
+func containerCreateEmptySnapshot(s *state.State, args db.InstanceArgs) (Instance, error) {
 	// Create the snapshot
-	c, err := containerCreateInternal(s, args)
+	c, err := instanceCreateInternal(s, args)
 	if err != nil {
 		return nil, err
 	}
@@ -544,7 +544,7 @@ func containerCreateAsCopy(s *state.State, args db.InstanceArgs, sourceContainer
 
 	if !refresh {
 		// Create the container.
-		ct, err = containerCreateInternal(s, args)
+		ct, err = instanceCreateInternal(s, args)
 		if err != nil {
 			return nil, err
 		}
@@ -564,7 +564,7 @@ func containerCreateAsCopy(s *state.State, args db.InstanceArgs, sourceContainer
 		parentStoragePool = parentLocalRootDiskDevice["pool"]
 	}
 
-	csList := []*container{}
+	csList := []*Instance{}
 	var snapshots []Instance
 
 	if !containerOnly {
@@ -632,7 +632,7 @@ func containerCreateAsCopy(s *state.State, args db.InstanceArgs, sourceContainer
 			}
 
 			// Create the snapshots.
-			cs, err := containerCreateInternal(s, csArgs)
+			cs, err := instanceCreateInternal(s, csArgs)
 			if err != nil {
 				if !refresh {
 					ct.Delete()
@@ -750,7 +750,7 @@ func containerCreateAsSnapshot(s *state.State, args db.InstanceArgs, sourceInsta
 	}
 
 	// Create the snapshot
-	c, err := containerCreateInternal(s, args)
+	c, err := instanceCreateInternal(s, args)
 	if err != nil {
 		return nil, err
 	}

From eeb7dccef05d70fdcbf54c66b0c0b123fbf8ddfd Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 6 Nov 2019 10:59:11 +0000
Subject: [PATCH 03/27] lxc/container: Renames containerCreateFromImage to
 instanceCreateFromImage

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

diff --git a/lxd/container.go b/lxd/container.go
index d3ecf525ef..537d524186 100644
--- a/lxd/container.go
+++ b/lxd/container.go
@@ -419,8 +419,8 @@ func containerCreateEmptySnapshot(s *state.State, args db.InstanceArgs) (Instanc
 	return c, nil
 }
 
-// containerCreateFromImage creates an instance from a rootfs image.
-func containerCreateFromImage(d *Daemon, args db.InstanceArgs, hash string, op *operations.Operation) (container, error) {
+// instanceCreateFromImage creates an instance from a rootfs image.
+func instanceCreateFromImage(d *Daemon, args db.InstanceArgs, hash string, op *operations.Operation) (Instance, error) {
 	s := d.State()
 
 	// Get the image properties.
@@ -475,59 +475,66 @@ func containerCreateFromImage(d *Daemon, args db.InstanceArgs, hash string, op *
 	// Set the BaseImage field (regardless of previous value).
 	args.BaseImage = hash
 
-	// Create the container
-	c, err := containerCreateInternal(s, args)
+	// Create the instance.
+	inst, err := instanceCreateInternal(s, args)
 	if err != nil {
-		return nil, errors.Wrap(err, "Create container")
+		return nil, errors.Wrap(err, "Create instance")
 	}
 
+	revert := true
+	defer func() {
+		if !revert {
+			return
+		}
+
+		inst.Delete()
+	}()
+
 	err = s.Cluster.ImageLastAccessUpdate(hash, time.Now().UTC())
 	if err != nil {
-		c.Delete()
 		return nil, fmt.Errorf("Error updating image last use date: %s", err)
 	}
 
 	// Check if we can load new storage layer for pool driver type.
-	pool, err := storagePools.GetPoolByInstance(d.State(), c)
+	pool, err := storagePools.GetPoolByInstance(d.State(), inst)
 	if err != storageDrivers.ErrUnknownDriver && err != storageDrivers.ErrNotImplemented {
 		if err != nil {
 			return nil, errors.Wrap(err, "Load instance storage pool")
 		}
 
-		err = pool.CreateInstanceFromImage(c, hash, op)
+		err = pool.CreateInstanceFromImage(inst, hash, op)
 		if err != nil {
-			c.Delete()
 			return nil, errors.Wrap(err, "Create instance from image")
 		}
-	} else if c.Type() == instancetype.Container {
+	} else if inst.Type() == instancetype.Container {
 		metadata := make(map[string]interface{})
 		var tracker *ioprogress.ProgressTracker
 		if op != nil {
 			tracker = &ioprogress.ProgressTracker{
 				Handler: func(percent, speed int64) {
+					// tomp TODO should the container reference here be removed?
 					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)
+		err = inst.Storage().ContainerCreateFromImage(inst, hash, tracker)
 		if err != nil {
-			c.Delete()
-			return nil, errors.Wrap(err, "Create container from image")
+			return nil, errors.Wrap(err, "Create instance from image")
 		}
 	} else {
 		return nil, fmt.Errorf("Instance type not supported")
 	}
 
 	// Apply any post-storage configuration.
-	err = containerConfigureInternal(d.State(), c)
+	err = containerConfigureInternal(d.State(), inst)
 	if err != nil {
-		c.Delete()
-		return nil, errors.Wrap(err, "Configure container")
+		return nil, errors.Wrap(err, "Configure instance")
 	}
 
-	return c, nil
+	revert = false
+	return inst, nil
 }
 
 func containerCreateAsCopy(s *state.State, args db.InstanceArgs, sourceContainer Instance, containerOnly bool, refresh bool) (Instance, error) {

From 3fc7315e8d4390a79765b9bb733de4c80d4dc237 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 6 Nov 2019 10:59:50 +0000
Subject: [PATCH 04/27] lxd/container: Renames containerCreateInternal to
 instanceCreateInternal

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

diff --git a/lxd/container.go b/lxd/container.go
index 537d524186..bd7d848107 100644
--- a/lxd/container.go
+++ b/lxd/container.go
@@ -799,8 +799,8 @@ func containerCreateAsSnapshot(s *state.State, args db.InstanceArgs, sourceInsta
 	return c, nil
 }
 
-func containerCreateInternal(s *state.State, args db.InstanceArgs) (container, error) {
-	// Set default values
+func instanceCreateInternal(s *state.State, args db.InstanceArgs) (Instance, error) {
+	// Set default values.
 	if args.Project == "" {
 		args.Project = "default"
 	}
@@ -832,11 +832,11 @@ func containerCreateInternal(s *state.State, args db.InstanceArgs) (container, e
 			return nil, err
 		}
 
-		// Unset expiry date since containers don't expire
+		// Unset expiry date since containers don't expire.
 		args.ExpiryDate = time.Time{}
 	}
 
-	// Validate container config
+	// Validate container config.
 	err := containerValidConfig(s.OS, args.Config, false, false)
 	if err != nil {
 		return nil, err
@@ -848,7 +848,7 @@ func containerCreateInternal(s *state.State, args db.InstanceArgs) (container, e
 		return nil, errors.Wrap(err, "Invalid devices")
 	}
 
-	// Validate architecture
+	// Validate architecture.
 	_, err = osarch.ArchitectureName(args.Architecture)
 	if err != nil {
 		return nil, err
@@ -858,7 +858,7 @@ func containerCreateInternal(s *state.State, args db.InstanceArgs) (container, e
 		return nil, fmt.Errorf("Requested architecture isn't supported by this host")
 	}
 
-	// Validate profiles
+	// Validate profiles.
 	profiles, err := s.Cluster.Profiles(args.Project)
 	if err != nil {
 		return nil, err
@@ -885,15 +885,15 @@ func containerCreateInternal(s *state.State, args db.InstanceArgs) (container, e
 		args.LastUsedDate = time.Unix(0, 0).UTC()
 	}
 
-	var container db.Instance
+	var dbInst db.Instance
+
 	err = s.Cluster.Transaction(func(tx *db.ClusterTx) error {
 		node, err := tx.NodeName()
 		if err != nil {
 			return err
 		}
 
-		// TODO: this check should probably be performed by the db
-		// package itself.
+		// TODO: this check should probably be performed by the db package itself.
 		exists, err := tx.ProjectExists(args.Project)
 		if err != nil {
 			return errors.Wrapf(err, "Check if project %q exists", args.Project)
@@ -932,13 +932,13 @@ func containerCreateInternal(s *state.State, args db.InstanceArgs) (container, e
 				return errors.Wrap(err, "Fetch created snapshot from the database")
 			}
 
-			container = db.InstanceSnapshotToInstance(instance, s)
+			dbInst = db.InstanceSnapshotToInstance(instance, s)
 
 			return nil
 		}
 
-		// Create the container entry
-		container = db.Instance{
+		// Create the instance entry.
+		dbInst = db.Instance{
 			Project:      args.Project,
 			Name:         args.Name,
 			Node:         node,
@@ -956,28 +956,28 @@ func containerCreateInternal(s *state.State, args db.InstanceArgs) (container, e
 			ExpiryDate:   args.ExpiryDate,
 		}
 
-		_, err = tx.InstanceCreate(container)
+		_, err = tx.InstanceCreate(dbInst)
 		if err != nil {
-			return errors.Wrap(err, "Add container info to the database")
+			return errors.Wrap(err, "Add instance info to the database")
 		}
 
-		// Read back the container, to get ID and creation time.
-		c, err := tx.InstanceGet(args.Project, args.Name)
+		// Read back the instance, to get ID and creation time.
+		dbRow, err := tx.InstanceGet(args.Project, args.Name)
 		if err != nil {
-			return errors.Wrap(err, "Fetch created container from the database")
+			return errors.Wrap(err, "Fetch created instance from the database")
 		}
 
-		container = *c
+		dbInst = *dbRow
 
-		if container.ID < 1 {
-			return errors.Wrapf(err, "Unexpected container database ID %d", container.ID)
+		if dbInst.ID < 1 {
+			return errors.Wrapf(err, "Unexpected instance database ID %d", dbInst.ID)
 		}
 
 		return nil
 	})
 	if err != nil {
 		if err == db.ErrAlreadyDefined {
-			thing := "Container"
+			thing := "Instance"
 			if shared.IsSnapshot(args.Name) {
 				thing = "Snapshot"
 			}
@@ -986,19 +986,34 @@ func containerCreateInternal(s *state.State, args db.InstanceArgs) (container, e
 		return nil, err
 	}
 
-	// Wipe any existing log for this container name
+	revert := true
+	defer func() {
+		if !revert {
+			return
+		}
+
+		s.Cluster.InstanceRemove(dbInst.Project, dbInst.Name)
+	}()
+
+	// Wipe any existing log for this instance name.
 	os.RemoveAll(shared.LogPath(args.Name))
 
-	args = db.ContainerToArgs(&container)
+	args = db.ContainerToArgs(&dbInst)
+
+	var inst Instance
+
+	if args.Type == instancetype.Container {
+		inst, err = containerLXCCreate(s, args)
+	} else {
+		return nil, fmt.Errorf("Instance type invalid")
+	}
 
-	// Setup the container struct and finish creation (storage and idmap)
-	c, err := containerLXCCreate(s, args)
 	if err != nil {
-		s.Cluster.ContainerRemove(args.Project, args.Name)
-		return nil, errors.Wrap(err, "Create LXC container")
+		return nil, errors.Wrap(err, "Create instance")
 	}
 
-	return c, nil
+	revert = false
+	return inst, nil
 }
 
 func containerConfigureInternal(state *state.State, c Instance) error {

From be479c678960be804016843d6eb1f41d5eb4d7ad Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 6 Nov 2019 11:00:39 +0000
Subject: [PATCH 05/27] lxd/container/lxc: Updates use of renamed
 c.state.Cluster.InstanceRemove

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

diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index b52b732806..2071b242bb 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -3614,7 +3614,7 @@ func (c *containerLXC) Delete() error {
 		}
 
 		// Remove the database record of the instance or snapshot instance.
-		if err := c.state.Cluster.ContainerRemove(c.Project(), c.Name()); err != nil {
+		if err := c.state.Cluster.InstanceRemove(c.Project(), c.Name()); err != nil {
 			logger.Error("Failed deleting instance entry", log.Ctx{"project": c.Project(), "instance": c.Name(), "err": err})
 			return err
 		}
@@ -3689,7 +3689,7 @@ func (c *containerLXC) Delete() error {
 		}
 
 		// Remove the database record
-		if err := c.state.Cluster.ContainerRemove(c.project, c.Name()); err != nil {
+		if err := c.state.Cluster.InstanceRemove(c.project, c.Name()); err != nil {
 			logger.Error("Failed deleting container entry", log.Ctx{"name": c.Name(), "err": err})
 			return err
 		}

From 58ad929d5189b1fe0455220f23bf67c063158f33 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 6 Nov 2019 11:01:04 +0000
Subject: [PATCH 06/27] lxd/containers/post: Adds VM support to createFromImage

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

diff --git a/lxd/containers_post.go b/lxd/containers_post.go
index e784bb3563..d501b67d9a 100644
--- a/lxd/containers_post.go
+++ b/lxd/containers_post.go
@@ -118,9 +118,16 @@ func createFromImage(d *Daemon, project string, req *api.InstancesPost) response
 			if err != nil {
 				return err
 			}
+
+			// Detect image type based on instance type requested.
+			imgType := "container"
+			if req.Type == "virtual-machine" {
+				imgType = "virtual-machine"
+			}
+
 			info, err = d.ImageDownload(
 				op, req.Source.Server, req.Source.Protocol, req.Source.Certificate,
-				req.Source.Secret, hash, "container", true, autoUpdate, "", true, project)
+				req.Source.Secret, hash, imgType, true, autoUpdate, "", true, project)
 			if err != nil {
 				return err
 			}
@@ -136,11 +143,12 @@ func createFromImage(d *Daemon, project string, req *api.InstancesPost) response
 			return err
 		}
 
-		_, err = containerCreateFromImage(d, args, info.Fingerprint, op)
+		_, err = instanceCreateFromImage(d, args, info.Fingerprint, op)
 		return err
 	}
 
 	resources := map[string][]string{}
+	// tomp TODO should this be renamed/added to?
 	resources["containers"] = []string{req.Name}
 
 	op, err := operations.OperationCreate(d.State(), project, operations.OperationClassTask, db.OperationContainerCreate, resources, nil, run, nil, nil)
@@ -198,7 +206,7 @@ func createFromMigration(d *Daemon, project string, req *api.InstancesPost) resp
 		return response.NotImplemented(fmt.Errorf("Mode '%s' not implemented", req.Source.Mode))
 	}
 
-	var c container
+	var c Instance
 
 	// Parse the architecture name
 	architecture, err := osarch.ArchitectureId(req.Architecture)
@@ -293,7 +301,7 @@ func createFromMigration(d *Daemon, project string, req *api.InstancesPost) resp
 			return response.BadRequest(fmt.Errorf("Instance type not container"))
 		}
 
-		c = inst.(container)
+		c = inst
 	}
 
 	if !req.Source.Refresh {
@@ -340,7 +348,7 @@ func createFromMigration(d *Daemon, project string, req *api.InstancesPost) resp
 			}
 
 			if ps.MigrationType() == migration.MigrationFSType_RSYNC {
-				c, err = containerCreateFromImage(d, args, req.Source.BaseImage, nil)
+				c, err = instanceCreateFromImage(d, args, req.Source.BaseImage, nil)
 				if err != nil {
 					return response.InternalError(err)
 				}

From da249124590ba32ec28611124b8ca129442069ac Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 6 Nov 2019 11:01:19 +0000
Subject: [PATCH 07/27] lxd/db/containers: Renames ContainerRemove to
 InstanceRemove

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

diff --git a/lxd/db/containers.go b/lxd/db/containers.go
index b2b4cf9d3d..58ff234f32 100644
--- a/lxd/db/containers.go
+++ b/lxd/db/containers.go
@@ -620,8 +620,8 @@ func (c *ClusterTx) configUpdate(id int, values map[string]string, insertSQL, de
 	return nil
 }
 
-// ContainerRemove removes the container with the given name from the database.
-func (c *Cluster) ContainerRemove(project, name string) error {
+// InstanceRemove removes the instance with the given name from the database.
+func (c *Cluster) InstanceRemove(project, name string) error {
 	if strings.Contains(name, shared.SnapshotDelimiter) {
 		parts := strings.SplitN(name, shared.SnapshotDelimiter, 2)
 		return c.Transaction(func(tx *ClusterTx) error {

From a6882c6c579b3d431af91b4ff6a45c18e0c3b59e Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 6 Nov 2019 11:04:06 +0000
Subject: [PATCH 08/27] lxd/container: Renames containerCreateAsEmpty to
 containerCreateAsEmpty

- Adds revert for safety

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

diff --git a/lxd/container.go b/lxd/container.go
index bd7d848107..f25f232e12 100644
--- a/lxd/container.go
+++ b/lxd/container.go
@@ -254,31 +254,38 @@ type container interface {
 	NextIdmap() (*idmap.IdmapSet, error)
 }
 
-// containerCreateAsEmpty creates an empty instance.
-func containerCreateAsEmpty(d *Daemon, args db.InstanceArgs) (Instance, error) {
-	// Create the container.
-	c, err := instanceCreateInternal(d.State(), args)
+// instanceCreateAsEmpty creates an empty instance.
+func instanceCreateAsEmpty(d *Daemon, args db.InstanceArgs) (Instance, error) {
+	// Create the instance record.
+	inst, err := instanceCreateInternal(d.State(), args)
 	if err != nil {
 		return nil, err
 	}
 
+	revert := true
+	defer func() {
+		if !revert {
+			return
+		}
+
+		inst.Delete()
+	}()
+
 	// Check if we can load new storage layer for pool driver type.
-	pool, err := storagePools.GetPoolByInstance(d.State(), c)
+	pool, err := storagePools.GetPoolByInstance(d.State(), inst)
 	if err != storageDrivers.ErrUnknownDriver && err != storageDrivers.ErrNotImplemented {
 		if err != nil {
 			return nil, errors.Wrap(err, "Load instance storage pool")
 		}
 
-		err = pool.CreateInstance(c, nil)
+		err = pool.CreateInstance(inst, nil)
 		if err != nil {
-			c.Delete()
 			return nil, errors.Wrap(err, "Create instance")
 		}
-	} else if c.Type() == instancetype.Container {
+	} else if inst.Type() == instancetype.Container {
 		// Now create the empty storage.
-		err = c.Storage().ContainerCreate(c)
+		err = inst.Storage().ContainerCreate(inst)
 		if err != nil {
-			c.Delete()
 			return nil, err
 		}
 	} else {
@@ -286,13 +293,13 @@ func containerCreateAsEmpty(d *Daemon, args db.InstanceArgs) (Instance, error) {
 	}
 
 	// Apply any post-storage configuration.
-	err = containerConfigureInternal(d.State(), c)
+	err = containerConfigureInternal(d.State(), inst)
 	if err != nil {
-		c.Delete()
 		return nil, err
 	}
 
-	return c, nil
+	revert = false
+	return inst, nil
 }
 
 func containerCreateFromBackup(s *state.State, info backup.Info, data io.ReadSeeker,

From 2ad54c4f2bbd19253027be680eabd0f20be4b5ca Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 6 Nov 2019 11:09:46 +0000
Subject: [PATCH 09/27] lxd/containers/post: Updates use of
 instanceCreateAsEmpty

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

diff --git a/lxd/containers_post.go b/lxd/containers_post.go
index d501b67d9a..eced2a1c89 100644
--- a/lxd/containers_post.go
+++ b/lxd/containers_post.go
@@ -185,7 +185,7 @@ func createFromNone(d *Daemon, project string, req *api.InstancesPost) response.
 	}
 
 	run := func(op *operations.Operation) error {
-		_, err := containerCreateAsEmpty(d, args)
+		_, err := instanceCreateAsEmpty(d, args)
 		return err
 	}
 
@@ -320,7 +320,7 @@ func createFromMigration(d *Daemon, project string, req *api.InstancesPost) resp
 		 */
 		_, _, err = d.cluster.ImageGet(args.Project, req.Source.BaseImage, false, true)
 		if err != nil {
-			c, err = containerCreateAsEmpty(d, args)
+			c, err = instanceCreateAsEmpty(d, args)
 			if err != nil {
 				return response.InternalError(err)
 			}
@@ -353,7 +353,7 @@ func createFromMigration(d *Daemon, project string, req *api.InstancesPost) resp
 					return response.InternalError(err)
 				}
 			} else {
-				c, err = containerCreateAsEmpty(d, args)
+				c, err = instanceCreateAsEmpty(d, args)
 				if err != nil {
 					return response.InternalError(err)
 				}

From 1901d15737fbb80e9a122f77451120fee05716dc Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 6 Nov 2019 11:36:17 +0000
Subject: [PATCH 10/27] lxd/storage/backend/lxd: Pass correct content type to
 storage drivers for VMs

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

diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go
index f246a6352a..f05cc06bb6 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -299,7 +299,12 @@ func (b *lxdBackend) CreateInstance(inst Instance, op *operations.Operation) err
 		b.DeleteInstance(inst, op)
 	}()
 
-	vol := b.newVolume(volType, drivers.ContentTypeFS, project.Prefix(inst.Project(), inst.Name()), nil)
+	contentType := drivers.ContentTypeFS
+	if inst.Type() == instancetype.VM {
+		contentType = drivers.ContentTypeBlock
+	}
+
+	vol := b.newVolume(volType, contentType, project.Prefix(inst.Project(), inst.Name()), nil)
 	err = b.driver.CreateVolume(vol, nil, op)
 	if err != nil {
 		return err
@@ -366,7 +371,12 @@ func (b *lxdBackend) CreateInstanceFromImage(inst Instance, fingerprint string,
 		b.DeleteInstance(inst, op)
 	}()
 
-	vol := b.newVolume(volType, drivers.ContentTypeFS, project.Prefix(inst.Project(), inst.Name()), nil)
+	contentType := drivers.ContentTypeFS
+	if inst.Type() == instancetype.VM {
+		contentType = drivers.ContentTypeBlock
+	}
+
+	vol := b.newVolume(volType, contentType, project.Prefix(inst.Project(), inst.Name()), nil)
 
 	// If the driver doesn't support optimized image volumes then create a new empty volume and
 	// populate it with the contents of the image archive.
@@ -384,7 +394,7 @@ func (b *lxdBackend) CreateInstanceFromImage(inst Instance, fingerprint string,
 			return err
 		}
 
-		imgVol := b.newVolume(drivers.VolumeTypeImage, drivers.ContentTypeFS, fingerprint, nil)
+		imgVol := b.newVolume(drivers.VolumeTypeImage, contentType, fingerprint, nil)
 		err = b.driver.CreateVolumeFromCopy(vol, imgVol, false, op)
 		if err != nil {
 			return err
@@ -839,9 +849,20 @@ func (b *lxdBackend) EnsureImage(fingerprint string, op *operations.Operation) e
 		return nil
 	}
 
+	// Load image info from database.
+	_, image, err := b.state.Cluster.ImageGetFromAnyProject(fingerprint)
+	if err != nil {
+		return err
+	}
+
+	contentType := drivers.ContentTypeFS
+	if api.InstanceType(image.Type) == api.InstanceTypeVM {
+		contentType = drivers.ContentTypeBlock
+	}
+
 	// Create the new image volume.
-	vol := b.newVolume(drivers.VolumeTypeImage, drivers.ContentTypeFS, fingerprint, nil)
-	err := b.driver.CreateVolume(vol, b.imageFiller(fingerprint, op), op)
+	vol := b.newVolume(drivers.VolumeTypeImage, contentType, fingerprint, nil)
+	err = b.driver.CreateVolume(vol, b.imageFiller(fingerprint, op), op)
 	if err != nil {
 		return err
 	}

From ebfc5f673d3abcd1dcfb6ae6acd9d541937f4af9 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 6 Nov 2019 11:57:18 +0000
Subject: [PATCH 11/27] lxd/storage/drivers/utils: Unexports
 deleteParentSnapshotDirIfEmpty

As not used outside of package.

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

diff --git a/lxd/storage/drivers/utils.go b/lxd/storage/drivers/utils.go
index ffc09539ed..655c2ac58a 100644
--- a/lxd/storage/drivers/utils.go
+++ b/lxd/storage/drivers/utils.go
@@ -192,9 +192,9 @@ func GetSnapshotVolumeName(parentName, snapshotName string) string {
 	return fmt.Sprintf("%s%s%s", parentName, shared.SnapshotDelimiter, snapshotName)
 }
 
-// DeleteParentSnapshotDirIfEmpty removes the parent snapshot directory if it is empty.
+// deleteParentSnapshotDirIfEmpty removes the parent snapshot directory if it is empty.
 // It accepts the pool name, volume type and parent volume name.
-func DeleteParentSnapshotDirIfEmpty(poolName string, volType VolumeType, volName string) error {
+func deleteParentSnapshotDirIfEmpty(poolName string, volType VolumeType, volName string) error {
 	snapshotsPath, err := GetVolumeSnapshotDir(poolName, volType, volName)
 	if err != nil {
 		return err

From 5d70b6b162775ef4e1a9de2ab58231e0380d0add Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 6 Nov 2019 11:57:50 +0000
Subject: [PATCH 12/27] lxd/storage/drivers/driver/dir: Updates use of
 deleteParentSnapshotDirIfEmpty

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

diff --git a/lxd/storage/drivers/driver_dir.go b/lxd/storage/drivers/driver_dir.go
index 58592d8b36..fdb9507217 100644
--- a/lxd/storage/drivers/driver_dir.go
+++ b/lxd/storage/drivers/driver_dir.go
@@ -639,7 +639,7 @@ func (d *dir) DeleteVolume(volType VolumeType, volName string, op *operations.Op
 
 	// Although the volume snapshot directory should already be removed, lets remove it here
 	// to just in case the top-level directory is left.
-	err = DeleteParentSnapshotDirIfEmpty(d.name, volType, volName)
+	err = deleteParentSnapshotDirIfEmpty(d.name, volType, volName)
 	if err != nil {
 		return err
 	}
@@ -834,7 +834,7 @@ func (d *dir) DeleteVolumeSnapshot(volType VolumeType, volName string, snapshotN
 	}
 
 	// Remove the parent snapshot directory if this is the last snapshot being removed.
-	err = DeleteParentSnapshotDirIfEmpty(d.name, volType, volName)
+	err = deleteParentSnapshotDirIfEmpty(d.name, volType, volName)
 	if err != nil {
 		return err
 	}

From 5f3ecea76bc2a302087ac973edd5b2e86cb3b060 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 6 Nov 2019 16:54:27 +0000
Subject: [PATCH 13/27] lxd/container/lxc: Updating DB usage to be instance
 type agnostic

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

diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index 2071b242bb..a6e5a13c96 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -3544,7 +3544,7 @@ func (c *containerLXC) Delete() error {
 	}
 
 	// Get the storage pool name of the instance.
-	poolName, err := c.state.Cluster.ContainerPool(c.Project(), c.Name())
+	poolName, err := c.state.Cluster.InstancePool(c.Project(), c.Name())
 	if err != nil {
 		return err
 	}
@@ -4055,7 +4055,12 @@ func writeBackupFile(c Instance) error {
 		return err
 	}
 
-	_, volume, err := s.Cluster.StoragePoolNodeVolumeGetTypeByProject(c.Project(), c.Name(), storagePoolVolumeTypeContainer, poolID)
+	dbType := db.StoragePoolVolumeTypeContainer
+	if c.Type() == instancetype.VM {
+		dbType = db.StoragePoolVolumeTypeVM
+	}
+
+	_, volume, err := s.Cluster.StoragePoolNodeVolumeGetTypeByProject(c.Project(), c.Name(), dbType, poolID)
 	if err != nil {
 		return err
 	}
@@ -6897,7 +6902,7 @@ func (c *containerLXC) StatePath() string {
 }
 
 func (c *containerLXC) StoragePool() (string, error) {
-	poolName, err := c.state.Cluster.ContainerPool(c.Project(), c.Name())
+	poolName, err := c.state.Cluster.InstancePool(c.Project(), c.Name())
 	if err != nil {
 		return "", err
 	}

From 1c8ad86c88eb129ac5796561d4563e61c10faf7e Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 6 Nov 2019 16:54:59 +0000
Subject: [PATCH 14/27] lxd/container/post: Updates usage of InstancePool

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

diff --git a/lxd/container_post.go b/lxd/container_post.go
index d9027961ce..3371b332b9 100644
--- a/lxd/container_post.go
+++ b/lxd/container_post.go
@@ -178,7 +178,7 @@ func containerPost(d *Daemon, r *http.Request) response.Response {
 			}
 
 			// Check if we are migrating a ceph-based container.
-			poolName, err := d.cluster.ContainerPool(project, name)
+			poolName, err := d.cluster.InstancePool(project, name)
 			if err != nil {
 				err = errors.Wrap(err, "Failed to fetch container's pool name")
 				return response.SmartError(err)
@@ -449,7 +449,7 @@ func containerPostClusteringMigrateWithCeph(d *Daemon, c Instance, project, oldN
 				return errors.Wrapf(
 					err, "Move container %s to %s with new name %s", oldName, newNode, newName)
 			}
-			poolName, err = tx.ContainerPool(project, newName)
+			poolName, err = tx.InstancePool(project, newName)
 			if err != nil {
 				return errors.Wrapf(err, "Get the container's storage pool name for %s", newName)
 			}

From 4f1254a4b996e4543939852487c383116e81b1fc Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 6 Nov 2019 17:19:55 +0000
Subject: [PATCH 15/27] lxd/container/test: Updates instanceCreateInternal
 usage

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

diff --git a/lxd/container_test.go b/lxd/container_test.go
index 4d49318e56..92b7711e9b 100644
--- a/lxd/container_test.go
+++ b/lxd/container_test.go
@@ -26,7 +26,7 @@ func (suite *containerTestSuite) TestContainer_ProfilesDefault() {
 		Name:      "testFoo",
 	}
 
-	c, err := containerCreateInternal(suite.d.State(), args)
+	c, err := instanceCreateInternal(suite.d.State(), args)
 	suite.Req.Nil(err)
 	defer c.Delete()
 
@@ -34,7 +34,7 @@ func (suite *containerTestSuite) TestContainer_ProfilesDefault() {
 	suite.Len(
 		profiles,
 		1,
-		"No default profile created on containerCreateInternal.")
+		"No default profile created on instanceCreateInternal.")
 
 	suite.Equal(
 		"default",
@@ -69,7 +69,7 @@ func (suite *containerTestSuite) TestContainer_ProfilesMulti() {
 		Name:      "testFoo",
 	}
 
-	c, err := containerCreateInternal(suite.d.State(), args)
+	c, err := instanceCreateInternal(suite.d.State(), args)
 	suite.Req.Nil(err)
 	defer c.Delete()
 
@@ -77,7 +77,7 @@ func (suite *containerTestSuite) TestContainer_ProfilesMulti() {
 	suite.Len(
 		profiles,
 		2,
-		"Didn't get both profiles in containerCreateInternal.")
+		"Didn't get both profiles in instanceCreateInternal.")
 
 	suite.True(
 		c.IsPrivileged(),
@@ -97,7 +97,7 @@ func (suite *containerTestSuite) TestContainer_ProfilesOverwriteDefaultNic() {
 		Name: "testFoo",
 	}
 
-	c, err := containerCreateInternal(suite.d.State(), args)
+	c, err := instanceCreateInternal(suite.d.State(), args)
 	suite.Req.Nil(err)
 
 	suite.True(c.IsPrivileged(), "This container should be privileged.")
@@ -128,7 +128,7 @@ func (suite *containerTestSuite) TestContainer_LoadFromDB() {
 	}
 
 	// Create the container
-	c, err := containerCreateInternal(suite.d.State(), args)
+	c, err := instanceCreateInternal(suite.d.State(), args)
 	suite.Req.Nil(err)
 	defer c.Delete()
 
@@ -159,7 +159,7 @@ func (suite *containerTestSuite) TestContainer_Path_Regular() {
 		Name:      "testFoo",
 	}
 
-	c, err := containerCreateInternal(suite.d.State(), args)
+	c, err := instanceCreateInternal(suite.d.State(), args)
 	suite.Req.Nil(err)
 	defer c.Delete()
 
@@ -175,7 +175,7 @@ func (suite *containerTestSuite) TestContainer_LogPath() {
 		Name:      "testFoo",
 	}
 
-	c, err := containerCreateInternal(suite.d.State(), args)
+	c, err := instanceCreateInternal(suite.d.State(), args)
 	suite.Req.Nil(err)
 	defer c.Delete()
 
@@ -190,7 +190,7 @@ func (suite *containerTestSuite) TestContainer_IsPrivileged_Privileged() {
 		Name:      "testFoo",
 	}
 
-	c, err := containerCreateInternal(suite.d.State(), args)
+	c, err := instanceCreateInternal(suite.d.State(), args)
 	suite.Req.Nil(err)
 
 	suite.Req.True(c.IsPrivileged(), "This container should be privileged.")
@@ -205,7 +205,7 @@ func (suite *containerTestSuite) TestContainer_IsPrivileged_Unprivileged() {
 		Name:      "testFoo",
 	}
 
-	c, err := containerCreateInternal(suite.d.State(), args)
+	c, err := instanceCreateInternal(suite.d.State(), args)
 	suite.Req.Nil(err)
 
 	suite.Req.False(c.IsPrivileged(), "This container should be unprivileged.")
@@ -219,7 +219,7 @@ func (suite *containerTestSuite) TestContainer_Rename() {
 		Name:      "testFoo",
 	}
 
-	c, err := containerCreateInternal(suite.d.State(), args)
+	c, err := instanceCreateInternal(suite.d.State(), args)
 	suite.Req.Nil(err)
 	defer c.Delete()
 
@@ -228,7 +228,7 @@ func (suite *containerTestSuite) TestContainer_Rename() {
 }
 
 func (suite *containerTestSuite) TestContainer_findIdmap_isolated() {
-	c1, err := containerCreateInternal(suite.d.State(), db.InstanceArgs{
+	c1, err := instanceCreateInternal(suite.d.State(), db.InstanceArgs{
 		Type: instancetype.Container,
 		Name: "isol-1",
 		Config: map[string]string{
@@ -238,7 +238,7 @@ func (suite *containerTestSuite) TestContainer_findIdmap_isolated() {
 	suite.Req.Nil(err)
 	defer c1.Delete()
 
-	c2, err := containerCreateInternal(suite.d.State(), db.InstanceArgs{
+	c2, err := instanceCreateInternal(suite.d.State(), db.InstanceArgs{
 		Type: instancetype.Container,
 		Name: "isol-2",
 		Config: map[string]string{
@@ -269,7 +269,7 @@ func (suite *containerTestSuite) TestContainer_findIdmap_isolated() {
 }
 
 func (suite *containerTestSuite) TestContainer_findIdmap_mixed() {
-	c1, err := containerCreateInternal(suite.d.State(), db.InstanceArgs{
+	c1, err := instanceCreateInternal(suite.d.State(), db.InstanceArgs{
 		Type: instancetype.Container,
 		Name: "isol-1",
 		Config: map[string]string{
@@ -279,7 +279,7 @@ func (suite *containerTestSuite) TestContainer_findIdmap_mixed() {
 	suite.Req.Nil(err)
 	defer c1.Delete()
 
-	c2, err := containerCreateInternal(suite.d.State(), db.InstanceArgs{
+	c2, err := instanceCreateInternal(suite.d.State(), db.InstanceArgs{
 		Type: instancetype.Container,
 		Name: "isol-2",
 		Config: map[string]string{
@@ -310,7 +310,7 @@ func (suite *containerTestSuite) TestContainer_findIdmap_mixed() {
 }
 
 func (suite *containerTestSuite) TestContainer_findIdmap_raw() {
-	c1, err := containerCreateInternal(suite.d.State(), db.InstanceArgs{
+	c1, err := instanceCreateInternal(suite.d.State(), db.InstanceArgs{
 		Type: instancetype.Container,
 		Name: "isol-1",
 		Config: map[string]string{
@@ -349,7 +349,7 @@ func (suite *containerTestSuite) TestContainer_findIdmap_maxed() {
 	maps := []*idmap.IdmapSet{}
 
 	for i := 0; i < 7; i++ {
-		c, err := containerCreateInternal(suite.d.State(), db.InstanceArgs{
+		c, err := instanceCreateInternal(suite.d.State(), db.InstanceArgs{
 			Type: instancetype.Container,
 			Name: fmt.Sprintf("isol-%d", i),
 			Config: map[string]string{

From dbead628dead023e34b038b1d0d8a755dbcd6623 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 6 Nov 2019 18:32:22 +0000
Subject: [PATCH 16/27] lxd/api/internal: InstancePath usage

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

diff --git a/lxd/api_internal.go b/lxd/api_internal.go
index 392b30f81f..ff0392ac18 100644
--- a/lxd/api_internal.go
+++ b/lxd/api_internal.go
@@ -698,7 +698,7 @@ func internalImport(d *Daemon, r *http.Request) response.Response {
 				onDiskPoolName = poolName
 			}
 			snapName := fmt.Sprintf("%s/%s", req.Name, od)
-			snapPath := driver.ContainerPath(snapName, true)
+			snapPath := driver.InstancePath(instancetype.Container, projectName, snapName, true)
 			err = lvmContainerDeleteInternal(projectName, poolName, req.Name,
 				true, onDiskPoolName, snapPath)
 		case "ceph":
@@ -936,7 +936,7 @@ func internalImport(d *Daemon, r *http.Request) response.Response {
 		return response.SmartError(err)
 	}
 
-	containerPath := driver.ContainerPath(project.Prefix(projectName, req.Name), false)
+	containerPath := driver.InstancePath(instancetype.Container, projectName, req.Name, false)
 	isPrivileged := false
 	if backup.Container.Config["security.privileged"] == "" {
 		isPrivileged = true

From 86ed197b6158db87975fa555efc754202759ab66 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 6 Nov 2019 18:33:02 +0000
Subject: [PATCH 17/27] lxd/container/lxc: InstancePath usage

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

diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index a6e5a13c96..193fc6f4e5 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -6854,8 +6854,7 @@ func (c *containerLXC) State() string {
 
 // Various container paths
 func (c *containerLXC) Path() string {
-	name := project.Prefix(c.Project(), c.Name())
-	return storagePools.ContainerPath(name, c.IsSnapshot())
+	return storagePools.InstancePath(c.Type(), c.Project(), c.Name(), c.IsSnapshot())
 }
 
 func (c *containerLXC) DevicesPath() string {

From d82f602da78d3a5aec4a8e8e9e4cd3c723a4502b Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 6 Nov 2019 18:33:22 +0000
Subject: [PATCH 18/27] lxd/storage/backend/lxd: InstancePath usage

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

diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go
index f05cc06bb6..12212d8211 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -178,8 +178,7 @@ func (b *lxdBackend) Unmount() (bool, error) {
 // ensureInstanceSymlink creates a symlink in the instance directory to the instance's mount path
 // if doesn't exist already.
 func (b *lxdBackend) ensureInstanceSymlink(instanceType instancetype.Type, projectName, instanceName, mountPath string) error {
-	volStorageName := project.Prefix(projectName, instanceName)
-	symlinkPath := ContainerPath(volStorageName, false)
+	symlinkPath := InstancePath(instanceType, projectName, instanceName, false)
 
 	// Remove any old symlinks left over by previous bugs that may point to a different pool.
 	if shared.PathExists(symlinkPath) {
@@ -200,8 +199,7 @@ func (b *lxdBackend) ensureInstanceSymlink(instanceType instancetype.Type, proje
 
 // removeInstanceSymlink removes a symlink in the instance directory to the instance's mount path.
 func (b *lxdBackend) removeInstanceSymlink(instanceType instancetype.Type, projectName, instanceName string) error {
-	volStorageName := project.Prefix(projectName, instanceName)
-	symlinkPath := ContainerPath(volStorageName, false)
+	symlinkPath := InstancePath(instanceType, projectName, instanceName, false)
 
 	if shared.PathExists(symlinkPath) {
 		err := os.Remove(symlinkPath)
@@ -223,7 +221,7 @@ func (b *lxdBackend) ensureInstanceSnapshotSymlink(instanceType instancetype.Typ
 	}
 
 	parentName, _, _ := shared.ContainerGetParentAndSnapshotName(instanceName)
-	snapshotSymlink := shared.VarPath("snapshots", project.Prefix(projectName, parentName))
+	snapshotSymlink := InstancePath(instanceType, projectName, parentName, true)
 	volStorageName := project.Prefix(projectName, parentName)
 
 	snapshotTargetPath, err := drivers.GetVolumeSnapshotDir(b.name, volType, volStorageName)
@@ -259,7 +257,7 @@ func (b *lxdBackend) removeInstanceSnapshotSymlinkIfUnused(instanceType instance
 	}
 
 	parentName, _, _ := shared.ContainerGetParentAndSnapshotName(instanceName)
-	snapshotSymlink := shared.VarPath("snapshots", project.Prefix(projectName, parentName))
+	snapshotSymlink := InstancePath(instanceType, projectName, parentName, true)
 	volStorageName := project.Prefix(projectName, parentName)
 
 	snapshotTargetPath, err := drivers.GetVolumeSnapshotDir(b.name, volType, volStorageName)

From d9d9df7a3334378849467201e06af6d0278c7cdf Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 6 Nov 2019 18:33:58 +0000
Subject: [PATCH 19/27] lxd/storage/storage: Renames ContainerPath to
 InstancePath

- Ads VM support

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

diff --git a/lxd/storage/storage.go b/lxd/storage/storage.go
index 4ec18a70e3..a30471982b 100644
--- a/lxd/storage/storage.go
+++ b/lxd/storage/storage.go
@@ -3,17 +3,27 @@ package storage
 import (
 	"os"
 
+	"github.com/lxc/lxd/lxd/instance/instancetype"
 	"github.com/lxc/lxd/lxd/project"
 	"github.com/lxc/lxd/shared"
 )
 
-// ContainerPath returns the directory of a container or snapshot.
-func ContainerPath(name string, isSnapshot bool) string {
+// InstancePath returns the directory of an instance or snapshot.
+func InstancePath(instanceType instancetype.Type, projectName, instanceName string, isSnapshot bool) string {
+	fullName := project.Prefix(projectName, instanceName)
+	if instanceType == instancetype.VM {
+		if isSnapshot {
+			return shared.VarPath("virtual-machines-snapshots", fullName)
+		}
+
+		return shared.VarPath("virtual-machines", fullName)
+	}
+
 	if isSnapshot {
-		return shared.VarPath("snapshots", name)
+		return shared.VarPath("snapshots", fullName)
 	}
 
-	return shared.VarPath("containers", name)
+	return shared.VarPath("containers", fullName)
 }
 
 // GetStoragePoolMountPoint returns the mountpoint of the given pool.

From 3d9903cf3732847ca46f83e38682481d313c9615 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 6 Nov 2019 18:34:19 +0000
Subject: [PATCH 20/27] lxd/storage/dir: InstancePath usage

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

diff --git a/lxd/storage_dir.go b/lxd/storage_dir.go
index 15044043d2..846077dda5 100644
--- a/lxd/storage_dir.go
+++ b/lxd/storage_dir.go
@@ -12,6 +12,7 @@ import (
 	"golang.org/x/sys/unix"
 
 	"github.com/lxc/lxd/lxd/backup"
+	"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"
@@ -1198,7 +1199,7 @@ func (s *storageDir) ContainerBackupLoad(info backup.Info, data io.ReadSeeker, t
 
 	// Create mountpoints
 	containerMntPoint := driver.GetContainerMountPoint(info.Project, s.pool.Name, info.Name)
-	err = driver.CreateContainerMountpoint(containerMntPoint, driver.ContainerPath(project.Prefix(info.Project, info.Name), false), info.Privileged)
+	err = driver.CreateContainerMountpoint(containerMntPoint, driver.InstancePath(instancetype.Container, info.Project, info.Name, false), info.Privileged)
 	if err != nil {
 		return errors.Wrap(err, "Create container mount point")
 	}

From 9a57538232f3d0ab1cd8c0a01b2d7771da815e1d Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 6 Nov 2019 18:34:42 +0000
Subject: [PATCH 21/27] lxd/storage/zfs: InstancePath usage

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

diff --git a/lxd/storage_zfs.go b/lxd/storage_zfs.go
index ca7cc6cbc2..da3350bde5 100644
--- a/lxd/storage_zfs.go
+++ b/lxd/storage_zfs.go
@@ -15,6 +15,7 @@ import (
 	"golang.org/x/sys/unix"
 
 	"github.com/lxc/lxd/lxd/backup"
+	"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"
@@ -2113,7 +2114,7 @@ func (s *storageZfs) ContainerBackupCreate(path string, backup backup.Backup, so
 func (s *storageZfs) doContainerBackupLoadOptimized(info backup.Info, data io.ReadSeeker, tarArgs []string) error {
 	containerName, _, _ := shared.ContainerGetParentAndSnapshotName(info.Name)
 	containerMntPoint := driver.GetContainerMountPoint(info.Project, s.pool.Name, containerName)
-	err := driver.CreateContainerMountpoint(containerMntPoint, driver.ContainerPath(project.Prefix(info.Project, info.Name), false), info.Privileged)
+	err := driver.CreateContainerMountpoint(containerMntPoint, driver.InstancePath(instancetype.Container, info.Project, info.Name, false), info.Privileged)
 	if err != nil {
 		return err
 	}

From b919f8c90161cdbbd63c7032516096e112866dab Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 6 Nov 2019 18:36:49 +0000
Subject: [PATCH 22/27] lxd/container/test: InstancePath usage

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

diff --git a/lxd/container_test.go b/lxd/container_test.go
index 92b7711e9b..40bb744df6 100644
--- a/lxd/container_test.go
+++ b/lxd/container_test.go
@@ -165,7 +165,7 @@ func (suite *containerTestSuite) TestContainer_Path_Regular() {
 
 	suite.Req.False(c.IsSnapshot(), "Shouldn't be a snapshot.")
 	suite.Req.Equal(shared.VarPath("containers", "testFoo"), c.Path())
-	suite.Req.Equal(shared.VarPath("containers", "testFoo2"), driver.ContainerPath("testFoo2", false))
+	suite.Req.Equal(shared.VarPath("containers", "testFoo2"), driver.InstancePath(instancetype.Container, "default", "testFoo2", false))
 }
 
 func (suite *containerTestSuite) TestContainer_LogPath() {

From 86db8038bd0e8f2e554f0d1420e477ac1213afc5 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 6 Nov 2019 16:56:21 +0000
Subject: [PATCH 23/27] lxd/db/storage/pools: Adds VM instance type constant
 and conversion codes

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

diff --git a/lxd/db/storage_pools.go b/lxd/db/storage_pools.go
index b2995b23e0..1f9f30c8f4 100644
--- a/lxd/db/storage_pools.go
+++ b/lxd/db/storage_pools.go
@@ -1053,6 +1053,7 @@ const (
 	StoragePoolVolumeTypeContainer = iota
 	StoragePoolVolumeTypeImage
 	StoragePoolVolumeTypeCustom
+	StoragePoolVolumeTypeVM
 )
 
 // Leave the string type in here! This guarantees that go treats this is as a
@@ -1060,6 +1061,7 @@ const (
 // constants which is not what we want.
 const (
 	StoragePoolVolumeTypeNameContainer string = "container"
+	StoragePoolVolumeTypeNameVM        string = "virtual-machine"
 	StoragePoolVolumeTypeNameImage     string = "image"
 	StoragePoolVolumeTypeNameCustom    string = "custom"
 )
@@ -1081,6 +1083,8 @@ func StoragePoolVolumeTypeToName(volumeType int) (string, error) {
 	switch volumeType {
 	case StoragePoolVolumeTypeContainer:
 		return StoragePoolVolumeTypeNameContainer, nil
+	case StoragePoolVolumeTypeVM:
+		return StoragePoolVolumeTypeNameVM, nil
 	case StoragePoolVolumeTypeImage:
 		return StoragePoolVolumeTypeNameImage, nil
 	case StoragePoolVolumeTypeCustom:

From a56797fbd3a52281445d7ba69beca06355f8241c Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 6 Nov 2019 16:55:27 +0000
Subject: [PATCH 24/27] lxd/db/containers: Updates pool lookup functions to be
 instance type agnostic

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/db/containers.go      | 28 ++++++++++++++--------------
 lxd/db/containers_test.go |  2 +-
 2 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/lxd/db/containers.go b/lxd/db/containers.go
index 58ff234f32..bb18ebf66c 100644
--- a/lxd/db/containers.go
+++ b/lxd/db/containers.go
@@ -444,7 +444,7 @@ func (c *ClusterTx) snapshotIDsAndNames(project, name string) (map[int]string, e
 func (c *ClusterTx) ContainerNodeMove(project, oldName, newName, newNode string) error {
 	// First check that the container to be moved is backed by a ceph
 	// volume.
-	poolName, err := c.ContainerPool(project, oldName)
+	poolName, err := c.InstancePool(project, oldName)
 	if err != nil {
 		return errors.Wrap(err, "failed to get container's storage pool name")
 	}
@@ -1085,23 +1085,23 @@ WHERE projects.name=? AND instances.name=?`
 	return max
 }
 
-// ContainerPool returns the storage pool of a given container.
+// InstancePool returns the storage pool of a given instance.
 //
-// This is a non-transactional variant of ClusterTx.ContainerPool().
-func (c *Cluster) ContainerPool(project, containerName string) (string, error) {
+// This is a non-transactional variant of ClusterTx.InstancePool().
+func (c *Cluster) InstancePool(project, instanceName string) (string, error) {
 	var poolName string
 	err := c.Transaction(func(tx *ClusterTx) error {
 		var err error
-		poolName, err = tx.ContainerPool(project, containerName)
+		poolName, err = tx.InstancePool(project, instanceName)
 		return err
 	})
 	return poolName, err
 }
 
-// ContainerPool returns the storage pool of a given container.
-func (c *ClusterTx) ContainerPool(project, containerName string) (string, error) {
-	if strings.Contains(containerName, shared.SnapshotDelimiter) {
-		return c.containerPoolSnapshot(project, containerName)
+// InstancePool returns the storage pool of a given instance.
+func (c *ClusterTx) InstancePool(project, instanceName string) (string, error) {
+	if strings.Contains(instanceName, shared.SnapshotDelimiter) {
+		return c.instancePoolSnapshot(project, instanceName)
 	}
 
 	// Get container storage volume. Since container names are globally
@@ -1113,9 +1113,9 @@ SELECT storage_pools.name FROM storage_pools
   JOIN storage_volumes ON storage_pools.id=storage_volumes.storage_pool_id
   JOIN instances ON instances.name=storage_volumes.name
   JOIN projects ON projects.id=instances.project_id
- WHERE projects.name=? AND storage_volumes.node_id=? AND storage_volumes.name=? AND storage_volumes.type=?
+ WHERE projects.name=? AND storage_volumes.node_id=? AND storage_volumes.name=? AND storage_volumes.type IN(?,?)
 `
-	inargs := []interface{}{project, c.nodeID, containerName, StoragePoolVolumeTypeContainer}
+	inargs := []interface{}{project, c.nodeID, instanceName, StoragePoolVolumeTypeContainer, StoragePoolVolumeTypeVM}
 	outargs := []interface{}{&poolName}
 
 	err := c.tx.QueryRow(query, inargs...).Scan(outargs...)
@@ -1130,15 +1130,15 @@ SELECT storage_pools.name FROM storage_pools
 	return poolName, nil
 }
 
-func (c *ClusterTx) containerPoolSnapshot(project, fullName string) (string, error) {
+func (c *ClusterTx) instancePoolSnapshot(project, fullName string) (string, error) {
 	poolName := ""
 	query := `
 SELECT storage_pools.name FROM storage_pools
   JOIN storage_volumes ON storage_pools.id=storage_volumes.storage_pool_id
   JOIN projects ON projects.id=storage_volumes.project_id
- WHERE projects.name=? AND storage_volumes.node_id=? AND storage_volumes.name=? AND storage_volumes.type=?
+ WHERE projects.name=? AND storage_volumes.node_id=? AND storage_volumes.name=? AND storage_volumes.type IN(?,?)
 `
-	inargs := []interface{}{project, c.nodeID, fullName, StoragePoolVolumeTypeContainer}
+	inargs := []interface{}{project, c.nodeID, fullName, StoragePoolVolumeTypeContainer, StoragePoolVolumeTypeVM}
 	outargs := []interface{}{&poolName}
 
 	err := c.tx.QueryRow(query, inargs...).Scan(outargs...)
diff --git a/lxd/db/containers_test.go b/lxd/db/containers_test.go
index be914912bb..4c399a935b 100644
--- a/lxd/db/containers_test.go
+++ b/lxd/db/containers_test.go
@@ -374,7 +374,7 @@ func TestContainerPool(t *testing.T) {
 	})
 	require.NoError(t, err)
 
-	poolName, err := cluster.ContainerPool("default", "c1")
+	poolName, err := cluster.InstancePool("default", "c1")
 	require.NoError(t, err)
 	assert.Equal(t, "default", poolName)
 }

From d05b31613e4704f0153b9e184edfe59f25bf8a28 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 6 Nov 2019 17:06:24 +0000
Subject: [PATCH 25/27] lxd/storage/load: InstancePool usage

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 ee3df9df32..bdad09351b 100644
--- a/lxd/storage/load.go
+++ b/lxd/storage/load.go
@@ -152,7 +152,7 @@ func GetPoolByName(state *state.State, name string) (Pool, error) {
 // If the pool's driver is not recognised then drivers.ErrUnknownDriver is returned. If the pool's
 // driver does not support the instance's type then drivers.ErrNotImplemented is returned.
 func GetPoolByInstance(s *state.State, inst Instance) (Pool, error) {
-	poolName, err := s.Cluster.ContainerPool(inst.Project(), inst.Name())
+	poolName, err := s.Cluster.InstancePool(inst.Project(), inst.Name())
 	if err != nil {
 		return nil, err
 	}

From df08df4ca72fee1db9e6593aae8eb70bf1a23738 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 7 Nov 2019 09:20:20 +0000
Subject: [PATCH 26/27] lxd/db/containers/test: InstancePool usage

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

diff --git a/lxd/db/containers_test.go b/lxd/db/containers_test.go
index 4c399a935b..2b2f96c65c 100644
--- a/lxd/db/containers_test.go
+++ b/lxd/db/containers_test.go
@@ -347,7 +347,7 @@ func TestContainersByNodeName(t *testing.T) {
 		}, result)
 }
 
-func TestContainerPool(t *testing.T) {
+func TestInstancePool(t *testing.T) {
 	cluster, cleanup := db.NewTestCluster(t)
 	defer cleanup()
 

From 8d62d915358260345e1fab2a20ff7ac1fd33512b Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 7 Nov 2019 09:20:34 +0000
Subject: [PATCH 27/27] lxd/storage: InstancePool usage

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

diff --git a/lxd/storage.go b/lxd/storage.go
index 7b50d49119..163bff5435 100644
--- a/lxd/storage.go
+++ b/lxd/storage.go
@@ -620,7 +620,7 @@ func storagePoolVolumeContainerCreateInit(s *state.State, project string, poolNa
 
 func storagePoolVolumeContainerLoadInit(s *state.State, project, containerName string) (storage, error) {
 	// Get the storage pool of a given container.
-	poolName, err := s.Cluster.ContainerPool(project, containerName)
+	poolName, err := s.Cluster.InstancePool(project, containerName)
 	if err != nil {
 		return nil, errors.Wrapf(err, "Load storage pool for container %q in project %q", containerName, project)
 	}


More information about the lxc-devel mailing list