Modify 'Hypervisor.ListInstances' to exclude instances that have been
shutdown by the user.  In other words, 'ListInstances' includes only
instances that are actually running.  This modification requires also
modifying the functions in the 'ganeti.backend' module that start,
stop, and reboot an instance, in order to work properly with user
shutdown.

Signed-off-by: Jose A. Lopes <[email protected]>
---
 lib/backend.py           | 70 +++++++++++++++++++++++++++---------------------
 lib/hypervisor/hv_kvm.py |  2 +-
 lib/hypervisor/hv_xen.py | 13 ++++++---
 3 files changed, 51 insertions(+), 34 deletions(-)

diff --git a/lib/backend.py b/lib/backend.py
index a016913..cc751af 100644
--- a/lib/backend.py
+++ b/lib/backend.py
@@ -55,6 +55,7 @@ from ganeti import errors
 from ganeti import utils
 from ganeti import ssh
 from ganeti import hypervisor
+from ganeti.hypervisor import hv_base
 from ganeti import constants
 from ganeti.storage import bdev
 from ganeti.storage import drbd
@@ -1810,6 +1811,18 @@ def _GatherAndLinkBlockDevs(instance):
   return block_devices
 
 
+def _IsInstanceUserDown(instance_info):
+  return instance_info and \
+      "state" in instance_info and \
+      hv_base.HvInstanceState.IsShutdown(instance_info["state"])
+
+
+def _GetInstanceInfo(instance):
+  """Helper function L{GetInstanceInfo}"""
+  return GetInstanceInfo(instance.name, instance.hypervisor,
+                         hvparams=instance.hvparams)
+
+
 def StartInstance(instance, startup_paused, reason, store_reason=True):
   """Start an instance.
 
@@ -1824,11 +1837,10 @@ def StartInstance(instance, startup_paused, reason, 
store_reason=True):
   @rtype: None
 
   """
-  running_instances = GetInstanceListForHypervisor(instance.hypervisor,
-                                                   instance.hvparams)
+  instance_info = _GetInstanceInfo(instance)
 
-  if instance.name in running_instances:
-    logging.info("Instance %s already running, not starting", instance.name)
+  if instance_info and not _IsInstanceUserDown(instance_info):
+    logging.info("Instance '%s' already running, not starting", instance.name)
     return
 
   try:
@@ -1860,12 +1872,10 @@ def InstanceShutdown(instance, timeout, reason, 
store_reason=True):
   @rtype: None
 
   """
-  hv_name = instance.hypervisor
-  hyper = hypervisor.GetHypervisor(hv_name)
-  iname = instance.name
+  hyper = hypervisor.GetHypervisor(instance.hypervisor)
 
-  if instance.name not in hyper.ListInstances(hvparams=instance.hvparams):
-    logging.info("Instance %s not running, doing nothing", iname)
+  if not _GetInstanceInfo(instance):
+    logging.info("Instance '%s' not running, doing nothing", instance.name)
     return
 
   class _TryShutdown(object):
@@ -1873,7 +1883,7 @@ def InstanceShutdown(instance, timeout, reason, 
store_reason=True):
       self.tried_once = False
 
     def __call__(self):
-      if iname not in hyper.ListInstances(hvparams=instance.hvparams):
+      if not _GetInstanceInfo(instance):
         return
 
       try:
@@ -1881,12 +1891,12 @@ def InstanceShutdown(instance, timeout, reason, 
store_reason=True):
         if store_reason:
           _StoreInstReasonTrail(instance.name, reason)
       except errors.HypervisorError, err:
-        if iname not in hyper.ListInstances(hvparams=instance.hvparams):
-          # if the instance is no longer existing, consider this a
-          # success and go to cleanup
+        # if the instance is no longer existing, consider this a
+        # success and go to cleanup
+        if not _GetInstanceInfo(instance):
           return
 
-        _Fail("Failed to stop instance %s: %s", iname, err)
+        _Fail("Failed to stop instance '%s': %s", instance.name, err)
 
       self.tried_once = True
 
@@ -1896,27 +1906,27 @@ def InstanceShutdown(instance, timeout, reason, 
store_reason=True):
     utils.Retry(_TryShutdown(), 5, timeout)
   except utils.RetryTimeout:
     # the shutdown did not succeed
-    logging.error("Shutdown of '%s' unsuccessful, forcing", iname)
+    logging.error("Shutdown of '%s' unsuccessful, forcing", instance.name)
 
     try:
       hyper.StopInstance(instance, force=True)
     except errors.HypervisorError, err:
-      if iname in hyper.ListInstances(hvparams=instance.hvparams):
-        # only raise an error if the instance still exists, otherwise
-        # the error could simply be "instance ... unknown"!
-        _Fail("Failed to force stop instance %s: %s", iname, err)
+      # only raise an error if the instance still exists, otherwise
+      # the error could simply be "instance ... unknown"!
+      if _GetInstanceInfo(instance):
+        _Fail("Failed to force stop instance '%s': %s", instance.name, err)
 
     time.sleep(1)
 
-    if iname in hyper.ListInstances(hvparams=instance.hvparams):
-      _Fail("Could not shutdown instance %s even by destroy", iname)
+    if _GetInstanceInfo(instance):
+      _Fail("Could not shutdown instance '%s' even by destroy", instance.name)
 
   try:
     hyper.CleanupInstance(instance.name)
   except errors.HypervisorError, err:
     logging.warning("Failed to execute post-shutdown cleanup step: %s", err)
 
-  _RemoveBlockDevLinks(iname, instance.disks)
+  _RemoveBlockDevLinks(instance.name, instance.disks)
 
 
 def InstanceReboot(instance, reboot_type, shutdown_timeout, reason):
@@ -1942,18 +1952,18 @@ def InstanceReboot(instance, reboot_type, 
shutdown_timeout, reason):
   @rtype: None
 
   """
