diff --git a/doc/rapi.rst b/doc/rapi.rst
index 23805d6f734f5ef00638e76b37fbf352ba31d661..3b785aeb8ac3769ba4448cd8288d116aba1e8211 100644
--- a/doc/rapi.rst
+++ b/doc/rapi.rst
@@ -1337,6 +1337,28 @@ be a job id.
 
 It supports the bool ``force`` argument.
 
+
+``/2/nodes/[node_name]/modify``
++++++++++++++++++++++++++++++++
+
+Modifies the parameters of a node. Supports the following commands:
+``POST``.
+
+``POST``
+~~~~~~~~
+
+Returns a job ID.
+
+Body parameters:
+
+.. opcode_params:: OP_NODE_SET_PARAMS
+   :exclude: node_name
+
+Job result:
+
+.. opcode_result:: OP_NODE_SET_PARAMS
+
+
 ``/2/nodes/[node_name]/storage``
 ++++++++++++++++++++++++++++++++
 
diff --git a/lib/constants.py b/lib/constants.py
index 79d0b2fed0d3921cc3ba71d3c2a781702d804aa8..003774c588b98e76ac4f3d05fb011a24dd9cdf40 100644
--- a/lib/constants.py
+++ b/lib/constants.py
@@ -270,6 +270,7 @@ EXPORT_CONF_FILE = "config.ini"
 XEN_BOOTLOADER = _autoconf.XEN_BOOTLOADER
 XEN_KERNEL = _autoconf.XEN_KERNEL
 XEN_INITRD = _autoconf.XEN_INITRD
+XEN_CMD = "xm"
 
 KVM_PATH = _autoconf.KVM_PATH
 SOCAT_PATH = _autoconf.SOCAT_PATH
diff --git a/lib/hypervisor/hv_xen.py b/lib/hypervisor/hv_xen.py
index f8113a8109e099851739a3ee5b37d8b5432a0af6..7e2418f203dfa09e5cb7a0e5703a3c79954b5d66 100644
--- a/lib/hypervisor/hv_xen.py
+++ b/lib/hypervisor/hv_xen.py
@@ -47,9 +47,22 @@ class XenHypervisor(hv_base.BaseHypervisor):
 
   ANCILLARY_FILES = [
     "/etc/xen/xend-config.sxp",
+    "/etc/xen/xl.conf",
     "/etc/xen/scripts/vif-bridge",
     ]
 
+  @staticmethod
+  def _ConfigFileName(instance_name):
+    """Get the config file name for an instance.
+
+    @param instance_name: instance name
+    @type instance_name: str
+    @return: fully qualified path to instance config file
+    @rtype: str
+
+    """
+    return "/etc/xen/%s" % instance_name
+
   @classmethod
   def _WriteConfigFile(cls, instance, block_devices):
     """Write the Xen config file for the instance.
@@ -64,7 +77,7 @@ class XenHypervisor(hv_base.BaseHypervisor):
     This version of the function just writes the config file from static data.
 
     """
-    utils.WriteFile("/etc/xen/%s" % instance_name, data=data)
+    utils.WriteFile(XenHypervisor._ConfigFileName(instance_name), data=data)
 
   @staticmethod
   def _ReadConfigFile(instance_name):
@@ -72,7 +85,8 @@ class XenHypervisor(hv_base.BaseHypervisor):
 
     """
     try:
-      file_content = utils.ReadFile("/etc/xen/%s" % instance_name)
+      file_content = utils.ReadFile(
+                       XenHypervisor._ConfigFileName(instance_name))
     except EnvironmentError, err:
       raise errors.HypervisorError("Failed to load Xen config file: %s" % err)
     return file_content
@@ -82,7 +96,7 @@ class XenHypervisor(hv_base.BaseHypervisor):
     """Remove the xen configuration file.
 
     """
-    utils.RemoveFile("/etc/xen/%s" % instance_name)
+    utils.RemoveFile(XenHypervisor._ConfigFileName(instance_name))
 
   @classmethod
   def _CreateConfigCpus(cls, cpu_mask):
@@ -121,7 +135,7 @@ class XenHypervisor(hv_base.BaseHypervisor):
     """Helper function for L{_GetXMList} to run "xm list".
 
     """
-    result = utils.RunCmd(["xm", "list"])
+    result = utils.RunCmd([constants.XEN_CMD, "list"])
     if result.failed:
       logging.error("xm list failed (%s): %s", result.fail_reason,
                     result.output)
@@ -217,10 +231,10 @@ class XenHypervisor(hv_base.BaseHypervisor):
 
     """
     self._WriteConfigFile(instance, block_devices)
-    cmd = ["xm", "create"]
+    cmd = [constants.XEN_CMD, "create"]
     if startup_paused:
-      cmd.extend(["--paused"])
-    cmd.extend([instance.name])
+      cmd.extend(["-p"])
+    cmd.extend([self._ConfigFileName(instance.name)])
     result = utils.RunCmd(cmd)
 
     if result.failed:
@@ -236,9 +250,9 @@ class XenHypervisor(hv_base.BaseHypervisor):
       name = instance.name
     self._RemoveConfigFile(name)
     if force:
