Revision 4a90bd4f

b/lib/backend.py
1451 1451
  _RemoveBlockDevLinks(iname, instance.disks)
1452 1452

  
1453 1453

  
1454
def InstanceReboot(instance, reboot_type, shutdown_timeout):
1454
def InstanceReboot(instance, reboot_type, shutdown_timeout, reason):
1455 1455
  """Reboot an instance.
1456 1456

  
1457 1457
  @type instance: L{objects.Instance}
......
1481 1481
  if reboot_type == constants.INSTANCE_REBOOT_SOFT:
1482 1482
    try:
1483 1483
      hyper.RebootInstance(instance)
1484
      reason.Store(instance.name)
1484 1485
    except errors.HypervisorError, err:
1485 1486
      _Fail("Failed to soft reboot instance %s: %s", instance.name, err)
1486 1487
  elif reboot_type == constants.INSTANCE_REBOOT_HARD:
1487 1488
    try:
1488 1489
      InstanceShutdown(instance, shutdown_timeout)
1489
      return StartInstance(instance, False)
1490
      result = StartInstance(instance, False)
1491
      reason.Store(instance.name)
1492
      return result
1490 1493
    except errors.HypervisorError, err:
1491 1494
      _Fail("Failed to hard reboot instance %s: %s", instance.name, err)
1492 1495
  else:
b/lib/client/gnt_instance.py
1552 1552
    [m_force_multi, REBOOT_TYPE_OPT, IGNORE_SECONDARIES_OPT, m_node_opt,
1553 1553
     m_pri_node_opt, m_sec_node_opt, m_clust_opt, m_inst_opt, SUBMIT_OPT,
1554 1554
     m_node_tags_opt, m_pri_node_tags_opt, m_sec_node_tags_opt,
1555
     m_inst_tags_opt, SHUTDOWN_TIMEOUT_OPT, DRY_RUN_OPT, PRIORITY_OPT],
1555
     m_inst_tags_opt, SHUTDOWN_TIMEOUT_OPT, DRY_RUN_OPT, PRIORITY_OPT,
1556
     REASON_OPT],
1556 1557
    "<instance>", "Reboots an instance"),
1557 1558
  "activate-disks": (
1558 1559
    ActivateDisks, ARGS_ONE_INSTANCE,
b/lib/cmdlib.py
7361 7361
    instance = self.instance
7362 7362
    ignore_secondaries = self.op.ignore_secondaries
7363 7363
    reboot_type = self.op.reboot_type
7364
    reason = self.op.reason
7364 7365

  
7365 7366
    remote_info = self.rpc.call_instance_info(instance.primary_node,
7366 7367
                                              instance.name,
......
7376 7377
        self.cfg.SetDiskID(disk, node_current)
7377 7378
      result = self.rpc.call_instance_reboot(node_current, instance,
7378 7379
                                             reboot_type,
7379
                                             self.op.shutdown_timeout)
7380
                                             self.op.shutdown_timeout,
7381
                                             reason)
7380 7382
      result.Raise("Could not reboot instance")
7381 7383
    else:
7382 7384
      if instance_running:
b/lib/constants.py
2343 2343
  INSTANCE_REASON_SOURCE_UNKNOWN,
2344 2344
  ])
2345 2345

  
2346
# The default reasons for the change of state of an instance
2347
INSTANCE_REASON_REBOOT = "reboot"
2348

  
2346 2349
# Do not re-export imported modules
2347 2350
del re, _vcsversion, _autoconf, socket, pathutils, compat
b/lib/opcodes.py
1451 1451
     "Whether to start the instance even if secondary disks are failing"),
1452 1452
    ("reboot_type", ht.NoDefault, ht.TElemOf(constants.REBOOT_TYPES),
1453 1453
     "How to reboot instance"),
1454
    ("reason", (constants.INSTANCE_REASON_SOURCE_UNKNOWN, None),
1455
     ht.TAnd(ht.TOr(ht.TList, ht.TTuple),
1456
             ht.TIsLength(2),
1457
             ht.TItems([
1458
              ht.TElemOf(constants.INSTANCE_REASON_SOURCES),
1459
              ht.TMaybeString,
1460
             ])
1461
             ),
1462
     "The reason why the reboot is happening"),
1454 1463
    ]
1455 1464
  OP_RESULT = ht.TNone
1456 1465

  
b/lib/rapi/client.py
1001 1001
                              (GANETI_RAPI_VERSION, instance)), query, None)
1002 1002

  
1003 1003
  def RebootInstance(self, instance, reboot_type=None, ignore_secondaries=None,
1004
                     dry_run=False):
1004
                     dry_run=False, reason_text=None):
1005 1005
    """Reboots an instance.
