[lxc-devel] [lxd/master] VM: Fixes disk resize regression
tomponline on Github
lxc-bot at linuxcontainers.org
Fri Oct 9 18:45:41 UTC 2020
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 552 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20201009/84e6c427/attachment.bin>
-------------- next part --------------
From 57f1dc94a63d5faf175b096f280269adcca51786 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Fri, 9 Oct 2020 19:39:09 +0100
Subject: [PATCH 1/2] lxd/instance/drivers/driver/qemu: Restores ability to
resize VM disks
- Moves check for preventing update of devices when VM is running into updateDevices().
- Fixes regression introduced by https://github.com/lxc/lxd/commit/6697599975c1199c226c00b68c7e3e278ea49c66#diff-8ac4860b5f669c17c92c37545fe2ecfd.
- Removes 1 call to IsRunning() by passing into updateDevices() from Update().
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/instance/drivers/driver_qemu.go | 44 +++++++++++++++++++++++------
1 file changed, 36 insertions(+), 8 deletions(-)
diff --git a/lxd/instance/drivers/driver_qemu.go b/lxd/instance/drivers/driver_qemu.go
index 0b697cbf58..7c641ef033 100644
--- a/lxd/instance/drivers/driver_qemu.go
+++ b/lxd/instance/drivers/driver_qemu.go
@@ -2836,7 +2836,37 @@ func (vm *qemu) Update(args db.InstanceArgs, userRequested bool) error {
}
// Diff the devices.
- removeDevices, addDevices, updateDevices, allUpdatedKeys := oldExpandedDevices.Update(vm.expandedDevices, nil)
+ removeDevices, addDevices, updateDevices, allUpdatedKeys := oldExpandedDevices.Update(vm.expandedDevices, func(oldDevice deviceConfig.Device, newDevice deviceConfig.Device) []string {
+ // This function needs to return a list of fields that are excluded from differences
+ // between oldDevice and newDevice. The result of this is that as long as the
+ // devices are otherwise identical except for the fields returned here, then the
+ // device is considered to be being "updated" rather than "added & removed".
+ oldNICType, err := nictype.NICType(vm.state, vm.Project(), newDevice)
+ if err != nil {
+ return []string{} // Cannot hot-update due to config error.
+ }
+
+ newNICType, err := nictype.NICType(vm.state, vm.Project(), oldDevice)
+ if err != nil {
+ return []string{} // Cannot hot-update due to config error.
+ }
+
+ if oldDevice["type"] != newDevice["type"] || oldNICType != newNICType {
+ return []string{} // Device types aren't the same, so this cannot be an update.
+ }
+
+ d, err := device.New(vm, vm.state, "", newDevice, nil, nil)
+ if err != nil {
+ return []string{} // Couldn't create Device, so this cannot be an update.
+ }
+
+ // TODO modify device framework to differentiate between devices that can only be updated when VM
+ // is stopped, but don't need to be removed then re-added. For now we rely upon the disk device
+ // indicating that it supports hot plugging, even for VMs, which it cannot. However this is
+ // needed so that the disk device's Update() function is called to allow disk resizing.
+ _, updateFields := d.CanHotPlug()
+ return updateFields
+ })
if userRequested {
// Do some validation of the config diff.
@@ -2854,12 +2884,8 @@ func (vm *qemu) Update(args db.InstanceArgs, userRequested bool) error {
isRunning := vm.IsRunning()
- if isRunning && len(allUpdatedKeys) > 0 {
- return fmt.Errorf("Devices cannot be changed when VM is running")
- }
-
// Use the device interface to apply update changes.
- err = vm.updateDevices(removeDevices, addDevices, updateDevices, oldExpandedDevices)
+ err = vm.updateDevices(removeDevices, addDevices, updateDevices, oldExpandedDevices, isRunning)
if err != nil {
return err
}
@@ -3055,8 +3081,10 @@ func (vm *qemu) updateMemoryLimit(newLimit string) error {
return fmt.Errorf("Failed setting memory to %d bytes (currently %d bytes) as it was taking too long", newSizeBytes, curSizeBytes)
}
-func (vm *qemu) updateDevices(removeDevices deviceConfig.Devices, addDevices deviceConfig.Devices, updateDevices deviceConfig.Devices, oldExpandedDevices deviceConfig.Devices) error {
- isRunning := vm.IsRunning()
+func (vm *qemu) updateDevices(removeDevices deviceConfig.Devices, addDevices deviceConfig.Devices, updateDevices deviceConfig.Devices, oldExpandedDevices deviceConfig.Devices, isRunning bool) error {
+ if isRunning && (len(removeDevices) > 0 || len(addDevices) > 0 || len(updateDevices) > 0) {
+ return fmt.Errorf("Devices cannot be changed when VM is running")
+ }
// Remove devices in reverse order to how they were added.
for _, dev := range removeDevices.Reversed() {
From 68dde3234a2e89118806ee57f60e8f4cd04ef997 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Fri, 9 Oct 2020 19:44:42 +0100
Subject: [PATCH 2/2] lxd/device/disk: Adds comment about VM instances
depending on CanHotPlug fields for stopped disk resize
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/device/disk.go | 2 ++
1 file changed, 2 insertions(+)
diff --git a/lxd/device/disk.go b/lxd/device/disk.go
index 790618cc4a..4f728007e7 100644
--- a/lxd/device/disk.go
+++ b/lxd/device/disk.go
@@ -231,6 +231,8 @@ func (d *disk) validateEnvironment() error {
// CanHotPlug returns whether the device can be managed whilst the instance is running, it also
// returns a list of fields that can be updated without triggering a device remove & add.
+// Note: At current time VM instances rely on this function indicating live update of "size" field is possible
+// to allow disk resize when VM is stopped.
func (d *disk) CanHotPlug() (bool, []string) {
return true, []string{"limits.max", "limits.read", "limits.write", "size"}
}
More information about the lxc-devel
mailing list