-      command = ["xm", "destroy", name]
+      command = [constants.XEN_CMD, "destroy", name]
     else:
-      command = ["xm", "shutdown", name]
+      command = [constants.XEN_CMD, "shutdown", name]
     result = utils.RunCmd(command)
 
     if result.failed:
@@ -255,7 +269,7 @@ class XenHypervisor(hv_base.BaseHypervisor):
       raise errors.HypervisorError("Failed to reboot instance %s,"
                                    " not running" % instance.name)
 
-    result = utils.RunCmd(["xm", "reboot", instance.name])
+    result = utils.RunCmd([constants.XEN_CMD, "reboot", instance.name])
     if result.failed:
       raise errors.HypervisorError("Failed to reboot instance %s: %s, %s" %
                                    (instance.name, result.fail_reason,
@@ -293,7 +307,7 @@ class XenHypervisor(hv_base.BaseHypervisor):
 
     """
     # note: in xen 3, memory has changed to total_memory
-    result = utils.RunCmd(["xm", "info"])
+    result = utils.RunCmd([constants.XEN_CMD, "info"])
     if result.failed:
       logging.error("Can't run 'xm info' (%s): %s", result.fail_reason,
                     result.output)
@@ -357,7 +371,7 @@ class XenHypervisor(hv_base.BaseHypervisor):
     For Xen, this verifies that the xend process is running.
 
     """
-    result = utils.RunCmd(["xm", "info"])
+    result = utils.RunCmd([constants.XEN_CMD, "info"])
     if result.failed:
       return "'xm info' failed: %s, %s" % (result.fail_reason, result.output)
 
@@ -464,7 +478,12 @@ class XenHypervisor(hv_base.BaseHypervisor):
       raise errors.HypervisorError("Remote host %s not listening on port"
                                    " %s, cannot migrate" % (target, port))
 
-    args = ["xm", "migrate", "-p", "%d" % 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])
@@ -524,7 +543,7 @@ class XenHypervisor(hv_base.BaseHypervisor):
     try:
       cls.LinuxPowercycle()
     finally:
-      utils.RunCmd(["xm", "debug", "R"])
+      utils.RunCmd([constants.XEN_CMD, "debug", "R"])
 
 
 class XenPvmHypervisor(XenHypervisor):
@@ -617,11 +636,12 @@ class XenPvmHypervisor(XenHypervisor):
     # just in case it exists
     utils.RemoveFile("/etc/xen/auto/%s" % instance.name)
     try:
-      utils.WriteFile("/etc/xen/%s" % instance.name, data=config.getvalue())
+      utils.WriteFile(cls._ConfigFileName(instance.name),
+                      data=config.getvalue())
     except EnvironmentError, err:
       raise errors.HypervisorError("Cannot write Xen instance confile"
-                                   " file /etc/xen/%s: %s" %
-                                   (instance.name, err))
+                                   " file %s: %s" %
+                                   (cls._ConfigFileName(instance.name), err))
 
     return True
 
@@ -763,11 +783,11 @@ class XenHvmHypervisor(XenHypervisor):
     # just in case it exists
     utils.RemoveFile("/etc/xen/auto/%s" % instance.name)
     try:
-      utils.WriteFile("/etc/xen/%s" % instance.name,
+      utils.WriteFile(cls._ConfigFileName(instance.name),
                       data=config.getvalue())
     except EnvironmentError, err:
       raise errors.HypervisorError("Cannot write Xen instance confile"
-                                   " file /etc/xen/%s: %s" %
-                                   (instance.name, err))
+                                   " file %s: %s" %
+                                   (cls._ConfigFileName(instance.name), err))
 
     return True
diff --git a/lib/opcodes.py b/lib/opcodes.py
index 1367c2a55256a8275d40d2a0b738c0e263e2a0b5..714d066c208d72931e38e23ddf721f35982834b6 100644
--- a/lib/opcodes.py
+++ b/lib/opcodes.py
@@ -158,7 +158,7 @@ _TestNicDef = ht.TDictOf(ht.TElemOf(constants.INIC_PARAMS),
 
 _TSetParamsResultItemItems = [
   ht.Comment("name of changed parameter")(ht.TNonEmptyString),
-  ht.TAny,
+  ht.Comment("new value")(ht.TAny),
   ]
 
 _TSetParamsResult = \
diff --git a/lib/rapi/client.py b/lib/rapi/client.py
index e72b30839a9eb73cbb2ee23e75077a8421d0fe35..6b37c71e930745e43ae9c94d0164514ab869a771 100644
--- a/lib/rapi/client.py
+++ b/lib/rapi/client.py
@@ -1452,7 +1452,7 @@ class GanetiRapiClient(object): # pylint: disable=R0904
                              ("/%s/nodes/%s/role" %
                               (GANETI_RAPI_VERSION, node)), None, None)
 
