Revision fed67843
b/lib/client/gnt_node.py | ||
---|---|---|
114 | 114 |
help=("Ignore the Node(s) offline status" |
115 | 115 |
" (potentially DANGEROUS)")) |
116 | 116 |
|
117 |
FORCE_MASTER_OPT = cli_option("--force-master", default=False, |
|
118 |
action="store_true", dest="force_master", |
|
119 |
help=("Operate on the master node too" |
|
120 |
" (potentially DANGEROUS)")) |
|
121 |
|
|
122 | 117 |
OOB_TIMEOUT_OPT = cli_option("--oob-timeout", dest="oob_timeout", type="int", |
123 | 118 |
default=constants.OOB_TIMEOUT, |
124 | 119 |
help="Maximum time to wait for out-of-band helper") |
125 | 120 |
|
126 |
|
|
127 | 121 |
def ConvertStorageType(user_storage_type): |
128 | 122 |
"""Converts a user storage type to its internal name. |
129 | 123 |
|
... | ... | |
495 | 489 |
@return: the desired exit code |
496 | 490 |
|
497 | 491 |
""" |
498 |
client = GetClient() |
|
499 | 492 |
command = args.pop(0) |
500 | 493 |
|
501 | 494 |
if opts.no_headers: |
... | ... | |
507 | 500 |
ToStderr("power subcommand %s not supported." % command) |
508 | 501 |
return constants.EXIT_FAILURE |
509 | 502 |
|
510 |
nodes = [node for (node, ) in client.QueryNodes(args, ["name"], False)] |
|
511 | 503 |
oob_command = "power-%s" % command |
512 | 504 |
|
513 | 505 |
if oob_command in _OOB_COMMAND_ASK: |
514 |
if not args and not opts.show_all: |
|
515 |
ToStderr("Please provide at least one node or use --all for this command" |
|
516 |
" as this is a potentially harmful command") |
|
517 |
return constants.EXIT_FAILURE |
|
518 |
elif args and opts.show_all: |
|
519 |
ToStderr("Please provide either nodes or use --all, can not use both at" |
|
520 |
" the same time") |
|
506 |
if not args: |
|
507 |
ToStderr("Please provide at least one node for this command") |
|
521 | 508 |
return constants.EXIT_FAILURE |
522 |
elif not opts.force and not ConfirmOperation(nodes, "nodes",
|
|
509 |
elif not opts.force and not ConfirmOperation(args, "nodes",
|
|
523 | 510 |
"power %s" % command): |
524 | 511 |
return constants.EXIT_FAILURE |
512 |
assert len(args) > 0 |
|
525 | 513 |
|
526 | 514 |
opcodelist = [] |
527 | 515 |
if not opts.ignore_status and oob_command == constants.OOB_POWER_OFF: |
528 | 516 |
# TODO: This is a little ugly as we can't catch and revert |
529 |
for node in nodes:
|
|
517 |
for node in args:
|
|
530 | 518 |
opcodelist.append(opcodes.OpNodeSetParams(node_name=node, offline=True, |
531 | 519 |
auto_promote=opts.auto_promote)) |
532 | 520 |
|
533 |
opcodelist.append(opcodes.OpOobCommand(node_names=nodes,
|
|
521 |
opcodelist.append(opcodes.OpOobCommand(node_names=args,
|
|
534 | 522 |
command=oob_command, |
535 | 523 |
ignore_status=opts.ignore_status, |
536 |
force_master=opts.force_master, |
|
537 | 524 |
timeout=opts.oob_timeout)) |
538 | 525 |
|
539 | 526 |
cli.SetGenericOpcodeOpts(opcodelist, opts) |
... | ... | |
870 | 857 |
[ArgChoice(min=1, max=1, choices=_LIST_POWER_COMMANDS), |
871 | 858 |
ArgNode()], |
872 | 859 |
[SUBMIT_OPT, AUTO_PROMOTE_OPT, PRIORITY_OPT, IGNORE_STATUS_OPT, |
873 |
FORCE_MASTER_OPT, FORCE_OPT, NOHDR_OPT, SEP_OPT, ALL_OPT, |
|
874 |
OOB_TIMEOUT_OPT], |
|
860 |
FORCE_OPT, NOHDR_OPT, SEP_OPT, OOB_TIMEOUT_OPT], |
|
875 | 861 |
"on|off|cycle|status [nodes...]", |
876 | 862 |
"Change power state of node by calling out-of-band helper."), |
877 | 863 |
'remove': ( |
b/lib/cmdlib.py | ||
---|---|---|
3216 | 3216 |
|
3217 | 3217 |
""" |
3218 | 3218 |
REG_BGL = False |
3219 |
_SKIP_MASTER = (constants.OOB_POWER_OFF, constants.OOB_POWER_CYCLE) |
|
3219 | 3220 |
|
3220 | 3221 |
def CheckPrereq(self): |
3221 | 3222 |
"""Check prerequisites. |
... | ... | |
3230 | 3231 |
self.nodes = [] |
3231 | 3232 |
self.master_node = self.cfg.GetMasterNode() |
3232 | 3233 |
|
3233 |
if self.op.command in (constants.OOB_POWER_OFF, constants.OOB_POWER_CYCLE): |
|
3234 |
# This does two things, it checks if master is in the list and if so and |
|
3235 |
# force_master is set it puts it to the end so the master is done last |
|
3236 |
try: |
|
3234 |
if self.op.node_names: |
|
3235 |
if self.op.command in self._SKIP_MASTER: |
|
3236 |
if self.master_node in self.op.node_names: |
|
3237 |
master_node_obj = self.cfg.GetNodeInfo(self.master_node) |
|
3238 |
master_oob_handler = _SupportsOob(self.cfg, master_node_obj) |
|
3239 |
|
|
3240 |
if master_oob_handler: |
|
3241 |
additional_text = ("Run '%s %s %s' if you want to operate on the" |
|
3242 |
" master regardless") % (master_oob_handler, |
|
3243 |
self.op.command, |
|
3244 |
self.master_node) |
|
3245 |
else: |
|
3246 |
additional_text = "The master node does not support out-of-band" |
|
3247 |
|
|
3248 |
raise errors.OpPrereqError(("Operating on the master node %s is not" |
|
3249 |
" allowed for %s\n%s") % |
|
3250 |
(self.master_node, self.op.command, |
|
3251 |
additional_text), errors.ECODE_INVAL) |
|
3252 |
else: |
|
3253 |
self.op.node_names = self.cfg.GetNodeList() |
|
3254 |
if self.op.command in self._SKIP_MASTER: |
|
3237 | 3255 |
self.op.node_names.remove(self.master_node) |
3238 |
except ValueError: |
|
3239 |
pass |
|
3240 |
else: |
|
3241 |
if self.op.force_master: |
|
3242 |
self.op.node_names.append(self.master_node) |
|
3243 |
else: |
|
3244 |
self.LogWarning("Master %s was skipped, use the force master" |
|
3245 |
" option to operate on the master too", |
|
3246 |
self.master_node) |
|
3247 |
if not self.op.node_names: |
|
3248 |
raise errors.OpPrereqError("No nodes left to operate on, aborting", |
|
3249 |
errors.ECODE_INVAL) |
|
3250 | 3256 |
|
3251 |
assert (self.master_node not in self.op.node_names or
|
|
3252 |
self.op.node_names[-1] == self.master_node)
|
|
3257 |
if self.op.command in self._SKIP_MASTER:
|
|
3258 |
assert self.master_node not in self.op.node_names
|
|
3253 | 3259 |
|
3254 | 3260 |
for node_name in self.op.node_names: |
3255 | 3261 |
node = self.cfg.GetNodeInfo(node_name) |
... | ... | |
3273 | 3279 |
if self.op.node_names: |
3274 | 3280 |
self.op.node_names = [_ExpandNodeName(self.cfg, name) |
3275 | 3281 |
for name in self.op.node_names] |
3282 |
lock_names = self.op.node_names |
|
3276 | 3283 |
else: |
3277 |
self.op.node_names = self.cfg.GetNodeList()
|
|
3284 |
lock_names = locking.ALL_SET
|
|
3278 | 3285 |
|
3279 | 3286 |
self.needed_locks = { |
3280 |
locking.LEVEL_NODE: self.op.node_names,
|
|
3287 |
locking.LEVEL_NODE: lock_names,
|
|
3281 | 3288 |
} |
3282 | 3289 |
|
3283 | 3290 |
def Exec(self, feedback_fn): |
b/lib/opcodes.py | ||
---|---|---|
658 | 658 |
("command", None, ht.TElemOf(constants.OOB_COMMANDS), None), |
659 | 659 |
("timeout", constants.OOB_TIMEOUT, ht.TInt, None), |
660 | 660 |
("ignore_status", False, ht.TBool, None), |
661 |
("force_master", False, ht.TBool, None), |
|
662 | 661 |
] |
663 | 662 |
|
664 | 663 |
|
b/qa/qa_node.py | ||
---|---|---|
253 | 253 |
node = qa_config.AcquireNode(exclude=master) |
254 | 254 |
|
255 | 255 |
master_name = master["primary"] |
256 |
full_master_name = qa_utils.ResolveNodeName(master) |
|
257 | 256 |
node_name = node["primary"] |
258 | 257 |
full_node_name = qa_utils.ResolveNodeName(node) |
259 | 258 |
|
... | ... | |
276 | 275 |
# Power off on master without options should fail |
277 | 276 |
AssertCommand(["gnt-node", "power", "-f", "off", master_name], fail=True) |
278 | 277 |
# With force master it should still fail |
279 |
AssertCommand(["gnt-node", "power", "-f", "--force-master", "off", |
|
280 |
master_name], fail=True) |
|
281 | 278 |
AssertCommand(["gnt-node", "power", "-f", "--ignore-status", "off", |
282 | 279 |
master_name], |
283 | 280 |
fail=True) |
284 |
# This should work again |
|
285 |
AssertCommand(["gnt-node", "power", "-f", "--ignore-status", |
|
286 |
"--force-master", "off", master_name]) |
|
287 |
_AssertOobCall(verify_path, "power-off %s" % full_master_name) |
|
288 | 281 |
|
289 | 282 |
# Verify we can't transform back to online when not yet powered on |
290 | 283 |
AssertCommand(["gnt-node", "modify", "-O", "no", node_name], |
... | ... | |
400 | 393 |
AssertCommand(["gnt-node", "modify", "--node-parameters", |
401 | 394 |
"oob_program=default", node_name]) |
402 | 395 |
AssertCommand(["rm", "-f", oob_path2, verify_path2]) |
403 |
|
|
404 |
verify_path3 = qa_utils.UploadData(master["primary"], "") |
|
405 |
oob_script = ("#!/bin/bash\n" |
|
406 |
"echo \"$@\" >> %s\n") % verify_path3 |
|
407 |
oob_path3 = qa_utils.UploadData(master["primary"], oob_script, mode=0700) |
|
408 |
|
|
409 |
AssertCommand(["gnt-cluster", "modify", "--node-parameters", |
|
410 |
"oob_program=%s" % oob_path3]) |
|
411 |
|
|
412 |
non_master_nodes = [] |
|
413 |
for node in qa_config.get('nodes'): |
|
414 |
if node != master: |
|
415 |
non_master_nodes.append(qa_utils.ResolveNodeName(node)) |
|
416 |
|
|
417 |
try: |
|
418 |
# Without the --force-master it should not have the master in it |
|
419 |
verify_content = ["power-cycle %s" % name for name in non_master_nodes] |
|
420 |
AssertCommand(["gnt-node", "power", "-f", "--all", "cycle"]) |
|
421 |
_AssertOobCall(verify_path3, "\n".join(verify_content)) |
|
422 |
|
|
423 |
# Empty file |
|
424 |
_UpdateOobFile(verify_path3, "") |
|
425 |
# With the --force-master it should have the master at last position |
|
426 |
verify_content.append("power-cycle %s" % full_master_name) |
|
427 |
AssertCommand(["gnt-node", "power", "--force-master", "-f", "--all", |
|
428 |
"cycle"]) |
|
429 |
_AssertOobCall(verify_path3, "\n".join(verify_content)) |
|
430 |
|
|
431 |
# Empty file |
|
432 |
_UpdateOobFile(verify_path3, "") |
|
433 |
# With master as first argument it should still be called last |
|
434 |
cmd = ["gnt-node", "power", "--force-master", "-f", "cycle", master_name] |
|
435 |
cmd.extend(non_master_nodes) |
|
436 |
AssertCommand(cmd) |
|
437 |
_AssertOobCall(verify_path3, "\n".join(verify_content)) |
|
438 |
finally: |
|
439 |
AssertCommand(["rm", "-f", oob_path3, verify_path3]) |
|
440 | 396 |
finally: |
441 | 397 |
AssertCommand(["gnt-cluster", "modify", "--node-parameters", |
442 | 398 |
"oob_program="]) |
Also available in: Unified diff