Commit 96acbc09 authored by Michael Hanselmann's avatar Michael Hanselmann
Browse files

Use object for blockdev_find RPC call result

This patch changes the return type for backend.BlockdevFind to an object
(objects.BlockDevStatus). Before a tuple was used. Adding more values to
this tuple causes a lot of work.  Converting the result to an object with
properties will make this a bit simpler.
Signed-off-by: default avatarMichael Hanselmann <>
Reviewed-by: default avatarGuido Trotter <>
parent 53548798
......@@ -213,7 +213,7 @@ class NodeHttpServer(http.server.HttpServer):
disk = objects.Disk.FromDict(params[0])
return backend.BlockdevFind(disk)
return backend.BlockdevFind(disk).ToDict()
def perspective_blockdev_snapshot(params):
......@@ -1384,7 +1384,12 @@ def BlockdevGetmirrorstatus(disks):
rbd = _RecursiveFindBD(dsk)
if rbd is None:
_Fail("Can't find device %s", dsk)
dstatus = rbd.CombinedSyncStatus()
stats.append((dstatus.sync_percent, dstatus.estimated_time,
dstatus.is_degraded, dstatus.ldisk_degraded))
return stats
......@@ -1415,19 +1420,20 @@ def BlockdevFind(disk):
@type disk: L{objects.Disk}
@param disk: the disk to find
@rtype: None or tuple
@return: None if the disk cannot be found, otherwise a
tuple (device_path, major, minor, sync_percent,
estimated_time, is_degraded)
@rtype: None or objects.BlockDevStatus
@return: None if the disk cannot be found, otherwise a the current
rbd = _RecursiveFindBD(disk)
except errors.BlockDeviceError, err:
_Fail("Failed to find device: %s", err, exc=True)
if rbd is None:
return None
return (rbd.dev_path, rbd.major, rbd.minor) + rbd.GetSyncStatus()
return rbd.GetSyncStatus()
def UploadFile(file_name, data, mode, uid, gid, atime, mtime):
......@@ -31,6 +31,7 @@ import logging
from ganeti import utils
from ganeti import errors
from ganeti import constants
from ganeti import objects
def _IgnoreError(fn, *args, **kwargs):
......@@ -228,12 +229,16 @@ class BlockDev(object):
data. This is only valid for some devices, the rest will always
return False (not degraded).
@rtype: tuple
@return: (sync_percent, estimated_time, is_degraded, ldisk)
@rtype: objects.BlockDevStatus
return None, None, False, False
return objects.BlockDevStatus(dev_path=self.dev_path,
def CombinedSyncStatus(self):
"""Calculate the mirror status recursively for our children.
......@@ -242,22 +247,40 @@ class BlockDev(object):
minimum percent and maximum time are calculated across our
@rtype: objects.BlockDevStatus
min_percent, max_time, is_degraded, ldisk = self.GetSyncStatus()
status = self.GetSyncStatus()
min_percent = status.sync_percent
max_time = status.estimated_time
is_degraded = status.is_degraded
ldisk_degraded = status.ldisk_degraded
if self._children:
for child in self._children:
c_percent, c_time, c_degraded, c_ldisk = child.GetSyncStatus()
child_status = child.GetSyncStatus()
if min_percent is None:
min_percent = c_percent
elif c_percent is not None:
min_percent = min(min_percent, c_percent)
min_percent = child_status.sync_percent
elif child_status.sync_percent is not None:
min_percent = min(min_percent, child_status.sync_percent)
if max_time is None:
max_time = c_time
elif c_time is not None:
max_time = max(max_time, c_time)
is_degraded = is_degraded or c_degraded
ldisk = ldisk or c_ldisk
return min_percent, max_time, is_degraded, ldisk
max_time = child_status.estimated_time
elif child_status.estimated_time is not None:
max_time = max(max_time, child_status.estimated_time)
is_degraded = is_degraded or child_status.is_degraded
ldisk_degraded = ldisk_degraded or child_status.ldisk_degraded
return objects.BlockDevStatus(dev_path=self.dev_path,
def SetInfo(self, text):
......@@ -506,11 +529,16 @@ class LogicalVolume(BlockDev):
The status was already read in Attach, so we just return it.
@rtype: tuple
@return: (sync_percent, estimated_time, is_degraded, ldisk)
@rtype: objects.BlockDevStatus
return None, None, self._degraded, self._degraded
return objects.BlockDevStatus(dev_path=self.dev_path,
def Open(self, force=False):
"""Make the device ready for I/O.
......@@ -1300,16 +1328,23 @@ class DRBD8(BaseDRBD):
We compute the ldisk parameter based on whether we have a local
disk or not.
@rtype: tuple
@return: (sync_percent, estimated_time, is_degraded, ldisk)
@rtype: objects.BlockDevStatus
if self.minor is None and not self.Attach():
_ThrowError("drbd%d: can't Attach() in GetSyncStatus", self._aminor)
stats = self.GetProcStatus()
ldisk = not stats.is_disk_uptodate
ldisk_degraded = not stats.is_disk_uptodate
is_degraded = not stats.is_connected
return stats.sync_percent, stats.est_time, is_degraded or ldisk, ldisk
return objects.BlockDevStatus(dev_path=self.dev_path,
is_degraded=(is_degraded or ldisk_degraded),
def Open(self, force=False):
"""Make the local state primary.
......@@ -607,6 +607,7 @@ def _BuildInstanceHookEnv(name, primary_node, secondary_nodes, os_type, status,
return env
def _NICListToTuple(lu, nics):
"""Build a list of nic information tuples.
......@@ -630,6 +631,7 @@ def _NICListToTuple(lu, nics):
hooks_nics.append((ip, mac, mode, link))
return hooks_nics
def _BuildInstanceHookEnvByObject(lu, instance, override=None):
"""Builds instance related env variables for hooks from an object.
......@@ -1872,12 +1874,9 @@ def _CheckDiskConsistency(lu, dev, node, on_primary, ldisk=False):
lu.cfg.SetDiskID(dev, node)
if ldisk:
idx = 6
idx = 5
result = True
if on_primary or dev.AssembleOnSecondary():
rstats = lu.rpc.call_blockdev_find(node, dev)
msg = rstats.fail_msg
......@@ -1888,7 +1887,11 @@ def _CheckDiskConsistency(lu, dev, node, on_primary, ldisk=False):
lu.LogWarning("Can't find disk on node %s", node)
result = False
result = result and (not rstats.payload[idx])
if ldisk:
result = result and not rstats.payload.ldisk_degraded
result = result and not rstats.payload.is_degraded
if dev.children:
for child in dev.children:
result = result and _CheckDiskConsistency(lu, child, node, on_primary)
......@@ -5885,7 +5888,7 @@ class TLReplaceDisks(Tasklet):
raise errors.OpExecError("Can't find DRBD device %s: %s" %
(name, msg))
if result.payload[5]:
if result.payload.is_degraded:
raise errors.OpExecError("DRBD device %s is degraded!" % name)
def _RemoveOldStorage(self, node_name, iv_names):
......@@ -6302,7 +6305,7 @@ class LUQueryInstanceData(NoHooksLU):
dev_pstatus = None
dev_pstatus.Raise("Can't compute disk status for %s" %
dev_pstatus = dev_pstatus.payload
dev_pstatus = dev_pstatus.payload.ToLegacyStatus()
dev_pstatus = None
......@@ -6320,7 +6323,7 @@ class LUQueryInstanceData(NoHooksLU):
dev_sstatus = None
dev_sstatus.Raise("Can't compute disk status for %s" %
dev_sstatus = dev_sstatus.payload
dev_sstatus = dev_sstatus.payload.ToLegacyStatus()
dev_sstatus = None
......@@ -39,6 +39,7 @@ from ganeti import constants
__all__ = ["ConfigObject", "ConfigData", "NIC", "Disk", "Instance",
"OS", "Node", "Cluster", "FillDict"]
def FillDict(defaults_dict, custom_dict):
"""Basic function to apply settings on top a default dict.
......@@ -864,6 +865,27 @@ class Cluster(TaggableObject):
class BlockDevStatus(ConfigObject):
"""Config object representing the status of a block device."""
__slots__ = [
def ToLegacyStatus(self):
"""Converts the device status to a legacy tuple.
return (self.dev_path, self.major, self.minor,
self.sync_percent, self.estimated_time,
self.is_degraded, self.ldisk_degraded)
class SerializableConfigParser(ConfigParser.SafeConfigParser):
"""Simple wrapper over ConfigParse that allows serialization.
......@@ -808,7 +808,10 @@ class RpcRunner(object):
This is a single-node call.
return self._SingleNodeCall(node, "blockdev_find", [disk.ToDict()])
result = self._SingleNodeCall(node, "blockdev_find", [disk.ToDict()])
if not result.failed and result.payload is not None:
result.payload = objects.BlockDevStatus.FromDict(result.payload)
return result
def call_blockdev_close(self, node, instance_name, disks):
"""Closes the given block devices.
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