Use hvparams in instance migration
[ganeti-local] / lib / hypervisor / hv_xen.py
index d2638f9..63ab47c 100644 (file)
@@ -1,7 +1,7 @@
 #
 #
 
 #
 #
 
-# Copyright (C) 2006, 2007, 2008, 2009, 2010 Google Inc.
+# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 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
 #
 # 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
@@ -24,6 +24,7 @@
 """
 
 import logging
 """
 
 import logging
+import string # pylint: disable=W0402
 from cStringIO import StringIO
 
 from ganeti import constants
 from cStringIO import StringIO
 
 from ganeti import constants
@@ -32,6 +33,272 @@ from ganeti import utils
 from ganeti.hypervisor import hv_base
 from ganeti import netutils
 from ganeti import objects
 from ganeti.hypervisor import hv_base
 from ganeti import netutils
 from ganeti import objects
+from ganeti import pathutils
+from ganeti import ssconf
+
+
+XEND_CONFIG_FILE = utils.PathJoin(pathutils.XEN_CONFIG_DIR, "xend-config.sxp")
+XL_CONFIG_FILE = utils.PathJoin(pathutils.XEN_CONFIG_DIR, "xen/xl.conf")
+VIF_BRIDGE_SCRIPT = utils.PathJoin(pathutils.XEN_CONFIG_DIR,
+                                   "scripts/vif-bridge")
+_DOM0_NAME = "Domain-0"
+_DISK_LETTERS = string.ascii_lowercase
+
+_FILE_DRIVER_MAP = {
+  constants.FD_LOOP: "file",
+  constants.FD_BLKTAP: "tap:aio",
+  }
+
+
+def _CreateConfigCpus(cpu_mask):
+  """Create a CPU config string for Xen's config 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))
+
+
+def _RunInstanceList(fn, instance_list_errors):
+  """Helper function for L{_GetInstanceList} to retrieve the list of instances
+  from xen.
+
+  @type fn: callable
+  @param fn: Function to query xen for the list of instances
+  @type instance_list_errors: list
+  @param instance_list_errors: Error list
+  @rtype: list
+
+  """
+  result = fn()
+  if result.failed:
+    logging.error("Retrieving the instance list from xen failed (%s): %s",
+                  result.fail_reason, result.output)
+    instance_list_errors.append(result)
+    raise utils.RetryAgain()
+
+  # skip over the heading
+  return result.stdout.splitlines()
+
+
+def _ParseXmList(lines, include_node):
+  """Parses the output of C{xm list}.
+
+  @type lines: list
+  @param lines: Output lines of C{xm list}
+  @type include_node: boolean
+  @param include_node: If True, return information for Dom0
+  @return: list of tuple containing (name, id, memory, vcpus, state, time
+    spent)
+
+  """
+  result = []
+
+  # Iterate through all lines while ignoring header
+  for line in lines[1:]:
+    # The format of lines is:
+    # Name      ID Mem(MiB) VCPUs State  Time(s)
+    # Domain-0   0  3418     4 r-----    266.2
+    data = line.split()
+    if len(data) != 6:
+      raise errors.HypervisorError("Can't parse output of xm list,"
+                                   " line: %s" % line)
+    try:
+      data[1] = int(data[1])
+      data[2] = int(data[2])
+      data[3] = int(data[3])
+      data[5] = float(data[5])
+    except (TypeError, ValueError), err:
+      raise errors.HypervisorError("Can't parse output of xm list,"
+                                   " line: %s, error: %s" % (line, err))
+
+    # skip the Domain-0 (optional)
+    if include_node or data[0] != _DOM0_NAME:
+      result.append(data)
+
+  return result
+
+
+def _GetInstanceList(fn, include_node, _timeout=5):
+  """Return the list of running instances.
+
+  See L{_RunInstanceList} and L{_ParseXmList} for parameter details.
+
+  """
+  instance_list_errors = []
+  try:
+    lines = utils.Retry(_RunInstanceList, (0.3, 1.5, 1.0), _timeout,
+                        args=(fn, instance_list_errors))
+  except utils.RetryTimeout:
+    if instance_list_errors:
+      instance_list_result = instance_list_errors.pop()
+
+      errmsg = ("listing instances failed, timeout exceeded (%s): %s" %
+                (instance_list_result.fail_reason, instance_list_result.output))
+    else:
+      errmsg = "listing instances failed"
+
+    raise errors.HypervisorError(errmsg)
+
+  return _ParseXmList(lines, include_node)
+
+
+def _ParseNodeInfo(info):
+  """Return information about the node.
+
+  @return: a dict with the following keys (memory values in MiB):
+        - memory_total: the total memory size on the node
+        - memory_free: the available memory on the node for instances
+        - nr_cpus: total number of CPUs
+        - nr_nodes: in a NUMA system, the number of domains
+        - nr_sockets: the number of physical CPU sockets in the node
+        - hv_version: the hypervisor version in the form (major, minor)
+
+  """
+  result = {}
+  cores_per_socket = threads_per_core = nr_cpus = None
+  xen_major, xen_minor = None, None
+  memory_total = None
+  memory_free = None
+
+  for line in info.splitlines():
+    fields = line.split(":", 1)
+
+    if len(fields) < 2:
+      continue
+
+    (key, val) = map(lambda s: s.strip(), fields)
+
+    # Note: in Xen 3, memory has changed to total_memory
+    if key in ("memory", "total_memory"):
+      memory_total = int(val)
+    elif key == "free_memory":
+      memory_free = int(val)
+    elif key == "nr_cpus":
+      nr_cpus = result["cpu_total"] = int(val)
+    elif key == "nr_nodes":
+      result["cpu_nodes"] = int(val)
+    elif key == "cores_per_socket":
+      cores_per_socket = int(val)
+    elif key == "threads_per_core":
+      threads_per_core = int(val)
+    elif key == "xen_major":
+      xen_major = int(val)
+    elif key == "xen_minor":
+      xen_minor = int(val)
+
+  if None not in [cores_per_socket, threads_per_core, nr_cpus]:
+    result["cpu_sockets"] = nr_cpus / (cores_per_socket * threads_per_core)
+
+  if memory_free is not None:
+    result["memory_free"] = memory_free
+
+  if memory_total is not None:
+    result["memory_total"] = memory_total
+
+  if not (xen_major is None or xen_minor is None):
+    result[constants.HV_NODEINFO_KEY_VERSION] = (xen_major, xen_minor)
+
+  return result
+
+
+def _MergeInstanceInfo(info, fn):
+  """Updates node information from L{_ParseNodeInfo} with instance info.
+
+  @type info: dict
+  @param info: Result from L{_ParseNodeInfo}
+  @type fn: callable
+  @param fn: Function returning result of running C{xm list}
+  @rtype: dict
+
+  """
+  total_instmem = 0
+
+  for (name, _, mem, vcpus, _, _) in fn(True):
+    if name == _DOM0_NAME:
+      info["memory_dom0"] = mem
+      info["dom0_cpus"] = vcpus
+
+    # Include Dom0 in total memory usage
+    total_instmem += mem
+
+  memory_free = info.get("memory_free")
+  memory_total = info.get("memory_total")
+
+  # Calculate memory used by hypervisor
+  if None not in [memory_total, memory_free, total_instmem]:
+    info["memory_hv"] = memory_total - memory_free - total_instmem
+
+  return info
+
+
+def _GetNodeInfo(info, fn):
+  """Combines L{_MergeInstanceInfo} and L{_ParseNodeInfo}.
+
+  """
+  return _MergeInstanceInfo(_ParseNodeInfo(info), fn)
+
+
+def _GetConfigFileDiskData(block_devices, blockdev_prefix,
+                           _letters=_DISK_LETTERS):
+  """Get disk directives for Xen config file.
+
+  This method builds the xen config disk directive according to the
+  given disk_template and block_devices.
+
+  @param block_devices: list of tuples (cfdev, rldev):
+      - cfdev: dict containing ganeti config disk part
+      - rldev: ganeti.block.bdev.BlockDev object
+  @param blockdev_prefix: a string containing blockdevice prefix,
+                          e.g. "sd" for /dev/sda
+
+  @return: string containing disk directive for xen instance config file
+
+  """
+  if len(block_devices) > len(_letters):
+    raise errors.HypervisorError("Too many disks")
+
+  disk_data = []
+
+  for sd_suffix, (cfdev, dev_path) in zip(_letters, block_devices):
+    sd_name = blockdev_prefix + sd_suffix
+
+    if cfdev.mode == constants.DISK_RDWR:
+      mode = "w"
+    else:
+      mode = "r"
+
+    if cfdev.dev_type == constants.LD_FILE:
+      driver = _FILE_DRIVER_MAP[cfdev.physical_id[0]]
+    else:
+      driver = "phy"
+
+    disk_data.append("'%s:%s,%s,%s'" % (driver, dev_path, sd_name, mode))
+
+  return disk_data
 
 
 class XenHypervisor(hv_base.BaseHypervisor):
 
 
 class XenHypervisor(hv_base.BaseHypervisor):
@@ -46,13 +313,65 @@ class XenHypervisor(hv_base.BaseHypervisor):
   REBOOT_RETRY_INTERVAL = 10
 
   ANCILLARY_FILES = [
   REBOOT_RETRY_INTERVAL = 10
 
   ANCILLARY_FILES = [
-    "/etc/xen/xend-config.sxp",
-    "/etc/xen/xl.conf",
-    "/etc/xen/scripts/vif-bridge",
+    XEND_CONFIG_FILE,
+    XL_CONFIG_FILE,
+    VIF_BRIDGE_SCRIPT,
     ]
     ]
+  ANCILLARY_FILES_OPT = [
+    XL_CONFIG_FILE,
+    ]
+
+  def __init__(self, _cfgdir=None, _run_cmd_fn=None, _cmd=None):
+    hv_base.BaseHypervisor.__init__(self)
+
+    if _cfgdir is None:
+      self._cfgdir = pathutils.XEN_CONFIG_DIR
+    else:
+      self._cfgdir = _cfgdir
+
+    if _run_cmd_fn is None:
+      self._run_cmd_fn = utils.RunCmd
+    else:
+      self._run_cmd_fn = _run_cmd_fn
+
+    self._cmd = _cmd
+
+  def _GetCommand(self, hvparams=None):
+    """Returns Xen command to use.
+
+    @type hvparams: dict of strings
+    @param hvparams: hypervisor parameters
+
+    """
+    if self._cmd is None:
+      if hvparams is not None:
+        cmd = hvparams[constants.HV_XEN_CMD]
+      else:
+        # TODO: Remove autoconf option once retrieving the command from
+        # the hvparams is fully implemented.
+        cmd = constants.XEN_CMD
+    else:
+      cmd = self._cmd
 
 
-  @staticmethod
-  def _ConfigFileName(instance_name):
+    if cmd not in constants.KNOWN_XEN_COMMANDS:
+      raise errors.ProgrammerError("Unknown Xen command '%s'" % cmd)
+
+    return cmd
+
+  def _RunXen(self, args, hvparams=None):
+    """Wrapper around L{utils.process.RunCmd} to run Xen command.
+
+    @type hvparams: dict of strings
+    @param hvparams: dictionary of hypervisor params
+    @see: L{utils.process.RunCmd}
+
+    """
+    cmd = [self._GetCommand(hvparams=hvparams)]
+    cmd.extend(args)
+
+    return self._run_cmd_fn(cmd)
+
+  def _ConfigFileName(self, instance_name):
     """Get the config file name for an instance.
 
     @param instance_name: instance name
     """Get the config file name for an instance.
 
     @param instance_name: instance name
@@ -61,112 +380,74 @@ class XenHypervisor(hv_base.BaseHypervisor):
     @rtype: str
 
     """
     @rtype: str
 
     """
-    return "/etc/xen/%s" % instance_name
+    return utils.PathJoin(self._cfgdir, instance_name)
 
   @classmethod
 
   @classmethod
-  def _WriteConfigFile(cls, instance, block_devices):
-    """Write the Xen config file for the instance.
+  def _GetConfig(cls, instance, startup_memory, block_devices):
+    """Build Xen configuration for an instance.
 
     """
     raise NotImplementedError
 
 
     """
     raise NotImplementedError
 
-  @staticmethod
-  def _WriteConfigFileStatic(instance_name, data):
+  def _WriteConfigFile(self, instance_name, data):
     """Write the Xen config file for the instance.
 
     This version of the function just writes the config file from static data.
 
     """
     """Write the Xen config file for the instance.
 
     This version of the function just writes the config file from static data.
 
     """
-    utils.WriteFile(XenHypervisor._ConfigFileName(instance_name), data=data)
+    # just in case it exists
+    utils.RemoveFile(utils.PathJoin(self._cfgdir, "auto", instance_name))
+
+    cfg_file = self._ConfigFileName(instance_name)
+    try:
+      utils.WriteFile(cfg_file, data=data)
+    except EnvironmentError, err:
+      raise errors.HypervisorError("Cannot write Xen instance configuration"
+                                   " file %s: %s" % (cfg_file, err))
 
 
-  @staticmethod
-  def _ReadConfigFile(instance_name):
+  def _ReadConfigFile(self, instance_name):
     """Returns the contents of the instance config file.
 
     """
     """Returns the contents of the instance config file.
 
     """
+    filename = self._ConfigFileName(instance_name)
+
     try:
     try:
-      file_content = utils.ReadFile(
-                       XenHypervisor._ConfigFileName(instance_name))
+      file_content = utils.ReadFile(filename)
     except EnvironmentError, err:
       raise errors.HypervisorError("Failed to load Xen config file: %s" % err)
     except EnvironmentError, err:
       raise errors.HypervisorError("Failed to load Xen config file: %s" % err)
+
     return file_content
 
     return file_content
 
-  @staticmethod
-  def _RemoveConfigFile(instance_name):
+  def _RemoveConfigFile(self, instance_name):
     """Remove the xen configuration file.
 
     """
     """Remove the xen configuration file.
 
     """
-    utils.RemoveFile(XenHypervisor._ConfigFileName(instance_name))
+    utils.RemoveFile(self._ConfigFileName(instance_name))
 
 
-  @staticmethod
-  def _RunXmList(xmlist_errors):
-    """Helper function for L{_GetXMList} to run "xm list".
+  def _StashConfigFile(self, instance_name):
+    """Move the Xen config file to the log directory and return its new path.
 
     """
 
     """
-    result = utils.RunCmd([constants.XEN_CMD, "list"])
-    if result.failed:
-      logging.error("xm list failed (%s): %s", result.fail_reason,
-                    result.output)
-      xmlist_errors.append(result)
-      raise utils.RetryAgain()
-
-    # skip over the heading
-    return result.stdout.splitlines()[1:]
-
-  @classmethod
-  def _GetXMList(cls, include_node):
-    """Return the list of running instances.
-
-    If the include_node argument is True, then we return information
-    for dom0 also, otherwise we filter that from the return value.
+    old_filename = self._ConfigFileName(instance_name)
+    base = ("%s-%s" %
+            (instance_name, utils.TimestampForFilename()))
+    new_filename = utils.PathJoin(pathutils.LOG_XEN_DIR, base)
+    utils.RenameFile(old_filename, new_filename)
+    return new_filename
 
 
-    @return: list of (name, id, memory, vcpus, state, time spent)
+  def _GetInstanceList(self, include_node, hvparams=None):
+    """Wrapper around module level L{_GetInstanceList}.
 
     """
 
     """
-    xmlist_errors = []
-    try:
-      lines = utils.Retry(cls._RunXmList, 1, 5, args=(xmlist_errors, ))
-    except utils.RetryTimeout:
-      if xmlist_errors:
-        xmlist_result = xmlist_errors.pop()
+    return _GetInstanceList(lambda: self._RunXen(["list"], hvparams=hvparams),
+                            include_node)
 
 
-        errmsg = ("xm list failed, timeout exceeded (%s): %s" %
-                  (xmlist_result.fail_reason, xmlist_result.output))
-      else:
-        errmsg = "xm list failed"
-
-      raise errors.HypervisorError(errmsg)
-
-    result = []
-    for line in lines:
-      # The format of lines is:
-      # Name      ID Mem(MiB) VCPUs State  Time(s)
-      # Domain-0   0  3418     4 r-----    266.2
-      data = line.split()
-      if len(data) != 6:
-        raise errors.HypervisorError("Can't parse output of xm list,"
-                                     " line: %s" % line)
-      try:
-        data[1] = int(data[1])
-        data[2] = int(data[2])
-        data[3] = int(data[3])
-        data[5] = float(data[5])
-      except (TypeError, ValueError), err:
-        raise errors.HypervisorError("Can't parse output of xm list,"
-                                     " line: %s, error: %s" % (line, err))
-
-      # skip the Domain-0 (optional)
-      if include_node or data[0] != "Domain-0":
-        result.append(data)
-
-    return result
-
-  def ListInstances(self):
+  def ListInstances(self, hvparams=None):
     """Get the list of running instances.
 
     """
     """Get the list of running instances.
 
     """
-    xm_list = self._GetXMList(False)
-    names = [info[0] for info in xm_list]
+    instance_list = self._GetInstanceList(False, hvparams=hvparams)
+    names = [info[0] for info in instance_list]
     return names
 
   def GetInstanceInfo(self, instance_name):
     return names
 
   def GetInstanceInfo(self, instance_name):
@@ -177,9 +458,9 @@ class XenHypervisor(hv_base.BaseHypervisor):
     @return: tuple (name, id, memory, vcpus, stat, times)
 
     """
     @return: tuple (name, id, memory, vcpus, stat, times)
 
     """
-    xm_list = self._GetXMList(instance_name == "Domain-0")
+    instance_list = self._GetInstanceList(instance_name == _DOM0_NAME)
     result = None
     result = None
-    for data in xm_list:
+    for data in instance_list:
       if data[0] == instance_name:
         result = data
         break
       if data[0] == instance_name:
         result = data
         break
@@ -191,24 +472,44 @@ class XenHypervisor(hv_base.BaseHypervisor):
     @return: list of tuples (name, id, memory, vcpus, stat, times)
 
     """
     @return: list of tuples (name, id, memory, vcpus, stat, times)
 
     """
-    xm_list = self._GetXMList(False)
-    return xm_list
+    return self._GetInstanceList(False)
+
+  def _MakeConfigFile(self, instance, startup_memory, block_devices):
+    """Gather configuration details and write to disk.
+
+    See L{_GetConfig} for arguments.
+
+    """
+    buf = StringIO()
+    buf.write("# Automatically generated by Ganeti. Do not edit!\n")
+    buf.write("\n")
+    buf.write(self._GetConfig(instance, startup_memory, block_devices))
+    buf.write("\n")
+
+    self._WriteConfigFile(instance.name, buf.getvalue())
 
   def StartInstance(self, instance, block_devices, startup_paused):
     """Start an instance.
 
     """
 
   def StartInstance(self, instance, block_devices, startup_paused):
     """Start an instance.
 
     """
-    self._WriteConfigFile(instance, block_devices)
-    cmd = [constants.XEN_CMD, "create"]
+    startup_memory = self._InstanceStartupMemory(instance)
+
+    self._MakeConfigFile(instance, startup_memory, block_devices)
+
+    cmd = ["create"]
     if startup_paused:
     if startup_paused:
-      cmd.extend(["-p"])
-    cmd.extend([self._ConfigFileName(instance.name)])
-    result = utils.RunCmd(cmd)
+      cmd.append("-p")
+    cmd.append(self._ConfigFileName(instance.name))
 
 
+    result = self._RunXen(cmd, hvparams=instance.hvparams)
     if result.failed:
     if result.failed:
-      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
+      # Move the Xen configuration file to the log directory to avoid
+      # leaving a stale config file behind.
+      stashed_config = self._StashConfigFile(instance.name)
+      raise errors.HypervisorError("Failed to start instance %s: %s (%s). Moved"
+                                   " config file to %s" %
                                    (instance.name, result.fail_reason,
                                    (instance.name, result.fail_reason,
-                                    result.output))
+                                    result.output, stashed_config))
 
   def StopInstance(self, instance, force=False, retry=False, name=None):
     """Stop an instance.
 
   def StopInstance(self, instance, force=False, retry=False, name=None):
     """Stop an instance.
@@ -216,17 +517,33 @@ class XenHypervisor(hv_base.BaseHypervisor):
     """
     if name is None:
       name = instance.name
     """
     if name is None:
       name = instance.name
-    self._RemoveConfigFile(name)
+
+    return self._StopInstance(name, force, instance.hvparams)
+
+  def _StopInstance(self, name, force, hvparams):
+    """Stop an instance.
+
+    @type name: string
+    @param name: name of the instance to be shutdown
+    @type force: boolean
+    @param force: flag specifying whether shutdown should be forced
+    @type hvparams: dict of string
+    @param hvparams: hypervisor parameters of the instance
+
+    """
     if force:
     if force:
-      command = [constants.XEN_CMD, "destroy", name]
+      action = "destroy"
     else:
     else:
-      command = [constants.XEN_CMD, "shutdown", name]
-    result = utils.RunCmd(command)
+      action = "shutdown"
 
 
+    result = self._RunXen([action, name], hvparams=hvparams)
     if result.failed:
       raise errors.HypervisorError("Failed to stop instance %s: %s, %s" %
                                    (name, result.fail_reason, result.output))
 
     if result.failed:
       raise errors.HypervisorError("Failed to stop instance %s: %s, %s" %
                                    (name, result.fail_reason, result.output))
 
+    # Remove configuration file if stopping/starting instance was successful
+    self._RemoveConfigFile(name)
+
   def RebootInstance(self, instance):
     """Reboot an instance.
 
   def RebootInstance(self, instance):
     """Reboot an instance.
 
@@ -237,7 +554,7 @@ class XenHypervisor(hv_base.BaseHypervisor):
       raise errors.HypervisorError("Failed to reboot instance %s,"
                                    " not running" % instance.name)
 
       raise errors.HypervisorError("Failed to reboot instance %s,"
                                    " not running" % instance.name)
 
-    result = utils.RunCmd([constants.XEN_CMD, "reboot", instance.name])
+    result = self._RunXen(["reboot", instance.name], hvparams=instance.hvparams)
     if result.failed:
       raise errors.HypervisorError("Failed to reboot instance %s: %s, %s" %
                                    (instance.name, result.fail_reason,
     if result.failed:
       raise errors.HypervisorError("Failed to reboot instance %s: %s, %s" %
                                    (instance.name, result.fail_reason,
@@ -261,65 +578,45 @@ class XenHypervisor(hv_base.BaseHypervisor):
                                    " did not reboot in the expected interval" %
                                    (instance.name, ))
 
                                    " did not reboot in the expected interval" %
                                    (instance.name, ))
 
+  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
+
+    """
+    result = self._RunXen(["mem-set", instance.name, mem],
+                          hvparams=instance.hvparams)
+    if result.failed:
+      raise errors.HypervisorError("Failed to balloon instance %s: %s (%s)" %
+                                   (instance.name, result.fail_reason,
+                                    result.output))
+
+    # Update configuration file
+    cmd = ["sed", "-ie", "s/^memory.*$/memory = %s/" % mem]
+    cmd.append(self._ConfigFileName(instance.name))
+
+    result = utils.RunCmd(cmd)
+    if result.failed:
+      raise errors.HypervisorError("Failed to update memory for %s: %s (%s)" %
+                                   (instance.name, result.fail_reason,
+                                    result.output))
+
   def GetNodeInfo(self):
     """Return information about the node.
 
   def GetNodeInfo(self):
     """Return information about the node.
 
