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

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) ===
Signed-off-by: Stéphane Graber <stgra...@ubuntu.com>
From 993886156574bdf1bb62530acc6bddbf3bb925ed Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com>
Date: Wed, 8 Jan 2020 15:57:05 -0500
Subject: [PATCH] lxd/storage: Support deleting snapshots during restore
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgra...@ubuntu.com>
---
 lxd/storage/backend_lxd.go    | 60 ++++++++++++++++++++++++++++++++++-
 lxd/storage/drivers/errors.go |  9 ++++++
 2 files changed, 68 insertions(+), 1 deletion(-)

diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go
index 89f6882817..1ec8fc2025 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -1699,6 +1699,35 @@ func (b *lxdBackend) RestoreInstanceSnapshot(inst 
instance.Instance, src instanc
        vol := b.newVolume(volType, contentType, volStorageName, rootDiskConf)
        err = b.driver.RestoreVolume(vol, snapshotName, op)
        if err != nil {
+               snapErr, ok := err.(drivers.ErrDeleteSnapshots)
+               if ok {
+                       // We need to delete some snapshots and try again.
+                       snaps, err := inst.Snapshots()
+                       if err != nil {
+                               return err
+                       }
+
+                       // Go through all the snapshots.
+                       for _, snap := range snaps {
+                               _, snapName, _ := 
shared.InstanceGetParentAndSnapshotName(src.Name())
+                               if !shared.StringInSlice(snapName, 
snapErr.Snapshots) {
+                                       continue
+                               }
+
+                               // Delete if listed.
+                               err := b.DeleteInstanceSnapshot(snap, op)
+                               if err != nil {
+                                       return err
+                               }
+                       }
+
+                       // Now try again.
+                       err = b.driver.RestoreVolume(vol, snapshotName, op)
+                       if err != nil {
+                               return err
+                       }
+               }
+
                return err
        }
 
@@ -2607,6 +2636,7 @@ func (b *lxdBackend) RestoreCustomVolume(volName string, 
snapshotName string, op
        logger.Debug("RestoreCustomVolume started")
        defer logger.Debug("RestoreCustomVolume finished")
 
+       // Sanity checks.
        if shared.IsSnapshot(volName) {
                return fmt.Errorf("Volume cannot be snapshot")
        }
@@ -2615,6 +2645,7 @@ func (b *lxdBackend) RestoreCustomVolume(volName string, 
snapshotName string, op
                return fmt.Errorf("Invalid snapshot name")
        }
 
+       // Check that the volume isn't in use.
        usingVolume, err := VolumeUsedByInstancesWithProfiles(b.state, 
b.Name(), volName, db.StoragePoolVolumeTypeNameCustom, true)
        if err != nil {
                return err
@@ -2624,8 +2655,35 @@ func (b *lxdBackend) RestoreCustomVolume(volName string, 
snapshotName string, op
                return fmt.Errorf("Cannot restore custom volume used by running 
instances")
        }
 
-       err = b.driver.RestoreVolume(b.newVolume(drivers.VolumeTypeCustom, 
drivers.ContentTypeFS, volName, nil), snapshotName, op)
+       // Get the volume config.
+       _, dbVol, err := 
b.state.Cluster.StoragePoolNodeVolumeGetTypeByProject("default", volName, 
db.StoragePoolVolumeTypeCustom, b.ID())
+       if err != nil {
+               if err == db.ErrNoSuchObject {
+                       return fmt.Errorf("Volume doesn't exist")
+               }
+
+               return err
+       }
+
+       err = b.driver.RestoreVolume(b.newVolume(drivers.VolumeTypeCustom, 
drivers.ContentTypeFS, volName, dbVol.Config), snapshotName, op)
        if err != nil {
+               snapErr, ok := err.(drivers.ErrDeleteSnapshots)
+               if ok {
+                       // We need to delete some snapshots and try again.
+                       for _, snapName := range snapErr.Snapshots {
+                               err := 
b.DeleteCustomVolumeSnapshot(fmt.Sprintf("%s/%s", volName, snapName), op)
+                               if err != nil {
+                                       return err
+                               }
+                       }
+
+                       // Now try again.
+                       err = 
b.driver.RestoreVolume(b.newVolume(drivers.VolumeTypeCustom, 
drivers.ContentTypeFS, volName, dbVol.Config), snapshotName, op)
+                       if err != nil {
+                               return err
+                       }
+               }
+
                return err
        }
 
diff --git a/lxd/storage/drivers/errors.go b/lxd/storage/drivers/errors.go
index e9fb157bc6..cae5eba16a 100644
--- a/lxd/storage/drivers/errors.go
+++ b/lxd/storage/drivers/errors.go
@@ -12,3 +12,12 @@ var ErrUnknownDriver = fmt.Errorf("Unknown driver")
 
 // ErrNotSupported is the "Not supported" error
 var ErrNotSupported = fmt.Errorf("Not supported")
+
+// ErrDeleteSnapshots is a special error used to tell the backend to delete 
more recent snapshots
+type ErrDeleteSnapshots struct {
+       Snapshots []string
+}
+
+func (e ErrDeleteSnapshots) Error() string {
+       return fmt.Sprintf("More recent snapshots must be deleted: %+v", 
e.Snapshots)
+}
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to