-  def SetNodeRole(self, node, role, force=False):
+  def SetNodeRole(self, node, role, force=False, auto_promote=None):
     """Sets the role for a node.
 
     @type node: str
@@ -1461,6 +1461,9 @@ class GanetiRapiClient(object): # pylint: disable=R0904
     @param role: the role to set for the node
     @type force: bool
     @param force: whether to force the role change
+    @type auto_promote: bool
+    @param auto_promote: Whether node(s) should be promoted to master candidate
+                         if necessary
 
     @rtype: string
     @return: job id
@@ -1470,6 +1473,9 @@ class GanetiRapiClient(object): # pylint: disable=R0904
       ("force", force),
       ]
 
+    if auto_promote is not None:
+      query.append(("auto-promote", auto_promote))
+
     return self._SendRequest(HTTP_PUT,
                              ("/%s/nodes/%s/role" %
                               (GANETI_RAPI_VERSION, node)), query, role)
@@ -1481,7 +1487,6 @@ class GanetiRapiClient(object): # pylint: disable=R0904
     @param node: Node name
     @type force: bool
     @param force: Whether to force the operation
-
     @rtype: string
     @return: job id
 
@@ -1494,6 +1499,21 @@ class GanetiRapiClient(object): # pylint: disable=R0904
                              ("/%s/nodes/%s/powercycle" %
                               (GANETI_RAPI_VERSION, node)), query, None)
 
+  def ModifyNode(self, node, **kwargs):
+    """Modifies a node.
+
+    More details for parameters can be found in the RAPI documentation.
+
+    @type node: string
+    @param node: Node name
+    @rtype: string
+    @return: job id
+
+    """
+    return self._SendRequest(HTTP_PUT,
+                             ("/%s/nodes/%s/modify" %
+                              (GANETI_RAPI_VERSION, node)), None, kwargs)
+
   def GetNodeStorageUnits(self, node, storage_type, output_fields):
     """Gets the storage units for a node.
 
diff --git a/lib/rapi/connector.py b/lib/rapi/connector.py
index a20027bee2511de36f41c1dc62d3fab4b40bb8bc..b701d7141c34170258e3c26f87e73375f838a5ac 100644
--- a/lib/rapi/connector.py
+++ b/lib/rapi/connector.py
@@ -117,6 +117,8 @@ def GetHandlers(node_name_pattern, instance_name_pattern,
       rlib2.R_2_nodes_name_evacuate,
     re.compile(r"^/2/nodes/(%s)/migrate$" % node_name_pattern):
       rlib2.R_2_nodes_name_migrate,
+    re.compile(r"^/2/nodes/(%s)/modify$" % node_name_pattern):
+      rlib2.R_2_nodes_name_modify,
     re.compile(r"^/2/nodes/(%s)/storage$" % node_name_pattern):
       rlib2.R_2_nodes_name_storage,
     re.compile(r"^/2/nodes/(%s)/storage/modify$" % node_name_pattern):
diff --git a/lib/rapi/rlib2.py b/lib/rapi/rlib2.py
index a3277e25fb333006dc14940ec3fc4e9184adfe45..ccaccf944966228083d8a5ce76a1cef71d37339c 100644
--- a/lib/rapi/rlib2.py
+++ b/lib/rapi/rlib2.py
@@ -468,6 +468,7 @@ class R_2_nodes_name_role(baserlib.OpcodeResource):
       "offline": offline,
       "drained": drained,
       "force": self.useForce(),
+      "auto_promote": bool(self._checkIntVariable("auto-promote", default=0)),
       })
 
 
@@ -522,6 +523,23 @@ class R_2_nodes_name_migrate(baserlib.OpcodeResource):
       })
 
 
+class R_2_nodes_name_modify(baserlib.OpcodeResource):
+  """/2/nodes/[node_name]/modify resource.
+
+  """
+  PUT_OPCODE = opcodes.OpNodeSetParams
+
+  def GetPutOpInput(self):
+    """Changes parameters of a node.
+
+    """
+    assert len(self.items) == 1
+
+    return (self.request_body, {
+      "node_name": self.items[0],
+      })
+
+
 class R_2_nodes_name_storage(baserlib.OpcodeResource):
   """/2/nodes/[node_name]/storage resource.
 
diff --git a/test/ganeti.rapi.client_unittest.py b/test/ganeti.rapi.client_unittest.py
index c84f72e915aba045d0602200b13c906133b485b7..e98198dc14d68d2e92f676bfa9100a2c03ff8642 100755
--- a/test/ganeti.rapi.client_unittest.py
+++ b/test/ganeti.rapi.client_unittest.py
@@ -983,6 +983,14 @@ class GanetiRapiClientTests(testutils.GanetiTestCase):
     self.assertFalse(self.rapi.GetLastRequestData())
     self.assertEqual(self.rapi.CountPending(), 0)
 
+  def testModifyNode(self):
+    self.rapi.AddResponse("3783")
+    job_id = self.client.ModifyNode("node16979.example.com", drained=True)
+    self.assertEqual(job_id, 3783)
+    self.assertHandler(rlib2.R_2_nodes_name_modify)
+    self.assertItems(["node16979.example.com"])
+    self.assertEqual(self.rapi.CountPending(), 0)
+
   def testGetNodeStorageUnits(self):
     self.rapi.AddResponse("42")
     self.assertEqual(42,