Commit f3e513ad authored by Iustin Pop's avatar Iustin Pop
Browse files

Implement block device renaming

This patch add code for renaming a device; more precisely, for changing
the unique_id of the device. This means:
  - logical volumes, rename the volume
  - drbd8, change the remote peer

This is needed for the being able to replace disks for drbd8.

Reviewed-by: imsnah
parent cc0451f3
...@@ -112,6 +112,14 @@ class ServerObject(pb.Avatar): ...@@ -112,6 +112,14 @@ class ServerObject(pb.Avatar):
bdev = objects.Disk.FromDict(bdev_s) bdev = objects.Disk.FromDict(bdev_s)
return backend.RemoveBlockDevice(bdev) return backend.RemoveBlockDevice(bdev)
@staticmethod
def perspective_blockdev_rename(params):
"""Remove a block device.
"""
devlist = [(objects.Disk.FromDict(ds), uid) for ds, uid in params]
return backend.RenameBlockDevices(devlist)
@staticmethod @staticmethod
def perspective_blockdev_assemble(params): def perspective_blockdev_assemble(params):
"""Assemble a block device. """Assemble a block device.
......
...@@ -1337,6 +1337,29 @@ def RemoveExport(export): ...@@ -1337,6 +1337,29 @@ def RemoveExport(export):
return True return True
def RenameBlockDevices(devlist):
"""Rename a list of block devices.
The devlist argument is a list of tuples (disk, new_logical,
new_physical). The return value will be a combined boolean result
(True only if all renames succeeded).
"""
result = True
for disk, unique_id in devlist:
dev = _RecursiveFindBD(disk)
if dev is None:
result = False
continue
try:
dev.Rename(unique_id)
except errors.BlockDeviceError, err:
logger.Error("Can't rename device '%s' to '%s': %s" %
(dev, unique_id, err))
result = False
return result
class HooksRunner(object): class HooksRunner(object):
"""Hook runner. """Hook runner.
......
...@@ -172,6 +172,15 @@ class BlockDev(object): ...@@ -172,6 +172,15 @@ class BlockDev(object):
raise NotImplementedError raise NotImplementedError
def Rename(self, new_id):
"""Rename this device.
This may or may not make sense for a given device type.
"""
raise NotImplementedError
def GetStatus(self): def GetStatus(self):
"""Return the status of the device. """Return the status of the device.
...@@ -368,6 +377,21 @@ class LogicalVolume(BlockDev): ...@@ -368,6 +377,21 @@ class LogicalVolume(BlockDev):
return not result.failed return not result.failed
def Rename(self, new_id):
"""Rename this logical volume.
"""
if not isinstance(new_id, (tuple, list)) or len(new_id) != 2:
raise errors.ProgrammerError("Invalid new logical id '%s'" % new_id)
new_vg, new_name = new_id
if new_vg != self._vg_name:
raise errors.ProgrammerError("Can't move a logical volume across"
" volume groups (from %s to to %s)" %
(self._vg_name, new_vg))
result = utils.RunCmd(["lvrename", new_vg, self._lv_name, new_name])
if result.failed:
raise errors.BlockDeviceError("Failed to rename the logical volume: %s" %
result.output)
def Attach(self): def Attach(self):
"""Attach to an existing LV. """Attach to an existing LV.
...@@ -700,6 +724,13 @@ class MDRaid1(BlockDev): ...@@ -700,6 +724,13 @@ class MDRaid1(BlockDev):
#TODO: maybe zero superblock on child devices? #TODO: maybe zero superblock on child devices?
return self.Shutdown() return self.Shutdown()
def Rename(self, new_id):
"""Rename a device.
This is not supported for md raid1 devices.
"""
raise errors.ProgrammerError("Can't rename a md raid1 device")
def AddChildren(self, devices): def AddChildren(self, devices):
"""Add new member(s) to the md raid1. """Add new member(s) to the md raid1.
...@@ -1056,6 +1087,14 @@ class BaseDRBD(BlockDev): ...@@ -1056,6 +1087,14 @@ class BaseDRBD(BlockDev):
return False return False
return True return True
def Rename(self, new_id):
"""Rename a device.
This is not supported for drbd devices.
"""
raise errors.ProgrammerError("Can't rename a drbd device")
class DRBDev(BaseDRBD): class DRBDev(BaseDRBD):
"""DRBD block device. """DRBD block device.
...@@ -1562,6 +1601,7 @@ class DRBDev(BaseDRBD): ...@@ -1562,6 +1601,7 @@ class DRBDev(BaseDRBD):
""" """
return self.Shutdown() return self.Shutdown()
class DRBD8(BaseDRBD): class DRBD8(BaseDRBD):
"""DRBD v8.x block device. """DRBD v8.x block device.
...@@ -2041,6 +2081,17 @@ class DRBD8(BaseDRBD): ...@@ -2041,6 +2081,17 @@ class DRBD8(BaseDRBD):
self._SetFromMinor(minor) self._SetFromMinor(minor)
return True return True
@classmethod
def _ShutdownNet(cls, minor):
"""Disconnect from the remote peer.
This fails if we don't have a local device.
"""
result = utils.RunCmd(["drbdsetup", cls._DevPath(minor), "disconnect"])
logger.Error("Can't shutdown network: %s" % result.output)
return not result.failed
@classmethod @classmethod
def _ShutdownAll(cls, minor): def _ShutdownAll(cls, minor):
"""Deactivate the device. """Deactivate the device.
...@@ -2066,6 +2117,27 @@ class DRBD8(BaseDRBD): ...@@ -2066,6 +2117,27 @@ class DRBD8(BaseDRBD):
self.dev_path = None self.dev_path = None
return True return True
def Rename(self, new_uid):
"""Re-connect this device to another peer.
"""
if self.minor is None:
raise errors.BlockDeviceError("Device not attached during rename")
if self._rhost is not None:
# this means we did have a host when we attached, so we are connected
if not self._ShutdownNet(self.minor):
raise errors.BlockDeviceError("Can't disconnect from remote peer")
old_id = self.unique_id
else:
old_id = None
self.unique_id = new_uid
if not self._AssembleNet(self.minor, self.unique_id, "C"):
logger.Error("Can't attach to new peer!")
if self.old_id is not None:
self._AssembleNet(self.minor, old_id, "C")
self.unique_id = old_id
raise errors.BlockDeviceError("Can't attach to new peer")
def Remove(self): def Remove(self):
"""Stub remove for DRBD devices. """Stub remove for DRBD devices.
......
...@@ -514,6 +514,19 @@ def call_blockdev_remove(node, bdev): ...@@ -514,6 +514,19 @@ def call_blockdev_remove(node, bdev):
return c.getresult().get(node, False) return c.getresult().get(node, False)
def call_blockdev_rename(node, devlist):
"""Request rename of the given block devices.
This is a single-node call.
"""
params = [(d.ToDict(), uid) for d, uid in devlist]
c = Client("blockdev_rename", params)
c.connect(node)
c.run()
return c.getresult().get(node, False)
def call_blockdev_assemble(node, disk, on_primary): def call_blockdev_assemble(node, disk, on_primary):
"""Request assembling of a given block device. """Request assembling of a given block device.
......
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