Commit cba1fce1 authored by Klaus Aehlig's avatar Klaus Aehlig

Merge branch 'stable-2.10' into master

* stable-2.10
  Fix documentation
  Replace all constant definitions with re-exports
  Prepare constants for automatic reexport
  Hs2Py constants: 'hvsParameterTypes' and 'hvsParameters'
  Fix indentation that triggers PEP8 error
  Check if hotplug is supported in CheckPrereq

* stable-2.9
  Revision bump for 2.9.0
  Schedule release of 2.9.0

* stable-2.8
  Improve error message for replace-disks
Signed-off-by: default avatarKlaus Aehlig <aehlig@google.com>
Reviewed-by: default avatarMichele Tartara <mtartara@google.com>
parents d5a9b556 8dd23148
......@@ -85,10 +85,10 @@ Python
version 1.0.1. It is still used for testing only.
Version 2.9.0 rc4
-----------------
Version 2.9.0
-------------
*(unreleased)*
*(Released Tue, 5 Nov 2013)*
Incompatible/important changes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
......@@ -159,6 +159,7 @@ Since 2.9.0 rc3
- Correctly start/stop luxid during gnt-cluster master-failover (inherited
from stable-2.8)
- Improved error messsages (inherited from stable-2.8)
Version 2.9.0 rc3
......
......@@ -2053,6 +2053,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.
......
......@@ -2842,6 +2842,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)
......@@ -3279,7 +3284,7 @@ class LUInstanceSetParams(LogicalUnit):
changes = [
("disk/%d" % idx,
"add:size=%s,mode=%s" % (disk.size, disk.mode)),
"add:size=%s,mode=%s" % (disk.size, disk.mode)),
]
if self.op.hotplug:
result = self.rpc.call_blockdev_assemble(self.instance.primary_node,
......
......@@ -2188,8 +2188,15 @@ class TLReplaceDisks(Tasklet):
if msg or not result.payload:
if not msg:
msg = "disk not found"
raise errors.OpExecError("Can't find disk/%d on node %s: %s" %
(idx, self.cfg.GetNodeName(node_uuid), msg))
if not self._CheckDisksActivated(self.instance):
extra_hint = ("\nDisks seem to be not properly activated. Try"
" running activate-disks on the instance before"
" using replace-disks.")
else:
extra_hint = ""
raise errors.OpExecError("Can't find disk/%d on node %s: %s%s" %
(idx, self.cfg.GetNodeName(node_uuid), msg,
extra_hint))
def _CheckDisksConsistency(self, node_uuid, on_primary, ldisk):
for idx, dev in enumerate(self.instance.disks):
......
This diff is collapsed.
......@@ -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 = [
......
......@@ -622,6 +622,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.
......
......@@ -1027,7 +1027,7 @@ rieHandshake = "Hi, I'm Ganeti"
rieVersion :: Int
rieVersion = 0
-- | Remote import/export certificate validity in seconds
-- | Remote import/export certificate validity (seconds)
rieCertValidity :: Int
rieCertValidity = 24 * 60 * 60
......@@ -1180,11 +1180,11 @@ minVgSize = 20480
defaultMacPrefix :: String
defaultMacPrefix = "aa:00:00"
-- | Default maximum instance wait time, in seconds.
-- | Default maximum instance wait time (seconds)
defaultShutdownTimeout :: Int
defaultShutdownTimeout = 120
-- | Node clock skew in seconds
-- | Node clock skew (seconds)
nodeMaxClockSkew :: Int
nodeMaxClockSkew = 150
......@@ -4303,10 +4303,10 @@ hotplugAllTargets :: FrozenSet String
hotplugAllTargets =
ConstantUtils.mkSet $ map Types.hotplugTargetToRaw [minBound..]
-- | Timeout for disk removal
-- | Timeout for disk removal (seconds)
diskRemoveRetryTimeout :: Int
diskRemoveRetryTimeout = 30
-- | Intervall between disk removal retries
-- | Interval between disk removal retries (seconds)
diskRemoveRetryInterval :: Int
diskRemoveRetryInterval = 3
......@@ -1997,6 +1997,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):
......@@ -2087,6 +2088,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):
......@@ -2111,6 +2113,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):
......@@ -2199,6 +2202,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)
......@@ -2212,6 +2216,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)
......
......@@ -213,9 +213,9 @@ class TestClient(object):
{"type": constants.CONFD_REQ_CLUSTER_MASTER},
{"type": constants.CONFD_REQ_CLUSTER_MASTER,
"query": {constants.CONFD_REQQ_FIELDS:
[constants.CONFD_REQFIELD_NAME,
constants.CONFD_REQFIELD_IP,
constants.CONFD_REQFIELD_MNODE_PIP,
[str(constants.CONFD_REQFIELD_NAME),
str(constants.CONFD_REQFIELD_IP),
str(constants.CONFD_REQFIELD_MNODE_PIP),
]}},
{"type": constants.CONFD_REQ_NODE_ROLE_BYNAME},
{"type": constants.CONFD_REQ_NODE_PIP_LIST},
......
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