Revision 1f350e0f

b/lib/backend.py
1355 1355
    _Fail("Hypervisor error: %s", err, exc=True)
1356 1356

  
1357 1357

  
1358
def InstanceShutdown(instance, timeout):
1358
def InstanceShutdown(instance, timeout, reason, store_reason=True):
1359 1359
  """Shut an instance down.
1360 1360

  
1361 1361
  @note: this functions uses polling with a hardcoded timeout.
......
1364 1364
  @param instance: the instance object
1365 1365
  @type timeout: integer
1366 1366
  @param timeout: maximum timeout for soft shutdown
1367
  @type reason: list of reasons
1368
  @param reason: the reason trail for this shutdown
1369
  @type store_reason: boolean
1370
  @param store_reason: whether to store the shutdown reason trail on file
1367 1371
  @rtype: None
1368 1372

  
1369 1373
  """
......
1385 1389

  
1386 1390
      try:
1387 1391
        hyper.StopInstance(instance, retry=self.tried_once)
1392
        if store_reason:
1393
          _StoreInstReasonTrail(instance.name, reason)
1388 1394
      except errors.HypervisorError, err:
1389 1395
        if iname not in hyper.ListInstances():
1390 1396
          # if the instance is no longer existing, consider this a
......
1460 1466
      _Fail("Failed to soft reboot instance %s: %s", instance.name, err)
1461 1467
  elif reboot_type == constants.INSTANCE_REBOOT_HARD:
1462 1468
    try:
1463
      InstanceShutdown(instance, shutdown_timeout)
1469
      InstanceShutdown(instance, shutdown_timeout, reason, store_reason=False)
1464 1470
      result = StartInstance(instance, False)
1465 1471
      _StoreInstReasonTrail(instance.name, reason)
1466 1472
      return result
b/lib/cmdlib.py
7449 7449
    else:
7450 7450
      if instance_running:
7451 7451
        result = self.rpc.call_instance_shutdown(node_current, instance,
7452
                                                 self.op.shutdown_timeout)
7452
                                                 self.op.shutdown_timeout,
7453
                                                 reason)
7453 7454
        result.Raise("Could not shutdown instance for full reboot")
7454 7455
        _ShutdownInstanceDisks(self, instance)
7455 7456
      else:
......
7525 7526
    instance = self.instance
7526 7527
    node_current = instance.primary_node
7527 7528
    timeout = self.op.timeout
7529
    reason = self.op.reason
7528 7530

  
7529 7531
    # If the instance is offline we shouldn't mark it as down, as that
7530 7532
    # resets the offline flag.
......
7535 7537
      assert self.op.ignore_offline_nodes
7536 7538
      self.LogInfo("Primary node offline, marked instance as stopped")
7537 7539
    else:
7538
      result = self.rpc.call_instance_shutdown(node_current, instance, timeout)
7540
      result = self.rpc.call_instance_shutdown(node_current, instance, timeout,
7541
                                               reason)
7539 7542
      msg = result.fail_msg
7540 7543
      if msg:
7541 7544
        self.LogWarning("Could not shutdown instance: %s", msg)
......
8116 8119
                 instance.name, instance.primary_node)
8117 8120

  
8118 8121
    result = self.rpc.call_instance_shutdown(instance.primary_node, instance,
8119
                                             self.op.shutdown_timeout)
8122
                                             self.op.shutdown_timeout,
8123
                                             self.op.reason)
8120 8124
    msg = result.fail_msg
8121 8125
    if msg:
8122 8126
      if self.op.ignore_failures:
......
8481 8485
            self.owned_locks(locking.LEVEL_NODE_RES))
8482 8486

  
8483 8487
    result = self.rpc.call_instance_shutdown(source_node, instance,
8484
                                             self.op.shutdown_timeout)
8488
                                             self.op.shutdown_timeout,
8489
                                             self.op.reason)
8485 8490
    msg = result.fail_msg
8486 8491
    if msg:
8487 8492
      if self.op.ignore_consistency:
......
9254 9259
                 instance.name, source_node)
9255 9260

  
9256 9261
    result = self.rpc.call_instance_shutdown(source_node, instance,
9257
                                             self.shutdown_timeout)
9262
                                             self.shutdown_timeout,
9263
                                             self.lu.op.reason)
9258 9264
    msg = result.fail_msg
9259 9265
    if msg:
9260 9266
      if self.ignore_consistency or primary_node.offline:
......
14927 14933
      # shutdown the instance, but not the disks
14928 14934
      feedback_fn("Shutting down instance %s" % instance.name)
14929 14935
      result = self.rpc.call_instance_shutdown(src_node, instance,
14930
                                               self.op.shutdown_timeout)
