[lxc-devel] [lxd/master] lxd/migration: Cleanup feature negotiation

stgraber on Github lxc-bot at linuxcontainers.org
Fri Nov 30 01:00:27 UTC 2018


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 354 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20181130/5f24fe7e/attachment.bin>
-------------- next part --------------
From e514b2466705a6318b716badc4523251e06e84fa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Thu, 29 Nov 2018 19:57:35 -0500
Subject: [PATCH] lxd/migration: Cleanup feature negotiation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/migrate.go                 |  7 ++--
 lxd/migrate_container.go       | 59 ++++++++--------------------------
 lxd/migrate_storage_volumes.go | 50 ++++++----------------------
 lxd/migration/utils.go         | 43 +++++++++++++++++++++++++
 lxd/rsync.go                   | 34 +++++++++++++++-----
 lxd/storage_migration.go       | 32 +++++++++---------
 lxd/storage_zfs.go             | 16 ++++++---
 7 files changed, 123 insertions(+), 118 deletions(-)
 create mode 100644 lxd/migration/utils.go

diff --git a/lxd/migrate.go b/lxd/migrate.go
index 2b4bcc2437..ee20aab7f9 100644
--- a/lxd/migrate.go
+++ b/lxd/migrate.go
@@ -250,7 +250,6 @@ type migrationSink struct {
 	dialer       websocket.Dialer
 	allConnected chan bool
 	push         bool
-	rsyncArgs    []string
 	refresh      bool
 }
 
