diff --git a/daemons/ganeti-noded b/daemons/ganeti-noded index 12f6b7a48b35f791b33593dc72b0409486bd5b78..665b84c3c3d2892b6b36b212ea682fae38d5ead3 100755 --- a/daemons/ganeti-noded +++ b/daemons/ganeti-noded @@ -135,7 +135,7 @@ class ServerObject(pb.Avatar): return backend.ShutdownBlockDevice(bdev) @staticmethod - def perspective_blockdev_addchild(params): + def perspective_blockdev_addchildren(params): """Add a child to a mirror device. Note: this is only valid for mirror devices. It's the caller's duty @@ -144,13 +144,13 @@ class ServerObject(pb.Avatar): """ bdev_s, ndev_s = params bdev = objects.Disk.FromDict(bdev_s) - ndev = objects.Disk.FromDict(ndev_s) - if bdev is None or ndev is None: + ndevs = [objects.Disk.FromDict(disk_s) for disk_s in ndev_s] + if bdev is None or ndevs.count(None) > 0: raise ValueError("can't unserialize data!") - return backend.MirrorAddChild(bdev, ndev) + return backend.MirrorAddChildren(bdev, ndevs) @staticmethod - def perspective_blockdev_removechild(params): + def perspective_blockdev_removechildren(params): """Remove a child from a mirror device. This is only valid for mirror devices, of course. It's the callers @@ -159,10 +159,10 @@ class ServerObject(pb.Avatar): """ bdev_s, ndev_s = params bdev = objects.Disk.FromDict(bdev_s) - ndev = objects.Disk.FromDict(ndev_s) - if bdev is None or ndev is None: + ndevs = [objects.Disk.FromDict(disk_s) for disk_s in ndev_s] + if bdev is None or ndevs.count(None) > 0: raise ValueError("can't unserialize data!") - return backend.MirrorRemoveChild(bdev, ndev) + return backend.MirrorRemoveChildren(bdev, ndevs) @staticmethod def perspective_blockdev_getmirrorstatus(params): diff --git a/lib/backend.py b/lib/backend.py index 78ce3816d35304b92125fff6e938c8a714607861..56dab650d82fb2fb0d159f4bf331f6be872c39ee 100644 --- a/lib/backend.py +++ b/lib/backend.py @@ -768,35 +768,33 @@ def ShutdownBlockDevice(disk): return result -def MirrorAddChild(md_cdev, new_cdev): - """Extend an MD raid1 array. +def MirrorAddChildren(parent_cdev, new_cdevs): + """Extend a mirrored block device. """ - md_bdev = _RecursiveFindBD(md_cdev, allow_partial=True) - if md_bdev is None: - logger.Error("Can't find md device") + parent_bdev = _RecursiveFindBD(parent_cdev, allow_partial=True) + if parent_bdev is None: + logger.Error("Can't find parent device") return False - new_bdev = _RecursiveFindBD(new_cdev) - if new_bdev is None: - logger.Error("Can't find new device to add") + new_bdevs = [_RecursiveFindBD(disk) for disk in new_cdevs] + if new_bdevs.count(None) > 0: + logger.Error("Can't find new device(s) to add") return False - new_bdev.Open() - md_bdev.AddChild(new_bdev) + parent_bdev.AddChildren(new_bdevs) return True -def MirrorRemoveChild(md_cdev, new_cdev): - """Reduce an MD raid1 array. +def MirrorRemoveChildren(parent_cdev, new_cdevs): + """Shrink a mirrored block device. """ - md_bdev = _RecursiveFindBD(md_cdev) - if md_bdev is None: + parent_bdev = _RecursiveFindBD(parent_cdev) + if parent_bdev is None: return False - new_bdev = _RecursiveFindBD(new_cdev) - if new_bdev is None: + new_bdevs = [_RecursiveFindBD(disk) for disk in new_cdevs] + if new_bdevs.count(None) > 0: return False - new_bdev.Open() - md_bdev.RemoveChild(new_bdev.dev_path) + parent_bdev.RemoveChildren(new_bdevs) return True diff --git a/lib/bdev.py b/lib/bdev.py index 0e8ddf4d48e8e9353d0f173a558accc69a542cc6..a01f813051ecfceb55eab2b547869ecfdc38978d 100644 --- a/lib/bdev.py +++ b/lib/bdev.py @@ -701,59 +701,71 @@ class MDRaid1(BlockDev): return self.Shutdown() - def AddChild(self, device): - """Add a new member to the md raid1. + def AddChildren(self, devices): + """Add new member(s) to the md raid1. """ if self.minor is None and not self.Attach(): raise errors.BlockDeviceError("Can't attach to device") - if device.dev_path is None: - raise errors.BlockDeviceError("New child is not initialised") - result = utils.RunCmd(["mdadm", "-a", self.dev_path, device.dev_path]) + + args = ["mdadm", "-a", self.dev_path] + for dev in devices: + if dev.dev_path is None: + raise errors.BlockDeviceError("Child '%s' is not initialised" % dev) + dev.Open() + args.append(dev.dev_path) + result = utils.RunCmd(args) if result.failed: raise errors.BlockDeviceError("Failed to add new device to array: %s" % result.output) - new_len = len(self._children) + 1 + new_len = len(self._children) + len(devices) result = utils.RunCmd(["mdadm", "--grow", self.dev_path, "-n", new_len]) if result.failed: raise errors.BlockDeviceError("Can't grow md array: %s" % result.output) - self._children.append(device) + self._children.extend(devices) - def RemoveChild(self, dev_path): - """Remove member from the md raid1. + def RemoveChildren(self, devices): + """Remove member(s) from the md raid1. """ if self.minor is None and not self.Attach(): raise errors.BlockDeviceError("Can't attach to device") - if len(self._children) == 1: - raise errors.BlockDeviceError("Can't reduce member when only one" - " child left") - for device in self._children: - if device.dev_path == dev_path: - break - else: - raise errors.BlockDeviceError("Can't find child with this path") - new_len = len(self._children) - 1 - result = utils.RunCmd(["mdadm", "-f", self.dev_path, dev_path]) + new_len = len(self._children) - len(devices) + if new_len < 1: + raise errors.BlockDeviceError("Can't reduce to less than one child") + args = ["mdadm", "-f", self.dev_path] + orig_devs = [] + for dev in devices: + args.append(dev.dev_path) + for c in self._children: + if c.dev_path == dev.dev_path: + orig_devs.append(c) + break + else: + raise errors.BlockDeviceError("Can't find device '%s' for removal" % + dev) + result = utils.RunCmd(args) if result.failed: - raise errors.BlockDeviceError("Failed to mark device as failed: %s" % + raise errors.BlockDeviceError("Failed to mark device(s) as failed: %s" % result.output) # it seems here we need a short delay for MD to update its # superblocks time.sleep(0.5) - result = utils.RunCmd(["mdadm", "-r", self.dev_path, dev_path]) + args[1] = "-r" + result = utils.RunCmd(args) if result.failed: - raise errors.BlockDeviceError("Failed to remove device from array:" - " %s" % result.output) + raise errors.BlockDeviceError("Failed to remove device(s) from array:" + " %s" % result.output) result = utils.RunCmd(["mdadm", "--grow", "--force", self.dev_path, "-n", new_len]) if result.failed: raise errors.BlockDeviceError("Can't shrink md array: %s" % result.output) - self._children.remove(device) + for dev in orig_devs: + self._children.remove(dev) def GetStatus(self): diff --git a/lib/cmdlib.py b/lib/cmdlib.py index ab433ed09a0f23a9770a7ab61f1f9bdf4dd388f2..04612d77bb1e1500b8152f45749d23b84f3b96bc 100644 --- a/lib/cmdlib.py +++ b/lib/cmdlib.py @@ -3223,8 +3223,8 @@ class LUAddMDDRBDComponent(LogicalUnit): # the device exists now # call the primary node to add the mirror to md logger.Info("adding new mirror component to md") - if not rpc.call_blockdev_addchild(instance.primary_node, - disk, new_drbd): + if not rpc.call_blockdev_addchildren(instance.primary_node, + disk, [new_drbd]): logger.Error("Can't add mirror compoment to md!") self.cfg.SetDiskID(new_drbd, remote_node) if not rpc.call_blockdev_remove(remote_node, new_drbd): @@ -3316,8 +3316,8 @@ class LURemoveMDDRBDComponent(LogicalUnit): child = self.child logger.Info("remove mirror component") self.cfg.SetDiskID(disk, instance.primary_node) - if not rpc.call_blockdev_removechild(instance.primary_node, - disk, child): + if not rpc.call_blockdev_removechildren(instance.primary_node, + disk, [child]): raise errors.OpExecError("Can't remove child from mirror.") for node in child.logical_id[:2]: @@ -3427,8 +3427,8 @@ class LUReplaceDisks(LogicalUnit): # the device exists now # call the primary node to add the mirror to md logger.Info("adding new mirror component to md") - if not rpc.call_blockdev_addchild(instance.primary_node, dev, - new_drbd): + if not rpc.call_blockdev_addchildren(instance.primary_node, dev, + [new_drbd]): logger.Error("Can't add mirror compoment to md!") cfg.SetDiskID(new_drbd, remote_node) if not rpc.call_blockdev_remove(remote_node, new_drbd): @@ -3462,8 +3462,8 @@ class LUReplaceDisks(LogicalUnit): dev, child, new_drbd = iv_names[name] logger.Info("remove mirror %s component" % name) cfg.SetDiskID(dev, instance.primary_node) - if not rpc.call_blockdev_removechild(instance.primary_node, - dev, child): + if not rpc.call_blockdev_removechildren(instance.primary_node, + dev, [child]): logger.Error("Can't remove child from mirror, aborting" " *this device cleanup*.\nYou need to cleanup manually!!") continue diff --git a/lib/rpc.py b/lib/rpc.py index f545e79d0432b4a43979203c31ea5e35d0f7356b..4153da8f58d9628863275c54883a3de594a76309 100644 --- a/lib/rpc.py +++ b/lib/rpc.py @@ -539,27 +539,27 @@ def call_blockdev_shutdown(node, disk): return c.getresult().get(node, False) -def call_blockdev_addchild(node, bdev, ndev): - """Request adding a new child to a (mirroring) device. +def call_blockdev_addchildren(node, bdev, ndevs): + """Request adding a list of children to a (mirroring) device. This is a single-node call. """ - params = [bdev.ToDict(), ndev.ToDict()] - c = Client("blockdev_addchild", params) + params = [bdev.ToDict(), [disk.ToDict() for disk in ndevs]] + c = Client("blockdev_addchildren", params) c.connect(node) c.run() return c.getresult().get(node, False) -def call_blockdev_removechild(node, bdev, ndev): - """Request removing a new child from a (mirroring) device. +def call_blockdev_removechildren(node, bdev, ndevs): + """Request removing a list of children from a (mirroring) device. This is a single-node call. """ - params = [bdev.ToDict(), ndev.ToDict()] - c = Client("blockdev_removechild", params) + params = [bdev.ToDict(), [disk.ToDict() for disk in ndevs]] + c = Client("blockdev_removechildren", params) c.connect(node) c.run() return c.getresult().get(node, False)