From 11faefa846b1da7595d15a637c5d5a6c4f20af20 Mon Sep 17 00:00:00 2001 From: Jannik Schönartz Date: Tue, 6 Apr 2021 19:43:53 +0200 Subject: [bas-python] Add programs, drm dependencie for edid data and remove hooks, because this module gets called through a bas registration hook --- modules.d/bas-python/module-setup.sh | 21 +- .../bas-python/scripts/00collect_hw_info_json.py | 233 -------------------- modules.d/bas-python/scripts/00reboot_script.sh | 10 - .../bas-python/scripts/collect_hw_info_json.py | 234 +++++++++++++++++++++ 4 files changed, 247 insertions(+), 251 deletions(-) delete mode 100755 modules.d/bas-python/scripts/00collect_hw_info_json.py delete mode 100755 modules.d/bas-python/scripts/00reboot_script.sh create mode 100755 modules.d/bas-python/scripts/collect_hw_info_json.py diff --git a/modules.d/bas-python/module-setup.sh b/modules.d/bas-python/module-setup.sh index 4fa8b260..2b5c6958 100755 --- a/modules.d/bas-python/module-setup.sh +++ b/modules.d/bas-python/module-setup.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash check() { - for bin in python3 pip3; do + for bin in python3 pip3 lshw ip dmidecode; do if ! hash "$bin" 2>&1 /dev/null; then echo "Missing '$bin' please install it..." return 1 @@ -10,13 +10,18 @@ check() { return 255 } depends() { - : + # drm is needed for getting the edid data + echo slx-drm } install() { - # Not needed but for testing the scripts manual + # Copy the python hardware collection script to /opt/bas/ mkdir -p "$initdir/opt/bas" - cp -r "$moddir/scripts" "$initdir/opt/bas/" + cp -r "$moddir/scripts/collect_hw_info_json.py" "$initdir/opt/bas/" + # For testing the scripts manual, copy em all + # cp -r "$moddir/scripts" "$initdir/opt/bas/" + + # Libs needed for python3 and dmiparser mkdir -p "$initdir/usr/lib" cp -r "/usr/lib/python3" "$initdir/usr/lib/" cp -r "/usr/lib/python3.8" "$initdir/usr/lib/" @@ -27,14 +32,14 @@ install() { mkdir -p "$initdir/usr/share" cp -r "/usr/share/python-wheels" "$initdir/usr/share/python-wheels/" + # Certificates mkdir -p "$initdir/etc/ssl/certs/" cp "/etc/ssl/certs/ca-certificates.crt" "$initdir/etc/ssl/certs/" - inst_multiple python3 pip3 + inst_multiple python3 pip3 lshw smartctl ip dmidecode - inst_hook pre-mount 00 "$moddir/scripts/00collect_hw_info_json.py" - # Call finish script instead of Switch Root - inst_hook pre-mount 00 "$moddir/scripts/00reboot_script.sh" + # Exec the python hook and reboot instead of Switch Root + # inst_hook pre-mount 00 "$moddir/scripts/python_hook.sh" return 0 } diff --git a/modules.d/bas-python/scripts/00collect_hw_info_json.py b/modules.d/bas-python/scripts/00collect_hw_info_json.py deleted file mode 100755 index 9eea9ca8..00000000 --- a/modules.d/bas-python/scripts/00collect_hw_info_json.py +++ /dev/null @@ -1,233 +0,0 @@ -from dmiparser import DmiParser -import json -import subprocess -from subprocess import PIPE -import shlex -import sys -import argparse -from os import listdir -import requests - -__debug = False - -# Run dmi command as subprocess and get the stdout -def run_subprocess(_cmd): - global __debug - proc = subprocess.run(_cmd, shell=True, stdout=PIPE, stderr=PIPE) - stdout = proc.stdout - stderr = proc.stderr - - if __debug: - print(_cmd + ':') - print() - print('Errors:') - print(stderr.decode()) - print() - # stderr len instead of proc.returncode > 0 is used because some have returncode 2 but are still valid - if len(stderr.decode()) > 0: - print(_cmd + ' Errors:') - print(stderr.decode()) - if proc.returncode != 0: - print('Error Return Code: ' + str(proc.returncode)) - print() - return False - else: - return stdout.decode() - else: - return stdout.decode() - -# Get and parse dmidecode using dmiparser -def get_dmidecode(): - _dmiraw = run_subprocess('dmidecode') - _dmiparsed = '' - if _dmiraw: - # Parse dmidecode - _dmiparsed = DmiParser(_dmiraw) - return json.loads(str(_dmiparsed)) - else: - return [] - -# Get the readlink -f output -def get_readlink(link): - _readlink = run_subprocess('readlink -f ' + link) - return _readlink - -# Get smartctl output in json format -def get_smartctl(): - diskdir = '/dev/disk/by-path/' - # Get and filter all disks - disks = listdir(diskdir) - filteredDisks = [i for i in disks if (not "-part" in i) and (not "-usb-" in i)] - smartctl = {} - for d in filteredDisks: - output = run_subprocess('smartctl -x --json ' + diskdir + d) - if isinstance(output, str): - try: - disk = json.loads(output) - disk['readlink'] = get_readlink(diskdir + d).rstrip() - smartctl[d] = disk - except ValueError as e: - print('smartctl failed with error:') - print(e) - print() - return [] - return smartctl - -# Get and process "lspci -mn" output -def get_lspci(): - lspci = [] - lspci_raw = run_subprocess('lspci -mn').split('\n') - for line in lspci_raw: - if len(line) <= 0: continue - - # Parsing shell like command parameters - parse = shlex.split(line) - lspci_parsed = {} - arguments = [] - values = [] - for parameter in parse: - # Split values from arguments - if parameter.startswith('-'): - arguments.append(parameter) - else: - values.append(parameter) - - # Prepare values positions are in order - if len(values) >= 6: - lspci_parsed['slot'] = values[0] - lspci_parsed['class'] = values[1] - lspci_parsed['vendor'] = values[2] - lspci_parsed['device'] = values[3] - lspci_parsed['subsystem_vendor'] = values[4] - lspci_parsed['subsystem'] = values[5] - - # Prepare arguments - if len(arguments) > 0: - for arg in arguments: - if arg.startswith('-p'): - lspci_parsed['progif'] = arg[2:] - elif arg.startswith('-r'): - lspci_parsed['rev'] = arg[2:] - else: continue - - lspci.append(lspci_parsed) - return lspci - -# Get ip data in json format -def get_ip(): - result = [] - ip_raw = run_subprocess('ip --json addr show') - if isinstance(ip_raw, str): - result = json.loads(ip_raw) - return result - -def get_net_fallback(): - result = {} - - # Get MAC address - interfaces = run_subprocess('ls /sys/class/net').split('\n') - for interface in interfaces: - # Skip local stuff - if interface == 'lo' or interface == '': - continue - net = {} - net['mac'] = run_subprocess('cat /sys/class/net/' + interface + '/address') - if net['mac'].endswith('\n'): - net['mac'] = net['mac'][:-1] - result[interface] = net - - # Get IP address - interfaces = run_subprocess('ip -o addr show | awk \'/inet/ {print $2, $3, $4}\'').split('\n') - for interface in interfaces: - if interface == '': - continue - interf = interface.split(' ') - if interf[0] == 'lo': - continue - else: - if interf[1] == 'inet': - result[interf[0]]['ipv4'] = interf[2] - elif interf[1] == 'inet6': - result[interf[0]]['ipv6'] = interf[2] - return result - -# Get and convert EDID data to hex -def get_edid(): - edid = [] - display_paths = run_subprocess('ls /sys/class/drm/*/edid') - if display_paths: - display_paths = display_paths.split('\n') - else: - return edid - for dp in display_paths: - if dp == '': continue - edid_hex = open(dp, 'rb').read().hex() - if len(edid_hex) > 0: - edid.append(edid_hex) - return edid - -def get_lshw(): - result = [] - lshw_raw = run_subprocess('lshw -json') - if isinstance(lshw_raw, str): - result = json.loads(lshw_raw) - return result - -def prepare_location(parent, rack, bay, slot): - location = {} - if parent: - location['parent'] = parent - if rack: - location['rack'] = rack - if bay: - location['bay'] = bay - if slot: - location['slot'] = slot - return location - -def send_post(url, payload): - headers = { 'Content-type': 'application/json', 'Accept': 'text/plain' } - # req = requests.post(url, json=payload, headers=headers) - req = requests.post(url, json=payload) - print("POST-Request Response: \n") - print(req.text) - -def main(): - global __debug - - # Create and parse arguments - parser = argparse.ArgumentParser(description='Collects hardware data from different tools and returns it as json.') - parser.add_argument('-d', '--debug', action='store_true', help='Prints all STDERR messages. (Non critical included)') - parser.add_argument('-u', '--url', action='store', help='If given, a post request with the generated JSON is sent to the given URL') - parser.add_argument('-p', '--print', action='store_true', help='Prints the generated JSON') - parser.add_argument('-r', '--rack', action='store', help='') - parser.add_argument('-s', '--slot', action='store', help='') - parser.add_argument('-b', '--bay', action='store', help='') - parser.add_argument('-l', '--location', action='store', help=': Roomname where the client is located') - args = parser.parse_args() - - if args.debug: - __debug = True - - # Run the tools - _collecthw = {} - _collecthw['dmidecode'] = get_dmidecode() - _collecthw['smartctl'] = get_smartctl() - _collecthw['lspci'] = get_lspci() - _collecthw['ip'] = get_ip() - _collecthw['edid'] = get_edid() - _collecthw['lshw'] = get_lshw() - _collecthw['net'] = get_net_fallback() - _collecthw['location'] = prepare_location(args.location, args.rack, args.bay, args.slot) - - collecthw_json = json.dumps(_collecthw) - if (args.url): - send_post(args.url, _collecthw) - - # Print out the final json - if (args.print): - print(json.dumps(_collecthw)) - -if __name__ == "__main__": - main() - diff --git a/modules.d/bas-python/scripts/00reboot_script.sh b/modules.d/bas-python/scripts/00reboot_script.sh deleted file mode 100755 index 2ae7ca55..00000000 --- a/modules.d/bas-python/scripts/00reboot_script.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -echo "°(^.^)° Everything finished (hopefully) successfull" - -# . /lib/dracut-lib.sh -# emergency_shell - -read -p "Press Enter to reboot" -reboot - diff --git a/modules.d/bas-python/scripts/collect_hw_info_json.py b/modules.d/bas-python/scripts/collect_hw_info_json.py new file mode 100755 index 00000000..1c2185f8 --- /dev/null +++ b/modules.d/bas-python/scripts/collect_hw_info_json.py @@ -0,0 +1,234 @@ +from dmiparser import DmiParser +import json +import subprocess +from subprocess import PIPE +import shlex +import sys +import argparse +from os import listdir +import requests + +__debug = False + +# Run dmi command as subprocess and get the stdout +def run_subprocess(_cmd): + global __debug + proc = subprocess.run(_cmd, shell=True, stdout=PIPE, stderr=PIPE) + stdout = proc.stdout + stderr = proc.stderr + + if __debug: + print(_cmd + ':') + print() + print('Errors:') + print(stderr.decode()) + print() + # stderr len instead of proc.returncode > 0 is used because some have returncode 2 but are still valid + if len(stderr.decode()) > 0: + print(_cmd + ' Errors:') + print(stderr.decode()) + if proc.returncode != 0: + print('Error Return Code: ' + str(proc.returncode)) + print() + return False + else: + return stdout.decode() + else: + return stdout.decode() + +# Get and parse dmidecode using dmiparser +def get_dmidecode(): + _dmiraw = run_subprocess('dmidecode') + _dmiparsed = '' + if _dmiraw: + # Parse dmidecode + _dmiparsed = DmiParser(_dmiraw) + return json.loads(str(_dmiparsed)) + else: + return [] + +# Get the readlink -f output +def get_readlink(link): + _readlink = run_subprocess('readlink -f ' + link) + return _readlink + +# Get smartctl output in json format +def get_smartctl(): + diskdir = '/dev/disk/by-path/' + # Get and filter all disks + disks = listdir(diskdir) + filteredDisks = [i for i in disks if (not "-part" in i) and (not "-usb-" in i)] + smartctl = {} + for d in filteredDisks: + output = run_subprocess('smartctl -x --json ' + diskdir + d) + if isinstance(output, str): + try: + disk = json.loads(output) + disk['readlink'] = get_readlink(diskdir + d).rstrip() + smartctl[d] = disk + except ValueError as e: + print('smartctl failed with error:') + print(e) + print() + return [] + return smartctl + +# Get and process "lspci -mn" output +def get_lspci(): + lspci = [] + lspci_raw = run_subprocess('lspci -mmn').split('\n') + for line in lspci_raw: + if len(line) <= 0: continue + + # Parsing shell like command parameters + parse = shlex.split(line) + lspci_parsed = {} + arguments = [] + values = [] + for parameter in parse: + # Split values from arguments + if parameter.startswith('-'): + arguments.append(parameter) + else: + values.append(parameter) + + # Prepare values positions are in order + if len(values) >= 6: + lspci_parsed['slot'] = values[0] + lspci_parsed['class'] = values[1] + lspci_parsed['vendor'] = values[2] + lspci_parsed['device'] = values[3] + lspci_parsed['subsystem_vendor'] = values[4] + lspci_parsed['subsystem'] = values[5] + + # Prepare arguments + if len(arguments) > 0: + for arg in arguments: + if arg.startswith('-p'): + lspci_parsed['progif'] = arg[2:] + elif arg.startswith('-r'): + lspci_parsed['rev'] = arg[2:] + else: continue + + lspci.append(lspci_parsed) + return lspci + +# Get ip data in json format +def get_ip(): + result = [] + ip_raw = run_subprocess('ip --json addr show') + if isinstance(ip_raw, str): + result = json.loads(ip_raw) + return result + +def get_net_fallback(): + result = {} + + # Get MAC address + interfaces = run_subprocess('ls /sys/class/net').split('\n') + for interface in interfaces: + # Skip local stuff + if interface == 'lo' or interface == '': + continue + net = {} + net['mac'] = run_subprocess('cat /sys/class/net/' + interface + '/address') + if net['mac'].endswith('\n'): + net['mac'] = net['mac'][:-1] + result[interface] = net + + # Get IP address + interfaces = run_subprocess('ip -o addr show | awk \'/inet/ {print $2, $3, $4}\'').split('\n') + for interface in interfaces: + if interface == '': + continue + interf = interface.split(' ') + if interf[0] == 'lo': + continue + else: + if interf[1] == 'inet': + result[interf[0]]['ipv4'] = interf[2] + elif interf[1] == 'inet6': + result[interf[0]]['ipv6'] = interf[2] + return result + +# Get and convert EDID data to hex +def get_edid(): + edid = [] + display_paths = run_subprocess('ls /sys/class/drm/*/edid') + if display_paths: + display_paths = display_paths.split('\n') + else: + return edid + for dp in display_paths: + if dp == '': continue + edid_hex = open(dp, 'rb').read().hex() + if len(edid_hex) > 0: + edid.append(edid_hex) + return edid + +def get_lshw(): + result = [] + lshw_raw = run_subprocess('lshw -json') + if isinstance(lshw_raw, str): + result = json.loads(lshw_raw) + return result + +def prepare_location(parent, rack, bay, slot): + location = {} + if parent: + location['parent'] = parent + if rack: + location['rack'] = rack + if bay: + location['bay'] = bay + if slot: + location['slot'] = slot + return location + +def send_post(url, payload): + headers = { 'Content-type': 'application/json', 'Accept': 'text/plain' } + # req = requests.post(url, json=payload, headers=headers) + req = requests.post(url, json=payload) + print("POST-Request Response: \n") + print(req.text) + +def main(): + global __debug + + # Create and parse arguments + parser = argparse.ArgumentParser(description='Collects hardware data from different tools and returns it as json.') + parser.add_argument('-d', '--debug', action='store_true', help='Prints all STDERR messages. (Non critical included)') + parser.add_argument('-u', '--url', action='store', help='If given, a post request with the generated JSON is sent to the given URL') + parser.add_argument('-p', '--print', action='store_true', help='Prints the generated JSON') + parser.add_argument('-r', '--rack', action='store', help='') + parser.add_argument('-s', '--slot', action='store', help='') + parser.add_argument('-b', '--bay', action='store', help='') + parser.add_argument('-l', '--location', action='store', help=': Roomname where the client is located') + args = parser.parse_args() + + if args.debug: + __debug = True + + # Run the tools + _collecthw = {} + _collecthw['version'] = 2.0 + _collecthw['dmidecode'] = get_dmidecode() + _collecthw['smartctl'] = get_smartctl() + _collecthw['lspci'] = get_lspci() + _collecthw['ip'] = get_ip() + _collecthw['edid'] = get_edid() + _collecthw['lshw'] = get_lshw() + _collecthw['net'] = get_net_fallback() + _collecthw['location'] = prepare_location(args.location, args.rack, args.bay, args.slot) + + collecthw_json = json.dumps(_collecthw) + if (args.url): + send_post(args.url, _collecthw) + + # Print out the final json + if (args.print): + print(json.dumps(_collecthw)) + +if __name__ == "__main__": + main() + -- cgit v1.2.3-55-g7522