Revision 61f232ec lib/cmdlib.py

b/lib/cmdlib.py
6350 6350

  
6351 6351

  
6352 6352
def _AssembleInstanceDisks(lu, instance, disks=None, ignore_secondaries=False,
6353
                           ignore_size=False):
6353
                           ignore_size=False, check=True):
6354 6354
  """Prepare the block devices for an instance.
6355 6355

  
6356 6356
  This sets up the block devices on all nodes.
......
6376 6376
  device_info = []
6377 6377
  disks_ok = True
6378 6378
  iname = instance.name
6379
  disks = _ExpandCheckDisks(instance, disks)
6379
  if check:
6380
    disks = _ExpandCheckDisks(instance, disks)
6380 6381

  
6381 6382
  # With the two passes mechanism we try to reduce the window of
6382 6383
  # opportunity for the race condition of switching DRBD to primary
......
8734 8735
    results.append("%s%s" % (new_id, val))
8735 8736
  return results
8736 8737

  
8738
def _GetPCIInfo(lu, dev_type):
8739

  
8740
  if lu.op.hotplug:
8741
    if hasattr(lu, 'hotplug_info'):
8742
      info = lu.hotplug_info
8743
    elif hasattr(lu, 'instance') and hasattr(lu.instance, 'hotplug_info'):
8744
      return lu.cfg.GetPCIInfo(lu.instance.name, dev_type)
8745

  
8746
    if info:
8747
      idx = getattr(info, dev_type)
8748
      setattr(info, dev_type, idx+1)
8749
      pci = info.pci_pool.pop()
8750
      return idx, pci
8751

  
8752
  return None, None
8753

  
8737 8754

  
8738 8755
def _GenerateDRBD8Branch(lu, primary, secondary, size, vgnames, names,
8739 8756
                         iv_name, p_minor, s_minor):
......
8750 8767
  dev_meta = objects.Disk(dev_type=constants.LD_LV, size=DRBD_META_SIZE,
8751 8768
                          logical_id=(vgnames[1], names[1]),
8752 8769
                          params={})
8753
  drbd_dev = objects.Disk(dev_type=constants.LD_DRBD8, size=size,
8770

  
8771
  disk_idx, pci = _GetPCIInfo(lu, 'disks')
8772
  drbd_dev = objects.Disk(idx=disk_idx, pci=pci,
8773
                          dev_type=constants.LD_DRBD8, size=size,
8754 8774
                          logical_id=(primary, secondary, port,
8755 8775
                                      p_minor, s_minor,
8756 8776
                                      shared_secret),
......
8859 8879
      size = disk[constants.IDISK_SIZE]
8860 8880
      feedback_fn("* disk %s, size %s" %
8861 8881
                  (disk_index, utils.FormatUnit(size, "h")))
8882

  
8883
      disk_idx, pci = _GetPCIInfo(lu, 'disks')
8884

  
8862 8885
      disks.append(objects.Disk(dev_type=dev_type, size=size,
8863 8886
                                logical_id=logical_id_fn(idx, disk_index, disk),
8864 8887
                                iv_name="disk/%d" % disk_index,
8865 8888
                                mode=disk[constants.IDISK_MODE],
8866
                                params={}))
8889
                                params={}, idx=disk_idx, pci=pci))
8867 8890

  
8868 8891
  return disks
8869 8892

  
......
9746 9769
    if self.op.identify_defaults:
9747 9770
      self._RevertToDefaults(cluster)
9748 9771

  
9772
    self.hotplug_info = None
9773
    if self.op.hotplug:
9774
      self.hotplug_info = objects.HotplugInfo(disks=0, nics=0,
9775
                                              pci_pool=list(range(16,32)))
9749 9776
    # NIC buildup
9750 9777
    self.nics = []
9751 9778
    for idx, nic in enumerate(self.op.nics):
......
9805 9832

  
9806 9833
      check_params = cluster.SimpleFillNIC(nicparams)
9807 9834
      objects.NIC.CheckParameterSyntax(check_params)
9808
      self.nics.append(objects.NIC(mac=mac, ip=nic_ip, nicparams=nicparams))
9835
      nic_idx, pci = _GetPCIInfo(self, 'nics')
9836
      self.nics.append(objects.NIC(idx=nic_idx, pci=pci,
9837
                                   mac=mac, ip=nic_ip,
9838
                                   nicparams=check_params))
9809 9839

  
9810 9840
    # disk checks/pre-build
9811 9841
    default_vg = self.cfg.GetVGName()
......
10089 10119
                            hvparams=self.op.hvparams,
10090 10120
                            hypervisor=self.op.hypervisor,
10091 10121
                            osparams=self.op.osparams,
10122
                            hotplug_info=self.hotplug_info,
10092 10123
                            )
10093 10124

  
10094 10125
    if self.op.tags:
......
12054 12085
        if remove_fn is not None:
12055 12086
          remove_fn(absidx, item, private)
12056 12087

  
12088
        #TODO: include a hotplugged msg in changes
12057 12089
        changes = [("%s/%s" % (kind, absidx), "remove")]
12058 12090

  
12059 12091
        assert container[absidx] == item
12060 12092
        del container[absidx]
12061 12093
      elif op == constants.DDM_MODIFY:
12062 12094
        if modify_fn is not None:
12095
          #TODO: include a hotplugged msg in changes
12063 12096
          changes = modify_fn(absidx, item, params, private)
12097

  
12064 12098
      else:
12065 12099
        raise errors.ProgrammerError("Unhandled operation '%s'" % op)
12066 12100

  
......
12362 12396
                                     " in cluster" % mac,
12363 12397
                                     errors.ECODE_NOTUNIQUE)
12364 12398

  
12399
    logging.info("new_params %s", new_params)
12400
    logging.info("new_filled_params %s", new_filled_params)
12365 12401
    private.params = new_params
12366 12402
    private.filled = new_filled_params
12367 12403

  
......
12385 12421
    # Prepare disk/NIC modifications
12386 12422
    self.diskmod = PrepareContainerMods(self.op.disks, None)
12387 12423
    self.nicmod = PrepareContainerMods(self.op.nics, _InstNicModPrivate)
12424
    logging.info("nicmod %s", self.nicmod)
12388 12425

  
12389 12426
    # OS change
12390 12427
    if self.op.os_name and not self.op.force:
......
12616 12653
                                 " (%d), cannot add more" % constants.MAX_NICS,
12617 12654
                                 errors.ECODE_STATE)
12618 12655

  
12656

  
12619 12657
    # Verify disk changes (operating on a copy)
12620 12658
    disks = instance.disks[:]
12621
    ApplyContainerMods("disk", disks, None, self.diskmod, None, None, None)
12659
    ApplyContainerMods("disk", disks, None, self.diskmod,
12660
                       None, None, None)
12622 12661
    if len(disks) > constants.MAX_DISKS:
12623 12662
      raise errors.OpPrereqError("Instance has too many disks (%d), cannot add"
12624 12663
                                 " more" % constants.MAX_DISKS,
......
12637 12676
      # Operate on copies as this is still in prereq
12638 12677
      nics = [nic.Copy() for nic in instance.nics]
12639 12678
      ApplyContainerMods("NIC", nics, self._nic_chgdesc, self.nicmod,
12640
                         self._CreateNewNic, self._ApplyNicMods, None)
12679
                         self._CreateNewNic, self._ApplyNicMods,
12680
                         self._RemoveNic)
12641 12681
      self._new_nics = nics
12642 12682
    else:
12643 12683
      self._new_nics = None
12644 12684

  
12685

  
12645 12686
  def _ConvertPlainToDrbd(self, feedback_fn):
12646 12687
    """Converts an instance from plain to drbd.
