@param name: OS name passed by the user, to check for validity
"""
+ variant = objects.OS.GetVariant(name)
if not os_obj.supported_variants:
+ if variant:
+ raise errors.OpPrereqError("OS '%s' doesn't support variants ('%s'"
+ " passed)" % (os_obj.name, variant),
+ errors.ECODE_INVAL)
return
- variant = objects.OS.GetVariant(name)
if not variant:
raise errors.OpPrereqError("OS name must include a variant",
errors.ECODE_INVAL)
@param all_nvinfo: RPC results
"""
- node_names = frozenset(node.name for node in nodeinfo)
+ node_names = frozenset(node.name for node in nodeinfo if not node.offline)
assert master_node in node_names
assert (len(files_all | files_all_opt | files_mc | files_vm) ==
fileinfo = dict((filename, {}) for filename in file2nodefn.keys())
for node in nodeinfo:
+ if node.offline:
+ continue
+
nresult = all_nvinfo[node.name]
if nresult.fail_msg or not nresult.payload:
_ErrorIf(len(os_data) > 1, self.ENODEOS, node,
"OS '%s' has multiple entries (first one shadows the rest): %s",
os_name, utils.CommaJoin([v[0] for v in os_data]))
- # this will catched in backend too
- _ErrorIf(compat.any(v >= constants.OS_API_V15 for v in f_api)
- and not f_var, self.ENODEOS, node,
- "OS %s with API at least %d does not declare any variant",
- os_name, constants.OS_API_V15)
# comparisons with the 'base' image
test = os_name not in base.oslist
_ErrorIf(test, self.ENODEOS, node,
def ExpandNames(self, lu):
lu.needed_locks = {}
- lu.share_locks[locking.LEVEL_INSTANCE] = 1
- lu.share_locks[locking.LEVEL_NODE] = 1
+ lu.share_locks = _ShareAll()
if self.names:
self.wanted = _GetWantedInstances(lu, self.names)
query.IQ_LIVE in self.requested_data)
if self.do_locking:
lu.needed_locks[locking.LEVEL_INSTANCE] = self.wanted
+ lu.needed_locks[locking.LEVEL_NODEGROUP] = []
lu.needed_locks[locking.LEVEL_NODE] = []
lu.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
+ self.do_grouplocks = (self.do_locking and
+ query.IQ_NODES in self.requested_data)
+
def DeclareLocks(self, lu, level):
- if level == locking.LEVEL_NODE and self.do_locking:
- lu._LockInstancesNodes() # pylint: disable-msg=W0212
+ if self.do_locking:
+ if level == locking.LEVEL_NODEGROUP and self.do_grouplocks:
+ assert not lu.needed_locks[locking.LEVEL_NODEGROUP]
+
+ # Lock all groups used by instances optimistically; this requires going
+ # via the node before it's locked, requiring verification later on
+ lu.needed_locks[locking.LEVEL_NODEGROUP] = \
+ set(group_uuid
+ for instance_name in
+ lu.glm.list_owned(locking.LEVEL_INSTANCE)
+ for group_uuid in
+ lu.cfg.GetInstanceNodeGroups(instance_name))
+ elif level == locking.LEVEL_NODE:
+ lu._LockInstancesNodes() # pylint: disable-msg=W0212
+
+ @staticmethod
+ def _CheckGroupLocks(lu):
+ owned_instances = frozenset(lu.glm.list_owned(locking.LEVEL_INSTANCE))
+ owned_groups = frozenset(lu.glm.list_owned(locking.LEVEL_NODEGROUP))
+
+ # Check if node groups for locked instances are still correct
+ for instance_name in owned_instances:
+ inst_groups = lu.cfg.GetInstanceNodeGroups(instance_name)
+ if not owned_groups.issuperset(inst_groups):
+ raise errors.OpPrereqError("Instance %s's node groups changed since"
+ " locks were acquired, current groups are"
+ " are '%s', owning groups '%s'; retry the"
+ " operation" %
+ (instance_name,
+ utils.CommaJoin(inst_groups),
+ utils.CommaJoin(owned_groups)),
+ errors.ECODE_STATE)
def _GetQueryData(self, lu):
"""Computes the list of instances and their attributes.
"""
+ if self.do_grouplocks:
+ self._CheckGroupLocks(lu)
+
cluster = lu.cfg.GetClusterInfo()
all_info = lu.cfg.GetAllInstancesInfo()
else:
consinfo = None
+ if query.IQ_NODES in self.requested_data:
+ node_names = set(itertools.chain(*map(operator.attrgetter("all_nodes"),
+ instance_list)))
+ nodes = dict((name, lu.cfg.GetNodeInfo(name)) for name in node_names)
+ groups = dict((uuid, lu.cfg.GetNodeGroup(uuid))
+ for uuid in set(map(operator.attrgetter("group"),
+ nodes.values())))
+ else:
+ nodes = None
+ groups = None
+
return query.InstanceQueryData(instance_list, lu.cfg.GetClusterInfo(),
disk_usage, offline_nodes, bad_nodes,
- live_data, wrongnode_inst, consinfo)
+ live_data, wrongnode_inst, consinfo,
+ nodes, groups)
class LUQuery(NoHooksLU):
ial = IAllocator(lu.cfg, lu.rpc,
mode=constants.IALLOCATOR_MODE_RELOC,
name=instance_name,
- relocate_from=relocate_from)
+ relocate_from=list(relocate_from))
ial.Run(iallocator_name)
elif self.op.mode == constants.IALLOCATOR_MODE_RELOC:
fname = _ExpandInstanceName(self.cfg, self.op.name)
self.op.name = fname
- self.relocate_from = self.cfg.GetInstanceInfo(fname).secondary_nodes
+ self.relocate_from = \
+ list(self.cfg.GetInstanceInfo(fname).secondary_nodes)
elif self.op.mode == constants.IALLOCATOR_MODE_MEVAC:
if not hasattr(self.op, "evac_nodes"):
raise errors.OpPrereqError("Missing attribute 'evac_nodes' on"