Revision 153d9724

b/daemons/ganeti-noded
135 135
    return backend.ShutdownBlockDevice(bdev)
136 136

  
137 137
  @staticmethod
138
  def perspective_blockdev_addchild(params):
138
  def perspective_blockdev_addchildren(params):
139 139
    """Add a child to a mirror device.
140 140

  
141 141
    Note: this is only valid for mirror devices. It's the caller's duty
......
144 144
    """
145 145
    bdev_s, ndev_s = params
146 146
    bdev = objects.Disk.FromDict(bdev_s)
147
    ndev = objects.Disk.FromDict(ndev_s)
148
    if bdev is None or ndev is None:
147
    ndevs = [objects.Disk.FromDict(disk_s) for disk_s in ndev_s]
148
    if bdev is None or ndevs.count(None) > 0:
149 149
      raise ValueError("can't unserialize data!")
150
    return backend.MirrorAddChild(bdev, ndev)
150
    return backend.MirrorAddChildren(bdev, ndevs)
151 151

  
152 152
  @staticmethod
153
  def perspective_blockdev_removechild(params):
153
  def perspective_blockdev_removechildren(params):
154 154
    """Remove a child from a mirror device.
155 155

  
156 156
    This is only valid for mirror devices, of course. It's the callers
......
159 159
    """
160 160
    bdev_s, ndev_s = params
161 161
    bdev = objects.Disk.FromDict(bdev_s)
162
    ndev = objects.Disk.FromDict(ndev_s)
163
    if bdev is None or ndev is None:
162
    ndevs = [objects.Disk.FromDict(disk_s) for disk_s in ndev_s]
163
    if bdev is None or ndevs.count(None) > 0:
164 164
      raise ValueError("can't unserialize data!")
165
    return backend.MirrorRemoveChild(bdev, ndev)
165
    return backend.MirrorRemoveChildren(bdev, ndevs)
166 166

  
167 167
  @staticmethod
168 168
  def perspective_blockdev_getmirrorstatus(params):
b/lib/backend.py
768 768
  return result
769 769

  
770 770

  
771
def MirrorAddChild(md_cdev, new_cdev):
772
  """Extend an MD raid1 array.
771
def MirrorAddChildren(parent_cdev, new_cdevs):
772
  """Extend a mirrored block device.
773 773

  
774 774
  """
775
  md_bdev = _RecursiveFindBD(md_cdev, allow_partial=True)
776
  if md_bdev is None:
777
    logger.Error("Can't find md device")
775
  parent_bdev = _RecursiveFindBD(parent_cdev, allow_partial=True)
776
  if parent_bdev is None:
777
    logger.Error("Can't find parent device")
778 778
    return False
779
  new_bdev = _RecursiveFindBD(new_cdev)
780
  if new_bdev is None:
781
    logger.Error("Can't find new device to add")
779
  new_bdevs = [_RecursiveFindBD(disk) for disk in new_cdevs]
780
  if new_bdevs.count(None) > 0:
781
    logger.Error("Can't find new device(s) to add")
782 782
    return False
783
  new_bdev.Open()
784
  md_bdev.AddChild(new_bdev)
783
  parent_bdev.AddChildren(new_bdevs)
785 784
  return True
786 785

  
787 786

  
788
def MirrorRemoveChild(md_cdev, new_cdev):
789
  """Reduce an MD raid1 array.
787
def MirrorRemoveChildren(parent_cdev, new_cdevs):
788
  """Shrink a mirrored block device.
790 789

  
791 790
  """
792
  md_bdev = _RecursiveFindBD(md_cdev)
793
  if md_bdev is None:
791
  parent_bdev = _RecursiveFindBD(parent_cdev)
792
  if parent_bdev is None:
794 793
    return False
795
  new_bdev = _RecursiveFindBD(new_cdev)
796
  if new_bdev is None:
794
  new_bdevs = [_RecursiveFindBD(disk) for disk in new_cdevs]
795
  if new_bdevs.count(None) > 0:
797 796
    return False
798
  new_bdev.Open()
799
  md_bdev.RemoveChild(new_bdev.dev_path)
