[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