To prepare a remote export, the X509 key and certificate need to be generated.
A handshake value is also returned for an easier check whether both clusters
share the same cluster domain secret.
---
 lib/cmdlib.py    |   62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/constants.py |    6 +++++
 lib/mcpu.py      |    1 +
 lib/opcodes.py   |   14 ++++++++++++
 4 files changed, 83 insertions(+), 0 deletions(-)

diff --git a/lib/cmdlib.py b/lib/cmdlib.py
index 8eeb471..a621451 100644
--- a/lib/cmdlib.py
+++ b/lib/cmdlib.py
@@ -8822,6 +8822,68 @@ class LUQueryExports(NoHooksLU):
     return result
 
 
+class LUPrepareExport(NoHooksLU):
+  """Prepares an instance for an export and returns useful information.
+
+  """
+  _OP_REQP = ["instance_name", "mode"]
+  REQ_BGL = False
+
+  def CheckArguments(self):
+    """Check the arguments.
+
+    """
+    if self.op.mode not in constants.EXPORT_MODES:
+      raise errors.OpPrereqError("Invalid export mode %r" % self.op.mode,
+                                 errors.ECODE_INVAL)
+
+  def ExpandNames(self):
+    self._ExpandAndLockInstance()
+
+  def CheckPrereq(self):
+    """Check prerequisites.
+
+    """
+    instance_name = self.op.instance_name
+
+    self.instance = self.cfg.GetInstanceInfo(instance_name)
+    assert self.instance is not None, \
+          "Cannot retrieve locked instance %s" % self.op.instance_name
+    _CheckNodeOnline(self, self.instance.primary_node)
+
+    self._cds = _GetClusterDomainSecret()
+
+  def Exec(self, feedback_fn):
+    """Prepares an instance for an export.
+
+    """
+    instance = self.instance
+
+    if self.op.mode == constants.EXPORT_MODE_REMOTE:
+      salt = utils.GenerateSecret(8)
+
+      feedback_fn("Generating X509 certificate on %s" % instance.primary_node)
+      result = self.rpc.call_x509_cert_create(instance.primary_node,
+                                              constants.RIE_CERT_VALIDITY)
+      result.Raise("Can't create X509 key and certificate on %s" % result.node)
+
+      (name, cert_pem) = result.payload
+
+      cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
+                                             cert_pem)
+
+      return {
+        "handshake": (utils.Sha1Hmac(self._cds, constants.RIE_HANDSHAKE,
+                                     salt=salt),
+                      salt),
+        "x509_key_name": (name, utils.Sha1Hmac(self._cds, name, salt=salt),
+                          salt),
+        "x509_ca": utils.SignX509Certificate(cert, self._cds, salt),
+        }
+
+    return None
+
+
 class LUExportInstance(LogicalUnit):
   """Export an instance to an image in the cluster.
 
diff --git a/lib/constants.py b/lib/constants.py
index 13af563..cf6a656 100644
--- a/lib/constants.py
+++ b/lib/constants.py
@@ -333,6 +333,12 @@ LOCKS_APPEND = 'append'
 INSTANCE_CREATE = "create"
 INSTANCE_IMPORT = "import"
 
+# Remote import/export handshake message
+RIE_HANDSHAKE = "Hi, I'm Ganeti"
+
+# Remote import/export certificate validity in seconds
+RIE_CERT_VALIDITY = 24 * 60 * 60
+
 DISK_TEMPLATES = frozenset([DT_DISKLESS, DT_PLAIN,
                             DT_DRBD8, DT_FILE])
 
diff --git a/lib/mcpu.py b/lib/mcpu.py
index c601c51..3198780 100644
--- a/lib/mcpu.py
+++ b/lib/mcpu.py
@@ -210,6 +210,7 @@ class Processor(object):
     opcodes.OpDiagnoseOS: cmdlib.LUDiagnoseOS,
     # exports lu
     opcodes.OpQueryExports: cmdlib.LUQueryExports,
+    opcodes.OpPrepareExport: cmdlib.LUPrepareExport,
     opcodes.OpExportInstance: cmdlib.LUExportInstance,
     opcodes.OpRemoveExport: cmdlib.LURemoveExport,
     # tags lu
diff --git a/lib/opcodes.py b/lib/opcodes.py
index c7d00be..149dbab 100644
--- a/lib/opcodes.py
+++ b/lib/opcodes.py
@@ -653,6 +653,20 @@ class OpQueryExports(OpCode):
   __slots__ = ["nodes", "use_locking"]
 
 
+class OpPrepareExport(OpCode):
+  """Prepares an instance export.
+
+  @ivar instance_name: Instance name
+  @ivar mode: Export mode (one of L{constants.EXPORT_MODES})
+
+  """
+  OP_ID = "OP_BACKUP_PREPARE"
+  OP_DSC_FIELD = "instance_name"
+  __slots__ = [
+    "instance_name", "mode",
+    ]
+
+
 class OpExportInstance(OpCode):
   """Export an instance."""
   OP_ID = "OP_BACKUP_EXPORT"
-- 
1.7.0.4

Reply via email to