diff --git a/doc/rapi.rst b/doc/rapi.rst
index df4a9ee792a397b81640f6c7ab6d3b475ee49434..0e82c3779f8f7a57c28d2d6e38caae3e9e280499 100644
--- a/doc/rapi.rst
+++ b/doc/rapi.rst
@@ -414,6 +414,12 @@ Body parameters:
   File storage driver.
 ``iallocator`` (string)
   Instance allocator name.
+``source_handshake``
+  Signed handshake from source (remote import only).
+``source_x509_ca`` (string)
+  Source X509 CA in PEM format (remote import only).
+``source_instance_name`` (string)
+  Source instance name (remote import only).
 ``hypervisor`` (string)
   Hypervisor name.
 ``hvparams`` (dict)
@@ -579,6 +585,47 @@ It supports the following commands: ``PUT``.
 Takes no parameters.
 
 
+``/2/instances/[instance_name]/prepare-export``
++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Prepares an export of an instance.
+
+It supports the following commands: ``PUT``.
+
+``PUT``
+~~~~~~~
+
+Takes one parameter, ``mode``, for the export mode. Returns a job ID.
+
+
+``/2/instances/[instance_name]/export``
++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Exports an instance.
+
+It supports the following commands: ``PUT``.
+
+``PUT``
+~~~~~~~
+
+Returns a job ID.
+
+Body parameters:
+
+``mode`` (string)
+  Export mode.
+``destination`` (required)
+  Destination information, depends on export mode.
+``shutdown`` (bool, required)
+  Whether to shutdown instance before export.
+``remove_instance`` (bool)
+  Whether to remove instance after export.
+``x509_key_name``
+  Name of X509 key (remote export only).
+``destination_x509_ca``
+  Destination X509 CA (remote export only).
+
+
 ``/2/instances/[instance_name]/tags``
 +++++++++++++++++++++++++++++++++++++
 
diff --git a/lib/rapi/client.py b/lib/rapi/client.py
index 262e3893e9b77732c62d271f1bcbcfe090163b89..e1513aa9ac54d871a848dad3ded01d2e0b68b3e2 100644
--- a/lib/rapi/client.py
+++ b/lib/rapi/client.py
@@ -840,6 +840,56 @@ class GanetiRapiClient(object):
                              ("/%s/instances/%s/replace-disks" %
                               (GANETI_RAPI_VERSION, instance)), query, None)
 
