def detect_system(hw_lst, output=None): 'Detect system characteristics from the output of lshw.' def find_element(xml, xml_spec, sys_subtype, sys_type='product', sys_cls='system', attrib=None, transform=None): 'Lookup an xml element and populate hw_lst when found.' elt = xml.findall(xml_spec) if len(elt) >= 1: if attrib: txt = elt[0].attrib[attrib] else: txt = elt[0].text if transform: txt = transform(txt) hw_lst.append((sys_cls, sys_type, sys_subtype, txt)) return txt return None # handle output injection for testing purpose if output: status = 0 else: status, output = cmd('lshw -xml') if status == 0: mobo_id = '' nic_id = '' xml = ET.fromstring(output) find_element(xml, "./node/serial", 'serial') find_element(xml, "./node/product", 'name') find_element(xml, "./node/vendor", 'vendor') find_element(xml, "./node/version", 'version') uuid = get_uuid(hw_lst) if uuid: # If we have an uuid, we shall check if it's part of a # known list of broken uuid # If so let's delete the uuid instead of reporting a stupid thing if uuid in ['Not']: uuid = '' else: hw_lst.append(('system', 'product', 'uuid', uuid)) for elt in xml.findall(".//node[@id='core']"): name = elt.find('physid') if name is not None: find_element(elt, 'product', 'name', 'motherboard', 'system') find_element(elt, 'vendor', 'vendor', 'motherboard', 'system') find_element(elt, 'version', 'version', 'motherboard', 'system') find_element(elt, 'serial', 'serial', 'motherboard', 'system') mobo_id = _get_value(hw_lst, 'system', 'motherboard', 'serial') for elt in xml.findall(".//node[@id='firmware']"): name = elt.find('physid') if name is not None: find_element(elt, 'version', 'version', 'bios', 'firmware') find_element(elt, 'date', 'date', 'bios', 'firmware') find_element(elt, 'vendor', 'vendor', 'bios', 'firmware') bank_count = 0 for elt in xml.findall(".//node[@class='memory']"): if not elt.attrib['id'].startswith('memory'): continue try: location = re.search('memory(:.*)', elt.attrib['id']).group(1) except AttributeError: location = '' name = elt.find('physid') if name is not None: find_element(elt, 'size', 'size', 'total', 'memory') for bank_list in elt.findall(".//node[@id]"): if 'bank:' in bank_list.get('id'): bank_count = bank_count + 1 for bank in elt.findall(".//node[@id='%s']" % (bank_list.get('id'))): bank_id = bank_list.get('id').replace( "bank:", "bank" + location + ":") find_element(bank, 'size', 'size', bank_id, 'memory') find_element(bank, 'clock', 'clock', bank_id, 'memory') find_element(bank, 'description', 'description', bank_id, 'memory') find_element(bank, 'vendor', 'vendor', bank_id, 'memory') find_element(bank, 'product', 'product', bank_id, 'memory') find_element(bank, 'serial', 'serial', bank_id, 'memory') find_element(bank, 'slot', 'slot', bank_id, 'memory') if bank_count > 0: hw_lst.append(('memory', 'banks', 'count', str(bank_count))) for elt in xml.findall(".//node[@class='network']"): name = elt.find('logicalname') if name is not None: find_element(elt, 'businfo', 'businfo', name.text, 'network') find_element(elt, 'vendor', 'vendor', name.text, 'network') find_element(elt, 'product', 'product', name.text, 'network') find_element(elt, "configuration/setting[@id='firmware']", 'firmware', name.text, 'network', 'value') find_element(elt, 'size', 'size', name.text, 'network') ipv4 = find_element(elt, "configuration/setting[@id='ip']", 'ipv4', name.text, 'network', 'value') if ipv4 is not None: sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: netmask = socket.inet_ntoa( fcntl.ioctl( sock, SIOCGIFNETMASK, struct.pack('256s', name.text.encode('utf-8')))[20:24]) hw_lst.append( ('network', name.text, 'ipv4-netmask', netmask)) cidr = get_cidr(netmask) hw_lst.append( ('network', name.text, 'ipv4-cidr', cidr)) net = (ipaddress.IPv4Interface( '%s/%s' % (ipv4, cidr)).network.network_address) hw_lst.append( ('network', name.text, 'ipv4-network', str(net))) except Exception as excpt: sys.stderr.write('unable to get info for %s: %s\n' % (name.text, str(excpt))) find_element(elt, "configuration/setting[@id='link']", 'link', name.text, 'network', 'value') find_element(elt, "configuration/setting[@id='driver']", 'driver', name.text, 'network', 'value') find_element(elt, "configuration/setting[@id='duplex']", 'duplex', name.text, 'network', 'value') find_element(elt, "configuration/setting[@id='speed']", 'speed', name.text, 'network', 'value') find_element(elt, "configuration/setting[@id='latency']", 'latency', name.text, 'network', 'value') find_element(elt, "configuration/setting[@id='autonegotiation']", 'autonegotiation', name.text, 'network', 'value') # lshw is not able to get the complete mac addr for ib # devices Let's workaround it with an ip command. if name.text.startswith('ib'): cmds = "ip addr show %s | grep link | awk '{print $2}'" status_ip, output_ip = cmd(cmds % name.text) if status_ip == 0: hw_lst.append(('network', name.text, 'serial', output_ip.split('\n')[0].lower())) else: find_element(elt, 'serial', 'serial', name.text, 'network', transform=lambda x: x.lower()) if not nic_id: nic_id = _get_value(hw_lst, 'network', name.text, 'serial') nic_id = nic_id.replace(':', '') detect_utils.get_ethtool_status(hw_lst, name.text) detect_utils.get_lld_status(hw_lst, name.text) fix_bad_serial(hw_lst, uuid, mobo_id, nic_id) else: sys.stderr.write("Unable to run lshw: %s\n" % output) return False get_cpus(hw_lst) osvendor_cmd = detect_utils.output_lines("lsb_release -is") for line in osvendor_cmd: hw_lst.append(('system', 'os', 'vendor', line.rstrip('\n').strip())) osinfo_cmd = detect_utils.output_lines("lsb_release -ds | tr -d '\"'") for line in osinfo_cmd: hw_lst.append(('system', 'os', 'version', line.rstrip('\n').strip())) uname_cmd = detect_utils.output_lines("uname -r") for line in uname_cmd: hw_lst.append( ('system', 'kernel', 'version', line.rstrip('\n').strip())) arch_cmd = detect_utils.output_lines("uname -i") for line in arch_cmd: hw_lst.append(('system', 'kernel', 'arch', line.rstrip('\n').strip())) cmdline_cmd = detect_utils.output_lines("cat /proc/cmdline") for line in cmdline_cmd: hw_lst.append( ('system', 'kernel', 'cmdline', line.rstrip('\n').strip())) return True
def get_cpus(hw_lst): def _maybe_int(v): try: base = 10 if 'x' in v: base = 16 v = int(v, base) except Exception: pass return v # Extracting lspcu information lscpu = {} output = detect_utils.output_lines('LANG=en_US.UTF-8 lscpu') for line in output: if ':' in line: item, value = line.split(':', 1) lscpu[item.strip(':')] = value.strip() # Extracting lspcu -x information # Use hexadecimal masks for CPU sets lscpux = {} output = detect_utils.output_lines('LANG=en_US.UTF-8 lscpu -x') for line in output: if ':' in line: item, value = line.split(':', 1) lscpux[item.strip(':')] = value.strip() hw_lst.append(("cpu", "physical", "number", int(lscpu["Socket(s)"]))) for processor in range(int(lscpu["Socket(s)"])): ptag = "physical_{}".format(processor) try: value = _from_file("/sys/devices/system/cpu/cpufreq/boost") except IOError: pass else: value = 'enabled' if value == '1' else 'disabled' hw_lst.append(('cpu', ptag, 'boost', value)) for (t_key, d_key, conv) in [('vendor', 'Vendor ID', None), ('product', 'Model name', None), ('cores', 'Core(s) per socket', int), ('threads', None, None), ('family', 'CPU family', int), ('model', 'Model', _maybe_int), ('stepping', 'Stepping', _maybe_int), ('l1d cache', 'L1d cache', None), ('l1i cache', 'L1i cache', None), ('l2 cache', 'L2 cache', None), ('l3 cache', 'L3 cache', None), ('min_Mhz', 'CPU min MHz', float), ('max_Mhz', 'CPU max MHz', float), ('current_Mhz', 'CPU MHz', float), ('flags', 'Flags', None)]: value = None if d_key in lscpu: value = lscpu[d_key] if conv: value = conv(value) elif t_key == 'threads': value = (int(lscpu.get('Thread(s) per core', 1)) * int(lscpu.get('Core(s) per socket', 1))) if value is not None: hw_lst.append(('cpu', ptag, t_key, value)) hw_lst.append(('cpu', 'logical', 'number', int(lscpu['CPU(s)']))) # Governors could be different on logical cpus for cpu in range(int(lscpu['CPU(s)'])): ltag = "logical_{}".format(cpu) try: value = _from_file(("/sys/devices/system/cpu/cpufreq/" "policy{}/scaling_governor".format(cpu))) except IOError: pass else: hw_lst.append(('cpu', ltag, "governor", value)) # Extracting numa nodes try: hw_lst.append(('numa', 'nodes', 'count', int(lscpu['NUMA node(s)']))) except KeyError: pass # Allow for sparse numa nodes. numa_nodes = [] for key in lscpux: match = re.match('NUMA node(\d+) CPU\(s\)', key) if match: numa_nodes.append((key, int(match.groups()[0]))) # NOTE(tonyb): Explicitly sort the list as prior to python 3.7? keys() did # not have a predictable ordering and there maybe consumers of hw_lst rely # on that. numa_nodes.sort(key=lambda t: t[1]) for (key, node_id) in numa_nodes: ntag = 'node_{}'.format(node_id) cpus = lscpu[key] # lscpu -x provides the cpu mask cpu_mask = lscpux[key] total_cpus = 0 min_cpu = None max_cpu = None # It's possible to have a NUMA node without any CPUs if cpus: for item in cpus.split(','): # lscpu report numa nodes like 0-5,48-53 if "-" in item: max_cpu = int(item.split("-")[1]) min_cpu = int(item.split("-")[0]) total_cpus = total_cpus + max_cpu - min_cpu + 1 else: # or like 0,1 # As we don't have dashes, there is only one core to count total_cpus = total_cpus + 1 # total_cpus = 12 for "0-5,48-53" hw_lst.append(('numa', ntag, 'cpu_count', total_cpus)) hw_lst.append(('numa', ntag, 'cpu_mask', cpu_mask))
def get_cpus(hw_lst): # Extracting lspcu information lscpu = {} output = detect_utils.output_lines('LANG=en_US.UTF-8 lscpu') for line in output: if ':' in line: item, value = line.split(':') lscpu[item.strip(':')] = value.strip() # Extracting lspcu -x information lscpux = {} output = detect_utils.output_lines('LANG=en_US.UTF-8 lscpu -x') for line in output: if ':' in line: item, value = line.split(':') lscpux[item.strip(':')] = value.strip() hw_lst.append(("cpu", "physical", "number", int(lscpu["Socket(s)"]))) for processor in range(int(lscpu["Socket(s)"])): hw_lst.append(('cpu', "physical_{}".format(processor), 'vendor', lscpu['Vendor ID'])) hw_lst.append(('cpu', "physical_{}".format(processor), 'product', lscpu['Model name'])) hw_lst.append(('cpu', "physical_{}".format(processor), 'cores', int(lscpu['Core(s) per socket']))) hw_lst.append(('cpu', "physical_{}".format(processor), 'threads', int(lscpu['Thread(s) per core']) * int(lscpu['Core(s) per socket']))) hw_lst.append(('cpu', "physical_{}".format(processor), 'family', int(lscpu['CPU family']))) hw_lst.append(('cpu', "physical_{}".format(processor), 'model', int(lscpu['Model']))) hw_lst.append(('cpu', "physical_{}".format(processor), 'stepping', int(lscpu['Stepping']))) for item in ['L1d cache', 'L1i cache', 'L2 cache', 'L3 cache']: hw_lst.append(('cpu', "physical_{}".format(processor), item.lower(), lscpu[item])) if 'CPU min MHz' in lscpu: hw_lst.append(('cpu', "physical_{}".format(processor), 'min_Mhz', float(lscpu['CPU min MHz']))) if 'CPU max MHz' in lscpu: hw_lst.append(('cpu', "physical_{}".format(processor), 'max_Mhz', float(lscpu['CPU max MHz']))) hw_lst.append(('cpu', "physical_{}".format(processor), 'current_Mhz', float(lscpu['CPU MHz']))) hw_lst.append( ('cpu', "physical_{}".format(processor), 'flags', lscpu['Flags'])) hw_lst.append(('cpu', 'logical', 'number', int(lscpu['CPU(s)']))) # Govenors could be differents on logical cpus for cpu in range(int(lscpu['CPU(s)'])): scaling_governor = detect_utils.output_lines( "cat /sys/devices/system/cpu/cpufreq/policy{}/scaling_governor". format(cpu)) for line in scaling_governor: hw_lst.append(('cpu', "logical_{}".format(cpu), "governor", line.rstrip('\n'))) # Extracting numa nodes hw_lst.append(('numa', 'nodes', 'count', int(lscpu['NUMA node(s)']))) for numa in range(int(lscpu['NUMA node(s)'])): cpus = lscpu['NUMA node{} CPU(s)'.format(numa)] # lscpu -x provides the cpu mask cpu_mask = lscpux['NUMA node{} CPU(s)'.format(numa)] total_cpus = 0 min_cpu = None max_cpu = None for item in cpus.split(','): # lscpu report numa nodes like 0-5,48-53 if "-" in item: max_cpu = int(item.split("-")[1]) min_cpu = int(item.split("-")[0]) total_cpus = total_cpus + max_cpu - min_cpu + 1 else: # or like 0,1 if min_cpu is None: min_cpu = int(item) else: max_cpu = int(item) total_cpus = total_cpus + max_cpu - min_cpu + 1 # total_cpus = 12 for "0-5,48-53" hw_lst.append( ('numa', 'node_{}'.format(numa), 'cpu_count', total_cpus)) hw_lst.append(('numa', 'node_{}'.format(numa), 'cpu_mask', cpu_mask))
def detect_system(hw_lst, output=None): 'Detect system characteristics from the output of lshw.' socket_count = 0 def find_element(xml, xml_spec, sys_subtype, sys_type='product', sys_cls='system', attrib=None, transform=None): 'Lookup an xml element and populate hw_lst when found.' elt = xml.findall(xml_spec) if len(elt) >= 1: if attrib: txt = elt[0].attrib[attrib] else: txt = elt[0].text if transform: txt = transform(txt) hw_lst.append((sys_cls, sys_type, sys_subtype, txt)) return txt return None # handle output injection for testing purpose if output: status = 0 else: status, output = cmd('lshw -xml') if status == 0: mobo_id = '' nic_id = '' xml = ET.fromstring(output) find_element(xml, "./node/serial", 'serial') find_element(xml, "./node/product", 'name') find_element(xml, "./node/vendor", 'vendor') find_element(xml, "./node/version", 'version') uuid = get_uuid() if uuid: # If we have an uuid, we shall check if it's part of a # known list of broken uuid # If so let's delete the uuid instead of reporting a stupid thing if uuid in ['Not']: uuid = '' else: hw_lst.append(('system', 'product', 'uuid', uuid)) for elt in xml.findall(".//node[@id='core']"): name = elt.find('physid') if name is not None: find_element(elt, 'product', 'name', 'motherboard', 'system') find_element(elt, 'vendor', 'vendor', 'motherboard', 'system') find_element(elt, 'version', 'version', 'motherboard', 'system') find_element(elt, 'serial', 'serial', 'motherboard', 'system') mobo_id = _get_value(hw_lst, 'system', 'motherboard', 'serial') for elt in xml.findall(".//node[@id='firmware']"): name = elt.find('physid') if name is not None: find_element(elt, 'version', 'version', 'bios', 'firmware') find_element(elt, 'date', 'date', 'bios', 'firmware') find_element(elt, 'vendor', 'vendor', 'bios', 'firmware') bank_count = 0 for elt in xml.findall(".//node[@class='memory']"): if not elt.attrib['id'].startswith('memory'): continue try: location = re.search('memory(:.*)', elt.attrib['id']).group(1) except AttributeError: location = '' name = elt.find('physid') if name is not None: find_element(elt, 'size', 'size', 'total', 'memory') for bank_list in elt.findall(".//node[@id]"): if 'bank:' in bank_list.get('id'): bank_count = bank_count + 1 for bank in elt.findall(".//node[@id='%s']" % (bank_list.get('id'))): bank_id = bank_list.get('id').replace("bank:", "bank" + location + ":") find_element(bank, 'size', 'size', bank_id, 'memory') find_element(bank, 'clock', 'clock', bank_id, 'memory') find_element(bank, 'description', 'description', bank_id, 'memory') find_element(bank, 'vendor', 'vendor', bank_id, 'memory') find_element(bank, 'product', 'product', bank_id, 'memory') find_element(bank, 'serial', 'serial', bank_id, 'memory') find_element(bank, 'slot', 'slot', bank_id, 'memory') if bank_count > 0: hw_lst.append(('memory', 'banks', 'count', str(bank_count))) for elt in xml.findall(".//node[@class='network']"): name = elt.find('logicalname') if name is not None: find_element(elt, 'businfo', 'businfo', name.text, 'network') find_element(elt, 'vendor', 'vendor', name.text, 'network') find_element(elt, 'product', 'product', name.text, 'network') find_element(elt, "configuration/setting[@id='firmware']", 'firmware', name.text, 'network', 'value') find_element(elt, 'size', 'size', name.text, 'network') ipv4 = find_element(elt, "configuration/setting[@id='ip']", 'ipv4', name.text, 'network', 'value') if ipv4 is not None: sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: netmask = socket.inet_ntoa( fcntl.ioctl( sock, SIOCGIFNETMASK, struct.pack('256s', name.text.encode('utf-8')))[20:24]) hw_lst.append( ('network', name.text, 'ipv4-netmask', netmask)) cidr = get_cidr(netmask) hw_lst.append( ('network', name.text, 'ipv4-cidr', cidr)) hw_lst.append( ('network', name.text, 'ipv4-network', "%s" % IPNetwork('%s/%s' % (ipv4, cidr)).network)) except Exception as excpt: sys.stderr.write('unable to get info for %s: %s\n' % (name.text, str(excpt))) find_element(elt, "configuration/setting[@id='link']", 'link', name.text, 'network', 'value') find_element(elt, "configuration/setting[@id='driver']", 'driver', name.text, 'network', 'value') find_element(elt, "configuration/setting[@id='duplex']", 'duplex', name.text, 'network', 'value') find_element(elt, "configuration/setting[@id='speed']", 'speed', name.text, 'network', 'value') find_element(elt, "configuration/setting[@id='latency']", 'latency', name.text, 'network', 'value') find_element(elt, "configuration/setting[@id='autonegotiation']", 'autonegotiation', name.text, 'network', 'value') # lshw is not able to get the complete mac addr for ib # devices Let's workaround it with an ip command. if name.text.startswith('ib'): cmds = "ip addr show %s | grep link | awk '{print $2}'" status_ip, output_ip = cmd(cmds % name.text) if status_ip == 0: hw_lst.append(('network', name.text, 'serial', output_ip.split('\n')[0].lower())) else: find_element(elt, 'serial', 'serial', name.text, 'network', transform=lambda x: x.lower()) if not nic_id: nic_id = _get_value(hw_lst, 'network', name.text, 'serial') nic_id = nic_id.replace(':', '') detect_utils.get_ethtool_status(hw_lst, name.text) detect_utils.get_lld_status(hw_lst, name.text) for elt in xml.findall(".//node[@class='processor']"): name = elt.find('physid') if name is not None: hw_lst.append(('cpu', 'physical_%s' % (socket_count), 'physid', name.text)) find_element(elt, 'product', 'product', 'physical_%s' % socket_count, 'cpu') find_element(elt, 'vendor', 'vendor', 'physical_%s' % socket_count, 'cpu') find_element(elt, 'version', 'version', 'physical_%s' % socket_count, 'cpu') find_element(elt, 'size', 'frequency', 'physical_%s' % socket_count, 'cpu') find_element(elt, 'clock', 'clock', 'physical_%s' % socket_count, 'cpu') find_element(elt, "configuration/setting[@id='cores']", 'cores', 'physical_%s' % socket_count, 'cpu', 'value') find_element(elt, "configuration/setting[@id='enabledcores']", 'enabled_cores', 'physical_%s' % socket_count, 'cpu', 'value') find_element(elt, "configuration/setting[@id='threads']", 'threads', 'physical_%s' % socket_count, 'cpu', 'value') elt_cap = elt.findall("capabilities/capability") cpu_flags = "" for cap in elt_cap: for element in cap.items(): cpu_flags = "%s %s" % (cpu_flags, element[1].strip()) hw_lst.append(('cpu', 'physical_%s' % (socket_count), 'flags', cpu_flags.strip())) socket_count = socket_count + 1 fix_bad_serial(hw_lst, uuid, mobo_id, nic_id) else: sys.stderr.write("Unable to run lshw: %s\n" % output) return False hw_lst.append(('cpu', 'physical', 'number', str(socket_count))) status, output = detect_utils.cmd('nproc') if status == 0: hw_lst.append(('cpu', 'logical', 'number', str(output).strip())) osvendor_cmd = detect_utils.output_lines("lsb_release -is") for line in osvendor_cmd: hw_lst.append(('system', 'os', 'vendor', line.rstrip('\n').strip())) osinfo_cmd = detect_utils.output_lines("lsb_release -ds | tr -d '\"'") for line in osinfo_cmd: hw_lst.append(('system', 'os', 'version', line.rstrip('\n').strip())) uname_cmd = detect_utils.output_lines("uname -r") for line in uname_cmd: hw_lst.append(('system', 'kernel', 'version', line.rstrip('\n').strip())) arch_cmd = detect_utils.output_lines("uname -i") for line in arch_cmd: hw_lst.append(('system', 'kernel', 'arch', line.rstrip('\n').strip())) cmdline_cmd = detect_utils.output_lines("cat /proc/cmdline") for line in cmdline_cmd: hw_lst.append(('system', 'kernel', 'cmdline', line.rstrip('\n').strip())) return True
def detect_system(hw_lst, output=None): 'Detect system characteristics from the output of lshw.' socket_count = 0 def find_element(xml, xml_spec, sys_subtype, sys_type='product', sys_cls='system', attrib=None, transform=None): 'Lookup an xml element and populate hw_lst when found.' elt = xml.findall(xml_spec) if len(elt) >= 1: if attrib: txt = elt[0].attrib[attrib] else: txt = elt[0].text if transform: txt = transform(txt) hw_lst.append((sys_cls, sys_type, sys_subtype, txt)) return txt return None # handle output injection for testing purpose if output: status = 0 else: status, output = cmd('lshw -xml') if status == 0: xml = ET.fromstring(output) find_element(xml, "./node/serial", 'serial') find_element(xml, "./node/product", 'name') find_element(xml, "./node/vendor", 'vendor') find_element(xml, "./node/version", 'version') uuid = get_uuid() if uuid: # If we have an uuid, let's manage a quirk list of stupid # serial numbers TYAN or Supermicro are known to provide # dirty serial numbers In that case, let's use the uuid # instead for i in hw_lst: if 'system' in i[0] and 'product' in i[1] and 'serial' in i[2]: # Does the current serial number is part of the quirk list if i[3] in ['0123456789']: # Let's delete the stupid SN and use the UUID instead hw_lst.remove(i) hw_lst.append(('system', 'product', 'serial', uuid)) break hw_lst.append(('system', 'product', 'uuid', uuid)) for elt in xml.findall(".//node[@id='core']"): name = elt.find('physid') if name is not None: find_element(elt, 'product', 'name', 'motherboard', 'system') find_element(elt, 'vendor', 'vendor', 'motherboard', 'system') find_element(elt, 'version', 'version', 'motherboard', 'system') find_element(elt, 'serial', 'serial', 'motherboard', 'system') for elt in xml.findall(".//node[@id='firmware']"): name = elt.find('physid') if name is not None: find_element(elt, 'version', 'version', 'bios', 'firmware') find_element(elt, 'date', 'date', 'bios', 'firmware') find_element(elt, 'vendor', 'vendor', 'bios', 'firmware') bank_count = 0 for elt in xml.findall(".//node[@class='memory']"): if not elt.attrib['id'].startswith('memory'): continue try: location = re.search('memory(:.*)', elt.attrib['id']).group(1) except AttributeError: location = '' name = elt.find('physid') if name is not None: find_element(elt, 'size', 'size', 'total', 'memory') for bank_list in elt.findall(".//node[@id]"): if 'bank:' in bank_list.get('id'): bank_count = bank_count + 1 for bank in elt.findall(".//node[@id='%s']" % (bank_list.get('id'))): bank_id = bank_list.get('id').replace( "bank:", "bank" + location + ":") find_element(bank, 'size', 'size', bank_id, 'memory') find_element(bank, 'clock', 'clock', bank_id, 'memory') find_element(bank, 'description', 'description', bank_id, 'memory') find_element(bank, 'vendor', 'vendor', bank_id, 'memory') find_element(bank, 'product', 'product', bank_id, 'memory') find_element(bank, 'serial', 'serial', bank_id, 'memory') find_element(bank, 'slot', 'slot', bank_id, 'memory') if bank_count > 0: hw_lst.append(('memory', 'banks', 'count', str(bank_count))) for elt in xml.findall(".//node[@class='network']"): name = elt.find('logicalname') if name is not None: find_element(elt, 'businfo', 'businfo', name.text, 'network') find_element(elt, 'vendor', 'vendor', name.text, 'network') find_element(elt, 'product', 'product', name.text, 'network') find_element(elt, "configuration/setting[@id='firmware']", 'firmware', name.text, 'network', 'value') find_element(elt, 'size', 'size', name.text, 'network') ipv4 = find_element(elt, "configuration/setting[@id='ip']", 'ipv4', name.text, 'network', 'value') if ipv4 is not None: sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: netmask = socket.inet_ntoa( fcntl.ioctl( sock, SIOCGIFNETMASK, struct.pack('256s', name.text.encode('utf-8')))[20:24]) hw_lst.append( ('network', name.text, 'ipv4-netmask', netmask)) cidr = get_cidr(netmask) hw_lst.append( ('network', name.text, 'ipv4-cidr', cidr)) hw_lst.append( ('network', name.text, 'ipv4-network', "%s" % IPNetwork('%s/%s' % (ipv4, cidr)).network)) except Exception as excpt: sys.stderr.write('unable to get info for %s: %s\n' % (name.text, str(excpt))) find_element(elt, "configuration/setting[@id='link']", 'link', name.text, 'network', 'value') find_element(elt, "configuration/setting[@id='driver']", 'driver', name.text, 'network', 'value') find_element(elt, "configuration/setting[@id='duplex']", 'duplex', name.text, 'network', 'value') find_element(elt, "configuration/setting[@id='speed']", 'speed', name.text, 'network', 'value') find_element(elt, "configuration/setting[@id='latency']", 'latency', name.text, 'network', 'value') find_element(elt, "configuration/setting[@id='autonegotiation']", 'autonegotiation', name.text, 'network', 'value') # lshw is not able to get the complete mac addr for ib # devices Let's workaround it with an ip command. if name.text.startswith('ib'): cmds = "ip addr show %s | grep link | awk '{print $2}'" status_ip, output_ip = cmd(cmds % name.text) if status_ip == 0: hw_lst.append(('network', name.text, 'serial', output_ip.split('\n')[0].lower())) else: find_element(elt, 'serial', 'serial', name.text, 'network', transform=lambda x: x.lower()) detect_utils.get_ethtool_status(hw_lst, name.text) detect_utils.get_lld_status(hw_lst, name.text) for elt in xml.findall(".//node[@class='processor']"): name = elt.find('physid') if name is not None: hw_lst.append(('cpu', 'physical_%s' % (socket_count), 'physid', name.text)) find_element(elt, 'product', 'product', 'physical_%s' % socket_count, 'cpu') find_element(elt, 'vendor', 'vendor', 'physical_%s' % socket_count, 'cpu') find_element(elt, 'version', 'version', 'physical_%s' % socket_count, 'cpu') find_element(elt, 'size', 'frequency', 'physical_%s' % socket_count, 'cpu') find_element(elt, 'clock', 'clock', 'physical_%s' % socket_count, 'cpu') find_element(elt, "configuration/setting[@id='cores']", 'cores', 'physical_%s' % socket_count, 'cpu', 'value') find_element(elt, "configuration/setting[@id='enabledcores']", 'enabled_cores', 'physical_%s' % socket_count, 'cpu', 'value') find_element(elt, "configuration/setting[@id='threads']", 'threads', 'physical_%s' % socket_count, 'cpu', 'value') elt_cap = elt.findall("capabilities/capability") cpu_flags = "" for cap in elt_cap: for element in cap.items(): cpu_flags = "%s %s" % (cpu_flags, element[1].strip()) hw_lst.append(('cpu', 'physical_%s' % (socket_count), 'flags', cpu_flags.strip())) socket_count = socket_count + 1 else: sys.stderr.write("Unable to run lshw: %s\n" % output) hw_lst.append(('cpu', 'physical', 'number', str(socket_count))) status, output = detect_utils.cmd('nproc') if status == 0: hw_lst.append(('cpu', 'logical', 'number', str(output).strip())) osvendor_cmd = detect_utils.output_lines("lsb_release -is") for line in osvendor_cmd: hw_lst.append(('system', 'os', 'vendor', line.rstrip('\n').strip())) osinfo_cmd = detect_utils.output_lines("lsb_release -ds | tr -d '\"'") for line in osinfo_cmd: hw_lst.append(('system', 'os', 'version', line.rstrip('\n').strip())) uname_cmd = detect_utils.output_lines("uname -r") for line in uname_cmd: hw_lst.append( ('system', 'kernel', 'version', line.rstrip('\n').strip())) arch_cmd = detect_utils.output_lines("uname -i") for line in arch_cmd: hw_lst.append(('system', 'kernel', 'arch', line.rstrip('\n').strip())) cmdline_cmd = detect_utils.output_lines("cat /proc/cmdline") for line in cmdline_cmd: hw_lst.append( ('system', 'kernel', 'cmdline', line.rstrip('\n').strip()))
def get_cpus(hw_lst): def _maybe_int(v): try: base = 10 if 'x' in v: base = 16 v = int(v, base) except Exception: pass return v # Extracting lspcu information lscpu = {} output = detect_utils.output_lines('LANG=en_US.UTF-8 lscpu') for line in output: if ':' in line: item, value = line.split(':') lscpu[item.strip(':')] = value.strip() # Extracting lspcu -x information lscpux = {} output = detect_utils.output_lines('LANG=en_US.UTF-8 lscpu -x') for line in output: if ':' in line: item, value = line.split(':') lscpux[item.strip(':')] = value.strip() hw_lst.append(("cpu", "physical", "number", int(lscpu["Socket(s)"]))) for processor in range(int(lscpu["Socket(s)"])): ptag = "physical_{}".format(processor) (exists, value) = _from_file("/sys/devices/system/cpu/cpufreq/boost", mapping={'1': 'enabled'}, default='disabled') if exists: hw_lst.append(('cpu', ptag, 'boost', value)) for (t_key, d_key, conv) in [('vendor', 'Vendor ID', None), ('product', 'Model name', None), ('cores', 'Core(s) per socket', int), ('threads', None, None), ('family', 'CPU family', int), ('model', 'Model', _maybe_int), ('stepping', 'Stepping', _maybe_int), ('l1d cache', 'L1d cache', None), ('l1i cache', 'L1i cache', None), ('l2 cache', 'L2 cache', None), ('l3 cache', 'L3 cache', None), ('min_Mhz', 'CPU min MHz', float), ('max_Mhz', 'CPU max MHz', float), ('current_Mhz', 'CPU MHz', float), ('flags', 'Flags', None)]: value = None if d_key in lscpu: value = lscpu[d_key] if conv: value = conv(value) elif t_key == 'threads': value = (int(lscpu.get('Thread(s) per core', 1)) * int(lscpu.get('Core(s) per socket', 1))) if value is not None: hw_lst.append(('cpu', ptag, t_key, value)) hw_lst.append(('cpu', 'logical', 'number', int(lscpu['CPU(s)']))) # Governors could be different on logical cpus for cpu in range(int(lscpu['CPU(s)'])): ltag = "logical_{}".format(cpu) (exists, value) = _from_file(("/sys/devices/system/cpu/cpufreq/" "policy{}/scaling_governor".format(cpu))) if exists: hw_lst.append(('cpu', ltag, "governor", value)) # Extracting numa nodes hw_lst.append(('numa', 'nodes', 'count', int(lscpu['NUMA node(s)']))) # Allow for sparse numa nodes. numa_nodes = [] for key in lscpux: match = re.match('NUMA node(\d+) CPU\(s\)', key) if match: numa_nodes.append((key, int(match.groups()[0]))) # NOTE(tonyb): Explictly sort the list as prior to python 3.7? keys() did # not have a predictable ordering and there maybe consumers of hw_lst rely # on that. numa_nodes.sort(key=lambda t: t[1]) for (key, node_id) in numa_nodes: ntag = 'node_{}'.format(node_id) cpus = lscpu[key] # lscpu -x provides the cpu mask cpu_mask = lscpux[key] total_cpus = 0 min_cpu = None max_cpu = None # It's possible to have a NUMA node without any CPUs if cpus: for item in cpus.split(','): # lscpu report numa nodes like 0-5,48-53 if "-" in item: max_cpu = int(item.split("-")[1]) min_cpu = int(item.split("-")[0]) total_cpus = total_cpus + max_cpu - min_cpu + 1 else: # or like 0,1 if min_cpu is None: min_cpu = int(item) else: max_cpu = int(item) total_cpus = total_cpus + max_cpu - min_cpu + 1 # total_cpus = 12 for "0-5,48-53" hw_lst.append(('numa', ntag, 'cpu_count', total_cpus)) hw_lst.append(('numa', ntag, 'cpu_mask', cpu_mask))
def detect_system(hw_lst, output=None): "Detect system characteristics from the output of lshw." socket_count = 0 def find_element(xml, xml_spec, sys_subtype, sys_type="product", sys_cls="system", attrib=None, transform=None): "Lookup an xml element and populate hw_lst when found." elt = xml.findall(xml_spec) if len(elt) >= 1: if attrib: txt = elt[0].attrib[attrib] else: txt = elt[0].text if transform: txt = transform(txt) hw_lst.append((sys_cls, sys_type, sys_subtype, txt)) return txt return None # handle output injection for testing purpose if output: status = 0 else: status, output = cmd("lshw -xml") if status == 0: mobo_id = "" nic_id = "" xml = ET.fromstring(output) find_element(xml, "./node/serial", "serial") find_element(xml, "./node/product", "name") find_element(xml, "./node/vendor", "vendor") find_element(xml, "./node/version", "version") uuid = get_uuid() if uuid: # If we have an uuid, we shall check if it's part of a # known list of broken uuid # If so let's delete the uuid instead of reporting a stupid thing if uuid in ["Not"]: uuid = "" else: hw_lst.append(("system", "product", "uuid", uuid)) for elt in xml.findall(".//node[@id='core']"): name = elt.find("physid") if name is not None: find_element(elt, "product", "name", "motherboard", "system") find_element(elt, "vendor", "vendor", "motherboard", "system") find_element(elt, "version", "version", "motherboard", "system") find_element(elt, "serial", "serial", "motherboard", "system") mobo_id = _get_value(hw_lst, "system", "motherboard", "serial") for elt in xml.findall(".//node[@id='firmware']"): name = elt.find("physid") if name is not None: find_element(elt, "version", "version", "bios", "firmware") find_element(elt, "date", "date", "bios", "firmware") find_element(elt, "vendor", "vendor", "bios", "firmware") bank_count = 0 for elt in xml.findall(".//node[@class='memory']"): if not elt.attrib["id"].startswith("memory"): continue try: location = re.search("memory(:.*)", elt.attrib["id"]).group(1) except AttributeError: location = "" name = elt.find("physid") if name is not None: find_element(elt, "size", "size", "total", "memory") for bank_list in elt.findall(".//node[@id]"): if "bank:" in bank_list.get("id"): bank_count = bank_count + 1 for bank in elt.findall(".//node[@id='%s']" % (bank_list.get("id"))): bank_id = bank_list.get("id").replace("bank:", "bank" + location + ":") find_element(bank, "size", "size", bank_id, "memory") find_element(bank, "clock", "clock", bank_id, "memory") find_element(bank, "description", "description", bank_id, "memory") find_element(bank, "vendor", "vendor", bank_id, "memory") find_element(bank, "product", "product", bank_id, "memory") find_element(bank, "serial", "serial", bank_id, "memory") find_element(bank, "slot", "slot", bank_id, "memory") if bank_count > 0: hw_lst.append(("memory", "banks", "count", str(bank_count))) for elt in xml.findall(".//node[@class='network']"): name = elt.find("logicalname") if name is not None: find_element(elt, "businfo", "businfo", name.text, "network") find_element(elt, "vendor", "vendor", name.text, "network") find_element(elt, "product", "product", name.text, "network") find_element(elt, "configuration/setting[@id='firmware']", "firmware", name.text, "network", "value") find_element(elt, "size", "size", name.text, "network") ipv4 = find_element(elt, "configuration/setting[@id='ip']", "ipv4", name.text, "network", "value") if ipv4 is not None: sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: netmask = socket.inet_ntoa( fcntl.ioctl(sock, SIOCGIFNETMASK, struct.pack("256s", name.text.encode("utf-8")))[20:24] ) hw_lst.append(("network", name.text, "ipv4-netmask", netmask)) cidr = get_cidr(netmask) hw_lst.append(("network", name.text, "ipv4-cidr", cidr)) hw_lst.append( ("network", name.text, "ipv4-network", "%s" % IPNetwork("%s/%s" % (ipv4, cidr)).network) ) except Exception as excpt: sys.stderr.write("unable to get info for %s: %s\n" % (name.text, str(excpt))) find_element(elt, "configuration/setting[@id='link']", "link", name.text, "network", "value") find_element(elt, "configuration/setting[@id='driver']", "driver", name.text, "network", "value") find_element(elt, "configuration/setting[@id='duplex']", "duplex", name.text, "network", "value") find_element(elt, "configuration/setting[@id='speed']", "speed", name.text, "network", "value") find_element(elt, "configuration/setting[@id='latency']", "latency", name.text, "network", "value") find_element( elt, "configuration/setting[@id='autonegotiation']", "autonegotiation", name.text, "network", "value", ) # lshw is not able to get the complete mac addr for ib # devices Let's workaround it with an ip command. if name.text.startswith("ib"): cmds = "ip addr show %s | grep link | awk '{print $2}'" status_ip, output_ip = cmd(cmds % name.text) if status_ip == 0: hw_lst.append(("network", name.text, "serial", output_ip.split("\n")[0].lower())) else: find_element(elt, "serial", "serial", name.text, "network", transform=lambda x: x.lower()) if not nic_id: nic_id = _get_value(hw_lst, "network", name.text, "serial") nic_id = nic_id.replace(":", "") detect_utils.get_ethtool_status(hw_lst, name.text) detect_utils.get_lld_status(hw_lst, name.text) for elt in xml.findall(".//node[@class='processor']"): name = elt.find("physid") if name is not None: hw_lst.append(("cpu", "physical_%s" % (socket_count), "physid", name.text)) find_element(elt, "product", "product", "physical_%s" % socket_count, "cpu") find_element(elt, "vendor", "vendor", "physical_%s" % socket_count, "cpu") find_element(elt, "version", "version", "physical_%s" % socket_count, "cpu") find_element(elt, "size", "frequency", "physical_%s" % socket_count, "cpu") find_element(elt, "clock", "clock", "physical_%s" % socket_count, "cpu") find_element( elt, "configuration/setting[@id='cores']", "cores", "physical_%s" % socket_count, "cpu", "value" ) find_element( elt, "configuration/setting[@id='enabledcores']", "enabled_cores", "physical_%s" % socket_count, "cpu", "value", ) find_element( elt, "configuration/setting[@id='threads']", "threads", "physical_%s" % socket_count, "cpu", "value" ) elt_cap = elt.findall("capabilities/capability") cpu_flags = "" for cap in elt_cap: for element in cap.items(): cpu_flags = "%s %s" % (cpu_flags, element[1].strip()) hw_lst.append(("cpu", "physical_%s" % (socket_count), "flags", cpu_flags.strip())) socket_count = socket_count + 1 fix_bad_serial(hw_lst, uuid, mobo_id, nic_id) else: sys.stderr.write("Unable to run lshw: %s\n" % output) return False hw_lst.append(("cpu", "physical", "number", str(socket_count))) status, output = detect_utils.cmd("nproc") if status == 0: hw_lst.append(("cpu", "logical", "number", str(output).strip())) osvendor_cmd = detect_utils.output_lines("lsb_release -is") for line in osvendor_cmd: hw_lst.append(("system", "os", "vendor", line.rstrip("\n").strip())) osinfo_cmd = detect_utils.output_lines("lsb_release -ds | tr -d '\"'") for line in osinfo_cmd: hw_lst.append(("system", "os", "version", line.rstrip("\n").strip())) uname_cmd = detect_utils.output_lines("uname -r") for line in uname_cmd: hw_lst.append(("system", "kernel", "version", line.rstrip("\n").strip())) arch_cmd = detect_utils.output_lines("uname -i") for line in arch_cmd: hw_lst.append(("system", "kernel", "arch", line.rstrip("\n").strip())) cmdline_cmd = detect_utils.output_lines("cat /proc/cmdline") for line in cmdline_cmd: hw_lst.append(("system", "kernel", "cmdline", line.rstrip("\n").strip())) return True