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