797
  parent_bdev.RemoveChildren(new_bdevs)
800 798
  return True
801 799

  
802 800

  
b/lib/bdev.py
701 701
    return self.Shutdown()
702 702

  
703 703

  
704
  def AddChild(self, device):
705
    """Add a new member to the md raid1.
704
  def AddChildren(self, devices):
705
    """Add new member(s) to the md raid1.
706 706

  
707 707
    """
708 708
    if self.minor is None and not self.Attach():
709 709
      raise errors.BlockDeviceError("Can't attach to device")
710
    if device.dev_path is None:
711
      raise errors.BlockDeviceError("New child is not initialised")
712
    result = utils.RunCmd(["mdadm", "-a", self.dev_path, device.dev_path])
710

  
711
    args = ["mdadm", "-a", self.dev_path]
712
    for dev in devices:
713
      if dev.dev_path is None:
714
        raise errors.BlockDeviceError("Child '%s' is not initialised" % dev)
715
      dev.Open()
716
      args.append(dev.dev_path)
717
    result = utils.RunCmd(args)
713 718
    if result.failed:
714 719
      raise errors.BlockDeviceError("Failed to add new device to array: %s" %
715 720
                                    result.output)
716
    new_len = len(self._children) + 1
721
    new_len = len(self._children) + len(devices)
717 722
    result = utils.RunCmd(["mdadm", "--grow", self.dev_path, "-n", new_len])
718 723
    if result.failed:
719 724
      raise errors.BlockDeviceError("Can't grow md array: %s" %
720 725
                                    result.output)
721
    self._children.append(device)
726
    self._children.extend(devices)
722 727

  
723 728

  
724
  def RemoveChild(self, dev_path):
725
    """Remove member from the md raid1.
729
  def RemoveChildren(self, devices):
730
    """Remove member(s) from the md raid1.
726 731

  
727 732
    """
728 733
    if self.minor is None and not self.Attach():
729 734
      raise errors.BlockDeviceError("Can't attach to device")
730
    if len(self._children) == 1:
731
      raise errors.BlockDeviceError("Can't reduce member when only one"
732
                                    " child left")
733
    for device in self._children:
734
      if device.dev_path == dev_path:
735
        break
736
    else:
737
      raise errors.BlockDeviceError("Can't find child with this path")
738
    new_len = len(self._children) - 1
739
    result = utils.RunCmd(["mdadm", "-f", self.dev_path, dev_path])
735
    new_len = len(self._children) - len(devices)
736
    if new_len < 1:
737
      raise errors.BlockDeviceError("Can't reduce to less than one child")
738
    args = ["mdadm", "-f", self.dev_path]
739
    orig_devs = []
740
    for dev in devices:
741
      args.append(dev.dev_path)
742
      for c in self._children:
743
        if c.dev_path == dev.dev_path:
744
          orig_devs.append(c)
745
          break
746
      else:
747
        raise errors.BlockDeviceError("Can't find device '%s' for removal" %
748
                                      dev)
749
    result = utils.RunCmd(args)
740 750
    if result.failed:
