From bbcf7ad022e5b0e8fd247175ef9cb98f1f6ca78f Mon Sep 17 00:00:00 2001
From: Iustin Pop <iustin@google.com>
Date: Mon, 22 Mar 2010 15:49:23 +0100
Subject: [PATCH] Extend the hypervisor API with name-only shutdown
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Currently the ShutdownInstance method of the hypervisors takes a full
instance object. However, when doing instance shutdowns from the node
only, we don't have a full object, just the name.

To handle this use case, we add a new β€˜name’ argument to the method,
which makes the shutdown not use/rely on the β€˜instance’ argument. The
KVM and fake hypervisors need a little bit of work, otherwise the change
is straightforward.

Signed-off-by: Iustin Pop <iustin@google.com>
Reviewed-by: RenΓ© Nussbaumer <rn@google.com>
---
 lib/hypervisor/hv_base.py   |  6 +++++-
 lib/hypervisor/hv_chroot.py |  7 +++++--
 lib/hypervisor/hv_fake.py   | 18 ++++++++++--------
 lib/hypervisor/hv_kvm.py    | 19 +++++++++++++------
 lib/hypervisor/hv_xen.py    | 13 +++++++------
 5 files changed, 40 insertions(+), 23 deletions(-)

diff --git a/lib/hypervisor/hv_base.py b/lib/hypervisor/hv_base.py
index db8bcb49a..af7aa9575 100644
--- a/lib/hypervisor/hv_base.py
+++ b/lib/hypervisor/hv_base.py
@@ -113,7 +113,7 @@ class BaseHypervisor(object):
     """Start an instance."""
     raise NotImplementedError
 
-  def StopInstance(self, instance, force=False, retry=False):
+  def StopInstance(self, instance, force=False, retry=False, name=None):
     """Stop an instance
 
     @type instance: L{objects.Instance}
@@ -122,6 +122,10 @@ class BaseHypervisor(object):
     @param force: whether to do a "hard" stop (destroy)
     @type retry: boolean
     @param retry: whether this is just a retry call
+    @type name: string or None
+    @param name: if this parameter is passed, the the instance object
+        should not be used (will be passed as None), and the shutdown
+        must be done by name only
 
     """
     raise NotImplementedError
diff --git a/lib/hypervisor/hv_chroot.py b/lib/hypervisor/hv_chroot.py
index cf40c5936..36b37a8eb 100644
--- a/lib/hypervisor/hv_chroot.py
+++ b/lib/hypervisor/hv_chroot.py
@@ -177,7 +177,7 @@ class ChrootManager(hv_base.BaseHypervisor):
       raise HypervisorError("Can't run the chroot start script: %s" %
                             result.output)
 
-  def StopInstance(self, instance, force=False, retry=False):
+  def StopInstance(self, instance, force=False, retry=False, name=None):
     """Stop an instance.
 
     This method has complicated cleanup tests, as we must:
@@ -186,7 +186,10 @@ class ChrootManager(hv_base.BaseHypervisor):
       - finally unmount the instance dir
 
     """
-    root_dir = self._InstanceDir(instance.name)
+    if name is None:
+      name = instance.name
+
+    root_dir = self._InstanceDir(name)
     if not os.path.exists(root_dir) or not self._IsDirLive(root_dir):
       return
 
diff --git a/lib/hypervisor/hv_fake.py b/lib/hypervisor/hv_fake.py
index d607d0de8..cea05d61e 100644
--- a/lib/hypervisor/hv_fake.py
+++ b/lib/hypervisor/hv_fake.py
@@ -136,13 +136,13 @@ class FakeHypervisor(hv_base.BaseHypervisor):
     finally:
       fh.close()
 
-  def _MarkDown(self, instance):
+  def _MarkDown(self, instance_name):
     """Mark the instance as running.
 
     This does no checks, which should be done by its callers.
 
     """
-    file_name = self._InstanceFile(instance.name)
+    file_name = self._InstanceFile(instance_name)
     utils.RemoveFile(file_name)
 
   def StartInstance(self, instance, block_devices):
@@ -162,17 +162,19 @@ class FakeHypervisor(hv_base.BaseHypervisor):
       raise errors.HypervisorError("Failed to start instance %s: %s" %
                                    (instance.name, err))
 
