return isinstance(val, dict)
+def _TIsLength(size):
+ """Check is the given container is of the given size.
+
+ """
+ return lambda container: len(container) == size
+
+
# Combinator types
def _TAnd(*args):
"""Combine multiple functions using an AND operation.
return fn
+def _TMap(fn, test):
+ """Checks that a modified version of the argument passes the given test.
+
+ """
+ return lambda val: test(fn(val))
+
+
# Type aliases
#: a non-empty string
_PMigrationMode = ("mode", None, _TOr(_TNone,
_TElemOf(constants.HT_MIGRATION_MODES)))
+#: the obsolete 'live' mode (boolean)
+_PMigrationLive = ("live", None, _TMaybeBool)
+
# End types
class LogicalUnit(object):
"""
if not os_obj.supported_variants:
return
- try:
- variant = name.split("+", 1)[1]
- except IndexError:
+ variant = objects.OS.GetVariant(name)
+ if not variant:
raise errors.OpPrereqError("OS name must include a variant",
errors.ECODE_INVAL)
self.LogWarning("Could not re-enable the master role on"
" the master, please restart manually: %s", msg)
+ return clustername
+
class LUSetClusterParams(LogicalUnit):
"""Change the parameters of the cluster.
("nicparams", None, _TOr(_TDict, _TNone)),
("drbd_helper", None, _TOr(_TString, _TNone)),
("default_iallocator", None, _TMaybeString),
+ ("reserved_lvs", None, _TOr(_TListOf(_TNonEmptyString), _TNone)),
+ ("hidden_oss", None, _TOr(_TListOf(\
+ _TAnd(_TList,
+ _TIsLength(2),
+ _TMap(lambda v: v[0], _TElemOf(constants.DDMS_VALUES)))),
+ _TNone)),
+ ("blacklisted_oss", None, _TOr(_TListOf(\
+ _TAnd(_TList,
+ _TIsLength(2),
+ _TMap(lambda v: v[0], _TElemOf(constants.DDMS_VALUES)))),
+ _TNone)),
]
REQ_BGL = False
if self.op.default_iallocator is not None:
self.cluster.default_iallocator = self.op.default_iallocator
+ if self.op.reserved_lvs is not None:
+ self.cluster.reserved_lvs = self.op.reserved_lvs
+
+ def helper_oss(aname, mods, desc):
+ lst = getattr(self.cluster, aname)
+ for key, val in mods:
+ if key == constants.DDM_ADD:
+ if val in lst:
+ feedback_fn("OS %s already in %s, ignoring", val, desc)
+ else:
+ lst.append(val)
+ elif key == constants.DDM_REMOVE:
+ if val in lst:
+ lst.remove(val)
+ else:
+ feedback_fn("OS %s not found in %s, ignoring", val, desc)
+ else:
+ raise errors.ProgrammerError("Invalid modification '%s'" % key)
+
+ if self.op.hidden_oss:
+ helper_oss("hidden_oss", self.op.hidden_oss,
+ "hidden OS list")
+
+ if self.op.blacklisted_oss:
+ helper_oss("blacklisted_oss", self.op.blacklisted_oss,
+ "blacklisted OS list")
+
self.cfg.Update(self.cluster, feedback_fn)
("names", _EmptyList, _TListOf(_TNonEmptyString)),
]
REQ_BGL = False
+ _HID = "hidden"
+ _BLK = "blacklisted"
+ _VLD = "valid"
_FIELDS_STATIC = utils.FieldSet()
- _FIELDS_DYNAMIC = utils.FieldSet("name", "valid", "node_status", "variants",
- "parameters", "api_versions")
+ _FIELDS_DYNAMIC = utils.FieldSet("name", _VLD, "node_status", "variants",
+ "parameters", "api_versions", _HID, _BLK)
def CheckArguments(self):
if self.op.names:
node_data = self.rpc.call_os_diagnose(valid_nodes)
pol = self._DiagnoseByOS(node_data)
output = []
+ cluster = self.cfg.GetClusterInfo()
- for os_name, os_data in pol.items():
+ for os_name in utils.NiceSort(pol.keys()):
+ os_data = pol[os_name]
row = []
valid = True
(variants, params, api_versions) = null_state = (set(), set(), set())
params.intersection_update(node_params)
api_versions.intersection_update(node_api)
+ is_hid = os_name in cluster.hidden_oss
+ is_blk = os_name in cluster.blacklisted_oss
+ if ((self._HID not in self.op.output_fields and is_hid) or
+ (self._BLK not in self.op.output_fields and is_blk) or
+ (self._VLD not in self.op.output_fields and not valid)):
+ continue
+
for field in self.op.output_fields:
if field == "name":
val = os_name
- elif field == "valid":
+ elif field == self._VLD:
val = valid
elif field == "node_status":
# this is just a copy of the dict
for node_name, nos_list in os_data.items():
val[node_name] = nos_list
elif field == "variants":
- val = list(variants)
+ val = utils.NiceSort(list(variants))
elif field == "parameters":
val = list(params)
elif field == "api_versions":
val = list(api_versions)
+ elif field == self._HID:
+ val = is_hid
+ elif field == self._BLK:
+ val = is_blk
else:
raise errors.ParameterError(field)
row.append(val)
# we can't change the master's node flags
if self.op.node_name == self.cfg.GetMasterNode():
raise errors.OpPrereqError("The master role can be changed"
- " only via masterfailover",
+ " only via master-failover",
errors.ECODE_INVAL)
_OP_PARAMS = [
_PInstanceName,
("new_name", _NoDefault, _TNonEmptyString),
- ("ignore_ip", False, _TBool),
- ("check_name", True, _TBool),
+ ("ip_check", False, _TBool),
+ ("name_check", True, _TBool),
]
+ def CheckArguments(self):
+ """Check arguments.
+
+ """
+ if self.op.ip_check and not self.op.name_check:
+ # TODO: make the ip check more flexible and not depend on the name check
+ raise errors.OpPrereqError("Cannot do ip check without a name check",
+ errors.ECODE_INVAL)
+
def BuildHooksEnv(self):
"""Build hooks env.
_CheckInstanceDown(self, instance, "cannot rename")
self.instance = instance
- # new name verification
- if self.op.check_name:
- name_info = netutils.GetHostInfo(self.op.new_name)
- self.op.new_name = name_info.name
-
new_name = self.op.new_name
+ if self.op.name_check:
+ hostinfo = netutils.HostInfo(netutils.HostInfo.NormalizeName(new_name))
+ new_name = self.op.new_name = hostinfo.name
+ if (self.op.ip_check and
+ netutils.TcpPing(hostinfo.ip, constants.DEFAULT_NODED_PORT)):
+ raise errors.OpPrereqError("IP %s of instance %s already in use" %
+ (hostinfo.ip, new_name),
+ errors.ECODE_NOTUNIQUE)
instance_list = self.cfg.GetInstanceList()
if new_name in instance_list:
raise errors.OpPrereqError("Instance '%s' is already in the cluster" %
new_name, errors.ECODE_EXISTS)
- if not self.op.ignore_ip:
- if netutils.TcpPing(name_info.ip, constants.DEFAULT_NODED_PORT):
- raise errors.OpPrereqError("IP %s of instance %s already in use" %
- (name_info.ip, new_name),
- errors.ECODE_NOTUNIQUE)
def Exec(self, feedback_fn):
"""Reinstall the instance.
finally:
_ShutdownInstanceDisks(self, inst)
+ return inst.name
+
class LURemoveInstance(LogicalUnit):
"""Remove an instance.
_OP_PARAMS = [
_PInstanceName,
_PMigrationMode,
+ _PMigrationLive,
("cleanup", False, _TBool),
]
_OP_PARAMS = [
_PNodeName,
_PMigrationMode,
+ _PMigrationLive,
]
REQ_BGL = False
self.instance = instance
- if self.lu.op.mode is None:
+ if self.lu.op.live is not None and self.lu.op.mode is not None:
+ raise errors.OpPrereqError("Only one of the 'live' and 'mode'"
+ " parameters are accepted",
+ errors.ECODE_INVAL)
+ if self.lu.op.live is not None:
+ if self.lu.op.live:
+ self.lu.op.mode = constants.HT_MIGRATION_LIVE
+ else:
+ self.lu.op.mode = constants.HT_MIGRATION_NONLIVE
+ # reset the 'live' parameter to None so that repeated
+ # invocations of CheckPrereq do not raise an exception
+ self.lu.op.live = None
+ elif self.lu.op.mode is None:
# read the default value from the hypervisor
i_hv = self.cfg.GetClusterInfo().FillHV(instance, skip_globals=False)
self.lu.op.mode = i_hv[constants.HV_MIGRATION_MODE]
("os_type", None, _TMaybeString),
("force_variant", False, _TBool),
("source_handshake", None, _TOr(_TList, _TNone)),
- ("source_x509_ca", None, _TOr(_TList, _TNone)),
+ ("source_x509_ca", None, _TMaybeString),
("source_instance_name", None, _TMaybeString),
("src_node", None, _TMaybeString),
("src_path", None, _TMaybeString),
("identify_defaults", False, _TBool),
("file_driver", None, _TOr(_TNone, _TElemOf(constants.FILE_DRIVER))),
("file_storage_dir", None, _TMaybeString),
- ("dry_run", False, _TBool),
]
REQ_BGL = False
if self.op.ip_check and not self.op.name_check:
# TODO: make the ip check more flexible and not depend on the name check
- raise errors.OpPrereqError("Cannot do ip checks without a name check",
+ raise errors.OpPrereqError("Cannot do ip check without a name check",
errors.ECODE_INVAL)
# check nics' parameter names
### Node/iallocator related checks
_CheckIAllocatorOrNode(self, "iallocator", "pnode")
+ if self.op.pnode is not None:
+ if self.op.disk_template in constants.DTS_NET_MIRROR:
+ if self.op.snode is None:
+ raise errors.OpPrereqError("The networked disk templates need"
+ " a mirror node", errors.ECODE_INVAL)
+ elif self.op.snode:
+ self.LogWarning("Secondary node will be ignored on non-mirrored disk"
+ " template")
+ self.op.snode = None
+
self._cds = _GetClusterDomainSecret()
if self.op.mode == constants.INSTANCE_IMPORT:
if self.op.os_type is None:
raise errors.OpPrereqError("No guest OS specified",
errors.ECODE_INVAL)
+ if self.op.os_type in self.cfg.GetClusterInfo().blacklisted_oss:
+ raise errors.OpPrereqError("Guest OS '%s' is not allowed for"
+ " installation" % self.op.os_type,
+ errors.ECODE_STATE)
if self.op.disk_template is None:
raise errors.OpPrereqError("No disk template specified",
errors.ECODE_INVAL)
# mirror node verification
if self.op.disk_template in constants.DTS_NET_MIRROR:
- if self.op.snode is None:
- raise errors.OpPrereqError("The networked disk templates need"
- " a mirror node", errors.ECODE_INVAL)
if self.op.snode == pnode.name:
raise errors.OpPrereqError("The secondary node cannot be the"
" primary node.", errors.ECODE_INVAL)
"""
_OP_PARAMS = [
("kind", _NoDefault, _TElemOf(constants.VALID_TAG_TYPES)),
- ("name", _NoDefault, _TNonEmptyString),
+ # Name is only meaningful for nodes and instances
+ ("name", _NoDefault, _TMaybeString),
]
REQ_BGL = False
"""
_OP_PARAMS = [
("kind", _NoDefault, _TElemOf(constants.VALID_TAG_TYPES)),
- ("name", _NoDefault, _TNonEmptyString),
+ # Name is only meaningful for nodes and instances
+ ("name", _NoDefault, _TMaybeString),
("tags", _NoDefault, _TListOf(_TNonEmptyString)),
]
REQ_BGL = False
"""
_OP_PARAMS = [
("kind", _NoDefault, _TElemOf(constants.VALID_TAG_TYPES)),
- ("name", _NoDefault, _TNonEmptyString),
+ # Name is only meaningful for nodes and instances
+ ("name", _NoDefault, _TMaybeString),
("tags", _NoDefault, _TListOf(_TNonEmptyString)),
]
REQ_BGL = False
self.LogInfo("Executing")
if self.op.log_messages:
+ self._Notify(False, constants.JQT_STARTMSG, len(self.op.log_messages))
for idx, msg in enumerate(self.op.log_messages):
self.LogInfo("Sending log message %s", idx + 1)
feedback_fn(constants.JQT_MSGPREFIX + msg)