Merge branch 'devel-2.5'
[ganeti-local] / lib / hypervisor / hv_xen.py
index 5a4bdb9..f8113a8 100644 (file)
@@ -84,6 +84,38 @@ class XenHypervisor(hv_base.BaseHypervisor):
     """
     utils.RemoveFile("/etc/xen/%s" % instance_name)
 
+  @classmethod
+  def _CreateConfigCpus(cls, cpu_mask):
+    """Create a CPU config string that's compatible with Xen's
+    configuration file.
+
+    """
+    # Convert the string CPU mask to a list of list of int's
+    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
+
+    if len(cpu_list) == 1:
+      all_cpu_mapping = cpu_list[0]
+      if all_cpu_mapping == constants.CPU_PINNING_OFF:
+        # If CPU pinning has 1 entry that's "all", then remove the
+        # parameter from the config file
+        return None
+      else:
+        # If CPU pinning has one non-all entry, mapping all vCPUS (the entire
+        # VM) to one physical CPU, using format 'cpu = "C"'
+        return "cpu = \"%s\"" % ",".join(map(str, all_cpu_mapping))
+    else:
+      def _GetCPUMap(vcpu):
+        if vcpu[0] == constants.CPU_PINNING_ALL_VAL:
+          cpu_map = constants.CPU_PINNING_ALL_XEN
+        else:
+          cpu_map = ",".join(map(str, vcpu))
+        return "\"%s\"" % cpu_map
+
+      # build the result string in format 'cpus = [ "c", "c", "c" ]',
+      # where each c is a physical CPU number, a range, a list, or any
+      # combination
+      return "cpus = [ %s ]" % ", ".join(map(_GetCPUMap, cpu_list))
+
   @staticmethod
   def _RunXmList(xmlist_errors):
     """Helper function for L{_GetXMList} to run "xm list".
@@ -392,7 +424,7 @@ class XenHypervisor(hv_base.BaseHypervisor):
     """
     pass
 
-  def FinalizeMigration(self, instance, info, success):
+  def FinalizeMigrationDst(self, instance, info, success):
     """Finalize an instance migration.
 
     After a successful migration we write the xen config file.
@@ -440,11 +472,42 @@ class XenHypervisor(hv_base.BaseHypervisor):
     if result.failed:
       raise errors.HypervisorError("Failed to migrate instance %s: %s" %
                                    (instance.name, result.output))
-    # remove old xen file after migration succeeded
-    try:
-      self._RemoveConfigFile(instance.name)
-    except EnvironmentError:
-      logging.exception("Failure while removing instance config file")
+
+  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:
+      # remove old xen file after migration succeeded
+      try:
+        self._RemoveConfigFile(instance.name)
+      except EnvironmentError:
+        logging.exception("Failure while removing instance config file")
+
+  def GetMigrationStatus(self, instance):
+    """Get the migration status
+
+    As MigrateInstance for Xen is still blocking, if this method is called it
+    means that MigrateInstance has completed successfully. So we can safely
+    assume that the migration was successful and notify this fact to the client.
+
+    @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)
 
   @classmethod
   def PowercycleNode(cls):
@@ -480,7 +543,8 @@ class XenPvmHypervisor(XenHypervisor):
     # TODO: Add a check for the blockdev prefix (matching [a-z:] or similar).
     constants.HV_BLOCKDEV_PREFIX: hv_base.NO_CHECK,
     constants.HV_REBOOT_BEHAVIOR:
-      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS)
+      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
+    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
     }
 
   @classmethod
@@ -519,6 +583,10 @@ class XenPvmHypervisor(XenHypervisor):
     # rest of the settings
     config.write("memory = %d\n" % instance.beparams[constants.BE_MEMORY])
     config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
+    cpu_pinning = cls._CreateConfigCpus(hvp[constants.HV_CPU_MASK])
+    if cpu_pinning:
+      config.write("%s\n" % cpu_pinning)
+
     config.write("name = '%s'\n" % instance.name)
 
     vif_data = []
@@ -589,7 +657,8 @@ class XenHvmHypervisor(XenHypervisor):
     # TODO: Add a check for the blockdev prefix (matching [a-z:] or similar).
     constants.HV_BLOCKDEV_PREFIX: hv_base.NO_CHECK,
     constants.HV_REBOOT_BEHAVIOR:
-      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS)
+      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
+    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
     }
 
   @classmethod
@@ -609,6 +678,10 @@ class XenHvmHypervisor(XenHypervisor):
     config.write("builder = 'hvm'\n")
     config.write("memory = %d\n" % instance.beparams[constants.BE_MEMORY])
     config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
+    cpu_pinning = cls._CreateConfigCpus(hvp[constants.HV_CPU_MASK])
+    if cpu_pinning:
+      config.write("%s\n" % cpu_pinning)
+
     config.write("name = '%s'\n" % instance.name)
     if hvp[constants.HV_PAE]:
       config.write("pae = 1\n")