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