1006 1006

  
1007 1007
    @type instance: str
1008
    @param instance: instance to rebot
1008
    @param instance: instance to reboot
1009 1009
    @type reboot_type: str
1010 1010
    @param reboot_type: one of: hard, soft, full
1011 1011
    @type ignore_secondaries: bool
......
1013 1013
        while re-assembling disks (in hard-reboot mode only)
1014 1014
    @type dry_run: bool
1015 1015
    @param dry_run: whether to perform a dry run
1016
    @type reason_text: string
1017
    @param reason_text: the reason for the reboot
1016 1018
    @rtype: string
1017 1019
    @return: job id
1018 1020

  
......
1022 1024
    _AppendIf(query, reboot_type, ("type", reboot_type))
1023 1025
    _AppendIf(query, ignore_secondaries is not None,
1024 1026
              ("ignore_secondaries", ignore_secondaries))
1027
    _AppendIf(query, reason_text, ("reason_text", reason_text))
1025 1028

  
1026 1029
    return self._SendRequest(HTTP_POST,
1027 1030
                             ("/%s/instances/%s/reboot" %
b/lib/rapi/rlib2.py
1040 1040
        self.queryargs.get("type", [constants.INSTANCE_REBOOT_HARD])[0],
1041 1041
      "ignore_secondaries": bool(self._checkIntVariable("ignore_secondaries")),
1042 1042
      "dry_run": self.dryRun(),
1043
      "reason": (
1044
        constants.INSTANCE_REASON_SOURCE_RAPI,
1045
        self._checkStringVariable("reason_text",
1046
                                  default=constants.INSTANCE_REASON_REBOOT),
1047
      )
1043 1048
      })
1044 1049

  
1045 1050

  
b/lib/rpc_defs.py
230 230
    ("inst", ED_INST_DICT, "Instance object"),
231 231
    ("reboot_type", None, None),
232 232
    ("shutdown_timeout", None, None),
233
    ("reason_text", None, "Reason for the reboot"),
233 234
    ], None, None, "Returns the list of running instances on the given nodes"),
