Revision e15a00dc

b/NEWS
36 36
- Hail and hbal now have the (optional) capability of accessing average CPU
37 37
  load information through the monitoring deamon, and to use it to dynamically
38 38
  adapt the allocation of instances.
39
- Hotplug support. Introduce new option '--hotplug' to ``gnt-instance modify``
40
  so that disk and NIC modifications take effect without the need of actual
41
  reboot. There are a couple of constrains currently for this feature:
42

  
43
   - only KVM hypervisor (versions >= 1.0) supports it,
44
   - one can not (yet) hotplug a disk using userspace access mode for RBD
45
   - in case of a downgrade instances should suffer a reboot in order to
46
     be migratable (due to core change of runtime files)
39 47

  
40 48
Misc changes
41 49
~~~~~~~~~~~~
......
102 110
New features
103 111
~~~~~~~~~~~~
104 112

  
105
- Hotplug support. Introduce new option --hotplug to gnt-instance modify
106
  so that disk and NIC modifications take effect without the need of actual
107
  reboot. This feature is currently supported only for KVM hypervisor with
108
  version greater than 1.0.
109 113
- DRBD 8.4 support. Depending on the installed DRBD version, Ganeti now uses
110 114
  the correct command syntax. It is possible to use different DRBD versions
111 115
  on different nodes as long as they are compatible to each other. This
b/lib/cli.py
1644 1644

  
1645 1645
HOTPLUG_OPT = cli_option("--hotplug", dest="hotplug",
1646 1646
                         action="store_true", default=False,
1647
                         help="Try to hotplug device")
1647
                         help="Hotplug supported devices (NICs and Disks)")
1648 1648

  
1649 1649
#: Options provided by all commands
1650 1650
COMMON_OPTS = [DEBUG_OPT, REASON_OPT]
b/lib/client/gnt_instance.py
1315 1315

  
1316 1316
  nics = _ConvertNicDiskModifications(opts.nics)
1317 1317
  for action, _, __ in nics:
1318
    if action == constants.DDM_MODIFY and opts.hotplug:
1318
    if action == constants.DDM_MODIFY and opts.hotplug and not opts.force:
1319 1319
      usertext = ("You are about to hot-modify a NIC. This will be done"
1320 1320
                  " by removing the exisiting and then adding a new one."
1321 1321
                  " Network connection might be lost. Continue?")
......
1364 1364
    ToStdout("Modified instance %s", args[0])
1365 1365
    for param, data in result:
1366 1366
      ToStdout(" - %-5s -> %s", param, data)
1367
    if not opts.hotplug:
1368
      ToStdout("Please don't forget that most parameters take effect"
1369
               " only at the next (re)start of the instance initiated by"
1370
               " ganeti; restarting from within the instance will"
1371
               " not be enough.")
1367
    ToStdout("Please don't forget that most parameters take effect"
1368
             " only at the next (re)start of the instance initiated by"
1369
             " ganeti; restarting from within the instance will"
1370
             " not be enough.")
1372 1371
  return 0
1373 1372

  
1374 1373

  
b/lib/cmdlib/instance.py
2228 2228
      if op == constants.DDM_REMOVE:
2229 2229
        assert not params
2230 2230

  
2231
        if remove_fn is not None:
2232
          remove_fn(absidx, item, private)
2233

  
2234 2231
        changes = [("%s/%s" % (kind, absidx), "remove")]
2235 2232

  
2233
        if remove_fn is not None:
2234
          msg = remove_fn(absidx, item, private)
2235
          if msg:
2236
            changes.append(("%s/%s" % (kind, absidx), msg))
2237

  
2236 2238
        assert container[absidx] == item
2237 2239
        del container[absidx]
2238 2240
      elif op == constants.DDM_MODIFY:
......
3236 3238

  
3237 3239
  def _HotplugDevice(self, action, dev_type, device, extra, seq):
3238 3240
    self.LogInfo("Trying to hotplug device...")