14936
                                               self.op.shutdown_timeout,
14937
                                               self.op.reason)
14931 14938
      # TODO: Maybe ignore failures if ignore_remove_failures is set
14932 14939
      result.Raise("Could not shutdown instance %s on"
14933 14940
                   " node %s" % (instance.name, src_node))
b/lib/rapi/client.py
1031 1031
                              (GANETI_RAPI_VERSION, instance)), query, None)
1032 1032

  
1033 1033
  def ShutdownInstance(self, instance, dry_run=False, no_remember=False,
1034
                       **kwargs):
1034
                       reason=None, **kwargs):
1035 1035
    """Shuts down an instance.
1036 1036

  
1037 1037
    @type instance: str
......
1040 1040
    @param dry_run: whether to perform a dry run
1041 1041
    @type no_remember: bool
1042 1042
    @param no_remember: if true, will not record the state change
1043
    @type reason: string
1044
    @param reason: the reason for the shutdown
1043 1045
    @rtype: string
1044 1046
    @return: job id
1045 1047

  
......
1049 1051

  
1050 1052
    _AppendDryRunIf(query, dry_run)
1051 1053
    _AppendIf(query, no_remember, ("no_remember", 1))
1054
    _AppendIf(query, reason, ("reason", reason))
1052 1055

  
1053 1056
    return self._SendRequest(HTTP_PUT,
1054 1057
                             ("/%s/instances/%s/shutdown" %
b/lib/rpc_defs.py
235 235
  ("instance_shutdown", SINGLE, None, constants.RPC_TMO_NORMAL, [
236 236
    ("instance", ED_INST_DICT, "Instance object"),
237 237
    ("timeout", None, None),
238
    ("reason", None, "The reason for the shutdown"),
238 239
    ], None, None, "Stops an instance"),
239 240
  ("instance_balloon_memory", SINGLE, None, constants.RPC_TMO_NORMAL, [
240 241
    ("instance", ED_INST_DICT, "Instance object"),
b/lib/server/noded.py
589 589
    """
590 590
    instance = objects.Instance.FromDict(params[0])
591 591
    timeout = params[1]
592
    return backend.InstanceShutdown(instance, timeout)
592
    trail = params[2]
593
    _extendReasonTrail(trail, "shutdown")
594
    return backend.InstanceShutdown(instance, timeout, trail)
593 595

  
594 596
  @staticmethod
595 597
  def perspective_instance_start(params):
b/test/py/ganeti.rapi.client_unittest.py
619 619
  def testShutdownInstance(self):
620 620
    self.rapi.AddResponse("1487")
621 621
    self.assertEqual(1487, self.client.ShutdownInstance("foo-instance",
622
                                                        dry_run=True,
623
                                                        reason="NoMore"))
624
    self.assertHandler(rlib2.R_2_instances_name_shutdown)
625
    self.assertItems(["foo-instance"])
626
    self.assertDryRun()
627
    self.assertQuery("reason", ["NoMore"])
628

  
629
  def testShutdownInstanceDefaultReason(self):
630
    self.rapi.AddResponse("1487")
631
    self.assertEqual(1487, self.client.ShutdownInstance("foo-instance",
622 632
                                                        dry_run=True))
623 633
    self.assertHandler(rlib2.R_2_instances_name_shutdown)
624 634
    self.assertItems(["foo-instance"])
625 635
    self.assertDryRun()
636
    self.assertQuery("reason", None)
626 637

  
627 638
  def testStartupInstance(self):
628 639
    self.rapi.AddResponse("27149")
b/test/py/ganeti.rapi.rlib2_unittest.py
422 422
    clfactory = _FakeClientFactory(_FakeClient)
423 423
    handler = _CreateHandler(rlib2.R_2_instances_name_shutdown, ["inst26791"], {
424 424
      "no_remember": ["0"],
425
      "reason": ["Not used anymore"],
425 426
      }, {}, clfactory)
426 427
    job_id = handler.PUT()
427 428

  
......
434 435
    self.assertEqual(op.instance_name, "inst26791")
435 436
    self.assertFalse(op.no_remember)
436 437
    self.assertFalse(op.dry_run)
438
    self.assertEqual(op.reason[0][0], constants.OPCODE_REASON_SRC_USER)
439
    self.assertEqual(op.reason[0][1], "Not used anymore")
440
    self.assertEqual(op.reason[1][0],
441
                     "%s:%s" % (constants.OPCODE_REASON_SRC_RLIB2,
442
                                "instances_name_shutdown"))
443
    self.assertEqual(op.reason[1][1], "")
437 444

  
438 445
    self.assertRaises(IndexError, cl.GetNextSubmittedJob)
439 446

  

Also available in: Unified diff