[lxc-devel] [lxd/master] fix zfs container copy
brauner on Github
lxc-bot at linuxcontainers.org
Thu Jun 8 20:33:23 UTC 2017
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 364 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20170608/1b919274/attachment.bin>
-------------- next part --------------
From b1eb7453d3911644a9b6d894de7e6dedd241b17d Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Thu, 8 Jun 2017 22:01:24 +0200
Subject: [PATCH 1/3] zfs: fix container copy
Closes #3395.
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
lxd/storage_zfs.go | 47 +++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 45 insertions(+), 2 deletions(-)
diff --git a/lxd/storage_zfs.go b/lxd/storage_zfs.go
index 37697fe63..dbe421525 100644
--- a/lxd/storage_zfs.go
+++ b/lxd/storage_zfs.go
@@ -958,7 +958,7 @@ func (s *storageZfs) copyWithSnapshots(target container, source container, paren
zfsSendCmd := exec.Command("zfs", args...)
targetSnapshotDataset := fmt.Sprintf("%s/containers/%s at snapshot-%s", poolName, targetParentName, targetSnapOnlyName)
- zfsRecvCmd := exec.Command("zfs", "receive", targetSnapshotDataset)
+ zfsRecvCmd := exec.Command("zfs", "receive", "-F", targetSnapshotDataset)
zfsRecvCmd.Stdin, _ = zfsSendCmd.StdoutPipe()
zfsRecvCmd.Stdout = os.Stdout
@@ -1019,8 +1019,9 @@ func (s *storageZfs) ContainerCopy(target container, source container, container
return err
}
+ prev := ""
+ prevSnapOnlyName := ""
for i, snap := range snapshots {
- prev := ""
if i > 0 {
prev = snapshots[i-1].Name()
}
@@ -1031,6 +1032,7 @@ func (s *storageZfs) ContainerCopy(target container, source container, container
}
_, snapOnlyName, _ := containerGetParentAndSnapshotName(snap.Name())
+ prevSnapOnlyName = snapOnlyName
newSnapName := fmt.Sprintf("%s/%s", target.Name(), snapOnlyName)
targetSnapshot, err := containerLoadByName(s.d, newSnapName)
if err != nil {
@@ -1043,6 +1045,47 @@ func (s *storageZfs) ContainerCopy(target container, source container, container
}
}
+ // send actual container
+ tmpSnapshotName := fmt.Sprintf("copy-send-%s", uuid.NewRandom().String())
+ err = s.zfsPoolVolumeSnapshotCreate(fmt.Sprintf("containers/%s", source.Name()), tmpSnapshotName)
+ if err != nil {
+ return err
+ }
+
+ poolName := s.getOnDiskPoolName()
+ currentSnapshotDataset := fmt.Sprintf("%s/containers/%s@%s", poolName, source.Name(), tmpSnapshotName)
+ args := []string{"send", currentSnapshotDataset}
+ if prevSnapOnlyName != "" {
+ parentSnapshotDataset := fmt.Sprintf("%s/containers/%s at snapshot-%s", poolName, source.Name(), prevSnapOnlyName)
+ args = append(args, "-i", parentSnapshotDataset)
+ }
+
+ zfsSendCmd := exec.Command("zfs", args...)
+ targetSnapshotDataset := fmt.Sprintf("%s/containers/%s@%s", poolName, target.Name(), tmpSnapshotName)
+ zfsRecvCmd := exec.Command("zfs", "receive", "-F", targetSnapshotDataset)
+
+ zfsRecvCmd.Stdin, _ = zfsSendCmd.StdoutPipe()
+ zfsRecvCmd.Stdout = os.Stdout
+ zfsRecvCmd.Stderr = os.Stderr
+
+ err = zfsRecvCmd.Start()
+ if err != nil {
+ return err
+ }
+
+ err = zfsSendCmd.Run()
+ if err != nil {
+ return err
+ }
+
+ err = zfsRecvCmd.Wait()
+ if err != nil {
+ return err
+ }
+
+ s.zfsPoolVolumeSnapshotDestroy(fmt.Sprintf("containers/%s", source.Name()), tmpSnapshotName)
+ s.zfsPoolVolumeSnapshotDestroy(fmt.Sprintf("containers/%s", target.Name()), tmpSnapshotName)
+
fs := fmt.Sprintf("containers/%s", target.Name())
err = s.zfsPoolVolumeSet(fs, "mountpoint", targetContainerMountPoint)
if err != nil {
From 17de1869158f22d7a77e6e33f46fa51100af9d1d Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Thu, 8 Jun 2017 22:21:55 +0200
Subject: [PATCH 2/3] storage: {copy,move} bugfixes
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
lxd/migrate.go | 2 +-
lxd/storage_btrfs.go | 22 ++++++++++++----------
lxd/storage_migration.go | 33 ++++++++++++++++++---------------
lxd/storage_zfs.go | 27 ++++++++++++++++-----------
4 files changed, 47 insertions(+), 37 deletions(-)
diff --git a/lxd/migrate.go b/lxd/migrate.go
index 5fa7d1db2..244ee1d73 100644
--- a/lxd/migrate.go
+++ b/lxd/migrate.go
@@ -401,7 +401,7 @@ func (s *migrationSourceWs) Do(migrateOp *operation) error {
return err
}
- err = driver.SendWhileRunning(s.fsConn, migrateOp, bwlimit)
+ err = driver.SendWhileRunning(s.fsConn, migrateOp, bwlimit, s.containerOnly)
if err != nil {
return abort(err)
}
diff --git a/lxd/storage_btrfs.go b/lxd/storage_btrfs.go
index 89f49ff4f..a403b5e8e 100644
--- a/lxd/storage_btrfs.go
+++ b/lxd/storage_btrfs.go
@@ -1770,7 +1770,7 @@ func (s *btrfsMigrationSourceDriver) send(conn *websocket.Conn, btrfsPath string
return err
}
-func (s *btrfsMigrationSourceDriver) SendWhileRunning(conn *websocket.Conn, op *operation, bwlimit string) error {
+func (s *btrfsMigrationSourceDriver) SendWhileRunning(conn *websocket.Conn, op *operation, bwlimit string, containerOnly bool) error {
_, containerPool := s.container.Storage().GetContainerPoolInfo()
containerName := s.container.Name()
containersPath := getContainerMountPoint(containerPool, "")
@@ -1806,16 +1806,18 @@ func (s *btrfsMigrationSourceDriver) SendWhileRunning(conn *websocket.Conn, op *
return s.send(conn, migrationSendSnapshot, "", wrapper)
}
- for i, snap := range s.snapshots {
- prev := ""
- if i > 0 {
- prev = getSnapshotMountPoint(containerPool, s.snapshots[i-1].Name())
- }
+ if !containerOnly {
+ for i, snap := range s.snapshots {
+ prev := ""
+ if i > 0 {
+ prev = getSnapshotMountPoint(containerPool, s.snapshots[i-1].Name())
+ }
- snapMntPoint := getSnapshotMountPoint(containerPool, snap.Name())
- wrapper := StorageProgressReader(op, "fs_progress", snap.Name())
- if err := s.send(conn, snapMntPoint, prev, wrapper); err != nil {
- return err
+ snapMntPoint := getSnapshotMountPoint(containerPool, snap.Name())
+ wrapper := StorageProgressReader(op, "fs_progress", snap.Name())
+ if err := s.send(conn, snapMntPoint, prev, wrapper); err != nil {
+ return err
+ }
}
}
diff --git a/lxd/storage_migration.go b/lxd/storage_migration.go
index 4f1e095c5..c49f2b373 100644
--- a/lxd/storage_migration.go
+++ b/lxd/storage_migration.go
@@ -18,7 +18,7 @@ type MigrationStorageSourceDriver interface {
/* send any bits of the container/snapshots that are possible while the
* container is still running.
*/
- SendWhileRunning(conn *websocket.Conn, op *operation, bwlimit string) error
+ SendWhileRunning(conn *websocket.Conn, op *operation, bwlimit string, containerOnly bool) error
/* send the final bits (e.g. a final delta snapshot for zfs, btrfs, or
* do a final rsync) of the fs after the container has been
@@ -42,22 +42,25 @@ func (s rsyncStorageSourceDriver) Snapshots() []container {
return s.snapshots
}
-func (s rsyncStorageSourceDriver) SendWhileRunning(conn *websocket.Conn, op *operation, bwlimit string) error {
+func (s rsyncStorageSourceDriver) SendWhileRunning(conn *websocket.Conn, op *operation, bwlimit string, containerOnly bool) error {
ctName, _, _ := containerGetParentAndSnapshotName(s.container.Name())
- for _, send := range s.snapshots {
- ourStart, err := send.StorageStart()
- if err != nil {
- return err
- }
- if ourStart {
- defer send.StorageStop()
- }
- path := send.Path()
- wrapper := StorageProgressReader(op, "fs_progress", send.Name())
- err = RsyncSend(ctName, shared.AddSlash(path), conn, wrapper, bwlimit)
- if err != nil {
- return err
+ if !containerOnly {
+ for _, send := range s.snapshots {
+ ourStart, err := send.StorageStart()
+ if err != nil {
+ return err
+ }
+ if ourStart {
+ defer send.StorageStop()
+ }
+
+ path := send.Path()
+ wrapper := StorageProgressReader(op, "fs_progress", send.Name())
+ err = RsyncSend(ctName, shared.AddSlash(path), conn, wrapper, bwlimit)
+ if err != nil {
+ return err
+ }
}
}
diff --git a/lxd/storage_zfs.go b/lxd/storage_zfs.go
index dbe421525..dea7044f5 100644
--- a/lxd/storage_zfs.go
+++ b/lxd/storage_zfs.go
@@ -2510,7 +2510,7 @@ func (s *zfsMigrationSourceDriver) send(conn *websocket.Conn, zfsName string, zf
return err
}
-func (s *zfsMigrationSourceDriver) SendWhileRunning(conn *websocket.Conn, op *operation, bwlimit string) error {
+func (s *zfsMigrationSourceDriver) SendWhileRunning(conn *websocket.Conn, op *operation, bwlimit string, containerOnly bool) error {
if s.container.IsSnapshot() {
_, snapOnlyName, _ := containerGetParentAndSnapshotName(s.container.Name())
snapshotName := fmt.Sprintf("snapshot-%s", snapOnlyName)
@@ -2519,18 +2519,19 @@ func (s *zfsMigrationSourceDriver) SendWhileRunning(conn *websocket.Conn, op *op
}
lastSnap := ""
+ if !containerOnly {
+ for i, snap := range s.zfsSnapshotNames {
+ prev := ""
+ if i > 0 {
+ prev = s.zfsSnapshotNames[i-1]
+ }
- for i, snap := range s.zfsSnapshotNames {
- prev := ""
- if i > 0 {
- prev = s.zfsSnapshotNames[i-1]
- }
-
- lastSnap = snap
+ lastSnap = snap
- wrapper := StorageProgressReader(op, "fs_progress", snap)
- if err := s.send(conn, snap, prev, wrapper); err != nil {
- return err
+ wrapper := StorageProgressReader(op, "fs_progress", snap)
+ if err := s.send(conn, snap, prev, wrapper); err != nil {
+ return err
+ }
}
}
@@ -2593,6 +2594,10 @@ func (s *storageZfs) MigrationSource(ct container, containerOnly bool) (Migratio
zfs: s,
}
+ if containerOnly {
+ return &driver, nil
+ }
+
/* List all the snapshots in order of reverse creation. The idea here
* is that we send the oldest to newest snapshot, hopefully saving on
* xfer costs. Then, after all that, we send the container itself.
From 4263ec402833cd45b0705e5448a560f610756691 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Thu, 8 Jun 2017 22:32:28 +0200
Subject: [PATCH 3/3] test: add more {copy,migration} tests
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
test/suites/migration.sh | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/test/suites/migration.sh b/test/suites/migration.sh
index 20b75addb..6a75cf4ec 100644
--- a/test/suites/migration.sh
+++ b/test/suites/migration.sh
@@ -128,27 +128,33 @@ migration() {
# Test container only copies
lxc init testimage cccp
+ echo "before" | lxc file push - cccp/blah
lxc snapshot cccp
lxc snapshot cccp
+ echo "after" | lxc file push - cccp/blah
# Local container only copy.
lxc copy cccp udssr --container-only
[ "$(lxc info udssr | grep -c snap)" -eq 0 ]
+ [ "$(lxc file pull udssr/blah -)" = "after" ]
lxc delete udssr
# Local container with snapshots copy.
lxc copy cccp udssr
[ "$(lxc info udssr | grep -c snap)" -eq 2 ]
+ [ "$(lxc file pull udssr/blah -)" = "after" ]
lxc delete udssr
# Remote container only copy.
lxc_remote copy l1:cccp l2:udssr --container-only
[ "$(lxc_remote info l2:udssr | grep -c snap)" -eq 0 ]
+ [ "$(lxc_remote file pull l2:udssr/blah -)" = "after" ]
lxc_remote delete l2:udssr
# Remote container with snapshots copy.
lxc_remote copy l1:cccp l2:udssr
[ "$(lxc_remote info l2:udssr | grep -c snap)" -eq 2 ]
+ [ "$(lxc_remote file pull l2:udssr/blah -)" = "after" ]
lxc_remote delete l2:udssr
# Remote container only move.
More information about the lxc-devel
mailing list