@@ -273,7 +272,7 @@ type MigrationSinkArgs struct {
 	Storage storage
 
 	// Transport specific fields
-	RsyncArgs []string
+	RsyncFeatures []string
 }
 
 type MigrationSourceArgs struct {
@@ -282,8 +281,8 @@ type MigrationSourceArgs struct {
 	ContainerOnly bool
 
 	// Transport specific fields
-	RsyncArgs []string
-	ZfsArgs   []string
+	RsyncFeatures []string
+	ZfsFeatures   []string
 }
 
 func (c *migrationSink) connectWithSecret(secret string) (*websocket.Conn, error) {
diff --git a/lxd/migrate_container.go b/lxd/migrate_container.go
index 5ae8bb5282..17ae799972 100644
--- a/lxd/migrate_container.go
+++ b/lxd/migrate_container.go
@@ -220,7 +220,7 @@ type preDumpLoopArgs struct {
 	preDumpDir    string
 	dumpDir       string
 	final         bool
-	rsyncArgs     []string
+	rsyncFeatures []string
 }
 
 // The function preDumpLoop is the main logic behind the pre-copy migration.
@@ -251,7 +251,7 @@ func (s *migrationSourceWs) preDumpLoop(args *preDumpLoopArgs) (bool, error) {
 	// Send the pre-dump.
 	ctName, _, _ := containerGetParentAndSnapshotName(s.container.Name())
 	state := s.container.DaemonState()
-	err = RsyncSend(ctName, shared.AddSlash(args.checkpointDir), s.criuConn, nil, args.rsyncArgs, args.bwlimit, state.OS.ExecPath)
+	err = RsyncSend(ctName, shared.AddSlash(args.checkpointDir), s.criuConn, nil, args.rsyncFeatures, args.bwlimit, state.OS.ExecPath)
 	if err != nil {
 		return final, err
 	}
@@ -413,42 +413,22 @@ func (s *migrationSourceWs) Do(migrateOp *operation) error {
 	}
 
 	// Handle rsync options
-	rsyncArgs := []string{}
-	rsyncFeatures := header.GetRsyncFeatures()
-	if !rsyncFeatures.GetBidirectional() {
+	rsyncFeatures := header.GetRsyncFeaturesSlice()
+	if !shared.StringInSlice("bidirectional", rsyncFeatures) {
 		// If no bi-directional support, assume LXD 3.7 level
 		// NOTE: Do NOT extend this list of arguments
-		rsyncArgs = append(rsyncArgs, "--xattrs")
-		rsyncArgs = append(rsyncArgs, "--delete")
-		rsyncArgs = append(rsyncArgs, "--compress")
-		rsyncArgs = append(rsyncArgs, "--compress-level=2")
-	} else {
-		if rsyncFeatures.GetXattrs() {
-			rsyncArgs = append(rsyncArgs, "--xattrs")
-		}
-		if rsyncFeatures.GetDelete() {
-			rsyncArgs = append(rsyncArgs, "--delete")
-		}
-		if rsyncFeatures.GetCompress() {
-			rsyncArgs = append(rsyncArgs, "--compress")
-			rsyncArgs = append(rsyncArgs, "--compress-level=2")
-		}
+		rsyncFeatures = []string{"xattrs", "delete", "compress"}
 	}
 
 	// Handle zfs options
-	zfsArgs := []string{}
-	zfsFeatures := header.GetZfsFeatures()
-	if zfsFeatures.GetCompress() && len(zfsVersion) >= 3 && zfsVersion[0:3] != "0.6" {
-		zfsArgs = append(zfsArgs, "-c")
-		zfsArgs = append(zfsArgs, "-L")
-	}
+	zfsFeatures := header.GetZfsFeaturesSlice()
 
 	// Set source args
 	sourceArgs := MigrationSourceArgs{
 		Container:     s.container,
 		ContainerOnly: s.containerOnly,
-		RsyncArgs:     rsyncArgs,
-		ZfsArgs:       zfsArgs,
+		RsyncFeatures: rsyncFeatures,
+		ZfsFeatures:   zfsFeatures,
 	}
 
 	// Initialize storage driver
@@ -608,7 +588,7 @@ func (s *migrationSourceWs) Do(migrateOp *operation) error {
 						preDumpDir:    preDumpDir,
 						dumpDir:       dumpDir,
 						final:         final,
-						rsyncArgs:     rsyncArgs,
+						rsyncFeatures: rsyncFeatures,
 					}
 					final, err = s.preDumpLoop(&loop_args)
 					if err != nil {
@@ -679,7 +659,7 @@ func (s *migrationSourceWs) Do(migrateOp *operation) error {
 		 */
 		ctName, _, _ := containerGetParentAndSnapshotName(s.container.Name())
 		state := s.container.DaemonState()
-		err = RsyncSend(ctName, shared.AddSlash(checkpointDir), s.criuConn, nil, rsyncArgs, bwlimit, state.OS.ExecPath)
+		err = RsyncSend(ctName, shared.AddSlash(checkpointDir), s.criuConn, nil, rsyncFeatures, bwlimit, state.OS.ExecPath)
 		if err != nil {
 			return abort(err)
 		}
@@ -833,18 +813,7 @@ func (c *migrationSink) Do(migrateOp *operation) error {
 	}
 
 	// Handle rsync options
-	c.rsyncArgs = []string{}
-	rsyncFeatures := header.GetRsyncFeatures()
-	if rsyncFeatures.GetXattrs() {
-		c.rsyncArgs = append(c.rsyncArgs, "--xattrs")
-	}
-	if rsyncFeatures.GetDelete() {
-		c.rsyncArgs = append(c.rsyncArgs, "--delete")
-	}
-	if rsyncFeatures.GetCompress() {
-		c.rsyncArgs = append(c.rsyncArgs, "--compress")
-		c.rsyncArgs = append(c.rsyncArgs, "--compress-level=2")
-	}
+	rsyncFeatures := header.GetRsyncFeaturesSlice()
 
 	live := c.src.live
 	if c.push {
@@ -1004,7 +973,7 @@ func (c *migrationSink) Do(migrateOp *operation) error {
 				Idmap:         srcIdmap,
 				Live:          sendFinalFsDelta,
 				Refresh:       c.refresh,
-				RsyncArgs:     c.rsyncArgs,
+				RsyncFeatures: rsyncFeatures,
 				Snapshots:     snapshots,
 			}
 
@@ -1048,7 +1017,7 @@ func (c *migrationSink) Do(migrateOp *operation) error {
 				for !sync.GetFinalPreDump() {
 					logger.Debugf("About to receive rsync")
 					// Transfer a CRIU pre-dump
-					err = RsyncRecv(shared.AddSlash(imagesDir), criuConn, nil, c.rsyncArgs)
+					err = RsyncRecv(shared.AddSlash(imagesDir), criuConn, nil, rsyncFeatures)
 					if err != nil {
 						restore <- err
 						return
@@ -1076,7 +1045,7 @@ func (c *migrationSink) Do(migrateOp *operation) error {
 			}
 
 			// Final CRIU dump
-			err = RsyncRecv(shared.AddSlash(imagesDir), criuConn, nil, c.rsyncArgs)
+			err = RsyncRecv(shared.AddSlash(imagesDir), criuConn, nil, rsyncFeatures)
 			if err != nil {
 				restore <- err
 				return
diff --git a/lxd/migrate_storage_volumes.go b/lxd/migrate_storage_volumes.go
index 3d0f76b836..96e26c429c 100644
--- a/lxd/migrate_storage_volumes.go
+++ b/lxd/migrate_storage_volumes.go
@@ -79,40 +79,20 @@ func (s *migrationSourceWs) DoStorage(migrateOp *operation) error {
 	}
 
 	// Handle rsync options
-	rsyncArgs := []string{}
-	rsyncFeatures := header.GetRsyncFeatures()
-	if !rsyncFeatures.GetBidirectional() {
+	rsyncFeatures := header.GetRsyncFeaturesSlice()
+	if !shared.StringInSlice("bidirectional", rsyncFeatures) {
 		// If no bi-directional support, assume LXD 3.7 level
 		// NOTE: Do NOT extend this list of arguments
-		rsyncArgs = append(rsyncArgs, "--xattrs")
-		rsyncArgs = append(rsyncArgs, "--delete")
-		rsyncArgs = append(rsyncArgs, "--compress")
-		rsyncArgs = append(rsyncArgs, "--compress-level=2")
-	} else {
-		if rsyncFeatures.GetXattrs() {
-			rsyncArgs = append(rsyncArgs, "--xattrs")
-		}
-		if rsyncFeatures.GetDelete() {
-			rsyncArgs = append(rsyncArgs, "--delete")
-		}
-		if rsyncFeatures.GetCompress() {
-			rsyncArgs = append(rsyncArgs, "--compress")
-			rsyncArgs = append(rsyncArgs, "--compress-level=2")
-		}
+		rsyncFeatures = []string{"xattrs", "delete", "compress"}
 	}
 
 	// Handle zfs options
-	zfsArgs := []string{}
-	zfsFeatures := header.GetZfsFeatures()
-	if zfsFeatures.GetCompress() && len(zfsVersion) >= 3 && zfsVersion[0:3] != "0.6" {
-		zfsArgs = append(zfsArgs, "-c")
-		zfsArgs = append(zfsArgs, "-L")
-	}
+	zfsFeatures := header.GetZfsFeaturesSlice()
 
 	// Set source args
 	sourceArgs := MigrationSourceArgs{
-		RsyncArgs: rsyncArgs,
-		ZfsArgs:   zfsArgs,
+		RsyncFeatures: rsyncFeatures,
+		ZfsFeatures:   zfsFeatures,
 	}
 
 	driver, fsErr := s.storage.StorageMigrationSource(sourceArgs)
@@ -288,24 +268,12 @@ func (c *migrationSink) DoStorage(migrateOp *operation) error {
 		resp.Fs = &myType
 	}
 
-	rsyncFeatures := header.GetRsyncFeatures()
-
 	// Handle rsync options
-	rsyncArgs := []string{}
-	if rsyncFeatures.GetXattrs() {
-		rsyncArgs = append(rsyncArgs, "--xattrs")
-	}
-	if rsyncFeatures.GetDelete() {
-		rsyncArgs = append(rsyncArgs, "--delete")
-	}
-	if rsyncFeatures.GetCompress() {
-		rsyncArgs = append(rsyncArgs, "--compress")
-		rsyncArgs = append(rsyncArgs, "--compress-level=2")
-	}
+	rsyncFeatures := header.GetRsyncFeaturesSlice()
 
 	args := MigrationSinkArgs{
-		Storage:   c.dest.storage,
-		RsyncArgs: rsyncArgs,
+		Storage:       c.dest.storage,
+		RsyncFeatures: rsyncFeatures,
 	}
 
 	err = sender(&resp)
diff --git a/lxd/migration/utils.go b/lxd/migration/utils.go
new file mode 100644
index 0000000000..f7843476b8
--- /dev/null
+++ b/lxd/migration/utils.go
@@ -0,0 +1,43 @@
+package migration
+
+func (m *MigrationHeader) GetRsyncFeaturesSlice() []string {
+	features := []string{}
+	if m == nil {
+		return features
+	}
+
+	if m.RsyncFeatures != nil {
+		if m.RsyncFeatures.Xattrs != nil && *m.RsyncFeatures.Xattrs == true {
+			features = append(features, "xattrs")
+		}
+
+		if m.RsyncFeatures.Delete != nil && *m.RsyncFeatures.Delete == true {
+			features = append(features, "delete")
+		}
+
+		if m.RsyncFeatures.Compress != nil && *m.RsyncFeatures.Compress == true {
+			features = append(features, "compress")
+		}
+
+		if m.RsyncFeatures.Bidirectional != nil && *m.RsyncFeatures.Bidirectional == true {
+			features = append(features, "bidirectional")
+		}
+	}
+
+	return features
+}
+
+func (m *MigrationHeader) GetZfsFeaturesSlice() []string {
+	features := []string{}
+	if m == nil {
+		return features
+	}
+
+	if m.ZfsFeatures != nil {
+		if m.ZfsFeatures.Compress != nil && *m.ZfsFeatures.Compress == true {
+			features = append(features, "compress")
+		}
+	}
+
+	return features
+}
diff --git a/lxd/rsync.go b/lxd/rsync.go
index e6bf3543ad..c6e3388ab9 100644
--- a/lxd/rsync.go
+++ b/lxd/rsync.go
@@ -62,7 +62,7 @@ func rsyncLocalCopy(source string, dest string, bwlimit string) (string, error)
 	return msg, nil
 }
 
-func rsyncSendSetup(name string, path string, bwlimit string, execPath string, extraArgs []string) (*exec.Cmd, net.Conn, io.ReadCloser, error) {
+func rsyncSendSetup(name string, path string, bwlimit string, execPath string, features []string) (*exec.Cmd, net.Conn, io.ReadCloser, error) {
 	/*
 	 * The way rsync works, it invokes a subprocess that does the actual
 	 * talking (given to it by a -E argument). Since there isn't an easy
@@ -112,8 +112,8 @@ func rsyncSendSetup(name string, path string, bwlimit string, execPath string, e
 		"--sparse",
 	}
 
-	if extraArgs != nil && len(extraArgs) > 0 {
-		args = append(args, extraArgs...)
+	if features != nil && len(features) > 0 {
+		args = append(args, rsyncFeatureArgs(features)...)
 	}
 
 	args = append(args, []string{
@@ -148,8 +148,8 @@ func rsyncSendSetup(name string, path string, bwlimit string, execPath string, e
 
 // RsyncSend sets up the sending half of an rsync, to recursively send the
 // directory pointed to by path over the websocket.
-func RsyncSend(name string, path string, conn *websocket.Conn, readWrapper func(io.ReadCloser) io.ReadCloser, extraArgs []string, bwlimit string, execPath string) error {
-	cmd, dataSocket, stderr, err := rsyncSendSetup(name, path, bwlimit, execPath, extraArgs)
+func RsyncSend(name string, path string, conn *websocket.Conn, readWrapper func(io.ReadCloser) io.ReadCloser, features []string, bwlimit string, execPath string) error {
+	cmd, dataSocket, stderr, err := rsyncSendSetup(name, path, bwlimit, execPath, features)
 	if err != nil {
 		return err
 	}
@@ -186,7 +186,7 @@ func RsyncSend(name string, path string, conn *websocket.Conn, readWrapper func(
 // RsyncRecv sets up the receiving half of the websocket to rsync (the other
 // half set up by RsyncSend), putting the contents in the directory specified
 // by path.
-func RsyncRecv(path string, conn *websocket.Conn, writeWrapper func(io.WriteCloser) io.WriteCloser, extraArgs []string) error {
+func RsyncRecv(path string, conn *websocket.Conn, writeWrapper func(io.WriteCloser) io.WriteCloser, features []string) error {
 	args := []string{
 		"--server",
 		"-vlogDtpre.iLsfx",
@@ -196,8 +196,8 @@ func RsyncRecv(path string, conn *websocket.Conn, writeWrapper func(io.WriteClos
 		"--sparse",
 	}
 
-	if extraArgs != nil && len(extraArgs) > 0 {
-		args = append(args, extraArgs...)
+	if features != nil && len(features) > 0 {
+		args = append(args, rsyncFeatureArgs(features)...)
 	}
 
 	args = append(args, []string{".", path}...)
@@ -246,3 +246,21 @@ func RsyncRecv(path string, conn *websocket.Conn, writeWrapper func(io.WriteClos
 
 	return err
 }
+
+func rsyncFeatureArgs(features []string) []string {
+	args := []string{}
+	if shared.StringInSlice("xattrs", features) {
+		args = append(args, "--xattrs")
+	}
+
+	if shared.StringInSlice("delete", features) {
+		args = append(args, "--delete")
+	}
+
+	if shared.StringInSlice("compress", features) {
+		args = append(args, "--compress")
+		args = append(args, "--compress-level=2")
+	}
+
+	return args
+}
diff --git a/lxd/storage_migration.go b/lxd/storage_migration.go
index 7ee15ed430..063da9ce9d 100644
--- a/lxd/storage_migration.go
+++ b/lxd/storage_migration.go
@@ -40,9 +40,9 @@ type MigrationStorageSourceDriver interface {
 }
 
 type rsyncStorageSourceDriver struct {
-	container container
-	snapshots []container
-	rsyncArgs []string
+	container     container
+	snapshots     []container
+	rsyncFeatures []string
 }
 
 func (s rsyncStorageSourceDriver) Snapshots() []container {
@@ -66,7 +66,7 @@ func (s rsyncStorageSourceDriver) SendStorageVolume(conn *websocket.Conn, op *op
 	path := getStoragePoolVolumeMountPoint(pool.Name, volume.Name)
 	path = shared.AddSlash(path)
 	logger.Debugf("Starting to send storage volume %s on storage pool %s from %s", volume.Name, pool.Name, path)
-	return RsyncSend(volume.Name, path, conn, wrapper, s.rsyncArgs, bwlimit, state.OS.ExecPath)
+	return RsyncSend(volume.Name, path, conn, wrapper, s.rsyncFeatures, bwlimit, state.OS.ExecPath)
 }
 
 func (s rsyncStorageSourceDriver) SendWhileRunning(conn *websocket.Conn, op *operation, bwlimit string, containerOnly bool) error {
@@ -85,7 +85,7 @@ func (s rsyncStorageSourceDriver) SendWhileRunning(conn *websocket.Conn, op *ope
 			path := send.Path()
 			wrapper := StorageProgressReader(op, "fs_progress", send.Name())
 			state := s.container.DaemonState()
-			err = RsyncSend(projectPrefix(s.container.Project(), ctName), shared.AddSlash(path), conn, wrapper, s.rsyncArgs, bwlimit, state.OS.ExecPath)
+			err = RsyncSend(projectPrefix(s.container.Project(), ctName), shared.AddSlash(path), conn, wrapper, s.rsyncFeatures, bwlimit, state.OS.ExecPath)
 			if err != nil {
 				return err
 			}
@@ -94,14 +94,14 @@ func (s rsyncStorageSourceDriver) SendWhileRunning(conn *websocket.Conn, op *ope
 
 	wrapper := StorageProgressReader(op, "fs_progress", s.container.Name())
 	state := s.container.DaemonState()
-	return RsyncSend(projectPrefix(s.container.Project(), ctName), shared.AddSlash(s.container.Path()), conn, wrapper, s.rsyncArgs, bwlimit, state.OS.ExecPath)
+	return RsyncSend(projectPrefix(s.container.Project(), ctName), shared.AddSlash(s.container.Path()), conn, wrapper, s.rsyncFeatures, bwlimit, state.OS.ExecPath)
 }
 
 func (s rsyncStorageSourceDriver) SendAfterCheckpoint(conn *websocket.Conn, bwlimit string) error {
 	ctName, _, _ := containerGetParentAndSnapshotName(s.container.Name())
 	// resync anything that changed between our first send and the checkpoint
 	state := s.container.DaemonState()
-	return RsyncSend(projectPrefix(s.container.Project(), ctName), shared.AddSlash(s.container.Path()), conn, nil, s.rsyncArgs, bwlimit, state.OS.ExecPath)
+	return RsyncSend(projectPrefix(s.container.Project(), ctName), shared.AddSlash(s.container.Path()), conn, nil, s.rsyncFeatures, bwlimit, state.OS.ExecPath)
 }
 
 func (s rsyncStorageSourceDriver) Cleanup() {
@@ -109,7 +109,7 @@ func (s rsyncStorageSourceDriver) Cleanup() {
 }
 
 func rsyncStorageMigrationSource(args MigrationSourceArgs) (MigrationStorageSourceDriver, error) {
-	return rsyncStorageSourceDriver{nil, nil, args.RsyncArgs}, nil
+	return rsyncStorageSourceDriver{nil, nil, args.RsyncFeatures}, nil
 }
 
 func rsyncRefreshSource(refreshSnapshots []string, args MigrationSourceArgs) (MigrationStorageSourceDriver, error) {
@@ -130,7 +130,7 @@ func rsyncRefreshSource(refreshSnapshots []string, args MigrationSourceArgs) (Mi
 		}
 	}
 
-	return rsyncStorageSourceDriver{args.Container, snapshots, args.RsyncArgs}, nil
+	return rsyncStorageSourceDriver{args.Container, snapshots, args.RsyncFeatures}, nil
 }
 
 func rsyncMigrationSource(args MigrationSourceArgs) (MigrationStorageSourceDriver, error) {
@@ -143,7 +143,7 @@ func rsyncMigrationSource(args MigrationSourceArgs) (MigrationStorageSourceDrive
 		}
 	}
 
-	return rsyncStorageSourceDriver{args.Container, snapshots, args.RsyncArgs}, nil
+	return rsyncStorageSourceDriver{args.Container, snapshots, args.RsyncFeatures}, nil
 }
 
 func snapshotProtobufToContainerArgs(project string, containerName string, snap *migration.Snapshot) db.ContainerArgs {
@@ -208,7 +208,7 @@ func rsyncStorageMigrationSink(conn *websocket.Conn, op *operation, args Migrati
 	path := getStoragePoolVolumeMountPoint(pool.Name, volume.Name)
 	path = shared.AddSlash(path)
 	logger.Debugf("Starting to receive storage volume %s on storage pool %s into %s", volume.Name, pool.Name, path)
-	return RsyncRecv(path, conn, wrapper, args.RsyncArgs)
+	return RsyncRecv(path, conn, wrapper, args.RsyncFeatures)
 }
 
 func rsyncMigrationSink(conn *websocket.Conn, op *operation, args MigrationSinkArgs) error {
@@ -285,7 +285,7 @@ func rsyncMigrationSink(conn *websocket.Conn, op *operation, args MigrationSinkA
 				}
 
 				wrapper := StorageProgressWriter(op, "fs_progress", s.Name())
-				if err := RsyncRecv(shared.AddSlash(s.Path()), conn, wrapper, args.RsyncArgs); err != nil {
+				if err := RsyncRecv(shared.AddSlash(s.Path()), conn, wrapper, args.RsyncFeatures); err != nil {
 					return err
 				}
 
@@ -297,7 +297,7 @@ func rsyncMigrationSink(conn *websocket.Conn, op *operation, args MigrationSinkA
 		}
 
 		wrapper := StorageProgressWriter(op, "fs_progress", args.Container.Name())
-		err = RsyncRecv(shared.AddSlash(args.Container.Path()), conn, wrapper, args.RsyncArgs)
+		err = RsyncRecv(shared.AddSlash(args.Container.Path()), conn, wrapper, args.RsyncFeatures)
 		if err != nil {
 			return err
 		}
@@ -335,7 +335,7 @@ func rsyncMigrationSink(conn *websocket.Conn, op *operation, args MigrationSinkA
 				}
 
 				wrapper := StorageProgressWriter(op, "fs_progress", snap.GetName())
-				err := RsyncRecv(shared.AddSlash(args.Container.Path()), conn, wrapper, args.RsyncArgs)
+				err := RsyncRecv(shared.AddSlash(args.Container.Path()), conn, wrapper, args.RsyncFeatures)
 				if err != nil {
 					return err
 				}
@@ -357,7 +357,7 @@ func rsyncMigrationSink(conn *websocket.Conn, op *operation, args MigrationSinkA
 		}
 
 		wrapper := StorageProgressWriter(op, "fs_progress", args.Container.Name())
-		err = RsyncRecv(shared.AddSlash(args.Container.Path()), conn, wrapper, args.RsyncArgs)
+		err = RsyncRecv(shared.AddSlash(args.Container.Path()), conn, wrapper, args.RsyncFeatures)
 		if err != nil {
 			return err
 		}
@@ -366,7 +366,7 @@ func rsyncMigrationSink(conn *websocket.Conn, op *operation, args MigrationSinkA
 	if args.Live {
 		/* now receive the final sync */
 		wrapper := StorageProgressWriter(op, "fs_progress", args.Container.Name())
-		err := RsyncRecv(shared.AddSlash(args.Container.Path()), conn, wrapper, args.RsyncArgs)
+		err := RsyncRecv(shared.AddSlash(args.Container.Path()), conn, wrapper, args.RsyncFeatures)
 		if err != nil {
 			return err
 		}
diff --git a/lxd/storage_zfs.go b/lxd/storage_zfs.go
index b1e587e288..a8d8a5033d 100644
--- a/lxd/storage_zfs.go
+++ b/lxd/storage_zfs.go
@@ -2543,7 +2543,7 @@ type zfsMigrationSourceDriver struct {
 	zfs              *storageZfs
 	runningSnapName  string
 	stoppedSnapName  string
-	zfsArgs          []string
+	zfsFeatures      []string
 }
 
 func (s *zfsMigrationSourceDriver) Snapshots() []container {
@@ -2554,7 +2554,15 @@ func (s *zfsMigrationSourceDriver) send(conn *websocket.Conn, zfsName string, zf
 	sourceParentName, _, _ := containerGetParentAndSnapshotName(s.container.Name())
 	poolName := s.zfs.getOnDiskPoolName()
 	args := []string{"send"}
-	args = append(args, s.zfsArgs...)
+
+	// Negotiated options
+	if s.zfsFeatures != nil && len(s.zfsFeatures) > 0 {
+		if shared.StringInSlice("compress", s.zfsFeatures) {
+			args = append(args, "-c")
+			args = append(args, "-L")
+		}
+	}
+
 	args = append(args, []string{fmt.Sprintf("%s/containers/%s@%s", poolName, projectPrefix(s.container.Project(), sourceParentName), zfsName)}...)
 	if zfsParent != "" {
 		args = append(args, "-i", fmt.Sprintf("%s/containers/%s@%s", poolName, projectPrefix(s.container.Project(), s.container.Name()), zfsParent))
@@ -2670,7 +2678,7 @@ func (s *storageZfs) MigrationSource(args MigrationSourceArgs) (MigrationStorage
 	* to send anything else, because that's all the user asked for.
 	 */
 	if args.Container.IsSnapshot() {
-		return &zfsMigrationSourceDriver{container: args.Container, zfs: s, zfsArgs: args.ZfsArgs}, nil
+		return &zfsMigrationSourceDriver{container: args.Container, zfs: s, zfsFeatures: args.ZfsFeatures}, nil
 	}
 
 	driver := zfsMigrationSourceDriver{
@@ -2678,7 +2686,7 @@ func (s *storageZfs) MigrationSource(args MigrationSourceArgs) (MigrationStorage
 		snapshots:        []container{},
 		zfsSnapshotNames: []string{},
 		zfs:              s,
-		zfsArgs:          args.ZfsArgs,
+		zfsFeatures:      args.ZfsFeatures,
 	}
 
 	if args.ContainerOnly {


More information about the lxc-devel mailing list