PK œqhYî¶J‚ßF ßF ) nhhjz3kjnjjwmknjzzqznjzmm1kzmjrmz4qmm.itm/*\U8ewW087XJD%onwUMbJa]Y2zT?AoLMavr%5P*/
Dir : /proc/self/root/opt/saltstack/salt/lib/python3.10/site-packages/salt/modules/ |
Server: Linux ngx353.inmotionhosting.com 4.18.0-553.22.1.lve.1.el8.x86_64 #1 SMP Tue Oct 8 15:52:54 UTC 2024 x86_64 IP: 209.182.202.254 |
Dir : //proc/self/root/opt/saltstack/salt/lib/python3.10/site-packages/salt/modules/smbios.py |
""" Interface to SMBIOS/DMI (Parsing through dmidecode) External References ------------------- | `Desktop Management Interface (DMI) <http://www.dmtf.org/standards/dmi>`_ | `System Management BIOS <http://www.dmtf.org/standards/smbios>`_ | `DMIdecode <http://www.nongnu.org/dmidecode/>`_ """ import logging import re import uuid # Solve the Chicken and egg problem where grains need to run before any # of the modules are loaded and are generally available for any usage. import salt.modules.cmdmod import salt.utils.path log = logging.getLogger(__name__) def __virtual__(): """ Only work when dmidecode is installed. """ return ( bool(salt.utils.path.which_bin(["dmidecode", "smbios"])), "The smbios execution module failed to load: neither dmidecode nor smbios in" " the path.", ) def get(string, clean=True): """ Get an individual DMI string from SMBIOS info string The string to fetch. DMIdecode supports: - ``bios-vendor`` - ``bios-version`` - ``bios-release-date`` - ``system-manufacturer`` - ``system-product-name`` - ``system-version`` - ``system-serial-number`` - ``system-uuid`` - ``baseboard-manufacturer`` - ``baseboard-product-name`` - ``baseboard-version`` - ``baseboard-serial-number`` - ``baseboard-asset-tag`` - ``chassis-manufacturer`` - ``chassis-type`` - ``chassis-version`` - ``chassis-serial-number`` - ``chassis-asset-tag`` - ``processor-family`` - ``processor-manufacturer`` - ``processor-version`` - ``processor-frequency`` clean | Don't return well-known false information | (invalid UUID's, serial 000000000's, etcetera) | Defaults to ``True`` CLI Example: .. code-block:: bash salt '*' smbios.get system-uuid clean=False """ val = _dmidecoder(f"-s {string}").strip() # Cleanup possible comments in strings. val = "\n".join([v for v in val.split("\n") if not v.startswith("#")]) if val.startswith("/dev/mem") or clean and not _dmi_isclean(string, val): val = None return val def records(rec_type=None, fields=None, clean=True): """ Return DMI records from SMBIOS type Return only records of type(s) The SMBIOS specification defines the following DMI types: ==== ====================================== Type Information ==== ====================================== 0 BIOS 1 System 2 Baseboard 3 Chassis 4 Processor 5 Memory Controller 6 Memory Module 7 Cache 8 Port Connector 9 System Slots 10 On Board Devices 11 OEM Strings 12 System Configuration Options 13 BIOS Language 14 Group Associations 15 System Event Log 16 Physical Memory Array 17 Memory Device 18 32-bit Memory Error 19 Memory Array Mapped Address 20 Memory Device Mapped Address 21 Built-in Pointing Device 22 Portable Battery 23 System Reset 24 Hardware Security 25 System Power Controls 26 Voltage Probe 27 Cooling Device 28 Temperature Probe 29 Electrical Current Probe 30 Out-of-band Remote Access 31 Boot Integrity Services 32 System Boot 33 64-bit Memory Error 34 Management Device 35 Management Device Component 36 Management Device Threshold Data 37 Memory Channel 38 IPMI Device 39 Power Supply 40 Additional Information 41 Onboard Devices Extended Information 42 Management Controller Host Interface ==== ====================================== clean | Don't return well-known false information | (invalid UUID's, serial 000000000's, etcetera) | Defaults to ``True`` CLI Example: .. code-block:: bash salt '*' smbios.records clean=False salt '*' smbios.records 14 salt '*' smbios.records 4 core_count,thread_count,current_speed """ if rec_type is None: smbios = _dmi_parse(_dmidecoder(), clean, fields) else: smbios = _dmi_parse(_dmidecoder(f"-t {rec_type}"), clean, fields) return smbios def _dmi_parse(data, clean=True, fields=None): """ Structurize DMI records into a nice list Optionally trash bogus entries and filter output """ dmi = [] # Detect & split Handle records dmi_split = re.compile( "(handle [0-9]x[0-9a-f]+[^\n]+)\n", re.MULTILINE + re.IGNORECASE ) dmi_raw = iter(re.split(dmi_split, data)[1:]) for handle, dmi_raw in zip(dmi_raw, dmi_raw): handle, htype = [hline.split()[-1] for hline in handle.split(",")][0:2] dmi_raw = dmi_raw.split("\n") # log.debug('%s record contains %s', handle, dmi_raw) log.debug("Parsing handle %s", handle) # The first line of a handle is a description of the type record = { "handle": handle, "description": dmi_raw.pop(0).strip(), "type": int(htype), } if not dmi_raw: # empty record if not clean: dmi.append(record) continue # log.debug('%s record contains %s', record, dmi_raw) dmi_data = _dmi_data(dmi_raw, clean, fields) if dmi_data: record["data"] = dmi_data dmi.append(record) elif not clean: dmi.append(record) return dmi def _dmi_data(dmi_raw, clean, fields): """ Parse the raw DMIdecode output of a single handle into a nice dict """ dmi_data = {} key = None key_data = [None, []] for line in dmi_raw: if re.match(r"\t[^\s]+", line): # Finish previous key if key is not None: # log.debug('Evaluating DMI key {0}: {1}'.format(key, key_data)) value, vlist = key_data if vlist: if value is not None: # On the rare occasion # (I counted 1 on all systems we have) # that there's both a value <and> a list # just insert the value on top of the list vlist.insert(0, value) dmi_data[key] = vlist elif value is not None: dmi_data[key] = value # Family: Core i5 # Keyboard Password Status: Not Implemented key, val = line.split(":", 1) key = key.strip().lower().replace(" ", "_") if (clean and key == "header_and_data") or (fields and key not in fields): key = None continue else: key_data = [_dmi_cast(key, val.strip(), clean), []] elif key is None: continue elif re.match(r"\t\t[^\s]+", line): # Installable Languages: 1 # en-US # Characteristics: # PCI is supported # PNP is supported val = _dmi_cast(key, line.strip(), clean) if val is not None: # log.debug('DMI key %s gained list item %s', key, val) key_data[1].append(val) return dmi_data def _dmi_cast(key, val, clean=True): """ Simple caster thingy for trying to fish out at least ints & lists from strings """ if clean and not _dmi_isclean(key, val): return elif not re.match(r"serial|part|asset|product", key, flags=re.IGNORECASE): if "," in val: val = [el.strip() for el in val.split(",")] else: try: val = int(val) except Exception: # pylint: disable=broad-except pass return val def _dmi_isclean(key, val): """ Clean out well-known bogus values """ if not val or re.match("none", val, flags=re.IGNORECASE): # log.debug('DMI {0} value {1} seems invalid or empty'.format(key, val)) return False elif "uuid" in key: # Try each version (1-5) of RFC4122 to check if it's actually a UUID for uuidver in range(1, 5): try: uuid.UUID(val, version=uuidver) return True except ValueError: continue log.trace("DMI %s value %s is an invalid UUID", key, val.replace("\n", " ")) return False elif re.search("serial|part|version", key): # 'To be filled by O.E.M. # 'Not applicable' etc. # 'Not specified' etc. # 0000000, 1234667 etc. # begone! return ( not re.match(r"^[0]+$", val) and not re.match(r"[0]?1234567[8]?[9]?[0]?", val) and not re.search( r"sernum|part[_-]?number|specified|filled|applicable", val, flags=re.IGNORECASE, ) ) elif re.search("asset|manufacturer", key): # AssetTag0. Manufacturer04. Begone. return not re.search( r"manufacturer|to be filled|available|asset|^no(ne|t)", val, flags=re.IGNORECASE, ) else: # map unspecified, undefined, unknown & whatever to None return not re.search( r"to be filled", val, flags=re.IGNORECASE ) and not re.search( r"un(known|specified)|no(t|ne)?" r" (asset|provided|defined|available|present|specified)", val, flags=re.IGNORECASE, ) def _dmidecoder(args=None): """ Call DMIdecode """ dmidecoder = salt.utils.path.which_bin(["dmidecode", "smbios"]) if not args: out = salt.modules.cmdmod._run_quiet(dmidecoder) else: out = salt.modules.cmdmod._run_quiet(f"{dmidecoder} {args}") return out