12647 12688

  
......
12789 12830
        self.LogWarning("Failed to create volume %s (%s) on node '%s': %s",
12790 12831
                        disk.iv_name, disk, node, err)
12791 12832

  
12833
    if self.op.hotplug and disk.pci:
12834
      disk_ok, device_info = _AssembleInstanceDisks(self, self.instance,
12835
                                                    [disk], check=False)
12836
      _, _, dev_path = device_info[0]
12837
      result = self.rpc.call_hot_add_disk(self.instance.primary_node,
12838
                                          self.instance, disk, dev_path, idx)
12792 12839
    return (disk, [
12793 12840
      ("disk/%d" % idx, "add:size=%s,mode=%s" % (disk.size, disk.mode)),
12794 12841
      ])
......
12808 12855
    """Removes a disk.
12809 12856

  
12810 12857
    """
12858
    #TODO: log warning in case hotplug is not possible
12859
    #      handle errors
12860
    if root.pci and not self.op.hotplug:
12861
      raise errors.OpPrereqError("Cannot remove a disk that has"
12862
                                 " been hotplugged"
12863
                                 " without removing it with hotplug",
12864
                                 errors.ECODE_INVAL)
12865
    if self.op.hotplug and root.pci:
12866
      self.rpc.call_hot_del_disk(self.instance.primary_node,
12867
                                 self.instance, root, idx)
