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