#: Attribute holding field definitions
FIELDS = None
- def __init__(self, names, fields, use_locking):
+ def __init__(self, filter_, fields, use_locking):
"""Initializes this class.
"""
- self.names = names
+ self.names = qlang.ReadSimpleFilter("name", filter_)
self.use_locking = use_locking
self.query = query.Query(self.FIELDS, fields)
@ivar instances: a list of running instances (runtime)
@ivar pinst: list of configured primary instances (config)
@ivar sinst: list of configured secondary instances (config)
- @ivar sbp: diction of {secondary-node: list of instances} of all peers
- of this node (config)
+ @ivar sbp: dictionary of {primary-node: list of instances} for all
+ instances for which this node is secondary (config)
@ivar mfree: free memory, as reported by hypervisor (runtime)
@ivar dfree: free disk, as reported by the node (runtime)
@ivar offline: the offline status (config)
node_current)
for node, n_img in node_image.items():
- if (not node == node_current):
+ if node != node_current:
test = instance in n_img.instances
_ErrorIf(test, self.EINSTANCEWRONGNODE, instance,
"instance should not run on node %s", node)
for idx, (success, status) in enumerate(disks)]
for nname, success, bdev_status, idx in diskdata:
- _ErrorIf(instanceconfig.admin_up and not success,
+ # the 'ghost node' construction in Exec() ensures that we have a
+ # node here
+ snode = node_image[nname]
+ bad_snode = snode.ghost or snode.offline
+ _ErrorIf(instanceconfig.admin_up and not success and not bad_snode,
self.EINSTANCEFAULTYDISK, instance,
"couldn't retrieve status for disk/%s on %s: %s",
idx, nname, bdev_status)
instances it was primary for.
"""
+ cluster_info = self.cfg.GetClusterInfo()
for node, n_img in node_image.items():
# This code checks that every node which is now listed as
# secondary has enough memory to host all instances it is
# WARNING: we currently take into account down instances as well
# as up ones, considering that even if they're down someone
# might want to start them even in the event of a node failure.
+ if n_img.offline:
+ # we're skipping offline nodes from the N+1 warning, since
+ # most likely we don't have good memory infromation from them;
+ # we already list instances living on such nodes, and that's
+ # enough warning
+ continue
for prinode, instances in n_img.sbp.items():
needed_mem = 0
for instance in instances:
- bep = self.cfg.GetClusterInfo().FillBE(instance_cfg[instance])
+ bep = cluster_info.FillBE(instance_cfg[instance])
if bep[constants.BE_AUTO_BALANCE]:
needed_mem += bep[constants.BE_MEMORY]
test = n_img.mfree < needed_mem
self.ENODERPC, pnode, "instance %s, connection to"
" primary node failed", instance)
- if pnode_img.offline:
- inst_nodes_offline.append(pnode)
+ _ErrorIf(pnode_img.offline, self.EINSTANCEBADNODE, instance,
+ "instance lives on offline node %s", inst_config.primary_node)
# If the instance is non-redundant we cannot survive losing its primary
# node, so we are not N+1 compliant. On the other hand we have no disk
# warn that the instance lives on offline nodes
_ErrorIf(inst_nodes_offline, self.EINSTANCEBADNODE, instance,
- "instance lives on offline node(s) %s",
+ "instance has offline secondary node(s) %s",
utils.CommaJoin(inst_nodes_offline))
# ... or ghost/non-vm_capable nodes
for node in inst_config.all_nodes:
newl = [v[2].Copy() for v in dskl]
for dsk in newl:
self.cfg.SetDiskID(dsk, node)
- result = self.rpc.call_blockdev_getsizes(node, newl)
+ result = self.rpc.call_blockdev_getsize(node, newl)
if result.fail_msg:
- self.LogWarning("Failure in blockdev_getsizes call to node"
+ self.LogWarning("Failure in blockdev_getsize call to node"
" %s, ignoring", node)
continue
- if len(result.data) != len(dskl):
+ if len(result.payload) != len(dskl):
+ logging.warning("Invalid result from node %s: len(dksl)=%d,"
+ " result.payload=%s", node, len(dskl), result.payload)
self.LogWarning("Invalid result from node %s, ignoring node results",
node)
continue
- for ((instance, idx, disk), size) in zip(dskl, result.data):
+ for ((instance, idx, disk), size) in zip(dskl, result.payload):
if size is None:
self.LogWarning("Disk %d of instance %s did not return size"
" information, ignoring", idx, instance.name)
"""
REG_BGL = False
+ _SKIP_MASTER = (constants.OOB_POWER_OFF, constants.OOB_POWER_CYCLE)
def CheckPrereq(self):
"""Check prerequisites.
"""
self.nodes = []
+ self.master_node = self.cfg.GetMasterNode()
+
+ if self.op.node_names:
+ if self.op.command in self._SKIP_MASTER:
+ if self.master_node in self.op.node_names:
+ master_node_obj = self.cfg.GetNodeInfo(self.master_node)
+ master_oob_handler = _SupportsOob(self.cfg, master_node_obj)
+
+ if master_oob_handler:
+ additional_text = ("Run '%s %s %s' if you want to operate on the"
+ " master regardless") % (master_oob_handler,
+ self.op.command,
+ self.master_node)
+ else:
+ additional_text = "The master node does not support out-of-band"
+
+ raise errors.OpPrereqError(("Operating on the master node %s is not"
+ " allowed for %s\n%s") %
+ (self.master_node, self.op.command,
+ additional_text), errors.ECODE_INVAL)
+ else:
+ self.op.node_names = self.cfg.GetNodeList()
+ if self.op.command in self._SKIP_MASTER:
+ self.op.node_names.remove(self.master_node)
+
+ if self.op.command in self._SKIP_MASTER:
+ assert self.master_node not in self.op.node_names
+
for node_name in self.op.node_names:
node = self.cfg.GetNodeInfo(node_name)
else:
self.nodes.append(node)
- if (self.op.command == constants.OOB_POWER_OFF and not node.offline):
+ if (not self.op.ignore_status and
+ (self.op.command == constants.OOB_POWER_OFF and not node.offline)):
raise errors.OpPrereqError(("Cannot power off node %s because it is"
" not marked offline") % node_name,
errors.ECODE_STATE)
if self.op.node_names:
self.op.node_names = [_ExpandNodeName(self.cfg, name)
for name in self.op.node_names]
+ lock_names = self.op.node_names
else:
- self.op.node_names = self.cfg.GetNodeList()
+ lock_names = locking.ALL_SET
self.needed_locks = {
- locking.LEVEL_NODE: self.op.node_names,
+ locking.LEVEL_NODE: lock_names,
}
def Exec(self, feedback_fn):
"""Execute OOB and return result if we expect any.
"""
- master_node = self.cfg.GetMasterNode()
+ master_node = self.master_node
ret = []
for node in self.nodes:
# Gather data as requested
if query.NQ_LIVE in self.requested_data:
- node_data = lu.rpc.call_node_info(nodenames, lu.cfg.GetVGName(),
+ # filter out non-vm_capable nodes
+ toquery_nodes = [name for name in nodenames if all_info[name].vm_capable]
+
+ node_data = lu.rpc.call_node_info(toquery_nodes, lu.cfg.GetVGName(),
lu.cfg.GetHypervisorType())
live_data = dict((name, nresult.payload)
for (name, nresult) in node_data.items()
REQ_BGL = False
def CheckArguments(self):
- self.nq = _NodeQuery(self.op.names, self.op.output_fields,
- self.op.use_locking)
+ self.nq = _NodeQuery(qlang.MakeSimpleFilter("name", self.op.names),
+ self.op.output_fields, self.op.use_locking)
def ExpandNames(self):
self.nq.ExpandNames(self)
def CheckArguments(self):
qcls = _GetQueryImplementation(self.op.what)
- names = qlang.ReadSimpleFilter("name", self.op.filter)
- self.impl = qcls(names, self.op.fields, False)
+ self.impl = qcls(self.op.filter, self.op.fields, False)
def ExpandNames(self):
self.impl.ExpandNames(self)
REQ_BGL = False
def CheckArguments(self):
- self.iq = _InstanceQuery(self.op.names, self.op.output_fields,
- self.op.use_locking)
+ self.iq = _InstanceQuery(qlang.MakeSimpleFilter("name", self.op.names),
+ self.op.output_fields, self.op.use_locking)
def ExpandNames(self):
self.iq.ExpandNames(self)
return req_size_dict[disk_template]
+def _FilterVmNodes(lu, nodenames):
+ """Filters out non-vm_capable nodes from a list.
+
+ @type lu: L{LogicalUnit}
+ @param lu: the logical unit for which we check
+ @type nodenames: list
+ @param nodenames: the list of nodes on which we should check
+ @rtype: list
+ @return: the list of vm-capable nodes
+
+ """
+ vm_nodes = frozenset(lu.cfg.GetNonVmCapableNodeList())
+ return [name for name in nodenames if name not in vm_nodes]
+
+
def _CheckHVParams(lu, nodenames, hvname, hvparams):
"""Hypervisor parameter validation.
@raise errors.OpPrereqError: if the parameters are not valid
"""
+ nodenames = _FilterVmNodes(lu, nodenames)
hvinfo = lu.rpc.call_hypervisor_validate_params(nodenames,
hvname,
hvparams)
@raise errors.OpPrereqError: if the parameters are not valid
"""
+ nodenames = _FilterVmNodes(lu, nodenames)
result = lu.rpc.call_os_validate(required, nodenames, osname,
[constants.OS_VALIDATE_PARAMETERS],
osparams)
if instance.name not in node_insts.payload:
if instance.admin_up:
- state = "ERROR_down"
+ state = constants.INSTST_ERRORDOWN
else:
- state = "ADMIN_down"
+ state = constants.INSTST_ADMINDOWN
raise errors.OpExecError("Instance %s is not running (state %s)" %
(instance.name, state))
class _GroupQuery(_QueryBase):
-
FIELDS = query.GROUP_FIELDS
def ExpandNames(self, lu):
REQ_BGL = False
def CheckArguments(self):
- self.gq = _GroupQuery(self.op.names, self.op.output_fields, False)
+ self.gq = _GroupQuery(qlang.MakeSimpleFilter("name", self.op.names),
+ self.op.output_fields, False)
def ExpandNames(self):
self.gq.ExpandNames(self)
def ExpandNames(self):
# This raises errors.OpPrereqError on its own:
- self.group_uuid = self.cfg.LookupNodeGroup(self.op.old_name)
+ self.group_uuid = self.cfg.LookupNodeGroup(self.op.group_name)
self.needed_locks = {
locking.LEVEL_NODEGROUP: [self.group_uuid],
def CheckPrereq(self):
"""Check prerequisites.
- This checks that the given old_name exists as a node group, and that
- new_name doesn't.
+ Ensures requested new name is not yet used.
"""
try:
"""
env = {
- "OLD_NAME": self.op.old_name,
+ "OLD_NAME": self.op.group_name,
"NEW_NAME": self.op.new_name,
}
if group is None:
raise errors.OpExecError("Could not retrieve group '%s' (UUID: %s)" %
- (self.op.old_name, self.group_uuid))
+ (self.op.group_name, self.group_uuid))
group.name = self.op.new_name
self.cfg.Update(group, feedback_fn)
"i_pri_up_memory": i_p_up_mem,
}
pnr_dyn.update(node_results[nname])
-
- node_results[nname] = pnr_dyn
+ node_results[nname] = pnr_dyn
return node_results