[lxc-devel] [lxd/master] Storage Volume Copy using in-memory pipe and migration logic

tomponline on Github lxc-bot at linuxcontainers.org
Wed Oct 30 13:39:29 UTC 2019


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 543 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20191030/8ed57ea5/attachment.bin>
-------------- next part --------------
From 19100009dea691fa57b8fa0e24f6db522e82c7df Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 30 Oct 2019 13:28:27 +0000
Subject: [PATCH 1/9] lxd/storage/memorypipe: Adds in-memory bidirectional pipe

Compatible with the io.ReadWriteCloser interface.

Used for simulating WebsocketIO between local endpoints.

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

diff --git a/lxd/storage/memorypipe/memory_pipe.go b/lxd/storage/memorypipe/memory_pipe.go
new file mode 100644
index 0000000000..2484c30c3b
--- /dev/null
+++ b/lxd/storage/memorypipe/memory_pipe.go
@@ -0,0 +1,72 @@
+package memorypipe
+
+import (
+	"io"
+)
+
+// msg represents an internal structure sent between the pipes.
+type msg struct {
+	data []byte
+	err  error
+}
+
+// pipe provides a bidirectional pipe compatible with io.ReadWriteCloser interface.
+// Note, however, that it does not behave exactly how one would expect an io.ReadWriteCloser to
+// behave. Specifically the Close() function does not close the pipe, but instead delivers an io.EOF
+// error to the next reader. After which it can be read again to receive new data. This means the
+// pipe can be closed multiple times. Each time it indicates that one particular session has ended.
+// The reason for this is to emulate the WebsocketIO's behaviour by allowing a single persistent
+// connection to be used for multiple sessions.
+type pipe struct {
+	ch       chan msg
+	otherEnd *pipe
+}
+
+// Read reads from the pipe into p. Returns number of bytes read and any errors.
+func (p *pipe) Read(b []byte) (int, error) {
+	msg := <-p.ch
+	if msg.err == io.EOF {
+		return -1, msg.err
+	}
+	n := copy(b, msg.data)
+	return n, msg.err
+}
+
+// Write writes to the pipe from p. Returns number of bytes written and any errors.
+func (p *pipe) Write(b []byte) (int, error) {
+	msg := msg{
+		data: append(b[:0:0], b...), // Create copy of b in case it is modified externally.
+		err:  nil,
+	}
+	p.otherEnd.ch <- msg // Send msg to the other side's Read function.
+	return len(msg.data), msg.err
+}
+
+// Close is unusual in that it doesn't actually close the pipe. Instead it sends an io.EOF error
+// to the other side's Read function. This is so the other side can detect that a session has ended.
+// Each call to Close will indicate to the other side that a session has ended, whilst allowing the
+// reuse of a single persistent pipe for multiple sessions.
+func (p *pipe) Close() error {
+	p.otherEnd.ch <- msg{
+		data: nil,
+		err:  io.EOF, // Indicates to the other side's Read function that session has ended.
+	}
+	return nil
+}
+
+// NewPipePair returns a pair of io.ReadWriterCloser pipes that are connected together such that
+// writes to one will appear as reads on the other and vice versa. Calling Close() on one end will
+// indicate to the other end that the session has ended.
+func NewPipePair() (io.ReadWriteCloser, io.ReadWriteCloser) {
+	aEnd := &pipe{
+		ch: make(chan msg, 1),
+	}
+
+	bEnd := &pipe{
+		ch: make(chan msg, 1),
+	}
+
+	aEnd.otherEnd = bEnd
+	bEnd.otherEnd = aEnd
+	return aEnd, bEnd
+}

From 126de79bafff4e082cac3b078e674d0fc3dad7c9 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 30 Oct 2019 13:29:16 +0000
Subject: [PATCH 2/9] lxd/migrate/storage/volumes: Updates use of migrate
 functions

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

