Mini Shell
"""
Module for devinfo
:maintainer: Alberto Planas <aplanas@suse.com>
:maturity: new
:depends: None
:platform: Linux
"""
import logging
log = logging.getLogger(__name__)
__func_alias__ = {
"filter_": "filter",
}
def _udev(udev_info, key):
"""
Return the value for a udev key.
The `key` parameter is a lower case text joined by dots. For
example, 'e.id_bus' will represent the key for
`udev_info['E']['ID_BUS']`.
"""
k, _, r = key.partition(".")
if not k:
return udev_info
if not isinstance(udev_info, dict):
return "n/a"
if not r:
return udev_info.get(k.upper(), "n/a")
return _udev(udev_info.get(k.upper(), {}), r)
def _match(udev_info, match_info):
"""
Check if `udev_info` match the information from `match_info`.
"""
res = True
for key, value in match_info.items():
udev_value = _udev(udev_info, key)
if isinstance(udev_value, dict):
# If is a dict we probably make a mistake in key from
# match_info, as is not accessing a final value
log.warning(
"The key %s for the udev information dictionary is not a leaf element",
key,
)
continue
# Converting both values to sets make easy to see if there is
# a coincidence between both values
value = set(value) if isinstance(value, list) else {value}
udev_value = set(udev_value) if isinstance(udev_value, list) else {udev_value}
res = res and (value & udev_value)
return res
def filter_(udev_in=None, udev_ex=None):
"""
Returns a list of devices, filtered under udev keys.
udev_in
A dictionary of key:values that are expected in the device
udev information
udev_ex
A dictionary of key:values that are not expected in the device
udev information (excluded)
The key is a lower case string, joined by dots, that represent a
path in the udev information dictionary. For example, 'e.id_bus'
will represent the udev entry `udev['E']['ID_BUS']`
If the udev entry is a list, the algorithm will check that at
least one item match one item of the value of the parameters.
Returns list of devices that match `udev_in` and do not match
`udev_ex`.
CLI Example:
.. code-block:: bash
salt '*' devinfo.filter udev_in='{"e.id_bus": "ata"}'
"""
udev_in = udev_in if udev_in else {}
udev_ex = udev_ex if udev_ex else {}
all_devices = __grains__["disks"]
# Get the udev information only one time
udev_info = {d: __salt__["udev.info"](d) for d in all_devices}
devices_udev_key_in = {d for d in all_devices if _match(udev_info[d], udev_in)}
devices_udev_key_ex = {
d for d in all_devices if _match(udev_info[d], udev_ex) if udev_ex
}
return sorted(devices_udev_key_in - devices_udev_key_ex)
def _hwinfo_parse_short(report):
"""Parse the output of hwinfo and return a dictionary"""
result = {}
current_result = {}
key_counter = 0
for line in report.strip().splitlines():
if line.startswith(" "):
key = key_counter
key_counter += 1
current_result[key] = line.strip()
elif line.startswith(" "):
key, value = line.strip().split(" ", 1)
current_result[key] = value.strip()
elif line.endswith(":"):
key = line[:-1]
value = {}
result[key] = value
current_result = value
key_counter = 0
else:
log.error("Error parsing hwinfo short output: %s", line)
return result
def _hwinfo_parse_full(report):
"""Parse the output of hwinfo and return a dictionary"""
result = {}
result_stack = []
level = 0
for line in report.strip().splitlines():
current_level = line.count(" ")
if level != current_level or len(result_stack) != result_stack:
result_stack = result_stack[:current_level]
level = current_level
line = line.strip()
# Ignore empty lines
if not line:
continue
# Initial line of a segment
if level == 0:
key, value = line.split(":", 1)
sub_result = {}
result[key] = sub_result
# The first line contains also a sub-element
key, value = value.strip().split(": ", 1)
sub_result[key] = value
result_stack.append(sub_result)
level += 1
continue
# Line is a note
if line.startswith("[") or ":" not in line:
sub_result = result_stack[-1]
sub_result["Note"] = line if not line.startswith("[") else line[1:-1]
continue
key, value = line.split(":", 1)
key, value = key.strip(), value.strip()
sub_result = result_stack[-1]
# If there is a value and it not starts with hash, this is a
# (key, value) entry. But there are exception on the rule,
# like when is about 'El Torito info', that is the begining of
# a new dictorionart.
if value and not value.startswith("#") and key != "El Torito info":
if key == "I/O Port":
key = "I/O Ports"
elif key == "Config Status":
value = dict(item.split("=") for item in value.split(", "))
elif key in ("Driver", "Driver Modules"):
value = value.replace('"', "").split(", ")
elif key in ("Tags", "Device Files", "Features"):
# We cannot split by ', ', as using spaces in
# inconsisten in some fields
value = [v.strip() for v in value.split(",")]
else:
if value.startswith('"'):
value = value[1:-1]
# If there is a collision, we store it as a list
if key in sub_result:
current_value = sub_result[key]
if type(current_value) is not list:
current_value = [current_value]
if value not in current_value:
current_value.append(value)
if len(current_value) == 1:
value = current_value[0]
else:
value = current_value
sub_result[key] = value
else:
if value.startswith("#"):
value = {"Handle": value}
elif key == "El Torito info":
value = value.split(", ")
value = {
"platform": value[0].split()[-1],
"bootable": "no" if "not" in value[1] else "yes",
}
else:
value = {}
sub_result[key] = value
result_stack.append(value)
level += 1
return result
def _hwinfo_parse(report, short):
"""Parse the output of hwinfo and return a dictionary"""
if short:
return _hwinfo_parse_short(report)
else:
return _hwinfo_parse_full(report)
def _hwinfo_efi():
"""Return information about EFI"""
return {
"efi": __grains__["efi"],
"efi-secure-boot": __grains__["efi-secure-boot"],
}
def _hwinfo_memory():
"""Return information about the memory"""
return {
"mem_total": __grains__["mem_total"],
}
def _hwinfo_network(short):
"""Return network information"""
info = {
"fqdn": __grains__["fqdn"],
"ip_interfaces": __grains__["ip_interfaces"],
}
if not short:
info["dns"] = __grains__["dns"]
return info
def hwinfo(items=None, short=True, listmd=False, devices=None):
"""
Probe for hardware
items
List of hardware items to inspect. Default ['bios', 'cpu', 'disk',
'memory', 'network', 'partition']
short
Show only a summary. Default True.
listmd
Report RAID devices. Default False.
devices
List of devices to show information from. Default None.
CLI Example:
.. code-block:: bash
salt '*' devinfo.hwinfo
salt '*' devinfo.hwinfo items='["disk"]' short=no
salt '*' devinfo.hwinfo items='["disk"]' short=no devices='["/dev/sda"]'
salt '*' devinfo.hwinfo devices=/dev/sda
"""
result = {}
if not items:
items = ["bios", "cpu", "disk", "memory", "network", "partition"]
if not isinstance(items, (list, tuple)):
items = [items]
if not devices:
devices = []
if devices and not isinstance(devices, (list, tuple)):
devices = [devices]
cmd = ["hwinfo"]
for item in items:
cmd.append(f"--{item}")
if short:
cmd.append("--short")
if listmd:
cmd.append("--listmd")
for device in devices:
cmd.append(f"--only {device}")
out = __salt__["cmd.run_stdout"](cmd)
result["hwinfo"] = _hwinfo_parse(out, short)
if "bios" in items:
result["bios grains"] = _hwinfo_efi()
if "memory" in items:
result["memory grains"] = _hwinfo_memory()
if "network" in items:
result["network grains"] = _hwinfo_network(short)
return result
Zerion Mini Shell 1.0