741
      raise errors.BlockDeviceError("Failed to mark device as failed: %s" %
751
      raise errors.BlockDeviceError("Failed to mark device(s) as failed: %s" %
742 752
                                    result.output)
743 753

  
744 754
    # it seems here we need a short delay for MD to update its
745 755
    # superblocks
746 756
    time.sleep(0.5)
747
    result = utils.RunCmd(["mdadm", "-r", self.dev_path, dev_path])
757
    args[1] = "-r"
758
    result = utils.RunCmd(args)
748 759
    if result.failed:
749
      raise errors.BlockDeviceError("Failed to remove device from array:"
750
                                        " %s" % result.output)
760
      raise errors.BlockDeviceError("Failed to remove device(s) from array:"
761
                                    " %s" % result.output)
751 762
    result = utils.RunCmd(["mdadm", "--grow", "--force", self.dev_path,
752 763
                           "-n", new_len])
753 764
    if result.failed:
754 765
      raise errors.BlockDeviceError("Can't shrink md array: %s" %
755 766
                                    result.output)
756
    self._children.remove(device)
767
    for dev in orig_devs:
768
      self._children.remove(dev)
757 769

  
758 770

  
759 771
  def GetStatus(self):
b/lib/cmdlib.py
3223 3223
    # the device exists now
3224 3224
    # call the primary node to add the mirror to md
3225 3225
    logger.Info("adding new mirror component to md")
3226
    if not rpc.call_blockdev_addchild(instance.primary_node,
3227
                                           disk, new_drbd):
3226
    if not rpc.call_blockdev_addchildren(instance.primary_node,
3227
                                         disk, [new_drbd]):
3228 3228
      logger.Error("Can't add mirror compoment to md!")
3229 3229
      self.cfg.SetDiskID(new_drbd, remote_node)
3230 3230
      if not rpc.call_blockdev_remove(remote_node, new_drbd):
......
3316 3316
    child = self.child
3317 3317
    logger.Info("remove mirror component")
3318 3318
    self.cfg.SetDiskID(disk, instance.primary_node)
3319
    if not rpc.call_blockdev_removechild(instance.primary_node,
3320
                                              disk, child):
3319
    if not rpc.call_blockdev_removechildren(instance.primary_node,
3320
                                            disk, [child]):
3321 3321
      raise errors.OpExecError("Can't remove child from mirror.")
3322 3322

  
3323 3323
    for node in child.logical_id[:2]:
......
3427 3427
      # the device exists now
3428 3428
      # call the primary node to add the mirror to md
3429 3429
      logger.Info("adding new mirror component to md")
3430
      if not rpc.call_blockdev_addchild(instance.primary_node, dev,
3431
                                        new_drbd):
3430
      if not rpc.call_blockdev_addchildren(instance.primary_node, dev,
3431
                                           [new_drbd]):
3432 3432
        logger.Error("Can't add mirror compoment to md!")
3433 3433
        cfg.SetDiskID(new_drbd, remote_node)
3434 3434
        if not rpc.call_blockdev_remove(remote_node, new_drbd):
......
3462 3462
      dev, child, new_drbd = iv_names[name]
3463 3463
      logger.Info("remove mirror %s component" % name)
3464 3464
      cfg.SetDiskID(dev, instance.primary_node)
3465
      if not rpc.call_blockdev_removechild(instance.primary_node,
3466
                                                dev, child):
3465
      if not rpc.call_blockdev_removechildren(instance.primary_node,
3466
                                              dev, [child]):
3467 3467
        logger.Error("Can't remove child from mirror, aborting"
3468 3468
                     " *this device cleanup*.\nYou need to cleanup manually!!")
3469 3469
        continue
b/lib/rpc.py
539 539
  return c.getresult().get(node, False)
540 540

  
541 541

  
542
def call_blockdev_addchild(node, bdev, ndev):
543
  """Request adding a new child to a (mirroring) device.
542
def call_blockdev_addchildren(node, bdev, ndevs):
543
  """Request adding a list of children to a (mirroring) device.
544 544

  
545 545
  This is a single-node call.
546 546

  
547 547
  """
548
  params = [bdev.ToDict(), ndev.ToDict()]
549
  c = Client("blockdev_addchild", params)
548
  params = [bdev.ToDict(), [disk.ToDict() for disk in ndevs]]
549
  c = Client("blockdev_addchildren", params)
550 550
  c.connect(node)
551 551
  c.run()
552 552
  return c.getresult().get(node, False)
553 553

  
554 554

  
555
def call_blockdev_removechild(node, bdev, ndev):
556
  """Request removing a new child from a (mirroring) device.
555
def call_blockdev_removechildren(node, bdev, ndevs):
556
  """Request removing a list of children from a (mirroring) device.
557 557

  
558 558
  This is a single-node call.
559 559

  
560 560
  """
561
  params = [bdev.ToDict(), ndev.ToDict()]
562
  c = Client("blockdev_removechild", params)
561
  params = [bdev.ToDict(), [disk.ToDict() for disk in ndevs]]
562
  c = Client("blockdev_removechildren", params)
563 563
  c.connect(node)
564 564
  c.run()
565 565
  return c.getresult().get(node, False)

Also available in: Unified diff