Revision aef59ae7 lib/cmdlib.py

b/lib/cmdlib.py
1265 1265

  
1266 1266
  ECLUSTERCFG = (TCLUSTER, "ECLUSTERCFG")
1267 1267
  ECLUSTERCERT = (TCLUSTER, "ECLUSTERCERT")
1268
  ECLUSTERFILECHECK = (TCLUSTER, "ECLUSTERFILECHECK")
1268 1269
  EINSTANCEBADNODE = (TINSTANCE, "EINSTANCEBADNODE")
1269 1270
  EINSTANCEDOWN = (TINSTANCE, "EINSTANCEDOWN")
1270 1271
  EINSTANCELAYOUT = (TINSTANCE, "EINSTANCELAYOUT")
......
1696 1697
                      "not enough memory to accomodate instance failovers"
1697 1698
                      " should node %s fail", prinode)
1698 1699

  
1699
  def _VerifyNodeFiles(self, ninfo, nresult, file_list, local_cksum,
1700
                       master_files):
1701
    """Verifies and computes the node required file checksums.
1700
  @classmethod
1701
  def _VerifyFiles(cls, errorif, nodeinfo, master_node, all_nvinfo,
1702
                   (files_all, files_all_opt, files_mc, files_vm)):
1703
    """Verifies file checksums collected from all nodes.
1702 1704

  
1703
    @type ninfo: L{objects.Node}
1704
    @param ninfo: the node to check
1705
    @param nresult: the remote results for the node
1706
    @param file_list: required list of files
1707
    @param local_cksum: dictionary of local files and their checksums
1708
    @param master_files: list of files that only masters should have
1705
    @param errorif: Callback for reporting errors
1706
    @param nodeinfo: List of L{objects.Node} objects
1707
    @param master_node: Name of master node
1708
    @param all_nvinfo: RPC results