234 235
  ("instance_shutdown", SINGLE, None, constants.RPC_TMO_NORMAL, [
235 236
    ("instance", ED_INST_DICT, "Instance object"),
b/lib/server/noded.py
112 112
  return ieioargs
113 113

  
114 114

  
115
def _DefaultAlternative(value, default):
116
  """Returns the given value, unless it is None. In that case, returns a
117
  default alternative.
118

  
119
  @param value: The value to return if it is not None.
120
  @param default: The value to return as a default alternative.
121
  @return: The given value or the default alternative.\
122

  
123
  """
124
  if value:
125
    return value
126

  
127
  return default
128

  
129

  
115 130
class MlockallRequestExecutor(http.server.HttpServerRequestExecutor):
116 131
  """Subclass ensuring request handlers are locked in RAM.
117 132

  
......
633 648
    instance = objects.Instance.FromDict(params[0])
634 649
    reboot_type = params[1]
635 650
    shutdown_timeout = params[2]
636
    return backend.InstanceReboot(instance, reboot_type, shutdown_timeout)
651
    (reason_source, reason_text) = params[3]
652
    reason_text = _DefaultAlternative(reason_text,
653
                                      constants.INSTANCE_REASON_REBOOT)
654
    reason = backend.InstReason(reason_source, reason_text)
655
    return backend.InstanceReboot(instance, reboot_type, shutdown_timeout,
656
                                  reason)
637 657

  
638 658
  @staticmethod
639 659
  def perspective_instance_balloon_memory(params):
b/src/Ganeti/OpCodes.hs
344 344
     , pShutdownTimeout
345 345
     , pIgnoreSecondaries
346 346
     , pRebootType
347
     , pReason
347 348
     ])
348 349
  , ("OpInstanceMove",
349 350
     [ pInstanceName
b/test/hs/Test/Ganeti/OpCodes.hs
241 241
          arbitrary <*> arbitrary
242 242
      "OP_INSTANCE_REBOOT" ->
243 243
        OpCodes.OpInstanceReboot <$> genFQDN <*> arbitrary <*>
244
          arbitrary <*> arbitrary
244
          arbitrary <*> arbitrary <*> ((,) <$> arbitrary <*> genStringNE)
245 245
      "OP_INSTANCE_MOVE" ->
246 246
        OpCodes.OpInstanceMove <$> genFQDN <*> arbitrary <*> arbitrary <*>
247 247
          genNodeNameNE <*> arbitrary
......
397 397
  octets <- vectorOf 3 $ choose (0::Int, 255)
398 398
  mkNonEmpty . intercalate ":" $ map (printf "%02x") octets
399 399

  
400
-- | Generate a non empty string
401
genStringNE :: Gen NonEmptyString
402
genStringNE = genName >>= mkNonEmpty
403

  
400 404
-- | Arbitrary instance for MetaOpCode, defined here due to TH ordering.
401 405
$(genArbitrary ''OpCodes.MetaOpCode)
402 406

  
b/test/py/ganeti.rapi.client_unittest.py
594 594
  def testRebootInstance(self):
595 595
    self.rapi.AddResponse("6146")
596 596
    job_id = self.client.RebootInstance("i-bar", reboot_type="hard",
597
                                        ignore_secondaries=True, dry_run=True,
598
                                        reason_text="Updates")
599
    self.assertEqual(6146, job_id)
600
    self.assertHandler(rlib2.R_2_instances_name_reboot)
601
    self.assertItems(["i-bar"])
602
    self.assertDryRun()
603
    self.assertQuery("type", ["hard"])
604
    self.assertQuery("ignore_secondaries", ["1"])
605
    self.assertQuery("reason_text", ["Updates"])
606

  
607
  def testRebootInstanceDefaultReason(self):
608
    self.rapi.AddResponse("6146")
609
    job_id = self.client.RebootInstance("i-bar", reboot_type="hard",
597 610
                                        ignore_secondaries=True, dry_run=True)
598 611
    self.assertEqual(6146, job_id)
599 612
    self.assertHandler(rlib2.R_2_instances_name_reboot)
......
601 614
    self.assertDryRun()
602 615
    self.assertQuery("type", ["hard"])
603 616
    self.assertQuery("ignore_secondaries", ["1"])
617
    self.assertQuery("reason_text", None)
604 618

  
605 619
  def testShutdownInstance(self):
606 620
    self.rapi.AddResponse("1487")
b/test/py/ganeti.rapi.rlib2_unittest.py
370 370
    handler = _CreateHandler(rlib2.R_2_instances_name_reboot, ["inst847"], {
371 371
      "dry-run": ["1"],
372 372
      "ignore_secondaries": ["1"],
373
      "reason_text": ["System update"]
373 374
      }, {}, clfactory)
374 375
    job_id = handler.POST()
375 376

  
......
383 384
    self.assertEqual(op.reboot_type, constants.INSTANCE_REBOOT_HARD)
384 385
    self.assertTrue(op.ignore_secondaries)
385 386
    self.assertTrue(op.dry_run)
387
    self.assertEqual(op.reason,
388
      (constants.INSTANCE_REASON_SOURCE_RAPI,
389
       "System update",
390
      ))
386 391

  
387 392
    self.assertRaises(IndexError, cl.GetNextSubmittedJob)
388 393

  

Also available in: Unified diff