3241
    msg = "hotplug:"
3239 3242
    result = self.rpc.call_hotplug_device(self.instance.primary_node,
3240 3243
                                          self.instance, action, dev_type,
3241 3244
                                          (device, self.instance),
......
3243 3246
    if result.fail_msg:
3244 3247
      self.LogWarning("Could not hotplug device: %s" % result.fail_msg)
3245 3248
      self.LogInfo("Continuing execution..")
3249
      msg += "failed"
3246 3250
    else:
3247 3251
      self.LogInfo("Hotplug done.")
3252
      msg += "done"
3253
    return msg
3248 3254

  
3249 3255
  def _CreateNewDisk(self, idx, params, _):
3250 3256
    """Creates a new disk.
......
3271 3277
                         disks=[(idx, disk, 0)],
3272 3278
                         cleanup=new_disks)
3273 3279

  
3280
    changes = [
3281
      ("disk/%d" % idx,
3282
      "add:size=%s,mode=%s" % (disk.size, disk.mode)),
3283
      ]
3274 3284
    if self.op.hotplug:
3275 3285
      result = self.rpc.call_blockdev_assemble(self.instance.primary_node,
3276 3286
                                               (disk, self.instance),
3277 3287
                                               self.instance.name, True, idx)
3278 3288
      if result.fail_msg:
3289
        changes.append(("disk/%d" % idx, "assemble:failed"))
3279 3290
        self.LogWarning("Can't assemble newly created disk %d: %s",
3280 3291
                        idx, result.fail_msg)
3281 3292
      else:
3282 3293
        _, link_name = result.payload
3283
        self._HotplugDevice(constants.HOTPLUG_ACTION_ADD,
3284
                            constants.HOTPLUG_TARGET_DISK,
3285
                            disk, link_name, idx)
3294
        msg = self._HotplugDevice(constants.HOTPLUG_ACTION_ADD,
3295
                                  constants.HOTPLUG_TARGET_DISK,
3296
                                  disk, link_name, idx)
3297
        changes.append(("disk/%d" % idx, msg))
3286 3298

  
3287
    return (disk, [
3288
      ("disk/%d" % idx, "add:size=%s,mode=%s" % (disk.size, disk.mode)),
3289
      ])
3299
    return (disk, changes)
3290 3300

  
3291 3301
  def _PostAddDisk(self, _, disk):
3292 3302
    if not WaitForSync(self, self.instance, disks=[disk],
......
3320 3330
    """Removes a disk.
3321 3331

  
3322 3332
    """
3333
    hotmsg = ""
3323 3334
    if self.op.hotplug:
3324
      self._HotplugDevice(constants.HOTPLUG_ACTION_REMOVE,
3325
                          constants.HOTPLUG_TARGET_DISK,
3326
                          root, None, idx)
3335
      hotmsg = self._HotplugDevice(constants.HOTPLUG_ACTION_REMOVE,
3336
                                   constants.HOTPLUG_TARGET_DISK,
3337
                                   root, None, idx)
3327 3338
      ShutdownInstanceDisks(self, self.instance, [root])
3328 3339

  
3329 3340
    (anno_disk,) = AnnotateDiskParams(self.instance, [root], self.cfg)
......
3340 3351
    if root.dev_type in constants.DTS_DRBD:
3341 3352
      self.cfg.AddTcpUdpPort(root.logical_id[2])
3342 3353

  
3354
    return hotmsg
3355

  
3343 3356
  def _CreateNewNic(self, idx, params, private):
3344 3357
    """Creates data structure for a new network interface.
3345 3358

  
......
3355 3368
                       nicparams=nicparams)
3356 3369
    nobj.uuid = self.cfg.GenerateUniqueID(self.proc.GetECId())
3357 3370

  
3358
    if self.op.hotplug:
3359
      self._HotplugDevice(constants.HOTPLUG_ACTION_ADD,
3360
                          constants.HOTPLUG_TARGET_NIC,
3361
                          nobj, None, idx)