1709 1709

  
1710 1710
    """
1711
    node = ninfo.name
1712
    _ErrorIf = self._ErrorIf # pylint: disable-msg=C0103
1711
    node_names = frozenset(node.name for node in nodeinfo)
1713 1712

  
1714
    remote_cksum = nresult.get(constants.NV_FILELIST, None)
1715
    test = not isinstance(remote_cksum, dict)
1716
    _ErrorIf(test, self.ENODEFILECHECK, node,
1717
             "node hasn't returned file checksum data")
1718
    if test:
1719
      return
1713
    assert master_node in node_names
1714
    assert (len(files_all | files_all_opt | files_mc | files_vm) ==
1715
            sum(map(len, [files_all, files_all_opt, files_mc, files_vm]))), \
1716
           "Found file listed in more than one file list"
1717

  
1718
    # Define functions determining which nodes to consider for a file
1719
    file2nodefn = dict([(filename, fn)
1720
      for (files, fn) in [(files_all, None),
1721
                          (files_all_opt, None),
1722
                          (files_mc, lambda node: (node.master_candidate or
1723
                                                   node.name == master_node)),
1724
                          (files_vm, lambda node: node.vm_capable)]
1725
      for filename in files])
1726

  
1727
    fileinfo = dict((filename, {}) for filename in file2nodefn.keys())
1728

  
1729
    for node in nodeinfo:
1730
      nresult = all_nvinfo[node.name]
1731

  
1732
      if nresult.fail_msg or not nresult.payload:
1733
        node_files = None
1734
      else:
1735
        node_files = nresult.payload.get(constants.NV_FILELIST, None)
1720 1736

  
1721
    for file_name in file_list:
1722
      node_is_mc = ninfo.master_candidate
1723
      must_have = (file_name not in master_files) or node_is_mc
1724
      # missing
1725
      test1 = file_name not in remote_cksum
1726
      # invalid checksum
1727
      test2 = not test1 and remote_cksum[file_name] != local_cksum[file_name]
1728
      # existing and good
1729
      test3 = not test1 and remote_cksum[file_name] == local_cksum[file_name]
1730
      _ErrorIf(test1 and must_have, self.ENODEFILECHECK, node,
1731
               "file '%s' missing", file_name)
1732
      _ErrorIf(test2 and must_have, self.ENODEFILECHECK, node,
1733
               "file '%s' has wrong checksum", file_name)
1734
      # not candidate and this is not a must-have file
1735
      _ErrorIf(test2 and not must_have, self.ENODEFILECHECK, node,
1736
               "file '%s' should not exist on non master"
1737
               " candidates (and the file is outdated)", file_name)
1738
      # all good, except non-master/non-must have combination
1739
      _ErrorIf(test3 and not must_have, self.ENODEFILECHECK, node,
1740
               "file '%s' should not exist"
1741
               " on non master candidates", file_name)
1737
      test = not (node_files and isinstance(node_files, dict))
1738
      errorif(test, cls.ENODEFILECHECK, node.name,
1739
              "Node did not return file checksum data")
1740
      if test:
1741
        continue
1742

  
1743
      for (filename, checksum) in node_files.items():
1744
        # Check if the file should be considered for a node
1745
        fn = file2nodefn[filename]
1746
        if fn is None or fn(node):
1747
          fileinfo[filename].setdefault(checksum, set()).add(node.name)
1748

  
1749
    for (filename, checksums) in fileinfo.items():
1750
      assert compat.all(len(i) > 10 for i in checksums), "Invalid checksum"
1751

  
1752
      # Nodes having the file
1753
      with_file = frozenset(node_name
1754
                            for nodes in fileinfo[filename].values()
1755
                            for node_name in nodes)
1756

  
1757
      # Nodes missing file
1758
      missing_file = node_names - with_file
1759

  
1760
      if filename in files_all_opt:
1761
        # All or no nodes
1762
        errorif(missing_file and missing_file != node_names,
1763
                cls.ECLUSTERFILECHECK, None,
1764
                "File %s is optional, but it must exist on all or no nodes (not"
1765
                " found on %s)",
1766
                filename, utils.CommaJoin(utils.NiceSort(missing_file)))
1767
      else:
1768
        errorif(missing_file, cls.ECLUSTERFILECHECK, None,
1769
                "File %s is missing from node(s) %s", filename,
1770
                utils.CommaJoin(utils.NiceSort(missing_file)))
1771

  
1772
      # See if there are multiple versions of the file
1773
      test = len(checksums) > 1
1774
      if test:
1775
        variants = ["variant %s on %s" %
1776
                    (idx + 1, utils.CommaJoin(utils.NiceSort(nodes)))
1777
                    for (idx, (checksum, nodes)) in
1778
                      enumerate(sorted(checksums.items()))]
1779
      else:
1780
        variants = []
1781

  
1782
      errorif(test, cls.ECLUSTERFILECHECK, None,
1783
              "File %s found with %s different checksums (%s)",
1784
              filename, len(checksums), "; ".join(variants))
1742 1785

  
1743 1786
  def _VerifyNodeDrbd(self, ninfo, nresult, instanceinfo, drbd_helper,
1744 1787
                      drbd_map):
......
2173 2216
    node_vol_should = {}
2174 2217

  
2175 2218
    # FIXME: verify OS list
2219

  
2220
    # File verification
2221
    filemap = _ComputeAncillaryFiles(cluster, False)
2222

  
2176 2223
    # do local checksums
2177
    master_files = [constants.CLUSTER_CONF_FILE]
2178 2224
    master_node = self.master_node = self.cfg.GetMasterNode()
2179 2225
    master_ip = self.cfg.GetMasterIP()
2180 2226

  
2181
    file_names = ssconf.SimpleStore().GetFileList()
2182
    file_names.extend(constants.ALL_CERT_FILES)
2183
    file_names.extend(master_files)
2184
    if cluster.modify_etc_hosts:
2185
      file_names.append(constants.ETC_HOSTS)
2186

  
2187
    local_checksums = utils.FingerprintFiles(file_names)
2188

  
2189 2227
    # Compute the set of hypervisor parameters
2190 2228
    hvp_data = []
2191 2229
    for hv_name in hypervisors:
......
2207 2245

  
2208 2246
    feedback_fn("* Gathering data (%d nodes)" % len(nodelist))
2209 2247
    node_verify_param = {
2210
      constants.NV_FILELIST: file_names,
2248
      constants.NV_FILELIST:
2249
        utils.UniqueSequence(filename
2250
                             for files in filemap
2251
                             for filename in files),
2211 2252
      constants.NV_NODELIST: [node.name for node in nodeinfo
2212 2253
                              if not node.offline],
2213 2254
      constants.NV_HYPERVISOR: hypervisors,
......
2289 2330
    feedback_fn("* Gathering disk information (%s nodes)" % len(nodelist))
2290 2331
    instdisk = self._CollectDiskInfo(nodelist, node_image, instanceinfo)
2291 2332

  
2333
    feedback_fn("* Verifying configuration file consistency")
2334
    self._VerifyFiles(_ErrorIf, nodeinfo, master_node, all_nvinfo, filemap)
2335

  
2292 2336
    feedback_fn("* Verifying node status")
2293 2337

  
2294 2338
    refos_img = None
......
2326 2370
      nimg.call_ok = self._VerifyNode(node_i, nresult)
2327 2371
      self._VerifyNodeTime(node_i, nresult, nvinfo_starttime, nvinfo_endtime)
2328 2372
      self._VerifyNodeNetwork(node_i, nresult)
2329
      self._VerifyNodeFiles(node_i, nresult, file_names, local_checksums,
2330
                            master_files)
2331

  
2332 2373
      self._VerifyOob(node_i, nresult)
2333 2374

  
2334 2375
      if nimg.vm_capable:

Also available in: Unified diff