The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/7047

This e-mail was sent by the LXC bot, direct replies will not reach the author
unless they happen to be subscribed to this list.

=== Description (from pull-request) ===
This is a WIP, and although the planned approach has changed, I'm putting this up for jenkins to test in the meantime.

Includes https://github.com/lxc/lxd/pull/7046
From fe4c3f2d91dc62cd298f336de2875d3c0e313286 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Tue, 17 Mar 2020 13:42:21 +0000
Subject: [PATCH 1/9] lxd/db/containers: Renames ContainerBackupCreate and
 ContainerBackupRemove

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/db/containers.go | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/lxd/db/containers.go b/lxd/db/containers.go
index 99a4abadb9..ad025f5990 100644
--- a/lxd/db/containers.go
+++ b/lxd/db/containers.go
@@ -1231,8 +1231,8 @@ WHERE projects.name=? AND instances.name=?`
        return result, nil
 }
 
-// ContainerBackupCreate creates a new backup
-func (c *Cluster) ContainerBackupCreate(args InstanceBackupArgs) error {
+// InstanceBackupCreate creates a new backup.
+func (c *Cluster) InstanceBackupCreate(args InstanceBackupArgs) error {
        _, err := c.ContainerBackupID(args.Name)
        if err == nil {
                return ErrAlreadyDefined
@@ -1264,7 +1264,7 @@ func (c *Cluster) ContainerBackupCreate(args 
InstanceBackupArgs) error {
 
                _, err = result.LastInsertId()
                if err != nil {
-                       return fmt.Errorf("Error inserting %s into database", 
args.Name)
+                       return fmt.Errorf("Error inserting %q into database", 
args.Name)
                }
 
                return nil
@@ -1273,9 +1273,8 @@ func (c *Cluster) ContainerBackupCreate(args 
InstanceBackupArgs) error {
        return err
 }
 
-// ContainerBackupRemove removes the container backup with the given name from
-// the database.
-func (c *Cluster) ContainerBackupRemove(name string) error {
+// InstanceBackupRemove removes the container backup with the given name from 
the database.
+func (c *Cluster) InstanceBackupRemove(name string) error {
        id, err := c.ContainerBackupID(name)
        if err != nil {
                return err

From d4e7c6c2f0d8cb2e8148d7e8980beda81066e435 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Tue, 17 Mar 2020 13:43:08 +0000
Subject: [PATCH 2/9] lxd/backup: backupCreate minor clean up

        Use of renamed functions
        Error message quoting
        Revert package usage

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/backup.go | 21 ++++++++++-----------
 1 file changed, 10 insertions(+), 11 deletions(-)

diff --git a/lxd/backup.go b/lxd/backup.go
index cccdf585da..f2082a87c7 100644
--- a/lxd/backup.go
+++ b/lxd/backup.go
@@ -18,6 +18,7 @@ import (
        "github.com/lxc/lxd/lxd/instance/instancetype"
        "github.com/lxc/lxd/lxd/operations"
        "github.com/lxc/lxd/lxd/project"
+       "github.com/lxc/lxd/lxd/revert"
        "github.com/lxc/lxd/lxd/state"
        storagePools "github.com/lxc/lxd/lxd/storage"
        "github.com/lxc/lxd/lxd/task"
@@ -29,23 +30,20 @@ import (
 
 // Create a new backup.
 func backupCreate(s *state.State, args db.InstanceBackupArgs, sourceInst 
instance.Instance) error {
+       revert := revert.New()
+       defer revert.Fail()
+
        // Create the database entry.
-       err := s.Cluster.ContainerBackupCreate(args)
+       err := s.Cluster.InstanceBackupCreate(args)
        if err != nil {
                if err == db.ErrAlreadyDefined {
-                       return fmt.Errorf("backup '%s' already exists", 
args.Name)
+                       return fmt.Errorf("Backup %q already exists", args.Name)
                }
 
                return errors.Wrap(err, "Insert backup info into database")
        }
 
-       revert := true
-       defer func() {
-               if !revert {
-                       return
-               }
-               s.Cluster.ContainerBackupRemove(args.Name)
-       }()
+       revert.Add(func() { s.Cluster.InstanceBackupRemove(args.Name) })
 
        // Get the backup struct.
        b, err := instance.BackupLoadByName(s, sourceInst.Project(), args.Name)
@@ -60,7 +58,8 @@ func backupCreate(s *state.State, args db.InstanceBackupArgs, 
sourceInst instanc
        if err != nil {
                return err
        }
-       defer os.RemoveAll(tmpPath)
+
+       revert.Add(func() { os.RemoveAll(tmpPath) })
 
        pool, err := storagePools.GetPoolByInstance(s, sourceInst)
        if err != nil {
@@ -78,7 +77,7 @@ func backupCreate(s *state.State, args db.InstanceBackupArgs, 
sourceInst instanc
                return err
        }
 
-       revert = false
+       revert.Success()
        return nil
 }
 

From a87e73093f7fd3212cb337c961512906b8f1d09a Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Tue, 17 Mar 2020 13:45:15 +0000
Subject: [PATCH 3/9] lxd/backup: InstanceBackupRemove usage

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/backup/backup.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lxd/backup/backup.go b/lxd/backup/backup.go
index 440e8fdb4d..f0cec28c62 100644
--- a/lxd/backup/backup.go
+++ b/lxd/backup/backup.go
@@ -239,7 +239,7 @@ func DoBackupDelete(s *state.State, projectName, 
backupName, containerName strin
        }
 
        // Remove the database record
-       err := s.Cluster.ContainerBackupRemove(backupName)
+       err := s.Cluster.InstanceBackupRemove(backupName)
        if err != nil {
                return err
        }

From 41d7652b1e886b720e92c8ae9879650601d6bb3b Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Tue, 17 Mar 2020 15:51:24 +0000
Subject: [PATCH 4/9] lxd/backup: Minor tweaks to backupCreateTarball

        Improves logging
        Uses revert package

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/backup.go | 33 +++++++++++++++------------------
 1 file changed, 15 insertions(+), 18 deletions(-)

diff --git a/lxd/backup.go b/lxd/backup.go
index f2082a87c7..3e7beed880 100644
--- a/lxd/backup.go
+++ b/lxd/backup.go
@@ -15,7 +15,6 @@ import (
        "github.com/lxc/lxd/lxd/cluster"
        "github.com/lxc/lxd/lxd/db"
        "github.com/lxc/lxd/lxd/instance"
-       "github.com/lxc/lxd/lxd/instance/instancetype"
        "github.com/lxc/lxd/lxd/operations"
        "github.com/lxc/lxd/lxd/project"
        "github.com/lxc/lxd/lxd/revert"
@@ -82,16 +81,15 @@ func backupCreate(s *state.State, args 
db.InstanceBackupArgs, sourceInst instanc
 }
 
 func backupCreateTarball(s *state.State, path string, b backup.Backup, c 
instance.Instance) error {
-       // Create the index
+       revert := revert.New()
+       defer revert.Fail()
+
+       // Create the index.
        poolName, err := c.StoragePool()
        if err != nil {
                return err
        }
 
-       if c.Type() != instancetype.Container {
-               return fmt.Errorf("Instance type must be container")
-       }
-
        indexFile := backup.Info{
                Name:       c.Name(),
                Privileged: c.IsPrivileged(),
@@ -124,18 +122,21 @@ func backupCreateTarball(s *state.State, path string, b 
backup.Backup, c instanc
                return err
        }
 
-       file, err := os.Create(filepath.Join(path, "index.yaml"))
+       indexFilePath := filepath.Join(path, "index.yaml")
+       file, err := os.Create(indexFilePath)
        if err != nil {
                return err
        }
 
+       revert.Add(func() { os.Remove(indexFilePath) })
+
        _, err = file.Write(data)
        file.Close()
        if err != nil {
                return err
        }
 
-       // Create the target path if needed
+       // Create the target path if needed.
        backupsPath := shared.VarPath("backups", project.Instance(c.Project(), 
c.Name()))
        if !shared.PathExists(backupsPath) {
                err := os.MkdirAll(backupsPath, 0700)
@@ -144,17 +145,12 @@ func backupCreateTarball(s *state.State, path string, b 
backup.Backup, c instanc
                }
        }
 
-       // Create the tarball
+       // Create the tarball.
        backupPath := shared.VarPath("backups", project.Instance(c.Project(), 
b.Name()))
-       success := false
-       defer func() {
-               if success {
-                       return
-               }
 
-               os.RemoveAll(backupPath)
-       }()
+       revert.Add(func() { os.RemoveAll(backupPath) })
 
+       logger.Debugf("Creating backup tarball from %q to %q", path, backupPath)
        args := []string{"-cf", backupPath, "--numeric-owner", "--xattrs", 
"-C", path, "--transform", "s,^./,backup/,S", "."}
        _, err = shared.RunCommand("tar", args...)
        if err != nil {
@@ -193,6 +189,7 @@ func backupCreateTarball(s *state.State, path string, b 
backup.Backup, c instanc
                defer compressed.Close()
                defer os.Remove(compressedName)
 
+               logger.Debugf("Compressing backup tarball %q", backupPath)
                err = compressFile(compress, infile, compressed)
                if err != nil {
                        return err
@@ -209,13 +206,13 @@ func backupCreateTarball(s *state.State, path string, b 
backup.Backup, c instanc
                }
        }
 
-       // Set permissions
+       // Set permissions.
        err = os.Chmod(backupPath, 0600)
        if err != nil {
                return err
        }
 
-       success = true
+       revert.Success()
        return nil
 }
 

From 4d0f223fa3901be801b1f3f37e3bf8d05d6dc38f Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Tue, 17 Mar 2020 15:51:54 +0000
Subject: [PATCH 5/9] lxd/rsync: Adds support for rsync arguments to LocalCopy

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/rsync/rsync.go | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/lxd/rsync/rsync.go b/lxd/rsync/rsync.go
index 6b18c743e1..101f4a7d65 100644
--- a/lxd/rsync/rsync.go
+++ b/lxd/rsync/rsync.go
@@ -19,7 +19,7 @@ import (
 )
 
 // LocalCopy copies a directory using rsync (with the --devices option).
-func LocalCopy(source string, dest string, bwlimit string, xattrs bool) 
(string, error) {
+func LocalCopy(source string, dest string, bwlimit string, xattrs bool, 
rsyncArgs ...string) (string, error) {
        err := os.MkdirAll(dest, 0755)
        if err != nil {
                return "", err
@@ -52,6 +52,10 @@ func LocalCopy(source string, dest string, bwlimit string, 
xattrs bool) (string,
                args = append(args, "--bwlimit", bwlimit)
        }
 
+       if len(rsyncArgs) > 0 {
+               args = append(args, rsyncArgs...)
+       }
+
        args = append(args,
                rsyncVerbosity,
                shared.AddSlash(source),

From 5c3c8dcb007a17253541b1e5e07babcb88da2f2c Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Tue, 17 Mar 2020 15:53:12 +0000
Subject: [PATCH 6/9] lxd/storage/drivers/utils: Minor tweak to copyDevice
 error message

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/storage/drivers/utils.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lxd/storage/drivers/utils.go b/lxd/storage/drivers/utils.go
index 430f9673b9..4981e6daf2 100644
--- a/lxd/storage/drivers/utils.go
+++ b/lxd/storage/drivers/utils.go
@@ -568,7 +568,7 @@ func copyDevice(inputPath, outputPath string) error {
 
        to, err := os.OpenFile(outputPath, os.O_WRONLY, 0)
        if err != nil {
-               return errors.Wrapf(err, "Error opening file writing %q", 
outputPath)
+               return errors.Wrapf(err, "Error opening file for writing %q", 
outputPath)
        }
        defer to.Close()
 

From 608fe31c50a256917931afee6c0a8021057e6433 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Tue, 17 Mar 2020 15:52:16 +0000
Subject: [PATCH 7/9] lxd/stroage/drivers/generic: Tweak error message of
 genericCreateVolumeFromMigration

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/storage/drivers/generic.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lxd/storage/drivers/generic.go b/lxd/storage/drivers/generic.go
index 02eb795e4d..ca18a04fc1 100644
--- a/lxd/storage/drivers/generic.go
+++ b/lxd/storage/drivers/generic.go
@@ -190,7 +190,7 @@ func genericCreateVolumeFromMigration(d Driver, initVolume 
func(vol Volume) (fun
 
                to, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0)
                if err != nil {
-                       return errors.Wrapf(err, "Error opening file writing 
%q", path)
+                       return errors.Wrapf(err, "Error opening file for 
writing %q", path)
                }
                defer to.Close()
 

From 4f4c7fd0e67fc791999939a1aa4d65e45f330a1e Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Tue, 17 Mar 2020 15:52:54 +0000
Subject: [PATCH 8/9] lxd/storage/drivers/generic/vfs: Adds VM support to
 genericVFSBackupVolume

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/storage/drivers/generic_vfs.go | 82 ++++++++++++++++++++++--------
 1 file changed, 61 insertions(+), 21 deletions(-)

diff --git a/lxd/storage/drivers/generic_vfs.go 
b/lxd/storage/drivers/generic_vfs.go
index 93a41e74c3..5d65a898ea 100644
--- a/lxd/storage/drivers/generic_vfs.go
+++ b/lxd/storage/drivers/generic_vfs.go
@@ -277,13 +277,64 @@ func genericVFSGetVolumeDiskPath(vol Volume) (string, 
error) {
 func genericVFSBackupVolume(d Driver, vol Volume, targetPath string, snapshots 
bool, op *operations.Operation) error {
        bwlimit := d.Config()["rsync.bwlimit"]
 
-       // Backups only implemented for containers currently.
-       if vol.volType != VolumeTypeContainer {
-               return ErrNotImplemented
+       // Define a function that can copy a volume into the backup target 
location.
+       backupVolume := func(v Volume, target string) error {
+               return v.MountTask(func(mountPath string, op 
*operations.Operation) error {
+                       if v.IsVMBlock() {
+                               blockPath, err := d.GetVolumeDiskPath(v)
+                               if err != nil {
+                                       return errors.Wrapf(err, "Error getting 
VM block volume disk path")
+                               }
+
+                               var rsyncArgs []string
+
+                               // Exclude the VM root disk path, if a file 
image.
+                               if !shared.IsBlockdevPath(blockPath) {
+                                       rsyncArgs = []string{"--exclude", 
filepath.Base(blockPath)}
+                               }
+
+                               d.Logger().Debug("Copying virtual machine 
config volume", log.Ctx{"sourcePath": mountPath, "targetPath": target})
+                               _, err = rsync.LocalCopy(mountPath, target, 
bwlimit, true, rsyncArgs...)
+                               if err != nil {
+                                       return err
+                               }
+
+                               targetFile := filepath.Join(target, "root.img")
+                               d.Logger().Debug("Copying virtual machine block 
volume", log.Ctx{"sourcePath": blockPath, "targetPath": targetFile})
+                               from, err := os.Open(blockPath)
+                               if err != nil {
+                                       return errors.Wrapf(err, "Error opening 
file for reading %q", blockPath)
+                               }
+                               defer from.Close()
+
+                               to, err := os.OpenFile(targetFile, 
os.O_CREATE|os.O_WRONLY, 0600)
+                               if err != nil {
+                                       return errors.Wrapf(err, "Error opening 
file for writing %q", targetFile)
+                               }
+                               defer to.Close()
+
+                               _, err = io.Copy(to, from)
+                               if err != nil {
+                                       return errors.Wrapf(err, "Error copying 
file %q to %q", blockPath, targetFile)
+                               }
+                       } else {
+                               d.Logger().Debug("Copying container filesystem 
volume", log.Ctx{"sourcePath": mountPath, "targetPath": target})
+                               _, err := rsync.LocalCopy(mountPath, target, 
bwlimit, true)
+                               if err != nil {
+                                       return err
+                               }
+                       }
+
+                       return nil
+               }, op)
        }
+
        // Handle snapshots.
        if snapshots {
                snapshotsPath := filepath.Join(targetPath, "snapshots")
+               if vol.IsVMBlock() {
+                       snapshotsPath = filepath.Join(targetPath, 
"virtual-machine-snapshots")
+               }
 
                // List the snapshots.
                snapshots, err := vol.Snapshots(op)
@@ -295,7 +346,7 @@ func genericVFSBackupVolume(d Driver, vol Volume, 
targetPath string, snapshots b
                if len(snapshots) > 0 {
                        err = os.MkdirAll(snapshotsPath, 0711)
                        if err != nil {
-                               return errors.Wrapf(err, "Failed to create 
directory '%s'", snapshotsPath)
+                               return errors.Wrapf(err, "Failed to create 
directory %q", snapshotsPath)
                        }
                }
 
@@ -303,31 +354,20 @@ func genericVFSBackupVolume(d Driver, vol Volume, 
targetPath string, snapshots b
                        _, snapName, _ := 
shared.InstanceGetParentAndSnapshotName(snapshot.Name())
                        target := filepath.Join(snapshotsPath, snapName)
 
-                       // Copy the snapshot.
-                       err = snapshot.MountTask(func(mountPath string, op 
*operations.Operation) error {
-                               _, err := rsync.LocalCopy(mountPath, target, 
bwlimit, true)
-                               if err != nil {
-                                       return err
-                               }
-
-                               return nil
-                       }, op)
+                       err := backupVolume(snapshot, target)
                        if err != nil {
                                return err
                        }
                }
        }
 
-       // Copy the parent volume itself.
+       // Copy the main volume itself.
        target := filepath.Join(targetPath, "container")
-       err := vol.MountTask(func(mountPath string, op *operations.Operation) 
error {
-               _, err := rsync.LocalCopy(mountPath, target, bwlimit, true)
-               if err != nil {
-                       return err
-               }
+       if vol.IsVMBlock() {
+               target = filepath.Join(targetPath, "virtual-machine")
+       }
 
-               return nil
-       }, op)
+       err := backupVolume(vol, target)
        if err != nil {
                return err
        }

From 3a0f3267418c18a0fa06bb53c7a04bc8102b86fc Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Tue, 17 Mar 2020 17:29:45 +0000
Subject: [PATCH 9/9] lxd/storage/drivers/driver/lvm/volumes: Fixes LVM VM
 snapshot list

This bug was introduced in d782daf202cda0de0a88886e21aa056775024139 due to the 
way that VM snapshot LVs are named differently than container snapshot LVs.

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/storage/drivers/driver_lvm_volumes.go | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/lxd/storage/drivers/driver_lvm_volumes.go 
b/lxd/storage/drivers/driver_lvm_volumes.go
index 76d7e93b2c..9eadf49623 100644
--- a/lxd/storage/drivers/driver_lvm_volumes.go
+++ b/lxd/storage/drivers/driver_lvm_volumes.go
@@ -734,8 +734,6 @@ func (d *lvm) UnmountVolumeSnapshot(snapVol Volume, op 
*operations.Operation) (b
 
 // VolumeSnapshots returns a list of snapshots for the volume.
 func (d *lvm) VolumeSnapshots(vol Volume, op *operations.Operation) ([]string, 
error) {
-       fullVolName := d.lvmFullVolumeName(vol.volType, vol.contentType, 
vol.name)
-
        // We use the volume list rather than inspecting the logical volumes 
themselves because the origin
        // property of an LVM snapshot can be removed/changed when restoring 
snapshots, such that they are no
        // marked as origin of the parent volume. Instead we use prefix 
matching on the volume names to find the
@@ -757,10 +755,29 @@ func (d *lvm) VolumeSnapshots(vol Volume, op 
*operations.Operation) ([]string, e
        }
 
        snapshots := []string{}
-       scanner := bufio.NewScanner(stdout)
+       fullVolName := d.lvmFullVolumeName(vol.volType, vol.contentType, 
vol.name)
+
+       // If block volume, remove the block suffix ready for comparison with 
LV list.
+       if vol.IsVMBlock() {
+               fullVolName = strings.TrimSuffix(fullVolName, lvmBlockVolSuffix)
+       }
+
        prefix := fmt.Sprintf("%s-", fullVolName)
+
+       scanner := bufio.NewScanner(stdout)
        for scanner.Scan() {
                snapLine := strings.TrimSpace(scanner.Text())
+
+               // If block volume, skip any LVs that don't end with the block 
suffix, and then for those that do
+               // remove the block suffix so that they can be compared with 
the fullVolName prefix.
+               if vol.IsVMBlock() {
+                       if !strings.HasSuffix(snapLine, lvmBlockVolSuffix) {
+                               continue // Ignore non-block volumes.
+                       }
+
+                       snapLine = strings.TrimSuffix(snapLine, 
lvmBlockVolSuffix)
+               }
+
                if strings.HasPrefix(snapLine, prefix) {
                        // Remove volume name prefix (including snapshot 
delimiter) and unescape snapshot name.
                        snapshots = append(snapshots, 
strings.Replace(strings.TrimPrefix(snapLine, prefix), "--", "-", -1))
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to