Commit c5708931 authored by Dimitris Aragiorgis's avatar Dimitris Aragiorgis Committed by Thomas Thrainer
Browse files

Hotplug: rpc support



Introduce new RPC that eventually invoke hypervisor specific
hotplug functions. In order to be generic it has the following
arguments: device type, action, device, extra info, seq.
Device type can be NIC or DISK, action can be ADD, REMOVE,
device is the NIC or Disk object, extra info is used by Disk
hotplug to point the device path and seq is the device index
(from the master perspective)

Add HotplugSupported() in all Hypervisors

Only KVM hypervisor supports this method. The other hypervisors
raise HypervisorError.

Before trying hotplug in backend layer invoke hyper.HotplugSupported
and abort RPC in case it is not implemented or for some other reason
not supported (disk+chroot, nic without fdsend, etc).
Signed-off-by: default avatarDimitris Aragiorgis <dimara@grnet.gr>
Signed-off-by: default avatarThomas Thrainer <thomasth@google.com>
Reviewed-by: default avatarThomas Thrainer <thomasth@google.com>
parent 4b82125b
......@@ -1966,6 +1966,43 @@ def GetMigrationStatus(instance):
_Fail("Failed to get migration status: %s", err, exc=True)
def HotplugDevice(instance, action, dev_type, device, extra, seq):
"""Hotplug a device
Hotplug is currently supported only for KVM Hypervisor.
@type instance: L{objects.Instance}
@param instance: the instance to which we hotplug a device
@type action: string
@param action: the hotplug action to perform
@type dev_type: string
@param dev_type: the device type to hotplug
@type device: either L{objects.NIC} or L{objects.Disk}
@param device: the device object to hotplug
@type extra: string
@param extra: extra info used by hotplug code (e.g. disk link)
@type seq: int
@param seq: the index of the device from master perspective
@raise RPCFail: in case instance does not have KVM hypervisor
"""
hyper = hypervisor.GetHypervisor(instance.hypervisor)
try:
hyper.HotplugSupported(instance, action, dev_type)
except (errors.HotplugError, errors.HypervisorError), err:
_Fail("Hotplug is not supported: %s", err)
if action == constants.HOTPLUG_ACTION_ADD:
fn = hyper.HotAddDevice
elif action == constants.HOTPLUG_ACTION_REMOVE:
fn = hyper.HotDelDevice
elif action == constants.HOTPLUG_ACTION_MODIFY:
fn = hyper.HotModDevice
else:
assert action in constants.HOTPLUG_ALL_ACTIONS
return fn(instance, dev_type, device, extra, seq)
def BlockdevCreate(disk, size, owner, on_primary, info, excl_stor):
"""Creates a block device for an instance.
......
......@@ -563,3 +563,28 @@ class BaseHypervisor(object):
return "; ".join(msgs)
else:
return None
def HotAddDevice(self, instance, dev_type, device, extra, seq):
"""Hot-add a device.
"""
pass
def HotDelDevice(self, instance, dev_type, device, extra, seq):
"""Hot-del a device.
"""
pass
def HotModDevice(self, instance, dev_type, device, extra, seq):
"""Hot-mod a device.
"""
pass
def HotplugSupported(self, instance, action, dev_type):
"""Whether hotplug is supported.
Depends on instance's hvparam, the action. and the dev_type
"""
raise NotImplementedError
......@@ -329,3 +329,9 @@ class ChrootManager(hv_base.BaseHypervisor):
"""
raise HypervisorError("Migration not supported by the chroot hypervisor")
def HotplugSupported(self, instance, action, dev_type):
"""Whether hotplug is supported.
"""
raise HypervisorError("Hotplug not supported by the chroot hypervisor")
......@@ -354,3 +354,9 @@ class FakeHypervisor(hv_base.BaseHypervisor):
"""
return objects.MigrationStatus(status=constants.HV_MIGRATION_COMPLETED)
def HotplugSupported(self, instance, action, dev_type):
"""Whether hotplug is supported.
"""
raise errors.HypervisorError("Hotplug not supported by the fake hypervisor")
......@@ -477,3 +477,9 @@ class LXCHypervisor(hv_base.BaseHypervisor):
"""
raise HypervisorError("Migration is not supported by the LXC hypervisor")
def HotplugSupported(self, instance, action, dev_type):
"""Whether hotplug is supported.
"""
raise HypervisorError("Hotplug not supported by the LXC hypervisor")
......@@ -948,6 +948,12 @@ class XenHypervisor(hv_base.BaseHypervisor):
raise errors.HypervisorError("Cannot run xen ('%s'). Error: %s."
% (constants.XEN_CMD_XL, result.stderr))
def HotplugSupported(self, instance, action, dev_type):
"""Whether hotplug is supported.
"""
raise errors.HypervisorError("Hotplug not supported by the xen hypervisor")
class XenPvmHypervisor(XenHypervisor):
"""Xen PVM hypervisor interface"""
......
......@@ -790,6 +790,7 @@ class RpcRunner(_RpcClientBase,
rpc_defs.ED_INST_DICT_HVP_BEP_DP: self._InstDictHvpBepDp,
rpc_defs.ED_INST_DICT_OSP_DP: self._InstDictOspDp,
rpc_defs.ED_NIC_DICT: self._NicDict,
rpc_defs.ED_DEVICE_DICT: self._DeviceDict,
# Encoders annotating disk parameters
rpc_defs.ED_DISKS_DICT_DP: self._DisksDictDP,
......@@ -831,6 +832,12 @@ class RpcRunner(_RpcClientBase,
n.netinfo = objects.Network.ToDict(nobj)
return n.ToDict()
def _DeviceDict(self, _, device):
if isinstance(device, objects.NIC):
return self._NicDict(None, device)
elif isinstance(device, objects.Disk):
return _ObjectToDict(None, device)
def _InstDict(self, node, instance, hvp=None, bep=None, osp=None):
"""Convert the given instance to a dict.
......
......@@ -72,7 +72,8 @@ ACCEPT_OFFLINE_NODE = object()
ED_DISKS_DICT_DP,
ED_MULTI_DISKS_DICT_DP,
ED_SINGLE_DISK_DICT_DP,
ED_NIC_DICT) = range(1, 16)
ED_NIC_DICT,
ED_DEVICE_DICT) = range(1, 17)
def _Prepare(calls):
......@@ -291,6 +292,14 @@ _INSTANCE_CALLS = [
("reinstall", None, None),
("debug", None, None),
], None, None, "Starts an instance"),
("hotplug_device", SINGLE, None, constants.RPC_TMO_NORMAL, [
("instance", ED_INST_DICT, "Instance object"),
("action", None, "Hotplug Action"),
("dev_type", None, "Device type"),
("device", ED_DEVICE_DICT, "Device dict"),
("extra", None, "Extra info for device (dev_path for disk)"),
("seq", None, "Device seq"),
], None, None, "Hoplug a device to a running instance"),
]
_IMPEXP_CALLS = [
......
......@@ -615,6 +615,21 @@ class NodeRequestHandler(http.server.HttpServerHandler):
_extendReasonTrail(trail, "start")
return backend.StartInstance(instance, startup_paused, trail)
@staticmethod
def perspective_hotplug_device(params):
"""Hotplugs device to a running instance.
"""
(idict, action, dev_type, ddict, extra, seq) = params
instance = objects.Instance.FromDict(idict)
if dev_type == constants.HOTPLUG_TARGET_DISK:
device = objects.Disk.FromDict(ddict)
elif dev_type == constants.HOTPLUG_TARGET_NIC:
device = objects.NIC.FromDict(ddict)
else:
assert dev_type in constants.HOTPLUG_ALL_TARGETS
return backend.HotplugDevice(instance, action, dev_type, device, extra, seq)
@staticmethod
def perspective_migration_info(params):
"""Gather information about an instance to be migrated.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment