Commit 24711492 authored by Dimitris Aragiorgis's avatar Dimitris Aragiorgis Committed by Klaus Aehlig

Check if hotplug is supported in CheckPrereq

Introduce new RPC hotplug_supported that invokes the corresponding
hypervisor's method which checks if hotplug is generally
supported. Call this RPC early in CheckPrereq() and abort if
hotplug is not supported. Currently only KVM hypervisor with
qemu versions > 1.0. Please note that this check is unaware of
target device and hotplug action. This latter check is still
done during hotplug_device() RPC.
Signed-off-by: default avatarDimitris Aragiorgis <dimara@grnet.gr>
Signed-off-by: default avatarKlaus Aehlig <aehlig@google.com>
Reviewed-by: default avatarKlaus Aehlig <aehlig@google.com>
parent cabc869c
......@@ -2003,6 +2003,17 @@ def HotplugDevice(instance, action, dev_type, device, extra, seq):
return fn(instance, dev_type, device, extra, seq)
def HotplugSupported(instance):
"""Checks if hotplug is generally supported.
"""
hyper = hypervisor.GetHypervisor(instance.hypervisor)
try:
hyper.HotplugSupported(instance)
except errors.HotplugError, err:
_Fail("Hotplug is not supported: %s", err)
def BlockdevCreate(disk, size, owner, on_primary, info, excl_stor):
"""Creates a block device for an instance.
......
......@@ -2843,6 +2843,11 @@ class LUInstanceSetParams(LogicalUnit):
# dictionary with instance information after the modification
ispec = {}
if self.op.hotplug:
result = self.rpc.call_hotplug_supported(self.instance.primary_node,
self.instance)
result.Raise("Hotplug is not supported.")
# Prepare NIC modifications
self.nicmod = _PrepareContainerMods(self.op.nics, _InstNicModPrivate)
......
......@@ -589,8 +589,8 @@ class BaseHypervisor(object):
def VerifyHotplugSupport(self, instance, action, dev_type):
"""Verifies that hotplug is supported.
Hotplug is not supported by default. If a hypervisor wants to support
it it should override this method.
Given the target device and hotplug action checks if hotplug is
actually supported.
@type instance: L{objects.Instance}
@param instance: the instance object
......@@ -600,5 +600,13 @@ class BaseHypervisor(object):
@param dev_type: one of the supported device types to hotplug
@raise errors.HotplugError: if hotplugging is not supported
"""
raise errors.HotplugError("Hotplug is not supported.")
def HotplugSupported(self, instance):
"""Checks if hotplug is supported.
By default is not. Currently only KVM hypervisor supports it.
"""
raise errors.HotplugError("Hotplug is not supported by this hypervisor")
......@@ -2003,22 +2003,12 @@ class KVMHypervisor(hv_base.BaseHypervisor):
"""Verifies that hotplug is supported.
Hotplug is *not* supported in case of:
- qemu versions < 1.0
- security models and chroot (disk hotplug)
- fdsend module is missing (nic hot-add)
@raise errors.HypervisorError: in one of the previous cases
"""
output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
# TODO: search for netdev_add, drive_add, device_add.....
match = self._INFO_VERSION_RE.search(output.stdout)
if not match:
raise errors.HotplugError("Try hotplug only in running instances.")
v_major, v_min, _, _ = match.groups()
if (int(v_major), int(v_min)) < (1, 0):
raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
if dev_type == constants.HOTPLUG_TARGET_DISK:
hvp = instance.hvparams
security_model = hvp[constants.HV_SECURITY_MODEL]
......@@ -2035,6 +2025,25 @@ class KVMHypervisor(hv_base.BaseHypervisor):
raise errors.HotplugError("Cannot hot-add NIC."
" fdsend python module is missing.")
def HotplugSupported(self, instance):
"""Checks if hotplug is generally supported.
Hotplug is *not* supported in case of:
- qemu versions < 1.0
- for stopped instances
@raise errors.HypervisorError: in one of the previous cases
"""
output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
# TODO: search for netdev_add, drive_add, device_add.....
match = self._INFO_VERSION_RE.search(output.stdout)
if not match:
raise errors.HotplugError("Try hotplug only in running instances.")
v_major, v_min, _, _ = match.groups()
if (int(v_major), int(v_min)) < (1, 0):
raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
def _CallHotplugCommand(self, name, cmd):
output = self._CallMonitorCommand(name, cmd)
# TODO: parse output and check if succeeded
......
......@@ -300,6 +300,9 @@ _INSTANCE_CALLS = [
("extra", None, "Extra info for device (dev_path for disk)"),
("seq", None, "Device seq"),
], None, None, "Hoplug a device to a running instance"),
("hotplug_supported", SINGLE, None, constants.RPC_TMO_NORMAL, [
("instance", ED_INST_DICT, "Instance object"),
], None, None, "Check if hotplug is supported"),
]
_IMPEXP_CALLS = [
......
......@@ -630,6 +630,14 @@ class NodeRequestHandler(http.server.HttpServerHandler):
assert dev_type in constants.HOTPLUG_ALL_TARGETS
return backend.HotplugDevice(instance, action, dev_type, device, extra, seq)
@staticmethod
def perspective_hotplug_supported(params):
"""Checks if hotplug is supported.
"""
instance = objects.Instance.FromDict(params[0])
return backend.HotplugSupported(instance)
@staticmethod
def perspective_migration_info(params):
"""Gather information about an instance to be migrated.
......
......@@ -1975,6 +1975,7 @@ class TestLUInstanceSetParams(CmdlibTestCase):
nics=[(constants.DDM_ADD, -1, {})],
hotplug=True)
self.ExecOpCode(op)
self.assertTrue(self.rpc.call_hotplug_supported.called)
self.assertTrue(self.rpc.call_hotplug_device.called)
def testAddNicWithIp(self):
......@@ -2065,6 +2066,7 @@ class TestLUInstanceSetParams(CmdlibTestCase):
nics=[(constants.DDM_MODIFY, 0, {})],
hotplug=True)
self.ExecOpCode(op)
self.assertTrue(self.rpc.call_hotplug_supported.called)
self.assertTrue(self.rpc.call_hotplug_device.called)
def testRemoveLastNic(self):
......@@ -2089,6 +2091,7 @@ class TestLUInstanceSetParams(CmdlibTestCase):
nics=[(constants.DDM_REMOVE, 0, {})],
hotplug=True)
self.ExecOpCode(op)
self.assertTrue(self.rpc.call_hotplug_supported.called)
self.assertTrue(self.rpc.call_hotplug_device.called)
def testSetOffline(self):
......@@ -2177,6 +2180,7 @@ class TestLUInstanceSetParams(CmdlibTestCase):
}]],
hotplug=True)
self.ExecOpCode(op)
self.assertTrue(self.rpc.call_hotplug_supported.called)
self.assertTrue(self.rpc.call_blockdev_create.called)
self.assertTrue(self.rpc.call_blockdev_assemble.called)
self.assertTrue(self.rpc.call_hotplug_device.called)
......@@ -2190,6 +2194,7 @@ class TestLUInstanceSetParams(CmdlibTestCase):
{}]],
hotplug=True)
self.ExecOpCode(op)
self.assertTrue(self.rpc.call_hotplug_supported.called)
self.assertTrue(self.rpc.call_hotplug_device.called)
self.assertTrue(self.rpc.call_blockdev_shutdown.called)
self.assertTrue(self.rpc.call_blockdev_remove.called)
......
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