12868
      _ShutdownInstanceDisks(self, self.instance, [root])
12869
      self.cfg.UpdatePCIInfo(self.instance.name, root.pci)
12870

  
12811 12871
    (anno_disk,) = _AnnotateDiskParams(self.instance, [root], self.cfg)
12812 12872
    for node, disk in anno_disk.ComputeNodeTree(self.instance.primary_node):
12813 12873
      self.cfg.SetDiskID(disk, node)
......
12820 12880
    if root.dev_type in constants.LDS_DRBD:
12821 12881
      self.cfg.AddTcpUdpPort(root.logical_id[2])
12822 12882

  
12823
  @staticmethod
12824
  def _CreateNewNic(idx, params, private):
12883
  def _CreateNewNic(self, idx, params, private):
12825 12884
    """Creates data structure for a new network interface.
12826 12885

  
12827 12886
    """
12828 12887
    mac = params[constants.INIC_MAC]
12829 12888
    ip = params.get(constants.INIC_IP, None)
12830
    nicparams = private.params
12831

  
12832
    return (objects.NIC(mac=mac, ip=ip, nicparams=nicparams), [
12889
    #TODO: not private.filled?? can a nic be saved without nicparams??
12890
    nicparams = private.filled
12891

  
12892
    nic = objects.NIC(mac=mac, ip=ip, nicparams=nicparams)
12893

  
12894
    #TODO: log warning in case hotplug is not possible
12895
    #      handle errors
12896
    #      return changes
12897
    if self.op.hotplug:
12898
      nic_idx, pci = _GetPCIInfo(self, 'nics')
12899
      nic.idx = nic_idx
12900
      nic.pci = pci
12901
      result = self.rpc.call_hot_add_nic(self.instance.primary_node,
12902
                                         self.instance, nic, idx)
12903
    desc =  [
12833 12904
      ("nic.%d" % idx,
12834 12905
       "add:mac=%s,ip=%s,mode=%s,link=%s" %
12835 12906
       (mac, ip, private.filled[constants.NIC_MODE],
12836 12907
       private.filled[constants.NIC_LINK])),
12837
      ])
12908
      ]
12909
    return (nic, desc)
12838 12910

  
12839
  @staticmethod
12840
  def _ApplyNicMods(idx, nic, params, private):
12911
  def _ApplyNicMods(self, idx, nic, params, private):
12841 12912
    """Modifies a network interface.
12842 12913

  
12843 12914
    """
......
12854 12925
      for (key, val) in params.items():
12855 12926
        changes.append(("nic.%s/%d" % (key, idx), val))
12856 12927

  
12928
    #TODO: log warning in case hotplug is not possible
12929
    #      handle errors
12930
    if self.op.hotplug and nic.pci:
12931
      self.rpc.call_hot_del_nic(self.instance.primary_node,
12932
                                self.instance, nic, idx)
12933
      result = self.rpc.call_hot_add_nic(self.instance.primary_node,
12934
                                         self.instance, nic, idx)
12857 12935
    return changes
12858 12936

  
12937
  def _RemoveNic(self, idx, nic, private):
12938
    if nic.pci and not self.op.hotplug:
12939
      raise errors.OpPrereqError("Cannot remove a nic that has been hotplugged"
12940
                                 " without removing it with hotplug",
12941
                                 errors.ECODE_INVAL)
12942
    #TODO: log warning in case hotplug is not possible
12943
    #      handle errors
12944
    if self.op.hotplug and nic.pci:
12945
      self.rpc.call_hot_del_nic(self.instance.primary_node,
12946
                                self.instance, nic, idx)
12947
      self.cfg.UpdatePCIInfo(self.instance.name, nic.pci)
12948

  
12949

  
12859 12950
  def Exec(self, feedback_fn):
12860 12951
    """Modifies an instance.
12861 12952

  

Also available in: Unified diff