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

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) ===

From 1c3e543c4011f3eeab41fbae671b5306f00656b5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com>
Date: Sun, 19 Jan 2020 14:27:55 +0200
Subject: [PATCH 1/4] lxd/vm: Fix incorrect bootindex

---
 lxd/instance/drivers/vm_qemu.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lxd/instance/drivers/vm_qemu.go b/lxd/instance/drivers/vm_qemu.go
index 2b71e0049a..4f14990274 100644
--- a/lxd/instance/drivers/vm_qemu.go
+++ b/lxd/instance/drivers/vm_qemu.go
@@ -1494,7 +1494,7 @@ netdev = "lxd_%s"
 mac = "%s"
 bus = "qemu_pcie%d"
 addr = "0x0"
-bootindex = "%d""
+bootindex = "%d"
 `, devName, devName, devTap, 5+nicIndex, 14+nicIndex, 5+nicIndex, 4+nicIndex, 
devName, devName, devHwaddr, 5+nicIndex, 2+nicIndex))
 
        return

From 6f10f885ea6b1de916c93a95d861dc81c1eec177 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com>
Date: Sun, 19 Jan 2020 16:32:35 +0200
Subject: [PATCH 2/4] lxd/vm: Implement snapshot 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/instance/drivers/vm_qemu.go | 113 +++++++++++++++++++++++++++++++-
 1 file changed, 112 insertions(+), 1 deletion(-)

diff --git a/lxd/instance/drivers/vm_qemu.go b/lxd/instance/drivers/vm_qemu.go
index 4f14990274..ee9a218112 100644
--- a/lxd/instance/drivers/vm_qemu.go
+++ b/lxd/instance/drivers/vm_qemu.go
@@ -1611,7 +1611,118 @@ func (vm *qemu) IsPrivileged() bool {
 
 // Restore restores an instance snapshot.
 func (vm *qemu) Restore(source instance.Instance, stateful bool) error {
-       return fmt.Errorf("Restore Not implemented")
+       if stateful {
+               return fmt.Errorf("Stateful snapshots of VMs aren't supported 
yet")
+       }
+
+       var ctxMap log.Ctx
+
+       // Load the storage driver
+       pool, err := storagePools.GetPoolByInstance(vm.state, vm)
+       if err != nil {
+               return err
+       }
+
+       // Ensure that storage is mounted for backup.yaml updates.
+       ourStart, err := pool.MountInstance(vm, nil)
+       if err != nil {
+               return err
+       }
+       if ourStart {
+               defer pool.UnmountInstance(vm, nil)
+       }
+
+       // Stop the instance.
+       wasRunning := false
+       if vm.IsRunning() {
+               wasRunning = true
+
+               ephemeral := vm.IsEphemeral()
+               if ephemeral {
+                       // Unset ephemeral flag.
+                       args := db.InstanceArgs{
+                               Architecture: vm.Architecture(),
+                               Config:       vm.LocalConfig(),
+                               Description:  vm.Description(),
+                               Devices:      vm.LocalDevices(),
+                               Ephemeral:    false,
+                               Profiles:     vm.Profiles(),
+                               Project:      vm.Project(),
+                               Type:         vm.Type(),
+                               Snapshot:     vm.IsSnapshot(),
+                       }
+
+                       err := vm.Update(args, false)
+                       if err != nil {
+                               return err
+                       }
+
+                       // On function return, set the flag back on.
+                       defer func() {
+                               args.Ephemeral = ephemeral
+                               vm.Update(args, true)
+                       }()
+               }
+
+               // This will unmount the instance storage.
+               err := vm.Stop(false)
+               if err != nil {
+                       return err
+               }
+       }
+
+       ctxMap = log.Ctx{
+               "project":   vm.project,
+               "name":      vm.name,
+               "created":   vm.creationDate,
+               "ephemeral": vm.ephemeral,
+               "used":      vm.lastUsedDate,
+               "source":    source.Name()}
+
+       logger.Info("Restoring instance", ctxMap)
+
+       // Restore the rootfs.
+       err = pool.RestoreInstanceSnapshot(vm, source, nil)
+       if err != nil {
+               return err
+       }
+
+       // Restore the configuration.
+       args := db.InstanceArgs{
+               Architecture: source.Architecture(),
+               Config:       source.LocalConfig(),
+               Description:  source.Description(),
+               Devices:      source.LocalDevices(),
+               Ephemeral:    source.IsEphemeral(),
+               Profiles:     source.Profiles(),
+               Project:      source.Project(),
+               Type:         source.Type(),
+               Snapshot:     source.IsSnapshot(),
+       }
+
+       err = vm.Update(args, false)
+       if err != nil {
+               logger.Error("Failed restoring instance configuration", ctxMap)
+               return err
+       }
+
+       // The old backup file may be out of date (e.g. it doesn't have all the 
current snapshots of
+       // the instance listed); let's write a new one to be safe.
+       err = vm.UpdateBackupFile()
+       if err != nil {
+               return err
+       }
+
+       vm.state.Events.SendLifecycle(vm.project, 
"virtual-machine-snapshot-restored", fmt.Sprintf("/1.0/virtual-machines/%s", 
vm.name), map[string]interface{}{"snapshot_name": vm.name})
+
+       // Restart the insance.
+       if wasRunning {
+               logger.Info("Restored instance", ctxMap)
+               return vm.Start(false)
+       }
+
+       logger.Info("Restored instance", ctxMap)
+       return nil
 }
 
 // Snapshots returns a list of snapshots.

From dcbb7d6979512152b0d0fff81d3d13a7e5d2701e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com>
Date: Sun, 19 Jan 2020 16:53:06 +0200
Subject: [PATCH 3/4] lxd/instance: Move LoadAllInternal
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/container.go               | 57 ++--------------------------------
 lxd/container_lxc.go           |  2 +-
 lxd/instance/instance_utils.go | 51 ++++++++++++++++++++++++++++++
 3 files changed, 55 insertions(+), 55 deletions(-)

diff --git a/lxd/container.go b/lxd/container.go
index b8281e8114..e86439c2df 100644
--- a/lxd/container.go
+++ b/lxd/container.go
@@ -30,7 +30,6 @@ import (
        storageDrivers "github.com/lxc/lxd/lxd/storage/drivers"
        "github.com/lxc/lxd/lxd/task"
        "github.com/lxc/lxd/shared"
-       "github.com/lxc/lxd/shared/api"
        "github.com/lxc/lxd/shared/ioprogress"
        log "github.com/lxc/lxd/shared/log15"
        "github.com/lxc/lxd/shared/logger"
@@ -963,7 +962,7 @@ func instanceLoadByProject(s *state.State, project string) 
([]instance.Instance,
                return nil, err
        }
 
-       return instanceLoadAllInternal(cts, s)
+       return instance.LoadAllInternal(s, cts)
 }
 
 // Load all instances across all projects.
@@ -1013,7 +1012,7 @@ func instanceLoadNodeAll(s *state.State, instanceType 
instancetype.Type) ([]inst
                return nil, err
        }
 
-       return instanceLoadAllInternal(insts, s)
+       return instance.LoadAllInternal(s, insts)
 }
 
 // Load all instances of this nodes under the given project.
@@ -1033,57 +1032,7 @@ func instanceLoadNodeProjectAll(s *state.State, project 
string, instanceType ins
                return nil, err
        }
 
-       return instanceLoadAllInternal(cts, s)
-}
-
-func instanceLoadAllInternal(dbInstances []db.Instance, s *state.State) 
([]instance.Instance, error) {
-       // Figure out what profiles are in use
-       profiles := map[string]map[string]api.Profile{}
-       for _, instArgs := range dbInstances {
-               projectProfiles, ok := profiles[instArgs.Project]
-               if !ok {
-                       projectProfiles = map[string]api.Profile{}
-                       profiles[instArgs.Project] = projectProfiles
-               }
-               for _, profile := range instArgs.Profiles {
-                       _, ok := projectProfiles[profile]
-                       if !ok {
-                               projectProfiles[profile] = api.Profile{}
-                       }
-               }
-       }
-
-       // Get the profile data
-       for project, projectProfiles := range profiles {
-               for name := range projectProfiles {
-                       _, profile, err := s.Cluster.ProfileGet(project, name)
-                       if err != nil {
-                               return nil, err
-                       }
-
-                       projectProfiles[name] = *profile
-               }
-       }
-
-       // Load the instances structs
-       instances := []instance.Instance{}
-       for _, dbInstance := range dbInstances {
-               // Figure out the instances's profiles
-               cProfiles := []api.Profile{}
-               for _, name := range dbInstance.Profiles {
-                       cProfiles = append(cProfiles, 
profiles[dbInstance.Project][name])
-               }
-
-               args := db.InstanceToArgs(&dbInstance)
-               inst, err := instance.Load(s, args, cProfiles)
-               if err != nil {
-                       return nil, err
-               }
-
-               instances = append(instances, inst)
-       }
-
-       return instances, nil
+       return instance.LoadAllInternal(s, cts)
 }
 
 func autoCreateContainerSnapshotsTask(d *Daemon) (task.Func, task.Schedule) {
diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index ca6e59c495..df12b17c21 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -3168,7 +3168,7 @@ func (c *containerLXC) Snapshots() ([]instance.Instance, 
error) {
        }
 
        // Build the snapshot list
-       containers, err := instanceLoadAllInternal(snaps, c.state)
+       containers, err := instance.LoadAllInternal(c.state, snaps)
        if err != nil {
                return nil, err
        }
diff --git a/lxd/instance/instance_utils.go b/lxd/instance/instance_utils.go
index 86a0b3724e..34e62a4c06 100644
--- a/lxd/instance/instance_utils.go
+++ b/lxd/instance/instance_utils.go
@@ -465,6 +465,57 @@ func LoadByProjectAndName(s *state.State, project, name 
string) (Instance, error
        return inst, nil
 }
 
+// LoadAllInternal loads a list of db insances into a list of instances.
+func LoadAllInternal(s *state.State, dbInstances []db.Instance) ([]Instance, 
error) {
+       // Figure out what profiles are in use
+       profiles := map[string]map[string]api.Profile{}
+       for _, instArgs := range dbInstances {
+               projectProfiles, ok := profiles[instArgs.Project]
+               if !ok {
+                       projectProfiles = map[string]api.Profile{}
+                       profiles[instArgs.Project] = projectProfiles
+               }
+               for _, profile := range instArgs.Profiles {
+                       _, ok := projectProfiles[profile]
+                       if !ok {
+                               projectProfiles[profile] = api.Profile{}
+                       }
+               }
+       }
+
+       // Get the profile data
+       for project, projectProfiles := range profiles {
+               for name := range projectProfiles {
+                       _, profile, err := s.Cluster.ProfileGet(project, name)
+                       if err != nil {
+                               return nil, err
+                       }
+
+                       projectProfiles[name] = *profile
+               }
+       }
+
+       // Load the instances structs
+       instances := []Instance{}
+       for _, dbInstance := range dbInstances {
+               // Figure out the instances's profiles
+               cProfiles := []api.Profile{}
+               for _, name := range dbInstance.Profiles {
+                       cProfiles = append(cProfiles, 
profiles[dbInstance.Project][name])
+               }
+
+               args := db.InstanceToArgs(&dbInstance)
+               inst, err := Load(s, args, cProfiles)
+               if err != nil {
+                       return nil, err
+               }
+
+               instances = append(instances, inst)
+       }
+
+       return instances, nil
+}
+
 // WriteBackupFile writes instance's config to a file. Deprecated, use 
inst.UpdateBackupFile().
 func WriteBackupFile(state *state.State, inst Instance) error {
        // We only write backup files out for actual instances.

From 69e9e755365c12a6ed061912f65ad6aacd3e2a93 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com>
Date: Sun, 19 Jan 2020 16:53:14 +0200
Subject: [PATCH 4/4] lxd/vm: Implement Snapshots
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/instance/drivers/vm_qemu.go | 33 ++++++++++++++++++++++++++++++++-
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/lxd/instance/drivers/vm_qemu.go b/lxd/instance/drivers/vm_qemu.go
index ee9a218112..a204477198 100644
--- a/lxd/instance/drivers/vm_qemu.go
+++ b/lxd/instance/drivers/vm_qemu.go
@@ -1727,7 +1727,38 @@ func (vm *qemu) Restore(source instance.Instance, 
stateful bool) error {
 
 // Snapshots returns a list of snapshots.
 func (vm *qemu) Snapshots() ([]instance.Instance, error) {
-       return []instance.Instance{}, nil
+       var snaps []db.Instance
+
+       if vm.IsSnapshot() {
+               return []instance.Instance{}, nil
+       }
+
+       // Get all the snapshots
+       err := vm.state.Cluster.Transaction(func(tx *db.ClusterTx) error {
+               var err error
+               snaps, err = tx.ContainerGetSnapshotsFull(vm.Project(), vm.name)
+               if err != nil {
+                       return err
+               }
+
+               return nil
+       })
+       if err != nil {
+               return nil, err
+       }
+
+       // Build the snapshot list
+       snapshots, err := instance.LoadAllInternal(vm.state, snaps)
+       if err != nil {
+               return nil, err
+       }
+
+       instances := make([]instance.Instance, len(snapshots))
+       for k, v := range snapshots {
+               instances[k] = instance.Instance(v)
+       }
+
+       return instances, nil
 }
 
 // Backups returns a list of backups.
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to