Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
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))
Ejemplo n.º 3
0
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))
Ejemplo n.º 4
0
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
Ejemplo n.º 5
0
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()))
Ejemplo n.º 6
0
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))
Ejemplo n.º 7
0
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