Browse Source

libvirt: fix nova can't delete the instance with nvram

Currently libvirt needs a flag when deleting an VM with a nvram file,
without which nova can't delete an instance booted with UEFI. Add
deletion flag for NVRAM. Also add a test case.

Co-authored-by: Derek Higgins <derekh@redhat.com>
Change-Id: I46baa952b6c3a1a4c5cf2660931f317cafb5757d
Closes-Bug: #1567807
(cherry picked from commit 539d381434)
tags/14.0.4
Kevin Zhao 2 years ago
parent
commit
bf6c5ba865

+ 1
- 0
nova/tests/unit/virt/libvirt/fakelibvirt.py View File

@@ -68,6 +68,7 @@ VIR_DOMAIN_EVENT_SHUTDOWN = 6
68 68
 VIR_DOMAIN_EVENT_PMSUSPENDED = 7
69 69
 
70 70
 VIR_DOMAIN_UNDEFINE_MANAGED_SAVE = 1
71
+VIR_DOMAIN_UNDEFINE_NVRAM = 4
71 72
 
72 73
 VIR_DOMAIN_AFFECT_CURRENT = 0
73 74
 VIR_DOMAIN_AFFECT_LIVE = 1

+ 26
- 0
nova/tests/unit/virt/libvirt/test_driver.py View File

@@ -11843,6 +11843,32 @@ class LibvirtConnTestCase(test.NoDBTestCase):
11843 11843
         drvr.destroy(self.context, instance, [])
11844 11844
         mock_save.assert_called_once_with()
11845 11845
 
11846
+    @mock.patch.object(objects.Instance, 'save')
11847
+    def test_destroy_removes_nvram(self, mock_save):
11848
+        mock_domain = mock.Mock(fakelibvirt.virDomain)
11849
+        mock_domain.ID.return_value = 123
11850
+
11851
+        drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
11852
+        drvr._host.get_domain = mock.Mock(return_value=mock_domain)
11853
+        drvr._has_uefi_support = mock.Mock(return_value=True)
11854
+        drvr.delete_instance_files = mock.Mock(return_value=None)
11855
+        drvr.get_info = mock.Mock(return_value=
11856
+            hardware.InstanceInfo(state=power_state.SHUTDOWN, id=-1)
11857
+        )
11858
+
11859
+        instance = objects.Instance(self.context, **self.test_instance)
11860
+        drvr.destroy(self.context, instance, [])
11861
+
11862
+        self.assertEqual(1, mock_domain.ID.call_count)
11863
+        mock_domain.destroy.assert_called_once_with()
11864
+        # undefineFlags should now be called with 5 as uefi us supported
11865
+        mock_domain.undefineFlags.assert_has_calls([mock.call(
11866
+            fakelibvirt.VIR_DOMAIN_UNDEFINE_MANAGED_SAVE |
11867
+            fakelibvirt.VIR_DOMAIN_UNDEFINE_NVRAM
11868
+        )])
11869
+        mock_domain.undefine.assert_not_called()
11870
+        mock_save.assert_called_once_with()
11871
+
11846 11872
     def test_destroy_timed_out(self):
11847 11873
         mock = self.mox.CreateMock(fakelibvirt.virDomain)
11848 11874
         mock.ID()

+ 6
- 0
nova/tests/unit/virt/libvirt/test_guest.py View File

@@ -161,6 +161,12 @@ class GuestTestCase(test.NoDBTestCase):
161 161
         self.domain.undefineFlags.assert_called_once_with(
162 162
             fakelibvirt.VIR_DOMAIN_UNDEFINE_MANAGED_SAVE)
163 163
 
164
+    def test_delete_configuration_with_nvram(self):
165
+        self.guest.delete_configuration(support_uefi=True)
166
+        self.domain.undefineFlags.assert_called_once_with(
167
+            fakelibvirt.VIR_DOMAIN_UNDEFINE_MANAGED_SAVE |
168
+            fakelibvirt.VIR_DOMAIN_UNDEFINE_NVRAM)
169
+
164 170
     def test_delete_configuration_exception(self):
165 171
         self.domain.undefineFlags.side_effect = fakelibvirt.libvirtError(
166 172
             'oops')

+ 6
- 3
nova/virt/libvirt/driver.py View File

@@ -865,7 +865,8 @@ class LibvirtDriver(driver.ComputeDriver):
865 865
         try:
866 866
             guest = self._host.get_guest(instance)
867 867
             try:
868
-                guest.delete_configuration()
868
+                support_uefi = self._has_uefi_support()
869
+                guest.delete_configuration(support_uefi)
869 870
             except libvirt.libvirtError as e:
870 871
                 with excutils.save_and_reraise_exception():
871 872
                     errcode = e.get_error_code()
@@ -1203,7 +1204,8 @@ class LibvirtDriver(driver.ComputeDriver):
1203 1204
             #             If any part of this block fails, the domain is
1204 1205
             #             re-defined regardless.
1205 1206
             if guest.has_persistent_configuration():
1206
-                guest.delete_configuration()
1207
+                support_uefi = self._has_uefi_support()
1208
+                guest.delete_configuration(support_uefi)
1207 1209
 
1208 1210
             # Start copy with VIR_DOMAIN_REBASE_REUSE_EXT flag to
1209 1211
             # allow writing to existing external volume file
@@ -1704,7 +1706,8 @@ class LibvirtDriver(driver.ComputeDriver):
1704 1706
             #             If any part of this block fails, the domain is
1705 1707
             #             re-defined regardless.
1706 1708
             if guest.has_persistent_configuration():
1707
-                guest.delete_configuration()
1709
+                support_uefi = self._has_uefi_support()
1710
+                guest.delete_configuration(support_uefi)
1708 1711
 
1709 1712
             # NOTE (rmk): Establish a temporary mirror of our root disk and
1710 1713
             #             issue an abort once we have a complete copy.

+ 5
- 3
nova/virt/libvirt/guest.py View File

@@ -255,11 +255,13 @@ class Guest(object):
255 255
                 yield VCPUInfo(
256 256
                     id=vcpu[0], cpu=vcpu[3], state=vcpu[1], time=vcpu[2])
257 257
 
258
-    def delete_configuration(self):
258
+    def delete_configuration(self, support_uefi=False):
259 259
         """Undefines a domain from hypervisor."""
260 260
         try:
261
-            self._domain.undefineFlags(
262
-                libvirt.VIR_DOMAIN_UNDEFINE_MANAGED_SAVE)
261
+            flags = libvirt.VIR_DOMAIN_UNDEFINE_MANAGED_SAVE
262
+            if support_uefi:
263
+                flags |= libvirt.VIR_DOMAIN_UNDEFINE_NVRAM
264
+            self._domain.undefineFlags(flags)
263 265
         except libvirt.libvirtError:
264 266
             LOG.debug("Error from libvirt during undefineFlags. %d"
265 267
                       "Retrying with undefine", self.id)

Loading…
Cancel
Save