Revision ec0292f1 lib/config.py

b/lib/config.py
275 275
    if not data.nodes[data.cluster.master_node].master_candidate:
276 276
      result.append("Master node is not a master candidate")
277 277

  
278
    cp_size = data.cluster.candidate_pool_size
279
    num_c = 0
280
    for node in data.nodes.values():
281
      if node.master_candidate:
282
        num_c += 1
283
    if cp_size > num_c and num_c < len(data.nodes):
284
      result.append("Not enough master candidates: actual %d, desired %d,"
285
                    " %d total nodes" % (num_c, cp_size, len(data.nodes)))
278
    mc_now, mc_max = self._UnlockedGetMasterCandidateStats()
279
    if mc_now < mc_max:
280
      result.append("Not enough master candidates: actual %d, target %d" %
281
                    (mc_now, mc_max))
286 282

  
287 283
    return result
288 284

  
......
772 768
    """Get the configuration of all nodes.
773 769

  
774 770
    @rtype: dict
775
    @returns: dict of (node, node_info), where node_info is what
771
    @return: dict of (node, node_info), where node_info is what
776 772
              would GetNodeInfo return for the node
777 773

  
778 774
    """
......
780 776
                    for node in self._UnlockedGetNodeList()])
781 777
    return my_dict
782 778

  
779
  def _UnlockedGetMasterCandidateStats(self):
780
    """Get the number of current and maximum desired and possible candidates.
781

  
782
    @rtype: tuple
783
    @return: tuple of (current, desired and possible)
784

  
785
    """
786
    mc_now = mc_max = 0
787
    for node in self._config_data.nodes.itervalues():
788
      if not node.offline:
789
        mc_max += 1
790
      if node.master_candidate:
791
        mc_now += 1
792
    mc_max = min(mc_max, self._config_data.cluster.candidate_pool_size)
793
    return (mc_now, mc_max)
794

  
795
  @locking.ssynchronized(_config_lock, shared=1)
796
  def GetMasterCandidateStats(self):
797
    """Get the number of current and maximum possible candidates.
798

  
799
    This is just a wrapper over L{_UnlockedGetMasterCandidateStats}.
800

  
801
    @rtype: tuple
802
    @return: tuple of (current, max)
803

  
804
    """
805
    return self._UnlockedGetMasterCandidateStats()
806

  
807
  @locking.ssynchronized(_config_lock)
808
  def MaintainCandidatePool(self):
809
    """Try to grow the candidate pool to the desired size.
810

  
811
    @rtype: list
812
    @return: list with the adjusted node names
813

  
814
    """
815
    mc_now, mc_max = self._UnlockedGetMasterCandidateStats()
816
    mod_list = []
817
    if mc_now < mc_max:
818
      node_list = self._config_data.nodes.keys()
819
      random.shuffle(node_list)
820
      for name in node_list:
821
        if mc_now >= mc_max:
822
          break
823
        node = self._config_data.nodes[name]
824
        if node.master_candidate or node.offline:
825
          continue
826
        mod_list.append(node.name)
827
        node.master_candidate = True
828
        node.serial_no += 1
829
        mc_now += 1
830
      if mc_now != mc_max:
831
        # this should not happen
832
        logging.warning("Warning: MaintainCandidatePool didn't manage to"
833
                        " fill the candidate pool (%d/%d)", mc_now, mc_max)
834
      if mod_list:
835
        self._config_data.cluster.serial_no += 1
836
        self._WriteConfig()
837

  
838
    return mod_list
839

  
783 840
  def _BumpSerialNo(self):
784 841
    """Bump up the serial number of the config.
785 842

  

Also available in: Unified diff