[lxc-devel] [lxd/master] Storage CreateInstanceFromCopy
tomponline on Github
lxc-bot at linuxcontainers.org
Wed Nov 20 14:57:50 UTC 2019
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 492 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20191120/8825b879/attachment-0001.bin>
-------------- next part --------------
From f05f3b32c95cdb8779542c38e9bfff74e96570ec 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 01/21] 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 55aaed404c..62c58392d9 100644
--- a/lxd/container.go
+++ b/lxd/container.go
@@ -570,7 +570,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, instanceOnly bool, refresh bool) (Instance, error) {
+func instanceCreateAsCopy(s *state.State, args db.InstanceArgs, sourceInst Instance, instanceOnly bool, refresh bool, op *operations.Operation) (Instance, error) {
var inst, revertInst Instance
var err error
From b67393185468a32228b19c09666dc8154975cf68 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 02/21] 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 dacc135db2..fc9b50c15b 100644
--- a/lxd/containers_post.go
+++ b/lxd/containers_post.go
@@ -604,7 +604,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 9f439ab952aa1199284e2044cfd4adee48bdcef8 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 03/21] lxd/container: Links instanceCreateAsCopy to new
storage pkg
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/container.go | 22 +++++++++++++++++++---
1 file changed, 19 insertions(+), 3 deletions(-)
diff --git a/lxd/container.go b/lxd/container.go
index 62c58392d9..08eafd8abc 100644
--- a/lxd/container.go
+++ b/lxd/container.go
@@ -701,9 +701,25 @@ func instanceCreateAsCopy(s *state.State, args db.InstanceArgs, sourceInst Insta
return nil, err
}
} else {
- err = inst.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 {
+ err = inst.Storage().ContainerCopy(inst, sourceInst, instanceOnly)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ return nil, fmt.Errorf("Instance type not supported")
}
}
From 5b11204a364a250b981b18e48bf2aca3cf0edacd 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 04/21] 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 08eafd8abc..cf5e79dc03 100644
--- a/lxd/container.go
+++ b/lxd/container.go
@@ -642,15 +642,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 != "" {
@@ -666,15 +666,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,
}
@@ -684,8 +684,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 d55c969b7344fa81c1c721ae473d5def2de9a1f7 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 05/21] 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 a2f4cda3b5ea701bbea8b0cf57b5af2db81efaa0 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 06/21] 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 28d902588beb86b257543a821a5c2048db6553f3 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 07/21] 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 61b0f68e0755f6949746bd086aab38135e625826 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 08/21] 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 91cc70939a712aa1af049bd6fb765891f98a2ff1 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 20 Nov 2019 14:45:49 +0000
Subject: [PATCH 09/21] lxd/container/lxc: Dont fail Delete() when removing
storage fails
Allows for partially created containers to be deleted.
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/container_lxc.go | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index 1c800c0b08..0c02c20ff9 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -3561,7 +3561,7 @@ func (c *containerLXC) Delete() error {
// Remove snapshot volume and database record.
err = pool.DeleteInstanceSnapshot(c, nil)
if err != nil {
- return err
+ logger.Error("Failed to delete instance snapshot volume", log.Ctx{"project": c.Project(), "instance": c.Name(), "err": err})
}
}
} else {
@@ -3569,8 +3569,7 @@ func (c *containerLXC) Delete() error {
// calling its Delete function.
err := instanceDeleteSnapshots(c.state, c.Project(), c.Name())
if err != nil {
- logger.Error("Failed to delete instance snapshots", log.Ctx{"project": c.Project(), "instance": c.Name(), "err": err})
- return err
+ logger.Error("Failed to delete instance snapshot volumes", log.Ctx{"project": c.Project(), "instance": c.Name(), "err": err})
}
// Remove all backups.
@@ -3590,7 +3589,7 @@ func (c *containerLXC) Delete() error {
// Remove the storage volume, snapshot volumes and database records.
err = pool.DeleteInstance(c, nil)
if err != nil {
- return err
+ logger.Error("Failed to delete instance volume", log.Ctx{"project": c.Project(), "instance": c.Name(), "err": err})
}
}
From 33eda3dbf4f10c3d711121780530dd43d931edc5 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 10/21] 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 2f1ac2c611ebc30a265097547817e33e8620937b 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 11/21] 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 7c2ba07760ae04046eee969f2f5f7443a7cadcac 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 12/21] 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 06072d9dab2672e4fe39dddd80d73870790287a2 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 13/21] 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 00aac41b09226fe0490219b454bf66008450b2d7 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 14/21] lxd/storage/backend/lxd: Implements
CreateInstanceFromCopy
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/storage/backend_lxd.go | 142 ++++++++++++++++++++++++++++++++++++-
1 file changed, 141 insertions(+), 1 deletion(-)
diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go
index f905181ef8..0a9a5921e4 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -326,8 +326,148 @@ 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
+
+ srcPool, err := GetPoolByInstance(b.state, src)
+ if err != nil {
+ return err
+ }
+
+ if b.Name() == srcPool.Name() {
+ logger.Debug("CreateInstanceFromCopy same-pool mode detected")
+ defer func() {
+ if !revert {
+ return
+ }
+ b.DeleteInstance(inst, op)
+ }()
+
+ 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 4ebad588c12a90d3318ec83c4627e1c47f339861 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 15/21] 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 0a9a5921e4..212de9a882 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -500,6 +500,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 {
@@ -508,12 +513,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.
@@ -531,6 +537,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 fe161fd0537cac33eed87f7fd829b290d34e46a1 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 16/21] 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 212de9a882..89c59ab8ae 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -559,8 +559,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 66fd38fa25580f7adf70bb2dd17cc3108fe6b751 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 17/21] 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 89c59ab8ae..e2f0a91bae 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -766,8 +766,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 049e5b671e229dcefe750f316c00bd491b2dee39 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 18/21] 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 e2f0a91bae..fc587b95c0 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -1086,9 +1086,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 0f3864d2887229913b3e00f54d0abb58e1d6395e 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 19/21] 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 fc587b95c0..7b4b17375e 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -1279,7 +1279,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 a6956cc6cffbece99d7ecc876df132a28250537c 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 20/21] 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 7b4b17375e..db740e13d1 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -1343,6 +1343,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 5d53653e88469a70d76c060b04e493cbcac8bac3 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 21/21] 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 db740e13d1..83e0c9bcf4 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -1399,7 +1399,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
More information about the lxc-devel
mailing list