drive_del after device_del in disk hot-remove
[ganeti-local] / lib / hypervisor / hv_fake.py
index 441e44b..b5abf7f 100644 (file)
@@ -1,7 +1,7 @@
 #
 #
 
-# Copyright (C) 2006, 2007, 2008 Google Inc.
+# Copyright (C) 2006, 2007, 2008, 2013 Google Inc.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -31,6 +31,7 @@ from ganeti import utils
 from ganeti import constants
 from ganeti import errors
 from ganeti import objects
+from ganeti import pathutils
 from ganeti.hypervisor import hv_base
 
 
@@ -41,24 +42,31 @@ class FakeHypervisor(hv_base.BaseHypervisor):
   a real virtualisation software installed.
 
   """
+  PARAMETERS = {
+    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
+    }
+
   CAN_MIGRATE = True
 
-  _ROOT_DIR = constants.RUN_GANETI_DIR + "/fake-hypervisor"
+  _ROOT_DIR = pathutils.RUN_DIR + "/fake-hypervisor"
 
   def __init__(self):
     hv_base.BaseHypervisor.__init__(self)
     utils.EnsureDirs([(self._ROOT_DIR, constants.RUN_DIRS_MODE)])
 
-  def ListInstances(self):
+  def ListInstances(self, hvparams=None):
     """Get the list of running instances.
 
     """
     return os.listdir(self._ROOT_DIR)
 
-  def GetInstanceInfo(self, instance_name):
+  def GetInstanceInfo(self, instance_name, hvparams=None):
     """Get instance properties.
 
+    @type instance_name: string
     @param instance_name: the instance name
+    @type hvparams: dict of strings
+    @param hvparams: hvparams to be used with this instance
 
     @return: tuple of (name, id, memory, vcpus, stat, times)
 
@@ -81,9 +89,11 @@ class FakeHypervisor(hv_base.BaseHypervisor):
       raise errors.HypervisorError("Failed to list instance %s: %s" %
                                    (instance_name, err))
 
-  def GetAllInstancesInfo(self):
+  def GetAllInstancesInfo(self, hvparams=None):
     """Get properties of all instances.
 
+    @type hvparams: dict of strings
+    @param hvparams: hypervisor parameter
     @return: list of tuples (name, id, memory, vcpus, stat, times)
 
     """
@@ -123,7 +133,7 @@ class FakeHypervisor(hv_base.BaseHypervisor):
     file_name = self._InstanceFile(instance_name)
     return os.path.exists(file_name)
 
-  def _MarkUp(self, instance):
+  def _MarkUp(self, instance, memory):
     """Mark the instance as running.
 
     This does no checks, which should be done by its callers.
@@ -133,7 +143,7 @@ class FakeHypervisor(hv_base.BaseHypervisor):
     fh = file(file_name, "w")
     try:
       fh.write("0\n%d\n%d\n" %
-               (instance.beparams[constants.BE_MEMORY],
+               (memory,
                 instance.beparams[constants.BE_VCPUS]))
     finally:
       fh.close()
@@ -159,7 +169,7 @@ class FakeHypervisor(hv_base.BaseHypervisor):
       raise errors.HypervisorError("Failed to start instance %s: %s" %
                                    (instance.name, "already running"))
     try:
-      self._MarkUp(instance)
+      self._MarkUp(instance, self._InstanceStartupMemory(instance))
     except IOError, err:
       raise errors.HypervisorError("Failed to start instance %s: %s" %
                                    (instance.name, err))
@@ -186,15 +196,28 @@ class FakeHypervisor(hv_base.BaseHypervisor):
     """
     return
 
-  def GetNodeInfo(self):
-    """Return information about the node.
+  def BalloonInstanceMemory(self, instance, mem):
+    """Balloon an instance memory to a certain value.
+
+    @type instance: L{objects.Instance}
+    @param instance: instance to be accepted
+    @type mem: int
+    @param mem: actual memory size to use for instance runtime
 
-    This is just a wrapper over the base GetLinuxNodeInfo method.
+    """
+    if not self._IsAlive(instance.name):
+      raise errors.HypervisorError("Failed to balloon memory for %s: %s" %
+                                   (instance.name, "not running"))
+    try:
+      self._MarkUp(instance, mem)
+    except EnvironmentError, err:
+      raise errors.HypervisorError("Failed to balloon memory for %s: %s" %
+                                   (instance.name, utils.ErrnoOrStr(err)))
+
+  def GetNodeInfo(self, hvparams=None):
+    """Return information about the node.
 
