[lxc-devel] [lxd/master] Instance Delete ordering

tomponline on Github lxc-bot at linuxcontainers.org
Thu Nov 21 13:42:46 UTC 2019


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 557 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20191121/51b7869e/attachment-0001.bin>
-------------- next part --------------
From 5c85d60df84c9d43dd4c6b2486e2d32d7f15943a Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 21 Nov 2019 11:06:50 +0000
Subject: [PATCH 01/26] lxd/vm/qemu: Removes deprecated Storage() function

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

diff --git a/lxd/vm_qemu.go b/lxd/vm_qemu.go
index 19781a3d2f..7f84e5eb35 100644
--- a/lxd/vm_qemu.go
+++ b/lxd/vm_qemu.go
@@ -49,7 +49,7 @@ import (
 
 var vmVsockTimeout time.Duration = time.Second
 
-func vmQemuLoad(s *state.State, args db.InstanceArgs, profiles []api.Profile) (Instance, error) {
+func vmQemuLoad(s *state.State, args db.InstanceArgs, profiles []api.Profile) (instance.Instance, error) {
 	// Create the container struct.
 	vm := vmQemuInstantiate(s, args)
 
@@ -111,7 +111,7 @@ func vmQemuInstantiate(s *state.State, args db.InstanceArgs) *vmQemu {
 }
 
 // vmQemuCreate creates a new storage volume record and returns an initialised Instance.
-func vmQemuCreate(s *state.State, args db.InstanceArgs) (Instance, error) {
+func vmQemuCreate(s *state.State, args db.InstanceArgs) (instance.Instance, error) {
 	// Create the instance struct.
 	vm := &vmQemu{
 		state:        s,
@@ -1262,12 +1262,12 @@ func (vm *vmQemu) IsPrivileged() bool {
 	return shared.IsTrue(vm.expandedConfig["security.privileged"])
 }
 
-func (vm *vmQemu) Restore(source Instance, stateful bool) error {
+func (vm *vmQemu) Restore(source instance.Instance, stateful bool) error {
 	return fmt.Errorf("Restore Not implemented")
 }
 
-func (vm *vmQemu) Snapshots() ([]Instance, error) {
-	return []Instance{}, nil
+func (vm *vmQemu) Snapshots() ([]instance.Instance, error) {
+	return []instance.Instance{}, nil
 }
 
 func (vm *vmQemu) Backups() ([]backup.Backup, error) {
@@ -2699,12 +2699,6 @@ func (vm *vmQemu) StorageStop() (bool, error) {
 	return false, storagePools.ErrNotImplemented
 }
 
-// Storage is deprecated will always return nil.
-// It is here just to satisfy the Instance interface (which will be updated in the future).
-func (vm *vmQemu) Storage() storage {
-	return nil
-}
-
 func (vm *vmQemu) DeferTemplateApply(trigger string) error {
 	return nil
 }

From 28e76d920760c3ffdc20c64729bcaf181a631813 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 21 Nov 2019 11:07:25 +0000
Subject: [PATCH 02/26] lxd/instance/instance/interface: Moves Instance
 interface into instance pkg

- Also removes Storage() function from interface so as not dependent on storage type in main pkg.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/instance/instance_interface.go | 113 +++++++++++++++++++++++++++++
 1 file changed, 113 insertions(+)
 create mode 100644 lxd/instance/instance_interface.go

diff --git a/lxd/instance/instance_interface.go b/lxd/instance/instance_interface.go
new file mode 100644
index 0000000000..fecd7d48b9
--- /dev/null
+++ b/lxd/instance/instance_interface.go
@@ -0,0 +1,113 @@
+package instance
+
+import (
+	"io"
+	"os"
+	"time"
+
+	"github.com/lxc/lxd/lxd/backup"
+	"github.com/lxc/lxd/lxd/db"
+	"github.com/lxc/lxd/lxd/device"
+	deviceConfig "github.com/lxc/lxd/lxd/device/config"
+	"github.com/lxc/lxd/lxd/instance/instancetype"
+	"github.com/lxc/lxd/lxd/operations"
+	"github.com/lxc/lxd/lxd/state"
+	"github.com/lxc/lxd/shared/api"
+)
+
+// The Instance interface
+type Instance interface {
+	// Instance actions
+	Freeze() error
+	Shutdown(timeout time.Duration) error
+	Start(stateful bool) error
+	Stop(stateful bool) error
+	Unfreeze() error
+
+	IsPrivileged() bool
+
+	// Snapshots & migration & backups
+	Restore(source Instance, stateful bool) error
+	Snapshots() ([]Instance, error)
+	Backups() ([]backup.Backup, error)
+
+	// Config handling
+	Rename(newName string) error
+
+	// TODO rename db.InstanceArgs to db.InstanceArgs.
+	Update(newConfig db.InstanceArgs, userRequested bool) error
+
+	Delete() error
+	Export(w io.Writer, properties map[string]string) error
+
+	// Live configuration
+	CGroupGet(key string) (string, error)
+	CGroupSet(key string, value string) error
+	VolatileSet(changes map[string]string) error
+
+	// File handling
+	FileExists(path string) error
+	FilePull(srcpath string, dstpath string) (int64, int64, os.FileMode, string, []string, error)
+	FilePush(fileType string, srcpath string, dstpath string, uid int64, gid int64, mode int, write string) error
+	FileRemove(path string) error
+
+	// Console - Allocate and run a console tty.
+	Console() (*os.File, error)
+	Exec(command []string, env map[string]string, stdin *os.File, stdout *os.File, stderr *os.File, cwd string, uid uint32, gid uint32) (Cmd, error)
+
+	// Status
+	Render() (interface{}, interface{}, error)
+	RenderFull() (*api.InstanceFull, interface{}, error)
+	RenderState() (*api.InstanceState, error)
+	IsRunning() bool
+	IsFrozen() bool
+	IsEphemeral() bool
+	IsSnapshot() bool
+	IsStateful() bool
+
+	// Hooks
+	DeviceEventHandler(*device.RunConfig) error
+
+	// Properties
+	ID() int
+	Location() string
+	Project() string
+	Name() string
+	Type() instancetype.Type
+	Description() string
+	Architecture() int
+	CreationDate() time.Time
+	LastUsedDate() time.Time
+	ExpandedConfig() map[string]string
+	ExpandedDevices() deviceConfig.Devices
+	LocalConfig() map[string]string
+	LocalDevices() deviceConfig.Devices
+	Profiles() []string
+	InitPID() int
+	State() string
+	ExpiryDate() time.Time
+
+	// Paths
+	Path() string
+	RootfsPath() string
+	TemplatesPath() string
+	StatePath() string
+	LogFilePath() string
+	ConsoleBufferLogPath() string
+	LogPath() string
+	DevicesPath() string
+
+	// Storage
+	StoragePool() (string, error)
+
+	// Progress reporting
+
+	SetOperation(op *operations.Operation)
+
+	// FIXME: Those should be internal functions
+	// Needed for migration for now.
+	StorageStart() (bool, error)
+	StorageStop() (bool, error)
+	DeferTemplateApply(trigger string) error
+	DaemonState() *state.State
+}

From 239ed8365356e20f068527c304d03a426c5c9afe Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 21 Nov 2019 11:07:55 +0000
Subject: [PATCH 03/26] lxd/instance/interface: Removes old Instance interface

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/instance_interface.go | 115 --------------------------------------
 1 file changed, 115 deletions(-)
 delete mode 100644 lxd/instance_interface.go

diff --git a/lxd/instance_interface.go b/lxd/instance_interface.go
deleted file mode 100644
index 274de7a8b8..0000000000
--- a/lxd/instance_interface.go
+++ /dev/null
@@ -1,115 +0,0 @@
-package main
-
-import (
-	"io"
-	"os"
-	"time"
-
-	"github.com/lxc/lxd/lxd/backup"
-	"github.com/lxc/lxd/lxd/db"
-	"github.com/lxc/lxd/lxd/device"
-	deviceConfig "github.com/lxc/lxd/lxd/device/config"
-	"github.com/lxc/lxd/lxd/instance"
-	"github.com/lxc/lxd/lxd/instance/instancetype"
-	"github.com/lxc/lxd/lxd/operations"
-	"github.com/lxc/lxd/lxd/state"
-	"github.com/lxc/lxd/shared/api"
-)
-
-// The Instance interface
-type Instance interface {
-	// Instance actions
-	Freeze() error
-	Shutdown(timeout time.Duration) error
-	Start(stateful bool) error
-	Stop(stateful bool) error
-	Unfreeze() error
-
-	IsPrivileged() bool
-
-	// Snapshots & migration & backups
-	Restore(source Instance, stateful bool) error
-	Snapshots() ([]Instance, error)
-	Backups() ([]backup.Backup, error)
-
-	// Config handling
-	Rename(newName string) error
-
-	// TODO rename db.InstanceArgs to db.InstanceArgs.
-	Update(newConfig db.InstanceArgs, userRequested bool) error
-
-	Delete() error
-	Export(w io.Writer, properties map[string]string) error
-
-	// Live configuration
-	CGroupGet(key string) (string, error)
-	CGroupSet(key string, value string) error
-	VolatileSet(changes map[string]string) error
-
-	// File handling
-	FileExists(path string) error
-	FilePull(srcpath string, dstpath string) (int64, int64, os.FileMode, string, []string, error)
-	FilePush(fileType string, srcpath string, dstpath string, uid int64, gid int64, mode int, write string) error
-	FileRemove(path string) error
-
-	// Console - Allocate and run a console tty.
-	Console() (*os.File, error)
-	Exec(command []string, env map[string]string, stdin *os.File, stdout *os.File, stderr *os.File, cwd string, uid uint32, gid uint32) (instance.Cmd, error)
-
-	// Status
-	Render() (interface{}, interface{}, error)
-	RenderFull() (*api.InstanceFull, interface{}, error)
-	RenderState() (*api.InstanceState, error)
-	IsRunning() bool
-	IsFrozen() bool
-	IsEphemeral() bool
-	IsSnapshot() bool
-	IsStateful() bool
-
-	// Hooks
-	DeviceEventHandler(*device.RunConfig) error
-
-	// Properties
-	ID() int
-	Location() string
-	Project() string
-	Name() string
-	Type() instancetype.Type
-	Description() string
-	Architecture() int
-	CreationDate() time.Time
-	LastUsedDate() time.Time
-	ExpandedConfig() map[string]string
-	ExpandedDevices() deviceConfig.Devices
-	LocalConfig() map[string]string
-	LocalDevices() deviceConfig.Devices
-	Profiles() []string
-	InitPID() int
-	State() string
-	ExpiryDate() time.Time
-
-	// Paths
-	Path() string
-	RootfsPath() string
-	TemplatesPath() string
-	StatePath() string
-	LogFilePath() string
-	ConsoleBufferLogPath() string
-	LogPath() string
-	DevicesPath() string
-
-	// Storage
-	StoragePool() (string, error)
-
-	// Progress reporting
-
-	SetOperation(op *operations.Operation)
-
-	// FIXME: Those should be internal functions
-	// Needed for migration for now.
-	StorageStart() (bool, error)
-	StorageStop() (bool, error)
-	Storage() storage
-	DeferTemplateApply(trigger string) error
-	DaemonState() *state.State
-}

From f5a0370c14f072cc631a9d92d533ade51021c104 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 21 Nov 2019 11:08:15 +0000
Subject: [PATCH 04/26] lxd: Updates references to Instance interface

- Also where Storage() is needed, converts to containerLXC type.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/backup.go                  |  22 +++++--
 lxd/container.go               | 104 ++++++++++++++++++++-------------
 lxd/container_console.go       |   3 +-
 lxd/container_exec.go          |   2 +-
 lxd/container_file.go          |   7 ++-
 lxd/container_lxc.go           |  12 ++--
 lxd/container_metadata.go      |   3 +-
 lxd/container_post.go          |   7 ++-
 lxd/containers.go              |  11 ++--
 lxd/containers_get.go          |   3 +-
 lxd/containers_post.go         |   5 +-
 lxd/devices.go                 |  12 ++--
 lxd/migrate.go                 |   7 ++-
 lxd/migrate_container.go       |  29 +++++----
 lxd/networks_utils.go          |   3 +-
 lxd/storage.go                 |  37 ++++++------
 lxd/storage_btrfs.go           |  84 +++++++++++++++++---------
 lxd/storage_ceph.go            |  59 +++++++++++--------
 lxd/storage_ceph_utils.go      |   7 ++-
 lxd/storage_cephfs.go          |  39 +++++++------
 lxd/storage_dir.go             |  70 +++++++++++++---------
 lxd/storage_lvm.go             |  59 +++++++++++--------
 lxd/storage_lvm_utils.go       |  15 ++---
 lxd/storage_migration.go       |  17 ++++--
 lxd/storage_migration_btrfs.go |  14 ++++-
 lxd/storage_migration_ceph.go  |   7 ++-
 lxd/storage_migration_zfs.go   |   5 +-
 lxd/storage_mock.go            |  37 ++++++------
 lxd/storage_zfs.go             |  72 +++++++++++++----------
 29 files changed, 455 insertions(+), 297 deletions(-)

diff --git a/lxd/backup.go b/lxd/backup.go
index 3be5273cd7..bdaa14315d 100644
--- a/lxd/backup.go
+++ b/lxd/backup.go
@@ -14,6 +14,8 @@ import (
 	"github.com/lxc/lxd/lxd/backup"
 	"github.com/lxc/lxd/lxd/cluster"
 	"github.com/lxc/lxd/lxd/db"
+	"github.com/lxc/lxd/lxd/instance"
+	"github.com/lxc/lxd/lxd/instance/instancetype"
 	"github.com/lxc/lxd/lxd/operations"
 	"github.com/lxc/lxd/lxd/project"
 	"github.com/lxc/lxd/lxd/state"
@@ -25,7 +27,7 @@ import (
 )
 
 // Create a new backup
-func backupCreate(s *state.State, args db.InstanceBackupArgs, sourceContainer Instance) error {
+func backupCreate(s *state.State, args db.InstanceBackupArgs, sourceContainer instance.Instance) error {
 	// Create the database entry
 	err := s.Cluster.ContainerBackupCreate(args)
 	if err != nil {
@@ -59,8 +61,14 @@ func backupCreate(s *state.State, args db.InstanceBackupArgs, sourceContainer In
 	}
 	defer os.RemoveAll(tmpPath)
 
+	if sourceContainer.Type() != instancetype.Container {
+		return fmt.Errorf("Instance type must be container")
+	}
+
+	ct := sourceContainer.(*containerLXC)
+
 	// Now create the empty snapshot
-	err = sourceContainer.Storage().ContainerBackupCreate(tmpPath, *b, sourceContainer)
+	err = ct.Storage().ContainerBackupCreate(tmpPath, *b, sourceContainer)
 	if err != nil {
 		s.Cluster.ContainerBackupRemove(args.Name)
 		return errors.Wrap(err, "Backup storage")
@@ -164,16 +172,22 @@ func backupFixStoragePool(c *db.Cluster, b backup.Info, useDefaultPool bool) err
 	return nil
 }
 
-func backupCreateTarball(s *state.State, path string, b backup.Backup, c Instance) error {
+func backupCreateTarball(s *state.State, path string, b backup.Backup, c instance.Instance) error {
 	// Create the index
 	pool, err := c.StoragePool()
 	if err != nil {
 		return err
 	}
 
+	if c.Type() != instancetype.Container {
+		return fmt.Errorf("Instance type must be container")
+	}
+
+	ct := c.(*containerLXC)
+
 	indexFile := backup.Info{
 		Name:       c.Name(),
-		Backend:    c.Storage().GetStorageTypeName(),
+		Backend:    ct.Storage().GetStorageTypeName(),
 		Privileged: c.IsPrivileged(),
 		Pool:       pool,
 		Snapshots:  []string{},
diff --git a/lxd/container.go b/lxd/container.go
index 1b25779c21..38ddca37e5 100644
--- a/lxd/container.go
+++ b/lxd/container.go
@@ -22,6 +22,7 @@ import (
 	"github.com/lxc/lxd/lxd/db"
 	"github.com/lxc/lxd/lxd/device"
 	deviceConfig "github.com/lxc/lxd/lxd/device/config"
+	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/instance/instancetype"
 	"github.com/lxc/lxd/lxd/operations"
 	"github.com/lxc/lxd/lxd/seccomp"
@@ -205,7 +206,7 @@ func instanceValidDevices(state *state.State, cluster *db.Cluster, instanceType
 	// Create a temporary Instance for use in device validation.
 	// Populate it's name, localDevices and expandedDevices properties based on the mode of
 	// validation occurring. In non-expanded validation expensive checks should be avoided.
-	var inst Instance
+	var inst instance.Instance
 
 	if instanceType == instancetype.Container {
 		c := &containerLXC{
@@ -257,7 +258,7 @@ func instanceValidDevices(state *state.State, cluster *db.Cluster, instanceType
 
 // The container interface
 type container interface {
-	Instance
+	instance.Instance
 
 	/* actionScript here is a script called action.sh in the stateDir, to
 	 * be passed to CRIU as --action-script
@@ -282,7 +283,7 @@ type container interface {
 }
 
 // instanceCreateAsEmpty creates an empty instance.
-func instanceCreateAsEmpty(d *Daemon, args db.InstanceArgs) (Instance, error) {
+func instanceCreateAsEmpty(d *Daemon, args db.InstanceArgs) (instance.Instance, error) {
 	// Create the instance record.
 	inst, err := instanceCreateInternal(d.State(), args)
 	if err != nil {
@@ -310,8 +311,10 @@ func instanceCreateAsEmpty(d *Daemon, args db.InstanceArgs) (Instance, error) {
 			return nil, errors.Wrap(err, "Create instance")
 		}
 	} else if inst.Type() == instancetype.Container {
+		ct := inst.(*containerLXC)
+
 		// Now create the empty storage.
-		err = inst.Storage().ContainerCreate(inst)
+		err = ct.Storage().ContainerCreate(inst)
 		if err != nil {
 			return nil, err
 		}
@@ -436,15 +439,21 @@ func containerCreateFromBackup(s *state.State, info backup.Info, data io.ReadSee
 	return pool, nil
 }
 
-func containerCreateEmptySnapshot(s *state.State, args db.InstanceArgs) (Instance, error) {
+func containerCreateEmptySnapshot(s *state.State, args db.InstanceArgs) (instance.Instance, error) {
 	// Create the snapshot
 	c, err := instanceCreateInternal(s, args)
 	if err != nil {
 		return nil, err
 	}
 
+	if c.Type() != instancetype.Container {
+		return nil, fmt.Errorf("Instance type must be container")
+	}
+
+	ct := c.(*containerLXC)
+
 	// Now create the empty snapshot
-	err = c.Storage().ContainerSnapshotCreateEmpty(c)
+	err = ct.Storage().ContainerSnapshotCreateEmpty(c)
 	if err != nil {
 		c.Delete()
 		return nil, err
@@ -454,7 +463,7 @@ func containerCreateEmptySnapshot(s *state.State, args db.InstanceArgs) (Instanc
 }
 
 // instanceCreateFromImage creates an instance from a rootfs image.
-func instanceCreateFromImage(d *Daemon, args db.InstanceArgs, hash string, op *operations.Operation) (Instance, error) {
+func instanceCreateFromImage(d *Daemon, args db.InstanceArgs, hash string, op *operations.Operation) (instance.Instance, error) {
 	s := d.State()
 
 	// Get the image properties.
@@ -552,7 +561,8 @@ func instanceCreateFromImage(d *Daemon, args db.InstanceArgs, hash string, op *o
 		}
 
 		// Now create the storage from an image.
-		err = inst.Storage().ContainerCreateFromImage(inst, hash, tracker)
+		ct := inst.(*containerLXC)
+		err = ct.Storage().ContainerCreateFromImage(inst, hash, tracker)
 		if err != nil {
 			return nil, errors.Wrap(err, "Create instance from image")
 		}
@@ -570,8 +580,8 @@ func instanceCreateFromImage(d *Daemon, args db.InstanceArgs, hash string, op *o
 	return inst, nil
 }
 
-func instanceCreateAsCopy(s *state.State, args db.InstanceArgs, sourceInst Instance, instanceOnly bool, refresh bool) (Instance, error) {
-	var inst, revertInst Instance
+func instanceCreateAsCopy(s *state.State, args db.InstanceArgs, sourceInst instance.Instance, instanceOnly bool, refresh bool) (instance.Instance, error) {
+	var inst, revertInst instance.Instance
 	var err error
 
 	defer func() {
@@ -613,8 +623,8 @@ func instanceCreateAsCopy(s *state.State, args db.InstanceArgs, sourceInst Insta
 		parentStoragePool = parentLocalRootDiskDevice["pool"]
 	}
 
-	snapList := []*Instance{}
-	var snapshots []Instance
+	snapList := []*instance.Instance{}
+	var snapshots []instance.Instance
 
 	if !instanceOnly {
 		if refresh {
@@ -695,13 +705,19 @@ func instanceCreateAsCopy(s *state.State, args db.InstanceArgs, sourceInst Insta
 	}
 
 	// Now clone or refresh the storage.
+	if inst.Type() != instancetype.Container {
+		return nil, fmt.Errorf("Instance type must be container")
+	}
+
+	ct := inst.(*containerLXC)
+
 	if refresh {
-		err = inst.Storage().ContainerRefresh(inst, sourceInst, snapshots)
+		err = ct.Storage().ContainerRefresh(inst, sourceInst, snapshots)
 		if err != nil {
 			return nil, err
 		}
 	} else {
-		err = inst.Storage().ContainerCopy(inst, sourceInst, instanceOnly)
+		err = ct.Storage().ContainerCopy(inst, sourceInst, instanceOnly)
 		if err != nil {
 			return nil, err
 		}
@@ -727,7 +743,7 @@ func instanceCreateAsCopy(s *state.State, args db.InstanceArgs, sourceInst Insta
 	return inst, nil
 }
 
-func containerCreateAsSnapshot(s *state.State, args db.InstanceArgs, sourceInstance Instance) (Instance, error) {
+func containerCreateAsSnapshot(s *state.State, args db.InstanceArgs, sourceInstance instance.Instance) (instance.Instance, error) {
 	if sourceInstance.Type() != instancetype.Container {
 		return nil, fmt.Errorf("Instance not container type")
 	}
@@ -784,7 +800,13 @@ func containerCreateAsSnapshot(s *state.State, args db.InstanceArgs, sourceInsta
 	}
 
 	// Clone the container
-	err = sourceInstance.Storage().ContainerSnapshotCreate(c, sourceInstance)
+	if sourceInstance.Type() != instancetype.Container {
+		return nil, fmt.Errorf("Instance type must be container")
+	}
+
+	ct := sourceInstance.(*containerLXC)
+
+	err = ct.Storage().ContainerSnapshotCreate(c, sourceInstance)
 	if err != nil {
 		c.Delete()
 		return nil, err
@@ -821,7 +843,7 @@ func containerCreateAsSnapshot(s *state.State, args db.InstanceArgs, sourceInsta
 }
 
 // instanceCreateInternal creates an instance record and storage volume record in the database.
-func instanceCreateInternal(s *state.State, args db.InstanceArgs) (Instance, error) {
+func instanceCreateInternal(s *state.State, args db.InstanceArgs) (instance.Instance, error) {
 	// Set default values.
 	if args.Project == "" {
 		args.Project = "default"
@@ -1022,7 +1044,7 @@ func instanceCreateInternal(s *state.State, args db.InstanceArgs) (Instance, err
 
 	args = db.ContainerToArgs(&dbInst)
 
-	var inst Instance
+	var inst instance.Instance
 
 	if args.Type == instancetype.Container {
 		inst, err = containerLXCCreate(s, args)
@@ -1041,7 +1063,7 @@ func instanceCreateInternal(s *state.State, args db.InstanceArgs) (Instance, err
 }
 
 // instanceConfigureInternal applies quota set in volatile "apply_quota" and writes a backup file.
-func instanceConfigureInternal(state *state.State, c Instance) error {
+func instanceConfigureInternal(state *state.State, c instance.Instance) error {
 	// Find the root device
 	rootDiskDeviceKey, rootDiskDevice, err := shared.GetRootDiskDevice(c.ExpandedDevices().CloneNative())
 	if err != nil {
@@ -1074,8 +1096,10 @@ func instanceConfigureInternal(state *state.State, c Instance) error {
 			return err
 		}
 
+		ct := c.(*containerLXC)
+
 		// handle quota: at this point, storage is guaranteed to be ready
-		storage := c.Storage()
+		storage := ct.Storage()
 		if rootDiskDevice["size"] != "" {
 			storageTypeName := storage.GetStorageTypeName()
 			if (storageTypeName == "lvm" || storageTypeName == "ceph") && c.IsRunning() {
@@ -1111,7 +1135,7 @@ func instanceConfigureInternal(state *state.State, c Instance) error {
 	return nil
 }
 
-func instanceLoadById(s *state.State, id int) (Instance, error) {
+func instanceLoadById(s *state.State, id int) (instance.Instance, error) {
 	// Get the DB record
 	project, name, err := s.Cluster.ContainerProjectAndName(id)
 	if err != nil {
@@ -1121,7 +1145,7 @@ func instanceLoadById(s *state.State, id int) (Instance, error) {
 	return instanceLoadByProjectAndName(s, project, name)
 }
 
-func instanceLoadByProjectAndName(s *state.State, project, name string) (Instance, error) {
+func instanceLoadByProjectAndName(s *state.State, project, name string) (instance.Instance, error) {
 	// Get the DB record
 	var container *db.Instance
 	err := s.Cluster.Transaction(func(tx *db.ClusterTx) error {
@@ -1166,7 +1190,7 @@ func instanceLoadByProjectAndName(s *state.State, project, name string) (Instanc
 	return inst, nil
 }
 
-func instanceLoadByProject(s *state.State, project string) ([]Instance, error) {
+func instanceLoadByProject(s *state.State, project string) ([]instance.Instance, error) {
 	// Get all the containers
 	var cts []db.Instance
 	err := s.Cluster.Transaction(func(tx *db.ClusterTx) error {
@@ -1190,7 +1214,7 @@ func instanceLoadByProject(s *state.State, project string) ([]Instance, error) {
 }
 
 // Load all instances across all projects.
-func instanceLoadFromAllProjects(s *state.State) ([]Instance, error) {
+func instanceLoadFromAllProjects(s *state.State) ([]instance.Instance, error) {
 	var projects []string
 
 	err := s.Cluster.Transaction(func(tx *db.ClusterTx) error {
@@ -1202,7 +1226,7 @@ func instanceLoadFromAllProjects(s *state.State) ([]Instance, error) {
 		return nil, err
 	}
 
-	instances := []Instance{}
+	instances := []instance.Instance{}
 	for _, project := range projects {
 		projectInstances, err := instanceLoadByProject(s, project)
 		if err != nil {
@@ -1215,12 +1239,12 @@ func instanceLoadFromAllProjects(s *state.State) ([]Instance, error) {
 }
 
 // Legacy interface.
-func instanceLoadAll(s *state.State) ([]Instance, error) {
+func instanceLoadAll(s *state.State) ([]instance.Instance, error) {
 	return instanceLoadByProject(s, "default")
 }
 
 // Load all instances of this nodes.
-func instanceLoadNodeAll(s *state.State) ([]Instance, error) {
+func instanceLoadNodeAll(s *state.State) ([]instance.Instance, error) {
 	// Get all the container arguments
 	var cts []db.Instance
 	err := s.Cluster.Transaction(func(tx *db.ClusterTx) error {
@@ -1240,7 +1264,7 @@ func instanceLoadNodeAll(s *state.State) ([]Instance, error) {
 }
 
 // Load all instances of this nodes under the given project.
-func instanceLoadNodeProjectAll(s *state.State, project string, instanceType instancetype.Type) ([]Instance, error) {
+func instanceLoadNodeProjectAll(s *state.State, project string, instanceType instancetype.Type) ([]instance.Instance, error) {
 	// Get all the container arguments
 	var cts []db.Instance
 	err := s.Cluster.Transaction(func(tx *db.ClusterTx) error {
@@ -1259,7 +1283,7 @@ func instanceLoadNodeProjectAll(s *state.State, project string, instanceType ins
 	return instanceLoadAllInternal(cts, s)
 }
 
-func instanceLoadAllInternal(dbInstances []db.Instance, s *state.State) ([]Instance, error) {
+func instanceLoadAllInternal(dbInstances []db.Instance, s *state.State) ([]instance.Instance, error) {
 	// Figure out what profiles are in use
 	profiles := map[string]map[string]api.Profile{}
 	for _, instArgs := range dbInstances {
@@ -1289,7 +1313,7 @@ func instanceLoadAllInternal(dbInstances []db.Instance, s *state.State) ([]Insta
 	}
 
 	// Load the instances structs
-	instances := []Instance{}
+	instances := []instance.Instance{}
 	for _, dbInstance := range dbInstances {
 		// Figure out the instances's profiles
 		cProfiles := []api.Profile{}
@@ -1310,8 +1334,8 @@ func instanceLoadAllInternal(dbInstances []db.Instance, s *state.State) ([]Insta
 }
 
 // instanceLoad creates the underlying instance type struct and returns it as an Instance.
-func instanceLoad(s *state.State, args db.InstanceArgs, profiles []api.Profile) (Instance, error) {
-	var inst Instance
+func instanceLoad(s *state.State, args db.InstanceArgs, profiles []api.Profile) (instance.Instance, error) {
+	var inst instance.Instance
 	var err error
 
 	if args.Type == instancetype.Container {
@@ -1333,7 +1357,7 @@ func instanceLoad(s *state.State, args db.InstanceArgs, profiles []api.Profile)
 // snapshots to remove from the target. A snapshot will be marked as "to sync" if it either doesn't
 // exist in the target or its creation date is different to the source. A snapshot will be marked
 // as "to delete" if it doesn't exist in the source or creation date is different to the source.
-func instanceCompareSnapshots(source Instance, target Instance) ([]Instance, []Instance, error) {
+func instanceCompareSnapshots(source instance.Instance, target instance.Instance) ([]instance.Instance, []instance.Instance, error) {
 	// Get the source snapshots.
 	sourceSnapshots, err := source.Snapshots()
 	if err != nil {
@@ -1350,8 +1374,8 @@ func instanceCompareSnapshots(source Instance, target Instance) ([]Instance, []I
 	sourceSnapshotsTime := map[string]time.Time{}
 	targetSnapshotsTime := map[string]time.Time{}
 
-	toDelete := []Instance{}
-	toSync := []Instance{}
+	toDelete := []instance.Instance{}
+	toSync := []instance.Instance{}
 
 	// Generate a list of source snapshot creation dates.
 	for _, snap := range sourceSnapshots {
@@ -1402,7 +1426,7 @@ func autoCreateContainerSnapshotsTask(d *Daemon) (task.Func, task.Schedule) {
 		}
 
 		// Figure out which need snapshotting (if any)
-		instances := []Instance{}
+		instances := []instance.Instance{}
 		for _, c := range allContainers {
 			schedule := c.ExpandedConfig()["snapshots.schedule"]
 
@@ -1483,7 +1507,7 @@ func autoCreateContainerSnapshotsTask(d *Daemon) (task.Func, task.Schedule) {
 	return f, schedule
 }
 
-func autoCreateContainerSnapshots(ctx context.Context, d *Daemon, instances []Instance) error {
+func autoCreateContainerSnapshots(ctx context.Context, d *Daemon, instances []instance.Instance) error {
 	// Make the snapshots
 	for _, c := range instances {
 		ch := make(chan error)
@@ -1545,7 +1569,7 @@ func pruneExpiredContainerSnapshotsTask(d *Daemon) (task.Func, task.Schedule) {
 		}
 
 		// Figure out which need snapshotting (if any)
-		expiredSnapshots := []Instance{}
+		expiredSnapshots := []instance.Instance{}
 		for _, c := range allInstances {
 			snapshots, err := c.Snapshots()
 			if err != nil {
@@ -1604,7 +1628,7 @@ func pruneExpiredContainerSnapshotsTask(d *Daemon) (task.Func, task.Schedule) {
 	return f, schedule
 }
 
-func pruneExpiredContainerSnapshots(ctx context.Context, d *Daemon, snapshots []Instance) error {
+func pruneExpiredContainerSnapshots(ctx context.Context, d *Daemon, snapshots []instance.Instance) error {
 	// Find snapshots to delete
 	for _, snapshot := range snapshots {
 		err := snapshot.Delete()
@@ -1616,7 +1640,7 @@ func pruneExpiredContainerSnapshots(ctx context.Context, d *Daemon, snapshots []
 	return nil
 }
 
-func containerDetermineNextSnapshotName(d *Daemon, c Instance, defaultPattern string) (string, error) {
+func containerDetermineNextSnapshotName(d *Daemon, c instance.Instance, defaultPattern string) (string, error) {
 	var err error
 
 	pattern := c.ExpandedConfig()["snapshots.pattern"]
diff --git a/lxd/container_console.go b/lxd/container_console.go
index 4c009e5961..3ac9fd45e0 100644
--- a/lxd/container_console.go
+++ b/lxd/container_console.go
@@ -16,6 +16,7 @@ import (
 
 	"github.com/lxc/lxd/lxd/cluster"
 	"github.com/lxc/lxd/lxd/db"
+	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/instance/instancetype"
 	"github.com/lxc/lxd/lxd/operations"
 	"github.com/lxc/lxd/lxd/response"
@@ -28,7 +29,7 @@ import (
 
 type consoleWs struct {
 	// instance currently worked on
-	instance Instance
+	instance instance.Instance
 
 	// websocket connections to bridge pty fds to
 	conns map[int]*websocket.Conn
diff --git a/lxd/container_exec.go b/lxd/container_exec.go
index fb1fa90972..de7e6ded6d 100644
--- a/lxd/container_exec.go
+++ b/lxd/container_exec.go
@@ -31,7 +31,7 @@ import (
 
 type execWs struct {
 	command  []string
-	instance Instance
+	instance instance.Instance
 	env      map[string]string
 
 	rootUid          int64
diff --git a/lxd/container_file.go b/lxd/container_file.go
index ce87766ed7..ce8fcac1b6 100644
--- a/lxd/container_file.go
+++ b/lxd/container_file.go
@@ -10,6 +10,7 @@ import (
 
 	"github.com/gorilla/mux"
 
+	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/response"
 	"github.com/lxc/lxd/shared"
 )
@@ -53,7 +54,7 @@ func containerFileHandler(d *Daemon, r *http.Request) response.Response {
 	}
 }
 
-func containerFileGet(c Instance, path string, r *http.Request) response.Response {
+func containerFileGet(c instance.Instance, path string, r *http.Request) response.Response {
 	/*
 	 * Copy out of the ns to a temporary file, and then use that to serve
 	 * the request from. This prevents us from having to worry about stuff
@@ -98,7 +99,7 @@ func containerFileGet(c Instance, path string, r *http.Request) response.Respons
 	}
 }
 
-func containerFilePost(c Instance, path string, r *http.Request) response.Response {
+func containerFilePost(c instance.Instance, path string, r *http.Request) response.Response {
 	// Extract file ownership and mode from headers
 	uid, gid, mode, type_, write := shared.ParseLXDFileHeaders(r.Header)
 
@@ -151,7 +152,7 @@ func containerFilePost(c Instance, path string, r *http.Request) response.Respon
 	}
 }
 
-func containerFileDelete(c Instance, path string, r *http.Request) response.Response {
+func containerFileDelete(c instance.Instance, path string, r *http.Request) response.Response {
 	err := c.FileRemove(path)
 	if err != nil {
 		return response.SmartError(err)
diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index 9cd60ca5ae..fac2ecc7e9 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -3260,11 +3260,11 @@ func (c *containerLXC) RenderState() (*api.InstanceState, error) {
 	return &status, nil
 }
 
-func (c *containerLXC) Snapshots() ([]Instance, error) {
+func (c *containerLXC) Snapshots() ([]instance.Instance, error) {
 	var snaps []db.Instance
 
 	if c.IsSnapshot() {
-		return []Instance{}, nil
+		return []instance.Instance{}, nil
 	}
 
 	// Get all the snapshots
@@ -3287,9 +3287,9 @@ func (c *containerLXC) Snapshots() ([]Instance, error) {
 		return nil, err
 	}
 
-	instances := make([]Instance, len(containers))
+	instances := make([]instance.Instance, len(containers))
 	for k, v := range containers {
-		instances[k] = Instance(v)
+		instances[k] = instance.Instance(v)
 	}
 
 	return instances, nil
@@ -3316,7 +3316,7 @@ func (c *containerLXC) Backups() ([]backup.Backup, error) {
 	return backups, nil
 }
 
-func (c *containerLXC) Restore(sourceContainer Instance, stateful bool) error {
+func (c *containerLXC) Restore(sourceContainer instance.Instance, stateful bool) error {
 	var ctxMap log.Ctx
 
 	// Initialize storage interface for the container.
@@ -4015,7 +4015,7 @@ type backupFile struct {
 	Volume    *api.StorageVolume      `yaml:"volume"`
 }
 
-func writeBackupFile(c Instance) error {
+func writeBackupFile(c instance.Instance) error {
 	// We only write backup files out for actual containers
 	if c.IsSnapshot() {
 		return nil
diff --git a/lxd/container_metadata.go b/lxd/container_metadata.go
index 0f6ecf828c..35d0aac470 100644
--- a/lxd/container_metadata.go
+++ b/lxd/container_metadata.go
@@ -13,6 +13,7 @@ import (
 	"github.com/gorilla/mux"
 	"gopkg.in/yaml.v2"
 
+	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/response"
 	"github.com/lxc/lxd/shared"
 	"github.com/lxc/lxd/shared/api"
@@ -358,7 +359,7 @@ func containerMetadataTemplatesDelete(d *Daemon, r *http.Request) response.Respo
 }
 
 // Return the full path of a container template.
-func getContainerTemplatePath(c Instance, filename string) (string, error) {
+func getContainerTemplatePath(c instance.Instance, filename string) (string, error) {
 	if strings.Contains(filename, "/") {
 		return "", fmt.Errorf("Invalid template filename")
 	}
diff --git a/lxd/container_post.go b/lxd/container_post.go
index 3371b332b9..65010b9338 100644
--- a/lxd/container_post.go
+++ b/lxd/container_post.go
@@ -14,6 +14,7 @@ import (
 	lxd "github.com/lxc/lxd/client"
 	"github.com/lxc/lxd/lxd/cluster"
 	"github.com/lxc/lxd/lxd/db"
+	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/instance/instancetype"
 	"github.com/lxc/lxd/lxd/operations"
 	"github.com/lxc/lxd/lxd/response"
@@ -104,7 +105,7 @@ func containerPost(d *Daemon, r *http.Request) response.Response {
 		return response.BadRequest(fmt.Errorf("Target node is offline"))
 	}
 
-	var inst Instance
+	var inst instance.Instance
 
 	// Check whether to forward the request to the node that is running the
 	// container. Here are the possible cases:
@@ -265,7 +266,7 @@ func containerPost(d *Daemon, r *http.Request) response.Response {
 }
 
 // Move a non-ceph container to another cluster node.
-func containerPostClusteringMigrate(d *Daemon, c Instance, oldName, newName, newNode string) response.Response {
+func containerPostClusteringMigrate(d *Daemon, c instance.Instance, oldName, newName, newNode string) response.Response {
 	cert := d.endpoints.NetworkCert()
 
 	var sourceAddress string
@@ -408,7 +409,7 @@ func containerPostClusteringMigrate(d *Daemon, c Instance, oldName, newName, new
 }
 
 // Special case migrating a container backed by ceph across two cluster nodes.
-func containerPostClusteringMigrateWithCeph(d *Daemon, c Instance, project, oldName, newName, newNode string, instanceType instancetype.Type) response.Response {
+func containerPostClusteringMigrateWithCeph(d *Daemon, c instance.Instance, project, oldName, newName, newNode string, instanceType instancetype.Type) response.Response {
 	run := func(*operations.Operation) error {
 		// If source node is online (i.e. we're serving the request on
 		// it, and c != nil), let's unmap the RBD volume locally
diff --git a/lxd/containers.go b/lxd/containers.go
index d98e4e6f47..a3a0b1f86f 100644
--- a/lxd/containers.go
+++ b/lxd/containers.go
@@ -9,6 +9,7 @@ import (
 	"time"
 
 	"github.com/lxc/lxd/lxd/db"
+	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/state"
 	"github.com/lxc/lxd/shared"
 	"github.com/lxc/lxd/shared/logger"
@@ -180,7 +181,7 @@ var instanceBackupExportCmd = APIEndpoint{
 	Get: APIEndpointAction{Handler: containerBackupExportGet, AccessHandler: AllowProjectPermission("containers", "view")},
 }
 
-type containerAutostartList []Instance
+type containerAutostartList []instance.Instance
 
 func (slice containerAutostartList) Len() int {
 	return len(slice)
@@ -210,7 +211,7 @@ func containersRestart(s *state.State) error {
 		return err
 	}
 
-	instances := []Instance{}
+	instances := []instance.Instance{}
 
 	for _, c := range result {
 		instances = append(instances, c)
@@ -246,7 +247,7 @@ func containersRestart(s *state.State) error {
 	return nil
 }
 
-type containerStopList []Instance
+type containerStopList []instance.Instance
 
 func (slice containerStopList) Len() int {
 	return len(slice)
@@ -307,7 +308,7 @@ func containersShutdown(s *state.State) error {
 	if err != nil {
 		// Mark database as offline
 		dbAvailable = false
-		instances = []Instance{}
+		instances = []instance.Instance{}
 
 		// List all containers on disk
 		cnames, err := containersOnDisk()
@@ -374,7 +375,7 @@ func containersShutdown(s *state.State) error {
 
 			// Stop the instance
 			wg.Add(1)
-			go func(c Instance, lastState string) {
+			go func(c instance.Instance, lastState string) {
 				c.Shutdown(time.Second * time.Duration(timeoutSeconds))
 				c.Stop(false)
 				c.VolatileSet(map[string]string{"volatile.last_state.power": lastState})
diff --git a/lxd/containers_get.go b/lxd/containers_get.go
index 3e4dc3d2bb..5fe0015cf3 100644
--- a/lxd/containers_get.go
+++ b/lxd/containers_get.go
@@ -15,6 +15,7 @@ import (
 	"github.com/lxc/lxd/lxd/cluster"
 	"github.com/lxc/lxd/lxd/db"
 	"github.com/lxc/lxd/lxd/db/query"
+	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/instance/instancetype"
 	"github.com/lxc/lxd/lxd/response"
 	"github.com/lxc/lxd/shared"
@@ -107,7 +108,7 @@ func doContainersGet(d *Daemon, r *http.Request) (interface{}, error) {
 	}
 
 	// Get the local instances
-	nodeCts := map[string]Instance{}
+	nodeCts := map[string]instance.Instance{}
 	if recursion > 0 {
 		cts, err := instanceLoadNodeProjectAll(d.State(), project, instanceType)
 		if err != nil {
diff --git a/lxd/containers_post.go b/lxd/containers_post.go
index dacc135db2..8c89892a15 100644
--- a/lxd/containers_post.go
+++ b/lxd/containers_post.go
@@ -21,6 +21,7 @@ import (
 	"github.com/lxc/lxd/lxd/cluster"
 	"github.com/lxc/lxd/lxd/db"
 	deviceConfig "github.com/lxc/lxd/lxd/device/config"
+	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/instance/instancetype"
 	"github.com/lxc/lxd/lxd/migration"
 	"github.com/lxc/lxd/lxd/operations"
@@ -207,7 +208,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 Instance
+	var c instance.Instance
 
 	// Parse the architecture name
 	architecture, err := osarch.ArchitectureId(req.Architecture)
@@ -894,7 +895,7 @@ func containerFindStoragePool(d *Daemon, project string, req *api.InstancesPost)
 	return storagePool, storagePoolProfile, localRootDiskDeviceKey, localRootDiskDevice, nil
 }
 
-func clusterCopyContainerInternal(d *Daemon, source Instance, project string, req *api.InstancesPost) response.Response {
+func clusterCopyContainerInternal(d *Daemon, source instance.Instance, project string, req *api.InstancesPost) response.Response {
 	name := req.Source.Source
 
 	// Locate the source of the container
diff --git a/lxd/devices.go b/lxd/devices.go
index 6b161e21fd..5939a0c494 100644
--- a/lxd/devices.go
+++ b/lxd/devices.go
@@ -16,11 +16,11 @@ import (
 
 	"github.com/lxc/lxd/lxd/cgroup"
 	"github.com/lxc/lxd/lxd/device"
+	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/state"
 	"github.com/lxc/lxd/shared"
-	"github.com/lxc/lxd/shared/logger"
-
 	log "github.com/lxc/lxd/shared/log15"
+	"github.com/lxc/lxd/shared/logger"
 )
 
 type deviceTaskCPU struct {
@@ -299,8 +299,8 @@ func deviceTaskBalance(s *state.State) {
 		return
 	}
 
-	fixedInstances := map[int][]Instance{}
-	balancedInstances := map[Instance]int{}
+	fixedInstances := map[int][]instance.Instance{}
+	balancedInstances := map[instance.Instance]int{}
 	for _, c := range instances {
 		conf := c.ExpandedConfig()
 		cpulimit, ok := conf["limits.cpu"]
@@ -332,14 +332,14 @@ func deviceTaskBalance(s *state.State) {
 				if ok {
 					fixedInstances[nr] = append(fixedInstances[nr], c)
 				} else {
-					fixedInstances[nr] = []Instance{c}
+					fixedInstances[nr] = []instance.Instance{c}
 				}
 			}
 		}
 	}
 
 	// Balance things
-	pinning := map[Instance][]string{}
+	pinning := map[instance.Instance][]string{}
 	usage := map[int]deviceTaskCPU{}
 
 	for _, id := range cpus {
diff --git a/lxd/migrate.go b/lxd/migrate.go
index b51e712bdf..bf0a0ea11e 100644
--- a/lxd/migrate.go
+++ b/lxd/migrate.go
@@ -18,6 +18,7 @@ import (
 	"github.com/golang/protobuf/proto"
 	"github.com/gorilla/websocket"
 
+	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/migration"
 	"github.com/lxc/lxd/lxd/operations"
 	"github.com/lxc/lxd/shared"
@@ -39,7 +40,7 @@ type migrationFields struct {
 	// container specific fields
 	live         bool
 	instanceOnly bool
-	instance     Instance
+	instance     instance.Instance
 
 	// storage specific fields
 	storage    storage
@@ -264,7 +265,7 @@ type MigrationSinkArgs struct {
 	Url     string
 
 	// Instance specific fields
-	Instance     Instance
+	Instance     instance.Instance
 	InstanceOnly bool
 	Idmap        *idmap.IdmapSet
 	Live         bool
@@ -281,7 +282,7 @@ type MigrationSinkArgs struct {
 
 type MigrationSourceArgs struct {
 	// Instance specific fields
-	Instance     Instance
+	Instance     instance.Instance
 	InstanceOnly bool
 
 	// Transport specific fields
diff --git a/lxd/migrate_container.go b/lxd/migrate_container.go
index fda13de567..c36df95fee 100644
--- a/lxd/migrate_container.go
+++ b/lxd/migrate_container.go
@@ -16,6 +16,7 @@ import (
 	"gopkg.in/lxc/go-lxc.v2"
 
 	"github.com/lxc/lxd/lxd/db"
+	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/instance/instancetype"
 	"github.com/lxc/lxd/lxd/migration"
 	"github.com/lxc/lxd/lxd/operations"
@@ -27,7 +28,7 @@ import (
 	"github.com/lxc/lxd/shared/logger"
 )
 
-func NewMigrationSource(inst Instance, stateful bool, instanceOnly bool) (*migrationSourceWs, error) {
+func NewMigrationSource(inst instance.Instance, stateful bool, instanceOnly bool) (*migrationSourceWs, error) {
 	ret := migrationSourceWs{migrationFields{instance: inst}, make(chan bool, 1)}
 	ret.instanceOnly = instanceOnly
 
@@ -80,7 +81,7 @@ fi
 	return err
 }
 
-func snapshotToProtobuf(c Instance) *migration.Snapshot {
+func snapshotToProtobuf(c instance.Instance) *migration.Snapshot {
 	config := []*migration.Config{}
 	for k, v := range c.LocalConfig() {
 		kCopy := string(k)
@@ -400,7 +401,13 @@ func (s *migrationSourceWs) Do(migrateOp *operations.Operation) error {
 
 	// The protocol says we have to send a header no matter what, so let's
 	// do that, but then immediately send an error.
-	myType := s.instance.Storage().MigrationType()
+	if s.instance.Type() != instancetype.Container {
+		return fmt.Errorf("Instance type must be container")
+	}
+
+	ct := s.instance.(*containerLXC)
+
+	myType := ct.Storage().MigrationType()
 	hasFeature := true
 	header := migration.MigrationHeader{
 		Fs:            &myType,
@@ -455,7 +462,7 @@ func (s *migrationSourceWs) Do(migrateOp *operations.Operation) error {
 	}
 
 	// Initialize storage driver
-	driver, fsErr := s.instance.Storage().MigrationSource(sourceArgs)
+	driver, fsErr := ct.Storage().MigrationSource(sourceArgs)
 	if fsErr != nil {
 		s.sendControl(fsErr)
 		return fsErr
@@ -473,7 +480,7 @@ func (s *migrationSourceWs) Do(migrateOp *operations.Operation) error {
 		}
 
 		// Check if this storage pool has a rate limit set for rsync.
-		poolwritable := s.instance.Storage().GetStoragePoolWritable()
+		poolwritable := ct.Storage().GetStoragePoolWritable()
 		if poolwritable.Config != nil {
 			bwlimit = poolwritable.Config["rsync.bwlimit"]
 		}
@@ -780,10 +787,10 @@ func NewMigrationSink(args *MigrationSinkArgs) (*migrationSink, error) {
 
 func (c *migrationSink) Do(migrateOp *operations.Operation) error {
 	if c.src.instance.Type() != instancetype.Container {
-		return fmt.Errorf("Instance not container type")
+		return fmt.Errorf("Instance type must be container")
 	}
 
-	ct := c.src.instance.(container)
+	ct := c.src.instance.(*containerLXC)
 
 	var err error
 
@@ -858,12 +865,12 @@ func (c *migrationSink) Do(migrateOp *operations.Operation) error {
 		}
 	}
 
-	mySink := c.src.instance.Storage().MigrationSink
+	mySink := ct.Storage().MigrationSink
 	if c.refresh {
 		mySink = rsyncMigrationSink
 	}
 
-	myType := c.src.instance.Storage().MigrationType()
+	myType := ct.Storage().MigrationType()
 	resp := migration.MigrationHeader{
 		Fs:            &myType,
 		Criu:          criuType,
@@ -1166,12 +1173,12 @@ func (s *migrationSourceWs) ConnectContainerTarget(target api.InstancePostTarget
 	return s.ConnectTarget(target.Certificate, target.Operation, target.Websockets)
 }
 
-func migrationCompareSnapshots(sourceSnapshots []*migration.Snapshot, targetSnapshots []Instance) ([]*migration.Snapshot, []Instance) {
+func migrationCompareSnapshots(sourceSnapshots []*migration.Snapshot, targetSnapshots []instance.Instance) ([]*migration.Snapshot, []instance.Instance) {
 	// Compare source and target
 	sourceSnapshotsTime := map[string]int64{}
 	targetSnapshotsTime := map[string]int64{}
 
-	toDelete := []Instance{}
+	toDelete := []instance.Instance{}
 	toSync := []*migration.Snapshot{}
 
 	for _, snap := range sourceSnapshots {
diff --git a/lxd/networks_utils.go b/lxd/networks_utils.go
index 05334b00c7..aa90ca415e 100644
--- a/lxd/networks_utils.go
+++ b/lxd/networks_utils.go
@@ -25,6 +25,7 @@ import (
 	"github.com/lxc/lxd/lxd/db"
 	"github.com/lxc/lxd/lxd/device"
 	"github.com/lxc/lxd/lxd/dnsmasq"
+	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/instance/instancetype"
 	"github.com/lxc/lxd/lxd/project"
 	"github.com/lxc/lxd/lxd/state"
@@ -90,7 +91,7 @@ func networkGetInterfaces(cluster *db.Cluster) ([]string, error) {
 	return networks, nil
 }
 
-func networkIsInUse(c Instance, name string) bool {
+func networkIsInUse(c instance.Instance, name string) bool {
 	for _, d := range c.ExpandedDevices() {
 		if d["type"] != "nic" {
 			continue
diff --git a/lxd/storage.go b/lxd/storage.go
index 138f7d144f..4fca279fca 100644
--- a/lxd/storage.go
+++ b/lxd/storage.go
@@ -14,6 +14,7 @@ import (
 	"github.com/lxc/lxd/lxd/backup"
 	"github.com/lxc/lxd/lxd/db"
 	"github.com/lxc/lxd/lxd/device"
+	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/instance/instancetype"
 	"github.com/lxc/lxd/lxd/migration"
 	"github.com/lxc/lxd/lxd/operations"
@@ -193,32 +194,32 @@ type storage interface {
 
 	// Functions dealing with container storage volumes.
 	// ContainerCreate creates an empty container (no rootfs/metadata.yaml)
-	ContainerCreate(container Instance) error
+	ContainerCreate(container instance.Instance) error
 
 	// ContainerCreateFromImage creates a container from a image.
-	ContainerCreateFromImage(c Instance, fingerprint string, tracker *ioprogress.ProgressTracker) error
-	ContainerDelete(c Instance) error
-	ContainerCopy(target Instance, source Instance, containerOnly bool) error
-	ContainerRefresh(target Instance, source Instance, snapshots []Instance) error
-	ContainerMount(c Instance) (bool, error)
-	ContainerUmount(c Instance, path string) (bool, error)
-	ContainerRename(container Instance, newName string) error
-	ContainerRestore(container Instance, sourceContainer Instance) error
-	ContainerGetUsage(container Instance) (int64, error)
+	ContainerCreateFromImage(c instance.Instance, fingerprint string, tracker *ioprogress.ProgressTracker) error
+	ContainerDelete(c instance.Instance) error
+	ContainerCopy(target instance.Instance, source instance.Instance, containerOnly bool) error
+	ContainerRefresh(target instance.Instance, source instance.Instance, snapshots []instance.Instance) error
+	ContainerMount(c instance.Instance) (bool, error)
+	ContainerUmount(c instance.Instance, path string) (bool, error)
+	ContainerRename(container instance.Instance, newName string) error
+	ContainerRestore(container instance.Instance, sourceContainer instance.Instance) error
+	ContainerGetUsage(container instance.Instance) (int64, error)
 	GetContainerPoolInfo() (int64, string, string)
-	ContainerStorageReady(container Instance) bool
+	ContainerStorageReady(container instance.Instance) bool
 
-	ContainerSnapshotCreate(target Instance, source Instance) error
-	ContainerSnapshotDelete(c Instance) error
-	ContainerSnapshotRename(c Instance, newName string) error
-	ContainerSnapshotStart(c Instance) (bool, error)
-	ContainerSnapshotStop(c Instance) (bool, error)
+	ContainerSnapshotCreate(target instance.Instance, source instance.Instance) error
+	ContainerSnapshotDelete(c instance.Instance) error
+	ContainerSnapshotRename(c instance.Instance, newName string) error
+	ContainerSnapshotStart(c instance.Instance) (bool, error)
+	ContainerSnapshotStop(c instance.Instance) (bool, error)
 
-	ContainerBackupCreate(path string, backup backup.Backup, sourceContainer Instance) error
+	ContainerBackupCreate(path string, backup backup.Backup, sourceContainer instance.Instance) error
 	ContainerBackupLoad(info backup.Info, data io.ReadSeeker, tarArgs []string) error
 
 	// For use in migrating snapshots.
-	ContainerSnapshotCreateEmpty(c Instance) error
+	ContainerSnapshotCreateEmpty(c instance.Instance) error
 
 	// Functions dealing with image storage volumes.
 	ImageCreate(fingerprint string, tracker *ioprogress.ProgressTracker) error
diff --git a/lxd/storage_btrfs.go b/lxd/storage_btrfs.go
index 99ef097b09..c598d76d89 100644
--- a/lxd/storage_btrfs.go
+++ b/lxd/storage_btrfs.go
@@ -17,6 +17,8 @@ import (
 	"golang.org/x/sys/unix"
 
 	"github.com/lxc/lxd/lxd/backup"
+	"github.com/lxc/lxd/lxd/instance"
+	"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"
@@ -803,7 +805,7 @@ func (s *storageBtrfs) StoragePoolVolumeRename(newName string) error {
 }
 
 // Functions dealing with container storage.
-func (s *storageBtrfs) ContainerStorageReady(container Instance) bool {
+func (s *storageBtrfs) ContainerStorageReady(container instance.Instance) bool {
 	containerMntPoint := driver.GetContainerMountPoint(container.Project(), s.pool.Name, container.Name())
 	return isBtrfsSubVolume(containerMntPoint)
 }
@@ -848,7 +850,7 @@ func (s *storageBtrfs) doContainerCreate(projectName, name string, privileged bo
 	return nil
 }
 
-func (s *storageBtrfs) ContainerCreate(container Instance) error {
+func (s *storageBtrfs) ContainerCreate(container instance.Instance) error {
 	err := s.doContainerCreate(container.Project(), container.Name(), container.IsPrivileged())
 	if err != nil {
 		return err
@@ -858,7 +860,7 @@ func (s *storageBtrfs) ContainerCreate(container Instance) error {
 }
 
 // And this function is why I started hating on btrfs...
-func (s *storageBtrfs) ContainerCreateFromImage(container Instance, fingerprint string, tracker *ioprogress.ProgressTracker) error {
+func (s *storageBtrfs) ContainerCreateFromImage(container instance.Instance, fingerprint string, tracker *ioprogress.ProgressTracker) error {
 	logger.Debugf("Creating BTRFS storage volume for container \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name)
 
 	source := s.pool.Config["source"]
@@ -941,7 +943,7 @@ func (s *storageBtrfs) ContainerCreateFromImage(container Instance, fingerprint
 	return nil
 }
 
-func (s *storageBtrfs) ContainerDelete(container Instance) error {
+func (s *storageBtrfs) ContainerDelete(container instance.Instance) error {
 	logger.Debugf("Deleting BTRFS storage volume for container \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name)
 
 	// The storage pool needs to be mounted.
@@ -988,7 +990,7 @@ func (s *storageBtrfs) ContainerDelete(container Instance) error {
 	return nil
 }
 
-func (s *storageBtrfs) copyContainer(target Instance, source Instance) error {
+func (s *storageBtrfs) copyContainer(target instance.Instance, source instance.Instance) error {
 	sourceContainerSubvolumeName := driver.GetContainerMountPoint(source.Project(), s.pool.Name, source.Name())
 	if source.IsSnapshot() {
 		sourceContainerSubvolumeName = driver.GetSnapshotMountPoint(source.Project(), s.pool.Name, source.Name())
@@ -1022,7 +1024,7 @@ func (s *storageBtrfs) copyContainer(target Instance, source Instance) error {
 	return nil
 }
 
-func (s *storageBtrfs) copySnapshot(target Instance, source Instance) error {
+func (s *storageBtrfs) copySnapshot(target instance.Instance, source instance.Instance) error {
 	sourceName := source.Name()
 	targetName := target.Name()
 	sourceContainerSubvolumeName := driver.GetSnapshotMountPoint(source.Project(), s.pool.Name, sourceName)
@@ -1053,7 +1055,7 @@ func (s *storageBtrfs) copySnapshot(target Instance, source Instance) error {
 	return nil
 }
 
-func (s *storageBtrfs) doCrossPoolContainerCopy(target Instance, source Instance, containerOnly bool, refresh bool, refreshSnapshots []Instance) error {
+func (s *storageBtrfs) doCrossPoolContainerCopy(target instance.Instance, source instance.Instance, containerOnly bool, refresh bool, refreshSnapshots []instance.Instance) error {
 	sourcePool, err := source.StoragePool()
 	if err != nil {
 		return err
@@ -1078,7 +1080,7 @@ func (s *storageBtrfs) doCrossPoolContainerCopy(target Instance, source Instance
 		return err
 	}
 
-	var snapshots []Instance
+	var snapshots []instance.Instance
 
 	if refresh {
 		snapshots = refreshSnapshots
@@ -1125,7 +1127,7 @@ func (s *storageBtrfs) doCrossPoolContainerCopy(target Instance, source Instance
 	return nil
 }
 
-func (s *storageBtrfs) ContainerCopy(target Instance, source Instance, containerOnly bool) error {
+func (s *storageBtrfs) ContainerCopy(target instance.Instance, source instance.Instance, containerOnly bool) error {
 	logger.Debugf("Copying BTRFS container storage %s to %s", source.Name(), target.Name())
 
 	// The storage pool needs to be mounted.
@@ -1142,8 +1144,19 @@ func (s *storageBtrfs) ContainerCopy(target Instance, source Instance, container
 		defer source.StorageStop()
 	}
 
-	_, sourcePool, _ := source.Storage().GetContainerPoolInfo()
-	_, targetPool, _ := target.Storage().GetContainerPoolInfo()
+	if target.Type() != instancetype.Container {
+		return fmt.Errorf("Target Instance type must be container")
+	}
+
+	if source.Type() != instancetype.Container {
+		return fmt.Errorf("Source Instance type must be container")
+	}
+
+	targetCt := target.(*containerLXC)
+	srcCt := source.(*containerLXC)
+
+	_, sourcePool, _ := srcCt.Storage().GetContainerPoolInfo()
+	_, targetPool, _ := targetCt.Storage().GetContainerPoolInfo()
 	if sourcePool != targetPool {
 		return s.doCrossPoolContainerCopy(target, source, containerOnly, false, nil)
 	}
@@ -1191,7 +1204,7 @@ func (s *storageBtrfs) ContainerCopy(target Instance, source Instance, container
 	return nil
 }
 
-func (s *storageBtrfs) ContainerRefresh(target Instance, source Instance, snapshots []Instance) error {
+func (s *storageBtrfs) ContainerRefresh(target instance.Instance, source instance.Instance, snapshots []instance.Instance) error {
 	logger.Debugf("Refreshing BTRFS container storage for %s from %s", target.Name(), source.Name())
 
 	// The storage pool needs to be mounted.
@@ -1211,7 +1224,7 @@ func (s *storageBtrfs) ContainerRefresh(target Instance, source Instance, snapsh
 	return s.doCrossPoolContainerCopy(target, source, len(snapshots) == 0, true, snapshots)
 }
 
-func (s *storageBtrfs) ContainerMount(c Instance) (bool, error) {
+func (s *storageBtrfs) ContainerMount(c instance.Instance) (bool, error) {
 	logger.Debugf("Mounting BTRFS storage volume for container \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name)
 
 	// The storage pool must be mounted.
@@ -1224,11 +1237,11 @@ func (s *storageBtrfs) ContainerMount(c Instance) (bool, error) {
 	return true, nil
 }
 
-func (s *storageBtrfs) ContainerUmount(c Instance, path string) (bool, error) {
+func (s *storageBtrfs) ContainerUmount(c instance.Instance, path string) (bool, error) {
 	return true, nil
 }
 
-func (s *storageBtrfs) ContainerRename(container Instance, newName string) error {
+func (s *storageBtrfs) ContainerRename(container instance.Instance, newName string) error {
 	logger.Debugf("Renaming BTRFS storage volume for container \"%s\" from %s to %s", s.volume.Name, s.volume.Name, newName)
 
 	// The storage pool must be mounted.
@@ -1277,7 +1290,7 @@ func (s *storageBtrfs) ContainerRename(container Instance, newName string) error
 	return nil
 }
 
-func (s *storageBtrfs) ContainerRestore(container Instance, sourceContainer Instance) error {
+func (s *storageBtrfs) ContainerRestore(container instance.Instance, sourceContainer instance.Instance) error {
 	logger.Debugf("Restoring BTRFS storage volume for container \"%s\" from %s to %s", s.volume.Name, sourceContainer.Name(), container.Name())
 
 	// The storage pool must be mounted.
@@ -1309,7 +1322,13 @@ func (s *storageBtrfs) ContainerRestore(container Instance, sourceContainer Inst
 	}
 
 	// Mount the source container.
-	srcContainerStorage := sourceContainer.Storage()
+	if sourceContainer.Type() != instancetype.Container {
+		return fmt.Errorf("Instance type must be container")
+	}
+
+	ct := sourceContainer.(*containerLXC)
+
+	srcContainerStorage := ct.Storage()
 	_, sourcePool, _ := srcContainerStorage.GetContainerPoolInfo()
 	sourceContainerSubvolumeName := ""
 	if sourceContainer.IsSnapshot() {
@@ -1362,7 +1381,7 @@ func (s *storageBtrfs) ContainerRestore(container Instance, sourceContainer Inst
 	return failure
 }
 
-func (s *storageBtrfs) ContainerGetUsage(container Instance) (int64, error) {
+func (s *storageBtrfs) ContainerGetUsage(container instance.Instance) (int64, error) {
 	return s.btrfsPoolVolumeQGroupUsage(container.Path())
 }
 
@@ -1415,7 +1434,7 @@ func (s *storageBtrfs) doContainerSnapshotCreate(projectName string, targetName
 	return nil
 }
 
-func (s *storageBtrfs) ContainerSnapshotCreate(snapshotContainer Instance, sourceContainer Instance) error {
+func (s *storageBtrfs) ContainerSnapshotCreate(snapshotContainer instance.Instance, sourceContainer instance.Instance) error {
 	err := s.doContainerSnapshotCreate(sourceContainer.Project(), snapshotContainer.Name(), sourceContainer.Name())
 	if err != nil {
 		s.ContainerSnapshotDelete(snapshotContainer)
@@ -1454,7 +1473,7 @@ func btrfsSnapshotDeleteInternal(projectName, poolName string, snapshotName stri
 	return nil
 }
 
-func (s *storageBtrfs) ContainerSnapshotDelete(snapshotContainer Instance) error {
+func (s *storageBtrfs) ContainerSnapshotDelete(snapshotContainer instance.Instance) error {
 	logger.Debugf("Deleting BTRFS storage volume for snapshot \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name)
 
 	_, err := s.StoragePoolMount()
@@ -1471,7 +1490,7 @@ func (s *storageBtrfs) ContainerSnapshotDelete(snapshotContainer Instance) error
 	return nil
 }
 
-func (s *storageBtrfs) ContainerSnapshotStart(container Instance) (bool, error) {
+func (s *storageBtrfs) ContainerSnapshotStart(container instance.Instance) (bool, error) {
 	logger.Debugf("Initializing BTRFS storage volume for snapshot \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name)
 
 	_, err := s.StoragePoolMount()
@@ -1500,7 +1519,7 @@ func (s *storageBtrfs) ContainerSnapshotStart(container Instance) (bool, error)
 	return true, nil
 }
 
-func (s *storageBtrfs) ContainerSnapshotStop(container Instance) (bool, error) {
+func (s *storageBtrfs) ContainerSnapshotStop(container instance.Instance) (bool, error) {
 	logger.Debugf("Stopping BTRFS storage volume for snapshot \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name)
 
 	_, err := s.StoragePoolMount()
@@ -1532,7 +1551,7 @@ func (s *storageBtrfs) ContainerSnapshotStop(container Instance) (bool, error) {
 }
 
 // ContainerSnapshotRename renames a snapshot of a container.
-func (s *storageBtrfs) ContainerSnapshotRename(snapshotContainer Instance, newName string) error {
+func (s *storageBtrfs) ContainerSnapshotRename(snapshotContainer instance.Instance, newName string) error {
 	logger.Debugf("Renaming BTRFS storage volume for snapshot \"%s\" from %s to %s", s.volume.Name, s.volume.Name, newName)
 
 	// The storage pool must be mounted.
@@ -1556,7 +1575,7 @@ func (s *storageBtrfs) ContainerSnapshotRename(snapshotContainer Instance, newNa
 
 // Needed for live migration where an empty snapshot needs to be created before
 // rsyncing into it.
-func (s *storageBtrfs) ContainerSnapshotCreateEmpty(snapshotContainer Instance) error {
+func (s *storageBtrfs) ContainerSnapshotCreateEmpty(snapshotContainer instance.Instance) error {
 	logger.Debugf("Creating empty BTRFS storage volume for snapshot \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name)
 
 	// Mount the storage pool.
@@ -1618,7 +1637,7 @@ func (s *storageBtrfs) doBtrfsBackup(cur string, prev string, target string) err
 	return err
 }
 
-func (s *storageBtrfs) doContainerBackupCreateOptimized(tmpPath string, backup backup.Backup, source Instance) error {
+func (s *storageBtrfs) doContainerBackupCreateOptimized(tmpPath string, backup backup.Backup, source instance.Instance) error {
 	// Handle snapshots
 	finalParent := ""
 	if !backup.InstanceOnly() {
@@ -1691,7 +1710,7 @@ func (s *storageBtrfs) doContainerBackupCreateOptimized(tmpPath string, backup b
 	return nil
 }
 
-func (s *storageBtrfs) doContainerBackupCreateVanilla(tmpPath string, backup backup.Backup, source Instance) error {
+func (s *storageBtrfs) doContainerBackupCreateVanilla(tmpPath string, backup backup.Backup, source instance.Instance) error {
 	// Prepare for rsync
 	rsync := func(oldPath string, newPath string, bwlimit string) error {
 		output, err := rsync.LocalCopy(oldPath, newPath, bwlimit, true)
@@ -1774,7 +1793,7 @@ func (s *storageBtrfs) doContainerBackupCreateVanilla(tmpPath string, backup bac
 	return nil
 }
 
-func (s *storageBtrfs) ContainerBackupCreate(path string, backup backup.Backup, source Instance) error {
+func (s *storageBtrfs) ContainerBackupCreate(path string, backup backup.Backup, source instance.Instance) error {
 	var err error
 
 	// Generate the actual backup
@@ -2439,7 +2458,7 @@ func (s *storageBtrfs) MigrationSource(args MigrationSourceArgs) (MigrationStora
 	 * xfer costs. Then, after all that, we send the container itself.
 	 */
 	var err error
-	var snapshots = []Instance{}
+	var snapshots = []instance.Instance{}
 	if !args.InstanceOnly {
 		snapshots, err = args.Instance.Snapshots()
 		if err != nil {
@@ -2539,7 +2558,14 @@ func (s *storageBtrfs) MigrationSink(conn *websocket.Conn, op *operations.Operat
 	}
 
 	instanceName := args.Instance.Name()
-	_, instancePool, _ := args.Instance.Storage().GetContainerPoolInfo()
+
+	if args.Instance.Type() != instancetype.Container {
+		return fmt.Errorf("Instance type must be container")
+	}
+
+	ct := args.Instance.(*containerLXC)
+
+	_, instancePool, _ := ct.Storage().GetContainerPoolInfo()
 	containersPath := driver.GetSnapshotMountPoint(args.Instance.Project(), instancePool, instanceName)
 	if !args.InstanceOnly && len(args.Snapshots) > 0 {
 		err := os.MkdirAll(containersPath, driver.ContainersDirMode)
diff --git a/lxd/storage_ceph.go b/lxd/storage_ceph.go
index 45a21a4f19..d9872487db 100644
--- a/lxd/storage_ceph.go
+++ b/lxd/storage_ceph.go
@@ -16,6 +16,8 @@ import (
 
 	"github.com/lxc/lxd/lxd/backup"
 	"github.com/lxc/lxd/lxd/db"
+	"github.com/lxc/lxd/lxd/instance"
+	"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"
@@ -767,7 +769,7 @@ func (s *storageCeph) StoragePoolUpdate(writable *api.StoragePoolPut, changedCon
 	return nil
 }
 
-func (s *storageCeph) ContainerStorageReady(container Instance) bool {
+func (s *storageCeph) ContainerStorageReady(container instance.Instance) bool {
 	name := container.Name()
 	logger.Debugf(`Checking if RBD storage volume for container "%s" on storage pool "%s" is ready`, name, s.pool.Name)
 
@@ -782,7 +784,7 @@ func (s *storageCeph) ContainerStorageReady(container Instance) bool {
 	return true
 }
 
-func (s *storageCeph) ContainerCreate(container Instance) error {
+func (s *storageCeph) ContainerCreate(container instance.Instance) error {
 	containerName := container.Name()
 	err := s.doContainerCreate(container.Project(), containerName, container.IsPrivileged())
 	if err != nil {
@@ -801,7 +803,7 @@ func (s *storageCeph) ContainerCreate(container Instance) error {
 	return nil
 }
 
-func (s *storageCeph) ContainerCreateFromImage(container Instance, fingerprint string, tracker *ioprogress.ProgressTracker) error {
+func (s *storageCeph) ContainerCreateFromImage(container instance.Instance, fingerprint string, tracker *ioprogress.ProgressTracker) error {
 	logger.Debugf(`Creating RBD storage volume for container "%s" on storage pool "%s"`, s.volume.Name, s.pool.Name)
 
 	revert := true
@@ -953,7 +955,7 @@ func (s *storageCeph) ContainerCreateFromImage(container Instance, fingerprint s
 	return nil
 }
 
-func (s *storageCeph) ContainerDelete(container Instance) error {
+func (s *storageCeph) ContainerDelete(container instance.Instance) error {
 	containerName := container.Name()
 	logger.Debugf(`Deleting RBD storage volume for container "%s" on storage pool "%s"`, containerName, s.pool.Name)
 
@@ -1002,7 +1004,7 @@ func (s *storageCeph) ContainerDelete(container Instance) error {
 // - for each snapshot dump the contents into the empty storage volume and
 //   after each dump take a snapshot of the rbd storage volume
 // - dump the container contents into the rbd storage volume.
-func (s *storageCeph) doCrossPoolContainerCopy(target Instance, source Instance, containerOnly bool, refresh bool, refreshSnapshots []Instance) error {
+func (s *storageCeph) doCrossPoolContainerCopy(target instance.Instance, source instance.Instance, containerOnly bool, refresh bool, refreshSnapshots []instance.Instance) error {
 	sourcePool, err := source.StoragePool()
 	if err != nil {
 		return err
@@ -1027,7 +1029,7 @@ func (s *storageCeph) doCrossPoolContainerCopy(target Instance, source Instance,
 		return err
 	}
 
-	var snapshots []Instance
+	var snapshots []instance.Instance
 
 	if refresh {
 		snapshots = refreshSnapshots
@@ -1097,13 +1099,24 @@ func (s *storageCeph) doCrossPoolContainerCopy(target Instance, source Instance,
 	return nil
 }
 
-func (s *storageCeph) ContainerCopy(target Instance, source Instance, containerOnly bool) error {
+func (s *storageCeph) ContainerCopy(target instance.Instance, source instance.Instance, containerOnly bool) error {
 	sourceContainerName := source.Name()
 	logger.Debugf(`Copying RBD container storage %s to %s`, sourceContainerName, target.Name())
 
+	if source.Type() != instancetype.Container {
+		return fmt.Errorf("Source Instance type must be container")
+	}
+
+	if target.Type() != instancetype.Container {
+		return fmt.Errorf("Target Instance type must be container")
+	}
+
+	srcCt := source.(*containerLXC)
+	targetCt := target.(*containerLXC)
+
 	// Handle cross pool copies
-	_, sourcePool, _ := source.Storage().GetContainerPoolInfo()
-	_, targetPool, _ := target.Storage().GetContainerPoolInfo()
+	_, sourcePool, _ := srcCt.Storage().GetContainerPoolInfo()
+	_, targetPool, _ := targetCt.Storage().GetContainerPoolInfo()
 	if sourcePool != targetPool {
 		return s.doCrossPoolContainerCopy(target, source, containerOnly, false, nil)
 	}
@@ -1330,13 +1343,13 @@ func (s *storageCeph) ContainerCopy(target Instance, source Instance, containerO
 	return nil
 }
 
-func (s *storageCeph) ContainerRefresh(target Instance, source Instance, snapshots []Instance) error {
+func (s *storageCeph) ContainerRefresh(target instance.Instance, source instance.Instance, snapshots []instance.Instance) error {
 	logger.Debugf(`Refreshing RBD container storage for %s from %s`, target.Name(), source.Name())
 
 	return s.doCrossPoolContainerCopy(target, source, len(snapshots) == 0, true, snapshots)
 }
 
-func (s *storageCeph) ContainerMount(c Instance) (bool, error) {
+func (s *storageCeph) ContainerMount(c instance.Instance) (bool, error) {
 	logger.Debugf("Mounting RBD storage volume for container \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name)
 
 	ourMount, err := s.doContainerMount(c.Project(), c.Name())
@@ -1348,7 +1361,7 @@ func (s *storageCeph) ContainerMount(c Instance) (bool, error) {
 	return ourMount, nil
 }
 
-func (s *storageCeph) ContainerUmount(c Instance, path string) (bool, error) {
+func (s *storageCeph) ContainerUmount(c instance.Instance, path string) (bool, error) {
 	logger.Debugf("Unmounting RBD storage volume for container \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name)
 	name := c.Name()
 
@@ -1397,7 +1410,7 @@ func (s *storageCeph) ContainerUmount(c Instance, path string) (bool, error) {
 	return ourUmount, nil
 }
 
-func (s *storageCeph) ContainerRename(c Instance, newName string) error {
+func (s *storageCeph) ContainerRename(c instance.Instance, newName string) error {
 	oldName := c.Name()
 	containerPath := c.Path()
 
@@ -1549,7 +1562,7 @@ func (s *storageCeph) ContainerRename(c Instance, newName string) error {
 	return nil
 }
 
-func (s *storageCeph) ContainerRestore(target Instance, source Instance) error {
+func (s *storageCeph) ContainerRestore(target instance.Instance, source instance.Instance) error {
 	sourceName := source.Name()
 	targetName := target.Name()
 
@@ -1591,11 +1604,11 @@ func (s *storageCeph) ContainerRestore(target Instance, source Instance) error {
 	return nil
 }
 
-func (s *storageCeph) ContainerGetUsage(container Instance) (int64, error) {
+func (s *storageCeph) ContainerGetUsage(container instance.Instance) (int64, error) {
 	return -1, fmt.Errorf("RBD quotas are currently not supported")
 }
 
-func (s *storageCeph) ContainerSnapshotCreate(snapshotContainer Instance, sourceContainer Instance) error {
+func (s *storageCeph) ContainerSnapshotCreate(snapshotContainer instance.Instance, sourceContainer instance.Instance) error {
 	containerMntPoint := driver.GetContainerMountPoint(sourceContainer.Project(), s.pool.Name, sourceContainer.Name())
 	if shared.IsMountPoint(containerMntPoint) {
 		// This is costly but we need to ensure that all cached data has
@@ -1614,7 +1627,7 @@ func (s *storageCeph) ContainerSnapshotCreate(snapshotContainer Instance, source
 	return s.doContainerSnapshotCreate(sourceContainer.Project(), snapshotContainer.Name(), sourceContainer.Name())
 }
 
-func (s *storageCeph) ContainerSnapshotDelete(snapshotContainer Instance) error {
+func (s *storageCeph) ContainerSnapshotDelete(snapshotContainer instance.Instance) error {
 	logger.Debugf(`Deleting RBD storage volume for snapshot "%s" on storage pool "%s"`, s.volume.Name, s.pool.Name)
 
 	snapshotContainerName := snapshotContainer.Name()
@@ -1680,7 +1693,7 @@ func (s *storageCeph) ContainerSnapshotDelete(snapshotContainer Instance) error
 	return nil
 }
 
-func (s *storageCeph) ContainerSnapshotRename(c Instance, newName string) error {
+func (s *storageCeph) ContainerSnapshotRename(c instance.Instance, newName string) error {
 	oldName := c.Name()
 	logger.Debugf(`Renaming RBD storage volume for snapshot "%s" from "%s" to "%s"`, oldName, oldName, newName)
 
@@ -1728,7 +1741,7 @@ func (s *storageCeph) ContainerSnapshotRename(c Instance, newName string) error
 	return nil
 }
 
-func (s *storageCeph) ContainerSnapshotStart(c Instance) (bool, error) {
+func (s *storageCeph) ContainerSnapshotStart(c instance.Instance) (bool, error) {
 	containerName := c.Name()
 	logger.Debugf(`Initializing RBD storage volume for snapshot "%s" on storage pool "%s"`, containerName, s.pool.Name)
 
@@ -1844,7 +1857,7 @@ func (s *storageCeph) ContainerSnapshotStart(c Instance) (bool, error) {
 	return true, nil
 }
 
-func (s *storageCeph) ContainerSnapshotStop(c Instance) (bool, error) {
+func (s *storageCeph) ContainerSnapshotStop(c instance.Instance) (bool, error) {
 	logger.Debugf(`Stopping RBD storage volume for snapshot "%s" on storage pool "%s"`, c.Name(), s.pool.Name)
 
 	containerName := c.Name()
@@ -1891,14 +1904,14 @@ func (s *storageCeph) ContainerSnapshotStop(c Instance) (bool, error) {
 	return true, nil
 }
 
-func (s *storageCeph) ContainerSnapshotCreateEmpty(c Instance) error {
+func (s *storageCeph) ContainerSnapshotCreateEmpty(c instance.Instance) error {
 	logger.Debugf(`Creating empty RBD storage volume for snapshot "%s" on storage pool "%s" (noop)`, c.Name(), s.pool.Name)
 
 	logger.Debugf(`Created empty RBD storage volume for snapshot "%s" on storage pool "%s" (noop)`, c.Name(), s.pool.Name)
 	return nil
 }
 
-func (s *storageCeph) ContainerBackupCreate(path string, backup backup.Backup, source Instance) error {
+func (s *storageCeph) ContainerBackupCreate(path string, backup backup.Backup, source instance.Instance) error {
 	// Generate the actual backup
 	if !backup.InstanceOnly() {
 		snapshots, err := source.Snapshots()
@@ -2814,7 +2827,7 @@ func (s *storageCeph) MigrationSource(args MigrationSourceArgs) (MigrationStorag
 
 	driver := rbdMigrationSourceDriver{
 		container:        args.Instance,
-		snapshots:        []Instance{},
+		snapshots:        []instance.Instance{},
 		rbdSnapshotNames: []string{},
 		ceph:             s,
 	}
diff --git a/lxd/storage_ceph_utils.go b/lxd/storage_ceph_utils.go
index 3ab341ea39..00baa837d7 100644
--- a/lxd/storage_ceph_utils.go
+++ b/lxd/storage_ceph_utils.go
@@ -16,6 +16,7 @@ import (
 
 	"github.com/lxc/lxd/lxd/backup"
 	"github.com/lxc/lxd/lxd/db"
+	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/project"
 	"github.com/lxc/lxd/lxd/rsync"
 	driver "github.com/lxc/lxd/lxd/storage"
@@ -745,7 +746,7 @@ func (s *storageCeph) getRBDMountOptions() string {
 // copyWithoutSnapshotsFull creates a non-sparse copy of a container
 // This does not introduce a dependency relation between the source RBD storage
 // volume and the target RBD storage volume.
-func (s *storageCeph) copyWithoutSnapshotsFull(target Instance, source Instance) error {
+func (s *storageCeph) copyWithoutSnapshotsFull(target instance.Instance, source instance.Instance) error {
 	logger.Debugf(`Creating non-sparse copy of RBD storage volume for container "%s" to "%s" without snapshots`, source.Name(), target.Name())
 
 	sourceIsSnapshot := source.IsSnapshot()
@@ -813,7 +814,7 @@ func (s *storageCeph) copyWithoutSnapshotsFull(target Instance, source Instance)
 // copyWithoutSnapshotsFull creates a sparse copy of a container
 // This introduces a dependency relation between the source RBD storage volume
 // and the target RBD storage volume.
-func (s *storageCeph) copyWithoutSnapshotsSparse(target Instance, source Instance) error {
+func (s *storageCeph) copyWithoutSnapshotsSparse(target instance.Instance, source instance.Instance) error {
 	logger.Debugf(`Creating sparse copy of RBD storage volume for container "%s" to "%s" without snapshots`, source.Name(),
 		target.Name())
 
@@ -1602,7 +1603,7 @@ func (s *storageCeph) cephRBDVolumeDumpToFile(sourceVolumeName string, file stri
 }
 
 // cephRBDVolumeBackupCreate creates a backup of a container or snapshot.
-func (s *storageCeph) cephRBDVolumeBackupCreate(tmpPath string, backup backup.Backup, source Instance) error {
+func (s *storageCeph) cephRBDVolumeBackupCreate(tmpPath string, backup backup.Backup, source instance.Instance) error {
 	sourceIsSnapshot := source.IsSnapshot()
 	sourceContainerName := source.Name()
 	sourceContainerOnlyName := project.Prefix(source.Project(), sourceContainerName)
diff --git a/lxd/storage_cephfs.go b/lxd/storage_cephfs.go
index 495165b75d..61de5d7284 100644
--- a/lxd/storage_cephfs.go
+++ b/lxd/storage_cephfs.go
@@ -14,6 +14,7 @@ import (
 	"github.com/pkg/errors"
 
 	"github.com/lxc/lxd/lxd/backup"
+	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/migration"
 	"github.com/lxc/lxd/lxd/operations"
 	"github.com/lxc/lxd/lxd/rsync"
@@ -621,81 +622,81 @@ func (s *storageCephFs) StoragePoolVolumeRename(newName string) error {
 	return nil
 }
 
-func (s *storageCephFs) ContainerStorageReady(container Instance) bool {
+func (s *storageCephFs) ContainerStorageReady(container instance.Instance) bool {
 	containerMntPoint := driver.GetContainerMountPoint(container.Project(), s.pool.Name, container.Name())
 	ok, _ := shared.PathIsEmpty(containerMntPoint)
 	return !ok
 }
 
-func (s *storageCephFs) ContainerCreate(container Instance) error {
+func (s *storageCephFs) ContainerCreate(container instance.Instance) error {
 	return fmt.Errorf("CEPHFS cannot be used for containers")
 }
 
-func (s *storageCephFs) ContainerCreateFromImage(container Instance, imageFingerprint string, tracker *ioprogress.ProgressTracker) error {
+func (s *storageCephFs) ContainerCreateFromImage(container instance.Instance, imageFingerprint string, tracker *ioprogress.ProgressTracker) error {
 	return fmt.Errorf("CEPHFS cannot be used for containers")
 }
 
-func (s *storageCephFs) ContainerCanRestore(container Instance, sourceContainer Instance) error {
+func (s *storageCephFs) ContainerCanRestore(container instance.Instance, sourceContainer instance.Instance) error {
 	return fmt.Errorf("CEPHFS cannot be used for containers")
 }
 
-func (s *storageCephFs) ContainerDelete(container Instance) error {
+func (s *storageCephFs) ContainerDelete(container instance.Instance) error {
 	return fmt.Errorf("CEPHFS cannot be used for containers")
 }
 
-func (s *storageCephFs) ContainerCopy(target Instance, source Instance, containerOnly bool) error {
+func (s *storageCephFs) ContainerCopy(target instance.Instance, source instance.Instance, containerOnly bool) error {
 	return fmt.Errorf("CEPHFS cannot be used for containers")
 }
 
-func (s *storageCephFs) ContainerRefresh(target Instance, source Instance, snapshots []Instance) error {
+func (s *storageCephFs) ContainerRefresh(target instance.Instance, source instance.Instance, snapshots []instance.Instance) error {
 	return fmt.Errorf("CEPHFS cannot be used for containers")
 }
 
-func (s *storageCephFs) ContainerMount(c Instance) (bool, error) {
+func (s *storageCephFs) ContainerMount(c instance.Instance) (bool, error) {
 	return false, fmt.Errorf("CEPHFS cannot be used for containers")
 }
 
-func (s *storageCephFs) ContainerUmount(c Instance, path string) (bool, error) {
+func (s *storageCephFs) ContainerUmount(c instance.Instance, path string) (bool, error) {
 	return false, fmt.Errorf("CEPHFS cannot be used for containers")
 }
 
-func (s *storageCephFs) ContainerRename(container Instance, newName string) error {
+func (s *storageCephFs) ContainerRename(container instance.Instance, newName string) error {
 	return fmt.Errorf("CEPHFS cannot be used for containers")
 }
 
-func (s *storageCephFs) ContainerRestore(container Instance, sourceContainer Instance) error {
+func (s *storageCephFs) ContainerRestore(container instance.Instance, sourceContainer instance.Instance) error {
 	return fmt.Errorf("CEPHFS cannot be used for containers")
 }
 
-func (s *storageCephFs) ContainerGetUsage(c Instance) (int64, error) {
+func (s *storageCephFs) ContainerGetUsage(c instance.Instance) (int64, error) {
 	return -1, fmt.Errorf("CEPHFS cannot be used for containers")
 }
 
-func (s *storageCephFs) ContainerSnapshotCreate(snapshotContainer Instance, sourceContainer Instance) error {
+func (s *storageCephFs) ContainerSnapshotCreate(snapshotContainer instance.Instance, sourceContainer instance.Instance) error {
 	return fmt.Errorf("CEPHFS cannot be used for containers")
 }
 
-func (s *storageCephFs) ContainerSnapshotCreateEmpty(snapshotContainer Instance) error {
+func (s *storageCephFs) ContainerSnapshotCreateEmpty(snapshotContainer instance.Instance) error {
 	return fmt.Errorf("CEPHFS cannot be used for containers")
 }
 
-func (s *storageCephFs) ContainerSnapshotDelete(snapshotContainer Instance) error {
+func (s *storageCephFs) ContainerSnapshotDelete(snapshotContainer instance.Instance) error {
 	return fmt.Errorf("CEPHFS cannot be used for containers")
 }
 
-func (s *storageCephFs) ContainerSnapshotRename(snapshotContainer Instance, newName string) error {
+func (s *storageCephFs) ContainerSnapshotRename(snapshotContainer instance.Instance, newName string) error {
 	return fmt.Errorf("CEPHFS cannot be used for containers")
 }
 
-func (s *storageCephFs) ContainerSnapshotStart(container Instance) (bool, error) {
+func (s *storageCephFs) ContainerSnapshotStart(container instance.Instance) (bool, error) {
 	return false, fmt.Errorf("CEPHFS cannot be used for containers")
 }
 
-func (s *storageCephFs) ContainerSnapshotStop(container Instance) (bool, error) {
+func (s *storageCephFs) ContainerSnapshotStop(container instance.Instance) (bool, error) {
 	return false, fmt.Errorf("CEPHFS cannot be used for containers")
 }
 
-func (s *storageCephFs) ContainerBackupCreate(path string, backup backup.Backup, source Instance) error {
+func (s *storageCephFs) ContainerBackupCreate(path string, backup backup.Backup, source instance.Instance) error {
 	return fmt.Errorf("CEPHFS cannot be used for containers")
 }
 
diff --git a/lxd/storage_dir.go b/lxd/storage_dir.go
index 71073bb63d..91cb164f98 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"
 	"github.com/lxc/lxd/lxd/instance/instancetype"
 	"github.com/lxc/lxd/lxd/migration"
 	"github.com/lxc/lxd/lxd/operations"
@@ -491,13 +492,13 @@ func (s *storageDir) StoragePoolVolumeRename(newName string) error {
 		storagePoolVolumeTypeCustom, s.poolID)
 }
 
-func (s *storageDir) ContainerStorageReady(container Instance) bool {
+func (s *storageDir) ContainerStorageReady(container instance.Instance) bool {
 	containerMntPoint := driver.GetContainerMountPoint(container.Project(), s.pool.Name, container.Name())
 	ok, _ := shared.PathIsEmpty(containerMntPoint)
 	return !ok
 }
 
-func (s *storageDir) ContainerCreate(container Instance) error {
+func (s *storageDir) ContainerCreate(container instance.Instance) error {
 	logger.Debugf("Creating empty DIR storage volume for container \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name)
 
 	_, err := s.StoragePoolMount()
@@ -539,7 +540,7 @@ func (s *storageDir) ContainerCreate(container Instance) error {
 	return nil
 }
 
-func (s *storageDir) ContainerCreateFromImage(container Instance, imageFingerprint string, tracker *ioprogress.ProgressTracker) error {
+func (s *storageDir) ContainerCreateFromImage(container instance.Instance, imageFingerprint string, tracker *ioprogress.ProgressTracker) error {
 	logger.Debugf("Creating DIR storage volume for container \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name)
 
 	_, err := s.StoragePoolMount()
@@ -589,7 +590,7 @@ func (s *storageDir) ContainerCreateFromImage(container Instance, imageFingerpri
 	return nil
 }
 
-func (s *storageDir) ContainerDelete(container Instance) error {
+func (s *storageDir) ContainerDelete(container instance.Instance) error {
 	logger.Debugf("Deleting DIR storage volume for container \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name)
 
 	source := s.pool.Config["source"]
@@ -651,9 +652,20 @@ func (s *storageDir) ContainerDelete(container Instance) error {
 	return nil
 }
 
-func (s *storageDir) copyContainer(target Instance, source Instance) error {
-	_, sourcePool, _ := source.Storage().GetContainerPoolInfo()
-	_, targetPool, _ := target.Storage().GetContainerPoolInfo()
+func (s *storageDir) copyContainer(target instance.Instance, source instance.Instance) error {
+	if source.Type() != instancetype.Container {
+		return fmt.Errorf("Source Instance type must be container")
+	}
+
+	if target.Type() != instancetype.Container {
+		return fmt.Errorf("Target Instance type must be container")
+	}
+
+	srcCt := source.(*containerLXC)
+	targetCt := target.(*containerLXC)
+
+	_, sourcePool, _ := srcCt.Storage().GetContainerPoolInfo()
+	_, targetPool, _ := targetCt.Storage().GetContainerPoolInfo()
 	sourceContainerMntPoint := driver.GetContainerMountPoint(source.Project(), sourcePool, source.Name())
 	if source.IsSnapshot() {
 		sourceContainerMntPoint = driver.GetSnapshotMountPoint(source.Project(), sourcePool, source.Name())
@@ -684,7 +696,7 @@ func (s *storageDir) copyContainer(target Instance, source Instance) error {
 	return nil
 }
 
-func (s *storageDir) copySnapshot(target Instance, targetPool string, source Instance, sourcePool string) error {
+func (s *storageDir) copySnapshot(target instance.Instance, targetPool string, source instance.Instance, sourcePool string) error {
 	sourceName := source.Name()
 	targetName := target.Name()
 	sourceContainerMntPoint := driver.GetSnapshotMountPoint(source.Project(), sourcePool, sourceName)
@@ -708,7 +720,7 @@ func (s *storageDir) copySnapshot(target Instance, targetPool string, source Ins
 	return nil
 }
 
-func (s *storageDir) ContainerCopy(target Instance, source Instance, containerOnly bool) error {
+func (s *storageDir) ContainerCopy(target instance.Instance, source instance.Instance, containerOnly bool) error {
 	logger.Debugf("Copying DIR container storage %s to %s", source.Name(), target.Name())
 
 	err := s.doContainerCopy(target, source, containerOnly, false, nil)
@@ -720,7 +732,7 @@ func (s *storageDir) ContainerCopy(target Instance, source Instance, containerOn
 	return nil
 }
 
-func (s *storageDir) doContainerCopy(target Instance, source Instance, containerOnly bool, refresh bool, refreshSnapshots []Instance) error {
+func (s *storageDir) doContainerCopy(target instance.Instance, source instance.Instance, containerOnly bool, refresh bool, refreshSnapshots []instance.Instance) error {
 	_, err := s.StoragePoolMount()
 	if err != nil {
 		return err
@@ -770,7 +782,7 @@ func (s *storageDir) doContainerCopy(target Instance, source Instance, container
 		return nil
 	}
 
-	var snapshots []Instance
+	var snapshots []instance.Instance
 
 	if refresh {
 		snapshots = refreshSnapshots
@@ -807,7 +819,7 @@ func (s *storageDir) doContainerCopy(target Instance, source Instance, container
 	return nil
 }
 
-func (s *storageDir) ContainerRefresh(target Instance, source Instance, snapshots []Instance) error {
+func (s *storageDir) ContainerRefresh(target instance.Instance, source instance.Instance, snapshots []instance.Instance) error {
 	logger.Debugf("Refreshing DIR container storage for %s from %s", target.Name(), source.Name())
 
 	err := s.doContainerCopy(target, source, len(snapshots) == 0, true, snapshots)
@@ -819,15 +831,15 @@ func (s *storageDir) ContainerRefresh(target Instance, source Instance, snapshot
 	return nil
 }
 
-func (s *storageDir) ContainerMount(c Instance) (bool, error) {
+func (s *storageDir) ContainerMount(c instance.Instance) (bool, error) {
 	return s.StoragePoolMount()
 }
 
-func (s *storageDir) ContainerUmount(c Instance, path string) (bool, error) {
+func (s *storageDir) ContainerUmount(c instance.Instance, path string) (bool, error) {
 	return true, nil
 }
 
-func (s *storageDir) ContainerRename(container Instance, newName string) error {
+func (s *storageDir) ContainerRename(container instance.Instance, newName string) error {
 	logger.Debugf("Renaming DIR storage volume for container \"%s\" from %s to %s", s.volume.Name, s.volume.Name, newName)
 
 	_, err := s.StoragePoolMount()
@@ -882,7 +894,7 @@ func (s *storageDir) ContainerRename(container Instance, newName string) error {
 	return nil
 }
 
-func (s *storageDir) ContainerRestore(container Instance, sourceContainer Instance) error {
+func (s *storageDir) ContainerRestore(container instance.Instance, sourceContainer instance.Instance) error {
 	logger.Debugf("Restoring DIR storage volume for container \"%s\" from %s to %s", s.volume.Name, sourceContainer.Name(), container.Name())
 
 	_, err := s.StoragePoolMount()
@@ -904,7 +916,7 @@ func (s *storageDir) ContainerRestore(container Instance, sourceContainer Instan
 	return nil
 }
 
-func (s *storageDir) ContainerGetUsage(c Instance) (int64, error) {
+func (s *storageDir) ContainerGetUsage(c instance.Instance) (int64, error) {
 	path := driver.GetContainerMountPoint(c.Project(), s.pool.Name, c.Name())
 
 	ok, err := quota.Supported(path)
@@ -921,7 +933,7 @@ func (s *storageDir) ContainerGetUsage(c Instance) (int64, error) {
 	return size, nil
 }
 
-func (s *storageDir) ContainerSnapshotCreate(snapshotContainer Instance, sourceContainer Instance) error {
+func (s *storageDir) ContainerSnapshotCreate(snapshotContainer instance.Instance, sourceContainer instance.Instance) error {
 	logger.Debugf("Creating DIR storage volume for snapshot \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name)
 
 	_, err := s.StoragePoolMount()
@@ -937,7 +949,7 @@ func (s *storageDir) ContainerSnapshotCreate(snapshotContainer Instance, sourceC
 		return err
 	}
 
-	rsync := func(snapshotContainer Instance, oldPath string, newPath string, bwlimit string) error {
+	rsync := func(snapshotContainer instance.Instance, oldPath string, newPath string, bwlimit string) error {
 		output, err := rsync.LocalCopy(oldPath, newPath, bwlimit, true)
 		if err != nil {
 			s.ContainerDelete(snapshotContainer)
@@ -954,7 +966,13 @@ func (s *storageDir) ContainerSnapshotCreate(snapshotContainer Instance, sourceC
 		defer sourceContainer.StorageStop()
 	}
 
-	_, sourcePool, _ := sourceContainer.Storage().GetContainerPoolInfo()
+	if sourceContainer.Type() != instancetype.Container {
+		return fmt.Errorf("Source Instance type must be container")
+	}
+
+	srcCt := sourceContainer.(*containerLXC)
+
+	_, sourcePool, _ := srcCt.Storage().GetContainerPoolInfo()
 	sourceContainerName := sourceContainer.Name()
 	sourceContainerMntPoint := driver.GetContainerMountPoint(sourceContainer.Project(), sourcePool, sourceContainerName)
 	bwlimit := s.pool.Config["rsync.bwlimit"]
@@ -998,7 +1016,7 @@ onSuccess:
 	return nil
 }
 
-func (s *storageDir) ContainerSnapshotCreateEmpty(snapshotContainer Instance) error {
+func (s *storageDir) ContainerSnapshotCreateEmpty(snapshotContainer instance.Instance) error {
 	logger.Debugf("Creating empty DIR storage volume for snapshot \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name)
 
 	_, err := s.StoragePoolMount()
@@ -1072,7 +1090,7 @@ func dirSnapshotDeleteInternal(projectName, poolName string, snapshotName string
 	return nil
 }
 
-func (s *storageDir) ContainerSnapshotDelete(snapshotContainer Instance) error {
+func (s *storageDir) ContainerSnapshotDelete(snapshotContainer instance.Instance) error {
 	logger.Debugf("Deleting DIR storage volume for snapshot \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name)
 
 	_, err := s.StoragePoolMount()
@@ -1095,7 +1113,7 @@ func (s *storageDir) ContainerSnapshotDelete(snapshotContainer Instance) error {
 	return nil
 }
 
-func (s *storageDir) ContainerSnapshotRename(snapshotContainer Instance, newName string) error {
+func (s *storageDir) ContainerSnapshotRename(snapshotContainer instance.Instance, newName string) error {
 	logger.Debugf("Renaming DIR storage volume for snapshot \"%s\" from %s to %s", s.volume.Name, s.volume.Name, newName)
 
 	_, err := s.StoragePoolMount()
@@ -1116,15 +1134,15 @@ func (s *storageDir) ContainerSnapshotRename(snapshotContainer Instance, newName
 	return nil
 }
 
-func (s *storageDir) ContainerSnapshotStart(container Instance) (bool, error) {
+func (s *storageDir) ContainerSnapshotStart(container instance.Instance) (bool, error) {
 	return s.StoragePoolMount()
 }
 
-func (s *storageDir) ContainerSnapshotStop(container Instance) (bool, error) {
+func (s *storageDir) ContainerSnapshotStop(container instance.Instance) (bool, error) {
 	return true, nil
 }
 
-func (s *storageDir) ContainerBackupCreate(path string, backup backup.Backup, source Instance) error {
+func (s *storageDir) ContainerBackupCreate(path string, backup backup.Backup, source instance.Instance) error {
 	// Prepare for rsync
 	rsync := func(oldPath string, newPath string, bwlimit string) error {
 		output, err := rsync.LocalCopy(oldPath, newPath, bwlimit, true)
diff --git a/lxd/storage_lvm.go b/lxd/storage_lvm.go
index 2f0166193d..a49fbac4c4 100644
--- a/lxd/storage_lvm.go
+++ b/lxd/storage_lvm.go
@@ -13,6 +13,8 @@ import (
 	"github.com/pkg/errors"
 
 	"github.com/lxc/lxd/lxd/backup"
+	"github.com/lxc/lxd/lxd/instance"
+	"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"
@@ -923,7 +925,7 @@ func (s *storageLvm) StoragePoolVolumeRename(newName string) error {
 		storagePoolVolumeTypeCustom, s.poolID)
 }
 
-func (s *storageLvm) ContainerStorageReady(container Instance) bool {
+func (s *storageLvm) ContainerStorageReady(container instance.Instance) bool {
 	containerLvmName := containerNameToLVName(container.Name())
 	poolName := s.getOnDiskPoolName()
 	containerLvmPath := getLvmDevPath(container.Project(), poolName, storagePoolVolumeAPIEndpointContainers, containerLvmName)
@@ -931,7 +933,7 @@ func (s *storageLvm) ContainerStorageReady(container Instance) bool {
 	return ok
 }
 
-func (s *storageLvm) ContainerCreate(container Instance) error {
+func (s *storageLvm) ContainerCreate(container instance.Instance) error {
 	logger.Debugf("Creating empty LVM storage volume for container \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name)
 
 	tryUndo := true
@@ -995,7 +997,7 @@ func (s *storageLvm) ContainerCreate(container Instance) error {
 	return nil
 }
 
-func (s *storageLvm) ContainerCreateFromImage(container Instance, fingerprint string, tracker *ioprogress.ProgressTracker) error {
+func (s *storageLvm) ContainerCreateFromImage(container instance.Instance, fingerprint string, tracker *ioprogress.ProgressTracker) error {
 	logger.Debugf("Creating LVM storage volume for container \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name)
 
 	tryUndo := true
@@ -1110,7 +1112,7 @@ func lvmContainerDeleteInternal(projectName, poolName string, ctName string, isS
 	return nil
 }
 
-func (s *storageLvm) ContainerDelete(container Instance) error {
+func (s *storageLvm) ContainerDelete(container instance.Instance) error {
 	logger.Debugf("Deleting LVM storage volume for container \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name)
 
 	containerName := container.Name()
@@ -1124,7 +1126,7 @@ func (s *storageLvm) ContainerDelete(container Instance) error {
 	return nil
 }
 
-func (s *storageLvm) ContainerCopy(target Instance, source Instance, containerOnly bool) error {
+func (s *storageLvm) ContainerCopy(target instance.Instance, source instance.Instance, containerOnly bool) error {
 	logger.Debugf("Copying LVM container storage for container %s to %s", source.Name(), target.Name())
 
 	err := s.doContainerCopy(target, source, containerOnly, false, nil)
@@ -1136,7 +1138,7 @@ func (s *storageLvm) ContainerCopy(target Instance, source Instance, containerOn
 	return nil
 }
 
-func (s *storageLvm) doContainerCopy(target Instance, source Instance, containerOnly bool, refresh bool, refreshSnapshots []Instance) error {
+func (s *storageLvm) doContainerCopy(target instance.Instance, source instance.Instance, containerOnly bool, refresh bool, refreshSnapshots []instance.Instance) error {
 	ourStart, err := source.StorageStart()
 	if err != nil {
 		return err
@@ -1180,7 +1182,7 @@ func (s *storageLvm) doContainerCopy(target Instance, source Instance, container
 		return nil
 	}
 
-	var snapshots []Instance
+	var snapshots []instance.Instance
 
 	if refresh {
 		snapshots = refreshSnapshots
@@ -1222,7 +1224,7 @@ func (s *storageLvm) doContainerCopy(target Instance, source Instance, container
 	return nil
 }
 
-func (s *storageLvm) ContainerRefresh(target Instance, source Instance, snapshots []Instance) error {
+func (s *storageLvm) ContainerRefresh(target instance.Instance, source instance.Instance, snapshots []instance.Instance) error {
 	logger.Debugf("Refreshing LVM container storage for %s from %s", target.Name(), source.Name())
 
 	err := s.doContainerCopy(target, source, len(snapshots) == 0, true, snapshots)
@@ -1234,7 +1236,7 @@ func (s *storageLvm) ContainerRefresh(target Instance, source Instance, snapshot
 	return nil
 }
 
-func (s *storageLvm) ContainerMount(c Instance) (bool, error) {
+func (s *storageLvm) ContainerMount(c instance.Instance) (bool, error) {
 	return s.doContainerMount(c.Project(), c.Name(), false)
 }
 
@@ -1295,7 +1297,7 @@ func (s *storageLvm) doContainerMount(project, name string, snap bool) (bool, er
 	return ourMount, nil
 }
 
-func (s *storageLvm) ContainerUmount(c Instance, path string) (bool, error) {
+func (s *storageLvm) ContainerUmount(c instance.Instance, path string) (bool, error) {
 	return s.umount(c.Project(), c.Name(), path)
 }
 
@@ -1343,7 +1345,7 @@ func (s *storageLvm) umount(project, name string, path string) (bool, error) {
 	return ourUmount, nil
 }
 
-func (s *storageLvm) ContainerRename(container Instance, newContainerName string) error {
+func (s *storageLvm) ContainerRename(container instance.Instance, newContainerName string) error {
 	logger.Debugf("Renaming LVM storage volume for container \"%s\" from %s to %s", s.volume.Name, s.volume.Name, newContainerName)
 
 	tryUndo := true
@@ -1424,10 +1426,21 @@ func (s *storageLvm) ContainerRename(container Instance, newContainerName string
 	return nil
 }
 
-func (s *storageLvm) ContainerRestore(target Instance, source Instance) error {
+func (s *storageLvm) ContainerRestore(target instance.Instance, source instance.Instance) error {
 	logger.Debugf("Restoring LVM storage volume for container \"%s\" from %s to %s", s.volume.Name, source.Name(), target.Name())
 
-	_, sourcePool, _ := source.Storage().GetContainerPoolInfo()
+	if source.Type() != instancetype.Container {
+		return fmt.Errorf("Source Instance type must be container")
+	}
+
+	if target.Type() != instancetype.Container {
+		return fmt.Errorf("Target Instance type must be container")
+	}
+
+	srcCt := source.(*containerLXC)
+	targetCt := target.(*containerLXC)
+
+	_, sourcePool, _ := srcCt.Storage().GetContainerPoolInfo()
 	if s.pool.Name != sourcePool {
 		return fmt.Errorf("containers must be on the same pool to be restored")
 	}
@@ -1439,12 +1452,12 @@ func (s *storageLvm) ContainerRestore(target Instance, source Instance) error {
 	targetLvmName := containerNameToLVName(targetName)
 	targetPath := target.Path()
 	if s.useThinpool {
-		ourUmount, err := target.Storage().ContainerUmount(target, targetPath)
+		ourUmount, err := targetCt.Storage().ContainerUmount(target, targetPath)
 		if err != nil {
 			return err
 		}
 		if ourUmount {
-			defer target.Storage().ContainerMount(target)
+			defer targetCt.Storage().ContainerMount(target)
 		}
 
 		poolName := s.getOnDiskPoolName()
@@ -1503,11 +1516,11 @@ func (s *storageLvm) ContainerRestore(target Instance, source Instance) error {
 	return nil
 }
 
-func (s *storageLvm) ContainerGetUsage(container Instance) (int64, error) {
+func (s *storageLvm) ContainerGetUsage(container instance.Instance) (int64, error) {
 	return -1, fmt.Errorf("the LVM container backend doesn't support quotas")
 }
 
-func (s *storageLvm) ContainerSnapshotCreate(snapshotContainer Instance, sourceContainer Instance) error {
+func (s *storageLvm) ContainerSnapshotCreate(snapshotContainer instance.Instance, sourceContainer instance.Instance) error {
 	logger.Debugf("Creating LVM storage volume for snapshot \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name)
 
 	err := s.createSnapshotContainer(snapshotContainer, sourceContainer, true)
@@ -1519,7 +1532,7 @@ func (s *storageLvm) ContainerSnapshotCreate(snapshotContainer Instance, sourceC
 	return nil
 }
 
-func (s *storageLvm) ContainerSnapshotDelete(snapshotContainer Instance) error {
+func (s *storageLvm) ContainerSnapshotDelete(snapshotContainer instance.Instance) error {
 	logger.Debugf("Deleting LVM storage volume for snapshot \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name)
 
 	err := s.ContainerDelete(snapshotContainer)
@@ -1531,7 +1544,7 @@ func (s *storageLvm) ContainerSnapshotDelete(snapshotContainer Instance) error {
 	return nil
 }
 
-func (s *storageLvm) ContainerSnapshotRename(snapshotContainer Instance, newContainerName string) error {
+func (s *storageLvm) ContainerSnapshotRename(snapshotContainer instance.Instance, newContainerName string) error {
 	logger.Debugf("Renaming LVM storage volume for snapshot \"%s\" from %s to %s", s.volume.Name, s.volume.Name, newContainerName)
 
 	tryUndo := true
@@ -1563,7 +1576,7 @@ func (s *storageLvm) ContainerSnapshotRename(snapshotContainer Instance, newCont
 	return nil
 }
 
-func (s *storageLvm) ContainerSnapshotStart(container Instance) (bool, error) {
+func (s *storageLvm) ContainerSnapshotStart(container instance.Instance) (bool, error) {
 	logger.Debugf(`Initializing LVM storage volume for snapshot "%s" on storage pool "%s"`, s.volume.Name, s.pool.Name)
 
 	poolName := s.getOnDiskPoolName()
@@ -1613,7 +1626,7 @@ func (s *storageLvm) ContainerSnapshotStart(container Instance) (bool, error) {
 	return true, nil
 }
 
-func (s *storageLvm) ContainerSnapshotStop(container Instance) (bool, error) {
+func (s *storageLvm) ContainerSnapshotStop(container instance.Instance) (bool, error) {
 	logger.Debugf("Stopping LVM storage volume for snapshot \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name)
 
 	containerName := container.Name()
@@ -1652,7 +1665,7 @@ func (s *storageLvm) ContainerSnapshotStop(container Instance) (bool, error) {
 	return true, nil
 }
 
-func (s *storageLvm) ContainerSnapshotCreateEmpty(snapshotContainer Instance) error {
+func (s *storageLvm) ContainerSnapshotCreateEmpty(snapshotContainer instance.Instance) error {
 	logger.Debugf("Creating empty LVM storage volume for snapshot \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name)
 
 	err := s.ContainerCreate(snapshotContainer)
@@ -1664,7 +1677,7 @@ func (s *storageLvm) ContainerSnapshotCreateEmpty(snapshotContainer Instance) er
 	return nil
 }
 
-func (s *storageLvm) ContainerBackupCreate(path string, backup backup.Backup, source Instance) error {
+func (s *storageLvm) ContainerBackupCreate(path string, backup backup.Backup, source instance.Instance) error {
 	poolName := s.getOnDiskPoolName()
 
 	// Prepare for rsync
diff --git a/lxd/storage_lvm_utils.go b/lxd/storage_lvm_utils.go
index 35b6333f7c..4362f09878 100644
--- a/lxd/storage_lvm_utils.go
+++ b/lxd/storage_lvm_utils.go
@@ -11,6 +11,7 @@ import (
 	"github.com/pkg/errors"
 
 	"github.com/lxc/lxd/lxd/db"
+	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/instance/instancetype"
 	"github.com/lxc/lxd/lxd/project"
 	"github.com/lxc/lxd/lxd/rsync"
@@ -257,7 +258,7 @@ func (s *storageLvm) createSnapshotLV(project, vgName string, origLvName string,
 	return targetLvmVolumePath, nil
 }
 
-func (s *storageLvm) createSnapshotContainer(snapshotContainer Instance, sourceContainer Instance, readonly bool) error {
+func (s *storageLvm) createSnapshotContainer(snapshotContainer instance.Instance, sourceContainer instance.Instance, readonly bool) error {
 	tryUndo := true
 
 	sourceContainerName := sourceContainer.Name()
@@ -304,7 +305,7 @@ func (s *storageLvm) createSnapshotContainer(snapshotContainer Instance, sourceC
 }
 
 // Copy a container on a storage pool that does use a thinpool.
-func (s *storageLvm) copyContainerThinpool(target Instance, source Instance, readonly bool) error {
+func (s *storageLvm) copyContainerThinpool(target instance.Instance, source instance.Instance, readonly bool) error {
 	err := s.createSnapshotContainer(target, source, readonly)
 	if err != nil {
 		logger.Errorf("Error creating snapshot LV for copy: %s", err)
@@ -342,7 +343,7 @@ func (s *storageLvm) copyContainerThinpool(target Instance, source Instance, rea
 	return nil
 }
 
-func (s *storageLvm) copySnapshot(target Instance, source Instance, refresh bool) error {
+func (s *storageLvm) copySnapshot(target instance.Instance, source instance.Instance, refresh bool) error {
 	sourcePool, err := source.StoragePool()
 	if err != nil {
 		return err
@@ -371,7 +372,7 @@ func (s *storageLvm) copySnapshot(target Instance, source Instance, refresh bool
 }
 
 // Copy a container on a storage pool that does not use a thinpool.
-func (s *storageLvm) copyContainerLv(target Instance, source Instance, readonly bool, refresh bool) error {
+func (s *storageLvm) copyContainerLv(target instance.Instance, source instance.Instance, readonly bool, refresh bool) error {
 	exists, err := storageLVExists(getLvmDevPath(target.Project(), s.getOnDiskPoolName(),
 		storagePoolVolumeAPIEndpointContainers, containerNameToLVName(target.Name())))
 	if err != nil {
@@ -446,7 +447,7 @@ func (s *storageLvm) copyContainerLv(target Instance, source Instance, readonly
 }
 
 // Copy an lvm container.
-func (s *storageLvm) copyContainer(target Instance, source Instance, refresh bool) error {
+func (s *storageLvm) copyContainer(target instance.Instance, source instance.Instance, refresh bool) error {
 	targetPool, err := target.StoragePool()
 	if err != nil {
 		return err
@@ -484,7 +485,7 @@ func (s *storageLvm) copyContainer(target Instance, source Instance, refresh boo
 	return nil
 }
 
-func (s *storageLvm) containerCreateFromImageLv(c Instance, fp string) error {
+func (s *storageLvm) containerCreateFromImageLv(c instance.Instance, fp string) error {
 	containerName := c.Name()
 
 	err := s.ContainerCreate(c)
@@ -516,7 +517,7 @@ func (s *storageLvm) containerCreateFromImageLv(c Instance, fp string) error {
 	return nil
 }
 
-func (s *storageLvm) containerCreateFromImageThinLv(c Instance, fp string) error {
+func (s *storageLvm) containerCreateFromImageThinLv(c instance.Instance, fp string) error {
 	poolName := s.getOnDiskPoolName()
 	// Check if the image already exists.
 	imageLvmDevPath := getLvmDevPath("default", poolName, storagePoolVolumeAPIEndpointImages, fp)
diff --git a/lxd/storage_migration.go b/lxd/storage_migration.go
index 6011f304ce..d8ef5561d9 100644
--- a/lxd/storage_migration.go
+++ b/lxd/storage_migration.go
@@ -8,6 +8,7 @@ import (
 
 	"github.com/lxc/lxd/lxd/db"
 	deviceConfig "github.com/lxc/lxd/lxd/device/config"
+	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/instance/instancetype"
 	"github.com/lxc/lxd/lxd/migration"
 	"github.com/lxc/lxd/lxd/operations"
@@ -43,8 +44,8 @@ type MigrationStorageSourceDriver interface {
 }
 
 type rsyncStorageSourceDriver struct {
-	container     Instance
-	snapshots     []Instance
+	container     instance.Instance
+	snapshots     []instance.Instance
 	rsyncFeatures []string
 }
 
@@ -147,7 +148,7 @@ func rsyncStorageMigrationSource(args MigrationSourceArgs) (MigrationStorageSour
 }
 
 func rsyncRefreshSource(refreshSnapshots []string, args MigrationSourceArgs) (MigrationStorageSourceDriver, error) {
-	var snapshots = []Instance{}
+	var snapshots = []instance.Instance{}
 	if !args.InstanceOnly {
 		allSnapshots, err := args.Instance.Snapshots()
 		if err != nil {
@@ -169,7 +170,7 @@ func rsyncRefreshSource(refreshSnapshots []string, args MigrationSourceArgs) (Mi
 
 func rsyncMigrationSource(args MigrationSourceArgs) (MigrationStorageSourceDriver, error) {
 	var err error
-	var snapshots = []Instance{}
+	var snapshots = []instance.Instance{}
 	if !args.InstanceOnly {
 		snapshots, err = args.Instance.Snapshots()
 		if err != nil {
@@ -311,7 +312,13 @@ func rsyncMigrationSink(conn *websocket.Conn, op *operations.Operation, args Mig
 		return err
 	}
 
-	isDirBackend := args.Instance.Storage().GetStorageType() == storageTypeDir
+	if args.Instance.Type() != instancetype.Container {
+		return fmt.Errorf("Instance type must be container")
+	}
+
+	ct := args.Instance.(*containerLXC)
+
+	isDirBackend := ct.Storage().GetStorageType() == storageTypeDir
 	if isDirBackend {
 		if !args.InstanceOnly {
 			for _, snap := range args.Snapshots {
diff --git a/lxd/storage_migration_btrfs.go b/lxd/storage_migration_btrfs.go
index 96286b1c24..3b95273e70 100644
--- a/lxd/storage_migration_btrfs.go
+++ b/lxd/storage_migration_btrfs.go
@@ -9,6 +9,8 @@ import (
 
 	"github.com/gorilla/websocket"
 
+	"github.com/lxc/lxd/lxd/instance"
+	"github.com/lxc/lxd/lxd/instance/instancetype"
 	"github.com/lxc/lxd/lxd/migration"
 	"github.com/lxc/lxd/lxd/operations"
 	driver "github.com/lxc/lxd/lxd/storage"
@@ -17,8 +19,8 @@ import (
 )
 
 type btrfsMigrationSourceDriver struct {
-	container          Instance
-	snapshots          []Instance
+	container          instance.Instance
+	snapshots          []instance.Instance
 	btrfsSnapshotNames []string
 	btrfs              *storageBtrfs
 	runningSnapName    string
@@ -70,7 +72,13 @@ func (s *btrfsMigrationSourceDriver) send(conn *websocket.Conn, btrfsPath string
 }
 
 func (s *btrfsMigrationSourceDriver) SendWhileRunning(conn *websocket.Conn, op *operations.Operation, bwlimit string, containerOnly bool) error {
-	_, containerPool, _ := s.container.Storage().GetContainerPoolInfo()
+	if s.container.Type() != instancetype.Container {
+		return fmt.Errorf("Instance type must be container")
+	}
+
+	ct := s.container.(*containerLXC)
+
+	_, containerPool, _ := ct.Storage().GetContainerPoolInfo()
 	containerName := s.container.Name()
 	containersPath := driver.GetContainerMountPoint("default", containerPool, "")
 	sourceName := containerName
diff --git a/lxd/storage_migration_ceph.go b/lxd/storage_migration_ceph.go
index 1817bfec07..851697c3e1 100644
--- a/lxd/storage_migration_ceph.go
+++ b/lxd/storage_migration_ceph.go
@@ -9,6 +9,7 @@ import (
 	"github.com/gorilla/websocket"
 	"github.com/pborman/uuid"
 
+	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/migration"
 	"github.com/lxc/lxd/lxd/operations"
 	"github.com/lxc/lxd/lxd/project"
@@ -17,15 +18,15 @@ import (
 )
 
 type rbdMigrationSourceDriver struct {
-	container        Instance
-	snapshots        []Instance
+	container        instance.Instance
+	snapshots        []instance.Instance
 	rbdSnapshotNames []string
 	ceph             *storageCeph
 	runningSnapName  string
 	stoppedSnapName  string
 }
 
-func (s *rbdMigrationSourceDriver) Snapshots() []Instance {
+func (s *rbdMigrationSourceDriver) Snapshots() []instance.Instance {
 	return s.snapshots
 }
 
diff --git a/lxd/storage_migration_zfs.go b/lxd/storage_migration_zfs.go
index 72747a08a4..9568918208 100644
--- a/lxd/storage_migration_zfs.go
+++ b/lxd/storage_migration_zfs.go
@@ -9,6 +9,7 @@ import (
 	"github.com/gorilla/websocket"
 	"github.com/pborman/uuid"
 
+	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/migration"
 	"github.com/lxc/lxd/lxd/operations"
 	"github.com/lxc/lxd/lxd/project"
@@ -17,8 +18,8 @@ import (
 )
 
 type zfsMigrationSourceDriver struct {
-	instance         Instance
-	snapshots        []Instance
+	instance         instance.Instance
+	snapshots        []instance.Instance
 	zfsSnapshotNames []string
 	zfs              *storageZfs
 	runningSnapName  string
diff --git a/lxd/storage_mock.go b/lxd/storage_mock.go
index 7b9c2d1d80..08fee51c8e 100644
--- a/lxd/storage_mock.go
+++ b/lxd/storage_mock.go
@@ -6,6 +6,7 @@ import (
 	"github.com/gorilla/websocket"
 
 	"github.com/lxc/lxd/lxd/backup"
+	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/migration"
 	"github.com/lxc/lxd/lxd/operations"
 	"github.com/lxc/lxd/lxd/state"
@@ -111,73 +112,73 @@ func (s *storageMock) StoragePoolUpdate(writable *api.StoragePoolPut, changedCon
 	return nil
 }
 
-func (s *storageMock) ContainerStorageReady(container Instance) bool {
+func (s *storageMock) ContainerStorageReady(container instance.Instance) bool {
 	return true
 }
 
-func (s *storageMock) ContainerCreate(container Instance) error {
+func (s *storageMock) ContainerCreate(container instance.Instance) error {
 	return nil
 }
 
-func (s *storageMock) ContainerCreateFromImage(container Instance, imageFingerprint string, tracker *ioprogress.ProgressTracker) error {
+func (s *storageMock) ContainerCreateFromImage(container instance.Instance, imageFingerprint string, tracker *ioprogress.ProgressTracker) error {
 	return nil
 }
 
-func (s *storageMock) ContainerDelete(container Instance) error {
+func (s *storageMock) ContainerDelete(container instance.Instance) error {
 	return nil
 }
 
-func (s *storageMock) ContainerCopy(target Instance, source Instance, containerOnly bool) error {
+func (s *storageMock) ContainerCopy(target instance.Instance, source instance.Instance, containerOnly bool) error {
 	return nil
 }
 
-func (s *storageMock) ContainerRefresh(target Instance, source Instance, snapshots []Instance) error {
+func (s *storageMock) ContainerRefresh(target instance.Instance, source instance.Instance, snapshots []instance.Instance) error {
 	return nil
 }
 
-func (s *storageMock) ContainerMount(c Instance) (bool, error) {
+func (s *storageMock) ContainerMount(c instance.Instance) (bool, error) {
 	return true, nil
 }
 
-func (s *storageMock) ContainerUmount(c Instance, path string) (bool, error) {
+func (s *storageMock) ContainerUmount(c instance.Instance, path string) (bool, error) {
 	return true, nil
 }
 
-func (s *storageMock) ContainerRename(container Instance, newName string) error {
+func (s *storageMock) ContainerRename(container instance.Instance, newName string) error {
 	return nil
 }
 
-func (s *storageMock) ContainerRestore(container Instance, sourceContainer Instance) error {
+func (s *storageMock) ContainerRestore(container instance.Instance, sourceContainer instance.Instance) error {
 	return nil
 }
 
-func (s *storageMock) ContainerGetUsage(container Instance) (int64, error) {
+func (s *storageMock) ContainerGetUsage(container instance.Instance) (int64, error) {
 	return 0, nil
 }
-func (s *storageMock) ContainerSnapshotCreate(snapshotContainer Instance, sourceContainer Instance) error {
+func (s *storageMock) ContainerSnapshotCreate(snapshotContainer instance.Instance, sourceContainer instance.Instance) error {
 	return nil
 }
-func (s *storageMock) ContainerSnapshotDelete(snapshotContainer Instance) error {
+func (s *storageMock) ContainerSnapshotDelete(snapshotContainer instance.Instance) error {
 	return nil
 }
 
-func (s *storageMock) ContainerSnapshotRename(snapshotContainer Instance, newName string) error {
+func (s *storageMock) ContainerSnapshotRename(snapshotContainer instance.Instance, newName string) error {
 	return nil
 }
 
-func (s *storageMock) ContainerSnapshotStart(container Instance) (bool, error) {
+func (s *storageMock) ContainerSnapshotStart(container instance.Instance) (bool, error) {
 	return true, nil
 }
 
-func (s *storageMock) ContainerSnapshotStop(container Instance) (bool, error) {
+func (s *storageMock) ContainerSnapshotStop(container instance.Instance) (bool, error) {
 	return true, nil
 }
 
-func (s *storageMock) ContainerSnapshotCreateEmpty(snapshotContainer Instance) error {
+func (s *storageMock) ContainerSnapshotCreateEmpty(snapshotContainer instance.Instance) error {
 	return nil
 }
 
-func (s *storageMock) ContainerBackupCreate(path string, backup backup.Backup, sourceContainer Instance) error {
+func (s *storageMock) ContainerBackupCreate(path string, backup backup.Backup, sourceContainer instance.Instance) error {
 	return nil
 }
 
diff --git a/lxd/storage_zfs.go b/lxd/storage_zfs.go
index be50dabb74..53caec7604 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"
 	"github.com/lxc/lxd/lxd/instance/instancetype"
 	"github.com/lxc/lxd/lxd/migration"
 	"github.com/lxc/lxd/lxd/operations"
@@ -764,11 +765,11 @@ func (s *storageZfs) StoragePoolVolumeRename(newName string) error {
 }
 
 // Things we don't need to care about
-func (s *storageZfs) ContainerMount(c Instance) (bool, error) {
+func (s *storageZfs) ContainerMount(c instance.Instance) (bool, error) {
 	return s.doContainerMount(c.Project(), c.Name(), c.IsPrivileged())
 }
 
-func (s *storageZfs) ContainerUmount(c Instance, path string) (bool, error) {
+func (s *storageZfs) ContainerUmount(c instance.Instance, path string) (bool, error) {
 	logger.Debugf("Unmounting ZFS storage volume for container \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name)
 	name := c.Name()
 
@@ -813,13 +814,13 @@ func (s *storageZfs) ContainerUmount(c Instance, path string) (bool, error) {
 }
 
 // Things we do have to care about
-func (s *storageZfs) ContainerStorageReady(container Instance) bool {
+func (s *storageZfs) ContainerStorageReady(container instance.Instance) bool {
 	volumeName := project.Prefix(container.Project(), container.Name())
 	fs := fmt.Sprintf("containers/%s", volumeName)
 	return zfsFilesystemEntityExists(s.getOnDiskPoolName(), fs)
 }
 
-func (s *storageZfs) ContainerCreate(container Instance) error {
+func (s *storageZfs) ContainerCreate(container instance.Instance) error {
 	err := s.doContainerCreate(container.Project(), container.Name(), container.IsPrivileged())
 	if err != nil {
 		s.doContainerDelete(container.Project(), container.Name())
@@ -842,7 +843,7 @@ func (s *storageZfs) ContainerCreate(container Instance) error {
 	return nil
 }
 
-func (s *storageZfs) ContainerCreateFromImage(container Instance, fingerprint string, tracker *ioprogress.ProgressTracker) error {
+func (s *storageZfs) ContainerCreateFromImage(container instance.Instance, fingerprint string, tracker *ioprogress.ProgressTracker) error {
 	logger.Debugf("Creating ZFS storage volume for container \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name)
 
 	containerPath := container.Path()
@@ -920,7 +921,7 @@ func (s *storageZfs) ContainerCreateFromImage(container Instance, fingerprint st
 	return nil
 }
 
-func (s *storageZfs) ContainerDelete(container Instance) error {
+func (s *storageZfs) ContainerDelete(container instance.Instance) error {
 	err := s.doContainerDelete(container.Project(), container.Name())
 	if err != nil {
 		return err
@@ -929,7 +930,7 @@ func (s *storageZfs) ContainerDelete(container Instance) error {
 	return nil
 }
 
-func (s *storageZfs) copyWithoutSnapshotsSparse(target Instance, source Instance) error {
+func (s *storageZfs) copyWithoutSnapshotsSparse(target instance.Instance, source instance.Instance) error {
 	poolName := s.getOnDiskPoolName()
 
 	sourceContainerName := source.Name()
@@ -1031,7 +1032,7 @@ func (s *storageZfs) copyWithoutSnapshotsSparse(target Instance, source Instance
 	return nil
 }
 
-func (s *storageZfs) copyWithoutSnapshotFull(target Instance, source Instance) error {
+func (s *storageZfs) copyWithoutSnapshotFull(target instance.Instance, source instance.Instance) error {
 	logger.Debugf("Creating full ZFS copy \"%s\" to \"%s\"", source.Name(), target.Name())
 
 	sourceIsSnapshot := source.IsSnapshot()
@@ -1132,7 +1133,7 @@ func (s *storageZfs) copyWithoutSnapshotFull(target Instance, source Instance) e
 	return nil
 }
 
-func (s *storageZfs) copyWithSnapshots(target Instance, source Instance, parentSnapshot string) error {
+func (s *storageZfs) copyWithSnapshots(target instance.Instance, source instance.Instance, parentSnapshot string) error {
 	sourceName := source.Name()
 	targetParentName, targetSnapOnlyName, _ := shared.ContainerGetParentAndSnapshotName(target.Name())
 	containersPath := driver.GetSnapshotMountPoint(target.Project(), s.pool.Name, targetParentName)
@@ -1179,7 +1180,7 @@ func (s *storageZfs) copyWithSnapshots(target Instance, source Instance, parentS
 	return nil
 }
 
-func (s *storageZfs) doCrossPoolContainerCopy(target Instance, source Instance, containerOnly bool, refresh bool, refreshSnapshots []Instance) error {
+func (s *storageZfs) doCrossPoolContainerCopy(target instance.Instance, source instance.Instance, containerOnly bool, refresh bool, refreshSnapshots []instance.Instance) error {
 	sourcePool, err := source.StoragePool()
 	if err != nil {
 		return err
@@ -1204,7 +1205,7 @@ func (s *storageZfs) doCrossPoolContainerCopy(target Instance, source Instance,
 		return err
 	}
 
-	var snapshots []Instance
+	var snapshots []instance.Instance
 
 	if refresh {
 		snapshots = refreshSnapshots
@@ -1257,7 +1258,7 @@ func (s *storageZfs) doCrossPoolContainerCopy(target Instance, source Instance,
 	return nil
 }
 
-func (s *storageZfs) ContainerCopy(target Instance, source Instance, containerOnly bool) error {
+func (s *storageZfs) ContainerCopy(target instance.Instance, source instance.Instance, containerOnly bool) error {
 	logger.Debugf("Copying ZFS container storage %s to %s", source.Name(), target.Name())
 
 	ourStart, err := source.StorageStart()
@@ -1268,8 +1269,19 @@ func (s *storageZfs) ContainerCopy(target Instance, source Instance, containerOn
 		defer source.StorageStop()
 	}
 
-	_, sourcePool, _ := source.Storage().GetContainerPoolInfo()
-	_, targetPool, _ := target.Storage().GetContainerPoolInfo()
+	if source.Type() != instancetype.Container {
+		return fmt.Errorf("Source Instance type must be container")
+	}
+
+	if target.Type() != instancetype.Container {
+		return fmt.Errorf("Target Instance type must be container")
+	}
+
+	srcCt := source.(*containerLXC)
+	targetCt := target.(*containerLXC)
+
+	_, sourcePool, _ := srcCt.Storage().GetContainerPoolInfo()
+	_, targetPool, _ := targetCt.Storage().GetContainerPoolInfo()
 	if sourcePool != targetPool {
 		return s.doCrossPoolContainerCopy(target, source, containerOnly, false, nil)
 	}
@@ -1384,7 +1396,7 @@ func (s *storageZfs) ContainerCopy(target Instance, source Instance, containerOn
 	return nil
 }
 
-func (s *storageZfs) ContainerRefresh(target Instance, source Instance, snapshots []Instance) error {
+func (s *storageZfs) ContainerRefresh(target instance.Instance, source instance.Instance, snapshots []instance.Instance) error {
 	logger.Debugf("Refreshing ZFS container storage for %s from %s", target.Name(), source.Name())
 
 	ourStart, err := source.StorageStart()
@@ -1398,7 +1410,7 @@ func (s *storageZfs) ContainerRefresh(target Instance, source Instance, snapshot
 	return s.doCrossPoolContainerCopy(target, source, len(snapshots) == 0, true, snapshots)
 }
 
-func (s *storageZfs) ContainerRename(container Instance, newName string) error {
+func (s *storageZfs) ContainerRename(container instance.Instance, newName string) error {
 	logger.Debugf("Renaming ZFS storage volume for container \"%s\" from %s to %s", s.volume.Name, s.volume.Name, newName)
 
 	poolName := s.getOnDiskPoolName()
@@ -1482,7 +1494,7 @@ func (s *storageZfs) ContainerRename(container Instance, newName string) error {
 	return nil
 }
 
-func (s *storageZfs) ContainerRestore(target Instance, source Instance) error {
+func (s *storageZfs) ContainerRestore(target instance.Instance, source instance.Instance) error {
 	logger.Debugf("Restoring ZFS storage volume for container \"%s\" from %s to %s", s.volume.Name, source.Name(), target.Name())
 
 	snaps, err := target.Snapshots()
@@ -1546,7 +1558,7 @@ func (s *storageZfs) ContainerRestore(target Instance, source Instance) error {
 	return nil
 }
 
-func (s *storageZfs) ContainerGetUsage(container Instance) (int64, error) {
+func (s *storageZfs) ContainerGetUsage(container instance.Instance) (int64, error) {
 	var err error
 
 	fs := fmt.Sprintf("containers/%s", project.Prefix(container.Project(), container.Name()))
@@ -1625,7 +1637,7 @@ func (s *storageZfs) doContainerSnapshotCreate(projectName, targetName string, s
 	return nil
 }
 
-func (s *storageZfs) ContainerSnapshotCreate(snapshotContainer Instance, sourceContainer Instance) error {
+func (s *storageZfs) ContainerSnapshotCreate(snapshotContainer instance.Instance, sourceContainer instance.Instance) error {
 	err := s.doContainerSnapshotCreate(sourceContainer.Project(), snapshotContainer.Name(), sourceContainer.Name())
 	if err != nil {
 		s.ContainerSnapshotDelete(snapshotContainer)
@@ -1719,7 +1731,7 @@ func zfsSnapshotDeleteInternal(projectName, poolName string, ctName string, onDi
 	return nil
 }
 
-func (s *storageZfs) ContainerSnapshotDelete(snapshotContainer Instance) error {
+func (s *storageZfs) ContainerSnapshotDelete(snapshotContainer instance.Instance) error {
 	logger.Debugf("Deleting ZFS storage volume for snapshot \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name)
 
 	poolName := s.getOnDiskPoolName()
@@ -1733,7 +1745,7 @@ func (s *storageZfs) ContainerSnapshotDelete(snapshotContainer Instance) error {
 	return nil
 }
 
-func (s *storageZfs) ContainerSnapshotRename(snapshotContainer Instance, newName string) error {
+func (s *storageZfs) ContainerSnapshotRename(snapshotContainer instance.Instance, newName string) error {
 	logger.Debugf("Renaming ZFS storage volume for snapshot \"%s\" from %s to %s", s.volume.Name, s.volume.Name, newName)
 
 	oldName := snapshotContainer.Name()
@@ -1798,7 +1810,7 @@ func (s *storageZfs) ContainerSnapshotRename(snapshotContainer Instance, newName
 	return nil
 }
 
-func (s *storageZfs) ContainerSnapshotStart(container Instance) (bool, error) {
+func (s *storageZfs) ContainerSnapshotStart(container instance.Instance) (bool, error) {
 	logger.Debugf("Initializing ZFS storage volume for snapshot \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name)
 
 	cName, sName, _ := shared.ContainerGetParentAndSnapshotName(container.Name())
@@ -1822,7 +1834,7 @@ func (s *storageZfs) ContainerSnapshotStart(container Instance) (bool, error) {
 	return true, nil
 }
 
-func (s *storageZfs) ContainerSnapshotStop(container Instance) (bool, error) {
+func (s *storageZfs) ContainerSnapshotStop(container instance.Instance) (bool, error) {
 	logger.Debugf("Stopping ZFS storage volume for snapshot \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name)
 
 	cName, sName, _ := shared.ContainerGetParentAndSnapshotName(container.Name())
@@ -1837,12 +1849,12 @@ func (s *storageZfs) ContainerSnapshotStop(container Instance) (bool, error) {
 	return true, nil
 }
 
-func (s *storageZfs) ContainerSnapshotCreateEmpty(snapshotContainer Instance) error {
+func (s *storageZfs) ContainerSnapshotCreateEmpty(snapshotContainer instance.Instance) error {
 	/* don't touch the fs yet, as migration will do that for us */
 	return nil
 }
 
-func (s *storageZfs) doContainerOnlyBackup(tmpPath string, backup backup.Backup, source Instance) error {
+func (s *storageZfs) doContainerOnlyBackup(tmpPath string, backup backup.Backup, source instance.Instance) error {
 	sourceIsSnapshot := source.IsSnapshot()
 	poolName := s.getOnDiskPoolName()
 
@@ -1890,7 +1902,7 @@ func (s *storageZfs) doContainerOnlyBackup(tmpPath string, backup backup.Backup,
 	return nil
 }
 
-func (s *storageZfs) doSnapshotBackup(tmpPath string, backup backup.Backup, source Instance, parentSnapshot string) error {
+func (s *storageZfs) doSnapshotBackup(tmpPath string, backup backup.Backup, source instance.Instance, parentSnapshot string) error {
 	sourceName := source.Name()
 	snapshotsPath := fmt.Sprintf("%s/snapshots", tmpPath)
 
@@ -1922,7 +1934,7 @@ func (s *storageZfs) doSnapshotBackup(tmpPath string, backup backup.Backup, sour
 	return zfsSendCmd.Run()
 }
 
-func (s *storageZfs) doContainerBackupCreateOptimized(tmpPath string, backup backup.Backup, source Instance) error {
+func (s *storageZfs) doContainerBackupCreateOptimized(tmpPath string, backup backup.Backup, source instance.Instance) error {
 	// Handle snapshots
 	snapshots, err := source.Snapshots()
 	if err != nil {
@@ -1991,7 +2003,7 @@ func (s *storageZfs) doContainerBackupCreateOptimized(tmpPath string, backup bac
 	return nil
 }
 
-func (s *storageZfs) doContainerBackupCreateVanilla(tmpPath string, backup backup.Backup, source Instance) error {
+func (s *storageZfs) doContainerBackupCreateVanilla(tmpPath string, backup backup.Backup, source instance.Instance) error {
 	// Prepare for rsync
 	rsync := func(oldPath string, newPath string, bwlimit string) error {
 		output, err := rsync.LocalCopy(oldPath, newPath, bwlimit, true)
@@ -2094,7 +2106,7 @@ func (s *storageZfs) doContainerBackupCreateVanilla(tmpPath string, backup backu
 	return nil
 }
 
-func (s *storageZfs) ContainerBackupCreate(path string, backup backup.Backup, source Instance) error {
+func (s *storageZfs) ContainerBackupCreate(path string, backup backup.Backup, source instance.Instance) error {
 	// Generate the actual backup
 	if backup.OptimizedStorage() {
 		err := s.doContainerBackupCreateOptimized(path, backup, source)
@@ -2520,7 +2532,7 @@ func (s *storageZfs) MigrationSource(args MigrationSourceArgs) (MigrationStorage
 
 	driver := zfsMigrationSourceDriver{
 		instance:         args.Instance,
-		snapshots:        []Instance{},
+		snapshots:        []instance.Instance{},
 		zfsSnapshotNames: []string{},
 		zfs:              s,
 		zfsFeatures:      args.ZfsFeatures,

From a8f71ec493ae76d3f44a979757544d560f4e9165 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 20 Nov 2019 14:43:51 +0000
Subject: [PATCH 05/26] lxd/container: Adds operation arg to
 instanceCreateAsCopy

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

diff --git a/lxd/container.go b/lxd/container.go
index 38ddca37e5..c7746434e8 100644
--- a/lxd/container.go
+++ b/lxd/container.go
@@ -580,7 +580,7 @@ func instanceCreateFromImage(d *Daemon, args db.InstanceArgs, hash string, op *o
 	return inst, nil
 }
 
-func instanceCreateAsCopy(s *state.State, args db.InstanceArgs, sourceInst instance.Instance, instanceOnly bool, refresh bool) (instance.Instance, error) {
+func instanceCreateAsCopy(s *state.State, args db.InstanceArgs, sourceInst instance.Instance, instanceOnly bool, refresh bool, op *operations.Operation) (instance.Instance, error) {
 	var inst, revertInst instance.Instance
 	var err error
 

From f7cd6310f4c5e06d5080250c854a121a4550ad9a Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 20 Nov 2019 14:46:25 +0000
Subject: [PATCH 06/26] lxd/containers/post: Passes operation to
 instanceCreateAsCopy

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

diff --git a/lxd/containers_post.go b/lxd/containers_post.go
index 8c89892a15..9e16d77f26 100644
--- a/lxd/containers_post.go
+++ b/lxd/containers_post.go
@@ -605,7 +605,7 @@ func createFromCopy(d *Daemon, project string, req *api.InstancesPost) response.
 
 	run := func(op *operations.Operation) error {
 		instanceOnly := req.Source.InstanceOnly || req.Source.ContainerOnly
-		_, err := instanceCreateAsCopy(d.State(), args, source, instanceOnly, req.Source.Refresh)
+		_, err := instanceCreateAsCopy(d.State(), args, source, instanceOnly, req.Source.Refresh, op)
 		if err != nil {
 			return err
 		}

From 08e56ef6106619d99c056b6a6d06e1bab7d25020 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 19 Nov 2019 12:09:23 +0000
Subject: [PATCH 07/26] lxd/container: Links instanceCreateAsCopy to new
 storage pkg

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

diff --git a/lxd/container.go b/lxd/container.go
index c7746434e8..8ceeb9ddd3 100644
--- a/lxd/container.go
+++ b/lxd/container.go
@@ -705,21 +705,37 @@ func instanceCreateAsCopy(s *state.State, args db.InstanceArgs, sourceInst insta
 	}
 
 	// Now clone or refresh the storage.
-	if inst.Type() != instancetype.Container {
-		return nil, fmt.Errorf("Instance type must be container")
-	}
-
-	ct := inst.(*containerLXC)
-
 	if refresh {
+		if inst.Type() != instancetype.Container {
+			return nil, fmt.Errorf("Instance type must be container")
+		}
+
+		ct := inst.(*containerLXC)
 		err = ct.Storage().ContainerRefresh(inst, sourceInst, snapshots)
 		if err != nil {
 			return nil, err
 		}
 	} else {
-		err = ct.Storage().ContainerCopy(inst, sourceInst, instanceOnly)
-		if err != nil {
-			return nil, err
+		// Check if we can load new storage layer for both target and source pool driver types.
+		pool, err := storagePools.GetPoolByInstance(s, inst)
+		_, srcPoolErr := storagePools.GetPoolByInstance(s, sourceInst)
+		if err != storageDrivers.ErrUnknownDriver && err != storageDrivers.ErrNotImplemented && srcPoolErr != storageDrivers.ErrUnknownDriver && srcPoolErr != storageDrivers.ErrNotImplemented {
+			if err != nil {
+				return nil, errors.Wrap(err, "Load instance storage pool")
+			}
+
+			err = pool.CreateInstanceFromCopy(inst, sourceInst, !instanceOnly, op)
+			if err != nil {
+				return nil, errors.Wrap(err, "Create instance from copy")
+			}
+		} else if inst.Type() == instancetype.Container {
+			ct := inst.(*containerLXC)
+			err = ct.Storage().ContainerCopy(inst, sourceInst, instanceOnly)
+			if err != nil {
+				return nil, err
+			}
+		} else {
+			return nil, fmt.Errorf("Instance type not supported")
 		}
 	}
 

From f094107873cb0f68970572e2ec15b7a016c5cf75 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 20 Nov 2019 14:44:20 +0000
Subject: [PATCH 08/26] lxd/container: source snapshot var naming for clarity

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

diff --git a/lxd/container.go b/lxd/container.go
index 8ceeb9ddd3..5a4a5274d3 100644
--- a/lxd/container.go
+++ b/lxd/container.go
@@ -652,15 +652,15 @@ func instanceCreateAsCopy(s *state.State, args db.InstanceArgs, sourceInst insta
 			}
 		}
 
-		for _, snap := range snapshots {
-			fields := strings.SplitN(snap.Name(), shared.SnapshotDelimiter, 2)
+		for _, srcSnap := range snapshots {
+			fields := strings.SplitN(srcSnap.Name(), shared.SnapshotDelimiter, 2)
 
 			// Ensure that snapshot and parent instance have the
 			// same storage pool in their local root disk device.
 			// If the root disk device for the snapshot comes from a
 			// profile on the new instance as well we don't need to
 			// do anything.
-			snapDevices := snap.LocalDevices()
+			snapDevices := srcSnap.LocalDevices()
 			if snapDevices != nil {
 				snapLocalRootDiskDeviceKey, _, _ := shared.GetRootDiskDevice(snapDevices.CloneNative())
 				if snapLocalRootDiskDeviceKey != "" {
@@ -676,15 +676,15 @@ func instanceCreateAsCopy(s *state.State, args db.InstanceArgs, sourceInst insta
 
 			newSnapName := fmt.Sprintf("%s/%s", inst.Name(), fields[1])
 			snapInstArgs := db.InstanceArgs{
-				Architecture: snap.Architecture(),
-				Config:       snap.LocalConfig(),
+				Architecture: srcSnap.Architecture(),
+				Config:       srcSnap.LocalConfig(),
 				Type:         sourceInst.Type(),
 				Snapshot:     true,
 				Devices:      snapDevices,
-				Description:  snap.Description(),
-				Ephemeral:    snap.IsEphemeral(),
+				Description:  srcSnap.Description(),
+				Ephemeral:    srcSnap.IsEphemeral(),
 				Name:         newSnapName,
-				Profiles:     snap.Profiles(),
+				Profiles:     srcSnap.Profiles(),
 				Project:      args.Project,
 			}
 
@@ -694,8 +694,8 @@ func instanceCreateAsCopy(s *state.State, args db.InstanceArgs, sourceInst insta
 				return nil, err
 			}
 
-			// Restore snapshot creation date.
-			err = s.Cluster.ContainerCreationUpdate(snapInst.ID(), snap.CreationDate())
+			// Set snapshot creation date to that of the source snapshot.
+			err = s.Cluster.InstanceSnapshotCreationUpdate(snapInst.ID(), srcSnap.CreationDate())
 			if err != nil {
 				return nil, err
 			}

From cbc50c684ee3ea864ed79ac86506c3d3341dcff5 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 20 Nov 2019 14:36:25 +0000
Subject: [PATCH 09/26] lxd/storage/interfaces: Exposes ExpandedDevices() on
 Instance interface

Used for accessing the root device config when managing instance storage volumes.

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

diff --git a/lxd/storage/interfaces.go b/lxd/storage/interfaces.go
index b9e26a6305..1412555764 100644
--- a/lxd/storage/interfaces.go
+++ b/lxd/storage/interfaces.go
@@ -3,6 +3,7 @@ package storage
 import (
 	"io"
 
+	deviceConfig "github.com/lxc/lxd/lxd/device/config"
 	"github.com/lxc/lxd/lxd/instance/instancetype"
 	"github.com/lxc/lxd/lxd/migration"
 	"github.com/lxc/lxd/lxd/operations"
@@ -20,6 +21,7 @@ type Instance interface {
 	IsRunning() bool
 	IsSnapshot() bool
 	DeferTemplateApply(trigger string) error
+	ExpandedDevices() deviceConfig.Devices
 }
 
 // Pool represents a LXD storage pool.

From b640f42ce030a96a0b18261bd5a954ade3555fba Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 20 Nov 2019 14:39:09 +0000
Subject: [PATCH 10/26] lxd/storage/interfaces: Updates Instance migration
 signatures

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

diff --git a/lxd/storage/interfaces.go b/lxd/storage/interfaces.go
index 1412555764..1c4adba620 100644
--- a/lxd/storage/interfaces.go
+++ b/lxd/storage/interfaces.go
@@ -45,11 +45,11 @@ type Pool interface {
 	CreateInstanceFromBackup(i Instance, sourcePath string, op *operations.Operation) error
 	CreateInstanceFromCopy(i Instance, src Instance, snapshots bool, op *operations.Operation) error
 	CreateInstanceFromImage(i Instance, fingerprint string, op *operations.Operation) error
-	CreateInstanceFromMigration(i Instance, conn io.ReadWriteCloser, args migration.SinkArgs, op *operations.Operation) error
+	CreateInstanceFromMigration(i Instance, conn io.ReadWriteCloser, args migration.VolumeTargetArgs, op *operations.Operation) error
 	RenameInstance(i Instance, newName string, op *operations.Operation) error
 	DeleteInstance(i Instance, op *operations.Operation) error
 
-	MigrateInstance(i Instance, snapshots bool, args migration.SourceArgs) (migration.StorageSourceDriver, error)
+	MigrateInstance(i Instance, conn io.ReadWriteCloser, args migration.VolumeSourceArgs, op *operations.Operation) error
 	RefreshInstance(i Instance, src Instance, snapshots bool, op *operations.Operation) error
 	BackupInstance(i Instance, targetPath string, optimized bool, snapshots bool, op *operations.Operation) error
 

From 3cce8639bea9989a2e32d56697068ff1b5ea2874 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 20 Nov 2019 14:40:18 +0000
Subject: [PATCH 11/26] lxd/storage/interfaces: Changes i arg var to inst to
 represent Instance

We don't use "i" for instance variables as its confused with the commonly used "i" for iterator.

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

diff --git a/lxd/storage/interfaces.go b/lxd/storage/interfaces.go
index 1c4adba620..7632620464 100644
--- a/lxd/storage/interfaces.go
+++ b/lxd/storage/interfaces.go
@@ -41,32 +41,32 @@ type Pool interface {
 	Unmount() (bool, error)
 
 	// Instances.
-	CreateInstance(i Instance, op *operations.Operation) error
-	CreateInstanceFromBackup(i Instance, sourcePath string, op *operations.Operation) error
-	CreateInstanceFromCopy(i Instance, src Instance, snapshots bool, op *operations.Operation) error
-	CreateInstanceFromImage(i Instance, fingerprint string, op *operations.Operation) error
-	CreateInstanceFromMigration(i Instance, conn io.ReadWriteCloser, args migration.VolumeTargetArgs, op *operations.Operation) error
-	RenameInstance(i Instance, newName string, op *operations.Operation) error
-	DeleteInstance(i Instance, op *operations.Operation) error
+	CreateInstance(inst Instance, op *operations.Operation) error
+	CreateInstanceFromBackup(inst Instance, sourcePath string, op *operations.Operation) error
+	CreateInstanceFromCopy(inst Instance, src Instance, snapshots bool, op *operations.Operation) error
+	CreateInstanceFromImage(inst Instance, fingerprint string, op *operations.Operation) error
+	CreateInstanceFromMigration(inst Instance, conn io.ReadWriteCloser, args migration.VolumeTargetArgs, op *operations.Operation) error
+	RenameInstance(inst Instance, newName string, op *operations.Operation) error
+	DeleteInstance(inst Instance, op *operations.Operation) error
 
-	MigrateInstance(i Instance, conn io.ReadWriteCloser, args migration.VolumeSourceArgs, op *operations.Operation) error
-	RefreshInstance(i Instance, src Instance, snapshots bool, op *operations.Operation) error
-	BackupInstance(i Instance, targetPath string, optimized bool, snapshots bool, op *operations.Operation) error
+	MigrateInstance(inst Instance, conn io.ReadWriteCloser, args migration.VolumeSourceArgs, op *operations.Operation) error
+	RefreshInstance(inst Instance, src Instance, snapshots bool, op *operations.Operation) error
+	BackupInstance(inst Instance, targetPath string, optimized bool, snapshots bool, op *operations.Operation) error
 
-	GetInstanceUsage(i Instance) (int64, error)
-	SetInstanceQuota(i Instance, size string, op *operations.Operation) error
+	GetInstanceUsage(inst Instance) (int64, error)
+	SetInstanceQuota(inst Instance, size string, op *operations.Operation) error
 
-	MountInstance(i Instance, op *operations.Operation) (bool, error)
-	UnmountInstance(i Instance, op *operations.Operation) (bool, error)
-	GetInstanceDisk(i Instance) (string, error)
+	MountInstance(inst Instance, op *operations.Operation) (bool, error)
+	UnmountInstance(inst Instance, op *operations.Operation) (bool, error)
+	GetInstanceDisk(inst Instance) (string, error)
 
 	// Instance snapshots.
-	CreateInstanceSnapshot(i Instance, name string, op *operations.Operation) error
-	RenameInstanceSnapshot(i Instance, newName string, op *operations.Operation) error
-	DeleteInstanceSnapshot(i Instance, op *operations.Operation) error
-	RestoreInstanceSnapshot(i Instance, op *operations.Operation) error
-	MountInstanceSnapshot(i Instance, op *operations.Operation) (bool, error)
-	UnmountInstanceSnapshot(i Instance, op *operations.Operation) (bool, error)
+	CreateInstanceSnapshot(inst Instance, name string, op *operations.Operation) error
+	RenameInstanceSnapshot(inst Instance, newName string, op *operations.Operation) error
+	DeleteInstanceSnapshot(inst Instance, op *operations.Operation) error
+	RestoreInstanceSnapshot(inst Instance, op *operations.Operation) error
+	MountInstanceSnapshot(inst Instance, op *operations.Operation) (bool, error)
+	UnmountInstanceSnapshot(inst Instance, op *operations.Operation) (bool, error)
 
 	// Images.
 	EnsureImage(fingerprint string, op *operations.Operation) error

From 94e7357d1d09672c4831a8bdf8497f3cf5e76097 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 20 Nov 2019 14:41:00 +0000
Subject: [PATCH 12/26] lxd/storage/backend/mock: Updates instance migration
 signatures

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

diff --git a/lxd/storage/backend_mock.go b/lxd/storage/backend_mock.go
index 4fd603bd48..f87beec2ee 100644
--- a/lxd/storage/backend_mock.go
+++ b/lxd/storage/backend_mock.go
@@ -74,7 +74,7 @@ func (b *mockBackend) CreateInstanceFromImage(i Instance, fingerprint string, op
 	return nil
 }
 
-func (b *mockBackend) CreateInstanceFromMigration(i Instance, conn io.ReadWriteCloser, args migration.SinkArgs, op *operations.Operation) error {
+func (b *mockBackend) CreateInstanceFromMigration(inst Instance, conn io.ReadWriteCloser, args migration.VolumeTargetArgs, op *operations.Operation) error {
 	return nil
 }
 
@@ -86,8 +86,8 @@ func (b *mockBackend) DeleteInstance(i Instance, op *operations.Operation) error
 	return nil
 }
 
-func (b *mockBackend) MigrateInstance(i Instance, snapshots bool, args migration.SourceArgs) (migration.StorageSourceDriver, error) {
-	return nil, nil
+func (b *mockBackend) MigrateInstance(inst Instance, conn io.ReadWriteCloser, args migration.VolumeSourceArgs, op *operations.Operation) error {
+	return nil
 }
 
 func (b *mockBackend) RefreshInstance(i Instance, src Instance, snapshots bool, op *operations.Operation) error {

From 199c7841ec8fdb86648d86e676ab777d5007a86a Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 20 Nov 2019 14:46:55 +0000
Subject: [PATCH 13/26] lxd/db/containers: Removes unused
 ContainerCreationUpdate replaces with InstanceSnapshotCreationUpdate

This aims to make it clear that using the former ContainerCreationUpdate function to update creation date of instance snapshot IDs is a bug and should not be done (it will be fixed in a separate commit).

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

diff --git a/lxd/db/containers.go b/lxd/db/containers.go
index 6f45b5b72c..271bb58599 100644
--- a/lxd/db/containers.go
+++ b/lxd/db/containers.go
@@ -973,11 +973,10 @@ func ContainerUpdate(tx *sql.Tx, id int, description string, architecture int, e
 	return nil
 }
 
-// ContainerCreationUpdate updates the cration_date field of the container
-// with the given ID.
-func (c *Cluster) ContainerCreationUpdate(id int, date time.Time) error {
-	stmt := `UPDATE instances SET creation_date=? WHERE id=?`
-	err := exec(c.db, stmt, date, id)
+// InstanceSnapshotCreationUpdate updates the creation_date field of the instance snapshot with ID.
+func (c *Cluster) InstanceSnapshotCreationUpdate(instanceID int, date time.Time) error {
+	stmt := `UPDATE instances_snapshots SET creation_date=? WHERE id=?`
+	err := exec(c.db, stmt, date, instanceID)
 	return err
 }
 

From 20564f28363d2989623cf34e1170f6bd8d854227 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 20 Nov 2019 14:48:28 +0000
Subject: [PATCH 14/26] lxd/migrate/storage/volumes: Fixes typo

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

diff --git a/lxd/migrate_storage_volumes.go b/lxd/migrate_storage_volumes.go
index 978d95ed88..90ebb3218c 100644
--- a/lxd/migrate_storage_volumes.go
+++ b/lxd/migrate_storage_volumes.go
@@ -145,7 +145,7 @@ func (s *migrationSourceWs) DoStorage(state *state.State, poolName string, volNa
 	if pool != nil {
 		migrationType, err := migration.MatchTypes(respHeader, migration.MigrationFSType_RSYNC, poolMigrationTypes)
 		if err != nil {
-			logger.Errorf("Failed to neogotiate migration type: %v", err)
+			logger.Errorf("Failed to negotiate migration type: %v", err)
 			s.sendControl(err)
 			return err
 		}

From 2df94b80690130eca5e68365496d6cf47a56494a Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 20 Nov 2019 14:48:56 +0000
Subject: [PATCH 15/26] lxd/migration/interfaces: Removes unused definitions

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/migration/interfaces.go | 12 ------------
 1 file changed, 12 deletions(-)
 delete mode 100644 lxd/migration/interfaces.go

diff --git a/lxd/migration/interfaces.go b/lxd/migration/interfaces.go
deleted file mode 100644
index 7264e9ef91..0000000000
--- a/lxd/migration/interfaces.go
+++ /dev/null
@@ -1,12 +0,0 @@
-package migration
-
-// FIXME: empty stubs until we're ready to move the migration code over
-
-type SourceArgs struct {
-}
-
-type SinkArgs struct {
-}
-
-type StorageSourceDriver interface {
-}

From 0064ab2629353e69069a41b3ec54fa254a7266f9 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 20 Nov 2019 14:49:45 +0000
Subject: [PATCH 16/26] lxd/storage/backend/lxd: Updates CreateInstance to use
 root disk device config

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

diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go
index 14e72c511f..f905181ef8 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -296,7 +296,13 @@ func (b *lxdBackend) CreateInstance(inst Instance, op *operations.Operation) err
 		contentType = drivers.ContentTypeBlock
 	}
 
-	vol := b.newVolume(volType, contentType, project.Prefix(inst.Project(), inst.Name()), nil)
+	// Find the root device config for instance.
+	_, rootDiskConf, err := shared.GetRootDiskDevice(inst.ExpandedDevices().CloneNative())
+	if err != nil {
+		return err
+	}
+
+	vol := b.newVolume(volType, contentType, project.Prefix(inst.Project(), inst.Name()), rootDiskConf)
 	err = b.driver.CreateVolume(vol, nil, op)
 	if err != nil {
 		return err

From 5cdf8408d911194c7b9e900d66f3e970f528d2a1 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 20 Nov 2019 14:50:25 +0000
Subject: [PATCH 17/26] lxd/storage/backend/lxd: Implements
 CreateInstanceFromCopy

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

diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go
index f905181ef8..240f7019fc 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -326,8 +326,146 @@ func (b *lxdBackend) CreateInstanceFromBackup(inst Instance, sourcePath string,
 	return ErrNotImplemented
 }
 
+// CreateInstanceFromCopy copies an instance volume and optionally its snapshots to new volume(s).
 func (b *lxdBackend) CreateInstanceFromCopy(inst Instance, src Instance, snapshots bool, op *operations.Operation) error {
-	return ErrNotImplemented
+	logger := logging.AddContext(b.logger, log.Ctx{"project": inst.Project(), "instance": inst.Name(), "src": src.Name(), "snapshots": snapshots})
+	logger.Debug("CreateInstanceFromCopy started")
+	defer logger.Debug("CreateInstanceFromCopy finished")
+
+	if inst.Type() != src.Type() {
+		return fmt.Errorf("Instance types must match")
+	}
+
+	volType, err := InstanceTypeToVolumeType(inst.Type())
+	if err != nil {
+		return err
+	}
+
+	volDBType, err := VolumeTypeToDBType(volType)
+	if err != nil {
+		return err
+	}
+
+	contentType := drivers.ContentTypeFS
+	if inst.Type() == instancetype.VM {
+		contentType = drivers.ContentTypeBlock
+	}
+
+	// Get the root disk device config.
+	_, rootDiskConf, err := shared.GetRootDiskDevice(inst.ExpandedDevices().CloneNative())
+	if err != nil {
+		return err
+	}
+
+	// Initialise a new volume containing the root disk config supplied in the new instance.
+	vol := b.newVolume(volType, contentType, project.Prefix(inst.Project(), inst.Name()), rootDiskConf)
+
+	// We don't need to use the source instance's root disk config, so set to nil.
+	srcVol := b.newVolume(volType, contentType, project.Prefix(src.Project(), src.Name()), nil)
+
+	revert := true
+	defer func() {
+		if !revert {
+			return
+		}
+		b.DeleteInstance(inst, op)
+	}()
+
+	srcPool, err := GetPoolByInstance(b.state, src)
+	if err != nil {
+		return err
+	}
+
+	if b.Name() == srcPool.Name() {
+		logger.Debug("CreateInstanceFromCopy same-pool mode detected")
+		err = b.driver.CreateVolumeFromCopy(vol, srcVol, snapshots, op)
+		if err != nil {
+			return err
+		}
+	} else {
+		// We are copying volumes between storage pools so use migration system as it will
+		// be able to negotiate a common transfer method between pool types.
+		logger.Debug("CreateInstanceFromCopy cross-pool mode detected")
+
+		// If we are copying snapshots, retrieve a list of snapshots from source volume.
+		snapshotNames := []string{}
+		if snapshots {
+			snapshots, err := VolumeSnapshotsGet(b.state, srcPool.Name(), src.Name(), volDBType)
+			if err != nil {
+				return err
+			}
+
+			for _, snapshot := range snapshots {
+				_, snapShotName, _ := shared.ContainerGetParentAndSnapshotName(snapshot.Name)
+				snapshotNames = append(snapshotNames, snapShotName)
+			}
+		}
+
+		// Use in-memory pipe pair to simulate a connection between the sender and receiver.
+		aEnd, bEnd := memorypipe.NewPipePair()
+
+		// Negotiate the migration type to use.
+		offeredTypes := srcPool.MigrationTypes(contentType)
+		offerHeader := migration.TypesToHeader(offeredTypes...)
+		migrationType, err := migration.MatchTypes(offerHeader, migration.MigrationFSType_RSYNC, b.MigrationTypes(contentType))
+		if err != nil {
+			return fmt.Errorf("Failed to negotiate copy migration type: %v", err)
+		}
+
+		// Run sender and receiver in separate go routines to prevent deadlocks.
+		aEndErrCh := make(chan error, 1)
+		bEndErrCh := make(chan error, 1)
+		go func() {
+			err := srcPool.MigrateInstance(src, aEnd, migration.VolumeSourceArgs{
+				Name:          src.Name(),
+				Snapshots:     snapshotNames,
+				MigrationType: migrationType,
+				TrackProgress: true, // Do use a progress tracker on sender.
+			}, op)
+
+			aEndErrCh <- err
+		}()
+
+		go func() {
+			err := b.CreateInstanceFromMigration(inst, bEnd, migration.VolumeTargetArgs{
+				Name:          inst.Name(),
+				Snapshots:     snapshotNames,
+				MigrationType: migrationType,
+				TrackProgress: false, // Do not a progress tracker on receiver.
+			}, op)
+
+			bEndErrCh <- err
+		}()
+
+		// Capture errors from the sender and receiver from their result channels.
+		errs := []error{}
+		aEndErr := <-aEndErrCh
+		if aEndErr != nil {
+			errs = append(errs, aEndErr)
+		}
+
+		bEndErr := <-bEndErrCh
+		if bEndErr != nil {
+			errs = append(errs, bEndErr)
+		}
+
+		if len(errs) > 0 {
+			return fmt.Errorf("Create instance volume from copy failed: %v", errs)
+		}
+	}
+
+	err = b.ensureInstanceSymlink(inst.Type(), inst.Project(), inst.Name(), vol.MountPath())
+	if err != nil {
+		return err
+	}
+
+	err = inst.DeferTemplateApply("copy")
+	if err != nil {
+		return err
+	}
+
+	revert = false
+	return nil
 }
 
 // imageFiller returns a function that can be used as a filler function with CreateVolume().

From 317c2c7b493b7a31b5290b9e146ac88cf66eaab1 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 20 Nov 2019 14:51:18 +0000
Subject: [PATCH 18/26] lxd/storage/backend/lxd: Updates
 CreateInstanceFromImage to use instance root disk config

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

diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go
index 240f7019fc..3739e13995 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -498,6 +498,11 @@ func (b *lxdBackend) CreateInstanceFromImage(inst Instance, fingerprint string,
 		return err
 	}
 
+	contentType := drivers.ContentTypeFS
+	if inst.Type() == instancetype.VM {
+		contentType = drivers.ContentTypeBlock
+	}
+
 	revert := true
 	defer func() {
 		if !revert {
@@ -506,12 +511,13 @@ func (b *lxdBackend) CreateInstanceFromImage(inst Instance, fingerprint string,
 		b.DeleteInstance(inst, op)
 	}()
 
-	contentType := drivers.ContentTypeFS
-	if inst.Type() == instancetype.VM {
-		contentType = drivers.ContentTypeBlock
+	// Get the root disk device config.
+	_, rootDiskConf, err := shared.GetRootDiskDevice(inst.ExpandedDevices().CloneNative())
+	if err != nil {
+		return err
 	}
 
-	vol := b.newVolume(volType, contentType, project.Prefix(inst.Project(), inst.Name()), nil)
+	vol := b.newVolume(volType, contentType, project.Prefix(inst.Project(), inst.Name()), rootDiskConf)
 
 	// 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.
@@ -529,6 +535,7 @@ func (b *lxdBackend) CreateInstanceFromImage(inst Instance, fingerprint string,
 			return err
 		}
 
+		// No config for an image volume so set to nil.
 		imgVol := b.newVolume(drivers.VolumeTypeImage, contentType, fingerprint, nil)
 		err = b.driver.CreateVolumeFromCopy(vol, imgVol, false, op)
 		if err != nil {

From fec0b361c07fac45f8abcca6be07069907af5807 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 20 Nov 2019 14:51:41 +0000
Subject: [PATCH 19/26] lxd/storage/backend/lxd: Implements
 CreateInstanceFromMigration

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

diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go
index 3739e13995..e2943a1b6b 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -557,8 +557,41 @@ func (b *lxdBackend) CreateInstanceFromImage(inst Instance, fingerprint string,
 	return nil
 }
 
-func (b *lxdBackend) CreateInstanceFromMigration(inst Instance, conn io.ReadWriteCloser, args migration.SinkArgs, op *operations.Operation) error {
-	return ErrNotImplemented
+// CreateInstanceFromMigration receives an instance being migrated.
+// The args.Name and args.Config fields are ignored and, instance properties are used instead.
+func (b *lxdBackend) CreateInstanceFromMigration(inst Instance, conn io.ReadWriteCloser, args migration.VolumeTargetArgs, op *operations.Operation) error {
+	logger := logging.AddContext(b.logger, log.Ctx{"project": inst.Project(), "instance": inst.Name(), "args": args})
+	logger.Debug("CreateInstanceFromMigration started")
+	defer logger.Debug("CreateInstanceFromMigration finished")
+
+	volType, err := InstanceTypeToVolumeType(inst.Type())
+	if err != nil {
+		return err
+	}
+
+	contentType := drivers.ContentTypeFS
+	if inst.Type() == instancetype.VM {
+		contentType = drivers.ContentTypeBlock
+	}
+
+	// Find the root device config for instance.
+	_, rootDiskConf, err := shared.GetRootDiskDevice(inst.ExpandedDevices().CloneNative())
+	if err != nil {
+		return err
+	}
+
+	// Override args.Name and args.Config to ensure volume is created based on instance.
+	args.Config = rootDiskConf
+	args.Name = inst.Name()
+
+	vol := b.newVolume(volType, contentType, args.Name, args.Config)
+	err = b.driver.CreateVolumeFromMigration(vol, conn, args, op)
+	if err != nil {
+		conn.Close()
+		return err
+	}
+
+	return nil
 }
 
 // RenameInstance renames the instance's root volume and any snapshot volumes.

From c14ef5968e6d1e20d188cac88ed2669ecd545511 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 20 Nov 2019 14:51:54 +0000
Subject: [PATCH 20/26] lxd/storage/backend/lxd: Implements MigrateInstance

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

diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go
index e2943a1b6b..0dd4cbbcde 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -764,8 +764,37 @@ func (b *lxdBackend) DeleteInstance(inst Instance, op *operations.Operation) err
 	return nil
 }
 
-func (b *lxdBackend) MigrateInstance(inst Instance, snapshots bool, args migration.SourceArgs) (migration.StorageSourceDriver, error) {
-	return nil, ErrNotImplemented
+// MigrateInstance sends an instance volume for migration.
+// The args.Name field is ignored and the name of the instance is used instead.
+func (b *lxdBackend) MigrateInstance(inst Instance, conn io.ReadWriteCloser, args migration.VolumeSourceArgs, op *operations.Operation) error {
+	logger := logging.AddContext(b.logger, log.Ctx{"project": inst.Project(), "instance": inst.Name(), "args": args})
+	logger.Debug("MigrateInstance started")
+	defer logger.Debug("MigrateInstance finished")
+
+	volType, err := InstanceTypeToVolumeType(inst.Type())
+	if err != nil {
+		return err
+	}
+
+	contentType := drivers.ContentTypeFS
+	if inst.Type() == instancetype.VM {
+		contentType = drivers.ContentTypeBlock
+	}
+
+	// Get the root disk device config.
+	_, rootDiskConf, err := shared.GetRootDiskDevice(inst.ExpandedDevices().CloneNative())
+	if err != nil {
+		return err
+	}
+
+	args.Name = inst.Name() // Override args.Name to ensure instance volume is sent.
+	vol := b.newVolume(volType, contentType, args.Name, rootDiskConf)
+	err = b.driver.MigrateVolume(vol, conn, args, op)
+	if err != nil {
+		return err
+	}
+
+	return nil
 }
 
 func (b *lxdBackend) RefreshInstance(inst Instance, src Instance, snapshots bool, op *operations.Operation) error {

From fedf57972106c38e15606d6d83e2e4dbce3c683a Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 20 Nov 2019 14:52:18 +0000
Subject: [PATCH 21/26] lxd/storage/backend/lxd: Adds comment to EnsureImage
 explaining for volume config not needed

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

diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go
index 0dd4cbbcde..9b25f18d51 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -1084,9 +1084,9 @@ func (b *lxdBackend) EnsureImage(fingerprint string, op *operations.Operation) e
 		contentType = drivers.ContentTypeBlock
 	}
 
-	// Create the new image volume.
-	vol := b.newVolume(drivers.VolumeTypeImage, contentType, fingerprint, nil)
-	err = b.driver.CreateVolume(vol, b.imageFiller(fingerprint, op), op)
+	// Create the new image volume. No config for an image volume so set to nil.
+	imgVol := b.newVolume(drivers.VolumeTypeImage, contentType, fingerprint, nil)
+	err = b.driver.CreateVolume(imgVol, b.imageFiller(fingerprint, op), op)
 	if err != nil {
 		return err
 	}

From cb8700b365a3dc4c4405b44e5c666d049e919d13 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 20 Nov 2019 14:52:45 +0000
Subject: [PATCH 22/26] lxd/storage/backend/lxd: Comment consistency in
 CreateCustomVolumeFromCopy

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

diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go
index 9b25f18d51..54bfc1df22 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -1277,7 +1277,7 @@ func (b *lxdBackend) CreateCustomVolumeFromCopy(volName, desc string, config map
 	// to negotiate a common transfer method between pool types.
 	logger.Debug("CreateCustomVolumeFromCopy cross-pool mode detected")
 
-	// Create in-memory pipe pair to simulate a connection between the sender and receiver.
+	// Use in-memory pipe pair to simulate a connection between the sender and receiver.
 	aEnd, bEnd := memorypipe.NewPipePair()
 
 	// Negotiate the migration type to use.

From 0457dd9fbe45b83f4dbd0364ad8cfa03d9f4fb5d Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 20 Nov 2019 14:53:07 +0000
Subject: [PATCH 23/26] lxd/storage/backend/lxd: Add comment to
 MigrateCustomVolume explaining volume config not needed

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

diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go
index 54bfc1df22..7c37832247 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -1341,6 +1341,7 @@ func (b *lxdBackend) MigrateCustomVolume(conn io.ReadWriteCloser, args migration
 	logger.Debug("MigrateCustomVolume started")
 	defer logger.Debug("MigrateCustomVolume finished")
 
+	// Volume config not needed to send a volume so set to nil.
 	vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, args.Name, nil)
 	err := b.driver.MigrateVolume(vol, conn, args, op)
 	if err != nil {

From b55bce036fecb54ef8f3f34ce92d2847780e6b98 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 20 Nov 2019 14:53:33 +0000
Subject: [PATCH 24/26] lxd/storage/backend/lxd: Close migration connection on
 error in CreateCustomVolumeFromMigration

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

diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go
index 7c37832247..be9b9396e9 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -1397,7 +1397,8 @@ func (b *lxdBackend) CreateCustomVolumeFromMigration(conn io.ReadWriteCloser, ar
 	vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, args.Name, args.Config)
 	err = b.driver.CreateVolumeFromMigration(vol, conn, args, op)
 	if err != nil {
-		return nil
+		conn.Close()
+		return err
 	}
 
 	revertDBVolumes = nil

From 270150b5df1d82b9fa6560969b46b79c89a5dd8c Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 21 Nov 2019 12:33:37 +0000
Subject: [PATCH 25/26] lxd/container/lxc: Reorders containerLXC Delete()
 stages

As follows:

1. Storage volume removal (using new or old storage layer). Detects not found error for storage volume and skips.
2. If not snapshot: Remove backups, remove MAAS record, remove devices.
3. Remove Instance DB record.
4. Send lifecycle event.

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

diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index fac2ecc7e9..9eed6fedcd 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -3547,15 +3547,9 @@ func (c *containerLXC) Delete() error {
 		}
 	}
 
-	// Get the storage pool name of the instance.
-	poolName, err := c.state.Cluster.InstancePool(c.Project(), c.Name())
-	if err != nil {
-		return err
-	}
-
 	// Check if we can load new storage layer for pool driver type.
-	pool, err := storagePools.GetPoolByName(c.state, poolName)
-	if err != storageDrivers.ErrUnknownDriver {
+	pool, err := storagePools.GetPoolByInstance(c.state, c)
+	if err != storageDrivers.ErrUnknownDriver && err != db.ErrNoSuchObject {
 		if err != nil {
 			return err
 		}
@@ -3577,19 +3571,6 @@ func (c *containerLXC) Delete() error {
 				return err
 			}
 
-			// Remove all backups.
-			backups, err := c.Backups()
-			if err != nil {
-				return err
-			}
-
-			for _, backup := range backups {
-				err = backup.Delete()
-				if err != nil {
-					return err
-				}
-			}
-
 			if !isImport {
 				// Remove the storage volume, snapshot volumes and database records.
 				err = pool.DeleteInstance(c, nil)
@@ -3597,32 +3578,8 @@ func (c *containerLXC) Delete() error {
 					return err
 				}
 			}
-
-			// Clean things up.
-			c.cleanup()
-
-			// Delete the MAAS entry.
-			err = c.maasDelete()
-			if err != nil {
-				logger.Error("Failed deleting instance MAAS record", log.Ctx{"project": c.Project(), "instance": c.Name(), "err": err})
-				return err
-			}
-
-			// Run device removal function for each device.
-			for k, m := range c.expandedDevices {
-				err = c.deviceRemove(k, m)
-				if err != nil && err != device.ErrUnsupportedDevType {
-					return errors.Wrapf(err, "Failed to remove device '%s'", k)
-				}
-			}
 		}
-
-		// Remove the database record of the instance or snapshot instance.
-		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
-		}
-	} else {
+	} else if err == storageDrivers.ErrUnknownDriver {
 		// Attempt to initialize storage interface for the container.
 		err := c.initStorage()
 		if err != nil {
@@ -3630,7 +3587,7 @@ func (c *containerLXC) Delete() error {
 		}
 
 		if c.IsSnapshot() {
-			// Remove the snapshot
+			// Remove the snapshot.
 			if c.storage != nil && !isImport {
 				err := c.storage.ContainerSnapshotDelete(c)
 				if err != nil {
@@ -3639,30 +3596,14 @@ func (c *containerLXC) Delete() error {
 				}
 			}
 		} else {
-			// Remove all snapshots
+			// Remove all snapshots.
 			err := instanceDeleteSnapshots(c.state, c.Project(), c.Name())
 			if err != nil {
 				logger.Warn("Failed to delete snapshots", log.Ctx{"name": c.Name(), "err": err})
 				return err
 			}
 
-			// Remove all backups
-			backups, err := c.Backups()
-			if err != nil {
-				return err
-			}
-
-			for _, backup := range backups {
-				err = backup.Delete()
-				if err != nil {
-					return err
-				}
-			}
-
-			// Clean things up
-			c.cleanup()
-
-			// Delete the container from disk
+			// Delete the container from disk.
 			if c.storage != nil && !isImport {
 				_, poolName, _ := c.storage.GetContainerPoolInfo()
 				containerMountPoint := storagePools.GetContainerMountPoint(c.Project(), poolName, c.Name())
@@ -3676,41 +3617,60 @@ func (c *containerLXC) Delete() error {
 				}
 			}
 
-			// Delete the MAAS entry
-			err = c.maasDelete()
-			if err != nil {
-				logger.Error("Failed deleting container MAAS record", log.Ctx{"name": c.Name(), "err": err})
-				return err
-			}
+			// Remove the database entry for the pool device.
+			if c.storage != nil {
+				// Get the name of the storage pool the container is attached to. This
+				// reverse-engineering works because container names are globally
+				// unique.
+				poolID, _, _ := c.storage.GetContainerPoolInfo()
 
-			// Remove devices from container.
-			for k, m := range c.expandedDevices {
-				err = c.deviceRemove(k, m)
-				if err != nil && err != device.ErrUnsupportedDevType {
-					return errors.Wrapf(err, "Failed to remove device '%s'", k)
+				// Remove volume from storage pool.
+				err := c.state.Cluster.StoragePoolVolumeDelete(c.Project(), c.Name(), storagePoolVolumeTypeContainer, poolID)
+				if err != nil {
+					return err
 				}
 			}
 		}
+	}
 
-		// Remove the database record
-		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})
+	// Perform other cleanup steps if not snapshot.
+	if !c.IsSnapshot() {
+		// Remove all backups.
+		backups, err := c.Backups()
+		if err != nil {
 			return err
 		}
 
-		// Remove the database entry for the pool device
-		if c.storage != nil {
-			// Get the name of the storage pool the container is attached to. This
-			// reverse-engineering works because container names are globally
-			// unique.
-			poolID, _, _ := c.storage.GetContainerPoolInfo()
-
-			// Remove volume from storage pool.
-			err := c.state.Cluster.StoragePoolVolumeDelete(c.Project(), c.Name(), storagePoolVolumeTypeContainer, poolID)
+		for _, backup := range backups {
+			err = backup.Delete()
 			if err != nil {
 				return err
 			}
 		}
+
+		// Delete the MAAS entry.
+		err = c.maasDelete()
+		if err != nil {
+			logger.Error("Failed deleting container MAAS record", log.Ctx{"name": c.Name(), "err": err})
+			return err
+		}
+
+		// Remove devices from container.
+		for k, m := range c.expandedDevices {
+			err = c.deviceRemove(k, m)
+			if err != nil && err != device.ErrUnsupportedDevType {
+				return errors.Wrapf(err, "Failed to remove device '%s'", k)
+			}
+		}
+
+		// Clean things up.
+		c.cleanup()
+	}
+
+	// Remove the database record of the instance or snapshot instance.
+	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
 	}
 
 	logger.Info("Deleted container", ctxMap)

From 1bcb38dc3cdeceda6f676875cc6b9313da5caeb1 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 21 Nov 2019 11:56:51 +0000
Subject: [PATCH 26/26] lxd/vm/qemu: Makes Delete() aligned with containerLXC's
 Delete()

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

diff --git a/lxd/vm_qemu.go b/lxd/vm_qemu.go
index 7f84e5eb35..3a639fc22f 100644
--- a/lxd/vm_qemu.go
+++ b/lxd/vm_qemu.go
@@ -1829,26 +1829,9 @@ func (vm *vmQemu) Delete() error {
 	// TODO consider lxd import detection for VMs.
 	isImport := false
 
-	// Remove all backups if not snapshot.
-	if !vm.IsSnapshot() {
-		backups, err := vm.Backups()
-		if err != nil {
-			logger.Error("Failed to load backups", log.Ctx{"project": vm.Project(), "instance": vm.Name(), "err": err})
-		}
-
-		for _, backup := range backups {
-			err = backup.Delete()
-			if err != nil {
-				logger.Error("Failed to delete backup", log.Ctx{"project": vm.Project(), "instance": vm.Name(), "backup": backup.Name, "err": err})
-			}
-		}
-	}
-
 	// Attempt to initialize storage interface for the instance.
 	pool, err := storagePools.GetPoolByInstance(vm.state, vm)
-	if err != nil {
-		logger.Error("Failed to init storage pool", log.Ctx{"project": vm.Project(), "instance": vm.Name(), "err": err})
-
+	if err != nil && err != db.ErrNoSuchObject {
 		// Because of the way vmQemuCreate creates the storage volume record before loading
 		// the storage pool driver, Delete() may be called as part of a revertion if the
 		// pool being used to create the VM on doesn't support VMs. This deletion will then
@@ -1856,6 +1839,7 @@ func (vm *vmQemu) Delete() error {
 		// DB record.
 		// TODO: This can be removed once all pool drivers are ported to new storage layer.
 		if err == storageDrivers.ErrUnknownDriver || err == storageDrivers.ErrNotImplemented {
+			logger.Warn("Unsupported storage pool type, removing DB volume record", log.Ctx{"project": vm.Project(), "instance": vm.Name(), "err": err})
 			// Remove the volume record from the database. This deletion would
 			// normally be handled by DeleteInstance() call below but since the storage
 			// driver (new storage) is not implemented, we need to do it here manually.
@@ -1873,6 +1857,8 @@ func (vm *vmQemu) Delete() error {
 			if err != nil {
 				return err
 			}
+		} else {
+			return err
 		}
 	}
 
@@ -1882,7 +1868,7 @@ func (vm *vmQemu) Delete() error {
 				// Remove snapshot volume and database record.
 				err = pool.DeleteInstanceSnapshot(vm, nil)
 				if err != nil {
-					logger.Error("Failed to delete instance snapshot volume", log.Ctx{"project": vm.Project(), "instance": vm.Name(), "err": err})
+					return err
 				}
 			}
 		} else {
@@ -1890,14 +1876,14 @@ func (vm *vmQemu) Delete() error {
 			// calling its Delete function.
 			err := instanceDeleteSnapshots(vm.state, vm.Project(), vm.Name())
 			if err != nil {
-				logger.Error("Failed to delete instance snapshot volumes", log.Ctx{"project": vm.Project(), "instance": vm.Name(), "err": err})
+				return err
 			}
 
 			if !isImport {
 				// Remove the storage volume, snapshot volumes and database records.
 				err = pool.DeleteInstance(vm, nil)
 				if err != nil {
-					logger.Error("Failed to delete instance volume", log.Ctx{"project": vm.Project(), "instance": vm.Name(), "err": err})
+					return err
 				}
 			}
 		}
@@ -1905,28 +1891,42 @@ func (vm *vmQemu) Delete() error {
 
 	// Perform other cleanup steps if not snapshot.
 	if !vm.IsSnapshot() {
-		// Clean things up.
-		vm.cleanup()
+		// Remove all backups.
+		backups, err := vm.Backups()
+		if err != nil {
+			return err
+		}
+
+		for _, backup := range backups {
+			err = backup.Delete()
+			if err != nil {
+				return err
+			}
+		}
 
 		// Delete the MAAS entry.
 		err = vm.maasDelete()
 		if err != nil {
 			logger.Error("Failed deleting instance MAAS record", log.Ctx{"project": vm.Project(), "instance": vm.Name(), "err": err})
+			return err
 		}
 
 		// Run device removal function for each device.
 		for k, m := range vm.expandedDevices {
 			err = vm.deviceRemove(k, m)
 			if err != nil && err != device.ErrUnsupportedDevType {
-				logger.Error("Failed to remove device", log.Ctx{"project": vm.Project(), "instance": vm.Name(), "device": k, "err": err})
+				return errors.Wrapf(err, "Failed to remove device '%s'", k)
 			}
 		}
+
+		// Clean things up.
+		vm.cleanup()
 	}
 
 	// Remove the database record of the instance or snapshot instance.
 	if err := vm.state.Cluster.InstanceRemove(vm.Project(), vm.Name()); err != nil {
 		logger.Error("Failed deleting instance entry", log.Ctx{"project": vm.Project(), "instance": vm.Name(), "err": err})
-		return err // This is the only step we should return prematurely at.
+		return err
 	}
 
 	logger.Info("Deleted instance", ctxMap)


More information about the lxc-devel mailing list