Revision 4a96f1d1 lib/cmdlib.py
b/lib/cmdlib.py | ||
---|---|---|
8903 | 8903 |
self.remove_instance = getattr(self.op, "remove_instance", False) |
8904 | 8904 |
self.ignore_remove_failures = getattr(self.op, "ignore_remove_failures", |
8905 | 8905 |
False) |
8906 |
self.export_mode = getattr(self.op, "mode", constants.EXPORT_MODE_LOCAL) |
|
8907 |
self.x509_key_name = getattr(self.op, "x509_key_name", None) |
|
8908 |
self.dest_x509_ca_pem = getattr(self.op, "destination_x509_ca", None) |
|
8906 | 8909 |
|
8907 | 8910 |
if self.remove_instance and not self.op.shutdown: |
8908 | 8911 |
raise errors.OpPrereqError("Can not remove instance without shutting it" |
8909 | 8912 |
" down before") |
8910 | 8913 |
|
8914 |
if self.export_mode not in constants.EXPORT_MODES: |
|
8915 |
raise errors.OpPrereqError("Invalid export mode %r" % self.export_mode, |
|
8916 |
errors.ECODE_INVAL) |
|
8917 |
|
|
8918 |
if self.export_mode == constants.EXPORT_MODE_REMOTE: |
|
8919 |
if not self.x509_key_name: |
|
8920 |
raise errors.OpPrereqError("Missing X509 key name for encryption", |
|
8921 |
errors.ECODE_INVAL) |
|
8922 |
|
|
8923 |
if not self.dest_x509_ca_pem: |
|
8924 |
raise errors.OpPrereqError("Missing destination X509 CA", |
|
8925 |
errors.ECODE_INVAL) |
|
8926 |
|
|
8911 | 8927 |
def ExpandNames(self): |
8912 | 8928 |
self._ExpandAndLockInstance() |
8913 | 8929 |
|
8914 |
# FIXME: lock only instance primary and destination node |
|
8915 |
# |
|
8916 |
# Sad but true, for now we have do lock all nodes, as we don't know where |
|
8917 |
# the previous export might be, and and in this LU we search for it and |
|
8918 |
# remove it from its current node. In the future we could fix this by: |
|
8919 |
# - making a tasklet to search (share-lock all), then create the new one, |
|
8920 |
# then one to remove, after |
|
8921 |
# - removing the removal operation altogether |
|
8922 |
self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET |
|
8930 |
# Lock all nodes for local exports |
|
8931 |
if self.export_mode == constants.EXPORT_MODE_LOCAL: |
|
8932 |
# FIXME: lock only instance primary and destination node |
|
8933 |
# |
|
8934 |
# Sad but true, for now we have do lock all nodes, as we don't know where |
|
8935 |
# the previous export might be, and in this LU we search for it and |
|
8936 |
# remove it from its current node. In the future we could fix this by: |
|
8937 |
# - making a tasklet to search (share-lock all), then create the new one, |
|
8938 |
# then one to remove, after |
|
8939 |
# - removing the removal operation altogether |
|
8940 |
self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET |
|
8923 | 8941 |
|
8924 | 8942 |
def DeclareLocks(self, level): |
8925 | 8943 |
"""Last minute lock declaration.""" |
... | ... | |
8932 | 8950 |
|
8933 | 8951 |
""" |
8934 | 8952 |
env = { |
8953 |
"EXPORT_MODE": self.export_mode, |
|
8935 | 8954 |
"EXPORT_NODE": self.op.target_node, |
8936 | 8955 |
"EXPORT_DO_SHUTDOWN": self.op.shutdown, |
8937 | 8956 |
"SHUTDOWN_TIMEOUT": self.shutdown_timeout, |
8938 | 8957 |
# TODO: Generic function for boolean env variables |
8939 | 8958 |
"REMOVE_INSTANCE": str(bool(self.remove_instance)), |
8940 | 8959 |
} |
8960 |
|
|
8941 | 8961 |
env.update(_BuildInstanceHookEnvByObject(self, self.instance)) |
8942 |
nl = [self.cfg.GetMasterNode(), self.instance.primary_node, |
|
8943 |
self.op.target_node] |
|
8962 |
|
|
8963 |
nl = [self.cfg.GetMasterNode(), self.instance.primary_node] |
|
8964 |
|
|
8965 |
if self.export_mode == constants.EXPORT_MODE_LOCAL: |
|
8966 |
nl.append(self.op.target_node) |
|
8967 |
|
|
8944 | 8968 |
return env, nl, nl |
8945 | 8969 |
|
8946 | 8970 |
def CheckPrereq(self): |
... | ... | |
8950 | 8974 |
|
8951 | 8975 |
""" |
8952 | 8976 |
instance_name = self.op.instance_name |
8977 |
|
|
8953 | 8978 |
self.instance = self.cfg.GetInstanceInfo(instance_name) |
8954 | 8979 |
assert self.instance is not None, \ |
8955 | 8980 |
"Cannot retrieve locked instance %s" % self.op.instance_name |
8956 | 8981 |
_CheckNodeOnline(self, self.instance.primary_node) |
8957 | 8982 |
|
8958 |
self.op.target_node = _ExpandNodeName(self.cfg, self.op.target_node) |
|
8959 |
self.dst_node = self.cfg.GetNodeInfo(self.op.target_node) |
|
8960 |
assert self.dst_node is not None |
|
8983 |
if self.export_mode == constants.EXPORT_MODE_LOCAL: |
|
8984 |
self.op.target_node = _ExpandNodeName(self.cfg, self.op.target_node) |
|
8985 |
self.dst_node = self.cfg.GetNodeInfo(self.op.target_node) |
|
8986 |
assert self.dst_node is not None |
|
8987 |
|
|
8988 |
_CheckNodeOnline(self, self.dst_node.name) |
|
8989 |
_CheckNodeNotDrained(self, self.dst_node.name) |
|
8990 |
|
|
8991 |
self._cds = None |
|
8992 |
self.dest_x509_ca = None |
|
8993 |
|
|
8994 |
elif self.export_mode == constants.EXPORT_MODE_REMOTE: |
|
8995 |
self.dst_node = None |
|
8996 |
|
|
8997 |
if len(self.op.target_node) != len(self.instance.disks): |
|
8998 |
raise errors.OpPrereqError(("Received destination information for %s" |
|
8999 |
" disks, but instance %s has %s disks") % |
|
9000 |
(len(self.op.target_node), instance_name, |
|
9001 |
len(self.instance.disks)), |
|
9002 |
errors.ECODE_INVAL) |
|
9003 |
|
|
9004 |
cds = _GetClusterDomainSecret() |
|
9005 |
|
|
9006 |
# Check X509 key name |
|
9007 |
try: |
|
9008 |
(key_name, hmac_digest, hmac_salt) = self.x509_key_name |
|
9009 |
except (TypeError, ValueError), err: |
|
9010 |
raise errors.OpPrereqError("Invalid data for X509 key name: %s" % err) |
|
8961 | 9011 |
|
8962 |
_CheckNodeOnline(self, self.dst_node.name) |
|
8963 |
_CheckNodeNotDrained(self, self.dst_node.name) |
|
9012 |
if not utils.VerifySha1Hmac(cds, key_name, hmac_digest, salt=hmac_salt): |
|
9013 |
raise errors.OpPrereqError("HMAC for X509 key name is wrong", |
|
9014 |
errors.ECODE_INVAL) |
|
9015 |
|
|
9016 |
# Load and verify CA |
|
9017 |
try: |
|
9018 |
(cert, _) = utils.LoadSignedX509Certificate(self.dest_x509_ca_pem, cds) |
|
9019 |
except OpenSSL.crypto.Error, err: |
|
9020 |
raise errors.OpPrereqError("Unable to load destination X509 CA (%s)" % |
|
9021 |
(err, ), errors.ECODE_INVAL) |
|
9022 |
|
|
9023 |
(errcode, msg) = utils.VerifyX509Certificate(cert, None, None) |
|
9024 |
if errcode is not None: |
|
9025 |
raise errors.OpPrereqError("Invalid destination X509 CA (%s)" % (msg, ), |
|
9026 |
errors.ECODE_INVAL) |
|
9027 |
|
|
9028 |
self.dest_x509_ca = cert |
|
9029 |
|
|
9030 |
# Verify target information |
|
9031 |
for idx, disk_data in enumerate(self.op.target_node): |
|
9032 |
try: |
|
9033 |
masterd.instance.CheckRemoteExportDiskInfo(cds, idx, disk_data) |
|
9034 |
except errors.GenericError, err: |
|
9035 |
raise errors.OpPrereqError("Target info for disk %s: %s" % (idx, err), |
|
9036 |
errors.ECODE_INVAL) |
|
9037 |
|
|
9038 |
else: |
|
9039 |
raise errors.ProgrammerError("Unhandled export mode %r" % |
|
9040 |
self.export_mode) |
|
8964 | 9041 |
|
8965 | 9042 |
# instance disk type verification |
8966 | 9043 |
# TODO: Implement export support for file-based disks |
... | ... | |
8976 | 9053 |
exports will be removed from the nodes A, B and D. |
8977 | 9054 |
|
8978 | 9055 |
""" |
9056 |
assert self.export_mode != constants.EXPORT_MODE_REMOTE |
|
9057 |
|
|
8979 | 9058 |
nodelist = self.cfg.GetNodeList() |
8980 | 9059 |
nodelist.remove(self.dst_node.name) |
8981 | 9060 |
|
... | ... | |
8999 | 9078 |
"""Export an instance to an image in the cluster. |
9000 | 9079 |
|
9001 | 9080 |
""" |
9081 |
assert self.export_mode in constants.EXPORT_MODES |
|
9082 |
|
|
9002 | 9083 |
instance = self.instance |
9003 | 9084 |
src_node = instance.primary_node |
9004 | 9085 |
|
... | ... | |
9029 | 9110 |
|
9030 | 9111 |
helper.CreateSnapshots() |
9031 | 9112 |
try: |
9032 |
(fin_resu, dresults) = helper.LocalExport(self.dst_node) |
|
9113 |
if self.export_mode == constants.EXPORT_MODE_LOCAL: |
|
9114 |
(fin_resu, dresults) = helper.LocalExport(self.dst_node) |
|
9115 |
elif self.export_mode == constants.EXPORT_MODE_REMOTE: |
|
9116 |
connect_timeout = constants.RIE_CONNECT_TIMEOUT |
|
9117 |
timeouts = masterd.instance.ImportExportTimeouts(connect_timeout) |
|
9118 |
|
|
9119 |
(key_name, _, _) = self.x509_key_name |
|
9120 |
(fin_resu, dresults) = helper.RemoteExport(key_name, |
|
9121 |
self.dest_x509_ca, |
|
9122 |
self.op.target_node, |
|
9123 |
timeouts) |
|
9033 | 9124 |
finally: |
9034 | 9125 |
helper.Cleanup() |
9035 | 9126 |
|
... | ... | |
9053 | 9144 |
_RemoveInstance(self, feedback_fn, instance, |
9054 | 9145 |
self.ignore_remove_failures) |
9055 | 9146 |
|
9056 |
self._CleanupExports(feedback_fn) |
|
9147 |
if self.export_mode == constants.EXPORT_MODE_LOCAL: |
|
9148 |
self._CleanupExports(feedback_fn) |
|
9057 | 9149 |
|
9058 | 9150 |
return fin_resu, dresults |
9059 | 9151 |
|
Also available in: Unified diff