From fb030283bed9e41a0343581fa21b81b2ebb07f15 Mon Sep 17 00:00:00 2001
From: Xiaoyan Ding <xyding@cn.ibm.com>
Date: Mon, 24 Feb 2014 16:17:46 +0800
Subject: [PATCH] VMWare: add power off vm before detach disk during unrescue

Non Hot Plug type disk like IDE can only be detached when the VM is power off.

Change-Id: Ib1f387a41abe2b52357854e90c2535ebb7b43f18
Close-bug: #1279199
(cherry picked from commit 1e1915aaaca38b5691794e0e052a42b9d95dd3c2)
---
 nova/tests/virt/vmwareapi/test_driver_api.py | 27 ++++++++++++++++++++++-----
 nova/virt/vmwareapi/vmops.py                 | 21 ++++++++++++++++-----
 2 files changed, 38 insertions(+), 10 deletions(-)

diff --git a/nova/tests/virt/vmwareapi/test_driver_api.py b/nova/tests/virt/vmwareapi/test_driver_api.py
index fb60335..c1481aa 100644
--- a/nova/tests/virt/vmwareapi/test_driver_api.py
+++ b/nova/tests/virt/vmwareapi/test_driver_api.py
@@ -1273,14 +1273,31 @@ def test_rescue_with_config_drive(self):
 
     def test_unrescue(self):
         self._rescue()
+        self.test_vm_ref = None
+        self.test_device_name = None
 
-        def fake_detach_disk_from_vm(*args, **kwargs):
-            pass
+        def fake_power_off_vm_ref(vm_ref):
+            self.test_vm_ref = vm_ref
+            self.assertIsNotNone(vm_ref)
 
-        self.stubs.Set(self.conn._volumeops, "detach_disk_from_vm",
-                       fake_detach_disk_from_vm)
+        def fake_detach_disk_from_vm(vm_ref, instance,
+                                     device_name, destroy_disk=False):
+            self.test_device_name = device_name
+            info = self.conn.get_info(instance)
+            self._check_vm_info(info, power_state.SHUTDOWN)
 
-        self.conn.unrescue(self.instance, None)
+        with contextlib.nested(
+            mock.patch.object(self.conn._vmops, "_power_off_vm_ref",
+                              side_effect=fake_power_off_vm_ref),
+            mock.patch.object(self.conn._volumeops, "detach_disk_from_vm",
+                              side_effect=fake_detach_disk_from_vm),
+        ) as (poweroff, detach):
+            self.conn.unrescue(self.instance, None)
+            poweroff.assert_called_once_with(self.test_vm_ref)
+            detach.assert_called_once_with(self.test_vm_ref, mock.ANY,
+                                           self.test_device_name)
+            self.test_vm_ref = None
+            self.test_device_name = None
         info = self.conn.get_info({'name': 1, 'uuid': self.uuid,
                                    'node': self.instance_node})
         self._check_vm_info(info, power_state.RUNNING)
diff --git a/nova/virt/vmwareapi/vmops.py b/nova/virt/vmwareapi/vmops.py
index 0c28a29..30f8373 100644
--- a/nova/virt/vmwareapi/vmops.py
+++ b/nova/virt/vmwareapi/vmops.py
@@ -1159,12 +1159,26 @@ def unrescue(self, instance):
                         "get_dynamic_property", vm_rescue_ref,
                         "VirtualMachine", "config.hardware.device")
         device = vm_util.get_vmdk_volume_disk(hardware_devices, path=vmdk_path)
+        self._power_off_vm_ref(vm_rescue_ref)
         self._volumeops.detach_disk_from_vm(vm_rescue_ref, r_instance, device)
         self.destroy(r_instance, None, instance_name=instance_name)
         self._power_on(instance)
 
+    def _power_off_vm_ref(self, vm_ref):
+        """Power off the specifed vm.
+
+        :param vm_ref: a reference object to the VM.
+        """
+        poweroff_task = self._session._call_method(
+                                    self._session._get_vim(),
+                                    "PowerOffVM_Task", vm_ref)
+        self._session._wait_for_task(poweroff_task)
+
     def power_off(self, instance):
-        """Power off the specified instance."""
+        """Power off the specified instance.
+
+        :param instance: nova.objects.instance.Instance
+        """
         vm_ref = vm_util.get_vm_ref(self._session, instance)
 
         pwr_state = self._session._call_method(vim_util,
@@ -1173,10 +1187,7 @@ def power_off(self, instance):
         # Only PoweredOn VMs can be powered off.
         if pwr_state == "poweredOn":
             LOG.debug(_("Powering off the VM"), instance=instance)
-            poweroff_task = self._session._call_method(
-                                        self._session._get_vim(),
-                                        "PowerOffVM_Task", vm_ref)
-            self._session._wait_for_task(poweroff_task)
+            self._power_off_vm_ref(vm_ref)
             LOG.debug(_("Powered off the VM"), instance=instance)
         # Raise Exception if VM is suspended
         elif pwr_state == "suspended":
-- 
1.9.3