+  def PrepareExport(self, instance, mode):
+    """Prepares an instance for an export.
+
+    @type instance: string
+    @param instance: Instance name
+    @type mode: string
+    @param mode: Export mode
+    @rtype: string
+    @return: Job ID
+
+    """
+    query = [("mode", mode)]
+    return self._SendRequest(HTTP_PUT,
+                             ("/%s/instances/%s/prepare-export" %
+                              (GANETI_RAPI_VERSION, instance)), query, None)
+
+  def ExportInstance(self, instance, mode, destination, shutdown=None,
+                     remove_instance=None,
+                     x509_key_name=None, destination_x509_ca=None):
+    """Exports an instance.
+
+    @type instance: string
+    @param instance: Instance name
+    @type mode: string
+    @param mode: Export mode
+    @rtype: string
+    @return: Job ID
+
+    """
+    body = {
+      "destination": destination,
+      "mode": mode,
+      }
+
+    if shutdown is not None:
+      body["shutdown"] = shutdown
+
+    if remove_instance is not None:
+      body["remove_instance"] = remove_instance
+
+    if x509_key_name is not None:
+      body["x509_key_name"] = x509_key_name
+
+    if destination_x509_ca is not None:
+      body["destination_x509_ca"] = destination_x509_ca
+
+    return self._SendRequest(HTTP_PUT,
+                             ("/%s/instances/%s/export" %
+                              (GANETI_RAPI_VERSION, instance)), None, body)
+
   def GetJobs(self):
     """Gets all jobs for the cluster.
 
diff --git a/lib/rapi/connector.py b/lib/rapi/connector.py
index aa60a0a89a0b22195db54f2f0bc7206912bc442a..1cef5927ea422848bb5cb072ab22d62b25929c86 100644
--- a/lib/rapi/connector.py
+++ b/lib/rapi/connector.py
@@ -205,6 +205,10 @@ def GetHandlers(node_name_pattern, instance_name_pattern, job_id_pattern):
       rlib2.R_2_instances_name_activate_disks,
     re.compile(r'^/2/instances/(%s)/deactivate-disks$' % instance_name_pattern):
       rlib2.R_2_instances_name_deactivate_disks,
+    re.compile(r'^/2/instances/(%s)/prepare-export$' % instance_name_pattern):
+      rlib2.R_2_instances_name_prepare_export,
+    re.compile(r'^/2/instances/(%s)/export$' % instance_name_pattern):
+      rlib2.R_2_instances_name_export,
 
     "/2/jobs": rlib2.R_2_jobs,
     re.compile(r'/2/jobs/(%s)$' % job_id_pattern):
diff --git a/lib/rapi/rlib2.py b/lib/rapi/rlib2.py
index 6626ae8434fdce8140b8ee8ef8f588a16e4a6e89..5425ed9628ba6493f86627cbd5ee0dac6ab6570f 100644
--- a/lib/rapi/rlib2.py
+++ b/lib/rapi/rlib2.py
@@ -578,6 +578,12 @@ def _ParseInstanceCreateRequestVersion1(data, dry_run):
                                              default=None),
     file_driver=baserlib.CheckParameter(data, "file_driver",
                                         default=constants.FD_LOOP),
+    source_handshake=baserlib.CheckParameter(data, "source_handshake",
+                                             default=None),
+    source_x509_ca=baserlib.CheckParameter(data, "source_x509_ca",
+                                           default=None),
+    source_instance_name=baserlib.CheckParameter(data, "source_instance_name",
+                                                 default=None),
     iallocator=baserlib.CheckParameter(data, "iallocator", default=None),
     hypervisor=baserlib.CheckParameter(data, "hypervisor", default=None),
     hvparams=hvparams,
@@ -891,6 +897,69 @@ class R_2_instances_name_deactivate_disks(baserlib.R_Generic):
     return baserlib.SubmitJob([op])
 
 
+class R_2_instances_name_prepare_export(baserlib.R_Generic):
+  """/2/instances/[instance_name]/prepare-export resource.
+
+  """
+  def PUT(self):
+    """Prepares an export for an instance.
+
+    @return: a job id
+
+    """
+    instance_name = self.items[0]
+    mode = self._checkStringVariable("mode")
+
+    op = opcodes.OpPrepareExport(instance_name=instance_name,
+                                 mode=mode)
+
+    return baserlib.SubmitJob([op])
+
+
+def _ParseExportInstanceRequest(name, data):
+  """Parses a request for an instance export.
+
+  @rtype: L{opcodes.OpExportInstance}
+  @return: Instance export opcode
+
+  """
+  mode = baserlib.CheckParameter(data, "mode",
+                                 default=constants.EXPORT_MODE_LOCAL)
+  target_node = baserlib.CheckParameter(data, "destination")
+  shutdown = baserlib.CheckParameter(data, "shutdown", exptype=bool)
+  remove_instance = baserlib.CheckParameter(data, "remove_instance",
+                                            exptype=bool, default=False)
+  x509_key_name = baserlib.CheckParameter(data, "x509_key_name", default=None)
+  destination_x509_ca = baserlib.CheckParameter(data, "destination_x509_ca",
+                                                default=None)
+
+  return opcodes.OpExportInstance(instance_name=name,
+                                  mode=mode,
+                                  target_node=target_node,
+                                  shutdown=shutdown,
+                                  remove_instance=remove_instance,
+                                  x509_key_name=x509_key_name,
+                                  destination_x509_ca=destination_x509_ca)
+
+
+class R_2_instances_name_export(baserlib.R_Generic):
+  """/2/instances/[instance_name]/export resource.
+
+  """
+  def PUT(self):
+    """Exports an instance.
+
+    @return: a job id
+
+    """
+    if not isinstance(self.request_body, dict):
+      raise http.HttpBadRequest("Invalid body contents, not a dictionary")
+
+    op = _ParseExportInstanceRequest(self.items[0], self.request_body)
+
+    return baserlib.SubmitJob([op])
+
+
 class _R_Tags(baserlib.R_Generic):
   """ Quasiclass for tagging resources
 
diff --git a/qa/qa_rapi.py b/qa/qa_rapi.py
index c8214865a67a9ed03fed972de8ea323646366fa8..eb35adbf2577b5b2ba77cef1e38decc5ac7a3e6b 100644
--- a/qa/qa_rapi.py
+++ b/qa/qa_rapi.py
@@ -198,6 +198,19 @@ def TestInstance(instance):
      _VerifyReturnsJob, 'PUT', None),
     ])
 
