Revision c832b6c8
b/lib/client/gnt_node.py | ||
---|---|---|
100 | 100 |
_MODIFIABLE_STORAGE_TYPES = constants.MODIFIABLE_STORAGE_FIELDS.keys() |
101 | 101 |
|
102 | 102 |
|
103 |
_OOB_COMMAND_ASK = frozenset([constants.OOB_POWER_OFF, |
|
104 |
constants.OOB_POWER_CYCLE]) |
|
105 |
|
|
106 |
|
|
103 | 107 |
NONODE_SETUP_OPT = cli_option("--no-node-setup", default=True, |
104 | 108 |
action="store_false", dest="node_setup", |
105 | 109 |
help=("Do not make initial SSH setup on remote" |
... | ... | |
487 | 491 |
@return: the desired exit code |
488 | 492 |
|
489 | 493 |
""" |
490 |
command = args[0] |
|
491 |
node = args[1] |
|
494 |
client = GetClient() |
|
495 |
command = args.pop(0) |
|
496 |
|
|
497 |
if opts.no_headers: |
|
498 |
headers = None |
|
499 |
else: |
|
500 |
headers = {"node": "Node", "status": "Status"} |
|
492 | 501 |
|
493 | 502 |
if command not in _LIST_POWER_COMMANDS: |
494 | 503 |
ToStderr("power subcommand %s not supported." % command) |
495 | 504 |
return constants.EXIT_FAILURE |
496 | 505 |
|
506 |
nodes = [node for (node, ) in client.QueryNodes(args, ["name"], False)] |
|
497 | 507 |
oob_command = "power-%s" % command |
498 | 508 |
|
509 |
if oob_command in _OOB_COMMAND_ASK: |
|
510 |
if not args and not opts.show_all: |
|
511 |
ToStderr("Please provide at least one node or use --all for this command" |
|
512 |
" as this is a potentially harmful command") |
|
513 |
return constants.EXIT_FAILURE |
|
514 |
elif args and opts.show_all: |
|
515 |
ToStderr("Please provide either nodes or use --all, can not use both at" |
|
516 |
" the same time") |
|
517 |
return constants.EXIT_FAILURE |
|
518 |
elif not opts.force and not ConfirmOperation(nodes, "nodes", |
|
519 |
"power %s" % command): |
|
520 |
return constants.EXIT_FAILURE |
|
521 |
|
|
499 | 522 |
opcodelist = [] |
500 | 523 |
if not opts.ignore_status and oob_command == constants.OOB_POWER_OFF: |
501 |
opcodelist.append(opcodes.OpNodeSetParams(node_name=node, offline=True, |
|
502 |
auto_promote=opts.auto_promote)) |
|
524 |
# TODO: This is a little ugly as we can't catch and revert |
|
525 |
for node in nodes: |
|
526 |
opcodelist.append(opcodes.OpNodeSetParams(node_name=node, offline=True, |
|
527 |
auto_promote=opts.auto_promote)) |
|
503 | 528 |
|
504 |
opcodelist.append(opcodes.OpOobCommand(node_names=[node],
|
|
529 |
opcodelist.append(opcodes.OpOobCommand(node_names=nodes,
|
|
505 | 530 |
command=oob_command, |
506 | 531 |
ignore_status=opts.ignore_status, |
507 | 532 |
force_master=opts.force_master)) |
... | ... | |
514 | 539 |
# If it fails PollJob gives us the error message in it |
515 | 540 |
result = cli.PollJob(job_id)[-1] |
516 | 541 |
|
517 |
if result: |
|
518 |
(_, data_tuple) = result[0] |
|
519 |
if data_tuple[0] != constants.RS_NORMAL: |
|
520 |
if data_tuple[0] == constants.RS_UNAVAIL: |
|
521 |
result = "OOB is not supported" |
|
522 |
else: |
|
523 |
result = "RPC failed, look out for warning in the output" |
|
524 |
ToStderr(result) |
|
525 |
return constants.EXIT_FAILURE |
|
526 |
else: |
|
542 |
errs = 0 |
|
543 |
data = [] |
|
544 |
for node_result in result: |
|
545 |
(node_tuple, data_tuple) = node_result |
|
546 |
(_, node_name) = node_tuple |
|
547 |
(data_status, data_node) = data_tuple |
|
548 |
if data_status == constants.RS_NORMAL: |
|
527 | 549 |
if oob_command == constants.OOB_POWER_STATUS: |
528 |
text = "The machine is %spowered" |
|
529 |
if data_tuple[1][constants.OOB_POWER_STATUS_POWERED]: |
|
530 |
result = text % "" |
|
550 |
if data_node[constants.OOB_POWER_STATUS_POWERED]: |
|
551 |
text = "powered" |
|
531 | 552 |
else: |
532 |
result = text % "not " |
|
533 |
ToStdout(result) |
|
553 |
text = "unpowered" |
|
554 |
data.append([node_name, text]) |
|
555 |
else: |
|
556 |
# We don't expect data here, so we just say, it was successfully invoked |
|
557 |
data.append([node_name, "invoked"]) |
|
558 |
else: |
|
559 |
errs += 1 |
|
560 |
data.append([node_name, cli.FormatResultError(data_status)]) |
|
561 |
|
|
562 |
data = GenerateTable(separator=opts.separator, headers=headers, |
|
563 |
fields=["node", "status"], data=data) |
|
564 |
|
|
565 |
for line in data: |
|
566 |
ToStdout(line) |
|
534 | 567 |
|
535 |
return constants.EXIT_SUCCESS |
|
568 |
if errs: |
|
569 |
return constants.EXIT_FAILURE |
|
570 |
else: |
|
571 |
return constants.EXIT_SUCCESS |
|
536 | 572 |
|
537 | 573 |
|
538 | 574 |
def Health(opts, args): |
... | ... | |
826 | 862 |
'power': ( |
827 | 863 |
PowerNode, |
828 | 864 |
[ArgChoice(min=1, max=1, choices=_LIST_POWER_COMMANDS), |
829 |
ArgNode(min=1, max=1)],
|
|
865 |
ArgNode()], |
|
830 | 866 |
[SUBMIT_OPT, AUTO_PROMOTE_OPT, PRIORITY_OPT, IGNORE_STATUS_OPT, |
831 |
FORCE_MASTER_OPT], |
|
832 |
"on|off|cycle|status <node>",
|
|
867 |
FORCE_MASTER_OPT, FORCE_OPT, NOHDR_OPT, SEP_OPT, ALL_OPT],
|
|
868 |
"on|off|cycle|status [nodes...]",
|
|
833 | 869 |
"Change power state of node by calling out-of-band helper."), |
834 | 870 |
'remove': ( |
835 | 871 |
RemoveNode, ARGS_ONE_NODE, [DRY_RUN_OPT, PRIORITY_OPT], |
b/qa/qa_node.py | ||
---|---|---|
240 | 240 |
master = qa_config.GetMasterNode() |
241 | 241 |
|
242 | 242 |
verify_output_cmd = utils.ShellQuoteArgs(["cat", verify_path]) |
243 |
output = qa_utils.GetCommandOutput(master["primary"], verify_output_cmd) |
|
243 |
output = qa_utils.GetCommandOutput(master["primary"], verify_output_cmd, |
|
244 |
tty=False) |
|
244 | 245 |
|
245 | 246 |
AssertEqual(expected_args, output.strip()) |
246 | 247 |
|
... | ... | |
269 | 270 |
AssertCommand(["gnt-node", "power", "on", node_name]) |
270 | 271 |
_AssertOobCall(verify_path, "power-on %s" % full_node_name) |
271 | 272 |
|
272 |
AssertCommand(["gnt-node", "power", "off", node_name]) |
|
273 |
AssertCommand(["gnt-node", "power", "-f", "off", node_name])
|
|
273 | 274 |
_AssertOobCall(verify_path, "power-off %s" % full_node_name) |
274 | 275 |
|
275 | 276 |
# Power off on master without options should fail |
276 |
AssertCommand(["gnt-node", "power", "off", master_name], fail=True) |
|
277 |
AssertCommand(["gnt-node", "power", "-f", "off", master_name], fail=True)
|
|
277 | 278 |
# With force master it should still fail |
278 |
AssertCommand(["gnt-node", "power", "--force-master", "off", master_name], |
|
279 |
fail=True) |
|
280 |
AssertCommand(["gnt-node", "power", "--ignore-status", "off", master_name], |
|
279 |
AssertCommand(["gnt-node", "power", "-f", "--force-master", "off", |
|
280 |
master_name], fail=True) |
|
281 |
AssertCommand(["gnt-node", "power", "-f", "--ignore-status", "off", |
|
282 |
master_name], |
|
281 | 283 |
fail=True) |
282 | 284 |
# This should work again |
283 |
AssertCommand(["gnt-node", "power", "--ignore-status", "--force-master",
|
|
284 |
"off", master_name]) |
|
285 |
AssertCommand(["gnt-node", "power", "-f", "--ignore-status",
|
|
286 |
"--force-master", "off", master_name])
|
|
285 | 287 |
_AssertOobCall(verify_path, "power-off %s" % full_master_name) |
286 | 288 |
|
287 | 289 |
# Verify we can't transform back to online when not yet powered on |
... | ... | |
291 | 293 |
AssertCommand(["gnt-node", "modify", "-O", "no", "--node-powered", "yes", |
292 | 294 |
node_name]) |
293 | 295 |
|
294 |
AssertCommand(["gnt-node", "power", "cycle", node_name]) |
|
296 |
AssertCommand(["gnt-node", "power", "-f", "cycle", node_name])
|
|
295 | 297 |
_AssertOobCall(verify_path, "power-cycle %s" % full_node_name) |
296 | 298 |
|
297 | 299 |
# Those commands should fail as they expect output which isn't provided yet |
... | ... | |
326 | 328 |
_AssertOobCall(verify_path, "power-on %s" % full_node_name) |
327 | 329 |
|
328 | 330 |
try: |
329 |
AssertCommand(["gnt-node", "power", "off", node_name], fail=True) |
|
331 |
AssertCommand(["gnt-node", "power", "-f", "off", node_name], fail=True)
|
|
330 | 332 |
_AssertOobCall(verify_path, "power-off %s" % full_node_name) |
331 | 333 |
finally: |
332 | 334 |
AssertCommand(["gnt-node", "modify", "-O", "no", node_name]) |
333 | 335 |
|
334 |
AssertCommand(["gnt-node", "power", "cycle", node_name], fail=True) |
|
336 |
AssertCommand(["gnt-node", "power", "-f", "cycle", node_name], fail=True)
|
|
335 | 337 |
_AssertOobCall(verify_path, "power-cycle %s" % full_node_name) |
336 | 338 |
|
337 | 339 |
# Data, exit 1 (all should fail) |
... | ... | |
341 | 343 |
_AssertOobCall(verify_path, "power-on %s" % full_node_name) |
342 | 344 |
|
343 | 345 |
try: |
344 |
AssertCommand(["gnt-node", "power", "off", node_name], fail=True) |
|
346 |
AssertCommand(["gnt-node", "power", "-f", "off", node_name], fail=True)
|
|
345 | 347 |
_AssertOobCall(verify_path, "power-off %s" % full_node_name) |
346 | 348 |
finally: |
347 | 349 |
AssertCommand(["gnt-node", "modify", "-O", "no", node_name]) |
348 | 350 |
|
349 |
AssertCommand(["gnt-node", "power", "cycle", node_name], fail=True) |
|
351 |
AssertCommand(["gnt-node", "power", "-f", "cycle", node_name], fail=True)
|
|
350 | 352 |
_AssertOobCall(verify_path, "power-cycle %s" % full_node_name) |
351 | 353 |
|
352 | 354 |
AssertCommand(["gnt-node", "power", "status", node_name], |
... | ... | |
365 | 367 |
_AssertOobCall(verify_path, "power-on %s" % full_node_name) |
366 | 368 |
|
367 | 369 |
try: |
368 |
AssertCommand(["gnt-node", "power", "off", node_name], fail=True) |
|
370 |
AssertCommand(["gnt-node", "power", "-f", "off", node_name], fail=True)
|
|
369 | 371 |
_AssertOobCall(verify_path, "power-off %s" % full_node_name) |
370 | 372 |
finally: |
371 | 373 |
AssertCommand(["gnt-node", "modify", "-O", "no", node_name]) |
372 | 374 |
|
373 |
AssertCommand(["gnt-node", "power", "cycle", node_name], fail=True) |
|
375 |
AssertCommand(["gnt-node", "power", "-f", "cycle", node_name], fail=True)
|
|
374 | 376 |
_AssertOobCall(verify_path, "power-cycle %s" % full_node_name) |
375 | 377 |
|
376 | 378 |
AssertCommand(["gnt-node", "power", "status", node_name], |
... | ... | |
398 | 400 |
AssertCommand(["gnt-node", "modify", "--node-parameters", |
399 | 401 |
"oob_program=default", node_name]) |
400 | 402 |
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]) |
|
401 | 440 |
finally: |
402 | 441 |
AssertCommand(["gnt-cluster", "modify", "--node-parameters", |
403 | 442 |
"oob_program="]) |
Also available in: Unified diff