-    @return: a dict with the following keys (values in MiB):
-          - memory_total: the total memory size on the node
-          - memory_free: the available memory on the node for instances
-          - memory_dom0: the memory used by the node itself, if available
+    See L{BaseHypervisor.GetLinuxNodeInfo}.
 
     """
     result = self.GetLinuxNodeInfo()
@@ -205,7 +228,7 @@ class FakeHypervisor(hv_base.BaseHypervisor):
     return result
 
   @classmethod
-  def GetInstanceConsole(cls, instance, hvparams, beparams):
+  def GetInstanceConsole(cls, instance, primary_node, hvparams, beparams):
     """Return information for connecting to the console of an instance.
 
     """
@@ -214,20 +237,31 @@ class FakeHypervisor(hv_base.BaseHypervisor):
                                    message=("Console not available for fake"
                                             " hypervisor"))
 
-  def Verify(self):
+  def Verify(self, hvparams=None):
     """Verify the hypervisor.
 
     For the fake hypervisor, it just checks the existence of the base
     dir.
 
+    @type hvparams: dict of strings
+    @param hvparams: hypervisor parameters to be verified against; not used
+      for fake hypervisors
+
+    @return: Problem description if something is wrong, C{None} otherwise
+
     """
-    if not os.path.exists(self._ROOT_DIR):
-      return "The required directory '%s' does not exist." % self._ROOT_DIR
+    if os.path.exists(self._ROOT_DIR):
+      return None
+    else:
+      return "The required directory '%s' does not exist" % self._ROOT_DIR
 
   @classmethod
-  def PowercycleNode(cls):
+  def PowercycleNode(cls, hvparams=None):
     """Fake hypervisor powercycle, just a wrapper over Linux powercycle.
 
+    @type hvparams: dict of strings
+    @param hvparams: hypervisor params to be used on this node
+
     """
     cls.LinuxPowercycle()
 
@@ -245,9 +279,11 @@ class FakeHypervisor(hv_base.BaseHypervisor):
     if self._IsAlive(instance.name):
       raise errors.HypervisorError("Can't accept instance, already running")
 
-  def MigrateInstance(self, instance, target, live):
+  def MigrateInstance(self, cluster_name, instance, target, live):
     """Migrate an instance.
 
+    @type cluster_name: string
+    @param cluster_name: name of the cluster
     @type instance: L{objects.Instance}
     @param instance: the instance to be migrated
     @type target: string
@@ -259,19 +295,62 @@ class FakeHypervisor(hv_base.BaseHypervisor):
     logging.debug("Fake hypervisor migrating %s to %s (live=%s)",
                   instance, target, live)
 
-    self._MarkDown(instance.name)
-
-  def FinalizeMigration(self, instance, info, success):
-    """Finalize an instance migration.
+  def FinalizeMigrationDst(self, instance, info, success):
+    """Finalize the instance migration on the target node.
 
     For the fake hv, this just marks the instance up.
 
     @type instance: L{objects.Instance}
     @param instance: instance whose migration is being finalized
+    @type info: string/data (opaque)
+    @param info: migration information, from the source node
+    @type success: boolean
+    @param success: whether the migration was a success or a failure
 
     """
     if success:
-      self._MarkUp(instance)
+      self._MarkUp(instance, self._InstanceStartupMemory(instance))
     else:
       # ensure it's down
       self._MarkDown(instance.name)
+
+  def PostMigrationCleanup(self, instance):
+    """Clean-up after a migration.
+
+    To be executed on the source node.
+
+    @type instance: L{objects.Instance}
+    @param instance: the instance that was migrated
+
+    """
+    pass
+
+  def FinalizeMigrationSource(self, instance, success, live):
+    """Finalize the instance migration on the source node.
+
+    @type instance: L{objects.Instance}
+    @param instance: the instance that was migrated
+    @type success: bool
+    @param success: whether the migration succeeded or not
+    @type live: bool
+    @param live: whether the user requested a live migration or not
+
+    """
+    # pylint: disable=W0613
+    if success:
+      self._MarkDown(instance.name)
+
+  def GetMigrationStatus(self, instance):
+    """Get the migration status
+
+    The fake hypervisor migration always succeeds.
+
+    @type instance: L{objects.Instance}
+    @param instance: the instance that is being migrated
+    @rtype: L{objects.MigrationStatus}
+    @return: the status of the current migration (one of
+             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
+             progress info that can be retrieved from the hypervisor
+
+    """
+    return objects.MigrationStatus(status=constants.HV_MIGRATION_COMPLETED)