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