3362

  
3363
    desc = [
3371
    changes = [
3364 3372
      ("nic.%d" % idx,
3365 3373
       "add:mac=%s,ip=%s,mode=%s,link=%s,network=%s" %
3366 3374
       (mac, ip, private.filled[constants.NIC_MODE],
3367 3375
       private.filled[constants.NIC_LINK], net)),
3368 3376
      ]
3369 3377

  
3370
    return (nobj, desc)
3378
    if self.op.hotplug:
3379
      msg = self._HotplugDevice(constants.HOTPLUG_ACTION_ADD,
3380
                                constants.HOTPLUG_TARGET_NIC,
3381
                                nobj, None, idx)
3382
      changes.append(("nic.%d" % idx, msg))
3383

  
3384
    return (nobj, changes)
3371 3385

  
3372 3386
  def _ApplyNicMods(self, idx, nic, params, private):
3373 3387
    """Modifies a network interface.
......
3393 3407
        changes.append(("nic.%s/%d" % (key, idx), val))
3394 3408

  
3395 3409
    if self.op.hotplug:
3396
      self._HotplugDevice(constants.HOTPLUG_ACTION_MODIFY,
3397
                          constants.HOTPLUG_TARGET_NIC,
3398
                          nic, None, idx)
3410
      msg = self._HotplugDevice(constants.HOTPLUG_ACTION_MODIFY,
3411
                                constants.HOTPLUG_TARGET_NIC,
3412
                                nic, None, idx)
3413
      changes.append(("nic/%d" % idx, msg))
3399 3414

  
3400 3415
    return changes
3401 3416

  
3402 3417
  def _RemoveNic(self, idx, nic, _):
3403 3418
    if self.op.hotplug:
3404
      self._HotplugDevice(constants.HOTPLUG_ACTION_REMOVE,
3405
                          constants.HOTPLUG_TARGET_NIC,
3406
                          nic, None, idx)
3419
      return self._HotplugDevice(constants.HOTPLUG_ACTION_REMOVE,
3420
                                 constants.HOTPLUG_TARGET_NIC,
3421
                                 nic, None, idx)
3407 3422

  
3408 3423
  def Exec(self, feedback_fn):
3409 3424
    """Modifies an instance.
b/man/gnt-instance.rst
1206 1206
If ``--ignore-ipolicy`` is given any instance policy violations occuring
1207 1207
during this operation are ignored.
1208 1208

  
1209
If ``--hotplug`` is given any disk and nic modifications will take
1209
If ``--hotplug`` is given any disk and NIC modifications will take
1210 1210
effect without the need of actual reboot. Please note that this feature
1211
is currently supported only for KVM hypervisor and for versions greater
1212
than 1.0.
1211
is currently supported only for KVM hypervisor and there are some
1212
restrictions: a) KVM versions >= 1.0 support it b) instances with chroot
1213
or uid pool security model do not support disk hotplug c) RBD disks with
1214
userspace access mode can not be hotplugged (yet) d) if hotplug fails
1215
(for any reason) a warning is printed but execution is continued e)
1216
for existing NIC modification interactive verification is needed unless
1217
``--force`` option is passed.
1213 1218

  
1214 1219
See **ganeti**\(7) for a description of ``--submit`` and other common
1215 1220
options.
b/qa/qa_instance.py
538 538
    qa_config.TestEnabled("instance-device-hotplug"):
539 539
    args.extend([
540 540
      ["--net", "-1:add", "--hotplug"],
541
      ["--net", "-1:modify,mac=aa:bb:cc:dd:ee:ff", "--hotplug"],
541
      ["--net", "-1:modify,mac=aa:bb:cc:dd:ee:ff", "--hotplug", "--force"],
542 542
      ["--net", "-1:remove", "--hotplug"],
543 543
      ["--disk", "-1:add,size=1G", "--hotplug"],
544 544
      ["--disk", "-1:remove", "--hotplug"],

Also available in: Unified diff