From a902b70c43231175b930b21b8d2f71e1f81dd355 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Tue, 16 May 2023 06:03:18 +0000 Subject: [PATCH] import rteval-3.5-4.el8 --- .gitignore | 2 +- .rteval.metadata | 2 +- ...DMI-WARNING-when-not-running-as-root.patch | 165 ++++++++ ...l-Catch-failures-in-python-dmidecode.patch | 54 +++ ...empt-to-get-DMIinfo-if-there-are-dmi.patch | 169 ++++++++ ...lace-python-ethtool-with-inline-code.patch | 399 ++++++++++++++++++ SPECS/rteval.spec | 49 ++- 7 files changed, 834 insertions(+), 6 deletions(-) create mode 100644 SOURCES/Fix-DMI-WARNING-when-not-running-as-root.patch create mode 100644 SOURCES/rteval-Catch-failures-in-python-dmidecode.patch create mode 100644 SOURCES/rteval-Don-t-attempt-to-get-DMIinfo-if-there-are-dmi.patch create mode 100644 SOURCES/rteval-Replace-python-ethtool-with-inline-code.patch diff --git a/.gitignore b/.gitignore index d8d179c..ce47971 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/rteval-3.4.tar.xz +SOURCES/rteval-3.5.tar.xz diff --git a/.rteval.metadata b/.rteval.metadata index a5f5fde..476b584 100644 --- a/.rteval.metadata +++ b/.rteval.metadata @@ -1 +1 @@ -0e04e697615aff39a95dfd864c6bf504bf0ac7c4 SOURCES/rteval-3.4.tar.xz +3aee70e8cca181b05b522acab8a44d45fb876e28 SOURCES/rteval-3.5.tar.xz diff --git a/SOURCES/Fix-DMI-WARNING-when-not-running-as-root.patch b/SOURCES/Fix-DMI-WARNING-when-not-running-as-root.patch new file mode 100644 index 0000000..e901b20 --- /dev/null +++ b/SOURCES/Fix-DMI-WARNING-when-not-running-as-root.patch @@ -0,0 +1,165 @@ +From 149c119df7c7a8ddfd1abc7a127d536cc0674230 Mon Sep 17 00:00:00 2001 +From: John Kacur +Date: Tue, 23 Aug 2022 14:57:37 -0400 +Subject: [PATCH 1/3] rteval: Fix "DMI WARNING" when not running as root + +In some cases it is not necessary to run as root, for example when +running -Z (--summarize) to summarize an existing report. + +In such cases we do not want to see the message: +** DMI WARNING ** Failed to open memory buffer (/dev/mem): Permission denied + +The fix here is to surpresses that message. + +In addition: +- the unused "config" option to DMIinfo.__init__ is removed +- A few strings are converted to f-strings +- "with" is used to open the xsltfile + +Signed-off-by: John Kacur +--- + rteval/sysinfo/__init__.py | 6 ++--- + rteval/sysinfo/dmi.py | 45 +++++++++++++++++++------------------- + 2 files changed, 26 insertions(+), 25 deletions(-) + +diff --git a/rteval/sysinfo/__init__.py b/rteval/sysinfo/__init__.py +index 0436ebb350d9..a4359382f006 100644 +--- a/rteval/sysinfo/__init__.py ++++ b/rteval/sysinfo/__init__.py +@@ -42,7 +42,7 @@ class SystemInfo(KernelInfo, SystemServices, dmi.DMIinfo, CPUtopology, + self.__logger = logger + KernelInfo.__init__(self, logger=logger) + SystemServices.__init__(self, logger=logger) +- dmi.DMIinfo.__init__(self, config, logger=logger) ++ dmi.DMIinfo.__init__(self, logger=logger) + CPUtopology.__init__(self) + OSInfo.__init__(self, logger=logger) + cmdlineInfo.__init__(self, logger=logger) +@@ -80,8 +80,8 @@ if __name__ == "__main__": + cfg.installdir = "." + si = SystemInfo(cfg, logger=l) + +- print("\tRunning on %s" % si.get_base_os()) +- print("\tNUMA nodes: %d" % si.mem_get_numa_nodes()) ++ print(f"\tRunning on {si.get_base_os()}") ++ print(f"\tNUMA nodes: {si.mem_get_numa_nodes()}") + print("\tMemory available: %03.2f %s\n" % si.mem_get_size()) + + print("\tServices: ") +diff --git a/rteval/sysinfo/dmi.py b/rteval/sysinfo/dmi.py +index 80cf3c723b36..5965c128c093 100644 +--- a/rteval/sysinfo/dmi.py ++++ b/rteval/sysinfo/dmi.py +@@ -1,6 +1,4 @@ + # +-# dmi.py - class to wrap DMI Table information +-# + # Copyright 2009 - 2013 Clark Williams + # Copyright 2009 - 2013 David Sommerseth + # +@@ -24,6 +22,7 @@ + # including keys needed to generate an equivalently functional executable + # are deemed to be part of the source code. + # ++""" dmi.py class to wrap DMI Table Information """ + + import sys + import os +@@ -52,16 +51,18 @@ def ProcessWarnings(): + if warnings is None: + return + ++ ignore1 = '/dev/mem: Permission denied' ++ ignore2 = 'No SMBIOS nor DMI entry point found, sorry.' ++ ignore3 = 'Failed to open memory buffer (/dev/mem): Permission denied' ++ ignore = (ignore1, ignore2, ignore3) + for warnline in warnings.split('\n'): + # Ignore these warnings, as they are "valid" if not running as root +- if warnline == '/dev/mem: Permission denied': +- continue +- if warnline == 'No SMBIOS nor DMI entry point found, sorry.': ++ if warnline in ignore: + continue + + # All other warnings will be printed + if len(warnline) > 0: +- print("** DMI WARNING ** %s" % warnline) ++ print(f"** DMI WARNING ** {warnline}") + + dmidecode.clear_warnings() + +@@ -69,8 +70,7 @@ def ProcessWarnings(): + class DMIinfo: + '''class used to obtain DMI info via python-dmidecode''' + +- # TODO: Remove unnecessary config +- def __init__(self, config, logger): ++ def __init__(self, logger): + self.__version = '0.5' + + if not dmidecode_loaded: +@@ -83,22 +83,24 @@ class DMIinfo: + + self.__xsltparser = self.__load_xslt('rteval_dmi.xsl') + +- def __load_xslt(self, fname): +- xsltfile = None ++ @staticmethod ++ def __load_xslt(fname): ++ xsltf = None + if os.path.exists(fname): +- xsltfile = open(fname, "r") +- elif rtevalConfig.default_config_search([fname], os.path.isfile): +- xsltfile = open(rtevalConfig.default_config_search([fname], os.path.isfile), "r") +- +- if xsltfile: +- xsltdoc = lxml.etree.parse(xsltfile) +- ret = lxml.etree.XSLT(xsltdoc) +- xsltfile.close() ++ xsltf = fname ++ else: ++ xsltf = rtevalConfig.default_config_search([fname], os.path.isfile) ++ ++ if xsltf: ++ with open(xsltf, "r") as xsltfile: ++ xsltdoc = lxml.etree.parse(xsltfile) ++ ret = lxml.etree.XSLT(xsltdoc) + return ret + + raise RuntimeError(f'Could not locate XSLT template for DMI data ({fname})') + + def MakeReport(self): ++ """ Add DMI information to final report """ + rep_n = libxml2.newNode("DMIinfo") + rep_n.newProp("version", self.__version) + if self.__fake: +@@ -113,7 +115,7 @@ class DMIinfo: + return rep_n + + def unit_test(rootdir): +- """ unit_test for dmi.py, looks a little crufty! """ ++ """ unit_test for dmi.py """ + + class UnittestConfigDummy: + def __init__(self, rootdir): +@@ -132,15 +134,14 @@ def unit_test(rootdir): + + log = Log() + log.SetLogVerbosity(Log.DEBUG|Log.INFO) +- cfg = UnittestConfigDummy(rootdir) +- d = DMIinfo(cfg, log) ++ d = DMIinfo(log) + dx = d.MakeReport() + x = libxml2.newDoc("1.0") + x.setRootElement(dx) + x.saveFormatFileEnc("-", "UTF-8", 1) + return 0 + except Exception as e: +- print("** EXCEPTION: %s" % str(e)) ++ print(f"** EXCEPTION: {str(e)}") + return 1 + + if __name__ == '__main__': +-- +2.37.3 + diff --git a/SOURCES/rteval-Catch-failures-in-python-dmidecode.patch b/SOURCES/rteval-Catch-failures-in-python-dmidecode.patch new file mode 100644 index 0000000..04d2bb3 --- /dev/null +++ b/SOURCES/rteval-Catch-failures-in-python-dmidecode.patch @@ -0,0 +1,54 @@ +From eacf0f1e55fa0e7217133172808bfef2c59242fb Mon Sep 17 00:00:00 2001 +From: John Kacur +Date: Thu, 2 Feb 2023 00:47:31 -0500 +Subject: [PATCH] rteval: Catch failures in python-dmidecode + +python-dmidecode can generate incorrect xml, +namely Attribute unit redefined + +Although useful, the dmidecode is not critical to rteval reporting. + +Therefore catch this, and first see if we can at least query the bios. +If that works report the bios instead of all, and if that +doesn't work, just continue without the dmidecode report. + +Signed-off-by: John Kacur +--- + rteval/sysinfo/dmi.py | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/rteval/sysinfo/dmi.py b/rteval/sysinfo/dmi.py +index 83f347623b58..89a7faae06b1 100644 +--- a/rteval/sysinfo/dmi.py ++++ b/rteval/sysinfo/dmi.py +@@ -79,6 +79,7 @@ class DMIinfo: + + def __init__(self, logger=None): + self.__version = '0.6' ++ self._log = logger + + if not dmidecode_avail: + logger.log(Log.DEBUG, "DMI info unavailable, ignoring DMI tables") +@@ -115,7 +116,18 @@ class DMIinfo: + rep_n.newProp("not_available", "1") + else: + self.__dmixml.SetResultType(dmidecode.DMIXML_DOC) +- dmiqry = xmlout.convert_libxml2_to_lxml_doc(self.__dmixml.QuerySection('all')) ++ try: ++ dmiqry = xmlout.convert_libxml2_to_lxml_doc(self.__dmixml.QuerySection('all')) ++ except Exception as ex1: ++ self._log.log(Log.DEBUG, f'** EXCEPTION {str(ex1)}, will query BIOS only') ++ try: ++ # If we can't query 'all', at least query 'bios' ++ dmiqry = xmlout.convert_libxml2_to_lxml_doc(self.__dmixml.QuerySection('bios')) ++ except Exception as ex2: ++ rep_n.addContent("No DMI tables available") ++ rep_n.newProp("not_available", "1") ++ self._log.log(Log.DEBUG, f'** EXCEPTION {str(ex2)}, dmi info will not be reported') ++ return rep_n + resdoc = self.__xsltparser(dmiqry) + dmi_n = xmlout.convert_lxml_to_libxml2_nodes(resdoc.getroot()) + rep_n.addChild(dmi_n) +-- +2.39.0 + diff --git a/SOURCES/rteval-Don-t-attempt-to-get-DMIinfo-if-there-are-dmi.patch b/SOURCES/rteval-Don-t-attempt-to-get-DMIinfo-if-there-are-dmi.patch new file mode 100644 index 0000000..aaf95f8 --- /dev/null +++ b/SOURCES/rteval-Don-t-attempt-to-get-DMIinfo-if-there-are-dmi.patch @@ -0,0 +1,169 @@ +From bce23ecc5d8bb6cab86843f7a42164ee44ef091f Mon Sep 17 00:00:00 2001 +From: John Kacur +Date: Thu, 27 Oct 2022 11:14:27 -0400 +Subject: [PATCH 3/3] rteval: Don't attempt to get DMIinfo if there are dmi + warnings + +If the python module dmidecode is available, but produces warnings, +you can get a traceback. This happens on some arm boxes, +as shown in the traceback below. + +Fix this by treating any warnings that are not listed in the +ignorable warnings as if dmi info is not available. + +Also add logging to dmi.ProcessWarnings() + +./rteval-cmd -d10s +** DMI WARNING ** /sys/firmware/efi/systab: SMBIOS entry point missing +got system topology: 1 node system (4 cores per node) +rteval run on 5.19.16-200.fc36.aarch64 started at Fri Oct 21 16:11:51 2022 +started 3 loads on 4 cores +started measurement threads on 4 cores +Run duration: 10.0 seconds +stopping run at Fri Oct 21 16:13:26 2022 +Traceback (most recent call last): + File "/root/src/rteval/./rteval-cmd", line 402, in + ec = rteval.Measure() + File "/root/src/rteval/rteval/__init__.py", line 286, in Measure + self._report(measure_start, self.__rtevcfg.xslt_report) + File "/root/src/rteval/rteval/rtevalReport.py", line 76, in _report + self.__xmlreport.AppendXMLnodes(self._sysinfo.MakeReport()) + File "/root/src/rteval/rteval/sysinfo/__init__.py", line 69, in MakeReport + report_n.addChild(dmi.DMIinfo.MakeReport(self)) + File "/root/src/rteval/rteval/sysinfo/dmi.py", line 111, in MakeReport + dmiqry = xmlout.convert_libxml2_to_lxml_doc(self.__dmixml.QuerySection('all')) + File "/usr/lib64/python3.10/site-packages/dmidecode.py", line 64, in QuerySection + ret = libxml2.xmlDoc( _obj = xmlapi(query_type='s', +RuntimeError: [src/dmidecodemodule.c:331] Error decoding DMI data + +** COLLECTED WARNINGS ** +/sys/firmware/efi/systab: SMBIOS entry point missing +** END OF WARNINGS ** + +Signed-off-by: John Kacur +--- + rteval-cmd | 4 ++-- + rteval/sysinfo/__init__.py | 2 +- + rteval/sysinfo/dmi.py | 34 +++++++++++++++++++++------------- + 3 files changed, 24 insertions(+), 16 deletions(-) + +diff --git a/rteval-cmd b/rteval-cmd +index 6a928362828f..1e6a7fc86baa 100755 +--- a/rteval-cmd ++++ b/rteval-cmd +@@ -210,8 +210,6 @@ def remove_offline(cpulist): + if __name__ == '__main__': + from rteval.sysinfo import dmi + +- dmi.ProcessWarnings() +- + # set LD_BIND_NOW to resolve shared library symbols + # note: any string will do, nothing significant about 'rteval' + +@@ -261,6 +259,8 @@ if __name__ == '__main__': + | (rtevcfg.debugging and Log.DEBUG) + logger.SetLogVerbosity(loglev) + ++ dmi.ProcessWarnings(logger=logger) ++ + # Load modules + loadmods = LoadModules(config, logger=logger) + measuremods = MeasurementModules(config, logger=logger) +diff --git a/rteval/sysinfo/__init__.py b/rteval/sysinfo/__init__.py +index bb1d00810856..5767e5b7f6fe 100644 +--- a/rteval/sysinfo/__init__.py ++++ b/rteval/sysinfo/__init__.py +@@ -49,7 +49,7 @@ class SystemInfo(KernelInfo, SystemServices, dmi.DMIinfo, CPUtopology, + NetworkInfo.__init__(self, logger=logger) + + # Parse initial DMI decoding errors +- dmi.ProcessWarnings() ++ dmi.ProcessWarnings(logger=logger) + + # Parse CPU info + CPUtopology._parse(self) +diff --git a/rteval/sysinfo/dmi.py b/rteval/sysinfo/dmi.py +index 5965c128c093..83f347623b58 100644 +--- a/rteval/sysinfo/dmi.py ++++ b/rteval/sysinfo/dmi.py +@@ -1,6 +1,7 @@ + # + # Copyright 2009 - 2013 Clark Williams + # Copyright 2009 - 2013 David Sommerseth ++# Copyright 2022 John Kacur + # + # This program is free software; you can redistribute it and/or modify + # it under the terms of the GNU General Public License as published by +@@ -34,14 +35,19 @@ from rteval import rtevalConfig + + try: + import dmidecode +- dmidecode_loaded = True ++ dmidecode_avail = True + except ModuleNotFoundError: +- dmidecode_loaded = False ++ dmidecode_avail = False + +-def ProcessWarnings(): ++def set_dmidecode_avail(val): ++ """ Used to set global variable dmidecode_avail from a function """ ++ global dmidecode_avail ++ dmidecode_avail = val ++ ++def ProcessWarnings(logger=None): + """ Process Warnings from dmidecode """ + +- if not dmidecode_loaded: ++ if not dmidecode_avail: + return + + if not hasattr(dmidecode, 'get_warnings'): +@@ -62,7 +68,8 @@ def ProcessWarnings(): + + # All other warnings will be printed + if len(warnline) > 0: +- print(f"** DMI WARNING ** {warnline}") ++ logger.log(Log.DEBUG, f"** DMI WARNING ** {warnline}") ++ set_dmidecode_avail(False) + + dmidecode.clear_warnings() + +@@ -70,11 +77,11 @@ def ProcessWarnings(): + class DMIinfo: + '''class used to obtain DMI info via python-dmidecode''' + +- def __init__(self, logger): +- self.__version = '0.5' ++ def __init__(self, logger=None): ++ self.__version = '0.6' + +- if not dmidecode_loaded: +- logger.log(Log.DEBUG|Log.WARN, "No dmidecode module found, ignoring DMI tables") ++ if not dmidecode_avail: ++ logger.log(Log.DEBUG, "DMI info unavailable, ignoring DMI tables") + self.__fake = True + return + +@@ -127,14 +134,15 @@ def unit_test(rootdir): + self.__dict__[k] = self.config[k] + + try: +- ProcessWarnings() ++ log = Log() ++ log.SetLogVerbosity(Log.DEBUG|Log.INFO) ++ ++ ProcessWarnings(logger=log) + if os.getuid() != 0: + print("** ERROR ** Must be root to run this unit_test()") + return 1 + +- log = Log() +- log.SetLogVerbosity(Log.DEBUG|Log.INFO) +- d = DMIinfo(log) ++ d = DMIinfo(logger=log) + dx = d.MakeReport() + x = libxml2.newDoc("1.0") + x.setRootElement(dx) +-- +2.37.3 + diff --git a/SOURCES/rteval-Replace-python-ethtool-with-inline-code.patch b/SOURCES/rteval-Replace-python-ethtool-with-inline-code.patch new file mode 100644 index 0000000..59b4592 --- /dev/null +++ b/SOURCES/rteval-Replace-python-ethtool-with-inline-code.patch @@ -0,0 +1,399 @@ +From d0552193364d160252d117c5bf2e298a31550e3c Mon Sep 17 00:00:00 2001 +From: John Kacur +Date: Mon, 10 Oct 2022 09:49:47 -0400 +Subject: [PATCH] rteval: Replace python-ethtool with inline code + +This patch adds the file newnet.py to replace the use of python-ethtool +The information it generates will appear in the summary.xml +You can also test the functionality by running +python rteval/sysinfo/newnet.py + +Signed-off-by: John Kacur +- V2 Add SPDX license identifier +Signed-off-by: John Kacur +--- + rteval/sysinfo/__init__.py | 3 +- + rteval/sysinfo/network.py | 117 ------------------- + rteval/sysinfo/newnet.py | 225 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 227 insertions(+), 118 deletions(-) + delete mode 100644 rteval/sysinfo/network.py + create mode 100644 rteval/sysinfo/newnet.py + +diff --git a/rteval/sysinfo/__init__.py b/rteval/sysinfo/__init__.py +index a4359382f006..bb1d00810856 100644 +--- a/rteval/sysinfo/__init__.py ++++ b/rteval/sysinfo/__init__.py +@@ -32,7 +32,7 @@ from rteval.sysinfo.services import SystemServices + from rteval.sysinfo.cputopology import CPUtopology + from rteval.sysinfo.memory import MemoryInfo + from rteval.sysinfo.osinfo import OSInfo +-from rteval.sysinfo.network import NetworkInfo ++from rteval.sysinfo.newnet import NetworkInfo + from rteval.sysinfo.cmdline import cmdlineInfo + from rteval.sysinfo import dmi + +@@ -46,6 +46,7 @@ class SystemInfo(KernelInfo, SystemServices, dmi.DMIinfo, CPUtopology, + CPUtopology.__init__(self) + OSInfo.__init__(self, logger=logger) + cmdlineInfo.__init__(self, logger=logger) ++ NetworkInfo.__init__(self, logger=logger) + + # Parse initial DMI decoding errors + dmi.ProcessWarnings() +diff --git a/rteval/sysinfo/network.py b/rteval/sysinfo/network.py +deleted file mode 100644 +index ce9989a1240b..000000000000 +--- a/rteval/sysinfo/network.py ++++ /dev/null +@@ -1,117 +0,0 @@ +-# -*- coding: utf-8 -*- +-# +-# Copyright 2009 - 2013 David Sommerseth +-# +-# This program is free software; you can redistribute it and/or modify +-# it under the terms of the GNU General Public License as published by +-# the Free Software Foundation; either version 2 of the License, or +-# (at your option) any later version. +-# +-# This program is distributed in the hope that it will be useful, +-# but WITHOUT ANY WARRANTY; without even the implied warranty of +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-# GNU General Public License for more details. +-# +-# You should have received a copy of the GNU General Public License along +-# with this program; if not, write to the Free Software Foundation, Inc., +-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +-# +-# For the avoidance of doubt the "preferred form" of this code is one which +-# is in an open unpatent encumbered format. Where cryptographic key signing +-# forms part of the process of creating an executable the information +-# including keys needed to generate an equivalently functional executable +-# are deemed to be part of the source code. +-# +- +-import ethtool, libxml2 +- +-class NetworkInfo(object): +- def __init__(self): +- pass +- +- def net_GetDefaultGW(self): +- # Get the interface name for the IPv4 default gw +- route = open('/proc/net/route') +- defgw4 = None +- if route: +- rl = route.readline() +- while rl != '' : +- rl = route.readline() +- splt = rl.split("\t") +- # Only catch default route +- if len(splt) > 2 and splt[2] != '00000000' and splt[1] == '00000000': +- defgw4 = splt[0] +- break +- route.close() +- return (defgw4, None) # IPv6 gw not yet implemented +- +- def MakeReport(self): +- ncfg_n = libxml2.newNode("NetworkConfig") +- (defgw4, defgw6) = self.net_GetDefaultGW() +- +- # Make an interface tag for each device found +- if hasattr(ethtool, 'get_interfaces_info'): +- # Using the newer python-ethtool API (version >= 0.4) +- for dev in ethtool.get_interfaces_info(ethtool.get_devices()): +- if dev.device == 'lo': +- continue +- +- intf_n = libxml2.newNode('interface') +- intf_n.newProp('device', dev.device) +- intf_n.newProp('hwaddr', dev.mac_address) +- ncfg_n.addChild(intf_n) +- +- # Protcol configurations +- if dev.ipv4_address: +- ipv4_n = libxml2.newNode('IPv4') +- ipv4_n.newProp('ipaddr', dev.ipv4_address) +- ipv4_n.newProp('netmask', str(dev.ipv4_netmask)) +- ipv4_n.newProp('broadcast', dev.ipv4_broadcast) +- ipv4_n.newProp('defaultgw', (defgw4 == dev.device) and '1' or '0') +- intf_n.addChild(ipv4_n) +- +- for ip6 in dev.get_ipv6_addresses(): +- ipv6_n = libxml2.newNode('IPv6') +- ipv6_n.newProp('ipaddr', ip6.address) +- ipv6_n.newProp('netmask', str(ip6.netmask)) +- ipv6_n.newProp('scope', ip6.scope) +- intf_n.addChild(ipv6_n) +- +- else: # Fall back to older python-ethtool API (version < 0.4) +- ifdevs = ethtool.get_active_devices() +- ifdevs.remove('lo') +- ifdevs.sort() +- +- for dev in ifdevs: +- intf_n = libxml2.newNode('interface') +- intf_n.newProp('device', dev.device) +- intf_n.newProp('hwaddr', dev.mac_address) +- ncfg_n.addChild(intf_n) +- +- ipv4_n = libxml2.newNode('IPv4') +- ipv4_n.newProp('ipaddr', ethtool.get_ipaddr(dev)) +- ipv4_n.newProp('netmask', str(ethtool.get_netmask(dev))) +- ipv4_n.newProp('defaultgw', (defgw4 == dev) and '1' or '0') +- intf_n.addChild(ipv4_n) +- +- return ncfg_n +- +- +-def unit_test(rootdir): +- import sys +- try: +- net = NetworkInfo() +- doc = libxml2.newDoc('1.0') +- cfg = net.MakeReport() +- doc.setRootElement(cfg) +- doc.saveFormatFileEnc('-', 'UTF-8', 1) +- +- except Exception as e: +- import traceback +- traceback.print_exc(file=sys.stdout) +- print("** EXCEPTION %s", str(e)) +- return 1 +- +-if __name__ == '__main__': +- unit_test(None) +- +diff --git a/rteval/sysinfo/newnet.py b/rteval/sysinfo/newnet.py +new file mode 100644 +index 000000000000..63417d9e59f1 +--- /dev/null ++++ b/rteval/sysinfo/newnet.py +@@ -0,0 +1,225 @@ ++''' Module to obtain network information for the rteval report ''' ++# ++# Copyright 2022 John Kacur 0: ++ (iface, dest, gateway, _, _, _, _, _, _, _, _) = line.split() ++ if iface == 'Iface': ++ line = f.readline().strip() ++ continue ++ if dest == '00000000' and gateway != '00000000': ++ addr = int(gateway, base=16) ++ defaultgw = str(ipaddress.IPv4Address(socket.ntohl(addr))) ++ return defaultgw ++ line = f.readline().strip() ++ return defaultgw ++ ++class IPv6Addresses(): ++ ''' Obtains a list of IPv6 addresses from the proc file system ''' ++ ++ def __init__(self): ++ self.data = {} ++ IPv6Addresses.load(self) ++ ++ def __contains__(self, dev): ++ return dev in self.data ++ ++ def __getitem__(self, dev): ++ return self.data.get(dev, None) ++ ++ def __iter__(self): ++ return iter(self.data) ++ ++ def load(self): ++ ''' ++ Called by init to load the self.data dictionary with device keys ++ and a list of ipv6addresses ++ ''' ++ MYP = '/proc/net/if_inet6' ++ with open(MYP, 'r') as f: ++ mystr = f.readline().strip() ++ while len(mystr) > 0: ++ ipv6addr , _, _, _, _, intf = mystr.split() ++ ipv6addr = compress_iv6(ipv6addr) ++ if intf == 'lo': ++ mystr = f.readline().strip() ++ continue ++ if intf not in self.data: ++ self.data[intf] = [ipv6addr] ++ else: ++ self.data[intf].append(ipv6addr) ++ mystr = f.readline().strip() ++ ++class IPv4Addresses(): ++ ''' Obtains a list of IPv4 addresses from the proc file system ''' ++ ++ def __init__(self): ++ self.data = {} ++ IPv4Addresses.load(self) ++ ++ def __contains__(self, dev): ++ return dev in self.data ++ ++ def __getitem__(self, dev): ++ return self.data[dev] ++ ++ def __iter__(self): ++ return iter(self.data) ++ ++ def load(self): ++ ''' ++ Called by init to load the self.data dictionary with ++ device keys, and value consisting of a list of ++ ipv4address, netmask and broadcast address ++ ''' ++ MYP = '/proc/net/route' ++ with open(MYP, 'r') as f: ++ mystr = f.readline().strip() ++ while len(mystr) > 0: ++ intf, dest, _, _, _, _, _, mask, _, _, _ = mystr.split() ++ # Skip over the head of the table an the gateway line ++ if intf == "Iface" or dest == '00000000': ++ mystr = f.readline().strip() ++ continue ++ d1 = int(dest, base=16) ++ m1 = int(mask, base=16) ++ addr = str(ipaddress.IPv4Address(socket.ntohl(d1))) ++ netmask = str(ipaddress.IPv4Address(socket.ntohl(m1))) ++ addr_with_mask = ipaddress.ip_network(addr + '/' + netmask) ++ broadcast = str(addr_with_mask.broadcast_address) ++ if intf not in self.data: ++ self.data[intf] = [(addr, netmask, broadcast)] ++ else: ++ self.data[intf].append((addr, netmask, broadcast)) ++ mystr = f.readline().strip() ++ ++ ++class MacAddresses(): ++ ''' Obtains a list of hardware addresses of network devices ''' ++ ++ def __init__(self): ++ self.mac_address = {} ++ self.path = None ++ MacAddresses.load(self) ++ ++ def load(self): ++ ''' ++ called by init to load self.mac_address as a dictionary of ++ device keys, and mac or hardware addresses as values ++ ''' ++ nics = get_active_devices() ++ for nic in nics: ++ self.path = f'/sys/class/net/{nic}' ++ hwaddr = MacAddresses.set_val(self, 'address') ++ self.mac_address[nic] = hwaddr ++ ++ def set_val(self, val): ++ ''' Return the result of reading self.path/val ''' ++ val_path = f'{self.path}/{val}' ++ if os.path.exists(val_path): ++ with open(val_path, 'r') as f: ++ return f.readline().strip() ++ return None ++ ++ def __contains__(self, dev): ++ return dev in self.mac_address ++ ++ def __getitem__(self, dev): ++ return self.mac_address[dev] ++ ++ def __iter__(self): ++ return iter(self.mac_address) ++ ++class NetworkInfo(): ++ ''' Creates an xml report of the network for rteval ''' ++ ++ def __init__(self, logger): ++ self.defgw4 = get_defaultgw() ++ self.__logger = logger ++ ++ def MakeReport(self): ++ ''' Make an xml report for rteval ''' ++ ncfg_n = libxml2.newNode("NetworkConfig") ++ defgw4 = self.defgw4 ++ ++ mads = MacAddresses() ++ for device in mads: ++ if device == 'lo': ++ continue ++ intf_n = libxml2.newNode('interface') ++ intf_n.newProp('device', device) ++ intf_n.newProp('hwaddr', mads[device]) ++ ncfg_n.addChild(intf_n) ++ ++ ipv4ads = IPv4Addresses() ++ ipv6ads = IPv6Addresses() ++ for dev in ipv4ads: ++ if dev != device: ++ continue ++ for lelem in ipv4ads[dev]: ++ ipv4_n = libxml2.newNode('IPv4') ++ (ipaddr, netmask, broadcast) = lelem ++ ipv4_n.newProp('ipaddr', ipaddr) ++ ipv4_n.newProp('netmask', netmask) ++ ipv4_n.newProp('broadcast', broadcast) ++ ipv4_n.newProp('defaultgw', (defgw4 == ipaddr) and '1' or '0') ++ intf_n.addChild(ipv4_n) ++ if ipv6ads[dev]: ++ for lelem in ipv6ads[dev]: ++ ipv6_n = libxml2.newNode('IPv6') ++ ipaddr = lelem ++ ipv6_n.newProp('ipaddr', ipaddr) ++ intf_n.addChild(ipv6_n) ++ return ncfg_n ++ ++if __name__ == "__main__": ++ ++ try: ++ log = Log() ++ log.SetLogVerbosity(Log.DEBUG|Log.INFO) ++ net = NetworkInfo(logger=log) ++ doc = libxml2.newDoc('1.0') ++ cfg = net.MakeReport() ++ doc.setRootElement(cfg) ++ doc.saveFormatFileEnc('-', 'UTF-8', 1) ++ ++ except Exception as e: ++ import traceback ++ traceback.print_exc(file=sys.stdout) ++ print(f"** EXCEPTION {str(e)}") +-- +2.37.3 + diff --git a/SPECS/rteval.spec b/SPECS/rteval.spec index 5ffd145..780df22 100644 --- a/SPECS/rteval.spec +++ b/SPECS/rteval.spec @@ -1,6 +1,6 @@ Name: rteval -Version: 3.4 -Release: 2%{?dist} +Version: 3.5 +Release: 4%{?dist} Summary: Utility to evaluate system suitability for RT Linux Group: Development/Tools @@ -11,9 +11,10 @@ BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: python3-devel Requires: platform-python -Requires: python3-ethtool Requires: python3-lxml +Requires: python3-libxml2 Requires: python3-dmidecode >= 3.10 +Requires: python3-requests Requires: rt-tests >= 1.5-11 Requires: rteval-loads >= 1.6-2 Requires: sysstat @@ -32,6 +33,10 @@ Requires: libmpc libmpc-devel Obsoletes: rteval-common <= 3.1 #Patches +Patch1: rteval-Replace-python-ethtool-with-inline-code.patch +Patch2: Fix-DMI-WARNING-when-not-running-as-root.patch +Patch3: rteval-Don-t-attempt-to-get-DMIinfo-if-there-are-dmi.patch +Patch4: rteval-Catch-failures-in-python-dmidecode.patch %description The rteval script is a utility for measuring various aspects of @@ -44,6 +49,10 @@ to the screen. %prep %setup -q +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 %build %{__python3} setup.py build @@ -62,7 +71,6 @@ to the screen. %{python3_sitelib}/rteval/rtevalXMLRPC.py* %{python3_sitelib}/rteval/version.py* %{python3_sitelib}/rteval/Log.py* -%{python3_sitelib}/rteval/misc.py* %{python3_sitelib}/rteval/systopology.py* %{_mandir}/man8/rteval.8.gz %config(noreplace) %{_sysconfdir}/rteval.conf @@ -78,6 +86,39 @@ to the screen. %{python3_sitelib}/rteval/__pycache__/* %changelog +* Wed Feb 08 2023 John Kacur - 3.5-4 +- Add check to catch python-dmidecode if it fails +Resolves: rhbz#2168373 +jiraProject == RHELPLAN-148048 + +* Thu Oct 27 2022 John Kacur - 3.5-3 +- Fix "DMI WARNING" when not running as root +- Don't attempt to get DMI info if dmidecode returns warnings +Resolves: rhbz#2136926 + +* Mon Oct 17 2022 John Kacur - 3.5-2 +- Remove dependency on python-ethtool by using inline code +- Add Requires of python-libxml2 +Resolves: rhbz#2131377 + +* Fri Sep 23 2022 John Kacur - 3.5-1 +- Rebase to rteval-3.5 upstream +Resolves: rhbz#2119172 + +* Thu Sep 22 2022 Leah Leshchinsky - 3.4-5 +- Add measurement and load location to run report +Resolves: rhbz#2082260 + +* Tue Sep 13 2022 John Kacur - 3.4-4 +- Make use of systopology instead of misc everywhere +- Allow user to enter compressed form of cpulist +Resolves: rhbz#2121535 + +* Mon Sep 12 2022 John Kacur - 3.4-3 +- Add option for downloading the kernel to compile as a load +- Add a manpage entry for the kernel download option +Resolves: rhbz#2107710 + * Tue Jun 28 2022 John Kacur - 3.4-2 - Add back __pycache__ to the rhel-8.7 spec file Resolves: rhbz#2069354