-  running_instances = GetInstanceListForHypervisor(instance.hypervisor,
-                                                   instance.hvparams)
-
-  if instance.name not in running_instances:
-    _Fail("Cannot reboot instance %s that is not running", instance.name)
+  # TODO: this is inconsistent with 'StartInstance' and 'InstanceShutdown'
+  # because those functions simply 'return' on error whereas this one
+  # raises an exception with '_Fail'
+  if not _GetInstanceInfo(instance):
+    _Fail("Cannot reboot instance '%s' that is not running", instance.name)
 
   hyper = hypervisor.GetHypervisor(instance.hypervisor)
   if reboot_type == constants.INSTANCE_REBOOT_SOFT:
     try:
       hyper.RebootInstance(instance)
     except errors.HypervisorError, err:
-      _Fail("Failed to soft reboot instance %s: %s", instance.name, err)
+      _Fail("Failed to soft reboot instance '%s': %s", instance.name, err)
   elif reboot_type == constants.INSTANCE_REBOOT_HARD:
     try:
       InstanceShutdown(instance, shutdown_timeout, reason, store_reason=False)
@@ -1961,9 +1971,9 @@ def InstanceReboot(instance, reboot_type, 
shutdown_timeout, reason):
       _StoreInstReasonTrail(instance.name, reason)
       return result
     except errors.HypervisorError, err:
-      _Fail("Failed to hard reboot instance %s: %s", instance.name, err)
+      _Fail("Failed to hard reboot instance '%s': %s", instance.name, err)
   else:
-    _Fail("Invalid reboot_type received: %s", reboot_type)
+    _Fail("Invalid reboot_type received: '%s'", reboot_type)
 
 
 def InstanceBalloonMemory(instance, memory):
diff --git a/lib/hypervisor/hv_kvm.py b/lib/hypervisor/hv_kvm.py
index 52d6e5f..ed5488e 100644
--- a/lib/hypervisor/hv_kvm.py
+++ b/lib/hypervisor/hv_kvm.py
@@ -1199,7 +1199,7 @@ class KVMHypervisor(hv_base.BaseHypervisor):
     """
     result = []
     for name in os.listdir(self._PIDS_DIR):
-      if self._InstancePidAlive(name)[2] or self._IsUserShutdown(name):
+      if self._InstancePidAlive(name)[2]:
         result.append(name)
     return result
 
diff --git a/lib/hypervisor/hv_xen.py b/lib/hypervisor/hv_xen.py
index b1fc96c..82e12aa 100644
--- a/lib/hypervisor/hv_xen.py
+++ b/lib/hypervisor/hv_xen.py
@@ -593,10 +593,17 @@ class XenHypervisor(hv_base.BaseHypervisor):
   def ListInstances(self, hvparams=None):
     """Get the list of running instances.
 
+    @type hvparams: dict of strings
+    @param hvparams: the instance's hypervisor params
+
+    @rtype: list of strings
+    @return: names of running instances
+
     """
-    instance_list = self._GetInstanceList(False, hvparams)
-    names = [info[0] for info in instance_list]
-    return names
+    instance_list = _GetRunningInstanceList(
+      lambda: self._RunXen(["list"], hvparams),
+      False)
+    return [info[0] for info in instance_list]
 
   def GetInstanceInfo(self, instance_name, hvparams=None):
     """Get instance properties.
-- 
1.9.1.423.g4596e3a

Reply via email to