Commit b04808ea authored by René Nussbaumer's avatar René Nussbaumer
Browse files

Modify LUOobCommand to support multiple nodes



This will change the result of this LU to a query like result. A list of
tuples with information about the state of the data.

It also includes the modification to the commands calling this opcode.
Signed-off-by: default avatarRené Nussbaumer <rn@google.com>
Reviewed-by: default avatarIustin Pop <iustin@google.com>
parent e18c6c47
...@@ -491,7 +491,8 @@ def PowerNode(opts, args): ...@@ -491,7 +491,8 @@ def PowerNode(opts, args):
opcodelist.append(opcodes.OpNodeSetParams(node_name=node, offline=True, opcodelist.append(opcodes.OpNodeSetParams(node_name=node, offline=True,
auto_promote=opts.auto_promote)) auto_promote=opts.auto_promote))
opcodelist.append(opcodes.OpOobCommand(node_name=node, command=oob_command)) opcodelist.append(opcodes.OpOobCommand(node_names=[node],
command=oob_command))
cli.SetGenericOpcodeOpts(opcodelist, opts) cli.SetGenericOpcodeOpts(opcodelist, opts)
...@@ -502,13 +503,22 @@ def PowerNode(opts, args): ...@@ -502,13 +503,22 @@ def PowerNode(opts, args):
result = cli.PollJob(job_id)[-1] result = cli.PollJob(job_id)[-1]
if result: if result:
(_, data_tuple) = result[0]
if data_tuple[0] != constants.RS_NORMAL:
if data_tuple[0] == constants.RS_UNAVAIL:
result = "OOB is not supported"
else:
result = "RPC failed, look out for warning in the output"
ToStderr(result)
return constants.EXIT_FAILURE
else:
if oob_command == constants.OOB_POWER_STATUS: if oob_command == constants.OOB_POWER_STATUS:
text = "The machine is %spowered" text = "The machine is %spowered"
if result[constants.OOB_POWER_STATUS_POWERED]: if data_tuple[1][constants.OOB_POWER_STATUS_POWERED]:
result = text % "" result = text % ""
else: else:
result = text % "not " result = text % "not "
ToStderr(result) ToStdout(result)
return constants.EXIT_SUCCESS return constants.EXIT_SUCCESS
......
...@@ -3192,31 +3192,33 @@ class LUOobCommand(NoHooksLU): ...@@ -3192,31 +3192,33 @@ class LUOobCommand(NoHooksLU):
Any errors are signaled by raising errors.OpPrereqError. Any errors are signaled by raising errors.OpPrereqError.
""" """
self.op.node_name = _ExpandNodeName(self.cfg, self.op.node_name) self.nodes = []
node = self.cfg.GetNodeInfo(self.op.node_name) for node_name in self.op.node_names:
node = self.cfg.GetNodeInfo(node_name)
if node is None: if node is None:
raise errors.OpPrereqError("Node %s not found" % self.op.node_name) raise errors.OpPrereqError("Node %s not found" % node_name,
errors.ECODE_NOENT)
self.oob_program = _SupportsOob(self.cfg, node) else:
self.nodes.append(node)
if not self.oob_program:
raise errors.OpPrereqError("OOB is not supported for node %s" %
self.op.node_name)
if self.op.command == constants.OOB_POWER_OFF and not node.offline: if (self.op.command == constants.OOB_POWER_OFF and not node.offline):
raise errors.OpPrereqError(("Cannot power off node %s because it is" raise errors.OpPrereqError(("Cannot power off node %s because it is"
" not marked offline") % self.op.node_name) " not marked offline") % node_name,
errors.ECODE_STATE)
self.node = node
def ExpandNames(self): def ExpandNames(self):
"""Gather locks we need. """Gather locks we need.
""" """
node_name = _ExpandNodeName(self.cfg, self.op.node_name) if self.op.node_names:
self.op.node_names = [_ExpandNodeName(self.cfg, name)
for name in self.op.node_names]
else:
self.op.node_names = self.cfg.GetNodeList()
self.needed_locks = { self.needed_locks = {
locking.LEVEL_NODE: [node_name], locking.LEVEL_NODE: self.op.node_names,
} }
def Exec(self, feedback_fn): def Exec(self, feedback_fn):
...@@ -3224,25 +3226,45 @@ class LUOobCommand(NoHooksLU): ...@@ -3224,25 +3226,45 @@ class LUOobCommand(NoHooksLU):
""" """
master_node = self.cfg.GetMasterNode() master_node = self.cfg.GetMasterNode()
node = self.node ret = []
for node in self.nodes:
node_entry = [(constants.RS_NORMAL, node.name)]
ret.append(node_entry)
oob_program = _SupportsOob(self.cfg, node)
if not oob_program:
node_entry.append((constants.RS_UNAVAIL, None))
continue
logging.info("Executing out-of-band command '%s' using '%s' on %s", logging.info("Executing out-of-band command '%s' using '%s' on %s",
self.op.command, self.oob_program, self.op.node_name) self.op.command, oob_program, node.name)
result = self.rpc.call_run_oob(master_node, self.oob_program, result = self.rpc.call_run_oob(master_node, oob_program,
self.op.command, self.op.node_name, self.op.command, node.name,
self.op.timeout) self.op.timeout)
result.Raise("An error occurred on execution of OOB helper") result.Raise("An error occurred on execution of OOB helper")
if result.fail_msg:
self.LogWarning("On node '%s' out-of-band RPC failed with: %s",
node.name, result.fail_msg)
node_entry.append((constants.RS_NODATA, None))
else:
try:
self._CheckPayload(result) self._CheckPayload(result)
except errors.OpExecError, err:
self.LogWarning("The payload returned by '%s' is not valid: %s",
node.name, err)
node_entry.append((constants.RS_NODATA, None))
else:
if self.op.command == constants.OOB_HEALTH: if self.op.command == constants.OOB_HEALTH:
# For health we should log important events # For health we should log important events
for item, status in result.payload: for item, status in result.payload:
if status in [constants.OOB_STATUS_WARNING, if status in [constants.OOB_STATUS_WARNING,
constants.OOB_STATUS_CRITICAL]: constants.OOB_STATUS_CRITICAL]:
logging.warning("On node '%s' item '%s' has status '%s'", self.LogWarning("On node '%s' item '%s' has status '%s'",
self.op.node_name, item, status) node.name, item, status)
if self.op.command == constants.OOB_POWER_ON: if self.op.command == constants.OOB_POWER_ON:
node.powered = True node.powered = True
...@@ -3250,14 +3272,19 @@ class LUOobCommand(NoHooksLU): ...@@ -3250,14 +3272,19 @@ class LUOobCommand(NoHooksLU):
node.powered = False node.powered = False
elif self.op.command == constants.OOB_POWER_STATUS: elif self.op.command == constants.OOB_POWER_STATUS:
powered = result.payload[constants.OOB_POWER_STATUS_POWERED] powered = result.payload[constants.OOB_POWER_STATUS_POWERED]
if powered != self.node.powered: if powered != node.powered:
logging.warning(("Recorded power state (%s) of node '%s' does not match" logging.warning(("Recorded power state (%s) of node '%s' does not"
" actual power state (%s)"), node.powered, " match actual power state (%s)"), node.powered,
self.op.node_name, powered) node.name, powered)
# For configuration changing commands we should update the node
if self.op.command in (constants.OOB_POWER_ON,
constants.OOB_POWER_OFF):
self.cfg.Update(node, feedback_fn) self.cfg.Update(node, feedback_fn)
return result.payload node_entry.append((constants.RS_NORMAL, result.payload))
return ret
def _CheckPayload(self, result): def _CheckPayload(self, result):
"""Checks if the payload is valid. """Checks if the payload is valid.
......
...@@ -590,7 +590,7 @@ class OpQueryFields(OpCode): ...@@ -590,7 +590,7 @@ class OpQueryFields(OpCode):
class OpOobCommand(OpCode): class OpOobCommand(OpCode):
"""Interact with OOB.""" """Interact with OOB."""
OP_PARAMS = [ OP_PARAMS = [
_PNodeName, ("node_names", ht.EmptyList, ht.TListOf(ht.TNonEmptyString)),
("command", None, ht.TElemOf(constants.OOB_COMMANDS)), ("command", None, ht.TElemOf(constants.OOB_COMMANDS)),
("timeout", constants.OOB_TIMEOUT, ht.TInt), ("timeout", constants.OOB_TIMEOUT, ht.TInt),
] ]
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment