Commit 6b31e28f authored by Dimitris Aragiorgis's avatar Dimitris Aragiorgis Committed by Klaus Aehlig
Browse files

Support disk hotplug with userspace access



Before any hotplug action we assemble the block device. Currently
call_blockdev_assemble() returns the link_name as calculated by
_SymlinkBlockDev().

With userspace support we have to return the drive_uri as calculated
by _CalculateDeviceURI() as well, in order for the drive_add monitor
command to be able to use it.

Additionally with this patch the runtime files are properly updated
to include the drive uri as well, and thus, upon instance migration,
the target process will be started with the correct drive options.
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 9179f383
......@@ -1978,8 +1978,8 @@ def HotplugDevice(instance, action, dev_type, device, extra, seq):
@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 extra: tuple
@param extra: extra info used for disk hotplug (disk link, drive uri)
@type seq: int
@param seq: the index of the device from master perspective
@raise RPCFail: in case instance does not have KVM hypervisor
......@@ -2268,7 +2268,7 @@ def _RecursiveAssembleBD(disk, owner, as_primary):
return result
def BlockdevAssemble(disk, owner, as_primary, idx):
def BlockdevAssemble(disk, instance, as_primary, idx):
"""Activate a block device for an instance.
This is a wrapper over _RecursiveAssembleBD.
......@@ -2279,13 +2279,15 @@ def BlockdevAssemble(disk, owner, as_primary, idx):
"""
try:
result = _RecursiveAssembleBD(disk, owner, as_primary)
result = _RecursiveAssembleBD(disk, instance.name, as_primary)
if isinstance(result, BlockDev):
# pylint: disable=E1103
dev_path = result.dev_path
link_name = None
uri = None
if as_primary:
link_name = _SymlinkBlockDev(owner, dev_path, idx)
link_name = _SymlinkBlockDev(instance.name, dev_path, idx)
uri = _CalculateDeviceURI(instance, disk, result)
elif result:
return result, result
else:
......@@ -2295,7 +2297,7 @@ def BlockdevAssemble(disk, owner, as_primary, idx):
except OSError, err:
_Fail("Error while symlinking disk: %s", err, exc=True)
return dev_path, link_name
return dev_path, link_name, uri
def BlockdevShutdown(disk):
......
......@@ -1884,7 +1884,7 @@ class LUInstanceMove(LogicalUnit):
idx, result.fail_msg)
errs.append(result.fail_msg)
break
dev_path, _ = result.payload
dev_path, _, __ = result.payload
result = self.rpc.call_blockdev_export(source_node.uuid, (disk,
self.instance),
target_node.secondary_ip,
......@@ -3353,16 +3353,16 @@ class LUInstanceSetParams(LogicalUnit):
if self.op.hotplug:
result = self.rpc.call_blockdev_assemble(self.instance.primary_node,
(disk, self.instance),
self.instance.name, True, idx)
self.instance, True, idx)
if result.fail_msg:
changes.append(("disk/%d" % idx, "assemble:failed"))
self.LogWarning("Can't assemble newly created disk %d: %s",
idx, result.fail_msg)
else:
_, link_name = result.payload
_, link_name, uri = result.payload
msg = self._HotplugDevice(constants.HOTPLUG_ACTION_ADD,
constants.HOTPLUG_TARGET_DISK,
disk, link_name, idx)
disk, (link_name, uri), idx)
changes.append(("disk/%d" % idx, msg))
return (disk, changes)
......
......@@ -1295,7 +1295,7 @@ def AssembleInstanceDisks(lu, instance, disks=None, ignore_secondaries=False,
node_disk = node_disk.Copy()
node_disk.UnsetSize()
result = lu.rpc.call_blockdev_assemble(node_uuid, (node_disk, instance),
instance.name, False, idx)
instance, False, idx)
msg = result.fail_msg
if msg:
is_offline_secondary = (node_uuid in instance.secondary_nodes and
......@@ -1320,7 +1320,7 @@ def AssembleInstanceDisks(lu, instance, disks=None, ignore_secondaries=False,
node_disk = node_disk.Copy()
node_disk.UnsetSize()
result = lu.rpc.call_blockdev_assemble(node_uuid, (node_disk, instance),
instance.name, True, idx)
instance, True, idx)
msg = result.fail_msg
if msg:
lu.LogWarning("Could not prepare block device %s on node %s"
......@@ -1328,7 +1328,7 @@ def AssembleInstanceDisks(lu, instance, disks=None, ignore_secondaries=False,
inst_disk.iv_name, lu.cfg.GetNodeName(node_uuid), msg)
disks_ok = False
else:
dev_path, _ = result.payload
dev_path, _, __ = result.payload
device_info.append((lu.cfg.GetNodeName(instance.primary_node),
inst_disk.iv_name, dev_path))
......
......@@ -112,10 +112,31 @@ _RUNTIME_DEVICE = {
}
_RUNTIME_ENTRY = {
constants.HOTPLUG_TARGET_NIC: lambda d, e: d,
constants.HOTPLUG_TARGET_DISK: lambda d, e: (d, e, None)
constants.HOTPLUG_TARGET_DISK: lambda d, e: (d, e[0], e[1])
}
def _GetDriveURI(disk, link, uri):
"""Helper function to get the drive uri to be used in --drive kvm option
@type disk: L{objects.Disk}
@param disk: A disk configuration object
@type link: string
@param link: The device link as returned by _SymlinkBlockDev()
@type uri: string
@param uri: The drive uri as returned by _CalculateDeviceURI()
"""
access_mode = disk.params.get(constants.LDP_ACCESS,
constants.DISK_KERNELSPACE)
if (uri and access_mode == constants.DISK_USERSPACE):
drive_uri = uri
else:
drive_uri = link
return drive_uri
def _GenerateDeviceKVMId(dev_type, dev):
"""Helper function to generate a unique device name used by KVM
......@@ -1304,12 +1325,7 @@ class KVMHypervisor(hv_base.BaseHypervisor):
if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
boot_val = ",boot=on"
access_mode = cfdev.params.get(constants.LDP_ACCESS,
constants.DISK_KERNELSPACE)
if (uri and access_mode == constants.DISK_USERSPACE):
drive_uri = uri
else:
drive_uri = link_name
drive_uri = _GetDriveURI(cfdev, link_name, uri)
drive_val = "file=%s,format=raw%s%s%s" % \
(drive_uri, if_val, boot_val, cache_val)
......@@ -2152,8 +2168,9 @@ class KVMHypervisor(hv_base.BaseHypervisor):
kvm_devid = _GenerateDeviceKVMId(dev_type, device)
runtime = self._LoadKVMRuntime(instance)
if dev_type == constants.HOTPLUG_TARGET_DISK:
drive_uri = _GetDriveURI(device, extra[0], extra[1])
cmds = ["drive_add dummy file=%s,if=none,id=%s,format=raw" %
(extra, kvm_devid)]
(drive_uri, kvm_devid)]
cmds += ["device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
(hex(device.pci), kvm_devid, kvm_devid)]
elif dev_type == constants.HOTPLUG_TARGET_NIC:
......
......@@ -380,7 +380,7 @@ _BLOCKDEV_CALLS = [
], None, None, "Request a pause/resume of given block device"),
("blockdev_assemble", SINGLE, None, constants.RPC_TMO_NORMAL, [
("disk", ED_SINGLE_DISK_DICT_DP, None),
("owner", None, None),
("instance", ED_INST_DICT, None),
("on_primary", None, None),
("idx", None, None),
], None, None, "Request assembling of a given block device"),
......
......@@ -253,11 +253,12 @@ class NodeRequestHandler(http.server.HttpServerHandler):
"""Assemble a block device.
"""
bdev_s, owner, on_primary, idx = params
bdev_s, idict, on_primary, idx = params
bdev = objects.Disk.FromDict(bdev_s)
instance = objects.Instance.FromDict(idict)
if bdev is None:
raise ValueError("can't unserialize data!")
return backend.BlockdevAssemble(bdev, owner, on_primary, idx)
return backend.BlockdevAssemble(bdev, instance, on_primary, idx)
@staticmethod
def perspective_blockdev_shutdown(params):
......
......@@ -105,7 +105,8 @@ class TestLUBackupExportBase(CmdlibTestCase):
self.rpc.call_blockdev_assemble.return_value = \
self.RpcResultsBuilder() \
.CreateSuccessfulNodeResult(self.master, ("/dev/mock_path",
"/dev/mock_link_name"))
"/dev/mock_link_name",
None))
self.rpc.call_blockdev_shutdown.return_value = \
self.RpcResultsBuilder() \
......
......@@ -128,7 +128,8 @@ class TestLUInstanceFailover(CmdlibTestCase):
.CreateSuccessfulNodeResult(self.master, True)
self.rpc.call_blockdev_assemble.return_value = \
self.RpcResultsBuilder() \
.CreateSuccessfulNodeResult(self.snode, ("/dev/mock", "/var/mock"))
.CreateSuccessfulNodeResult(self.snode,
("/dev/mock", "/var/mock", None))
self.rpc.call_instance_start.return_value = \
self.RpcResultsBuilder() \
.CreateSuccessfulNodeResult(self.snode, True)
......
......@@ -1485,7 +1485,8 @@ class TestLUInstanceMove(CmdlibTestCase):
self.rpc.call_blockdev_assemble.return_value = \
self.RpcResultsBuilder() \
.CreateSuccessfulNodeResult(self.node, ("/dev/mocked_path",
"/var/run/ganeti/instance-disks/mocked_d"))
"/var/run/ganeti/instance-disks/mocked_d",
None))
self.rpc.call_blockdev_export.return_value = \
self.RpcResultsBuilder() \
.CreateSuccessfulNodeResult(self.master, "")
......@@ -1601,7 +1602,7 @@ class TestLUInstanceRename(CmdlibTestCase):
def testFileInstance(self):
self.rpc.call_blockdev_assemble.return_value = \
self.RpcResultsBuilder() \
.CreateSuccessfulNodeResult(self.master, (None, None))
.CreateSuccessfulNodeResult(self.master, (None, None, None))
self.rpc.call_blockdev_shutdown.return_value = \
self.RpcResultsBuilder() \
.CreateSuccessfulNodeResult(self.master, None)
......@@ -2195,7 +2196,8 @@ class TestLUInstanceSetParams(CmdlibTestCase):
self.rpc.call_blockdev_assemble.return_value = \
self.RpcResultsBuilder() \
.CreateSuccessfulNodeResult(self.master, ("/dev/mocked_path",
"/var/run/ganeti/instance-disks/mocked_d"))
"/var/run/ganeti/instance-disks/mocked_d",
None))
op = self.CopyOpCode(self.op,
disks=[[constants.DDM_ADD, -1,
{
......
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