-  def StopInstance(self, instance, force=False, retry=False):
+  def StopInstance(self, instance, force=False, retry=False, name=None):
     """Stop an instance.
 
     For the fake hypervisor, this just removes the file in the base
     dir, if it exist, otherwise we raise an exception.
 
     """
-    if not self._IsAlive(instance.name):
+    if name is None:
+      name = instance.name
+    if not self._IsAlive(name):
       raise errors.HypervisorError("Failed to stop instance %s: %s" %
-                                   (instance.name, "not running"))
-    self._MarkDown(instance)
+                                   (name, "not running"))
+    self._MarkDown(name)
 
   def RebootInstance(self, instance):
     """Reboot an instance.
@@ -252,7 +254,7 @@ class FakeHypervisor(hv_base.BaseHypervisor):
     logging.debug("Fake hypervisor migrating %s to %s (live=%s)",
                   instance, target, live)
 
-    self._MarkDown(instance)
+    self._MarkDown(instance.name)
 
   def FinalizeMigration(self, instance, info, success):
     """Finalize an instance migration.
@@ -267,4 +269,4 @@ class FakeHypervisor(hv_base.BaseHypervisor):
       self._MarkUp(instance)
     else:
       # ensure it's down
-      self._MarkDown(instance)
+      self._MarkDown(instance.name)
diff --git a/lib/hypervisor/hv_kvm.py b/lib/hypervisor/hv_kvm.py
index 2035e2d6a..b9f20f3dd 100644
--- a/lib/hypervisor/hv_kvm.py
+++ b/lib/hypervisor/hv_kvm.py
@@ -613,19 +613,26 @@ class KVMHypervisor(hv_base.BaseHypervisor):
 
     return result
 
-  def StopInstance(self, instance, force=False, retry=False):
+  def StopInstance(self, instance, force=False, retry=False, name=None):
     """Stop an instance.
 
     """
-    pidfile, pid, alive = self._InstancePidAlive(instance.name)
+    if name is not None and not force:
+      raise errors.HypervisorError("Cannot shutdown cleanly by name only")
+    if name is None:
+      name = instance.name
+      acpi = instance.hvparams[constants.HV_ACPI]
+    else:
+      acpi = False
+    pidfile, pid, alive = self._InstancePidAlive(name)
     if pid > 0 and alive:
-      if force or not instance.hvparams[constants.HV_ACPI]:
+      if force or not acpi:
         utils.KillProcess(pid)
       else:
-        self._CallMonitorCommand(instance.name, 'system_powerdown')
+        self._CallMonitorCommand(name, 'system_powerdown')
 
-    if not self._InstancePidAlive(instance.name)[2]:
-      self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
+    if not self._InstancePidAlive(name)[2]:
+      self._RemoveInstanceRuntimeFiles(pidfile, name)
       return True
     else:
       return False
diff --git a/lib/hypervisor/hv_xen.py b/lib/hypervisor/hv_xen.py
index e16c03080..575e3b940 100644
--- a/lib/hypervisor/hv_xen.py
+++ b/lib/hypervisor/hv_xen.py
@@ -189,21 +189,22 @@ class XenHypervisor(hv_base.BaseHypervisor):
                                    (instance.name, result.fail_reason,
                                     result.output))
 
-  def StopInstance(self, instance, force=False, retry=False):
+  def StopInstance(self, instance, force=False, retry=False, name=None):
     """Stop an instance.
 
     """
-    self._RemoveConfigFile(instance.name)
+    if name is None:
+      name = instance.name
+    self._RemoveConfigFile(name)
     if force:
-      command = ["xm", "destroy", instance.name]
+      command = ["xm", "destroy", name]
     else:
-      command = ["xm", "shutdown", instance.name]
+      command = ["xm", "shutdown", name]
     result = utils.RunCmd(command)
 
     if result.failed:
       raise errors.HypervisorError("Failed to stop instance %s: %s, %s" %
-                                   (instance.name, result.fail_reason,
-                                    result.output))
+                                   (name, result.fail_reason, result.output))
 
   def RebootInstance(self, instance):
     """Reboot an instance.
-- 
GitLab