def __comparePackagesToString(self, comparePackages): stringUtil = StringUtil() rString = "" missingPackagesMap = comparePackages.getMissingPackagesMap() if (len(missingPackagesMap.keys()) > 0): description = "The following hosts did not have certain cluster packages installed(whereas other hosts did have the packages installed):" keys = missingPackagesMap.keys() keys.sort() missingPackagesTable = [] for key in keys: reportNames = missingPackagesMap.get(key) reportNames.sort() if (len(reportNames) > 0): currentHostnames = "" for reportName in reportNames: currentHostnames += "%s " % (reportName) missingPackagesTable.append([key, currentHostnames]) tableHeader = ["Package Name", "Hostname(s)"] tableOfStrings = stringUtil.toTableStringsList( missingPackagesTable, tableHeader) rString += StringUtil.formatBulletString(description, [], tableOfStrings) differentPackagesVersionMap = comparePackages.getDiffernetPackagesVersionMap( ) if (len(differentPackagesVersionMap.keys()) > 0): description = "The following hosts had a different package version installed:" keys = differentPackagesVersionMap.keys() keys.sort() differentPackageVersionsTable = [] for key in keys: reportNames = differentPackagesVersionMap.get(key) reportNames.sort() if (len(reportNames) > 0): currentHostnames = "" for reportName in reportNames: currentHostnames += "%s " % (reportName) differentPackageVersionsTable.append( [key, currentHostnames]) tableHeader = ["Package Name", "Hostname(s)"] tableOfStrings = stringUtil.toTableStringsList( differentPackageVersionsTable, tableHeader) rString += StringUtil.formatBulletString(description, [], tableOfStrings) if (len(rString) > 0): rString = "%s\n%s" % (comparePackages, rString) return rString
def __compareDataToString(self, compareData): stringUtil = StringUtil() rString = "" nonBaseCompareMap = compareData.getNonBaseCompareMap() if (not len(nonBaseCompareMap.keys()) > 0): return rString description = "The following hosts had similar compared values:" baseCompareMap = compareData.getBaseCompareMap() keys = baseCompareMap.keys() keys.sort() compareTable = [] for key in keys: reportNames = baseCompareMap.get(key) reportNames.sort() currentHostnames = "" for reportName in reportNames: currentHostnames += "%s " % (reportName) compareTable.append([key, currentHostnames]) tableHeader = ["Compared String", "Hostname(s)"] tableOfStrings = stringUtil.toTableStringsList(compareTable, tableHeader) rString += StringUtil.formatBulletString(description, [], tableOfStrings) description = "The following hosts had different compared values than the above compared values:" keys = nonBaseCompareMap.keys() keys.sort() compareTable = [] for key in keys: reportNames = nonBaseCompareMap.get(key) reportNames.sort() currentHostnames = "" for reportName in reportNames: currentHostnames += "%s " % (reportName) compareTable.append([key, currentHostnames]) tableHeader = ["Compared String", "Hostname(s)"] tableOfStrings = stringUtil.toTableStringsList(compareTable, tableHeader) rString += StringUtil.formatBulletString(description, [], tableOfStrings) if (len(rString) > 0): rString = "%s\n%s" % (compareData, rString) return rString
def evaluateClusteredFilesystems(self): # Is active/active nfs supported? Sorta # urls = ["https://access.redhat.com/solutions/59498"] rString = "" baseClusterNode = self.__cnc.getBaseClusterNode() if (baseClusterNode == None): return rString cca = ClusterHAConfAnalyzer(baseClusterNode.getPathToClusterConf()) if ((cca.getTransportMode() == "broadcast") or (cca.getTransportMode() == "udpu")): for clusternode in self.__cnc.getClusterNodes(): if (len(clusternode.getClusterStorageFilesystemList()) > 0): description = "There is known limitations for GFS2 filesystem when using the " description += "following transports: \"%s\"." %(cca.getTransportMode()) urls = ["https://access.redhat.com/solutions/162193", "https://access.redhat.com/articles/146163", "https://access.redhat.com/solutions/459243"] rString += "%s\n" %(StringUtil.formatBulletString(description, urls)) break; for clusternode in self.__cnc.getClusterNodes(): stringUtil = StringUtil() clusterNodeEvalString = "" # ################################################################### # Distro Specific evaluations # ################################################################### # The distro release of this node distroRelease = clusternode.getDistroRelease() if ((distroRelease.getDistroName() == "RHEL") and (distroRelease.getMajorVersion() == 5)): # Check if GFS2 module should be removed on RH5 nodes if (self.__doesGFS2ModuleNeedRemoval(clusternode.getUnameA(), clusternode.getClusterModulePackagesVersion())) : description = "The kmod-gfs2 is installed on a running kernel >= 2.6.18-128. This module should be removed since the module is included in the kernel." urls = ["https://access.redhat.com/solutions/17832"] clusterNodeEvalString += StringUtil.formatBulletString(description, urls) # ################################################################### # Analyze the Clustered Storage # ################################################################### listOfClusterStorageFilesystems = clusternode.getClusterStorageFilesystemList() # ################################################################### # Verify that GFS/GFS2 filesystem is using lvm with cluster bit set # ################################################################### fsTable = [] # Verify the locking_type is set to 3 cause built-in cluster locking is required. if (len(listOfClusterStorageFilesystems) > 0): devicemapperCommandsMap = self.__cnc.getStorageData(clusternode.getClusterNodeName()).getDMCommandsMap() lvm = LVM(DeviceMapperParser.parseVGSVData(devicemapperCommandsMap.get("vgs_-v")), DeviceMapperParser.parseLVSAODevicesData(devicemapperCommandsMap.get("lvs_-a_-o_devices")), self.__cnc.getStorageData(clusternode.getClusterNodeName()).getLVMConfData()) if (not lvm.isLockingTypeClustering()): description = "The locking_type is not set to type 3 for built-in cluster locking. A GFS/GFS2 filesystem requires the filesystem be on a " description += "clustered LVM volume with locking_type 3 enabled in the /etc/lvm/lvm.conf." urls = ["https://access.redhat.com/solutions/46637"] clusterNodeEvalString += StringUtil.formatBulletString(description, urls) # Disabling this check for now cause still working on how to do it. """ # Verify that the clustered filesystem has clusterbit set on the vg. # Verify the locking_type is set to 3 cause built-in cluster locking is required. fsTable = [] if (len(listOfClusterStorageFilesystems) > 0): devicemapperCommandsMap = self.__cnc.getStorageData(clusternode.getClusterNodeName()).getDMCommandsMap() lvm = LVM(DeviceMapperParser.parseVGSVData(devicemapperCommandsMap.get("vgs_-v")), DeviceMapperParser.parseLVSAODevicesData(devicemapperCommandsMap.get("lvs_-a_-o_devices")), self.__cnc.getStorageData(clusternode.getClusterNodeName()).getLVMConfData()) for csFilesystem in listOfClusterStorageFilesystems: pathToDevice = str(csFilesystem.getDeviceName().strip().rstrip()) if (not lvm.isClusteredLVMDevice(pathToDevice)): currentFS = [pathToDevice, csFilesystem.getMountPoint(), csFilesystem.getFSType()] if (not currentFS in fsTable): fsTable.append(currentFS) if (len(fsTable) > 0): stringUtil = StringUtil() description = "The following filesystems appears not to be on a clustered LVM volume. A clustered LVM volume is required for GFS/GFS2 fileystems." tableHeader = ["device_name", "mount_point", "fs_type"] tableOfStrings = stringUtil.toTableStringsList(fsTable, tableHeader) urls = ["https://access.redhat.com/solutions/46637"] clusterNodeEvalString += StringUtil.formatBulletString(description, urls, tableOfStrings) """ # ################################################################### # Verify they are exporting a gfs/gfs2 fs via samba and nfs correctly # ################################################################### tableHeader = ["device_name", "mount_point", "nfs_mp", "smb_mp"] fsTable = [] for csFilesystem in listOfClusterStorageFilesystems: # There are 4 ways of mounting gfs via nfs/smb at same time that # needs to be checked: # 1) nfs mount via /etc/exports and smb mount via /etc/samba/smb.conf # 2) nfs mount via /etc/cluster/cluster.conf and smb mount via /etc/cluster/cluster.conf # 3) nfs mount via /etc/cluster/cluster.conf and smb mount via /etc/samba/smb.conf. # 4) nfs mount via /etc/exports and smb mount via /etc/cluster/cluster.conf if (csFilesystem.isEtcExportMount() and csFilesystem.isSMBSectionMount()): # 1) nfs mount via /etc/exports and smb mount via /etc/samba/smb.conf #print "1: %s" %(csFilesystem.getMountPoint()) nfsMP = csFilesystem.getEtcExportMount().getMountPoint() smbSectionList = csFilesystem.getSMBSectionMountList() if (len(smbSectionList) > 0): smbMP = smbSectionList.pop().getOptionValue("path").strip() fsTable.append([csFilesystem.getDeviceName(), csFilesystem.getMountPoint(), "%s(EN)" %(nfsMP), "%s(ES)" %(smbMP)]) for smbSection in smbSectionList: smbMP = smbSection.getOptionValue("path").strip() fsTable.append(["", "", "", "%s(ES)" %(smbMP)]) elif ((not csFilesystem.isEtcExportMount()) and (not csFilesystem.isSMBSectionMount())): # 2) nfs mount via /etc/cluster/cluster.conf and smb mount via /etc/cluster/cluster.conf #print "2: %s" %(csFilesystem.getMountPoint()) if((self.__isNFSChildOfClusterStorageResource(cca, csFilesystem)) and (len(csFilesystem.getClusteredSMBNames()) > 0)): nfsMP = csFilesystem.getMountPoint() smbPaths = [] for name in csFilesystem.getClusteredSMBNames(): for smbSection in csFilesystem.getClusteredSMBSectionList(name): currentPath = smbSection.getOptionValue("path").strip() if (len(currentPath) > 0): smbPaths.append(currentPath) if ((len(nfsMP) > 0) and (len(smbPaths) > 0)): # Pop the first one off the list. smbMP = smbPaths.pop() fsTable.append([csFilesystem.getDeviceName(), csFilesystem.getMountPoint(), "%s(CN)" %(nfsMP), "%s(CS)" %(smbMP)]) # IF there any left add those with some blanks. for smbMP in smbPaths: fsTable.append(["", "", "", "%s(CS)" %(smbMP)]) elif ((csFilesystem.isSMBSectionMount()) and (self.__isNFSChildOfClusterStorageResource(cca, csFilesystem))): # 3) nfs mount via /etc/cluster/cluster.conf and smb mount via /etc/samba/smb.conf. #print "3: %s" %(csFilesystem.getMountPoint()) nfsMP = csFilesystem.getMountPoint() smbSectionList = csFilesystem.getSMBSectionMountList() if (len(smbSectionList) > 0): smbMP = smbSectionList.pop().getOptionValue("path").strip() fsTable.append([csFilesystem.getDeviceName(), csFilesystem.getMountPoint(), "%s(CN)" %(nfsMP), "%s(ES)" %(smbMP)]) for smbSection in smbSectionList: smbMP = smbSection.getOptionValue("path").strip() fsTable.append(["", "", "", "%s(ES)" %(smbMP)]) elif ((csFilesystem.isEtcExportMount()) and (len(csFilesystem.getClusteredSMBNames()) > 0)): # 4) nfs mount via /etc/exports and smb mount via /etc/cluster/cluster.conf # print "4: %s" %(csFilesystem.getMountPoint()) smbSectionList = [] for name in csFilesystem.getClusteredSMBNames(): smbSectionList += csFilesystem.getClusteredSMBSectionList(name) if (len(smbSectionList) > 0): smbMP = smbSectionList.pop().getOptionValue("path").strip() fsTable.append([csFilesystem.getDeviceName(), csFilesystem.getMountPoint(), "%s(EN)" %(nfsMP), "%s(CS)" %(smbMP)]) for smbSection in smbSectionList: smbMP = smbSection.getOptionValue("path").strip() fsTable.append(["", "", "", "%s(CS)" %(smbMP)]) # Write the table if it is not empty. if (len(fsTable) > 0): description = "The following GFS/GFS2 filesystem(s) are being exported by NFS and SMB(samba) which is unsupported. " description += "The mount point(s) that were found will be noted with these symbols below: " description += "nfs export via /etc/exports (EN) " description += "nfs export via /etc/cluster/cluster.conf (CN) " description += "samba export via /etc/exports for samba (ES) " description += "samba export via /etc/cluster/cluster.conf for samba (CS)" urls = ["https://access.redhat.com/solutions/39855"] tableOfStrings = stringUtil.toTableStringsList(fsTable, tableHeader) clusterNodeEvalString += StringUtil.formatBulletString(description, urls, tableOfStrings) # ################################################################### # Check for localflocks if they are exporting nfs. # ################################################################### fsTable = [] for csFilesystem in listOfClusterStorageFilesystems: # If a GFS or GFS2 fs is in /etc/exports or has a child that is # nfsexport then localflocks required. if ((csFilesystem.isEtcExportMount()) or (self.__isNFSChildOfClusterStorageResource(cca, csFilesystem))): csFilesystemOptions = csFilesystem.getAllMountOptions() if (not csFilesystemOptions.find("localflocks") >= 0): fsTable.append([csFilesystem.getDeviceName(), csFilesystem.getMountPoint()]) # Write the table if it is not empty. if (len(fsTable) > 0): tableHeader = ["device_name", "mount_point"] description = "Any GFS/GFS2 filesystem that is exported with NFS should have the option \"localflocks\" set." description += "The following GFS/GFS2 filesystem do not have the option set." tableOfStrings = stringUtil.toTableStringsList(fsTable, tableHeader) urls = ["https://access.redhat.com/solutions/20327", "http://docs.redhat.com/docs/en-US/Red_Hat_Enterprise_Linux/5/html-single/Configuration_Example_-_NFS_Over_GFS/index.html#locking_considerations"] clusterNodeEvalString += StringUtil.formatBulletString(description, urls, tableOfStrings) # ################################################################### # Check to see if the GFS/GFS2 fs has certain mount options enabled. # ################################################################### fsTable = [] for csFilesystem in listOfClusterStorageFilesystems: csFilesystemOptions = csFilesystem.getAllMountOptions() if (not csFilesystemOptions.find("noatime") >= 0): fsTable.append([csFilesystem.getDeviceName(), csFilesystem.getMountPoint()]) if (len(fsTable) > 0): # Verified that noatime implies nodiratime, so nodiratime check # does not need to be done. description = "There were GFS/GFS2 file-systems that did not have the mount option \"noatime\"(no \"nodiratime\" is implied. " description += "when noatime is set) enabled. Unless atime support is essential, Red Hat recommends setting the mount option " description += "\"noatime\" on every GFS/GFS2 mount point. This will significantly improve performance since it prevents " description += "reads from turning into writes because the access time attribute will not be updated." urls = ["https://access.redhat.com/articles/628093#slowdown_due_to_system_configuration_issues"] clusterNodeEvalString += StringUtil.formatBulletString(description, urls) # ################################################################### # Make sure GFS/GFS2 filesystems dont have fsck option enable # ################################################################### for csFilesystem in listOfClusterStorageFilesystems: if (csFilesystem.isEtcFstabMount()): if (not csFilesystem.getEtcFstabMount().getFSFsck() == "0"): description = "There were GFS/GFS2 file-systems that had the fsck option enabled in the /etc/fstab file. This option " description += "should be disabled(set value to 0) or corruption will occur eventually." urls = ["https://access.redhat.com/solutions/766393"] clusterNodeEvalString += StringUtil.formatBulletString(description, urls) # ################################################################### # Add to string with the hostname and header if needed. # ################################################################### if (len(clusterNodeEvalString) > 0): rString += "%s(Cluster Node ID: %s):\n%s\n\n" %(clusternode.getClusterNodeName(), clusternode.getClusterNodeID(), clusterNodeEvalString.rstrip()) # Return the string if (len(rString) > 0): sectionHeader = "%s\nCluster Storage Configuration Known Issues\n%s" %(self.__seperator, self.__seperator) rString = "%s\n%s" %(sectionHeader, rString) return rString