+  # Test OpPrepareExport
+  (job_id, ) = _DoTests([
+    ("/2/instances/%s/prepare-export?mode=%s" %
+     (instance["name"], constants.EXPORT_MODE_REMOTE),
+     _VerifyReturnsJob, "PUT", None),
+    ])
+
+  result = _WaitForRapiJob(job_id)[0]
+  AssertEqual(len(result["handshake"]), 3)
+  AssertEqual(result["handshake"][0], constants.RIE_VERSION)
+  AssertEqual(len(result["x509_key_name"]), 3)
+  AssertIn("-----BEGIN CERTIFICATE-----", result["x509_ca"])
+
 
 def TestNode(node):
   """Testing getting node(s) info via remote API.
@@ -259,7 +272,8 @@ def _WaitForRapiJob(job_id):
     ("/2/jobs/%s" % job_id, _VerifyJob, "GET", None),
     ])
 
-  rapi.client_utils.PollJob(_rapi_client, job_id, cli.StdioJobPollReportCb())
+  return rapi.client_utils.PollJob(_rapi_client, job_id,
+                                   cli.StdioJobPollReportCb())
 
 
 def TestRapiInstanceAdd(node, use_client):
diff --git a/test/ganeti.rapi.client_unittest.py b/test/ganeti.rapi.client_unittest.py
index 54fd5ff23eb5839027d35c5cbc7366ecedc4151c..10c23d00c5118ace57392e451a26f191d869e2f1 100755
--- a/test/ganeti.rapi.client_unittest.py
+++ b/test/ganeti.rapi.client_unittest.py
@@ -396,6 +396,26 @@ class GanetiRapiClientTests(testutils.GanetiTestCase):
     self.assertItems(["instance-moo"])
     self.assertQuery("disks", None)
 
+  def testPrepareExport(self):
+    self.rapi.AddResponse("8326")
+    self.assertEqual(8326, self.client.PrepareExport("inst1", "local"))
+    self.assertHandler(rlib2.R_2_instances_name_prepare_export)
+    self.assertItems(["inst1"])
+    self.assertQuery("mode", ["local"])
+
+  def testExportInstance(self):
+    self.rapi.AddResponse("19695")
+    job_id = self.client.ExportInstance("inst2", "local", "nodeX",
+                                        shutdown=True)
+    self.assertEqual(job_id, 19695)
+    self.assertHandler(rlib2.R_2_instances_name_export)
+    self.assertItems(["inst2"])
+
+    data = serializer.LoadJson(self.http.last_request.data)
+    self.assertEqual(data["mode"], "local")
+    self.assertEqual(data["destination"], "nodeX")
+    self.assertEqual(data["shutdown"], True)
+
   def testGetJobs(self):
     self.rapi.AddResponse('[ { "id": "123", "uri": "\\/2\\/jobs\\/123" },'
                           '  { "id": "124", "uri": "\\/2\\/jobs\\/124" } ]')
diff --git a/test/ganeti.rapi.rlib2_unittest.py b/test/ganeti.rapi.rlib2_unittest.py
index 70f163e3b435ebcfe1f20b29880ca6d1c8e9a64c..d2cab632c353c6acf9c39fff1402f6e51b1ede7e 100755
--- a/test/ganeti.rapi.rlib2_unittest.py
+++ b/test/ganeti.rapi.rlib2_unittest.py
@@ -180,5 +180,49 @@ class TestParseInstanceCreateRequestVersion1(testutils.GanetiTestCase):
         self.assertRaises(http.HttpBadRequest, self.Parse, data, False)
 
 
+class TestParseExportInstanceRequest(testutils.GanetiTestCase):
+  def setUp(self):
+    testutils.GanetiTestCase.setUp(self)
+
+    self.Parse = rlib2._ParseExportInstanceRequest
+
+  def test(self):
+    name = "instmoo"
+    data = {
+      "mode": constants.EXPORT_MODE_REMOTE,
+      "destination": [(1, 2, 3), (99, 99, 99)],
+      "shutdown": True,
+      "remove_instance": True,
+      "x509_key_name": ("name", "hash"),
+      "destination_x509_ca": ("x", "y", "z"),
+      }
+    op = self.Parse(name, data)
+    self.assert_(isinstance(op, opcodes.OpExportInstance))
+    self.assertEqual(op.instance_name, name)
+    self.assertEqual(op.mode, constants.EXPORT_MODE_REMOTE)
+    self.assertEqual(op.shutdown, True)
+    self.assertEqual(op.remove_instance, True)
+    self.assertEqualValues(op.x509_key_name, ("name", "hash"))
+    self.assertEqualValues(op.destination_x509_ca, ("x", "y", "z"))
+
+  def testDefaults(self):
+    name = "inst1"
+    data = {
+      "destination": "node2",
+      "shutdown": False,
+      }
+    op = self.Parse(name, data)
+    self.assert_(isinstance(op, opcodes.OpExportInstance))
+    self.assertEqual(op.instance_name, name)
+    self.assertEqual(op.mode, constants.EXPORT_MODE_LOCAL)
+    self.assertEqual(op.remove_instance, False)
+
+  def testErrors(self):
+    self.assertRaises(http.HttpBadRequest, self.Parse, "err1",
+                      { "remove_instance": "True", })
+    self.assertRaises(http.HttpBadRequest, self.Parse, "err1",
+                      { "remove_instance": "False", })
+
+
 if __name__ == '__main__':
   testutils.GanetiTestProgram()