-    @return: a dict with the following keys (memory 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
-          - nr_cpus: total number of CPUs
-          - nr_nodes: in a NUMA system, the number of domains
-          - nr_sockets: the number of physical CPU sockets in the node
-          - hv_version: the hypervisor version in the form (major, minor)
+    @see: L{_GetNodeInfo} and L{_ParseNodeInfo}
 
     """
 
     """
-    # note: in xen 3, memory has changed to total_memory
-    result = utils.RunCmd([constants.XEN_CMD, "info"])
+    result = self._RunXen(["info"])
     if result.failed:
       logging.error("Can't run 'xm info' (%s): %s", result.fail_reason,
                     result.output)
       return None
 
     if result.failed:
       logging.error("Can't run 'xm info' (%s): %s", result.fail_reason,
                     result.output)
       return None
 
-    xmoutput = result.stdout.splitlines()
-    result = {}
-    cores_per_socket = threads_per_core = nr_cpus = None
-    xen_major, xen_minor = None, None
-    for line in xmoutput:
-      splitfields = line.split(":", 1)
-
-      if len(splitfields) > 1:
-        key = splitfields[0].strip()
-        val = splitfields[1].strip()
-        if key == "memory" or key == "total_memory":
-          result["memory_total"] = int(val)
-        elif key == "free_memory":
-          result["memory_free"] = int(val)
-        elif key == "nr_cpus":
-          nr_cpus = result["cpu_total"] = int(val)
-        elif key == "nr_nodes":
-          result["cpu_nodes"] = int(val)
-        elif key == "cores_per_socket":
-          cores_per_socket = int(val)
-        elif key == "threads_per_core":
-          threads_per_core = int(val)
-        elif key == "xen_major":
-          xen_major = int(val)
-        elif key == "xen_minor":
-          xen_minor = int(val)
-
-    if (cores_per_socket is not None and
-        threads_per_core is not None and nr_cpus is not None):
-      result["cpu_sockets"] = nr_cpus / (cores_per_socket * threads_per_core)
-
-    dom0_info = self.GetInstanceInfo("Domain-0")
-    if dom0_info is not None:
-      result["memory_dom0"] = dom0_info[2]
-
-    if not (xen_major is None or xen_minor is None):
-      result[constants.HV_NODEINFO_KEY_VERSION] = (xen_major, xen_minor)
-
-    return result
+    return _GetNodeInfo(result.stdout, self._GetInstanceList)
 
   @classmethod
   def GetInstanceConsole(cls, instance, hvparams, beparams):
 
   @classmethod
   def GetInstanceConsole(cls, instance, hvparams, beparams):
@@ -329,58 +626,39 @@ class XenHypervisor(hv_base.BaseHypervisor):
     return objects.InstanceConsole(instance=instance.name,
                                    kind=constants.CONS_SSH,
                                    host=instance.primary_node,
     return objects.InstanceConsole(instance=instance.name,
                                    kind=constants.CONS_SSH,
                                    host=instance.primary_node,
-                                   user=constants.GANETI_RUNAS,
-                                   command=[constants.XM_CONSOLE_WRAPPER,
-                                            instance.name])
+                                   user=constants.SSH_CONSOLE_USER,
+                                   command=[pathutils.XEN_CONSOLE_WRAPPER,
+                                            constants.XEN_CMD, instance.name])
 
 
-  def Verify(self):
+  def Verify(self, hvparams=None):
     """Verify the hypervisor.
 
     For Xen, this verifies that the xend process is running.
 
     """Verify the hypervisor.
 
     For Xen, this verifies that the xend process is running.
 
+    @type hvparams: dict of strings
+    @param hvparams: hypervisor parameters to be verified against
+
+    @return: Problem description if something is wrong, C{None} otherwise
+
     """
     """
-    result = utils.RunCmd([constants.XEN_CMD, "info"])
+    if hvparams is None:
+      return "Could not verify the hypervisor, because no hvparams were" \
+             " provided."
+
+    if constants.HV_XEN_CMD in hvparams:
+      xen_cmd = hvparams[constants.HV_XEN_CMD]
+      try:
+        self._CheckToolstack(xen_cmd)
+      except errors.HypervisorError:
+        return "The configured xen toolstack '%s' is not available on this" \
+               " node." % xen_cmd
+
+    result = self._RunXen(["info"], hvparams=hvparams)
     if result.failed:
     if result.failed:
-      return "'xm info' failed: %s, %s" % (result.fail_reason, result.output)
-
-  @staticmethod
-  def _GetConfigFileDiskData(block_devices, blockdev_prefix):
-    """Get disk directive for xen config file.
-
-    This method builds the xen config disk directive according to the
-    given disk_template and block_devices.
-
-    @param block_devices: list of tuples (cfdev, rldev):
-        - cfdev: dict containing ganeti config disk part
-        - rldev: ganeti.bdev.BlockDev object
-    @param blockdev_prefix: a string containing blockdevice prefix,
-                            e.g. "sd" for /dev/sda
-
-    @return: string containing disk directive for xen instance config file
-
-    """
-    FILE_DRIVER_MAP = {
-      constants.FD_LOOP: "file",
-      constants.FD_BLKTAP: "tap:aio",
-      }
-    disk_data = []
-    if len(block_devices) > 24:
-      # 'z' - 'a' = 24
-      raise errors.HypervisorError("Too many disks")
-    namespace = [blockdev_prefix + chr(i + ord("a")) for i in range(24)]
-    for sd_name, (cfdev, dev_path) in zip(namespace, block_devices):
-      if cfdev.mode == constants.DISK_RDWR:
-        mode = "w"
-      else:
-        mode = "r"
-      if cfdev.dev_type == constants.LD_FILE:
-        line = "'%s:%s,%s,%s'" % (FILE_DRIVER_MAP[cfdev.physical_id[0]],
-                                  dev_path, sd_name, mode)
-      else:
-        line = "'phy:%s,%s,%s'" % (dev_path, sd_name, mode)
-      disk_data.append(line)
+      return "Retrieving information from xen failed: %s, %s" % \
+        (result.fail_reason, result.output)
 
 
-    return disk_data
+    return None
 
   def MigrationInfo(self, instance):
     """Get instance information to perform a migration.
 
   def MigrationInfo(self, instance):
     """Get instance information to perform a migration.
@@ -406,7 +684,7 @@ class XenHypervisor(hv_base.BaseHypervisor):
     """
     pass
 
     """
     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.
     """Finalize an instance migration.
 
     After a successful migration we write the xen config file.
@@ -421,7 +699,7 @@ class XenHypervisor(hv_base.BaseHypervisor):
 
     """
     if success:
 
     """
     if success:
-      self._WriteConfigFileStatic(instance.name, info)
+      self._WriteConfigFile(instance.name, info)
 
   def MigrateInstance(self, instance, target, live):
     """Migrate an instance to a target node.
 
   def MigrateInstance(self, instance, target, live):
     """Migrate an instance to a target node.
@@ -437,33 +715,92 @@ class XenHypervisor(hv_base.BaseHypervisor):
     @param live: perform a live migration
 
     """
     @param live: perform a live migration
 
     """
-    if self.GetInstanceInfo(instance.name) is None:
+    port = instance.hvparams[constants.HV_MIGRATION_PORT]
+
+    # TODO: Pass cluster name via RPC
+    cluster_name = ssconf.SimpleStore().GetClusterName()
+
+    return self._MigrateInstance(cluster_name, instance.name, target, port,
+                                 live, instance.hvparams)
+
+  def _MigrateInstance(self, cluster_name, instance_name, target, port, live,
+                       hvparams, _ping_fn=netutils.TcpPing):
+    """Migrate an instance to a target node.
+
+    @see: L{MigrateInstance} for details
+
+    """
+    if hvparams is None:
+      raise errors.HypervisorError("No hvparams provided.")
+
+    if self.GetInstanceInfo(instance_name, hvparams=hvparams) is None:
       raise errors.HypervisorError("Instance not running, cannot migrate")
 
       raise errors.HypervisorError("Instance not running, cannot migrate")
 
-    port = instance.hvparams[constants.HV_MIGRATION_PORT]
+    cmd = self._GetCommand(hvparams=hvparams)
 
 
-    if not netutils.TcpPing(target, port, live_port_needed=True):
+    if (cmd == constants.XEN_CMD_XM and
+        not _ping_fn(target, port, live_port_needed=True)):
       raise errors.HypervisorError("Remote host %s not listening on port"
                                    " %s, cannot migrate" % (target, port))
 
       raise errors.HypervisorError("Remote host %s not listening on port"
                                    " %s, cannot migrate" % (target, port))
 
-    # FIXME: migrate must be upgraded for transitioning to "xl" (xen 4.1).
-    #  -l doesn't exist anymore
-    #  -p doesn't exist anymore
-    #  -C config_file must be passed
-    #  ssh must recognize the key of the target host for the migration
-    args = [constants.XEN_CMD, "migrate", "-p", "%d" % port]
-    if live:
-      args.append("-l")
-    args.extend([instance.name, target])
-    result = utils.RunCmd(args)
+    args = ["migrate"]
+
+    if cmd == constants.XEN_CMD_XM:
+      args.extend(["-p", "%d" % port])
+      if live:
+        args.append("-l")
+
+    elif cmd == constants.XEN_CMD_XL:
+      args.extend([
+        "-s", constants.XL_SSH_CMD % cluster_name,
+        "-C", self._ConfigFileName(instance_name),
+        ])
+
+    else:
+      raise errors.HypervisorError("Unsupported Xen command: %s" % self._cmd)
+
+    args.extend([instance_name, target])
+
+    result = self._RunXen(args, hvparams=hvparams)
     if result.failed:
       raise errors.HypervisorError("Failed to migrate instance %s: %s" %
     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")
+                                   (instance_name, result.output))
+
+  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):
 
   @classmethod
   def PowercycleNode(cls):
@@ -482,6 +819,48 @@ class XenHypervisor(hv_base.BaseHypervisor):
     finally:
       utils.RunCmd([constants.XEN_CMD, "debug", "R"])
 
     finally:
       utils.RunCmd([constants.XEN_CMD, "debug", "R"])
 
+  def _CheckToolstack(self, xen_cmd):
+    """Check whether the given toolstack is available on the node.
+
+    @type xen_cmd: string
+    @param xen_cmd: xen command (e.g. 'xm' or 'xl')
+
+    """
+    binary_found = self._CheckToolstackBinary(xen_cmd)
+    if not binary_found:
+      raise errors.HypervisorError("No '%s' binary found on node." % xen_cmd)
+    elif xen_cmd == constants.XEN_CMD_XL:
+      if not self._CheckToolstackXlConfigured():
+        raise errors.HypervisorError("Toolstack '%s' is not enabled on this"
+                                     "node." % xen_cmd)
+
+  def _CheckToolstackBinary(self, xen_cmd):
+    """Checks whether the xen command's binary is found on the machine.
+
+    """
+    if xen_cmd not in constants.KNOWN_XEN_COMMANDS:
+      raise errors.HypervisorError("Unknown xen command '%s'." % xen_cmd)
+    result = self._run_cmd_fn(["which", xen_cmd])
+    return not result.failed
+
+  def _CheckToolstackXlConfigured(self):
+    """Checks whether xl is enabled on an xl-capable node.
+
+    @rtype: bool
+    @returns: C{True} if 'xl' is enabled, C{False} otherwise
+
+    """
+    result = self._run_cmd_fn([constants.XEN_CMD_XL, "help"])
+    if not result.failed:
+      return True
+    elif result.failed:
+      if "toolstack" in result.stderr:
+        return False
+      # xl fails for some other reason than the toolstack
+      else:
+        raise errors.HypervisorError("Cannot run xen ('%s'). Error: %s."
+                                     % (constants.XEN_CMD_XL, result.stderr))
+
 
 class XenPvmHypervisor(XenHypervisor):
   """Xen PVM hypervisor interface"""
 
 class XenPvmHypervisor(XenHypervisor):
   """Xen PVM hypervisor interface"""
@@ -499,11 +878,16 @@ 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:
     # 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,
+    constants.HV_CPU_CAP: hv_base.OPT_NONNEGATIVE_INT_CHECK,
+    constants.HV_CPU_WEIGHT:
+      (False, lambda x: 0 < x < 65536, "invalid weight", None, None),
+    constants.HV_XEN_CMD:
+      hv_base.ParamInSet(True, constants.KNOWN_XEN_COMMANDS),
     }
 
     }
 
-  @classmethod
-  def _WriteConfigFile(cls, instance, block_devices):
+  def _GetConfig(self, instance, startup_memory, block_devices):
     """Write the Xen config file for the instance.
 
     """
     """Write the Xen config file for the instance.
 
     """
@@ -536,8 +920,19 @@ class XenPvmHypervisor(XenHypervisor):
         config.write("ramdisk = '%s'\n" % initrd_path)
 
     # rest of the settings
         config.write("ramdisk = '%s'\n" % initrd_path)
 
     # rest of the settings
-    config.write("memory = %d\n" % instance.beparams[constants.BE_MEMORY])
+    config.write("memory = %d\n" % startup_memory)
+    config.write("maxmem = %d\n" % instance.beparams[constants.BE_MAXMEM])
     config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
     config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
+    cpu_pinning = _CreateConfigCpus(hvp[constants.HV_CPU_MASK])
+    if cpu_pinning:
+      config.write("%s\n" % cpu_pinning)
+    cpu_cap = hvp[constants.HV_CPU_CAP]
+    if cpu_cap:
+      config.write("cpu_cap=%d\n" % cpu_cap)
+    cpu_weight = hvp[constants.HV_CPU_WEIGHT]
+    if cpu_weight:
+      config.write("cpu_weight=%d\n" % cpu_weight)
+
     config.write("name = '%s'\n" % instance.name)
 
     vif_data = []
     config.write("name = '%s'\n" % instance.name)
 
     vif_data = []
@@ -550,8 +945,8 @@ class XenPvmHypervisor(XenHypervisor):
         nic_str += ", bridge=%s" % nic.nicparams[constants.NIC_LINK]
       vif_data.append("'%s'" % nic_str)
 
         nic_str += ", bridge=%s" % nic.nicparams[constants.NIC_LINK]
       vif_data.append("'%s'" % nic_str)
 
-    disk_data = cls._GetConfigFileDiskData(block_devices,
-                                           hvp[constants.HV_BLOCKDEV_PREFIX])
+    disk_data = \
+      _GetConfigFileDiskData(block_devices, hvp[constants.HV_BLOCKDEV_PREFIX])
 
     config.write("vif = [%s]\n" % ",".join(vif_data))
     config.write("disk = [%s]\n" % ",".join(disk_data))
 
     config.write("vif = [%s]\n" % ",".join(vif_data))
     config.write("disk = [%s]\n" % ",".join(disk_data))
@@ -565,24 +960,18 @@ class XenPvmHypervisor(XenHypervisor):
       config.write("on_reboot = 'destroy'\n")
     config.write("on_crash = 'restart'\n")
     config.write("extra = '%s'\n" % hvp[constants.HV_KERNEL_ARGS])
       config.write("on_reboot = 'destroy'\n")
     config.write("on_crash = 'restart'\n")
     config.write("extra = '%s'\n" % hvp[constants.HV_KERNEL_ARGS])
-    # just in case it exists
-    utils.RemoveFile("/etc/xen/auto/%s" % instance.name)
-    try:
-      utils.WriteFile(cls._ConfigFileName(instance.name),
-                      data=config.getvalue())
-    except EnvironmentError, err:
-      raise errors.HypervisorError("Cannot write Xen instance confile"
-                                   " file %s: %s" %
-                                   (cls._ConfigFileName(instance.name), err))
 
 
-    return True
+    return config.getvalue()
 
 
 class XenHvmHypervisor(XenHypervisor):
   """Xen HVM hypervisor interface"""
 
   ANCILLARY_FILES = XenHypervisor.ANCILLARY_FILES + [
 
 
 class XenHvmHypervisor(XenHypervisor):
   """Xen HVM hypervisor interface"""
 
   ANCILLARY_FILES = XenHypervisor.ANCILLARY_FILES + [
-    constants.VNC_PASSWORD_FILE,
+    pathutils.VNC_PASSWORD_FILE,
+    ]
+  ANCILLARY_FILES_OPT = XenHypervisor.ANCILLARY_FILES_OPT + [
+    pathutils.VNC_PASSWORD_FILE,
     ]
 
   PARAMETERS = {
     ]
 
   PARAMETERS = {
@@ -608,27 +997,46 @@ class XenHvmHypervisor(XenHypervisor):
     constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
     # TODO: Add a check for the blockdev prefix (matching [a-z:] or similar).
     constants.HV_BLOCKDEV_PREFIX: hv_base.NO_CHECK,
     constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
     # TODO: Add a check for the blockdev prefix (matching [a-z:] or similar).
     constants.HV_BLOCKDEV_PREFIX: hv_base.NO_CHECK,
+    # Add PCI passthrough
+    constants.HV_PASSTHROUGH: hv_base.NO_CHECK,
     constants.HV_REBOOT_BEHAVIOR:
     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,
+    constants.HV_CPU_CAP: hv_base.NO_CHECK,
+    constants.HV_CPU_WEIGHT:
+      (False, lambda x: 0 < x < 65535, "invalid weight", None, None),
+    constants.HV_VIF_TYPE:
+      hv_base.ParamInSet(False, constants.HT_HVM_VALID_VIF_TYPES),
+    constants.HV_XEN_CMD:
+      hv_base.ParamInSet(True, constants.KNOWN_XEN_COMMANDS),
     }
 
     }
 
-  @classmethod
-  def _WriteConfigFile(cls, instance, block_devices):
+  def _GetConfig(self, instance, startup_memory, block_devices):
     """Create a Xen 3.1 HVM config file.
 
     """
     hvp = instance.hvparams
 
     config = StringIO()
     """Create a Xen 3.1 HVM config file.
 
     """
     hvp = instance.hvparams
 
     config = StringIO()
-    config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
 
     # kernel handling
     kpath = hvp[constants.HV_KERNEL_PATH]
     config.write("kernel = '%s'\n" % kpath)
 
     config.write("builder = 'hvm'\n")
 
     # kernel handling
     kpath = hvp[constants.HV_KERNEL_PATH]
     config.write("kernel = '%s'\n" % kpath)
 
     config.write("builder = 'hvm'\n")
-    config.write("memory = %d\n" % instance.beparams[constants.BE_MEMORY])
+    config.write("memory = %d\n" % startup_memory)
+    config.write("maxmem = %d\n" % instance.beparams[constants.BE_MAXMEM])
     config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
     config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
+    cpu_pinning = _CreateConfigCpus(hvp[constants.HV_CPU_MASK])
+    if cpu_pinning:
+      config.write("%s\n" % cpu_pinning)
+    cpu_cap = hvp[constants.HV_CPU_CAP]
+    if cpu_cap:
+      config.write("cpu_cap=%d\n" % cpu_cap)
+    cpu_weight = hvp[constants.HV_CPU_WEIGHT]
+    if cpu_weight:
+      config.write("cpu_weight=%d\n" % cpu_weight)
+
     config.write("name = '%s'\n" % instance.name)
     if hvp[constants.HV_PAE]:
       config.write("pae = 1\n")
     config.write("name = '%s'\n" % instance.name)
     if hvp[constants.HV_PAE]:
       config.write("pae = 1\n")
@@ -672,14 +1080,23 @@ class XenHvmHypervisor(XenHypervisor):
       config.write("localtime = 1\n")
 
     vif_data = []
       config.write("localtime = 1\n")
 
     vif_data = []
+    # Note: what is called 'nic_type' here, is used as value for the xen nic
+    # vif config parameter 'model'. For the xen nic vif parameter 'type', we use
+    # the 'vif_type' to avoid a clash of notation.
     nic_type = hvp[constants.HV_NIC_TYPE]
     nic_type = hvp[constants.HV_NIC_TYPE]
+
     if nic_type is None:
     if nic_type is None:
+      vif_type_str = ""
+      if hvp[constants.HV_VIF_TYPE]:
+        vif_type_str = ", type=%s" % hvp[constants.HV_VIF_TYPE]
       # ensure old instances don't change
       # ensure old instances don't change
-      nic_type_str = ", type=ioemu"
+      nic_type_str = vif_type_str
     elif nic_type == constants.HT_NIC_PARAVIRTUAL:
       nic_type_str = ", type=paravirtualized"
     else:
     elif nic_type == constants.HT_NIC_PARAVIRTUAL:
       nic_type_str = ", type=paravirtualized"
     else:
-      nic_type_str = ", model=%s, type=ioemu" % nic_type
+      # parameter 'model' is only valid with type 'ioemu'
+      nic_type_str = ", model=%s, type=%s" % \
+        (nic_type, constants.HT_HVM_VIF_IOEMU)
     for nic in instance.nics:
       nic_str = "mac=%s%s" % (nic.mac, nic_type_str)
       ip = getattr(nic, "ip", None)
     for nic in instance.nics:
       nic_str = "mac=%s%s" % (nic.mac, nic_type_str)
       ip = getattr(nic, "ip", None)
@@ -691,8 +1108,8 @@ class XenHvmHypervisor(XenHypervisor):
 
     config.write("vif = [%s]\n" % ",".join(vif_data))
 
 
     config.write("vif = [%s]\n" % ",".join(vif_data))
 
-    disk_data = cls._GetConfigFileDiskData(block_devices,
-                                           hvp[constants.HV_BLOCKDEV_PREFIX])
+    disk_data = \
+      _GetConfigFileDiskData(block_devices, hvp[constants.HV_BLOCKDEV_PREFIX])
 
     iso_path = hvp[constants.HV_CDROM_IMAGE_PATH]
     if iso_path:
 
     iso_path = hvp[constants.HV_CDROM_IMAGE_PATH]
     if iso_path:
@@ -700,21 +1117,17 @@ class XenHvmHypervisor(XenHypervisor):
       disk_data.append(iso)
 
     config.write("disk = [%s]\n" % (",".join(disk_data)))
       disk_data.append(iso)
 
     config.write("disk = [%s]\n" % (",".join(disk_data)))
-
+    # Add PCI passthrough
+    pci_pass_arr = []
+    pci_pass = hvp[constants.HV_PASSTHROUGH]
+    if pci_pass:
+      pci_pass_arr = pci_pass.split(";")
+      config.write("pci = %s\n" % pci_pass_arr)
     config.write("on_poweroff = 'destroy'\n")
     if hvp[constants.HV_REBOOT_BEHAVIOR] == constants.INSTANCE_REBOOT_ALLOWED:
       config.write("on_reboot = 'restart'\n")
     else:
       config.write("on_reboot = 'destroy'\n")
     config.write("on_crash = 'restart'\n")
     config.write("on_poweroff = 'destroy'\n")
     if hvp[constants.HV_REBOOT_BEHAVIOR] == constants.INSTANCE_REBOOT_ALLOWED:
       config.write("on_reboot = 'restart'\n")
     else:
       config.write("on_reboot = 'destroy'\n")
     config.write("on_crash = 'restart'\n")
-    # just in case it exists
-    utils.RemoveFile("/etc/xen/auto/%s" % instance.name)
-    try:
-      utils.WriteFile(cls._ConfigFileName(instance.name),
-                      data=config.getvalue())
-    except EnvironmentError, err:
-      raise errors.HypervisorError("Cannot write Xen instance confile"
-                                   " file %s: %s" %
-                                   (cls._ConfigFileName(instance.name), err))
 
 
-    return True
+    return config.getvalue()