diff --git a/lxd/migrate_storage_volumes.go b/lxd/migrate_storage_volumes.go
index ce232d9f65..a60ea178ba 100644
--- a/lxd/migrate_storage_volumes.go
+++ b/lxd/migrate_storage_volumes.go
@@ -156,7 +156,7 @@ func (s *migrationSourceWs) DoStorage(state *state.State, poolName string, volNa
 			Snapshots:     snapshotNames,
 		}
 
-		err = pool.MigrateCustomVolume(&shared.WebsocketIO{Conn: s.fsConn}, volSourceArgs, migrateOp)
+		err = pool.MigrateCustomVolume(&shared.WebsocketIO{Conn: s.fsConn}, volSourceArgs, true, migrateOp)
 		if err != nil {
 			go s.sendControl(err)
 			return err
@@ -371,7 +371,7 @@ func (c *migrationSink) DoStorage(state *state.State, poolName string, req *api.
 				}
 			}
 
-			return pool.CreateCustomVolumeFromMigration(&shared.WebsocketIO{Conn: conn}, volTargetArgs, op)
+			return pool.CreateCustomVolumeFromMigration(&shared.WebsocketIO{Conn: conn}, volTargetArgs, true, op)
 		}
 	} else {
 		// Setup legacy storage migration sink if destination pool isn't supported yet by

From b4b678d07c379741d0a9ee89ff301b38923a6a49 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 30 Oct 2019 13:31:24 +0000
Subject: [PATCH 3/9] lxd/storage/backend/lxd: Updates
 CreateCustomVolumeFromCopy to use migration logic

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

diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go
index 277c2b1f4f..368f7f5173 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -11,6 +11,7 @@ import (
 	"github.com/lxc/lxd/lxd/operations"
 	"github.com/lxc/lxd/lxd/state"
 	"github.com/lxc/lxd/lxd/storage/drivers"
+	"github.com/lxc/lxd/lxd/storage/memorypipe"
 	"github.com/lxc/lxd/shared"
 	"github.com/lxc/lxd/shared/api"
 )
@@ -273,12 +274,6 @@ func (b *lxdBackend) CreateCustomVolume(volName, desc string, config map[string]
 // CreateCustomVolumeFromCopy creates a custom volume from an existing custom volume.
 // It copies the snapshots from the source volume by default, but can be disabled if requested.
 func (b *lxdBackend) CreateCustomVolumeFromCopy(volName, desc string, config map[string]string, srcPoolName, srcVolName string, srcVolOnly bool, op *operations.Operation) error {
-	// Default to copying snapshots too, but if VolumeOnly is supplied then we only copy volume.
-	copySnapshots := true
-	if srcVolOnly {
-		copySnapshots = false
-	}
-
 	// Setup the source pool backend instance.
 	var srcPool *lxdBackend
 	if b.name == srcPoolName {
@@ -319,60 +314,72 @@ func (b *lxdBackend) CreateCustomVolumeFromCopy(volName, desc string, config map
 		desc = srcVolRow.Description
 	}
 
-	// Check the supplied config and remove any fields not relevant for destination pool type.
-	err = b.driver.ValidateVolume(config, true)
-	if err != nil {
-		return err
-	}
+	// If we are copying snapshots, retrieve a list of snapshots from source volume.
+	snapshotNames := []string{}
+	if !srcVolOnly {
+		snapshots, err := VolumeSnapshotsGet(b.state, srcPoolName, srcVolName, db.StoragePoolVolumeTypeCustom)
+		if err != nil {
+			return err
+		}
 
-	// Create slice to record DB volumes created if revert needed later.
-	revertDBVolumes := []string{}
-	defer func() {
-		// Remove any DB volume rows created if we are reverting.
-		for _, volName := range revertDBVolumes {
-			b.state.Cluster.StoragePoolVolumeDelete("default", volName, db.StoragePoolVolumeTypeCustom, b.ID())
+		for _, snapshot := range snapshots {
+			_, snapShotName, _ := shared.ContainerGetParentAndSnapshotName(snapshot.Name)
+			snapshotNames = append(snapshotNames, snapShotName)
 		}
-	}()
+	}
 
-	// Create database entry for new storage volume.
-	err = VolumeDBCreate(b.state, b.name, volName, desc, db.StoragePoolVolumeTypeNameCustom, false, config)
+	// Create 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(drivers.ContentTypeFS)
+	offerHeader := migration.TypesToHeader(offeredTypes...)
+	migrationType, err := migration.MatchTypes(offerHeader, b.MigrationTypes(drivers.ContentTypeFS))
 	if err != nil {
-		return err
+		return fmt.Errorf("Failed to neogotiate copy migration type: %v", err)
 	}
 
-	revertDBVolumes = append(revertDBVolumes, volName)
+	// 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.MigrateCustomVolume(aEnd, migration.VolumeSourceArgs{
+			Name:          srcVolName,
+			Snapshots:     snapshotNames,
+			MigrationType: migrationType,
+		}, false, op) // Do not use a progress tracker on sender.
 
-	if copySnapshots {
-		// If we are copying snapshots, retrieve a list of snapshots from source volume.
-		snapshots, err := VolumeSnapshotsGet(b.state, srcPoolName, volName, db.StoragePoolVolumeTypeCustom)
-		if err != nil {
-			return err
-		}
+		aEndErrCh <- err
+	}()
 
-		// Create a database entry and copy the volume for each snapshot.
-		for _, srcSnapshot := range snapshots {
-			// Convert the source snapshot volume name into the new snapshot volume name.
-			_, snapName, _ := shared.ContainerGetParentAndSnapshotName(srcSnapshot.Name)
-			newSnapshotName := drivers.GetSnapshotVolumeName(volName, snapName)
+	go func() {
+		err := b.CreateCustomVolumeFromMigration(bEnd, migration.VolumeTargetArgs{
+			Name:          volName,
+			Description:   desc,
+			Config:        config,
+			Snapshots:     snapshotNames,
+			MigrationType: migrationType,
+		}, true, op) // Do use a progress tracker on receiver.
 
-			// Create database entry for new storage volume.
-			err = VolumeDBCreate(b.state, b.name, newSnapshotName, srcSnapshot.Description, db.StoragePoolVolumeTypeNameCustom, true, config)
-			if err != nil {
-				return err
-			}
+		bEndErrCh <- err
+	}()
 
-			revertDBVolumes = append(revertDBVolumes, newSnapshotName)
-		}
+	// Capture errors from the sender and receiver from their result channels.
+	errs := []error{}
+	aEndErr := <-aEndErrCh
+	if aEndErr != nil {
+		errs = append(errs, aEndErr)
 	}
 
-	srcVol := srcPool.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, srcVolName, nil)
-	targetVol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volName, config)
-	err = b.driver.CreateVolumeFromCopy(targetVol, srcVol, copySnapshots, op)
-	if err != nil {
-		return err
+	bEndErr := <-bEndErrCh
+	if bEndErr != nil {
+		errs = append(errs, bEndErr)
+	}
+
+	if len(errs) > 0 {
+		return fmt.Errorf("Create custom volume from copy failed: %v", errs)
 	}
 
-	revertDBVolumes = nil // Don't revert DB volumes.
 	return nil
 }
 

From 786215e75dabffc672cd3abd467a967cc4efb80b Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 30 Oct 2019 13:31:51 +0000
Subject: [PATCH 4/9] lxd/storage/backend/lxd: Updates migration functions to
 accept progress tracker indicator

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

diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go
index 368f7f5173..7216bb7932 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -384,9 +384,9 @@ func (b *lxdBackend) CreateCustomVolumeFromCopy(volName, desc string, config map
 }
 
 // MigrateCustomVolume sends a volume for migration.
-func (b *lxdBackend) MigrateCustomVolume(conn io.ReadWriteCloser, args migration.VolumeSourceArgs, op *operations.Operation) error {
+func (b *lxdBackend) MigrateCustomVolume(conn io.ReadWriteCloser, args migration.VolumeSourceArgs, trackProgress bool, op *operations.Operation) error {
 	vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, args.Name, nil)
-	err := b.driver.MigrateVolume(vol, conn, args, op)
+	err := b.driver.MigrateVolume(vol, conn, args, trackProgress, op)
 	if err != nil {
 		return err
 	}
@@ -395,7 +395,7 @@ func (b *lxdBackend) MigrateCustomVolume(conn io.ReadWriteCloser, args migration
 }
 
 // CreateCustomVolumeFromMigration receives a volume being migrated.
-func (b *lxdBackend) CreateCustomVolumeFromMigration(conn io.ReadWriteCloser, args migration.VolumeTargetArgs, op *operations.Operation) error {
+func (b *lxdBackend) CreateCustomVolumeFromMigration(conn io.ReadWriteCloser, args migration.VolumeTargetArgs, trackProgress bool, op *operations.Operation) error {
 	// Create slice to record DB volumes created if revert needed later.
 	revertDBVolumes := []string{}
 	defer func() {
@@ -434,7 +434,7 @@ 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)
+	err = b.driver.CreateVolumeFromMigration(vol, conn, args, trackProgress, op)
 	if err != nil {
 		return nil
 	}

From e752afc647705551d6bbb4c789e55c14ca36ffa5 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 30 Oct 2019 13:32:26 +0000
Subject: [PATCH 5/9] lxd/storage/backend/mock: Updates migration functions to
 accept progress tracker indicator

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

diff --git a/lxd/storage/backend_mock.go b/lxd/storage/backend_mock.go
index 86562bc73e..d2987626af 100644
--- a/lxd/storage/backend_mock.go
+++ b/lxd/storage/backend_mock.go
@@ -168,11 +168,11 @@ func (b *mockBackend) DeleteCustomVolume(volName string, op *operations.Operatio
 	return nil
 }
 
-func (b *mockBackend) MigrateCustomVolume(conn io.ReadWriteCloser, args migration.VolumeSourceArgs, op *operations.Operation) error {
+func (b *mockBackend) MigrateCustomVolume(conn io.ReadWriteCloser, args migration.VolumeSourceArgs, trackProgress bool, op *operations.Operation) error {
 	return nil
 }
 
-func (b *mockBackend) CreateCustomVolumeFromMigration(conn io.ReadWriteCloser, args migration.VolumeTargetArgs, op *operations.Operation) error {
+func (b *mockBackend) CreateCustomVolumeFromMigration(conn io.ReadWriteCloser, args migration.VolumeTargetArgs, trackProgress bool, op *operations.Operation) error {
 	return nil
 }
 

From b78993cf27476721627e061ee7bc790eb054416a Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 30 Oct 2019 13:33:02 +0000
Subject: [PATCH 6/9] lxd/storage/drivers/driver/common: Improves comment

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

diff --git a/lxd/storage/drivers/driver_common.go b/lxd/storage/drivers/driver_common.go
index f549975c3f..b2298ff330 100644
--- a/lxd/storage/drivers/driver_common.go
+++ b/lxd/storage/drivers/driver_common.go
@@ -70,8 +70,8 @@ func (d *common) validateVolume(volConfig map[string]string, driverRules map[str
 	return nil
 }
 
-// MigrationType returns the type of transfer method used when doing migrations between pools
-// of the same type.
+// MigrationType returns the type of transfer methods to be used when doing migrations between pools
+// in preference order.
 func (d *common) MigrationTypes(contentType ContentType) []migration.Type {
 	if contentType != ContentTypeFS {
 		return nil

From 0f3fa0c3b7ac54ccb2d9c01956b280878cd1e01b Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 30 Oct 2019 13:33:32 +0000
Subject: [PATCH 7/9] lxd/storage/drivers/driver/dir: Updates migration
 functions to accept progress tracker indicator

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

diff --git a/lxd/storage/drivers/driver_dir.go b/lxd/storage/drivers/driver_dir.go
index 19e856df35..c9e3cbd28f 100644
--- a/lxd/storage/drivers/driver_dir.go
+++ b/lxd/storage/drivers/driver_dir.go
@@ -15,6 +15,7 @@ import (
 	"github.com/lxc/lxd/lxd/storage/quota"
 	"github.com/lxc/lxd/shared"
 	"github.com/lxc/lxd/shared/api"
+	"github.com/lxc/lxd/shared/ioprogress"
 	"github.com/lxc/lxd/shared/units"
 )
 
@@ -184,7 +185,7 @@ func (d *dir) CreateVolume(vol Volume, filler func(path string) error, op *opera
 }
 
 // MigrateVolume sends a volume for migration.
-func (d *dir) MigrateVolume(vol Volume, conn io.ReadWriteCloser, volSrcArgs migration.VolumeSourceArgs, op *operations.Operation) error {
+func (d *dir) MigrateVolume(vol Volume, conn io.ReadWriteCloser, volSrcArgs migration.VolumeSourceArgs, trackProgress bool, op *operations.Operation) error {
 	if volSrcArgs.MigrationType.FSType != migration.MigrationFSType_RSYNC {
 		return fmt.Errorf("Migration type not supported")
 	}
@@ -199,7 +200,10 @@ func (d *dir) MigrateVolume(vol Volume, conn io.ReadWriteCloser, volSrcArgs migr
 
 		// Send snapshot to recipient (ensure local snapshot volume is mounted if needed).
 		err = snapshot.MountTask(func(mountPath string, op *operations.Operation) error {
-			wrapper := migration.ProgressTracker(op, "fs_progress", snapshot.name)
+			var wrapper *ioprogress.ProgressTracker
+			if trackProgress {
+				wrapper = migration.ProgressTracker(op, "fs_progress", snapshot.name)
+			}
 			path := shared.AddSlash(mountPath)
 			return rsync.Send(snapshot.name, path, conn, wrapper, volSrcArgs.MigrationType.Features, bwlimit, d.state.OS.ExecPath)
 		}, op)
@@ -210,14 +214,17 @@ func (d *dir) MigrateVolume(vol Volume, conn io.ReadWriteCloser, volSrcArgs migr
 
 	// Send volume to recipient (ensure local volume is mounted if needed).
 	return vol.MountTask(func(mountPath string, op *operations.Operation) error {
-		wrapper := migration.ProgressTracker(op, "fs_progress", vol.name)
+		var wrapper *ioprogress.ProgressTracker
+		if trackProgress {
+			wrapper = migration.ProgressTracker(op, "fs_progress", vol.name)
+		}
 		path := shared.AddSlash(mountPath)
 		return rsync.Send(vol.name, path, conn, wrapper, volSrcArgs.MigrationType.Features, bwlimit, d.state.OS.ExecPath)
 	}, op)
 }
 
 // CreateVolumeFromMigration creates a volume being sent via a migration.
-func (d *dir) CreateVolumeFromMigration(vol Volume, conn io.ReadWriteCloser, volTargetArgs migration.VolumeTargetArgs, op *operations.Operation) error {
+func (d *dir) CreateVolumeFromMigration(vol Volume, conn io.ReadWriteCloser, volTargetArgs migration.VolumeTargetArgs, trackProgress bool, op *operations.Operation) error {
 	if vol.contentType != ContentTypeFS {
 		return fmt.Errorf("Content type not supported")
 	}
@@ -266,7 +273,10 @@ func (d *dir) CreateVolumeFromMigration(vol Volume, conn io.ReadWriteCloser, vol
 
 		// Receive snapshot from sender (ensure local snapshot volume is mounted if needed).
 		err = snapshot.MountTask(func(mountPath string, op *operations.Operation) error {
-			wrapper := migration.ProgressTracker(op, "fs_progress", snapshot.name)
+			var wrapper *ioprogress.ProgressTracker
+			if trackProgress {
+				wrapper = migration.ProgressTracker(op, "fs_progress", snapshot.name)
+			}
 			path := shared.AddSlash(mountPath)
 			return rsync.Recv(path, conn, wrapper, volTargetArgs.MigrationType.Features)
 		}, op)
@@ -299,7 +309,10 @@ func (d *dir) CreateVolumeFromMigration(vol Volume, conn io.ReadWriteCloser, vol
 
 	// Receive volume from sender (ensure local volume is mounted if needed).
 	err = vol.MountTask(func(mountPath string, op *operations.Operation) error {
-		wrapper := migration.ProgressTracker(op, "fs_progress", vol.name)
+		var wrapper *ioprogress.ProgressTracker
+		if trackProgress {
+			wrapper = migration.ProgressTracker(op, "fs_progress", vol.name)
+		}
 		path := shared.AddSlash(mountPath)
 		return rsync.Recv(path, conn, wrapper, volTargetArgs.MigrationType.Features)
 	}, op)

From 0737102ab3e9e8ad8e2a2eef79c69a7d4bb8d018 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 30 Oct 2019 13:33:58 +0000
Subject: [PATCH 8/9] lxd/storage/drivers/interface: Updates migration
 functions to accept progress tracker indicator

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

diff --git a/lxd/storage/drivers/interface.go b/lxd/storage/drivers/interface.go
index c7d79fd84b..2e6024982c 100644
--- a/lxd/storage/drivers/interface.go
+++ b/lxd/storage/drivers/interface.go
@@ -59,6 +59,6 @@ type Driver interface {
 
 	// Migration.
 	MigrationTypes(contentType ContentType) []migration.Type
-	MigrateVolume(vol Volume, conn io.ReadWriteCloser, volSrcArgs migration.VolumeSourceArgs, op *operations.Operation) error
-	CreateVolumeFromMigration(vol Volume, conn io.ReadWriteCloser, volTargetArgs migration.VolumeTargetArgs, op *operations.Operation) error
+	MigrateVolume(vol Volume, conn io.ReadWriteCloser, volSrcArgs migration.VolumeSourceArgs, trackProgress bool, op *operations.Operation) error
+	CreateVolumeFromMigration(vol Volume, conn io.ReadWriteCloser, volTargetArgs migration.VolumeTargetArgs, trackProgress bool, op *operations.Operation) error
 }

From 05f3e1a478f3813abf945657f591f63b5af4e6d9 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 30 Oct 2019 13:34:18 +0000
Subject: [PATCH 9/9] lxd/storage/interfaces: Updates migration functions to
 accept progress tracker indicator

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 d1d3cbdbba..3412d03351 100644
--- a/lxd/storage/interfaces.go
+++ b/lxd/storage/interfaces.go
@@ -88,6 +88,6 @@ type Pool interface {
 
 	// Custom volume migration.
 	MigrationTypes(contentType drivers.ContentType) []migration.Type
-	CreateCustomVolumeFromMigration(conn io.ReadWriteCloser, args migration.VolumeTargetArgs, op *operations.Operation) error
-	MigrateCustomVolume(conn io.ReadWriteCloser, args migration.VolumeSourceArgs, op *operations.Operation) error
+	CreateCustomVolumeFromMigration(conn io.ReadWriteCloser, args migration.VolumeTargetArgs, trackProgress bool, op *operations.Operation) error
+	MigrateCustomVolume(conn io.ReadWriteCloser, args migration.VolumeSourceArgs, trackProgress bool, op *operations.Operation) error
 }


More information about the lxc-devel mailing list