Commit ef628379 authored by Guido Trotter's avatar Guido Trotter
Browse files

Allow disk operation to act on a subset of disks

If the disks= parameter is passed, we can assemble/wait for
sync/shutdown only some disks belonging to an instance, rather than all.

This is useful to only activate/sync/shutdown the affected disk when
growing it.
Signed-off-by: default avatarGuido Trotter <>
Reviewed-by: default avatarIustin Pop <>
parent 7cf722ea
......@@ -2588,19 +2588,21 @@ class LURedistributeConfig(NoHooksLU):
def _WaitForSync(lu, instance, oneshot=False):
def _WaitForSync(lu, instance, disks=None, oneshot=False):
"""Sleep and poll for an instance's disk to sync.
if not instance.disks:
if not instance.disks or disks is not None and not disks:
return True
disks = _ExpandCheckDisks(instance, disks)
if not oneshot:
lu.proc.LogInfo("Waiting for instance %s to sync disks." %
node = instance.primary_node
for dev in instance.disks:
for dev in disks:
lu.cfg.SetDiskID(dev, node)
# TODO: Convert to utils.Retry
......@@ -2611,7 +2613,7 @@ def _WaitForSync(lu, instance, oneshot=False):
max_time = 0
done = True
cumul_degraded = False
rstats = lu.rpc.call_blockdev_getmirrorstatus(node, instance.disks)
rstats = lu.rpc.call_blockdev_getmirrorstatus(node, disks)
msg = rstats.fail_msg
if msg:
lu.LogWarning("Can't get any data from node %s: %s", node, msg)
......@@ -2626,7 +2628,7 @@ def _WaitForSync(lu, instance, oneshot=False):
for i, mstat in enumerate(rstats):
if mstat is None:
lu.LogWarning("Can't compute data for node %s/%s",
node, instance.disks[i].iv_name)
node, disks[i].iv_name)
cumul_degraded = (cumul_degraded or
......@@ -2639,8 +2641,7 @@ def _WaitForSync(lu, instance, oneshot=False):
rem_time = "no time estimate"
lu.proc.LogInfo("- device %s: %5.2f%% done, %s" %
(instance.disks[i].iv_name, mstat.sync_percent,
(disks[i].iv_name, mstat.sync_percent, rem_time))
# if we're done but degraded, let's do a few small retries, to
# make sure we see a stable and not transient situation; therefore
......@@ -3875,7 +3876,7 @@ class LUActivateInstanceDisks(NoHooksLU):
return disks_info
def _AssembleInstanceDisks(lu, instance, ignore_secondaries=False,
def _AssembleInstanceDisks(lu, instance, disks=None, ignore_secondaries=False,
"""Prepare the block devices for an instance.
......@@ -3885,6 +3886,8 @@ def _AssembleInstanceDisks(lu, instance, ignore_secondaries=False,
@param lu: the logical unit on whose behalf we execute
@type instance: L{objects.Instance}
@param instance: the instance for whose disks we assemble
@type disks: list of L{objects.Disk} or None
@param disks: which disks to assemble (or all, if None)
@type ignore_secondaries: boolean
@param ignore_secondaries: if true, errors on secondary nodes
won't result in an error return from the function
......@@ -3900,6 +3903,8 @@ def _AssembleInstanceDisks(lu, instance, ignore_secondaries=False,
device_info = []
disks_ok = True
iname =
disks = _ExpandCheckDisks(instance, disks)
# With the two passes mechanism we try to reduce the window of
# opportunity for the race condition of switching DRBD to primary
# before handshaking occured, but we do not eliminate it
......@@ -3910,7 +3915,7 @@ def _AssembleInstanceDisks(lu, instance, ignore_secondaries=False,
# SyncSource, etc.)
# 1st pass, assemble on all nodes in secondary mode
for inst_disk in instance.disks:
for inst_disk in disks:
for node, node_disk in inst_disk.ComputeNodeTree(instance.primary_node):
if ignore_size:
node_disk = node_disk.Copy()
......@@ -3928,7 +3933,7 @@ def _AssembleInstanceDisks(lu, instance, ignore_secondaries=False,
# FIXME: race condition on drbd migration to primary
# 2nd pass, do only the primary node
for inst_disk in instance.disks:
for inst_disk in disks:
dev_path = None
for node, node_disk in inst_disk.ComputeNodeTree(instance.primary_node):
......@@ -3953,7 +3958,7 @@ def _AssembleInstanceDisks(lu, instance, ignore_secondaries=False,
# leave the disks configured for the primary node
# this is a workaround that would be fixed better by
# improving the logical/physical id handling
for disk in instance.disks:
for disk in disks:
lu.cfg.SetDiskID(disk, instance.primary_node)
return disks_ok, device_info
......@@ -4008,7 +4013,7 @@ class LUDeactivateInstanceDisks(NoHooksLU):
_SafeShutdownInstanceDisks(self, instance)
def _SafeShutdownInstanceDisks(lu, instance):
def _SafeShutdownInstanceDisks(lu, instance, disks=None):
"""Shutdown block devices of an instance.
This function checks if an instance is running, before calling
......@@ -4016,10 +4021,28 @@ def _SafeShutdownInstanceDisks(lu, instance):
_CheckInstanceDown(lu, instance, "cannot shutdown disks")
_ShutdownInstanceDisks(lu, instance)
_ShutdownInstanceDisks(lu, instance, disks=disks)
def _ExpandCheckDisks(instance, disks):
"""Return the instance disks selected by the disks list
@type disks: list of L{objects.Disk} or None
@param disks: selected disks
@rtype: list of L{objects.Disk}
@return: selected instance disks to act on
def _ShutdownInstanceDisks(lu, instance, ignore_primary=False):
if disks is None:
return instance.disks
if not set(disks).issubset(instance.disks):
raise errors.ProgrammerError("Can only act on disks belonging to the"
" target instance")
return disks
def _ShutdownInstanceDisks(lu, instance, disks=None, ignore_primary=False):
"""Shutdown block devices of an instance.
This does the shutdown on all nodes of the instance.
......@@ -4029,7 +4052,9 @@ def _ShutdownInstanceDisks(lu, instance, ignore_primary=False):
all_result = True
for disk in instance.disks:
disks = _ExpandCheckDisks(instance, disks)
for disk in disks:
for node, top_disk in disk.ComputeNodeTree(instance.primary_node):
lu.cfg.SetDiskID(top_disk, node)
result = lu.rpc.call_blockdev_shutdown(node, top_disk)
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