From dfdb6a02cddd1e32fc5483f43d4c184faa72719d Mon Sep 17 00:00:00 2001 From: Petr Vavrin Date: Tue, 2 Aug 2022 17:53:06 +0200 Subject: [PATCH 1/9] code cleanup, bug fixing, new commands, code formatted with black --- modules/blkid.py | 68 ++-- modules/blockdev.py | 65 +++- modules/busctl.py | 116 +++++- modules/chrt.py | 81 ++-- modules/compgen.py | 128 +++--- modules/dev_disk.py | 74 ++-- modules/dev_input.py | 42 ++ modules/df.py | 75 ++-- modules/dmidecode.py | 299 +++++++------- modules/dnf.py | 153 ++++---- modules/env.py | 44 ++- modules/etc_default.py | 95 +++-- modules/etc_fstab.py | 63 +-- modules/etc_group.py | 33 +- modules/etc_hosts.py | 95 +++-- modules/etc_locale_gen.py | 48 +-- modules/etc_mtab.py | 72 ++-- modules/etc_passwd.py | 31 +- modules/etc_release.py | 47 ++- modules/etc_shadow.py | 41 +- modules/etc_timezone.py | 28 +- modules/fbset.py | 212 +++++----- modules/findmnt.py | 52 ++- modules/free.py | 68 ++-- modules/getconf.py | 50 ++- modules/hostnamectl.py | 49 ++- modules/ifconfig.py | 160 ++++---- modules/lsblk.py | 63 +-- modules/lscpu.py | 51 ++- modules/lsmod.py | 62 +-- modules/lsns.py | 38 +- modules/lsof.py | 203 +++++----- modules/lspci.py | 65 ++-- modules/lsusb.py | 229 ++++++----- modules/modinfo.py | 70 ++-- modules/parted.py | 112 +++--- modules/proc_buddyinfo.py | 33 ++ modules/proc_bus_input.py | 82 ++++ modules/proc_cgroups.py | 24 ++ modules/proc_cmdline.py | 66 ++-- modules/proc_consoles.py | 110 +++--- modules/proc_cpuinfo.py | 76 ++-- modules/proc_crypto.py | 59 +-- modules/proc_devices.py | 70 ++-- modules/proc_diskstats.py | 91 ++--- modules/proc_dma.py | 47 ++- modules/proc_filesystems.py | 56 +-- modules/proc_fs.py | 95 +++-- modules/proc_iomem.py | 54 +-- modules/proc_ioports.py | 56 +-- modules/proc_loadavg.py | 54 +-- modules/proc_locks.py | 60 +-- modules/proc_meminfo.py | 70 ++-- modules/proc_modules.py | 58 +-- modules/proc_mounts.py | 64 +-- modules/proc_net.py | 146 +++++++ modules/proc_partitions.py | 36 +- modules/proc_scsi.py | 102 +++-- modules/proc_slabinfo.py | 71 ++++ modules/proc_stat.py | 38 ++ modules/proc_swaps.py | 34 +- modules/proc_sys.py | 87 +++-- modules/proc_uptime.py | 43 +- modules/proc_version.py | 29 +- modules/proc_version_signature.py | 19 + modules/proc_vmstat.py | 47 ++- modules/prtstat.py | 62 +-- modules/ps.py | 109 +++--- modules/python.py | 139 ++++--- modules/route.py | 22 ++ modules/rpm.py | 49 ++- modules/services_status.py | 89 +++-- modules/sysctl.py | 92 +++-- modules/sysinfo_lib.py | 285 +++++++------- modules/timedatectl.py | 55 ++- modules/udevadm.py | 238 +++++++----- modules/uname.py | 110 +++--- modules/vmstat.py | 260 +++++++------ modules/yum.py | 155 ++++---- sysinfo.py | 627 ++++++++++++++++++------------ 80 files changed, 4416 insertions(+), 2935 deletions(-) create mode 100644 modules/dev_input.py create mode 100644 modules/proc_buddyinfo.py create mode 100644 modules/proc_bus_input.py create mode 100644 modules/proc_cgroups.py create mode 100644 modules/proc_net.py create mode 100644 modules/proc_slabinfo.py create mode 100644 modules/proc_stat.py create mode 100644 modules/proc_version_signature.py create mode 100644 modules/route.py diff --git a/modules/blkid.py b/modules/blkid.py index 349a59e..1f00422 100644 --- a/modules/blkid.py +++ b/modules/blkid.py @@ -1,33 +1,35 @@ - -import re -from sysinfo_lib import camelCase - - -def parser(stdout, stderr): - output = {} - ignoredLines = [] - if stdout: - device = '' - for line in stdout.splitlines(): - dev = re.search(r'^>>> Device: (\S+)', line) - kv = re.search(r'^(\w[^=]+)=(.*)$', line) - if dev: - device = dev.group(1) - output[device] = {} - elif kv: - output[device][camelCase(kv.group(1))] = kv.group(2) - else: - ignoredLines.append(line) - pass - - return { - 'output': output, - 'ignored': ignoredLines - } - -def register(main): - main['blkid'] = { - 'cmd': """blkid -o device | xargs -n 1 -I {} sh -c "echo '>>> Device: {}'; blkid -o export -p {}; blkid -o export -i {}" """, - 'description': 'Block device attributes', - 'parser': parser - } \ No newline at end of file +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + device = "" + for line in stdout.splitlines(): + dev = re.search(r"^>>> Device: (\S+)", line) + if dev: + device = dev.group(1) + output[device] = {} + continue + + kv = re.search(r"^(\w[^=]+)=(.*)$", line) + if kv: + key = camelCase(kv.group(1), to_camelcase) + value = kv.group(2) + output[device][key] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["blkid"] = { + "cmd": """blkid -o device | xargs -n 1 -I {} sh -c "echo '>>> Device: {}'; blkid -o export -p {}; blkid -o export -i {}" """, + "description": "Block device attributes", + "parser": parser, + } diff --git a/modules/blockdev.py b/modules/blockdev.py index 8768ee3..9dd8ec3 100644 --- a/modules/blockdev.py +++ b/modules/blockdev.py @@ -1,16 +1,49 @@ - -from sysinfo_lib import parseTable - -def parser(stdout, stderr): - output = {} - if stdout: - output = parseTable(stdout) - - return {'output': output} - -def register(main): - main['blockdev'] = { - 'cmd': 'blockdev --report | column -t', - 'description': 'Block device ioctls', - 'parser': parser - } \ No newline at end of file +from sysinfo_lib import parseTable, camelCase +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + if stdout: + output = parseTable(stdout, to_camelcase=to_camelcase) + + return {"output": output, "unprocessed": []} + + +def parser_detail(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + device = "" + for line in stdout.splitlines(): + dev = re.search(r"^>>> Device: (\S+)", line) + if dev: + device = dev.group(1) + output[device] = {} + continue + + kv = re.search(r"^get (\w[^:]+): (.*)$", line) + if kv: + key = camelCase(kv.group(1), to_camelcase) + value = kv.group(2) + output[device][key] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["blockdev"] = { + "cmd": "blockdev --report | column -t", + "description": "Block device ioctls", + "parser": parser, + } + + main["blockdev_detail"] = { + "cmd": """blkid -o device | xargs -n 1 -I {} sh -c "echo '>>> Device: {}'; blockdev -v --getalignoff --getbsz --getdiscardzeroes --getfra --getiomin --getioopt --getmaxsect --getpbsz --getra --getro --getsize64 --getss {}" """, + "description": "Block device ioctls details", + "parser": parser_detail, + } diff --git a/modules/busctl.py b/modules/busctl.py index 4258610..badd141 100644 --- a/modules/busctl.py +++ b/modules/busctl.py @@ -1,16 +1,100 @@ - -from sysinfo_lib import parseTable - -def parser(stdout, stderr): - output = {} - if stdout: - output = parseTable(stdout) - - return {'output': output} - -def register(main): - main['busctl'] = { - 'cmd': 'busctl --no-pager | column -t', - 'description': 'Introspect the bus', - 'parser': parser - } +import re +from sysinfo_lib import parseTable, camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + if stdout: + output = parseTable(stdout, to_camelcase=to_camelcase) + + return {"output": output, "unprocessed": []} + + +def parser_tree(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + name = "" + for line in stdout.splitlines(): + header = re.search(r"^(\S+) (.+):", line) + + if header: + name = header.group(2) + output[name] = [] + continue + + tree = re.search(r"^\/(.+)$", line) + if tree and name: + output[name].append(tree.group(1)) + continue + + if line == "" or line == "/": + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def parser_status(stdout, stderr, to_camelcase): + output = {} + key = "" + is_array = False + unprocessed = [] + + if stdout: + device = "" + for line in stdout.splitlines(): + dev = re.search(r"^>>> Device: (\S+)", line) + if dev: + device = dev.group(1) + output[device] = {} + key = "" + is_array = False + continue + + kv = re.search(r"^(\w[^=]+)=(.*)$", line) + if kv: + key = camelCase(kv.group(1), to_camelcase) + value = kv.group(2).strip() + + if re.match(r"^cap_", value): + is_array = True + output[device][key] = value.split(r" ") + print(value.split(r" ")) + + else: + output[device][key] = value + + continue + + cont = re.search(r"^\s\s+(.*)$", line) + if cont and key and is_array: + key = camelCase(key, to_camelcase) + output[device][key] += cont.group(1).strip().split(r" ") + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["busctl"] = { + "cmd": "busctl --no-pager | column -t", + "description": "Introspect the bus", + "parser": parser, + } + + main["busctl_tree"] = { + "cmd": "busctl --no-pager --list tree", + "description": "Object tree for services", + "parser": parser_tree, + } + + main["busctl_status"] = { + "cmd": """busctl list | awk '!/^(NAME)/ {print $1}' | xargs -n 1 -I {} sh -c "echo '>>> Device: {}'; busctl --no-pager status {}" """, + "description": "Process information and credentials of a bus service", + "parser": parser_status, + } diff --git a/modules/chrt.py b/modules/chrt.py index 1d2e306..9c46ca1 100644 --- a/modules/chrt.py +++ b/modules/chrt.py @@ -1,29 +1,52 @@ - -import re - -def parser(stdout, stderr): - output = {} - pid = None - if stdout: - for line in stdout.splitlines(): - pidSearch = re.search(r'^>>>\s+PID:\s+(\S+)', line) - if pidSearch: - pid = pidSearch.group(1) - output[pid] = {'pid': pid, 'scheduling': {}, 'current': {}} - - if pid: - sched = re.search(r'^SCHED_(\S+)[^:]+:\s*(\S+)', line) - if sched: - output[pid]['scheduling'][sched.group(1).strip()] = sched.group(2).strip() - - current = re.search(r'current scheduling (\S+).*:\s*(\S+)', line) - if current: - output[pid]['current'][current.group(1).strip()] = current.group(2).strip() - return {'output': output} - -def register(main): - main['chrt'] = { - 'cmd': """ps -eo pid | grep -vi pid | xargs -I {} sh -c "echo '>>> PID: {}'; chrt -a --pid {}; echo '----'; chrt -m --pid {};" """, - 'description': 'Scheduling attributes of all the tasks (threads)', - 'parser': parser - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + pid = None + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + + pidSearch = re.search(r"^>>>\s+PID:\s+(\S+)", line) + if pidSearch: + pid = pidSearch.group(1) + output[pid] = {"pid": pid, "scheduling": {}, "current": {}} + continue + + if pid: + sched = re.search(r"^SCHED_(\S+)[^:]+:\s*(\S+)", line) + if sched: + key = camelCase(sched.group(1).strip(), to_camelcase) + value = sched.group(2).strip() + + output[pid]["scheduling"][key] = value + continue + + current = re.search(r"current scheduling (\S+).*:\s*(\S+)", line) + if current: + key = camelCase(current.group(1).strip(), to_camelcase) + value = current.group(2).strip() + + if re.match(r"^SCHED_", value): + value = camelCase(value.replace("SCHED_", ""), to_camelcase) + + output[pid]["current"][key] = value + continue + + if line.strip("-") == "": + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["chrt"] = { + "cmd": """ps -eo pid | grep -vi pid | xargs -I {} sh -c "echo '>>> PID: {}'; chrt -a --pid {}; echo '----'; chrt -m --pid {};" """, + "description": "Scheduling attributes of all the tasks (threads)", + "parser": parser, + } diff --git a/modules/compgen.py b/modules/compgen.py index f3f92fa..fb36bfd 100644 --- a/modules/compgen.py +++ b/modules/compgen.py @@ -1,63 +1,65 @@ - -from sysinfo_lib import sortedList - -def parser(stdout, stderr): - if stdout: - return {'output': sortedList(stdout)} - else: - return {} - -def register(main): - main['shell_alias'] = { - 'cmd': '$(which bash) -c "compgen -a"', - 'description': 'Shell alias names', - 'parser': parser - } - - main['shell_builtins'] = { - 'cmd': '$(which bash) -c "compgen -b"', - 'description': 'Names of shell builtin commands', - 'parser': parser - } - - main['shell_all_commands'] = { - 'cmd': '$(which bash) -c "compgen -c"', - 'description': 'Shell command names', - 'parser': parser - } - - main['shell_exported_variables'] = { - 'cmd': '$(which bash) -c "compgen -e"', - 'description': 'Names of exported shell variables', - 'parser': parser - } - - main['groups'] = { - 'cmd': '$(which bash) -c "compgen -g"', - 'description': 'Group names', - 'parser': parser - } - - main['jobs'] = { - 'cmd': '$(which bash) -c "compgen -j"', - 'description': 'Job names, if job control is active', - 'parser': parser - } - - main['services'] = { - 'cmd': '$(which bash) -c "compgen -s"', - 'description': 'Service names', - 'parser': parser - } - - main['users'] = { - 'cmd': '$(which bash) -c "compgen -u"', - 'description': 'User names', - 'parser': parser - } - - main['shell_variables'] = { - 'cmd': '$(which bash) -c "compgen -v"', - 'description': 'Names of all shell variables', - 'parser': parser - } +from sysinfo_lib import sortedList + + +def parser(stdout, stderr, to_camelcase): + if stdout: + return {"output": sortedList(stdout), "unprocessed": []} + + else: + return {} + + +def register(main): + main["shell_alias"] = { + "cmd": '$(which bash) -c "compgen -a"', + "description": "Shell alias names (compgen)", + "parser": parser, + } + + main["shell_builtins"] = { + "cmd": '$(which bash) -c "compgen -b"', + "description": "Names of shell builtin commands (compgen)", + "parser": parser, + } + + main["shell_all_commands"] = { + "cmd": '$(which bash) -c "compgen -c"', + "description": "Shell command names (compgen)", + "parser": parser, + } + + main["shell_exported_variables"] = { + "cmd": '$(which bash) -c "compgen -e"', + "description": "Names of exported shell variables (compgen)", + "parser": parser, + } + + main["shell_variables"] = { + "cmd": '$(which bash) -c "compgen -v"', + "description": "Names of all shell variables (compgen)", + "parser": parser, + } + + main["groups"] = { + "cmd": '$(which bash) -c "compgen -g"', + "description": "Group names (compgen)", + "parser": parser, + } + + main["jobs"] = { + "cmd": '$(which bash) -c "compgen -j"', + "description": "Job names, if job control is active (compgen)", + "parser": parser, + } + + main["services"] = { + "cmd": '$(which bash) -c "compgen -s"', + "description": "Service names (compgen)", + "parser": parser, + } + + main["users"] = { + "cmd": '$(which bash) -c "compgen -u"', + "description": "User names (compgen)", + "parser": parser, + } diff --git a/modules/dev_disk.py b/modules/dev_disk.py index be13a0f..df7b5e7 100644 --- a/modules/dev_disk.py +++ b/modules/dev_disk.py @@ -1,32 +1,42 @@ - -import re - -def parser(stdout, stderr): - output = {'all': {}} - if stdout: - typeName = '' - for line in stdout.splitlines(): - matchType = re.search(r'^\/dev\/disk\/by-(.*):\s*$', line) - if matchType: - typeName = matchType.group(1) - output[typeName] = {} - - matchEntry = re.search(r'\s(\S+)\s+->\s+[\.\/]+(.*)$', line) - if matchEntry and typeName: - key = matchEntry.group(1).strip() - value = matchEntry.group(2).strip() - output[typeName][key] = value - - if not value in output['all']: - output['all'][value] = {} - - output['all'][value][typeName] = key - - return {'output': output} - -def register(main): - main['dev_disk'] = { - 'cmd': 'ls -l /dev/disk/by-*', - 'description': 'Disk devices mapping', - 'parser': parser - } +import re + + +def parser(stdout, stderr, to_camelcase): + output = {"all": {}} + unprocessed = [] + + if stdout: + typeName = "" + for line in stdout.splitlines(): + matchType = re.search(r"^\/dev\/disk\/by-(.*):\s*$", line) + if matchType: + typeName = matchType.group(1) + output[typeName] = {} + continue + + matchEntry = re.search(r"\s(\S+)\s+->\s+[\.\/]+(.*)$", line) + if matchEntry and typeName: + key = matchEntry.group(1).strip() + value = matchEntry.group(2).strip() + output[typeName][key] = value + + if not value in output["all"]: + output["all"][value] = {} + + output["all"][value][typeName] = key + continue + + if line == "" or re.match(r"^total", line): + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["dev_disk"] = { + "cmd": "ls -l /dev/disk/by-*", + "description": "Disk devices mapping", + "parser": parser, + } diff --git a/modules/dev_input.py b/modules/dev_input.py new file mode 100644 index 0000000..85f56ab --- /dev/null +++ b/modules/dev_input.py @@ -0,0 +1,42 @@ +import re + + +def parser(stdout, stderr, to_camelcase): + output = {"all": {}} + unprocessed = [] + + if stdout: + typeName = "" + for line in stdout.splitlines(): + matchType = re.search(r"^\/dev\/input\/by-(.*):\s*$", line) + if matchType: + typeName = matchType.group(1) + output[typeName] = {} + continue + + matchEntry = re.search(r"\s(\S+)\s+->\s+[\.\/]+(.*)$", line) + if matchEntry and typeName: + key = matchEntry.group(1).strip() + value = matchEntry.group(2).strip() + output[typeName][key] = value + + if not value in output["all"]: + output["all"][value] = {} + + output["all"][value][typeName] = key + continue + + if line == "" or re.match(r"^total", line): + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["dev_input"] = { + "cmd": "ls -l /dev/input/by-*", + "description": "Input devices mapping", + "parser": parser, + } diff --git a/modules/df.py b/modules/df.py index 7ad9fa4..163c045 100644 --- a/modules/df.py +++ b/modules/df.py @@ -1,38 +1,45 @@ import re -def parser(stdout, stderr): - output = {} - ignoredLines = [] - if stdout: - reSplit = re.compile(r'\s+') - for line in stdout.splitlines(): - cols = reSplit.split(line) - if len(cols) > 11 and cols[11].lower() != 'mounted': - output[cols[11]] = { - 'source': cols[0], - 'fstype': cols[1], - 'itotal': cols[2], - 'iused': cols[3], - 'iavail': cols[4], - 'ipcent': cols[5], - 'size': cols[6], - 'used': cols[7], - 'avail': cols[8], - 'pcent': cols[9], - 'file': cols[10], - 'target': cols[11] - } - else: - ignoredLines.append(line) - - return { - 'output': output, - 'ignored': ignoredLines - } + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + reSplit = re.compile(r"\s+") + for line in stdout.splitlines(): + cols = reSplit.split(line) + if len(cols) > 11: + if cols[11].lower() == "mounted": + continue + + output[cols[11]] = { + "source": cols[0], + "fstype": cols[1], + "itotal": cols[2], + "iused": cols[3], + "iavail": cols[4], + "ipcent": cols[5], + "size": cols[6], + "used": cols[7], + "avail": cols[8], + "pcent": cols[9], + "file": cols[10], + "target": cols[11], + } + continue + + if re.match(r"Filesystem", line): + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + def register(main): - main['df'] = { - 'cmd': 'df -a --output=source,fstype,itotal,iused,iavail,ipcent,size,used,avail,pcent,file,target', - 'description': 'Report file system disk space usage', - 'parser': parser - } \ No newline at end of file + main["df"] = { + "cmd": "df -a --output=source,fstype,itotal,iused,iavail,ipcent,size,used,avail,pcent,file,target", + "description": "Report file system disk space usage", + "parser": parser, + } diff --git a/modules/dmidecode.py b/modules/dmidecode.py index 8ebff83..94aaa04 100644 --- a/modules/dmidecode.py +++ b/modules/dmidecode.py @@ -1,132 +1,167 @@ - -import re -from sysinfo_lib import camelCase - -def parser(stdout, stderr): - dmiSections = { - '0': 'BIOS', - '1': 'System', - '2': 'Base Board', - '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' - } - section = None - output = {} - - if stdout: - for line in stdout.splitlines(): - if line.strip() == '': - section = None - - handleSearch = re.search(r'^Handle\s+([^,]+),\s+DMI type\s+([^,]+),', line, re.IGNORECASE) - if handleSearch: - handle = handleSearch.group(1) - dmiType = handleSearch.group(2) - if dmiType in dmiSections: - section = camelCase(dmiSections[dmiType]) - output[section] = { - '__handle': handle, - '__dmiType': dmiType - } - - entry = re.search(r'^\s+([^:]+):\s+(.*)$', line) - if section and entry: - output[section][camelCase(entry.group(1))] = entry.group(2).strip() - - return {'output': output} - -def register(main): - main['dmidecode'] = { - 'cmd': 'dmidecode', - 'description': 'Dumping all information from DMI (SMBIOS)', - 'parser': parser - } - - main['dmidecode_bios'] = { - 'cmd': 'dmidecode -t bios', - 'description': 'Dumping BIOS information from DMI (SMBIOS)', - 'parser': parser - } - - main['dmidecode_system'] = { - 'cmd': 'dmidecode -t system', - 'description': 'Dumping SYSTEM information from DMI (SMBIOS)', - 'parser': parser - } - - main['dmidecode_baseboard'] = { - 'cmd': 'dmidecode -t baseboard', - 'description': 'Dumping BASEBOARD information from DMI (SMBIOS)', - 'parser': parser - } - - main['dmidecode_chassis'] = { - 'cmd': 'dmidecode -t chassis', - 'description': 'Dumping CHASSIS information from DMI (SMBIOS)', - 'parser': parser - } - - main['dmidecode_processor'] = { - 'cmd': 'dmidecode -t processor', - 'description': 'Dumping CHASSIS information from DMI (SMBIOS)', - 'parser': parser - } - - main['dmidecode_memory'] = { - 'cmd': 'dmidecode -t memory', - 'description': 'Dumping MEMORY information from DMI (SMBIOS)', - 'parser': parser - } - - main['dmidecode_cache'] = { - 'cmd': 'dmidecode -t cache', - 'description': 'Dumping CACHE information from DMI (SMBIOS)', - 'parser': parser - } - - main['dmidecode_connector'] = { - 'cmd': 'dmidecode -t connector', - 'description': 'Dumping CONNECTOR information from DMI (SMBIOS)', - 'parser': parser - } - - main['dmidecode_slot'] = { - 'cmd': 'dmidecode -t slot', - 'description': 'Dumping SLOT information from DMI (SMBIOS)', - 'parser': parser - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + dmiSections = { + "0": "BIOS", + "1": "System", + "2": "Base Board", + "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", + "126": "Disabled entry", + "127": "End of table", + } + handle = None + output = {} + unprocessed = [] + + if stdout: + + # fix multiline + stdout = re.sub(r"\n\t\t", " ", stdout) + + for line in stdout.splitlines(): + if line.strip() == "": + handle = None + + handleSearch = re.search( + r"^Handle\s+([^,]+),\s+DMI type\s+([^,]+),", line, re.IGNORECASE + ) + if handleSearch: + handle = handleSearch.group(1) + dmiType = handleSearch.group(2) + intDmiType = int(dmiType) + + if intDmiType > 127 and intDmiType < 256: + output[handle] = {"__dmiType": dmiType, "__section": "OEM Specific"} + continue + + if dmiType in dmiSections: + output[handle] = { + "__dmiType": dmiType, + "__section": dmiSections[dmiType], + } + continue + + output[handle] = {"__dmiType": dmiType, "__section": "Unknown"} + continue + + if handle and re.match(r"^\S", line): + output[handle]["__type"] = line + continue + + entry = re.search(r"^\s+([^:]+):\s+(.*)$", line) + if handle and entry: + key = camelCase(entry.group(1), to_camelcase) + value = entry.group(2).strip() + + output[handle][key] = value + continue + + if line == "": + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["dmidecode"] = { + "cmd": "dmidecode", + "description": "Dumping all information from DMI (SMBIOS)", + "parser": parser, + } + + main["dmidecode_bios"] = { + "cmd": "dmidecode -t bios", + "description": "Dumping BIOS information from DMI (SMBIOS)", + "parser": parser, + } + + main["dmidecode_system"] = { + "cmd": "dmidecode -t system", + "description": "Dumping SYSTEM information from DMI (SMBIOS)", + "parser": parser, + } + + main["dmidecode_baseboard"] = { + "cmd": "dmidecode -t baseboard", + "description": "Dumping BASEBOARD information from DMI (SMBIOS)", + "parser": parser, + } + + main["dmidecode_chassis"] = { + "cmd": "dmidecode -t chassis", + "description": "Dumping CHASSIS information from DMI (SMBIOS)", + "parser": parser, + } + + main["dmidecode_processor"] = { + "cmd": "dmidecode -t processor", + "description": "Dumping CHASSIS information from DMI (SMBIOS)", + "parser": parser, + } + + main["dmidecode_memory"] = { + "cmd": "dmidecode -t memory", + "description": "Dumping MEMORY information from DMI (SMBIOS)", + "parser": parser, + } + + main["dmidecode_cache"] = { + "cmd": "dmidecode -t cache", + "description": "Dumping CACHE information from DMI (SMBIOS)", + "parser": parser, + } + + main["dmidecode_connector"] = { + "cmd": "dmidecode -t connector", + "description": "Dumping CONNECTOR information from DMI (SMBIOS)", + "parser": parser, + } + + main["dmidecode_slot"] = { + "cmd": "dmidecode -t slot", + "description": "Dumping SLOT information from DMI (SMBIOS)", + "parser": parser, + } diff --git a/modules/dnf.py b/modules/dnf.py index 7b72a0e..f5e9a07 100644 --- a/modules/dnf.py +++ b/modules/dnf.py @@ -1,72 +1,81 @@ - -import re - -def parser_repolist(stdout, stderr): - output = {'repos': [], 'errors': []} - insideTable = False - col1 = None - col2 = None - if stdout: - for line in stdout.splitlines(): - tableHeader = re.search(r'^(repo id\s+)(repo name\s+)status', line, re.IGNORECASE) - - if col1 and col2: - tableRow = re.search(r'^(.{%s})(.{%s})(.*)$' % (col1, col2), line) - - if insideTable and tableRow: - output['repos'].append({ - 'repo': tableRow.group(1).strip(), - 'repo_name': tableRow.group(2).strip(), - 'status': tableRow.group(3).strip() - }) - continue - - if tableHeader: - insideTable = True - col1 = len(tableHeader.group(1)) - col2 = len(tableHeader.group(2)) - - else: - insideTable = False - - if stderr: - for line in stderr.splitlines(): - if re.search(r'http.*error .*', line, re.IGNORECASE): - if not line in output['errors']: - output['errors'].append(line) - - return {'output': output} - -def parser_installed(stdout, stderr): - output = {'packages': [], 'errors': []} - if stdout: - for line in stdout.splitlines(): - package = re.search(r'^([\S\.]+)\.(\S+)\s+(\S+\.\S+)\s+(\S+.*)$', line) - if package: - output['packages'].append({ - 'name': package.group(1).strip(), - 'arch': package.group(2).strip(), - 'version': package.group(3).strip(), - 'status': package.group(4).strip() - }) - - if stderr: - for line in stderr.splitlines(): - if re.search(r'http.*error .*', line, re.IGNORECASE): - if not line in output['errors']: - output['errors'].append(line) - - return {'output': output} - -def register(main): - main['dnf_repolist'] = { - 'cmd': 'dnf repolist --all', - 'description': 'DNF - defined repositories', - 'parser': parser_repolist - } - - main['dnf_installed'] = { - 'cmd': 'dnf list installed', - 'description': 'DNF - list installed packages', - 'parser': parser_installed - } +import re + + +def parser_repolist(stdout, stderr, to_camelcase): + output = {"repos": [], "errors": []} + + insideTable = False + col1 = None + col2 = None + if stdout: + for line in stdout.splitlines(): + tableHeader = re.search( + r"^(repo id\s+)(repo name\s+)status", line, re.IGNORECASE + ) + + if col1 and col2: + tableRow = re.search(r"^(.{%s})(.{%s})(.*)$" % (col1, col2), line) + + if insideTable and tableRow: + output["repos"].append( + { + "repo": tableRow.group(1).strip(), + "repo_name": tableRow.group(2).strip(), + "status": tableRow.group(3).strip(), + } + ) + continue + + if tableHeader: + insideTable = True + col1 = len(tableHeader.group(1)) + col2 = len(tableHeader.group(2)) + + else: + insideTable = False + + if stderr: + for line in stderr.splitlines(): + if re.search(r"http.*error .*", line, re.IGNORECASE): + if not line in output["errors"]: + output["errors"].append(line) + + return {"output": output} + + +def parser_installed(stdout, stderr, to_camelcase): + output = {"packages": [], "errors": []} + if stdout: + for line in stdout.splitlines(): + package = re.search(r"^([\S\.]+)\.(\S+)\s+(\S+\.\S+)\s+(\S+.*)$", line) + if package: + output["packages"].append( + { + "name": package.group(1).strip(), + "arch": package.group(2).strip(), + "version": package.group(3).strip(), + "status": package.group(4).strip(), + } + ) + + if stderr: + for line in stderr.splitlines(): + if re.search(r"http.*error .*", line, re.IGNORECASE): + if not line in output["errors"]: + output["errors"].append(line) + + return {"output": output} + + +def register(main): + main["dnf_repolist"] = { + "cmd": "dnf repolist --all", + "description": "DNF - defined repositories", + "parser": parser_repolist, + } + + main["dnf_installed"] = { + "cmd": "dnf list installed", + "description": "DNF - list installed packages", + "parser": parser_installed, + } diff --git a/modules/env.py b/modules/env.py index d6fc230..4749e56 100644 --- a/modules/env.py +++ b/modules/env.py @@ -1,19 +1,25 @@ - -import re - -def parser(stdout, stderr): - output = {} - if stdout: - for line in stdout.splitlines(): - lineMatch = re.search(r'^([^=]+)=(.*)$', line) - if lineMatch: - output[lineMatch.group(1)] = lineMatch.group(2) - - return {'output': output} - -def register(main): - main['env'] = { - 'cmd': 'env', - 'description': 'Environment variables', - 'parser': parser - } \ No newline at end of file +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + lineMatch = re.search(r"^([^=]+)=(.*)$", line) + if lineMatch: + output[lineMatch.group(1)] = lineMatch.group(2) + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["env"] = { + "cmd": "env", + "description": "Environment variables", + "parser": parser, + } diff --git a/modules/etc_default.py b/modules/etc_default.py index b0912f0..4ec06f2 100644 --- a/modules/etc_default.py +++ b/modules/etc_default.py @@ -1,41 +1,54 @@ - -import re - -def setPathValue(data, path, value): - pathRest = None - pathParts = re.search(r'^([^\/]+)\/?(.*)$', path) - if pathParts: - path = pathParts.group(1) - pathRest = pathParts.group(2) - - if not path in data: - data[path] = {} - - if pathRest: - setPathValue(data[path], pathRest, value) - else: - if isinstance(data[path], dict): - data[path] = [] - data[path].append(value) - -def parser(stdout, stderr): - output = {} - if stdout: - for line in stdout.splitlines(): - pathValue = re.search(r'^\/etc\/default\/([^:]+):(.*)$', line) - if pathValue: - path = pathValue.group(1) - value = pathValue.group(2) - if value.strip() == '': - continue - if not re.search(r'^\s*#', value): - setPathValue(output, path, value) - - return {'output': output} - -def register(main): - main['etc_default'] = { - 'cmd': 'find /etc/default -type f -follow -print | xargs grep ""', - 'description': 'Default configuration for programs', - 'parser': parser - } \ No newline at end of file +import re + + +def setPathValue(data, path, value): + pathRest = None + pathParts = re.search(r"^([^\/]+)\/?(.*)$", path) + if pathParts: + path = pathParts.group(1) + pathRest = pathParts.group(2) + + if not path in data: + data[path] = {} + + if pathRest: + setPathValue(data[path], pathRest, value) + + else: + if isinstance(data[path], dict): + data[path] = [] + data[path].append(value) + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + pathValue = re.search(r"^\/etc\/default\/([^:]+):(.*)$", line) + if pathValue: + path = pathValue.group(1) + value = pathValue.group(2) + if value.strip() == "": + continue + + if not re.search(r"^\s*#", value): + setPathValue(output, path, value) + continue + + if re.match(r"^\s*#", value): + # ignore line with comment + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["etc_default"] = { + "cmd": 'find /etc/default -type f -follow -print | xargs grep ""', + "description": "Default configuration for programs", + "parser": parser, + } diff --git a/modules/etc_fstab.py b/modules/etc_fstab.py index a43c3c4..ec748b6 100644 --- a/modules/etc_fstab.py +++ b/modules/etc_fstab.py @@ -1,28 +1,35 @@ - -import re - -def parser(stdout, stderr): - output = {} - if stdout: - for line in stdout.splitlines(): - if re.match(r'^\s*#', line): - continue - lineMatch = re.split(r'\s+', line) - if lineMatch and len(lineMatch) > 5: - output[lineMatch[0]] = { - 'location': lineMatch[0], - 'mountPoint': lineMatch[1], - 'type': lineMatch[2], - 'security': lineMatch[3], - 'dump': lineMatch[4], - 'fsckOrder': lineMatch[5] - } - - return {'output': output} - -def register(main): - main['etc_fstab'] = { - 'cmd': 'cat /etc/fstab', - 'description': 'Filesystems mounted on boot', - 'parser': parser - } \ No newline at end of file +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + if re.match(r"^\s*#", line): + continue + + lineMatch = re.split(r"\s+", line) + if lineMatch and len(lineMatch) > 5: + output[lineMatch[0]] = { + "location": lineMatch[0], + "mountPoint": lineMatch[1], + "type": lineMatch[2], + "security": lineMatch[3], + "dump": lineMatch[4], + "fsckOrder": lineMatch[5], + } + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["etc_fstab"] = { + "cmd": "cat /etc/fstab", + "description": "Filesystems mounted on boot", + "parser": parser, + } diff --git a/modules/etc_group.py b/modules/etc_group.py index 099cc8b..74be8c7 100644 --- a/modules/etc_group.py +++ b/modules/etc_group.py @@ -1,16 +1,17 @@ - -from sysinfo_lib import parseCharDelimitedTable, tableToDict - -def parser(stdout, stderr): - columnsNames = ['groupName', 'password', 'gid', 'groupList'] - output = parseCharDelimitedTable(stdout, ':', columnsNames) - output = tableToDict(output, 'groupName') - return {'output': output} - -def register(main): - main['etc_group'] = { - 'cmd': 'cat /etc/group', - 'description': 'Groups essential information', - 'parser': parser - } - +from sysinfo_lib import parseCharDelimitedTable, tableToDict + + +def parser(stdout, stderr, to_camelcase): + columnsNames = ["groupName", "password", "gid", "groupList"] + output = parseCharDelimitedTable(stdout, ":", columnsNames) + output = tableToDict(output, "groupName") + + return {"output": output, "unprocessed": []} + + +def register(main): + main["etc_group"] = { + "cmd": "cat /etc/group", + "description": "Groups essential information", + "parser": parser, + } diff --git a/modules/etc_hosts.py b/modules/etc_hosts.py index c2c86e9..6ee525c 100644 --- a/modules/etc_hosts.py +++ b/modules/etc_hosts.py @@ -1,25 +1,70 @@ - -import re - -def parser(stdout, stderr): - output = {} - if stdout: - for line in stdout.splitlines(): - values = re.search(r'^\/etc\/([^\:]+):\s*(.*)$', line) - if not values: - continue - group = values.group(1) - value = re.sub(r'#.*$', '', values.group(2)).strip() - if group not in output: - output[group] = [] - if value != '': - output[group].append(value.split('\t')) - - return {'output': output} - -def register(main): - main['etc_hosts'] = { - 'cmd': """grep "" /etc/hosts*""", - 'description': 'Maps hostnames to IP addresses', - 'parser': parser - } +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + values = re.search(r"^\/etc\/([^\:]+):\s*(.*)$", line) + if values: + group = values.group(1) + value = values.group(2).strip() + + if value == "": + continue + + if re.match(r"\s*#", value): + # ignore line with comment + continue + + if group not in output: + output[group] = [] + + if group in ["hosts"]: + parts = re.search(r"^(\S+)\s+([^#]+)#?(.*)$", value) + if parts: + ip = parts.group(1).strip() + hostnames = parts.group(2).strip() + comment = parts.group(3).strip() + + output[group].append( + { + "ip": ip, + "hostnames": re.split(r"\s+", hostnames), + "comment": comment, + } + ) + continue + + if group in ["hosts.allow", "hosts.deny"]: + print("value", value) + parts = re.search(r"^([^:]+):\s*([^:]+):?([^#]+)#?(.*)$", value) + if parts: + daemon_list = parts.group(1).strip().split(",") + client_list = parts.group(2).strip().split(",") + command = parts.group(3).strip() + comment = parts.group(4).strip() + + output[group].append( + { + "daemonList": daemon_list, + "clientList": client_list, + "command": command, + "comment": comment, + } + ) + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["etc_hosts"] = { + "cmd": """grep "" /etc/hosts*""", + "description": "Maps hostnames to IP addresses", + "parser": parser, + } diff --git a/modules/etc_locale_gen.py b/modules/etc_locale_gen.py index 1a7c09b..b1960d0 100644 --- a/modules/etc_locale_gen.py +++ b/modules/etc_locale_gen.py @@ -1,22 +1,26 @@ - -import re - -def parser(stdout, stderr): - output = [] - if stdout: - for line in stdout.splitlines(): - values = re.search(r'^\s*([^#]+)', line) - if not values: - continue - value = values.group(1).strip() - if value != '': - output.append(value) - - return {'output': output} - -def register(main): - main['etc_locale_gen'] = { - 'cmd': 'cat /etc/locale.gen', - 'description': 'Configuration file for locale-gen', - 'parser': parser - } +import re + + +def parser(stdout, stderr, to_camelcase): + output = [] + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + values = re.search(r"^\s*([^#]+)", line) + if not values: + continue + + value = values.group(1).strip() + if value != "": + output.append(value) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["etc_locale_gen"] = { + "cmd": "cat /etc/locale.gen", + "description": "Configuration file for locale-gen", + "parser": parser, + } diff --git a/modules/etc_mtab.py b/modules/etc_mtab.py index 0b8ae00..6845c16 100644 --- a/modules/etc_mtab.py +++ b/modules/etc_mtab.py @@ -1,26 +1,46 @@ - -import re - -def parser(stdout, stderr): - output = {} - if stdout: - for line in stdout.splitlines(): - values = re.split(r'\s+', line) - if len(values) > 5: - output[values[1]] = { - 'partition': values[0], - 'mountPoint': values[1], - 'fileSystem': values[2], - 'mountOptions': re.split(r',', values[3]), - 'dump': values[4], - 'fsckOrder': values[5] - } - - return {'output': output} - -def register(main): - main['etc_mtab'] = { - 'cmd': 'cat /etc/mtab', - 'description': 'Currently mounted filesystems', - 'parser': parser - } +import re + + +def parse_mount_options(value): + output = {} + for option in re.split(r"\s*,\s*", value): + dir = re.search(r"^([^=]+)=(.*)$", option) + + if dir: + output[dir.group(1)] = dir.group(2).split(":") + + else: + output[option] = True + + return output + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + values = re.split(r"\s+", line) + if len(values) > 5: + output[values[1]] = { + "partition": values[0], + "mountPoint": values[1], + "fileSystem": values[2], + "mountOptions": parse_mount_options(values[3]), + "dump": values[4], + "fsckOrder": values[5], + } + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["etc_mtab"] = { + "cmd": "cat /etc/mtab", + "description": "Currently mounted filesystems", + "parser": parser, + } diff --git a/modules/etc_passwd.py b/modules/etc_passwd.py index 6ca092c..b5dd72d 100644 --- a/modules/etc_passwd.py +++ b/modules/etc_passwd.py @@ -1,15 +1,16 @@ - -from sysinfo_lib import parseCharDelimitedTable, tableToDict - -def parser(stdout, stderr): - columnsNames = ['username', 'password', 'uid', 'gid', 'idInfo', 'homeDir', 'shell'] - output = parseCharDelimitedTable(stdout, ':', columnsNames) - output = tableToDict(output, 'username') - return {'output': output} - -def register(main): - main['etc_passwd'] = { - 'cmd': 'cat /etc/passwd', - 'description': 'Attributes of each user or account on a computer', - 'parser': parser - } +from sysinfo_lib import parseCharDelimitedTable, tableToDict + + +def parser(stdout, stderr, to_camelcase): + columnsNames = ["username", "password", "uid", "gid", "idInfo", "homeDir", "shell"] + output = parseCharDelimitedTable(stdout, ":", columnsNames) + output = tableToDict(output, "username") + return {"output": output, "unprocessed": []} + + +def register(main): + main["etc_passwd"] = { + "cmd": "cat /etc/passwd", + "description": "Attributes of each user or account on a computer", + "parser": parser, + } diff --git a/modules/etc_release.py b/modules/etc_release.py index 70f1b90..a0aebac 100644 --- a/modules/etc_release.py +++ b/modules/etc_release.py @@ -1,19 +1,28 @@ - -import re - -def parser(stdout, stderr): - output = {} - if stdout: - for line in stdout.splitlines(): - values = re.search(r'^([^=]+)=(.*)$', line) - if values: - output[values.group(1)] = values.group(2).strip().strip('"') - - return {'output': output} - -def register(main): - main['etc_release'] = { - 'cmd': 'cat /etc/*release', - 'description': 'OS release info', - 'parser': parser - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + values = re.search(r"^([^=]+)=(.*)$", line) + if values: + key = camelCase(values.group(1), to_camelcase) + value = values.group(2).strip().strip('"') + output[key] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["etc_release"] = { + "cmd": "cat /etc/*release", + "description": "OS release info", + "parser": parser, + } diff --git a/modules/etc_shadow.py b/modules/etc_shadow.py index 767b9f3..4d5529a 100644 --- a/modules/etc_shadow.py +++ b/modules/etc_shadow.py @@ -1,15 +1,26 @@ - -from sysinfo_lib import parseCharDelimitedTable, tableToDict - -def parser(stdout, stderr): - columnsNames = ['username', 'password', 'lastPasswordChange', 'minimum', 'maximum', 'warn', 'inactive', 'expire'] - output = parseCharDelimitedTable(stdout, ':', columnsNames) - output = tableToDict(output, 'username') - return {'output': output} - -def register(main): - main['etc_shadow'] = { - 'cmd': 'cat /etc/shadow', - 'description': 'Shadow database of the passwd file', - 'parser': parser - } +from sysinfo_lib import parseCharDelimitedTable, tableToDict + + +def parser(stdout, stderr, to_camelcase): + columnsNames = [ + "username", + "password", + "lastPasswordChange", + "minimum", + "maximum", + "warn", + "inactive", + "expire", + ] + output = parseCharDelimitedTable(stdout, ":", columnsNames) + output = tableToDict(output, "username") + + return {"output": output, "unprocessed": []} + + +def register(main): + main["etc_shadow"] = { + "cmd": "cat /etc/shadow", + "description": "Shadow database of the passwd file", + "parser": parser, + } diff --git a/modules/etc_timezone.py b/modules/etc_timezone.py index 10cf6ca..f230423 100644 --- a/modules/etc_timezone.py +++ b/modules/etc_timezone.py @@ -1,13 +1,15 @@ - -def parser(stdout, stderr): - output = '' - if stdout: - output = stdout.strip() - return {'output': output} - -def register(main): - main['etc_timezone'] = { - 'cmd': 'cat /etc/timezone', - 'description': 'Timezone settings', - 'parser': parser - } +def parser(stdout, stderr, to_camelcase): + output = "" + + if stdout: + output = stdout.strip() + + return {"output": output, "unprocessed": []} + + +def register(main): + main["etc_timezone"] = { + "cmd": "cat /etc/timezone", + "description": "Timezone settings", + "parser": parser, + } diff --git a/modules/fbset.py b/modules/fbset.py index 5d28910..616e39e 100644 --- a/modules/fbset.py +++ b/modules/fbset.py @@ -1,93 +1,119 @@ - -import re - -def parser(stdout, stderr): - output = {} - modeName = '' - if stdout: - for line in stdout.splitlines(): - mode = re.search(r'^\s*mode "([^"]+)\s*"$', line) - if mode: - modeName = mode.group(1) - output[modeName] = {} - - endmode = re.search(r'^\s*endmode', line) - if endmode: - modeName = '' - - if modeName: - geometry = re.search(r'^\s*geometry\s*(\d+)\s*(\d+)\s*(\d+)\s*(\d+)\s*(\d+)\s*$', line) - if geometry: - output[modeName]['geometry'] = { - 'xres': geometry.group(1), - 'yres': geometry.group(2), - 'xresVirtual': geometry.group(3), - 'yresVirtual': geometry.group(4), - 'bitsPerPixel': geometry.group(5) - } - - timings = re.search(r'^\s*timings\s*(\d+)\s*(\d+)\s*(\d+)\s*(\d+)\s*(\d+)\s*(\d+)\s*(\d+)\s*$', line) - if timings: - output[modeName]['timings'] = { - 'pixclock': timings.group(1), - 'leftMargin': timings.group(2), - 'rightMargin': timings.group(3), - 'upperMargin': timings.group(4), - 'lowerMargin': timings.group(5), - 'hsyncLen': timings.group(6), - 'vsyncLen': timings.group(7) - } - - rgba = re.search(r'^\s*rgba\s*(\d+)\/(\d+),(\d+)\/(\d+),(\d+)\/(\d+),(\d+)\/(\d+)\s*$', line) - if rgba: - output[modeName]['rgba'] = { - 'redLength': rgba.group(1), - 'redOffset': rgba.group(2), - 'greenLength': rgba.group(3), - 'greenOffset': rgba.group(4), - 'blueLength': rgba.group(5), - 'blueOffset': rgba.group(6), - 'transpLength': rgba.group(7), - 'transpOffset': rgba.group(8) - } - - state = re.search(r'^\s*(interlaced|double|vsync|hsync|csync|extsync)\s+(\S+)\s*$', line) - if state: - output[modeName][state.group(1)] = state.group(2) - - return { - 'output': { - 'mode': output - } - } - -def parserInfo(stdout, stderr): - output = parser(stdout, stderr) - output['output']['info'] = {} - - informationBlock = False - if stdout: - for line in stdout.splitlines(): - info = re.search(r'^\s*Frame buffer device information:\s*$', line) - if info: - informationBlock = True - - if informationBlock: - keyValue = re.search(r'^\s+(\S+)\s*:\s+(.*)\s*$', line) - if keyValue: - output['output']['info'][keyValue.group(1)] = keyValue.group(2) - - return output - -def register(main): - main['fbset'] = { - 'cmd': 'fbset -a', - 'description': 'Show frame buffer device settings', - 'parser': parser - } - - main['fbset_info'] = { - 'cmd': 'fbset -i', - 'description': 'Show frame buffer device information', - 'parser': parserInfo - } \ No newline at end of file +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + modeName = "" + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + mode = re.search(r'^\s*mode "([^"]+)\s*"$', line) + if mode: + modeName = mode.group(1) + output[modeName] = {} + continue + + endmode = re.search(r"^\s*endmode", line) + if endmode: + modeName = "" + continue + + if modeName: + geometry = re.search( + r"^\s+geometry\s*(\d+)\s*(\d+)\s*(\d+)\s*(\d+)\s*(\d+)\s*$", line + ) + if geometry: + output[modeName]["geometry"] = { + "xres": geometry.group(1), + "yres": geometry.group(2), + "xresVirtual": geometry.group(3), + "yresVirtual": geometry.group(4), + "bitsPerPixel": geometry.group(5), + } + continue + + timings = re.search( + r"^\s+timings\s*(\d+)\s*(\d+)\s*(\d+)\s*(\d+)\s*(\d+)\s*(\d+)\s*(\d+)\s*$", + line, + ) + if timings: + output[modeName]["timings"] = { + "pixclock": timings.group(1), + "leftMargin": timings.group(2), + "rightMargin": timings.group(3), + "upperMargin": timings.group(4), + "lowerMargin": timings.group(5), + "hsyncLen": timings.group(6), + "vsyncLen": timings.group(7), + } + continue + + rgba = re.search( + r"^\s+rgba\s*(\d+)\/(\d+),(\d+)\/(\d+),(\d+)\/(\d+),(\d+)\/(\d+)\s*$", + line, + ) + if rgba: + output[modeName]["rgba"] = { + "redLength": rgba.group(1), + "redOffset": rgba.group(2), + "greenLength": rgba.group(3), + "greenOffset": rgba.group(4), + "blueLength": rgba.group(5), + "blueOffset": rgba.group(6), + "transpLength": rgba.group(7), + "transpOffset": rgba.group(8), + } + continue + + state = re.search( + r"^\s+(interlaced|double|vsync|hsync|csync|extsync)\s+(\S+)\s*$", + line, + ) + if state: + output[modeName][state.group(1)] = state.group(2) + continue + + kv = re.search(r"^\s+(\S+)\s+(.*)$", line) + if kv: + output[modeName][kv.group(1)] = kv.group(2) + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def parserInfo(stdout, stderr, to_camelcase): + output = parser(stdout, stderr, to_camelcase) + output["output"]["info"] = {} + + informationBlock = False + if stdout: + for line in stdout.splitlines(): + info = re.search(r"^\s*Frame buffer device information:\s*$", line) + if info: + informationBlock = True + continue + + if informationBlock: + keyValue = re.search(r"^\s+(\S+)\s*:\s+(.*)\s*$", line) + if keyValue: + output["output"]["info"][keyValue.group(1)] = keyValue.group(2) + continue + + return output + + +def register(main): + main["fbset"] = { + "cmd": "fbset -a", + "description": "Show frame buffer device settings", + "parser": parser, + } + + main["fbset_info"] = { + "cmd": "fbset -i", + "description": "Show frame buffer device information", + "parser": parserInfo, + } diff --git a/modules/findmnt.py b/modules/findmnt.py index ce9f9af..bbb3811 100644 --- a/modules/findmnt.py +++ b/modules/findmnt.py @@ -1,16 +1,36 @@ - -from sysinfo_lib import parseTable - -def parser(stdout, stderr): - output = {} - if stdout: - output = parseTable(stdout) - - return {'output': output} - -def register(main): - main['findmnt'] = { - 'cmd': 'findmnt -Al | column -t', - 'description': 'List all mounted filesytems', - 'parser': parser - } \ No newline at end of file +from sysinfo_lib import parseTable +import re + + +def parse_mount_options(value): + output = {} + for option in re.split(r"\s*,\s*", value): + dir = re.search(r"^([^=]+)=(.*)$", option) + + if dir: + output[dir.group(1)] = dir.group(2).split(":") + + else: + output[option] = True + + return output + + +def parser(stdout, stderr, to_camelcase): + output = {} + if stdout: + output = parseTable(stdout, to_camelcase=to_camelcase) + + for entry in output: + if "options" in entry: + entry["options"] = parse_mount_options(entry["options"]) + + return {"output": output, "unprocessed": []} + + +def register(main): + main["findmnt"] = { + "cmd": "findmnt -Al | column -t", + "description": "List all mounted filesytems", + "parser": parser, + } diff --git a/modules/free.py b/modules/free.py index 5edf159..9042fd2 100644 --- a/modules/free.py +++ b/modules/free.py @@ -1,29 +1,39 @@ - -import re -from sysinfo_lib import camelCase - -def parser(stdout, stderr): - output = {} - columns = None - if stdout: - typeName = '' - for line in stdout.splitlines(): - if re.search(r'total\s+used', line, re.IGNORECASE): - columns = re.split(r'\s+', line.strip()) - - entrySearch = re.search(r'^([^:]+):\s+(.*)$', line) - if columns and entrySearch: - type = camelCase(entrySearch.group(1)) - output[type] = {} - for idx, value in enumerate(re.split(r'\s+', entrySearch.group(2).strip())): - if idx < len(columns): - output[type][columns[idx]] = value - - return {'output': output} - -def register(main): - main['free'] = { - 'cmd': 'free -b -l -w', - 'description': 'Amount of free and used memory in the system', - 'parser': parser - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + columns = None + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + if re.search(r"total\s+used", line, re.IGNORECASE): + columns = re.split(r"\s+", line.strip()) + continue + + entrySearch = re.search(r"^([^:]+):\s+(.*)$", line) + if columns and entrySearch: + type = camelCase(entrySearch.group(1), to_camelcase) + output[type] = {} + for idx, value in enumerate( + re.split(r"\s+", entrySearch.group(2).strip()) + ): + if idx < len(columns): + key = camelCase(columns[idx], to_camelcase) + output[type][key] = value + + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["free"] = { + "cmd": "free -b -l -w", + "description": "Amount of free and used memory in the system", + "parser": parser, + } diff --git a/modules/getconf.py b/modules/getconf.py index 03a97e9..cd90800 100644 --- a/modules/getconf.py +++ b/modules/getconf.py @@ -1,21 +1,29 @@ - -import re - -def parser(stdout, stderr): - output = {} - if stdout: - for line in stdout.splitlines(): - kv = re.search(r'^(\S+)\s*(.*)$', line) - if kv: - output[kv.group(1)] = kv.group(2).strip() - - return { - 'output': output, - } - -def register(main): - main['getconf'] = { - 'cmd': 'getconf -a', - 'description': 'Configuration variables for the current system and their values', - 'parser': parser - } \ No newline at end of file +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + kv = re.search(r"^(\S+)\s*(.*)$", line) + if kv: + key = camelCase(kv.group(1), to_camelcase) + value = kv.group(2).strip() + + output[key] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["getconf"] = { + "cmd": "getconf -a", + "description": "Configuration variables for the current system and their values", + "parser": parser, + } diff --git a/modules/hostnamectl.py b/modules/hostnamectl.py index 3403da7..1b9d637 100644 --- a/modules/hostnamectl.py +++ b/modules/hostnamectl.py @@ -1,20 +1,29 @@ - -import re -from sysinfo_lib import camelCase - -def parser(stdout, stderr): - output = {} - if stdout: - for line in stdout.splitlines(): - lineMatch = re.search(r'^([^:]+):\s*(.*)', line) - if lineMatch: - output[camelCase(lineMatch.group(1))] = lineMatch.group(2) - - return {'output': output} - -def register(main): - main['hostnamectl'] = { - 'cmd': 'hostnamectl status', - 'description': 'Current system hostname and related information', - 'parser': parser - } \ No newline at end of file +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + kv = re.search(r"^([^:]+):\s*(.*)", line) + if kv: + key = camelCase(kv.group(1), to_camelcase) + value = kv.group(2) + + output[key] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["hostnamectl"] = { + "cmd": "hostnamectl status", + "description": "Current system hostname and related information", + "parser": parser, + } diff --git a/modules/ifconfig.py b/modules/ifconfig.py index ba26809..5b777ca 100644 --- a/modules/ifconfig.py +++ b/modules/ifconfig.py @@ -1,74 +1,86 @@ - -import re -from sysinfo_lib import camelCase - -def extractValue(data, line, key, regExp): - search = re.search(regExp, line, re.IGNORECASE) - if search: - data[key] = search.group(1) - return data - -def extractValues(data, line): - for pair in re.split(r'\s\s+', line): - desc = re.search(r'^(.*)\((.*)\)$', pair.strip()) - if desc: - data['description'] = desc.group(2) - if desc.group(1): - pair = desc.group(1).strip() - else: - continue - - kv = re.search(r'^([^\s]+)\s(\S.*)$', pair) - if kv: - value = kv.group(2) - valueFix = re.search(r'^(\S+)\s+(\S+)\s(\S+)$', value) - if valueFix: - data[kv.group(1)] = valueFix.group(1) - data[valueFix.group(2)] = valueFix.group(3) - else: - data[kv.group(1)] = value - - return extractValues - -def parser(stdout, stderr): - output = {} - blockData = {} - if stdout: - for block in re.split(r'\r\r|\n\n|\r\n\r\n', stdout): - blockData = {'entries': [], 'rx': {}, 'tx': {}} - for line in block.splitlines(): - header = re.search(r'^(\S[^:]+):\s*(.*)$', line) - if header: - name = header.group(1) - blockData['name'] = name - extractValue(blockData, line, 'flags', r'flags=(\S+)') - extractValues(blockData, header.group(2)) - output[name] = blockData - - rxTx = re.search(r'^\s+([rt]x)\s+(.*)$', line, re.IGNORECASE) - if rxTx: - type = rxTx.group(1).lower() - extractValues(blockData[type], rxTx.group(2)) - continue - - sub = re.search(r'^\s+(\S+)\s\s(.*)$', line, re.IGNORECASE) - if sub: - subData = {'type': sub.group(1)} - extractValues(subData, sub.group(2)) - blockData['entries'].append(subData) - continue - - sub = re.search(r'^\s+(\S+)\s(\S+)\s\s(.*)$', line, re.IGNORECASE) - if sub: - subData = {'type': sub.group(1), 'value': sub.group(2)} - extractValues(subData, sub.group(3)) - blockData['entries'].append(subData) - - return {'output': output} - -def register(main): - main['ifconfig'] = { - 'cmd': 'ifconfig -a -v', - 'description': 'List all interfaces which are currently available, even if down', - 'parser': parser - } +import re +from sysinfo_lib import camelCase + + +def extractValue(data, line, key, regExp): + search = re.search(regExp, line, re.IGNORECASE) + if search: + data[key] = search.group(1) + return data + + +def extractValues(data, line, to_camelcase): + for pair in re.split(r"\s\s+", line): + desc = re.search(r"^(.*)\((.*)\)$", pair.strip()) + if desc: + data["description"] = desc.group(2) + if desc.group(1): + pair = desc.group(1).strip() + else: + continue + + kv = re.search(r"^([^\s]+)\s(\S.*)$", pair) + if kv: + key = camelCase(kv.group(1), to_camelcase) + value = kv.group(2).strip() + valueFix = re.search(r"^(\S+)\s+(\S+)\s(\S+)$", value) + + if valueFix: + data[key] = valueFix.group(1) + data[valueFix.group(2)] = valueFix.group(3) + else: + data[key] = value + + return extractValues + + +def parser(stdout, stderr, to_camelcase): + output = {} + blockData = {} + unprocessed = [] + + if stdout: + for block in re.split(r"\r\r|\n\n|\r\n\r\n", stdout): + blockData = {"entries": [], "rx": {}, "tx": {}} + + for line in block.splitlines(): + header = re.search(r"^(\S[^:]+):\s*(.*)$", line) + if header: + name = header.group(1) + blockData["name"] = name + extractValue(blockData, line, "flags", r"flags=(\S+)") + extractValues(blockData, header.group(2), to_camelcase) + output[name] = blockData + continue + + rxTx = re.search(r"^\s+([rt]x)\s+(.*)$", line, re.IGNORECASE) + if rxTx: + type = rxTx.group(1).lower() + extractValues(blockData[type], rxTx.group(2), to_camelcase) + continue + + sub = re.search(r"^\s+(\S+)\s\s(.*)$", line, re.IGNORECASE) + if sub: + subData = {"type": sub.group(1)} + extractValues(subData, sub.group(2), to_camelcase) + blockData["entries"].append(subData) + continue + + sub = re.search(r"^\s+(\S+)\s(\S+)\s\s(.*)$", line, re.IGNORECASE) + if sub: + subData = {"type": sub.group(1), "value": sub.group(2)} + extractValues(subData, sub.group(3), to_camelcase) + blockData["entries"].append(subData) + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["ifconfig"] = { + "cmd": "ifconfig -a -v", + "description": "List all interfaces which are currently available, even if down", + "parser": parser, + } diff --git a/modules/lsblk.py b/modules/lsblk.py index ab06997..ca06026 100644 --- a/modules/lsblk.py +++ b/modules/lsblk.py @@ -1,25 +1,38 @@ - -import re -from sysinfo_lib import camelCase - -def parser(stdout, stderr): - output = {} - if stdout: - for line in stdout.splitlines(): - entry = {} - kv = re.findall(r'(\S[^=]+)=\"([^"]*)\"', line) - if kv: - for pair in kv: - entry[camelCase(pair[0])] = pair[1].strip() - - if 'name' in entry: - output[entry['name']] = entry - - return {'output': output} - -def register(main): - main['lsblk'] = { - 'cmd': 'lsblk -P -o NAME,KNAME,MAJ:MIN,FSTYPE,MOUNTPOINT,LABEL,UUID,PARTLABEL,PARTUUID,RA,RO,RM,MODEL,SERIAL,SIZE,STATE,OWNER,GROUP,MODE,ALIGNMENT,MIN-IO,OPT-IO,PHY-SEC,LOG-SEC,ROTA,SCHED,RQ-SIZE,TYPE,DISC-ALN,DISC-GRAN,DISC-MAX,DISC-ZERO,WSAME,WWN,RAND,PKNAME,HCTL,TRAN,REV,VENDOR', - 'description': 'Lists information about all block devices', - 'parser': parser - } \ No newline at end of file +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + entry = {} + kv = re.findall(r'(\S[^=]+)=\"([^"]*)\"', line) + if kv: + for pair in kv: + key = camelCase(pair[0], to_camelcase) + value = pair[1].strip() + + entry[key] = value + + if "name" in entry: + output[entry["name"]] = entry + continue + + elif "NAME" in entry: + output[entry["NAME"]] = entry + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["lsblk"] = { + "cmd": "lsblk -P -o NAME,KNAME,MAJ:MIN,FSTYPE,MOUNTPOINT,LABEL,UUID,PARTLABEL,PARTUUID,RA,RO,RM,MODEL,SERIAL,SIZE,STATE,OWNER,GROUP,MODE,ALIGNMENT,MIN-IO,OPT-IO,PHY-SEC,LOG-SEC,ROTA,SCHED,RQ-SIZE,TYPE,DISC-ALN,DISC-GRAN,DISC-MAX,DISC-ZERO,WSAME,WWN,RAND,PKNAME,HCTL,TRAN,REV,VENDOR", + "description": "Lists information about all block devices", + "parser": parser, + } diff --git a/modules/lscpu.py b/modules/lscpu.py index 4c40546..49cba41 100644 --- a/modules/lscpu.py +++ b/modules/lscpu.py @@ -1,21 +1,30 @@ - -import re -from sysinfo_lib import camelCase - -def parser(stdout, stderr): - output = {} - if stdout: - for line in stdout.splitlines(): - line = re.sub(r'\(s\)', 's', line) - lineMatch = re.search(r'^([^:]+):\s*(.*)', line) - if lineMatch: - output[camelCase(lineMatch.group(1))] = lineMatch.group(2) - - return {'output': output} - -def register(main): - main['lscpu'] = { - 'cmd': 'lscpu', - 'description': 'Information about the CPU architecture', - 'parser': parser - } \ No newline at end of file +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + line = re.sub(r"\(s\)", "s", line) + kv = re.search(r"^([^:]+):\s*(.*)", line) + if kv: + key = camelCase(kv.group(1), to_camelcase) + value = kv.group(2) + + output[key] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["lscpu"] = { + "cmd": "lscpu", + "description": "Information about the CPU architecture", + "parser": parser, + } diff --git a/modules/lsmod.py b/modules/lsmod.py index 9e1e131..2ffc99c 100644 --- a/modules/lsmod.py +++ b/modules/lsmod.py @@ -1,24 +1,38 @@ - -import re - -def parser(stdout, stderr): - output = {} - if stdout: - for line in stdout.splitlines(): - lineMatch = re.search(r'^(^\S+)\s*(\d+)\s*(\d+)\s*(.*)$', line) - if lineMatch: - output[lineMatch.group(1)] = { - 'module': lineMatch.group(1), - 'size': lineMatch.group(2), - 'usedNumber': lineMatch.group(3), - 'usedBy': lineMatch.group(4) - } - - return {'output': output} - -def register(main): - main['lsmod'] = { - 'cmd': 'lsmod', - 'description': 'Show the status of modules in the Linux Kernel', - 'parser': parser - } \ No newline at end of file +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + if re.match(r"Module.*Size", line): + continue + + lineMatch = re.search(r"^(^\S+)\s*(\d+)\s*(\d+)\s*(.*)$", line) + if lineMatch: + used_by = lineMatch.group(4).split(",") + if len(used_by) == 1: + if used_by[0] == "": + used_by = [] + + output[lineMatch.group(1)] = { + "module": lineMatch.group(1), + "size": lineMatch.group(2), + "usedNumber": lineMatch.group(3), + "usedBy": used_by, + } + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["lsmod"] = { + "cmd": "lsmod", + "description": "Show the status of modules in the Linux Kernel", + "parser": parser, + } diff --git a/modules/lsns.py b/modules/lsns.py index cc4339e..a573e1a 100644 --- a/modules/lsns.py +++ b/modules/lsns.py @@ -1,16 +1,22 @@ - -from sysinfo_lib import parseTable - -def parser(stdout, stderr): - output = {} - if stdout: - output = parseTable(stdout, r'^(\s*NS)(\sTYPE\s+)(\sPATH\s*)(\s\s*NPROCS)(\s*\sPID)(\s*\sPPID)(\s*\sUID)(\sUSER\s*)(\sCOMMAND\s*)') - - return {'output': output} - -def register(main): - main['lsns'] = { - 'cmd': 'lsns -o NS,TYPE,PATH,NPROCS,PID,PPID,UID,USER,COMMAND', - 'description': 'Block device ioctls', - 'parser': parser - } \ No newline at end of file +from sysinfo_lib import parseTable + + +def parser(stdout, stderr, to_camelcase): + output = {} + + if stdout: + output = parseTable( + stdout, + header_pattern=r"^(\s*NS)(\sTYPE\s+)(\sPATH\s*)(\s\s*NPROCS)(\s*\sPID)(\s*\sPPID)(\s*\sUID)(\sUSER\s*)(\sCOMMAND\s*)", + to_camelcase=to_camelcase, + ) + + return {"output": output, "unprocessed": []} + + +def register(main): + main["lsns"] = { + "cmd": "lsns -o NS,TYPE,PATH,NPROCS,PID,PPID,UID,USER,COMMAND", + "description": "Block device ioctls", + "parser": parser, + } diff --git a/modules/lsof.py b/modules/lsof.py index 6118248..017417b 100644 --- a/modules/lsof.py +++ b/modules/lsof.py @@ -1,98 +1,105 @@ - -import re - -opField = { - 'a': 'accessMode', - 'c': 'commandName', - 'C': 'structureShareCount', - 'd': 'deviceCharacterCode', - 'D': 'majorMinorDeviceNumber', - 'f': 'fileDescriptor', - 'F': 'structureAddress', - 'g': 'processGroupId', - 'G': 'flags', - 'i': 'inodeNumber', - 'k': 'linkCount', - 'K': 'taskId', - 'l': 'lockStatus', - 'L': 'loginName', - 'm': 'markerBetweenRepeatedOutput', - 'n': 'name', - 'N': 'nodeIdentifier', - 'o': 'fileOffset', - 'p': 'processId', - 'P': 'protocolName', - 'r': 'rawDeviceNumber', - 'R': 'parentPid', - 's': 'fileSize', - 'S': 'streamModuleAndDeviceNames', - 't': 'fileType', - 'T': 'tcpTpiInfo', - 'u': 'userId', - 'z': 'zoneName', - 'Z': 'selinuxSecurityContext' -} - -tcptpiField = { - 'QR': 'readQueueSize', - 'QS': 'sendQueueSize', - 'SO': 'socketOptionsAndValues', - 'SS': 'socketStates', - 'ST': 'connectionState', - 'TF': 'tcpFlagsAndValues', - 'WR': 'windowReadSize', - 'WW': 'windowWriteSize' -} - -def parseElements(elements): - global opField - global tcptpiField - output = {} - for el in elements: - ident = el[0:1] - content = el[1:] - identType = opField.get(ident, ident) - if identType: - if not identType in output: - output[identType] = {} - if ident == 'T': - fifc = (content + '=').split('=') - fifcType = tcptpiField.get(fifc[0], fifc[0]) - output[identType][fifcType] = fifc[1] - - else: - output[identType] = content - - return output - -def parser(stdout, stderr): - output = {} - pid = None - if stdout: - for line in re.split(r'\x00\n', stdout): - line = re.sub(r'^[\s\x00]*', '', line) - elements = re.split(r'\x00', line) - if not elements: - continue - - first = elements.pop(0) - if first: - ident = first[0:1] - content = first[1:] - if ident == 'p': - pid = content - output[pid] = parseElements(elements) - output[pid]['pid'] = pid - output[pid]['files'] = [] - - if pid and ident == 'f': - output[pid]['files'].append(parseElements(elements)) - - return {'output': output} - -def register(main): - main['lsof'] = { - 'cmd': 'lsof -F0', - 'description': 'Information about files opened by processes', - 'parser': parser - } +import re + +opField = { + "a": "accessMode", + "c": "commandName", + "C": "structureShareCount", + "d": "deviceCharacterCode", + "D": "majorMinorDeviceNumber", + "f": "fileDescriptor", + "F": "structureAddress", + "g": "processGroupId", + "G": "flags", + "i": "inodeNumber", + "k": "linkCount", + "K": "taskId", + "l": "lockStatus", + "L": "loginName", + "m": "markerBetweenRepeatedOutput", + "n": "name", + "N": "nodeIdentifier", + "o": "fileOffset", + "p": "processId", + "P": "protocolName", + "r": "rawDeviceNumber", + "R": "parentPid", + "s": "fileSize", + "S": "streamModuleAndDeviceNames", + "t": "fileType", + "T": "tcpTpiInfo", + "u": "userId", + "z": "zoneName", + "Z": "selinuxSecurityContext", +} + +tcptpiField = { + "QR": "readQueueSize", + "QS": "sendQueueSize", + "SO": "socketOptionsAndValues", + "SS": "socketStates", + "ST": "connectionState", + "TF": "tcpFlagsAndValues", + "WR": "windowReadSize", + "WW": "windowWriteSize", +} + + +def parseElements(elements): + global opField + global tcptpiField + output = {} + for el in elements: + ident = el[0:1] + content = el[1:].strip() + + identType = opField.get(ident, ident) + if identType: + if not identType in output: + output[identType] = {} + + if ident == "T": + fifc = (content + "=").split("=") + fifcType = tcptpiField.get(fifc[0], fifc[0]) + + output[identType][fifcType] = fifc[1] + + else: + output[identType] = content + + return output + + +def parser(stdout, stderr, to_camelcase): + output = {} + pid = None + + if stdout: + for line in re.split(r"\x00\n", stdout): + line = re.sub(r"^[\s\x00]*", "", line) + elements = re.split(r"\x00", line) + if not elements: + continue + + first = elements.pop(0) + if first: + ident = first[0:1] + content = first[1:] + + if ident == "p": + pid = content + output[pid] = parseElements(elements) + output[pid]["pid"] = pid + output[pid]["files"] = [] + + if pid and ident == "f": + output[pid]["files"].append(parseElements(elements)) + + return {"output": output, "unprocessed": []} + + +def register(main): + main["lsof"] = { + "cmd": "lsof -F0", + "description": "Information about files opened by processes", + "parser": parser, + } diff --git a/modules/lspci.py b/modules/lspci.py index ddbed32..9b9bf05 100644 --- a/modules/lspci.py +++ b/modules/lspci.py @@ -1,26 +1,39 @@ - -import re -from sysinfo_lib import camelCase - -def parser(stdout, stderr): - output = {} - slot = None - if stdout: - for line in stdout.splitlines(): - slotSearch = re.search(r'^Slot:\s+(.*)$', line, re.IGNORECASE) - if slotSearch: - slot = slotSearch.group(1).strip() - output[slot] = {} - - keyValueSearch = re.search(r'^(\S[^:]+):\s+(.*)$', line) - if slot and keyValueSearch: - output[slot][camelCase(keyValueSearch.group(1))] = keyValueSearch.group(2).strip() - - return {'output': output} - -def register(main): - main['lspci'] = { - 'cmd': 'lspci -mm -vvv', - 'description': 'List all PCI devices', - 'parser': parser - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + slot = None + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + if line.strip() == "": + continue + + slotSearch = re.search(r"^Slot:\s+(.*)$", line, re.IGNORECASE) + if slotSearch: + slot = slotSearch.group(1).strip() + output[slot] = {} + continue + + kv = re.search(r"^(\S[^:]+):\s+(.*)$", line) + if slot and kv: + key = camelCase(kv.group(1), to_camelcase) + value = kv.group(2).strip() + + output[slot][key] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["lspci"] = { + "cmd": "lspci -mm -vvv", + "description": "List all PCI devices", + "parser": parser, + } diff --git a/modules/lsusb.py b/modules/lsusb.py index d70afab..c8b622d 100644 --- a/modules/lsusb.py +++ b/modules/lsusb.py @@ -1,93 +1,136 @@ - -import re -from sysinfo_lib import camelCase - -def extractDescriptors(data, lineNumber, offset): - output = {} - ln = lineNumber - descOffset = 0 - while ln < len(data): - line = data[ln] - searchDesc = re.search(r'^(\s*)(.*)Descriptors?:\s*$', line, re.IGNORECASE) - searchStatus = re.search(r'^(\s*)(.*Status)?:\s*(.*)$', line, re.IGNORECASE) - searchKeyValue = re.search(r'^\s*(\S+)\s+([0-9].*)$', line) - searchOffset = re.search(r'^(\s*)', line) - if searchOffset: - lineOffset = len(searchOffset.group(1)) - - if lineOffset < offset: - ln -= 1 - break - - if searchDesc: - descOffset = len(searchDesc.group(1)) + 2 - desc, ln = extractDescriptors(data, ln + 1, descOffset) - name = camelCase(searchDesc.group(2).strip()) - output[name] = desc - - elif searchStatus: - statusOffset = len(searchStatus.group(1)) + 2 - desc, ln = extractDescriptors(data, ln + 1, statusOffset) - name = camelCase(searchStatus.group(2).strip()) - if searchStatus.group(3).strip() != '': - desc['value'] = searchStatus.group(3).strip() - output[name] = desc - - elif searchKeyValue: - key = searchKeyValue.group(1).strip(':') - value = searchKeyValue.group(2).strip() - valueSplit = re.search(r'^(\S+)\s+(\S.*)$', value) - if valueSplit: - value = [valueSplit.group(1), valueSplit.group(2)] - if key in output: - output[key] = [output[key], value] - else: - output[key] = value - - else: - if not 'data' in output: - output['data'] = [] - output['data'].append(line.strip()) - - ln += 1 - return output, ln - -def parseBlock(data): - output = {} - lines = data.split('\n') - - while lines[0].strip() == '': - lines.pop(0) - - firstLine = lines.pop(0) - busDevice = re.search(r'Bus\s+(\S+)\s+Device\s+([^:]+):\s+ID\s+([^:]+):(\S+)\s*(.*)$', firstLine, re.IGNORECASE) - if busDevice: - output['bus'] = busDevice.group(1) - output['device'] = busDevice.group(2) - output['idVendor'] = busDevice.group(3) - output['idProduct'] = busDevice.group(4) - output['vendorProduct'] = busDevice.group(5) - - output['desc'], tmp = extractDescriptors(lines, 0, 0) - - return output - -def parser(stdout, stderr): - output = {} - if stdout: - delimiter = '-' * 20 - blocks = re.split(delimiter, re.sub(r'\n\nBus', '\n\n' + delimiter + 'Bus', stdout)) - if blocks: - for block in blocks: - blockData = parseBlock(block) - if 'bus' in blockData and 'device' in blockData: - id = blockData['bus'] + '/' + blockData['device'] - output[id] = blockData - return {'output': output} - -def register(main): - main['lsusb'] = { - 'cmd': 'lsusb -v', - 'description': 'List USB devices', - 'parser': parser - } \ No newline at end of file +import re +from sysinfo_lib import camelCase + + +def extractDescriptors(data, lineNumber, offset, to_camelcase): + output = {} + ln = lineNumber + descOffset = 0 + + while ln < len(data): + line = data[ln] + + searchOffset = re.search(r"^(\s*)", line) + if searchOffset: + lineOffset = len(searchOffset.group(1)) + + if lineOffset < offset: + ln -= 1 + break + + searchDesc = re.search(r"^(\s*)(.*Descriptor):\s*$", line, re.IGNORECASE) + if searchDesc: + descOffset = len(searchDesc.group(1)) + 2 + desc, ln = extractDescriptors(data, ln + 1, descOffset, to_camelcase) + name = camelCase(searchDesc.group(2).strip(), to_camelcase) + output[name] = desc + ln += 1 + continue + + searchStatus = re.search(r"^(\s*)(.*Status):\s*(.*)$", line, re.IGNORECASE) + if searchStatus: + statusOffset = len(searchStatus.group(1)) + 2 + desc, ln = extractDescriptors(data, ln + 1, statusOffset, to_camelcase) + name = camelCase(searchStatus.group(2).strip(), to_camelcase) + if searchStatus.group(3).strip() != "": + desc["value"] = searchStatus.group(3).strip() + + if name == "hubPortStatus": + print("desc", desc) + output[name] = desc + ln += 1 + continue + + searchKeyIndexValue = re.search(r"^\s*(\S+)\s+([0-9]+):\s+(.*)$", line) + if searchKeyIndexValue: + key = camelCase(searchKeyIndexValue.group(1), to_camelcase) + number = searchKeyIndexValue.group(2) + value = searchKeyIndexValue.group(3).strip() + + valueSplit = re.search(r"^(\S+)\s+(\S.*)$", value) + if valueSplit: + value = [valueSplit.group(1), valueSplit.group(2)] + + if not key in output: + output[key] = {} + + output[key][number] = value + + ln += 1 + continue + + searchKeyValue = re.search(r"^\s*(\S+)\s+([0-9].*)$", line) + if searchKeyValue: + key = camelCase(searchKeyValue.group(1).strip(":"), to_camelcase) + value = searchKeyValue.group(2).strip() + + valueSplit = re.search(r"^(\S+)\s+(\S.*)$", value) + if valueSplit: + value = [valueSplit.group(1), valueSplit.group(2)] + + if key in output: + output[key] = [output[key], value] + else: + output[key] = value + + ln += 1 + continue + + if not "data" in output: + output["data"] = [] + + output["data"].append(line.strip()) + + ln += 1 + return output, ln + + +def parseBlock(data, to_camelcase): + output = {} + lines = data.split("\n") + + while lines[0].strip() == "": + lines.pop(0) + + firstLine = lines.pop(0) + busDevice = re.search( + r"Bus\s+(\S+)\s+Device\s+([^:]+):\s+ID\s+([^:]+):(\S+)\s*(.*)$", + firstLine, + re.IGNORECASE, + ) + if busDevice: + output["bus"] = busDevice.group(1) + output["device"] = busDevice.group(2) + output["idVendor"] = busDevice.group(3) + output["idProduct"] = busDevice.group(4) + output["vendorProduct"] = busDevice.group(5) + + output["desc"], tmp = extractDescriptors(lines, 0, 0, to_camelcase) + + return output + + +def parser(stdout, stderr, to_camelcase): + output = {} + + if stdout: + delimiter = "-" * 20 + blocks = re.split( + delimiter, re.sub(r"\n\nBus", "\n\n" + delimiter + "Bus", stdout) + ) + if blocks: + for block in blocks: + blockData = parseBlock(block, to_camelcase) + if "bus" in blockData and "device" in blockData: + id = blockData["bus"] + "/" + blockData["device"] + output[id] = blockData + + return {"output": output, "unprocessed": []} + + +def register(main): + main["lsusb"] = { + "cmd": "lsusb -v", + "description": "List USB devices", + "parser": parser, + } diff --git a/modules/modinfo.py b/modules/modinfo.py index 16a90fe..edd5bbd 100644 --- a/modules/modinfo.py +++ b/modules/modinfo.py @@ -1,31 +1,39 @@ -import re -from sysinfo_lib import camelCase - -def parser(stdout, stderr): - output = {} - moduleName = None - if stdout: - for line in stdout.splitlines(): - values = re.search(r'^([^:]+):\s+(.*)$', line) - if not values: - continue - - key = values.group(1) - value = values.group(2) - - if key == 'moduleName': - moduleName = value - output[moduleName] = {} - - if moduleName: - output[moduleName][key] = value.strip() - - - return {'output': output} - -def register(main): - main['modinfo'] = { - 'cmd': """lsmod | grep -v "Module" | sed 's/ .*//g' | xargs -I {} -n 1 sh -c "echo 'moduleName: {}'; modinfo {}" """, - 'description': 'Information about a Linux Kernel modules', - 'parser': parser - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + moduleName = None + unprocessed = [] + + if stdout: + stdout_fix = re.sub(r"\n[\t]+", " ", stdout) + + for line in stdout_fix.splitlines(): + kv = re.search(r"^([^:]+):\s+(.*)$", line) + if kv: + key = kv.group(1) + value = kv.group(2) + + if key == ">>> moduleName": + moduleName = value + output[moduleName] = {} + continue + + if moduleName: + key = camelCase(key, to_camelcase) + output[moduleName][key] = value.strip() + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["modinfo"] = { + "cmd": """lsmod | grep -v "Module" | sed 's/ .*//g' | xargs -I {} -n 1 sh -c "echo '>>> moduleName: {}'; modinfo {}" """, + "description": "Information about a Linux Kernel modules", + "parser": parser, + } diff --git a/modules/parted.py b/modules/parted.py index 477bd88..4974976 100644 --- a/modules/parted.py +++ b/modules/parted.py @@ -1,52 +1,60 @@ - -import re - -def parser(stdout, stderr): - output = {} - defaultUnit = None - path = None - if stdout: - for line in stdout.splitlines(): - if line.strip() == '': - defaultUnit = None - path = None - - unitSearch = re.search(r'^(\S+);$', line) - if unitSearch: - defaultUnit = unitSearch.group(1) - - lineSplit = (line.strip(';') + (':' * 10)).split(':') - - if defaultUnit and re.search(r'^(\/[^:]+)', line): - path = lineSplit[0] - output[path] = { - 'path': lineSplit[0], - 'defaultUnit': defaultUnit, - 'end': lineSplit[1], - 'devType': lineSplit[2], - 'sectorSize': lineSplit[3], - 'physSectorSize': lineSplit[4], - 'ptName': lineSplit[5], - 'model': lineSplit[6], - 'diskFlags': lineSplit[7], - 'table': {} - } - - if path and re.search(r'^(\d+):', line): - output[path]['table'][lineSplit[0]] = { - 'start': lineSplit[1], - 'end': lineSplit[2], - 'size': lineSplit[3], - 'fileSystem': lineSplit[4], - 'flags': lineSplit[5] - } - - return {'output': output} - -def register(main): - main['parted'] = { - 'cmd': 'parted -m -l print', - 'description': 'Lists partition layout on all block devices', - 'parser': parser - } - \ No newline at end of file +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + defaultUnit = None + path = None + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + if line.strip() == "": + defaultUnit = None + path = None + continue + + unitSearch = re.search(r"^(\S+);$", line) + if unitSearch: + defaultUnit = unitSearch.group(1) + continue + + lineSplit = (line.strip(";") + (":" * 10)).split(":") + + if defaultUnit and re.search(r"^(\/[^:]+)", line): + path = lineSplit[0] + output[path] = { + "path": lineSplit[0], + "defaultUnit": defaultUnit, + "end": lineSplit[1], + "devType": lineSplit[2], + "sectorSize": lineSplit[3], + "physSectorSize": lineSplit[4], + "ptName": lineSplit[5], + "model": lineSplit[6], + "diskFlags": lineSplit[7], + "table": {}, + } + continue + + if path and re.search(r"^(\d+):", line): + output[path]["table"][lineSplit[0]] = { + "start": lineSplit[1], + "end": lineSplit[2], + "size": lineSplit[3], + "fileSystem": lineSplit[4], + "flags": lineSplit[5], + } + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["parted"] = { + "cmd": "parted -m -l print", + "description": "Lists partition layout on all block devices", + "parser": parser, + } diff --git a/modules/proc_buddyinfo.py b/modules/proc_buddyinfo.py new file mode 100644 index 0000000..fdf47ad --- /dev/null +++ b/modules/proc_buddyinfo.py @@ -0,0 +1,33 @@ +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {"nodes": {}} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + row = re.search(r"Node\s([^,]+),\szone\s+(\S+)\s*(.*)$", line) + if row: + node = row.group(1) + zone = row.group(2) + value = re.split(r"\s+", row.group(3).strip()) + + if not node in output["nodes"]: + output["nodes"][node] = {} + + output["nodes"][node][zone] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_buddyinfo"] = { + "cmd": "cat /proc/buddyinfo", + "description": "Memory fragmentation", + "parser": parser, + } diff --git a/modules/proc_bus_input.py b/modules/proc_bus_input.py new file mode 100644 index 0000000..692aee8 --- /dev/null +++ b/modules/proc_bus_input.py @@ -0,0 +1,82 @@ +import re +from sysinfo_lib import camelCase + + +def extract_params(entry, params, to_camelcase): + patterns = [ + r"(\S[^=]+)=(\S+)", + r'(\S[^=]+)=\"([^"]*)\"', + r"(\S[^=]+)=(\s|$)", + ] + + for pattern in patterns: + kv = re.findall(pattern, params) + if kv: + for pair in kv: + key = camelCase(pair[0], to_camelcase) + value = pair[1] + entry[key] = value + + +def parser(stdout, stderr, to_camelcase): + output = {"devices": [], "handlers": {}} + unprocessed = [] + types = { + "I": "deviceId", + "N": "name", + "P": "physicalPath", + "S": "sysfsPath", + "U": "uid", + "H": "inputHandlers", + "B": "bitmaps", + } + + if stdout: + [devices, handlers] = stdout.split(">>> handlers") + + print(devices) + + for block in re.split(r"\r\r|\n\n|\r\n\r\n", devices): + blockData = {} + + for line in block.splitlines(): + parts = re.search(r"^(\w):\s+(.*)$", line) + if parts: + type = parts.group(1).strip() + params = parts.group(2).strip() + + if type in types: + type_label = types[type] + if not type_label in blockData: + blockData[type_label] = {} + + extract_params(blockData[type_label], params, to_camelcase) + + output["devices"].append(blockData) + + for line in handlers.splitlines(): + line = re.sub(r"^N: ", "", line) + + kv = re.findall(r"(\S[^=]+)=(\S+)", line) + if kv: + entry = {} + for pair in kv: + key = camelCase(pair[0], to_camelcase) + value = pair[1] + entry[key] = value + + if "name" in entry: + output["handlers"][entry["name"]] = entry + + if "Name" in entry: + output["handlers"][entry["Name"]] = entry + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_bus_input"] = { + "cmd": 'cat /proc/bus/input/devices; echo ">>> handlers"; cat /proc/bus/input/handlers;', + "description": "Input devices", + "parser": parser, + } diff --git a/modules/proc_cgroups.py b/modules/proc_cgroups.py new file mode 100644 index 0000000..8d8430e --- /dev/null +++ b/modules/proc_cgroups.py @@ -0,0 +1,24 @@ +from sysinfo_lib import parseSpaceTable, tableToDict + + +def parser(stdout, stderr, to_camelcase): + output = {} + + if stdout: + stdout = stdout.replace("#subsys_name", "subsys_name") + + output = parseSpaceTable(stdout, to_camelcase=to_camelcase) + if to_camelcase: + output = tableToDict(output, "subsysName") + else: + output = tableToDict(output, "subsys_name") + + return {"output": output, "unprocessed": []} + + +def register(main): + main["proc_cgroups"] = { + "cmd": "cat /proc/cgroups", + "description": "Control groups", + "parser": parser, + } diff --git a/modules/proc_cmdline.py b/modules/proc_cmdline.py index e248f95..c2a699b 100644 --- a/modules/proc_cmdline.py +++ b/modules/proc_cmdline.py @@ -1,30 +1,36 @@ - -import re - -def parser(stdout, stderr): - output = {} - if stdout: - for kv in re.split(r'[\s\t]+', stdout.strip()): - splitted = re.search(r'^([^=]+)=(.*)$', kv) - if splitted: - key = splitted.group(1) - value = splitted.group(2) - else: - key = kv - value = '' - if key in output: - if isinstance(output[key], str): - output[key] = [output[key]] - - output[key].append(value) - else: - output[key] = value - - return {'output': output} - -def register(main): - main['proc_cmdline'] = { - 'cmd': 'cat /proc/cmdline', - 'description': 'Parameters passed to the kernel at the time it is started', - 'parser': parser - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + + if stdout: + for kv in re.split(r"[\s\t]+", stdout.strip()): + splitted = re.search(r"^([^=]+)=(.*)$", kv) + if splitted: + key = camelCase(splitted.group(1), to_camelcase) + value = splitted.group(2) + + else: + key = kv + value = "" + + if key in output: + if isinstance(output[key], str): + output[key] = [output[key]] + + output[key].append(value) + + else: + output[key] = value + + return {"output": output, "unprocessed": []} + + +def register(main): + main["proc_cmdline"] = { + "cmd": "cat /proc/cmdline", + "description": "Parameters passed to the kernel at the time it is started", + "parser": parser, + } diff --git a/modules/proc_consoles.py b/modules/proc_consoles.py index dbd0434..8a8b0ec 100644 --- a/modules/proc_consoles.py +++ b/modules/proc_consoles.py @@ -1,52 +1,58 @@ - -import re - -def parser(stdout, stderr): - """ - The columns are: - device name of the device - operations R = can do read operations - W = can do write operations - U = can do unblank - flags E = it is enabled - C = it is preferred console - B = it is primary boot console - p = it is used for printk buffer - b = it is not a TTY but a Braille device - a = it is safe to use when cpu is offline - major:minor major and minor number of the device separated by a colon - """ - - output = {} - if stdout: - for line in stdout.splitlines(): - values = re.search(r'^(\S+)\s+(.*)\s+(\S+):(\S+)', line) - if values: - params = values.group(2).strip() - output[values.group(1)] = { - 'device': values.group(1), - 'operations': { - 'read': 'R' in params, - 'write': 'W' in params, - 'unblank': 'U' in params, - }, - 'flags': { - 'enabled': 'E' in params, - 'preferred': 'C' in params, - 'primaryBoot': 'B' in params, - 'printkBuffer': 'p' in params, - 'braile': 'b' in params, - 'safeCpuOffline': 'a' in params, - }, - 'major': values.group(3), - 'minor': values.group(4) - } - - return {'output': output} - -def register(main): - main['proc_consoles'] = { - 'cmd': 'cat /proc/consoles', - 'description': 'Information about current consoles including tty', - 'parser': parser - } +import re + + +def parser(stdout, stderr, to_camelcase): + """ + The columns are: + device name of the device + operations R = can do read operations + W = can do write operations + U = can do unblank + flags E = it is enabled + C = it is preferred console + B = it is primary boot console + p = it is used for printk buffer + b = it is not a TTY but a Braille device + a = it is safe to use when cpu is offline + major:minor major and minor number of the device separated by a colon + """ + + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + values = re.search(r"^(\S+)\s+(.*)\s+(\S+):(\S+)", line) + if values: + params = values.group(2).strip() + output[values.group(1)] = { + "device": values.group(1), + "operations": { + "read": "R" in params, + "write": "W" in params, + "unblank": "U" in params, + }, + "flags": { + "enabled": "E" in params, + "preferred": "C" in params, + "primaryBoot": "B" in params, + "printkBuffer": "p" in params, + "braile": "b" in params, + "safeCpuOffline": "a" in params, + }, + "major": values.group(3), + "minor": values.group(4), + } + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_consoles"] = { + "cmd": "cat /proc/consoles", + "description": "Information about current consoles including tty", + "parser": parser, + } diff --git a/modules/proc_cpuinfo.py b/modules/proc_cpuinfo.py index 1b8e920..c97ba77 100644 --- a/modules/proc_cpuinfo.py +++ b/modules/proc_cpuinfo.py @@ -1,36 +1,40 @@ - -import re -from sysinfo_lib import camelCase - -def parser(stdout, stderr): - output = { - 'processor': {}, - 'hardware': {}, - 'oth': {} - } - - if stdout: - for block in re.split(r'\r\r|\n\n|\r\n\r\n', stdout): - sub = {} - for line in block.splitlines(): - values = re.search(r'([^\t]+)\s*:\s*(.*)$', line) - if values: - sub[camelCase(values.group(1).strip())] = values.group(2).strip() - - if 'processor' in sub: - output['processor'][sub['processor']] = sub - - elif 'hardware' in sub: - output['hardware'] = sub - - else: - output['oth'] = sub - - return {'output': output} - -def register(main): - main['proc_cpuinfo'] = { - 'cmd': 'cat /proc/cpuinfo', - 'description': 'Type of processor used by your system', - 'parser': parser - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {"processor": {}, "hardware": {}, "oth": {}} + unprocessed = [] + + if stdout: + for block in re.split(r"\r\r|\n\n|\r\n\r\n", stdout): + sub = {} + for line in block.splitlines(): + kv = re.search(r"([^\t]+)\s*:\s*(.*)$", line) + if kv: + key = camelCase(kv.group(1).strip(), to_camelcase) + value = kv.group(2).strip() + + sub[key] = value + continue + + unprocessed.append(line) + + if "processor" in sub: + output["processor"][sub["processor"]] = sub + + elif "hardware" in sub: + output["hardware"] = sub + + else: + output["oth"] = sub + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_cpuinfo"] = { + "cmd": "cat /proc/cpuinfo", + "description": "Type of processor used by your system", + "parser": parser, + } diff --git a/modules/proc_crypto.py b/modules/proc_crypto.py index 442f82c..6d27263 100644 --- a/modules/proc_crypto.py +++ b/modules/proc_crypto.py @@ -1,25 +1,34 @@ - -import re -from sysinfo_lib import camelCase - -def parser(stdout, stderr): - output = {} - if stdout: - for block in re.split(r'\r\r|\n\n|\r\n\r\n', stdout): - sub = {} - for line in block.splitlines(): - values = re.search(r'([^\t]+)\s*:\s*(.*)$', line) - if values: - sub[camelCase(values.group(1).strip())] = values.group(2).strip() - - if 'name' in sub: - output[sub['name']] = sub - - return {'output': output} - -def register(main): - main['proc_crypto'] = { - 'cmd': 'cat /proc/crypto', - 'description': 'Installed cryptographic ciphers used by the Linux kernel', - 'parser': parser - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for block in re.split(r"\r\r|\n\n|\r\n\r\n", stdout): + sub = {} + for line in block.splitlines(): + kv = re.search(r"([^\t]+)\s*:\s*(.*)$", line) + if kv: + key = camelCase(kv.group(1).strip(), to_camelcase) + value = kv.group(2).strip() + + sub[key] = value + continue + + unprocessed.append(line) + + if "name" in sub: + output[sub["name"]] = sub + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_crypto"] = { + "cmd": "cat /proc/crypto", + "description": "Installed cryptographic ciphers used by the Linux kernel", + "parser": parser, + } diff --git a/modules/proc_devices.py b/modules/proc_devices.py index 7d11094..b65e691 100644 --- a/modules/proc_devices.py +++ b/modules/proc_devices.py @@ -1,31 +1,39 @@ - -import re -from sysinfo_lib import camelCase - -def parser(stdout, stderr): - output = {} - deviceType = None - if stdout: - for line in stdout.splitlines(): - dt = re.search(r'^([^:]+):', line) - if dt: - deviceType = camelCase(dt.group(1)) - output[deviceType] = {} - - dv = re.search(r'^\s*(\d+)\s*(.*)$', line) - if dv and deviceType: - id = dv.group(1) - name = dv.group(2) - if not name in output[deviceType]: - output[deviceType][name] = [] - - output[deviceType][name].append(id) - - return {'output': output} - -def register(main): - main['proc_devices'] = { - 'cmd': 'cat /proc/devices', - 'description': 'Installed cryptographic ciphers used by the Linux kernel', - 'parser': parser - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + deviceType = None + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + dt = re.search(r"^([^:]+):", line) + if dt: + deviceType = camelCase(dt.group(1), to_camelcase) + output[deviceType] = {} + continue + + dv = re.search(r"^\s*(\d+)\s*(.*)$", line) + if dv and deviceType: + id = dv.group(1) + name = dv.group(2) + + if not name in output[deviceType]: + output[deviceType][name] = [] + + output[deviceType][name].append(id) + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_devices"] = { + "cmd": "cat /proc/devices", + "description": "Installed cryptographic ciphers used by the Linux kernel", + "parser": parser, + } diff --git a/modules/proc_diskstats.py b/modules/proc_diskstats.py index d3d29cd..9374451 100644 --- a/modules/proc_diskstats.py +++ b/modules/proc_diskstats.py @@ -1,44 +1,47 @@ - -import re -from sysinfo_lib import camelCase - -def parser(stdout, stderr): - output = {} - columnNames = [ - 'majorNumber', - 'minorNumber', - 'deviceName', - 'readsCompletedSuccessfully', - 'readsMerged', - 'sectorsRead', - 'timeSpentReading', - 'writesCompleted', - 'writesMerged', - 'sectorsWritten', - 'timeSpentWriting', - 'IOsCurrentlyInProgress', - 'timeSpentDoingIOs', - 'weightedTimeSpentDoingIOs' - ] - lenColumnNames = len(columnNames) - - if stdout: - for line in stdout.splitlines(): - line = line.strip() - columns = re.split(r'\s+', line) - if not columns: - continue - - output[columns[2]] = {} - for num, val in enumerate(columns, start=0): - if num < lenColumnNames: - output[columns[2]][columnNames[num]] = val - - return {'output': output} - -def register(main): - main['proc_diskstats'] = { - 'cmd': 'cat /proc/diskstats', - 'description': 'I/O statistics of block devices', - 'parser': parser - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + columnNames = [ + "majorNumber", + "minorNumber", + "deviceName", + "readsCompletedSuccessfully", + "readsMerged", + "sectorsRead", + "timeSpentReading", + "writesCompleted", + "writesMerged", + "sectorsWritten", + "timeSpentWriting", + "IOsCurrentlyInProgress", + "timeSpentDoingIOs", + "weightedTimeSpentDoingIOs", + ] + lenColumnNames = len(columnNames) + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + line = line.strip() + columns = re.split(r"\s+", line) + if columns: + output[columns[2]] = {} + for num, val in enumerate(columns, start=0): + if num < lenColumnNames: + output[columns[2]][columnNames[num]] = val + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_diskstats"] = { + "cmd": "cat /proc/diskstats", + "description": "I/O statistics of block devices", + "parser": parser, + } diff --git a/modules/proc_dma.py b/modules/proc_dma.py index da73728..85f95ff 100644 --- a/modules/proc_dma.py +++ b/modules/proc_dma.py @@ -1,19 +1,28 @@ - -import re - -def parser(stdout, stderr): - output = {} - if stdout: - for line in stdout.splitlines(): - keyValueSearch = re.search(r'^\s*([^:]+):\s*(.*)$', line) - if keyValueSearch: - output[keyValueSearch.group(1)] = keyValueSearch.group(2).strip() - - return {'output': output} - -def register(main): - main['proc_dma'] = { - 'cmd': 'cat /proc/dma', - 'description': 'List of the registered ISA DMA channels in use', - 'parser': parser - } \ No newline at end of file +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + kv = re.search(r"^\s*([^:]+):\s*(.*)$", line) + if kv: + key = kv.group(1).strip() + value = kv.group(2).strip() + + output[key] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_dma"] = { + "cmd": "cat /proc/dma", + "description": "List of the registered ISA DMA channels in use", + "parser": parser, + } diff --git a/modules/proc_filesystems.py b/modules/proc_filesystems.py index 6a2d22f..11d5903 100644 --- a/modules/proc_filesystems.py +++ b/modules/proc_filesystems.py @@ -1,23 +1,33 @@ - -import re - -def parser(stdout, stderr): - output = {} - if stdout: - for line in stdout.splitlines(): - lineMatch = re.search(r'^(\S+)\s+(\S+)', line) - if lineMatch: - output[lineMatch.group(2).strip()] = lineMatch.group(1).strip() - - lineMatch = re.search(r'^\s+(\S+)$', line) - if lineMatch: - output[lineMatch.group(1).strip()] = '' - - return {'output': output} - -def register(main): - main['proc_filesystems'] = { - 'cmd': 'cat /proc/filesystems', - 'description': 'List of the file system types currently supported by the kernel', - 'parser': parser - } \ No newline at end of file +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + kv = re.search(r"^(\S+)\s+(\S+)", line) + if kv: + key = kv.group(2).strip() + value = kv.group(1).strip() + + output[key] = value + continue + + k = re.search(r"^\s+(\S+)$", line) + if k: + output[k.group(1).strip()] = "" + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_filesystems"] = { + "cmd": "cat /proc/filesystems", + "description": "List of the file system types currently supported by the kernel", + "parser": parser, + } diff --git a/modules/proc_fs.py b/modules/proc_fs.py index 2c38911..c06a1d1 100644 --- a/modules/proc_fs.py +++ b/modules/proc_fs.py @@ -1,39 +1,56 @@ - -import re - -def setPathValue(data, path, value): - pathRest = None - pathParts = re.search(r'^([^\/]+)\/?(.*)$', path) - if pathParts: - path = pathParts.group(1) - pathRest = pathParts.group(2) - - if not path in data: - data[path] = {} - - if pathRest: - setPathValue(data[path], pathRest, value) - else: - if isinstance(data[path], dict): - data[path] = [] - data[path].append(value) - -def parser(stdout, stderr): - output = {} - if stdout: - for line in stdout.splitlines(): - pathValue = re.search(r'^\/proc\/fs\/([^:]+):(.*)$', line) - if pathValue: - path = pathValue.group(1) - value = pathValue.group(2) - if not re.search(r'^\s*#', value): - setPathValue(output, path, value) - - return {'output': output} - -def register(main): - main['proc_fs'] = { - 'cmd': 'find /proc/fs -type f -follow -print | xargs grep ""', - 'description': 'File system parameters', - 'parser': parser - } +import re +from sysinfo_lib import camelCase + + +def setPathValue(data, path, value): + pathRest = None + pathParts = re.search(r"^([^\/]+)\/?(.*)$", path) + if pathParts: + path = camelCase(pathParts.group(1)) + pathRest = pathParts.group(2) + + if not path in data: + data[path] = {} + + if pathRest: + setPathValue(data[path], pathRest, value) + + else: + path = camelCase(path) + if isinstance(data[path], dict): + data[path] = [] + + data[path].append(value) + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + pathValue = re.search(r"^\/proc\/fs\/([^:]+):(.*)$", line) + if pathValue: + path = pathValue.group(1) + value = pathValue.group(2) + + print(path, value) + # if not re.search(r"^\s*#", value): + # setPathValue(output, path, value) + + # continue + + # else: + # print(line) + + # unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_fs"] = { + "cmd": """find /proc/fs -type f -follow -print | xargs grep "" """, + "description": "File system parameters", + "parser": parser, + } diff --git a/modules/proc_iomem.py b/modules/proc_iomem.py index 9781a58..6edfdfe 100644 --- a/modules/proc_iomem.py +++ b/modules/proc_iomem.py @@ -1,23 +1,31 @@ - -import re - -def parser(stdout, stderr): - output = [] - if stdout: - for line in stdout.splitlines(): - values = re.search(r'^\s*([^-]+)-(\S+)\s*:\s*(.*)$', line) - if values: - output.append({ - 'from': values.group(1), - 'to': values.group(2), - 'device': values.group(3) - }) - - return {'output': output} - -def register(main): - main['proc_iomem'] = { - 'cmd': 'cat /proc/iomem', - 'description': """Map of the system's memory for each physical device""", - 'parser': parser - } \ No newline at end of file +import re + + +def parser(stdout, stderr, to_camelcase): + output = [] + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + values = re.search(r"^\s*([^-]+)-(\S+)\s*:\s*(.*)$", line) + if values: + output.append( + { + "from": values.group(1), + "to": values.group(2), + "device": values.group(3), + } + ) + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_iomem"] = { + "cmd": "cat /proc/iomem", + "description": """Map of the system's memory for each physical device""", + "parser": parser, + } diff --git a/modules/proc_ioports.py b/modules/proc_ioports.py index 5d02a71..580993c 100644 --- a/modules/proc_ioports.py +++ b/modules/proc_ioports.py @@ -1,23 +1,33 @@ - -import re - -def parser(stdout, stderr): - output = [] - if stdout: - for line in stdout.splitlines(): - entrySearch = re.search(r'^\s*([^-]+)-(\S+)\s*:\s*(.*)$', line, re.IGNORECASE) - if entrySearch: - output.append({ - 'from': entrySearch.group(1), - 'to': entrySearch.group(2), - 'device': entrySearch.group(3) - }) - - return {'output': output} - -def register(main): - main['proc_ioports'] = { - 'cmd': 'cat /proc/ioports', - 'description': 'List of currently registered port regions used for input or output communication with a device', - 'parser': parser - } +import re + + +def parser(stdout, stderr, to_camelcase): + output = [] + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + entrySearch = re.search( + r"^\s*([^-]+)-(\S+)\s*:\s*(.*)$", line, re.IGNORECASE + ) + if entrySearch: + output.append( + { + "from": entrySearch.group(1), + "to": entrySearch.group(2), + "device": entrySearch.group(3), + } + ) + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_ioports"] = { + "cmd": "cat /proc/ioports", + "description": "List of currently registered port regions used for input or output communication with a device", + "parser": parser, + } diff --git a/modules/proc_loadavg.py b/modules/proc_loadavg.py index 7f7929e..80bf8ce 100644 --- a/modules/proc_loadavg.py +++ b/modules/proc_loadavg.py @@ -1,24 +1,30 @@ - -import re - -def parser(stdout, stderr): - output = {} - if stdout: - values = re.search(r'^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)', stdout.strip()) - if values: - output = { - 'periodLast': values.group(1), - 'period5minute': values.group(2), - 'period15minute': values.group(3), - 'processes': values.group(4), - 'lastPid': values.group(5) - } - - return {'output': output} - -def register(main): - main['proc_loadavg'] = { - 'cmd': 'cat /proc/loadavg', - 'description': 'Load average in regard to both the CPU and IO over time', - 'parser': parser - } \ No newline at end of file +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + values = re.search(r"^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)", stdout.strip()) + if values: + output = { + "periodLast": values.group(1), + "period5minute": values.group(2), + "period15minute": values.group(3), + "processes": values.group(4), + "lastPid": values.group(5), + } + + else: + unprocessed.append(stdout) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_loadavg"] = { + "cmd": "cat /proc/loadavg", + "description": "Load average in regard to both the CPU and IO over time", + "parser": parser, + } diff --git a/modules/proc_locks.py b/modules/proc_locks.py index 82a8eb4..38d97e0 100644 --- a/modules/proc_locks.py +++ b/modules/proc_locks.py @@ -1,27 +1,33 @@ - -import re - -def parser(stdout, stderr): - output = {} - if stdout: - for line in stdout.splitlines(): - lineSplit = re.split(r'[\s\t]+', line) - if lineSplit and len(lineSplit) > 5: - output[lineSplit[0]] = { - 'uid': lineSplit[0], - 'class': lineSplit[1], - 'lockType': lineSplit[2], - 'allowAccessType': lineSplit[3], - 'pid': lineSplit[4], - 'fileID': lineSplit[5], - 'lockedRegion': lineSplit[6] - } - - return {'output': output} - -def register(main): - main['proc_locks'] = { - 'cmd': 'cat /proc/locks', - 'description': 'Files currently locked by the kernel', - 'parser': parser - } \ No newline at end of file +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + lineSplit = re.split(r"[\s\t]+", line) + if lineSplit and len(lineSplit) > 5: + output[lineSplit[0]] = { + "uid": lineSplit[0], + "class": lineSplit[1], + "lockType": lineSplit[2], + "allowAccessType": lineSplit[3], + "pid": lineSplit[4], + "fileID": lineSplit[5], + "lockedRegion": lineSplit[6], + } + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_locks"] = { + "cmd": "cat /proc/locks", + "description": "Files currently locked by the kernel", + "parser": parser, + } diff --git a/modules/proc_meminfo.py b/modules/proc_meminfo.py index f9bd14d..e71f48a 100644 --- a/modules/proc_meminfo.py +++ b/modules/proc_meminfo.py @@ -1,33 +1,37 @@ - -import re -from sysinfo_lib import camelCase - -def parser(stdout, stderr): - output = {} - if stdout: - for line in stdout.splitlines(): - keyValueSearch = re.search(r'^([^:]+):\s*(.*)$', line, re.IGNORECASE) - if keyValueSearch: - key = keyValueSearch.group(1).strip(':') - value = keyValueSearch.group(2).strip() - - valueSearch = re.search(r'(.*)\s+(.*)$', value) - if valueSearch: - output[camelCase(key)] = { - 'value': valueSearch.group(1), - 'type': valueSearch.group(2) - } - else: - output[camelCase(key)] = { - 'value': value, - 'type': '' - } - - return {'output': output} - -def register(main): - main['proc_meminfo'] = { - 'cmd': 'cat /proc/meminfo', - 'description': 'Reports a large amount of valuable information about the systems RAM usage', - 'parser': parser - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + kv = re.search(r"^([^:]+):\s*(.*)$", line, re.IGNORECASE) + if kv: + key = camelCase(kv.group(1).strip(":"), to_camelcase) + value = kv.group(2).strip() + + valueSearch = re.search(r"(.*)\s+(.*)$", value) + if valueSearch: + output[key] = { + "value": valueSearch.group(1), + "type": valueSearch.group(2), + } + else: + output[key] = {"value": value, "type": ""} + + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": []} + + +def register(main): + main["proc_meminfo"] = { + "cmd": "cat /proc/meminfo", + "description": "Reports a large amount of valuable information about the systems RAM usage", + "parser": parser, + } diff --git a/modules/proc_modules.py b/modules/proc_modules.py index 4c5e7ea..1fa121a 100644 --- a/modules/proc_modules.py +++ b/modules/proc_modules.py @@ -1,26 +1,32 @@ - -import re - -def parser(stdout, stderr): - output = {} - if stdout: - for line in stdout.splitlines(): - lineSplit = re.split(r'[\s\t]+', line) - if lineSplit and len(lineSplit) > 5: - output[lineSplit[0]] = { - 'moduleName': lineSplit[0], - 'moduleMemorySize': lineSplit[1], - 'numInstancesLoaded': lineSplit[2], - 'depends': lineSplit[3].strip(',').split(','), - 'state': lineSplit[4], - 'kernelMemoryOffset': lineSplit[5] - } - - return {'output': output} - -def register(main): - main['proc_modules'] = { - 'cmd': 'cat /proc/modules', - 'description': 'List of all modules loaded into the kernel', - 'parser': parser - } \ No newline at end of file +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + lineSplit = re.split(r"[\s\t]+", line) + if lineSplit and len(lineSplit) > 5: + output[lineSplit[0]] = { + "moduleName": lineSplit[0], + "moduleMemorySize": lineSplit[1], + "numInstancesLoaded": lineSplit[2], + "depends": lineSplit[3].strip(",").split(","), + "state": lineSplit[4], + "kernelMemoryOffset": lineSplit[5], + } + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_modules"] = { + "cmd": "cat /proc/modules", + "description": "List of all modules loaded into the kernel", + "parser": parser, + } diff --git a/modules/proc_mounts.py b/modules/proc_mounts.py index a67d195..dd46a25 100644 --- a/modules/proc_mounts.py +++ b/modules/proc_mounts.py @@ -1,29 +1,35 @@ - -import re - -def parser(stdout, stderr): - output = {} - if stdout: - for line in stdout.splitlines(): - lineSplit = re.split(r'[\s\t]+', line) - if lineSplit and len(lineSplit) > 4: - accessValues = {} - for access in re.split(r',', lineSplit[3]): - accessSplit = re.split(r'=', access + '=') - accessValues[accessSplit[0]] = accessSplit[1] - - output[lineSplit[1]] = { - 'device': lineSplit[0], - 'mountPoint': lineSplit[1], - 'type': lineSplit[2], - 'access': accessValues - } - - return {'output': output} - -def register(main): - main['proc_mounts'] = { - 'cmd': 'cat /proc/mounts', - 'description': 'List mounted filesystems (info provides from kernel)', - 'parser': parser - } \ No newline at end of file +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + lineSplit = re.split(r"[\s\t]+", line) + if lineSplit and len(lineSplit) > 4: + accessValues = {} + for access in re.split(r",", lineSplit[3]): + accessSplit = re.split(r"=", access + "=") + accessValues[accessSplit[0]] = accessSplit[1] + + output[lineSplit[1]] = { + "device": lineSplit[0], + "mountPoint": lineSplit[1], + "type": lineSplit[2], + "access": accessValues, + } + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_mounts"] = { + "cmd": "cat /proc/mounts", + "description": "List mounted filesystems (info provides from kernel)", + "parser": parser, + } diff --git a/modules/proc_net.py b/modules/proc_net.py new file mode 100644 index 0000000..9ed3f67 --- /dev/null +++ b/modules/proc_net.py @@ -0,0 +1,146 @@ +import struct +import socket +from sysinfo_lib import parseSpaceTable, tableToDict + + +def parser_route(stdout, stderr, to_camelcase): + output = {} + + if stdout: + output = parseSpaceTable(stdout, to_camelcase=to_camelcase) + if to_camelcase: + output = tableToDict(output, "iface") + else: + output = tableToDict(output, "Iface") + + return {"output": output, "unprocessed": []} + + +def split_every_n(data, n): + return [data[i : i + n] for i in range(0, len(data), n)] + + +def parse_ipv4_address(address): + hex_addr, hex_port = address.split(":") + + addr_list = split_every_n(hex_addr, 2) + addr_list.reverse() + addr = ".".join(map(lambda x: str(int(x, 16)), addr_list)) + port = str(int(hex_port, 16)) + + return addr, port + + +def parse_ipv6_address(address): + hex_addr, hex_port = address.split(":") + + addr = bytes.fromhex(hex_addr) + addr = struct.unpack(">IIII", addr) + addr = struct.pack("@IIII", *addr) + addr = socket.inet_ntop(socket.AF_INET6, addr) + port = str(int(hex_port, 16)) + + return addr, port + + +def extend_address4(entry, name, name_addr, name_port): + if name in entry: + address, port = parse_ipv4_address(entry[name]) + entry[name_addr] = address + entry[name_port] = port + + +def extend_address6(entry, name, name_addr, name_port): + if name in entry: + address, port = parse_ipv6_address(entry[name]) + entry[name_addr] = address + entry[name_port] = port + + +def parser_tcp_udp(stdout, stderr, to_camelcase): + output = {} + + if stdout: + output = parseSpaceTable(stdout, to_camelcase=to_camelcase) + + for entry in output: + extend_address4(entry, "local_address", "local_addr", "local_port") + extend_address4(entry, "rem_address", "rem_addr", "rem_port") + extend_address4(entry, "localAddress", "localAddr", "localPort") + extend_address4(entry, "remAddress", "remAddr", "remPort") + + return {"output": output, "unprocessed": []} + + +def parser_tcp_udp_6(stdout, stderr, to_camelcase): + output = {} + + if stdout: + output = parseSpaceTable(stdout, to_camelcase=to_camelcase) + + for entry in output: + extend_address6(entry, "local_address", "local_addr", "local_port") + extend_address6(entry, "rem_address", "rem_addr", "rem_port") + extend_address6(entry, "localAddress", "localAddr", "localPort") + extend_address6(entry, "remAddress", "remAddr", "remPort") + + return {"output": output, "unprocessed": []} + + +def parser_arp(stdout, stderr, to_camelcase): + output = {} + + if stdout: + output = parseSpaceTable(stdout, to_camelcase=to_camelcase) + + return {"output": output, "unprocessed": []} + + +def register(main): + main["proc_net_route"] = { + "cmd": "cat /proc/net/route", + "description": "IP routing information", + "parser": parser_route, + } + + main["proc_net_ax25_route"] = { + "cmd": "cat /proc/net/ax25_route", + "description": "AX25 routing information", + "parser": parser_route, + } + + main["proc_net_ipx_route"] = { + "cmd": "cat /proc/net/ipx_route", + "description": "IPX routing information", + "parser": parser_route, + } + + main["proc_net_tcp"] = { + "cmd": "cat /proc/net/tcp", + "description": "TCP socket table", + "parser": parser_tcp_udp, + } + + main["proc_net_udp"] = { + "cmd": "cat /proc/net/udp", + "description": "UDP socket table", + "parser": parser_tcp_udp, + } + + main["proc_net_tcp6"] = { + "cmd": "cat /proc/net/tcp6", + "description": "TCP6 socket table", + "parser": parser_tcp_udp_6, + } + + main["proc_net_udp6"] = { + "cmd": "cat /proc/net/udp6", + "description": "UDP6 socket table", + "parser": parser_tcp_udp_6, + } + + main["proc_net_arp"] = { + "cmd": "cat /proc/net/arp", + "description": "ARP ", + "parser": parser_arp, + } diff --git a/modules/proc_partitions.py b/modules/proc_partitions.py index 1a28ee9..14d021e 100644 --- a/modules/proc_partitions.py +++ b/modules/proc_partitions.py @@ -1,17 +1,19 @@ - -from sysinfo_lib import parseSpaceTable, tableToDict - -def parser(stdout, stderr): - output = {} - if stdout: - output = parseSpaceTable(stdout) - output = tableToDict(output, 'name') - - return {'output': output} - -def register(main): - main['proc_partitions'] = { - 'cmd': 'cat /proc/partitions', - 'description': 'Partition block allocation information', - 'parser': parser - } \ No newline at end of file +from sysinfo_lib import parseSpaceTable, tableToDict + + +def parser(stdout, stderr, to_camelcase): + output = {} + + if stdout: + output = parseSpaceTable(stdout, to_camelcase=to_camelcase) + output = tableToDict(output, "name") + + return {"output": output, "unprocessed": []} + + +def register(main): + main["proc_partitions"] = { + "cmd": "cat /proc/partitions", + "description": "Partition block allocation information", + "parser": parser, + } diff --git a/modules/proc_scsi.py b/modules/proc_scsi.py index a77bdbb..3b0c0f6 100644 --- a/modules/proc_scsi.py +++ b/modules/proc_scsi.py @@ -1,42 +1,60 @@ - -import re - -def parser(stdout, stderr): - output = {} - path = None - if stdout: - for line in stdout.splitlines(): - hostSearch = re.search(r'^Host:\s+(\S+)\s+Channel:\s+(\S+)\s+Id:\s+(\S+)\s+Lun:\s+(\S+)$', line, re.IGNORECASE) - if hostSearch: - host = hostSearch.group(1) - channel = hostSearch.group(2) - id = hostSearch.group(3) - lun = hostSearch.group(4) - path = '%s:%s:%s:%s' % (host.replace('scsi', ''), channel, id, lun) - output[path] = { - 'host': host, - 'channel': channel, - 'id': id, - 'lun': lun - } - - if path: - vendorSearch = re.search(r'^\s+Vendor:\s+(.*)\s+Model:\s+(.*)\s+Rev:\s+(.*)$', line, re.IGNORECASE) - if vendorSearch: - output[path]['vendor'] = vendorSearch.group(1).strip() - output[path]['model'] = vendorSearch.group(2).strip() - output[path]['rev'] = vendorSearch.group(3).strip() - - typeSearch = re.search(r'^\s+Type:\s+(.*)\s+ANSI\s+SCSI\s+revision:\s+(.*)$', line, re.IGNORECASE) - if typeSearch: - output[path]['type'] = typeSearch.group(1).strip() - output[path]['revision'] = typeSearch.group(2).strip() - - return {'output': output} - -def register(main): - main['proc_scsi'] = { - 'cmd': 'cat /proc/scsi/scsi', - 'description': 'List of every recognized SCSI device', - 'parser': parser - } +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + path = None + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + hostSearch = re.search( + r"^Host:\s+(\S+)\s+Channel:\s+(\S+)\s+Id:\s+(\S+)\s+Lun:\s+(\S+)$", + line, + re.IGNORECASE, + ) + if hostSearch: + host = hostSearch.group(1) + channel = hostSearch.group(2) + id = hostSearch.group(3) + lun = hostSearch.group(4) + path = "%s:%s:%s:%s" % (host.replace("scsi", ""), channel, id, lun) + output[path] = {"host": host, "channel": channel, "id": id, "lun": lun} + continue + + if path: + vendorSearch = re.search( + r"^\s+Vendor:\s+(.*)\s+Model:\s+(.*)\s+Rev:\s+(.*)$", + line, + re.IGNORECASE, + ) + if vendorSearch: + output[path]["vendor"] = vendorSearch.group(1).strip() + output[path]["model"] = vendorSearch.group(2).strip() + output[path]["rev"] = vendorSearch.group(3).strip() + continue + + typeSearch = re.search( + r"^\s+Type:\s+(.*)\s+ANSI\s+SCSI\s+revision:\s+(.*)$", + line, + re.IGNORECASE, + ) + if typeSearch: + output[path]["type"] = typeSearch.group(1).strip() + output[path]["revision"] = typeSearch.group(2).strip() + continue + + if re.match(r"Attached devices", line): + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_scsi"] = { + "cmd": "cat /proc/scsi/scsi", + "description": "List of every recognized SCSI device", + "parser": parser, + } diff --git a/modules/proc_slabinfo.py b/modules/proc_slabinfo.py new file mode 100644 index 0000000..17b8ed9 --- /dev/null +++ b/modules/proc_slabinfo.py @@ -0,0 +1,71 @@ +import re +from sysinfo_lib import camelCase + + +def extract_key_value(keys, data): + entry = {} + + if len(keys) == len(data): + for key_index, key in enumerate(keys): + entry[key] = data[key_index] + + return entry + + +def parser(stdout, stderr, to_camelcase): + output = {} + key_names = [] + has_keys = False + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + if re.match(r"^slabinfo - version", line): + continue + + header = re.search(r"^# name\s+(.*)$", line) + if header: + parts = header.group(1).strip().split(":") + for part in parts: + part = part.strip() + part = re.sub(r"(tunables|slabdata)\s+", "", part) + part = part.replace("<", "").replace(">", "") + part_columns = re.split(r"\s+", part) + part_columns = [ + camelCase(key, to_camelcase) for key in part_columns + ] + + key_names.append(part_columns) + + has_keys = True + continue + + row = re.search(r"^(\S+)\s+(.*)\s:\stunables(.*)\s:\sslabdata(.*)$", line) + if has_keys and row: + name = row.group(1) + statistics_data = re.split(r"\s+", row.group(2).strip()) + tunables_data = re.split(r"\s+", row.group(3).strip()) + slabdata_data = re.split(r"\s+", row.group(4).strip()) + + statistics = extract_key_value(key_names[0], statistics_data) + tunables = extract_key_value(key_names[1], tunables_data) + slabdata = extract_key_value(key_names[2], slabdata_data) + + output[name] = { + "statistics": statistics, + "tunables": tunables, + "slabdata": slabdata, + } + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_slabinfo"] = { + "cmd": "cat /proc/slabinfo", + "description": "Kernel caches informations", + "parser": parser, + } diff --git a/modules/proc_stat.py b/modules/proc_stat.py new file mode 100644 index 0000000..b6dd55b --- /dev/null +++ b/modules/proc_stat.py @@ -0,0 +1,38 @@ +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + + if stdout: + for line in stdout.splitlines(): + parts = re.split(r"\s+", line) + key = parts.pop(0) + + if re.match(r"^cpu", key) and len(parts) == 10: + output[key] = { + "user": parts[0], + "nice": parts[1], + "system": parts[2], + "idle": parts[3], + "iowait": parts[4], + "irq": parts[5], + "softirq": parts[6], + "steal": parts[7], + "guest": parts[8], + "guest_nice": parts[9], + } + continue + + output[key] = " ".join(parts) + + return {"output": output, "unprocessed": []} + + +def register(main): + main["proc_stat"] = { + "cmd": "cat /proc/stat", + "description": "Kernel/system statistics", + "parser": parser, + } diff --git a/modules/proc_swaps.py b/modules/proc_swaps.py index 8726e37..dcddab5 100644 --- a/modules/proc_swaps.py +++ b/modules/proc_swaps.py @@ -1,16 +1,18 @@ - -from sysinfo_lib import parseSpaceTable - -def parser(stdout, stderr): - output = {} - if stdout: - output = parseSpaceTable(stdout) - - return {'output': output} - -def register(main): - main['proc_swaps'] = { - 'cmd': 'cat /proc/swaps', - 'description': 'Measures swap space and its utilization', - 'parser': parser - } \ No newline at end of file +from sysinfo_lib import parseSpaceTable + + +def parser(stdout, stderr, to_camelcase): + output = {} + + if stdout: + output = parseSpaceTable(stdout, to_camelcase=to_camelcase) + + return {"output": output, "unprocessed": []} + + +def register(main): + main["proc_swaps"] = { + "cmd": "cat /proc/swaps", + "description": "Measures swap space and its utilization", + "parser": parser, + } diff --git a/modules/proc_sys.py b/modules/proc_sys.py index 33944a3..feceaf9 100644 --- a/modules/proc_sys.py +++ b/modules/proc_sys.py @@ -1,39 +1,48 @@ - -import re - -def setPathValue(data, path, value): - pathRest = None - pathParts = re.search(r'^([^\/]+)\/?(.*)$', path) - if pathParts: - path = pathParts.group(1) - pathRest = pathParts.group(2) - - if not path in data: - data[path] = {} - - if pathRest: - setPathValue(data[path], pathRest, value) - else: - data[path] = value - -def parser(stdout, stderr): - output = {} - if stdout: - for line in stdout.splitlines(): - pathValue = re.search(r'^\/proc\/sys\/([^:]+):(.*)$', line) - if pathValue: - path = pathValue.group(1) - value = pathValue.group(2) - if value.strip() == '': - continue - if not re.search(r'^\s*#', value): - setPathValue(output, path, value) - - return {'output': output} - -def register(main): - main['proc_sys'] = { - 'cmd': """find /proc/sys -type f -follow -print 2>/dev/null | xargs -n 1 -I {} sh -c 'VAL=$(cat {} 2>/dev/null); echo {}:$VAL;'""", - 'description': 'Information about the system and kernel features', - 'parser': parser - } \ No newline at end of file +import re +from sysinfo_lib import camelCase + + +def setPathValue(data, path, value, to_camelcase): + pathRest = None + pathParts = re.search(r"^([^\/]+)\/?(.*)$", path) + if pathParts: + path = camelCase(pathParts.group(1), to_camelcase) + pathRest = pathParts.group(2) + + else: + path = camelCase(path) + + if not path in data: + data[path] = {} + + if pathRest: + setPathValue(data[path], pathRest, value, to_camelcase) + else: + key = camelCase(path, to_camelcase) + data[key] = value + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + pathValue = re.search(r"^\/proc\/sys\/([^:]+):(.*)$", line) + if pathValue: + path = pathValue.group(1) + value = pathValue.group(2) + setPathValue(output, path, value, to_camelcase) + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_sys"] = { + "cmd": """find /proc/sys -type f -follow -print 2>/dev/null | xargs -n 1 -I {} sh -c 'VAL=$(cat {} 2>/dev/null); echo {}:$VAL;'""", + "description": "Information about the system and kernel features", + "parser": parser, + } diff --git a/modules/proc_uptime.py b/modules/proc_uptime.py index 76eff29..f04aaaf 100644 --- a/modules/proc_uptime.py +++ b/modules/proc_uptime.py @@ -1,20 +1,23 @@ -import re - -def parser(stdout, stderr): - output = {} - if stdout: - splitted = re.split(r'\s+', stdout.strip()) - if len(splitted) > 0: - output['systemUp'] = splitted[0] - - if len(splitted) > 1: - output['sumCoresIdle'] = splitted[1] - - return {'output': output} - -def register(main): - main['proc_uptime'] = { - 'cmd': 'cat /proc/uptime', - 'description': 'Information detailing how long the system has been on since its last restart', - 'parser': parser - } \ No newline at end of file +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + + if stdout: + splitted = re.split(r"\s+", stdout.strip()) + if len(splitted) > 0: + output["systemUp"] = splitted[0] + + if len(splitted) > 1: + output["sumCoresIdle"] = splitted[1] + + return {"output": output, "unprocessed": []} + + +def register(main): + main["proc_uptime"] = { + "cmd": "cat /proc/uptime", + "description": "Information detailing how long the system has been on since its last restart", + "parser": parser, + } diff --git a/modules/proc_version.py b/modules/proc_version.py index 174f919..2f2e2e3 100644 --- a/modules/proc_version.py +++ b/modules/proc_version.py @@ -1,14 +1,15 @@ - -def parser(stdout, stderr): - output = {} - if stdout: - output = stdout.strip() - - return {'output': output} - -def register(main): - main['proc_version'] = { - 'cmd': 'cat /proc/version', - 'description': 'Version of the Linux kernel, the version of gcc used to compile the kernel, and the time of kernel compilation', - 'parser': parser - } \ No newline at end of file +def parser(stdout, stderr, to_camelcase): + output = {} + + if stdout: + output = stdout.strip() + + return {"output": output, "unprocessed": []} + + +def register(main): + main["proc_version"] = { + "cmd": "cat /proc/version", + "description": "Version of the Linux kernel, the version of gcc used to compile the kernel, and the time of kernel compilation", + "parser": parser, + } diff --git a/modules/proc_version_signature.py b/modules/proc_version_signature.py new file mode 100644 index 0000000..dfa042a --- /dev/null +++ b/modules/proc_version_signature.py @@ -0,0 +1,19 @@ +import re + + +def parser(stdout, stderr, to_camelcase): + output = "" + + if stdout: + output = re.sub(r"\n|\r|\r\n", "", stdout) + output = stdout.strip() + + return {"output": output, "unprocessed": []} + + +def register(main): + main["proc_version_signature"] = { + "cmd": "cat /proc/version_signature", + "description": "OS version signature", + "parser": parser, + } diff --git a/modules/proc_vmstat.py b/modules/proc_vmstat.py index bdf2c31..6e8d299 100644 --- a/modules/proc_vmstat.py +++ b/modules/proc_vmstat.py @@ -1,18 +1,29 @@ -import re - -def parser(stdout, stderr): - output = {} - if stdout: - for line in stdout.splitlines(): - lineMatch = re.search(r'^([^\s+]+)\s(.*)$', line) - if lineMatch: - output[lineMatch.group(1)] = lineMatch.group(2) - - return {'output': output} - -def register(main): - main['proc_vmstat'] = { - 'cmd': 'cat /proc/vmstat', - 'description': 'Detailed virtual memory statistics from the kernel', - 'parser': parser - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + lineMatch = re.search(r"^([^\s+]+)\s(.*)$", line) + if lineMatch: + key = camelCase(lineMatch.group(1), to_camelcase) + value = lineMatch.group(2) + + output[key] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_vmstat"] = { + "cmd": "cat /proc/vmstat", + "description": "Detailed virtual memory statistics from the kernel", + "parser": parser, + } diff --git a/modules/prtstat.py b/modules/prtstat.py index 9a476dc..a4a484b 100644 --- a/modules/prtstat.py +++ b/modules/prtstat.py @@ -1,25 +1,37 @@ - -import re - -def parser(stdout, stderr): - output = {} - pid = '' - if stdout: - for line in stdout.splitlines(): - lineMatch = re.findall(r'(\S+):\s(\S+)', line) - for kv in lineMatch: - if kv[0] == 'pid': - pid = kv[1] - output[pid] = {} - - if pid != '': - output[pid][kv[0]] = kv[1] - - return {'output': output} - -def register(main): - main['prtstat'] = { - 'cmd': 'ps -eo pid | xargs -I {} prtstat -r {}', - 'description': 'Print statistics of a processes', - 'parser': parser - } \ No newline at end of file +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + pid = "" + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + processed = False + pairs = re.findall(r"(\S+):\s(\S+)", line) + for kv in pairs: + if kv[0] == "pid": + pid = kv[1] + output[pid] = {} + + if pid != "": + key = camelCase(kv[0], to_camelcase) + value = kv[1].strip() + + output[pid][key] = value + processed = True + + if not processed: + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["prtstat"] = { + "cmd": "ps -eo pid | xargs -I {} prtstat -r {}", + "description": "Print statistics of a processes", + "parser": parser, + } diff --git a/modules/ps.py b/modules/ps.py index 9d62fe7..839de03 100644 --- a/modules/ps.py +++ b/modules/ps.py @@ -1,51 +1,58 @@ - -import re - -def parser(stdout, stderr): - output = {} - columnsNames = [ - 'user', - 'ruser', - 'group', - 'rgroup', - 'pid', - 'ppid', - 'pgid', - 'cpu', - 'size', - 'bytes', - 'nice', - 'time', - 'stime', - 'tty', - 'args' - ] - columnsCount = len(columnsNames) - if stdout: - for line in stdout.splitlines(): - if re.search(r'ps --cols 2048 -eo', line) or re.search(r'USER.*RUSER.*GROUP', line): - continue - - cols = re.split(r'\s+', line) - if cols: - entry = {} - for num, val in enumerate(cols, start=0): - if num < columnsCount: - name = columnsNames[num] - entry[name] = val - elif 'args' in entry: - entry['args'] += ' ' + val - - if 'pid' in entry: - output[entry['pid']] = entry - - return {'output': output} - -def register(main): - main['ps'] = { - 'cmd': 'ps --cols 2048 -eo user:80,ruser:80,group:80,rgroup:80,pid,ppid,pgid,pcpu,vsz,nice,etime,time,stime,tty,args 2>/dev/null', - 'description': 'Report a snapshot of the current processes', - 'parser': parser - } - - +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + columnsNames = [ + "user", + "ruser", + "group", + "rgroup", + "pid", + "ppid", + "pgid", + "cpu", + "size", + "bytes", + "nice", + "time", + "stime", + "tty", + "args", + ] + columnsCount = len(columnsNames) + + if stdout: + for line in stdout.splitlines(): + if re.search(r"ps --cols 12288 -eo", line) or re.search( + r"USER.*RUSER.*GROUP", line + ): + continue + + cols = re.split(r"\s+", line) + if cols: + entry = {} + for num, val in enumerate(cols, start=0): + if num < columnsCount: + name = columnsNames[num] + entry[name] = val + + elif "args" in entry: + entry["args"] += " " + val + + if "pid" in entry: + output[entry["pid"]] = entry + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["ps"] = { + "cmd": "ps --cols 12288 -eo user:256,ruser:256,group:256,rgroup:256,pid,ppid,pgid,pcpu,vsz,nice,etime,time,stime,tty,args 2>/dev/null", + "description": "Report a snapshot of the current processes", + "parser": parser, + } diff --git a/modules/python.py b/modules/python.py index a665ef2..4862140 100644 --- a/modules/python.py +++ b/modules/python.py @@ -1,61 +1,78 @@ -import platform - -loaded_pkg_resources = False - -try: - import pkg_resources - loaded_pkg_resources = True -except: - pass - -def python_pip_packages(): - output = {} - for pkg in pkg_resources.working_set: - package = {} - for key in ['location', 'project_name', 'key', 'version', 'parsed_version', 'py_version', 'platform', 'precedence']: - if hasattr(pkg, key): - package[key] = str(getattr(pkg, key)) - - if 'key' in package: - output[package['key']] = package - - return output - -def python_platform(): - output = { - 'architecture': platform.architecture(), - 'machine': platform.machine(), - 'node': platform.node(), - 'platform': { - 'normal': platform.platform(), - 'aliased': platform.platform(aliased=True), - 'terse': platform.platform(terse=True) - }, - 'processor': platform.processor(), - 'python': { - 'branch': platform.python_branch(), - 'build': platform.python_build(), - 'compiler': platform.python_compiler(), - 'implementation': platform.python_implementation(), - 'revision': platform.python_revision(), - 'version': platform.python_version(), - 'versionTuple': platform.python_version_tuple(), - }, - 'release': platform.release(), - 'system': platform.system(), - 'version': platform.version(), - 'uname': platform.uname(), - } - return output - -def register(main): - if loaded_pkg_resources: - main['python_pip_packages'] = { - 'function': python_pip_packages, - 'description': 'List available python modules', - } - - main['python_platform'] = { - 'function': python_platform, - 'description': 'Probe the underlying platform\'s hardware, operating system, and Python interpreter version information', - } +import platform + +from modules.sysinfo_lib import camelCase + + +try: + import pkg_resources + + loaded_pkg_resources = True +except: + loaded_pkg_resources = False + + +def python_pip_packages(to_camelcase): + output = {} + + if loaded_pkg_resources: + for pkg in pkg_resources.working_set: + package = {} + for key in [ + "location", + "project_name", + "key", + "version", + "parsed_version", + "py_version", + "platform", + "precedence", + ]: + if hasattr(pkg, key): + key_case = camelCase(key, to_camelcase) + package[key_case] = str(getattr(pkg, key)) + + if "key" in package: + output[package["key"]] = package + + return {"output": output, "unprocessed": []} + + +def python_platform(to_camelcase): + output = { + "architecture": platform.architecture(), + "machine": platform.machine(), + "node": platform.node(), + "platform": { + "normal": platform.platform(), + "aliased": platform.platform(aliased=True), + "terse": platform.platform(terse=True), + }, + "processor": platform.processor(), + "python": { + "branch": platform.python_branch(), + "build": platform.python_build(), + "compiler": platform.python_compiler(), + "implementation": platform.python_implementation(), + "revision": platform.python_revision(), + "version": platform.python_version(), + "versionTuple": platform.python_version_tuple(), + }, + "release": platform.release(), + "system": platform.system(), + "version": platform.version(), + "uname": platform.uname(), + } + return {"output": output, "unprocessed": []} + + +def register(main): + if loaded_pkg_resources: + main["python_pip_packages"] = { + "function": python_pip_packages, + "description": "List available python modules", + } + + main["python_platform"] = { + "function": python_platform, + "description": "Probe the underlying platform's hardware, operating system, and Python interpreter version information", + } diff --git a/modules/route.py b/modules/route.py new file mode 100644 index 0000000..808820b --- /dev/null +++ b/modules/route.py @@ -0,0 +1,22 @@ +from sysinfo_lib import parseTable + + +def parser(stdout, stderr, to_camelcase): + output = {} + + if stdout: + output = parseTable( + stdout, + header_pattern=r"^(Destination\s*)(\sGateway\s*)(\sGenmask\s*)(\sFlags\s*)(\sMetric\s*)(\sRef\s)(\s*Use)(\sIface\s*)(\sMSS\s*)(\sWindow\s*)(\sirtt\s*)", + to_camelcase=to_camelcase, + ) + + return {"output": output, "unprocessed": []} + + +def register(main): + main["route"] = { + "cmd": "route -ee", + "description": "IP routing table", + "parser": parser, + } diff --git a/modules/rpm.py b/modules/rpm.py index 0f2c4f2..f066d2c 100644 --- a/modules/rpm.py +++ b/modules/rpm.py @@ -1,18 +1,31 @@ - -from sysinfo_lib import parseCharDelimitedTable, tableToDict - -def parser(stdout, stderr): - output = {} - columns = ['installtime', 'buildtime', 'name', 'version', 'release', 'arch', 'vendor', 'packager', 'distribution', 'disttag'] - if stdout: - output = parseCharDelimitedTable(stdout, '|', columns) - output = tableToDict(output, 'name') - - return {'output': output} - -def register(main): - main['rpm'] = { - 'cmd': 'rpm -q -a --queryformat "%{INSTALLTIME}|%{BUILDTIME}|%{NAME}|%{VERSION}|%{RELEASE}|%{arch}|%{VENDOR}|%{PACKAGER}|%{DISTRIBUTION}|%{DISTTAG}\n"', - 'description': 'Querying all RPM packages', - 'parser': parser - } +from sysinfo_lib import parseCharDelimitedTable, tableToDict + + +def parser(stdout, stderr, to_camelcase): + output = {} + columns = [ + "installtime", + "buildtime", + "name", + "version", + "release", + "arch", + "vendor", + "packager", + "distribution", + "disttag", + ] + + if stdout: + output = parseCharDelimitedTable(stdout, "|", columns) + output = tableToDict(output, "name") + + return {"output": output, "unprocessed": []} + + +def register(main): + main["rpm"] = { + "cmd": 'rpm -q -a --queryformat "%{INSTALLTIME}|%{BUILDTIME}|%{NAME}|%{VERSION}|%{RELEASE}|%{arch}|%{VENDOR}|%{PACKAGER}|%{DISTRIBUTION}|%{DISTTAG}\n"', + "description": "Querying all RPM packages", + "parser": parser, + } diff --git a/modules/services_status.py b/modules/services_status.py index cb9057d..78c49e7 100644 --- a/modules/services_status.py +++ b/modules/services_status.py @@ -1,39 +1,50 @@ - -import re -from sysinfo_lib import parseTable, tableToDict - -def parser_services(stdout, stderr): - output = parseTable(stdout) - output = tableToDict(output, 'unit') - return {'output': output} - -def parser_services_params(stdout, stderr): - output = {} - service = None - if stdout: - for line in stdout.splitlines(): - serviceSearch = re.search(r'^>>>\s*Service:\s*(.*)$', line) - if serviceSearch: - service = serviceSearch.group(1).strip() - output[service] = {} - - if service: - keyValueSearch = re.search(r'^([^=]+)=(.*)$', line) - if keyValueSearch: - output[service][keyValueSearch.group(1)] = keyValueSearch.group(2).strip() - - return {'output': output} - -def register(main): - main['services_list'] = { - 'cmd': """systemctl -l --type service --all --plain | grep -i -e ".service\|description" | sed 's/^\s*//g' """, - 'description': 'Displays services with status', - 'parser': parser_services - } - - main['services_params'] = { - 'cmd': """systemctl -l --type service --all --plain | sed -E 's/^\s*(\\S+.service).*$/\\1/g' | grep -i -e ".service" | xargs -I '{}' sh -c "echo '>>> Service: {}'; systemctl show {} --no-page" """, - 'description': 'Displays services with status', - 'parser': parser_services_params - } - +import re +from sysinfo_lib import parseTable, tableToDict, camelCase + + +def parser_services(stdout, stderr, to_camelcase): + output = parseTable(stdout, to_camelcase=to_camelcase) + output = tableToDict(output, "unit") + + return {"output": output, "unprocessed": []} + + +def parser_services_params(stdout, stderr, to_camelcase): + output = {} + service = None + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + service_search = re.search(r"^>>>\s*Service:\s*(.*)$", line) + if service_search: + service = service_search.group(1).strip() + output[service] = {} + continue + + if service: + kv = re.search(r"^([^=]+)=(.*)$", line) + if kv: + key = camelCase(kv.group(1), to_camelcase) + value = kv.group(2).strip() + + output[service][key] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["services_list"] = { + "cmd": """systemctl -l --type service --all --plain | grep -i -e ".service\|description" | sed 's/^\s*//g' """, + "description": "Displays services with status", + "parser": parser_services, + } + + main["services_params"] = { + "cmd": """systemctl -l --type service --all --plain | sed -E 's/^\s*(\\S+.service).*$/\\1/g' | grep -i -e ".service" | xargs -I '{}' sh -c "echo '>>> Service: {}'; systemctl show {} --no-page" """, + "description": "Displays services with params", + "parser": parser_services_params, + } diff --git a/modules/sysctl.py b/modules/sysctl.py index 8b1bd2e..bd6dbec 100644 --- a/modules/sysctl.py +++ b/modules/sysctl.py @@ -1,41 +1,51 @@ - -import re - -def setPathValue(data, path, value): - pathRest = None - pathParts = re.search(r'^([^\.]+)\.?(.*)$', path) - if pathParts: - path = pathParts.group(1) - pathRest = pathParts.group(2) - - if not path in data: - data[path] = {} - - if pathRest: - setPathValue(data[path], pathRest, value) - else: - data[path] = value - -def parser(stdout, stderr): - output = {} - if stdout: - for line in stdout.splitlines(): - kv = re.search(r'^([^=]+)=(.*)$', line) - if kv: - key = kv.group(1).strip() - value = kv.group(2).strip() - setPathValue(output, key, value) - - return {'output': output} - -def register(main): - main['sysctl'] = { - 'cmd': 'sysctl -a -e', - 'description': 'Runtime kernel parameters', - 'parser': parser - } - main['sysctl_system'] = { - 'cmd': 'sysctl -a -e --system', - 'description': 'Runtime kernel parameters from all system configuration files', - 'parser': parser - } +import re +from sysinfo_lib import camelCase + + +def set_path_value(data, path, value, to_camelcase): + pathRest = None + pathParts = re.search(r"^([^\.]+)\.?(.*)$", path) + if pathParts: + path = camelCase(pathParts.group(1), to_camelcase) + pathRest = pathParts.group(2) + + if not path in data: + data[path] = {} + + if pathRest: + set_path_value(data[path], pathRest, value, to_camelcase) + else: + data[path] = value + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + kv = re.search(r"^([^=]+)=(.*)$", line) + if kv: + key = kv.group(1).strip() + value = kv.group(2).strip() + + set_path_value(output, key, value, to_camelcase) + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["sysctl"] = { + "cmd": "sysctl -a -e", + "description": "Runtime kernel parameters", + "parser": parser, + } + + main["sysctl_system"] = { + "cmd": "sysctl -a -e --system", + "description": "Runtime kernel parameters from all system configuration files", + "parser": parser, + } diff --git a/modules/sysinfo_lib.py b/modules/sysinfo_lib.py index 2bdf4cd..acc6e9e 100644 --- a/modules/sysinfo_lib.py +++ b/modules/sysinfo_lib.py @@ -1,130 +1,155 @@ -import sys -import re -from struct import pack, unpack - -PY2 = sys.version_info[0] == 2 -PY3 = sys.version_info[0] == 3 - -def sortedList(st): - values = list(set(st.splitlines())) - values.sort() - return values - -def camelCase(st): - output = ''.join(x for x in st.title() if x.isalnum()) - if len(output) == 1: - return output.lower() - elif len(output) > 1: - return output[0].lower() + output[1:] - else: - return '' - -def parseTable(input, headerPattern = None, endPattern = None, ignoreEmpty = True): - output = [] - colNames = [] - colLengths = [] - header = None - lines = input.splitlines() - - if len(lines) == 0: - return output - - while len(lines) > 0 and lines[0].strip() == '': - lines.pop(0) - - if headerPattern: - while len(lines) > 0 and not re.search(headerPattern, lines[0], re.IGNORECASE): - lines.pop(0) - - if len(lines) == 0: - return output - - header = re.search(headerPattern, lines.pop(0), re.IGNORECASE) - if header: - header = header.groups() - - else: - header = re.findall(r'(\S+\s*)', lines.pop(0), re.IGNORECASE) - - if header: - for value in header: - colNames.append(camelCase(value.strip())) - colLengths.append(len(value)) - - if len(colNames) > 0: - colLengths[-1] = 8192 - totalLength = sum(colLengths) - packTemplate = ''.join([str(s) + 's' for s in colLengths]) - - for line in lines: - if ignoreEmpty == True and line.strip() == '': - continue - row = {} - if endPattern and re.match(endPattern, line): - break - if PY2: - cols = unpack(packTemplate, line + (' ' * (totalLength - len(line)))) - else: - cols = unpack(packTemplate, bytes(line + (' ' * (totalLength - len(line))), 'utf-8')) - for num, val in enumerate(cols, start=0): - if PY2: - row[colNames[num]] = val.strip() - else: - row[colNames[num]] = str(val.strip(), 'utf-8') - output.append(row) - - return output - -def parseSpaceTable(input, ignoreEmpty = True): - output = [] - colNames = [] - lines = input.splitlines() - - if len(lines) == 0: - return output - - while len(lines) > 0 and lines[0].strip() == '': - lines.pop(0) - - header = re.findall(r'(\S+[\s\t]*)', lines.pop(0), re.IGNORECASE) - if header: - for value in header: - colNames.append(camelCase(value.strip())) - - if len(colNames) > 0: - for line in lines: - if ignoreEmpty == True and line.strip() == '': - continue - row = {} - cols = re.split(r'\s+', line.strip()) - for num, val in enumerate(cols, start=0): - if num < len(colNames): - row[colNames[num]] = val.strip() - output.append(row) - - return output - -def parseCharDelimitedTable(input, delimiter, columnsNames): - output = [] - if input: - columns = len(columnsNames) + 1 - for line in input.splitlines(): - values = re.split(re.escape(delimiter), line + (delimiter * columns)) - row = {} - for num, val in enumerate(columnsNames, start=0): - if num < columns and num < len(values): - row[val] = values[num] - output.append(row) - return output - -def tableToDict(input, key): - output = {} - - for row in input: - if isinstance(row, dict): - if key in row: - output[row[key]] = row - else: - return input - - return output +import sys +import re +from struct import pack, unpack + +PY2 = sys.version_info[0] == 2 +PY3 = sys.version_info[0] == 3 + + +def sortedList(st): + values = list(set(st.splitlines())) + values.sort() + return values + +def camelCase_cb(matchobj): + return " ".join([matchobj.group(1), matchobj.group(2)]) + +def camelCase(st, to_camelcase): + if not to_camelcase: + return st + + st = re.sub(r"([a-z])([A-Z])", camelCase_cb, st) + + output = "".join(x for x in st.title() if x.isalnum()) + if len(output) == 1: + return output.lower() + + elif len(output) > 1: + return output[0].lower() + output[1:] + + else: + return "" + + +def parseTable( + input, header_pattern=None, end_pattern=None, ignore_empty=True, to_camelcase=False +): + output = [] + colNames = [] + colLengths = [] + header = None + lines = input.splitlines() + + if len(lines) == 0: + return output + + while len(lines) > 0 and lines[0].strip() == "": + lines.pop(0) + + if header_pattern: + while len(lines) > 0 and not re.search(header_pattern, lines[0], re.IGNORECASE): + lines.pop(0) + + if len(lines) == 0: + return output + + header = re.search(header_pattern, lines.pop(0), re.IGNORECASE) + if header: + header = header.groups() + + else: + header = re.findall(r"(\S+\s*)", lines.pop(0), re.IGNORECASE) + + if header: + for value in header: + colNames.append(camelCase(value.strip(), to_camelcase)) + colLengths.append(len(value)) + + if len(colNames) > 0: + colLengths[-1] = 8192 + totalLength = sum(colLengths) + packTemplate = "".join([str(s) + "s" for s in colLengths]) + + for line in lines: + if ignore_empty == True and line.strip() == "": + continue + + row = {} + if end_pattern and re.match(end_pattern, line): + break + + if PY2: + cols = unpack(packTemplate, line + (" " * (totalLength - len(line)))) + else: + cols = unpack( + packTemplate, + bytes(line + (" " * (totalLength - len(line))), "utf-8"), + ) + + for num, val in enumerate(cols, start=0): + if PY2: + row[colNames[num]] = val.strip() + else: + row[colNames[num]] = str(val.strip(), "utf-8") + + output.append(row) + + return output + + +def parseSpaceTable(input, ignore_empty=True, to_camelcase=False): + output = [] + colNames = [] + lines = input.splitlines() + + if len(lines) == 0: + return output + + while len(lines) > 0 and lines[0].strip() == "": + lines.pop(0) + + header = re.findall(r"(\S+[\s\t]*)", lines.pop(0), re.IGNORECASE) + if header: + for value in header: + colNames.append(camelCase(value.strip(), to_camelcase)) + + if len(colNames) > 0: + for line in lines: + if ignore_empty == True and line.strip() == "": + continue + row = {} + cols = re.split(r"\s+", line.strip()) + for num, val in enumerate(cols, start=0): + if num < len(colNames): + row[colNames[num]] = val.strip() + + output.append(row) + + return output + + +def parseCharDelimitedTable(input, delimiter, columnsNames): + output = [] + if input: + columns = len(columnsNames) + 1 + for line in input.splitlines(): + values = re.split(re.escape(delimiter), line + (delimiter * columns)) + row = {} + for num, val in enumerate(columnsNames, start=0): + if num < columns and num < len(values): + row[val] = values[num] + output.append(row) + return output + + +def tableToDict(input, key): + output = {} + + for row in input: + if isinstance(row, dict): + if key in row: + output[row[key]] = row + else: + return input + + return output diff --git a/modules/timedatectl.py b/modules/timedatectl.py index 84d286e..8711e9b 100644 --- a/modules/timedatectl.py +++ b/modules/timedatectl.py @@ -1,20 +1,35 @@ - -import re -from sysinfo_lib import camelCase - -def parser(stdout, stderr): - output = {} - if stdout: - for line in stdout.splitlines(): - lineMatch = re.search(r'^([^:]+):\s*(.*)', line) - if lineMatch: - output[camelCase(lineMatch.group(1))] = lineMatch.group(2) - - return {'output': output} - -def register(main): - main['timedatectl'] = { - 'cmd': 'timedatectl status', - 'description': 'System time and date', - 'parser': parser - } \ No newline at end of file +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + lineMatch = re.search(r"^([^:]+):\s*(.*)", line) + if lineMatch: + key = camelCase(lineMatch.group(1).strip(), to_camelcase) + value = lineMatch.group(2).strip() + + output[key] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["timedatectl"] = { + "cmd": "timedatectl status", + "description": "System time and date", + "parser": parser, + } + + main["timedatectl_timesync"] = { + "cmd": "timedatectl timesync-status", + "description": "Status of systemd-timesyncd.service", + "parser": parser, + } diff --git a/modules/udevadm.py b/modules/udevadm.py index f10dc53..9aff430 100644 --- a/modules/udevadm.py +++ b/modules/udevadm.py @@ -1,97 +1,141 @@ - -import re -from sysinfo_lib import camelCase - -def parser(stdout, stderr): - output = {'devices': {}, 'parents': {}} - types = { - 'P': 'path', - 'N': 'node', - 'L': 'linkPriority', - 'E': 'entry', - 'S': 'link' - } - device = None - parent = None - if stdout: - for line in stdout.splitlines(): - deviceSearch = re.search(r'^>>> Device: (\S+)', line) - if deviceSearch: - device = deviceSearch.group(1) - output['devices'][device] = {'parents': [], 'entry': {}, 'link': []} - parent = None - - if not device: - continue - - keyValue = re.search(r'^(\S):\s+(.*)$', line) - if keyValue: - key = keyValue.group(1) - value = keyValue.group(2).strip() - if key in types: - key = types[key] - - if key == 'entry': - valueSearch = re.search(r'^([^=]+)=(.*)$', value) - if valueSearch: - subkey = valueSearch.group(1).lower() - subvalue = valueSearch.group(2).strip() - output['devices'][device]['entry'][subkey] = subvalue - - elif key == 'link': - output['devices'][device]['link'].append(value) - - else: - output['devices'][device][key] = value - - deviceLook = re.search(r'^\s+looking at device \'([^\']+)', line) - if deviceLook: - parent = deviceLook.group(1) - if not parent in output['parents']: - output['parents'][parent] = {} - output['devices'][device]['parents'].append(parent) - - parentDeviceLook = re.search(r'^\s+looking at device \'([^\']+)', line) - if parentDeviceLook: - parent = parentDeviceLook.group(1) - if not parent in output['parents']: - output['parents'][parent] = {} - output['devices'][device]['parents'].append(parent) - - if parent: - parentKeyValue = re.search(r'^\s+([^=]+)=="([^"]+)"', line) - if parentKeyValue: - key = parentKeyValue.group(1).lower() - value = parentKeyValue.group(2) - - multipleValues = re.match(r'^(\s+\d+)+$', value) - if multipleValues: - value = re.split(r'\s+', value.strip()) - - keyAttr = re.match(r'^(\S+){([^}]+)}', key, re.IGNORECASE) - if keyAttr: - attrType = keyAttr.group(1).lower() - if not attrType in output['parents'][parent]: - output['parents'][parent][attrType] = {} - - attrKey = camelCase(keyAttr.group(2)) - output['parents'][parent][attrType][attrKey] = value - - else: - output['parents'][parent][key] = value - - return {'output': output} - - -def register(main): - main['udevadm'] = { - 'cmd': """udevadm info --export-db | grep "DEVNAME" | cut -d "=" -f2 | xargs -n 1 -I {} sh -c "echo '>>> Device: {}'; udevadm info --query=all --name={}; udevadm info --attribute-walk --name={}" """, - 'description': 'Queries the udev database for device information stored in the udev database', - 'parser': parser - } - - main['udevadm_block_devices'] = { - 'cmd': """find /dev/ -type b | xargs -n 1 -I {} sh -c "echo '>>> Device: {}'; udevadm info --query=all --name={}; udevadm info --attribute-walk --name={}" """, - 'description': 'Queries the udev database for block device information stored in the udev database', - 'parser': parser - } +import re +from sysinfo_lib import camelCase + + +def parse_looking_entry(line, entry, to_camelcase): + key_value = re.search(r'^\s+([^=]+)=="([^"]*)"', line) + if key_value: + key = key_value.group(1).lower() + value = key_value.group(2) + + multiple_values = re.match(r"^(\s+\d+)+$", value) + if multiple_values: + value = re.split(r"\s+", value.strip()) + + key_attr = re.match(r"^(\S+){([^}]+)}", key, re.IGNORECASE) + if key_attr: + attrType = camelCase(key_attr.group(1), to_camelcase) + + if not attrType in entry: + entry[attrType] = {} + + path = key_attr.group(2).split("/") + + if len(path) == 1: + key_case = camelCase(path[0], to_camelcase) + entry[attrType][key_case] = value + + else: + sub_entry = entry[attrType] + + for part in path[0:-1]: + part_case = camelCase(part, to_camelcase) + + if not part_case in sub_entry: + sub_entry[part_case] = {} + + sub_entry = sub_entry[part_case] + + key_case = camelCase(path[-1], to_camelcase) + sub_entry[key_case] = value + + else: + entry[key] = value + + return True + + return False + + +def parser(stdout, stderr, to_camelcase): + output = {"devices": {}, "parents": {}} + types = {"P": "path", "N": "node", "L": "linkPriority", "E": "entry", "S": "link"} + device = None + parent = None + looking_entry = None + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + deviceSearch = re.search(r"^>>> Device: (\S+)", line) + if deviceSearch: + device = deviceSearch.group(1) + output["devices"][device] = {"parents": [], "entry": {}, "link": []} + parent = None + continue + + if not device: + continue + + if line.strip() == "": + looking_entry = None + continue + + if re.match( + r"^.*(Udevadm info starts|chain of parent|the udev rules|rule to match|single parent device)", + line, + ): + continue + + keyValue = re.search(r"^(\S):\s+(.*)$", line) + if keyValue: + key = keyValue.group(1) + value = keyValue.group(2).strip() + if key in types: + key = types[key] + + if key == "entry": + valueSearch = re.search(r"^([^=]+)=(.*)$", value) + if valueSearch: + subkey = camelCase(valueSearch.group(1), to_camelcase) + subvalue = valueSearch.group(2).strip() + output["devices"][device]["entry"][subkey] = subvalue + + elif key == "link": + output["devices"][device]["link"].append(value) + + else: + output["devices"][device][key] = value + + continue + + deviceLook = re.search(r"^\s+looking at device \'([^\']+)", line) + if deviceLook: + looking_entry = output["devices"][device] + continue + + parentDeviceLook = re.search( + r"^\s+looking at parent device \'([^\']+)", line + ) + if parentDeviceLook: + parent = parentDeviceLook.group(1) + output["devices"][device]["parents"].append(parent) + + if not parent in output["parents"]: + output["parents"][parent] = {} + + looking_entry = output["parents"][parent] + continue + + if isinstance(looking_entry, dict): + processed = parse_looking_entry(line, looking_entry, to_camelcase) + if processed: + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["udevadm"] = { + "cmd": """udevadm info --export-db | grep "DEVNAME" | cut -d "=" -f2 | xargs -n 1 -I {} sh -c "echo '>>> Device: {}'; udevadm info --query=all --name={}; udevadm info --attribute-walk --name={}" """, + "description": "Queries the udev database for device information stored in the udev database", + "parser": parser, + } + + main["udevadm_block_devices"] = { + "cmd": """find /dev/ -type b | xargs -n 1 -I {} sh -c "echo '>>> Device: {}'; udevadm info --query=all --name={}; udevadm info --attribute-walk --name={}" """, + "description": "Queries the udev database for block device information stored in the udev database", + "parser": parser, + } diff --git a/modules/uname.py b/modules/uname.py index 26d5d3a..624e08c 100644 --- a/modules/uname.py +++ b/modules/uname.py @@ -1,59 +1,61 @@ - import re -def parser(stdout, stderr): - output = '' - if stdout: - output = re.sub(r'\n|\r|\r\n', '', stdout) - output = stdout.strip() - return {'output': output} +def parser(stdout, stderr, to_camelcase): + output = "" + + if stdout: + output = re.sub(r"\n|\r|\r\n", "", stdout) + output = stdout.strip() + + return {"output": output, "unprocessed": []} + def register(main): - main['kernel_name'] = { - 'cmd': 'uname -s', - 'description': 'Kernel name', - 'parser': parser - } - - main['kernel_release'] = { - 'cmd': 'uname -r', - 'description': 'Kernel release', - 'parser': parser - } - - main['kernel_version'] = { - 'cmd': 'uname -v', - 'description': 'Kernel version', - 'parser': parser - } - - main['nodename'] = { - 'cmd': 'uname -n', - 'description': 'Network node hostname', - 'parser': parser - } - - main['machine'] = { - 'cmd': 'uname -m', - 'description': 'Machine hardware name', - 'parser': parser - } - - main['processor'] = { - 'cmd': 'uname -p', - 'description': 'Processor type', - 'parser': parser - } - - main['hardware_platform'] = { - 'cmd': 'uname -i', - 'description': 'Hardware platform', - 'parser': parser - } - - main['operating_system'] = { - 'cmd': 'uname -o', - 'description': 'Operating system', - 'parser': parser - } + main["kernel_name"] = { + "cmd": "uname -s", + "description": "Kernel name (uname)", + "parser": parser, + } + + main["kernel_release"] = { + "cmd": "uname -r", + "description": "Kernel release (uname)", + "parser": parser, + } + + main["kernel_version"] = { + "cmd": "uname -v", + "description": "Kernel version (uname)", + "parser": parser, + } + + main["nodename"] = { + "cmd": "uname -n", + "description": "Network node hostname (uname)", + "parser": parser, + } + + main["machine"] = { + "cmd": "uname -m", + "description": "Machine hardware name (uname)", + "parser": parser, + } + + main["processor"] = { + "cmd": "uname -p", + "description": "Processor type (uname)", + "parser": parser, + } + + main["hardware_platform"] = { + "cmd": "uname -i", + "description": "Hardware platform (uname)", + "parser": parser, + } + + main["operating_system"] = { + "cmd": "uname -o", + "description": "Operating system (uname)", + "parser": parser, + } diff --git a/modules/vmstat.py b/modules/vmstat.py index 2b0c2c5..0603fc9 100644 --- a/modules/vmstat.py +++ b/modules/vmstat.py @@ -1,116 +1,144 @@ - -import re -import sys -from struct import pack, unpack -from sysinfo_lib import camelCase - -PY2 = sys.version_info[0] == 2 -PY3 = sys.version_info[0] == 3 - -def parser_stats(stdout, stderr): - output = {} - if stdout: - for line in stdout.splitlines(): - entry = re.search(r'^\s*(\d+)\s+(.*)$', line) - if entry: - output[camelCase(entry.group(2).strip())] = entry.group(1).strip() - - return {'output': output} - -def parser_disk(stdout, stderr): - output = {} - sectionsNames = [] - sectionsMask = '' - totalLength = 0 - columnPaths = [] - if stdout: - for line in stdout.splitlines(): - if re.match(r'disk.*reads', line, re.IGNORECASE): - topHeader = re.split(r'\s+', line) - if topHeader: - for value in topHeader: - sectionsNames.append(value.strip().strip('-').lower()) - totalLength += len(value) + 1 - sectionsMask += str(len(value) + 1) + 's' - - elif not sectionsMask: - continue - - if re.match(r'.*total.*merged.*sectors.*', line): - lineFix = line + (' ' * (totalLength - len(line))) - if sys.version_info[0] != 2: - lineFix = bytes(lineFix, 'utf-8') - - sectionData = unpack(sectionsMask, lineFix) - if sectionData: - index = 0 - - for sec in sectionData: - if PY2: - secStrip = sec.strip() - else: - secStrip = str(sec.strip(), 'utf-8') - - topColumns = re.split(r'\s+', secStrip) - if topColumns: - - for column in topColumns: - if column: - columnPaths.append(camelCase('%s %s' %(sectionsNames[index], column, ))) - else: - columnPaths.append('%s' %(sectionsNames[index], )) - index += 1 - else: - entry = {} - columns = re.split(r'\s+', line) - for ci, cv in enumerate(columns): - if ci < len(columnPaths): - entry[columnPaths[ci]] = cv - if 'disk' in entry: - output[entry['disk']] = entry - - return {'output': output} - -def parser_disk_sum(stdout, stderr): - output = {} - if stdout: - for line in stdout.splitlines(): - entry = re.search(r'^\s*(\d+)\s+(.*)$', line) - if entry: - output[camelCase(entry.group(2).strip())] = entry.group(1).strip() - - return {'output': output} - -def parser_forks(stdout, stderr): - output = {} - if stdout: - forks = re.search(r'\s*(\d+)\s*forks', stdout) - if forks: - output['forks'] = forks.group(1) - - return {'output': output} - -def register(main): - main['vmstat_stats'] = { - 'cmd': 'vmstat -s', - 'description': 'Displays a table of various event counters and memory statistics', - 'parser': parser_stats - } - - main['vmstat_disk'] = { - 'cmd': 'vmstat -dwn', - 'description': 'Report disk statistics', - 'parser': parser_disk - } - - main['vmstat_disk_sum'] = { - 'cmd': 'vmstat -D', - 'description': 'Report some summary statistics about disk activity', - 'parser': parser_disk_sum - } - - main['vmstat_forks'] = { - 'cmd': 'vmstat -f', - 'description': 'Displays the number of forks since boot', - 'parser': parser_forks - } +import re +import sys +from struct import pack, unpack +from sysinfo_lib import camelCase + +PY2 = sys.version_info[0] == 2 +PY3 = sys.version_info[0] == 3 + + +def parser_stats(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + entry = re.search(r"^\s*(\d+)\s+(.*)$", line) + if entry: + key = camelCase(entry.group(2).strip(), to_camelcase) + value = entry.group(1).strip() + output[key] = value + + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def parser_disk(stdout, stderr, to_camelcase): + output = {} + sectionsNames = [] + sectionsMask = "" + totalLength = 0 + columnPaths = [] + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + if re.match(r"disk.*reads", line, re.IGNORECASE): + topHeader = re.split(r"\s+", line) + if topHeader: + for value in topHeader: + sectionsNames.append(value.strip().strip("-").lower()) + totalLength += len(value) + 1 + sectionsMask += str(len(value) + 1) + "s" + continue + + if sectionsMask: + if re.match(r".*total.*merged.*sectors.*", line): + lineFix = line + (" " * (totalLength - len(line))) + if PY3: + lineFix = bytes(lineFix, "utf-8") + + sectionData = unpack(sectionsMask, lineFix) + if sectionData: + for index, sec in enumerate(sectionData): + if PY2: + secStrip = sec.strip() + else: + secStrip = str(sec.strip(), "utf-8") + + topColumns = re.split(r"\s+", secStrip) + for column in topColumns: + if column: + columnPaths.append( + camelCase( + "%s %s" + % ( + sectionsNames[index], + column, + ), + to_camelcase, + ) + ) + else: + columnPaths.append("%s" % (sectionsNames[index],)) + + else: + entry = {} + columns = re.split(r"\s+", line) + for ci, cv in enumerate(columns): + if ci < len(columnPaths): + entry[columnPaths[ci]] = cv + + if "disk" in entry: + output[entry["disk"]] = entry + + return {"output": output, "unprocessed": unprocessed} + + +def parser_disk_sum(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + entry = re.search(r"^\s*(\d+)\s+(.*)$", line) + if entry: + key = camelCase(entry.group(2).strip(), to_camelcase) + value = entry.group(1).strip() + + output[key] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def parser_forks(stdout, stderr, to_camelcase): + output = {} + + if stdout: + forks = re.search(r"\s*(\d+)\s*forks", stdout) + if forks: + output["forks"] = forks.group(1) + + return {"output": output, "unprocessed": []} + + +def register(main): + main["vmstat_stats"] = { + "cmd": "vmstat -s", + "description": "Displays a table of various event counters and memory statistics", + "parser": parser_stats, + } + + main["vmstat_disk"] = { + "cmd": "vmstat -dwn", + "description": "Report disk statistics", + "parser": parser_disk, + } + + main["vmstat_disk_sum"] = { + "cmd": "vmstat -D", + "description": "Report some summary statistics about disk activity", + "parser": parser_disk_sum, + } + + main["vmstat_forks"] = { + "cmd": "vmstat -f", + "description": "Displays the number of forks since boot", + "parser": parser_forks, + } diff --git a/modules/yum.py b/modules/yum.py index c3fa9a6..1f3206e 100644 --- a/modules/yum.py +++ b/modules/yum.py @@ -1,73 +1,82 @@ - -import re - -def parser_repolist(stdout, stderr): - output = {'mirrors': [], 'repos': [], 'errors': []} - insideTable = False - if stdout: - for line in stdout.splitlines(): - mirrors = re.search(r'^\s*\*\s*([^:]+):\s*(.*)$', line) - if mirrors: - output['mirrors'].append({ - 'repo': mirrors.group(1).strip(), - 'host': mirrors.group(2).strip() - }) - - tableHeader = re.search(r'^repo id\s+repo name\s+status', line, re.IGNORECASE) - tableRow = re.search(r'^([^\/]+)\/([^\/]+)\/(.*)\s\s+(\S+.*)\s\s+(\S+.*)$', line) - if tableHeader: - insideTable = True - - elif insideTable and tableRow: - output['repos'].append({ - 'repo': tableRow.group(1).strip(), - 'version': tableRow.group(2).strip(), - 'arch': tableRow.group(3).strip(), - 'repo_name': tableRow.group(4).strip(), - 'status': tableRow.group(5).strip() - }) - - else: - insideTable = False - - if stderr: - for line in stderr.splitlines(): - if re.search(r'http.*error .*', line, re.IGNORECASE): - if not line in output['errors']: - output['errors'].append(line) - - return {'output': output} - -def parser_installed(stdout, stderr): - output = {'packages': [], 'errors': []} - if stdout: - for line in stdout.splitlines(): - package = re.search(r'^([\S\.]+)\.(\S+)\s+(\S+\.\S+)\s+(\S+.*)$', line) - if package: - output['packages'].append({ - 'name': package.group(1).strip(), - 'arch': package.group(2).strip(), - 'version': package.group(3).strip(), - 'status': package.group(4).strip() - }) - - if stderr: - for line in stderr.splitlines(): - if re.search(r'http.*error .*', line, re.IGNORECASE): - if not line in output['errors']: - output['errors'].append(line) - - return {'output': output} - -def register(main): - main['yum_repolist'] = { - 'cmd': 'yum repolist all', - 'description': 'YUM - defined repositories', - 'parser': parser_repolist - } - - main['yum_installed'] = { - 'cmd': 'yum list installed', - 'description': 'YUM - list installed packages', - 'parser': parser_installed - } +import re + + +def parser_repolist(stdout, stderr, to_camelcase): + output = {"mirrors": [], "repos": [], "errors": []} + insideTable = False + if stdout: + for line in stdout.splitlines(): + mirrors = re.search(r"^\s*\*\s*([^:]+):\s*(.*)$", line) + if mirrors: + output["mirrors"].append( + {"repo": mirrors.group(1).strip(), "host": mirrors.group(2).strip()} + ) + + tableHeader = re.search( + r"^repo id\s+repo name\s+status", line, re.IGNORECASE + ) + tableRow = re.search( + r"^([^\/]+)\/([^\/]+)\/(.*)\s\s+(\S+.*)\s\s+(\S+.*)$", line + ) + if tableHeader: + insideTable = True + + elif insideTable and tableRow: + output["repos"].append( + { + "repo": tableRow.group(1).strip(), + "version": tableRow.group(2).strip(), + "arch": tableRow.group(3).strip(), + "repo_name": tableRow.group(4).strip(), + "status": tableRow.group(5).strip(), + } + ) + + else: + insideTable = False + + if stderr: + for line in stderr.splitlines(): + if re.search(r"http.*error .*", line, re.IGNORECASE): + if not line in output["errors"]: + output["errors"].append(line) + + return {"output": output} + + +def parser_installed(stdout, stderr, to_camelcase): + output = {"packages": [], "errors": []} + if stdout: + for line in stdout.splitlines(): + package = re.search(r"^([\S\.]+)\.(\S+)\s+(\S+\.\S+)\s+(\S+.*)$", line) + if package: + output["packages"].append( + { + "name": package.group(1).strip(), + "arch": package.group(2).strip(), + "version": package.group(3).strip(), + "status": package.group(4).strip(), + } + ) + + if stderr: + for line in stderr.splitlines(): + if re.search(r"http.*error .*", line, re.IGNORECASE): + if not line in output["errors"]: + output["errors"].append(line) + + return {"output": output} + + +def register(main): + main["yum_repolist"] = { + "cmd": "yum repolist all", + "description": "YUM - defined repositories", + "parser": parser_repolist, + } + + main["yum_installed"] = { + "cmd": "yum list installed", + "description": "YUM - list installed packages", + "parser": parser_installed, + } diff --git a/sysinfo.py b/sysinfo.py index d8bfa98..58cd0d9 100644 --- a/sysinfo.py +++ b/sysinfo.py @@ -1,255 +1,372 @@ -""" - * - * sysinfo - Python based scripts for obtaining system information from Linux. - * - * Petr Vavrin (peterbay) pvavrin@gmail.com - * https://github.com/peterbay - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * -""" - -import os -import sys -import glob -import json -import argparse -import subprocess -from threading import Timer -from multiprocessing import Pool -from os.path import dirname, basename, isfile, join - -sys.path.append(join(dirname(__file__), 'modules')) - -siModules = {} -PY2 = sys.version_info[0] == 2 -PY3 = sys.version_info[0] == 3 - -def loadModules(): - global siModules - global PY2 - global PY3 - modules = glob.glob(join(dirname(__file__), 'modules', '*.py')) - for f in modules: - if isfile(f) and not f.endswith('__init__.py'): - if PY2: - import imp - lib = imp.load_source(basename(f)[:-3], f) - if hasattr(lib, 'register'): - lib.register(siModules) - else: - from importlib import import_module - lib = __import__(basename(f)[:-3]) - if hasattr(lib, 'register'): - lib.register(siModules) - -def readFile(pathToFile): - try: - f = open(pathToFile, 'r') - content = f.read() - f.close() - return content, None - - except Exception as err: - return None, err - -def writeToFile(pathToFile, content): - try: - f = open(pathToFile, 'w') - f.write(content) - f.close() - - except Exception as err: - sys.stdout.write('ERROR: Can\'t write to file \'%s\': %s\n' % (pathToFile, err)) - -def pathCheck(args): - if args.export_dir: - if not os.access(args.export_dir, os.W_OK): - sys.stdout.write('ERROR: Export directory \'%s\' not exist or is not writable\n' % (args.export_dir, )) - exit(1) - - if args.import_dir: - if not os.access(args.import_dir, os.R_OK): - sys.stdout.write('ERROR: Import directory \'%s\' not exist or is not readable\n' % (args.import_dir, )) - exit(1) - -def kill(process): - return process.kill() - -def executeCmd(cmd): - try: - proc = subprocess.Popen(cmd.get('cmd', ''), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - cmdTimer = Timer(int(cmd.get('timeout', 30)), kill, [proc]) - - try: - cmdTimer.start() - outs, errs = proc.communicate() - - except Exception as err: - proc.kill() - outs, errs = proc.communicate() - cmd['error'] = err - - finally: - cmdTimer.cancel() - - except Exception as err: - cmd['error'] = err - - if proc: - procPoll = proc.poll() - if procPoll != 0: - cmd['rc'] = procPoll - if not cmd.get('error', None): - cmd['error'] = 'error' - - if PY2: - cmd['stdout'] = outs - cmd['stderr'] = errs - else: - cmd['stdout'] = str(outs, 'utf-8') - cmd['stderr'] = str(errs, 'utf-8') - -def execute(cmd): - if not isinstance(cmd, dict): - return {} - - if 'import_dir' in cmd: - commandImportPath = join(cmd.get('import_dir', ''), cmd.get('name', '')) - cmd['stdout'], cmd['stderr'] = readFile(commandImportPath) - - else: - outs, errs = '', '' - - if 'function' in cmd: - moduleFunction = cmd.get('function', None) - if moduleFunction and callable(moduleFunction): - outs = moduleFunction() - - cmd['stdout'] = outs - cmd['stderr'] = errs - return cmd - - elif 'cmd' in cmd: - executeCmd(cmd) - - return cmd - -def run(args): - poolSize = int(args.pool) - loadModules() - p = Pool(poolSize) - selectedModules = [] - executeModules = False - results = {} - - for name, settings in sorted(siModules.items()): - if args.list: - sys.stdout.write('%-25s - %s\n' % (name, settings.get('description', ''), )) - - elif args.info: - if 'function' in settings: - info = 'built-in function' - else: - info = settings.get('cmd', '') - - sys.stdout.write('%-25s - %s\n' % (name, info, )) - - elif args.all or name in args.commands: - settings['name'] = name - if args.import_dir: - settings['import_dir'] = args.import_dir - selectedModules.append(settings) - executeModules = True - - if executeModules: - for result in p.map(execute, selectedModules): - name = result.get('name', None) - if not name: - continue - - if args.error and not result.get('error', None): - continue - - if args.export_dir: - commandExportPath = join(args.export_dir, name) - writeToFile(commandExportPath, result.get('stdout', None)) - - if args.export_only: - continue - - parser = result.get('parser', None) - if parser and callable(parser): - try: - parsed = parser(result.get('stdout', None), result.get('stderr', None)) - - if isinstance(parsed, dict): - result['output'] = parsed.get('output', None) - result['ignored'] = parsed.get('ignored', None) - except Exception as err: - result['parser_error'] = str(err) - - else: - result['output'] = result.get('stdout', None) - - result.pop('parser', None) - result.pop('function', None) - - if not args.verbose and not args.error: - result.pop('stdout', None) - result.pop('stderr', None) - result.pop('rc', None) - result.pop('cmd', None) - result.pop('description', None) - result.pop('name', None) - result.pop('ignored', None) - result.pop('import_dir', None) - - results[name] = result - - if not args.export_only: - if args.output: - writeToFile(args.output, json.dumps(results, indent=4, sort_keys=True)) - - else: - sys.stdout.write(json.dumps(results, indent=4, sort_keys=True) + '\n') - - elif not args.list and not args.info: - sys.stdout.write('No commands to execute\n') - -def argsError(error): - pass - -def main(argv): - parser = argparse.ArgumentParser() - parser.error = argsError - - parser.add_argument('--all', '-a', action='store_true', default=False, help='Execute all commands.') - parser.add_argument('--error', '-e', action='store_true', default=False, help='Show only error outputs from commands.') - parser.add_argument('--export-only', action='store_true', default=False, help='Export output from commands without processing.') - parser.add_argument('--export-dir', help='Path to the directory for saving output from commands.') - parser.add_argument('--import-dir', help='Path to the directory for reading the stored outputs of commands.') - parser.add_argument('--info', '-i', action='store_true', default=False, help='List all commands with command line arguments.') - parser.add_argument('--list', '-l', action='store_true', default=False, help='List all commands.') - parser.add_argument('--output', '-o', help='Path to the output file.') - parser.add_argument('--pool', '-p', default='5', type=int, help='Pool size for parallel execution of commands. (default value is 5)') - parser.add_argument('--verbose', '-v', action='store_true', default=False, help='Add more info to output - options, commands, raw command result.') - parser.add_argument('commands', nargs='*', help='Commands') - - args = parser.parse_args() - pathCheck(args) - run (args) - -if __name__ == '__main__': - main(sys.argv) +""" + * + * sysinfo - Python based scripts for obtaining system information from Linux. + * + * Petr Vavrin (peterbay) pvavrin@gmail.com + * https://github.com/peterbay + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * +""" + +import os +import sys +import glob +import json +import argparse +import subprocess +from threading import Timer +from multiprocessing import Pool +from os.path import dirname, basename, isfile, join + +sys.path.append(join(dirname(__file__), "modules")) + +siModules = {} +PY2 = sys.version_info[0] == 2 +PY3 = sys.version_info[0] == 3 + + +def loadModules(): + global siModules + global PY2 + global PY3 + modules = glob.glob(join(dirname(__file__), "modules", "*.py")) + for f in modules: + if isfile(f) and not f.endswith("__init__.py"): + if PY2: + import imp + + lib = imp.load_source(basename(f)[:-3], f) + if hasattr(lib, "register"): + lib.register(siModules) + else: + from importlib import import_module + + lib = __import__(basename(f)[:-3]) + if hasattr(lib, "register"): + lib.register(siModules) + + +def readFile(pathToFile): + try: + f = open(pathToFile, "r") + content = f.read() + f.close() + return content, None + + except Exception as err: + return None, err + + +def writeToFile(pathToFile, content): + try: + f = open(pathToFile, "w") + f.write(content) + f.close() + + except Exception as err: + sys.stdout.write("ERROR: Can't write to file '%s': %s\n" % (pathToFile, err)) + + +def pathCheck(args): + if args.export_dir: + if not os.access(args.export_dir, os.W_OK): + sys.stdout.write( + "ERROR: Export directory '%s' not exist or is not writable\n" + % (args.export_dir,) + ) + exit(1) + + if args.import_dir: + if not os.access(args.import_dir, os.R_OK): + sys.stdout.write( + "ERROR: Import directory '%s' not exist or is not readable\n" + % (args.import_dir,) + ) + exit(1) + + +def kill(process): + return process.kill() + + +def executeCmd(cmd): + try: + command = cmd.get("cmd", None) + if not command: + cmd["error"] = "Empty command" + return + + proc = subprocess.Popen( + command, + shell=True, + executable="/usr/bin/bash", + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + cmdTimer = Timer(int(cmd.get("timeout", 30)), kill, [proc]) + + try: + cmdTimer.start() + outs, errs = proc.communicate() + + except Exception as err: + print(err) + proc.kill() + outs, errs = proc.communicate() + cmd["error"] = err + + finally: + cmdTimer.cancel() + + except Exception as err: + print(err) + cmd["error"] = err + + if proc: + procPoll = proc.poll() + if procPoll != 0: + cmd["rc"] = procPoll + if not "error" in cmd: + cmd["error"] = "Unknown error" + + if PY2: + cmd["stdout"] = outs + cmd["stderr"] = errs + else: + cmd["stdout"] = str(outs, "utf-8") + cmd["stderr"] = str(errs, "utf-8") + + +def execute(cmd): + if not isinstance(cmd, dict): + return {} + + if "import_dir" in cmd: + commandImportPath = join(cmd.get("import_dir", ""), cmd.get("name", "")) + cmd["stdout"], cmd["stderr"] = readFile(commandImportPath) + + else: + outs, errs = "", "" + to_camelcase = cmd.get("to_camelcase", None) + + if "function" in cmd: + moduleFunction = cmd.get("function", None) + if moduleFunction and callable(moduleFunction): + outs = moduleFunction(to_camelcase) + + cmd["stdout"] = outs + cmd["stderr"] = errs + return cmd + + elif "cmd" in cmd: + executeCmd(cmd) + + return cmd + + +def run(args): + poolSize = int(args.pool) + loadModules() + p = Pool(poolSize) + selectedModules = [] + executeModules = False + results = {} + + to_camelcase = args.camel_case + + for name, settings in sorted(siModules.items()): + if args.list: + sys.stdout.write( + "%-25s - %s\n" + % ( + name, + settings.get("description", ""), + ) + ) + + elif args.info: + if "function" in settings: + info = "built-in function" + else: + info = settings.get("cmd", "") + + sys.stdout.write( + "%-25s - %s\n" + % ( + name, + info, + ) + ) + + elif args.all or name in args.commands: + settings["name"] = name + if args.import_dir: + settings["import_dir"] = args.import_dir + + settings["to_camelcase"] = args.camel_case + selectedModules.append(settings) + executeModules = True + + if executeModules: + for result in p.map(execute, selectedModules): + name = result.get("name", None) + if not name: + continue + + if args.error and not result.get("error", None): + continue + + if args.export_dir: + commandExportPath = join(args.export_dir, name) + writeToFile(commandExportPath, result.get("stdout", None)) + + if args.export_only: + continue + + parser = result.get("parser", None) + if parser and callable(parser): + try: + parsed = parser( + result.get("stdout", None), + result.get("stderr", None), + to_camelcase, + ) + + if isinstance(parsed, dict): + result["output"] = parsed.get("output", None) + result["unprocessed"] = parsed.get("unprocessed", None) + + except Exception as err: + result["parser_error"] = str(err) + + else: + stdout = result.get("stdout", None) + if isinstance(stdout, dict): + result["output"] = stdout.get("output", None) + result["unprocessed"] = stdout.get("unprocessed", None) + + else: + result["output"] = stdout + result["unprocessed"] = [] + + result.pop("parser", None) + result.pop("function", None) + + if not args.verbose and not args.error: + result.pop("stdout", None) + result.pop("stderr", None) + result.pop("rc", None) + result.pop("cmd", None) + result.pop("description", None) + result.pop("name", None) + result.pop("unprocessed", None) + result.pop("import_dir", None) + + results[name] = result + + if not args.export_only: + if args.output: + writeToFile(args.output, json.dumps(results, indent=4, sort_keys=True)) + + else: + sys.stdout.write(json.dumps(results, indent=4, sort_keys=True) + "\n") + + elif not args.list and not args.info: + sys.stdout.write("No commands to execute\n") + + +def argsError(error): + pass + + +def main(argv): + parser = argparse.ArgumentParser() + parser.error = argsError + + parser.add_argument( + "--all", "-a", action="store_true", default=False, help="Execute all commands." + ) + + parser.add_argument( + "--camel-case", + "-c", + action="store_true", + default=False, + help="Convert keys to CamelCase.", + ) + + parser.add_argument( + "--error", + "-e", + action="store_true", + default=False, + help="Show only error outputs from commands.", + ) + + parser.add_argument( + "--export-only", + action="store_true", + default=False, + help="Export output from commands without processing.", + ) + + parser.add_argument( + "--export-dir", help="Path to the directory for saving output from commands." + ) + + parser.add_argument( + "--import-dir", + help="Path to the directory for reading the stored outputs of commands.", + ) + + parser.add_argument( + "--info", + "-i", + action="store_true", + default=False, + help="List all commands with command line arguments.", + ) + + parser.add_argument( + "--list", "-l", action="store_true", default=False, help="List all commands." + ) + + parser.add_argument("--output", "-o", help="Path to the output file.") + + parser.add_argument( + "--pool", + "-p", + default="5", + type=int, + help="Pool size for parallel execution of commands. (default value is 5)", + ) + + parser.add_argument( + "--verbose", + "-v", + action="store_true", + default=False, + help="Add more info to output - options, commands, raw command result.", + ) + + parser.add_argument("commands", nargs="*", help="Commands") + + args = parser.parse_args() + pathCheck(args) + run(args) + + +if __name__ == "__main__": + main(sys.argv) From f82b10bd9d1d08e968366677b44d0cf5c354a9c3 Mon Sep 17 00:00:00 2001 From: Petr Vavrin Date: Fri, 5 Aug 2022 00:06:09 +0200 Subject: [PATCH 2/9] new commands: arp, chage, update_alternatives --- modules/arp.py | 20 +++++++++++++++++++ modules/chage.py | 36 ++++++++++++++++++++++++++++++++++ modules/update_alternatives.py | 31 +++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 modules/arp.py create mode 100644 modules/chage.py create mode 100644 modules/update_alternatives.py diff --git a/modules/arp.py b/modules/arp.py new file mode 100644 index 0000000..cbd64e7 --- /dev/null +++ b/modules/arp.py @@ -0,0 +1,20 @@ +import re +from sysinfo_lib import parseTable, tableToDict, camelCase + + +def parser(stdout, stderr, to_camelcase): + output = parseTable( + stdout, + header_pattern=r"^(Address\s+)\s(HWtype\s+)\s(HWaddress\s+)\s(Flags Mask\s+)\s(Iface\s*)", + to_camelcase=to_camelcase, + ) + + return {"output": output, "unprocessed": []} + + +def register(main): + main["arp"] = { + "cmd": """arp""", + "description": "System ARP cache", + "parser": parser, + } diff --git a/modules/chage.py b/modules/chage.py new file mode 100644 index 0000000..cb80519 --- /dev/null +++ b/modules/chage.py @@ -0,0 +1,36 @@ +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + user = None + + if stdout: + for line in stdout.splitlines(): + user_match = re.search(r"^>>> User:\s+(.*)$", line) + if user_match: + user = user_match.group(1) + output[user] = {"name": user} + continue + + kv = re.search(r"^([^:]+):\s*(.*)$", line) + if user and kv: + key = camelCase(kv.group(1).strip(), to_camelcase) + value = kv.group(2).strip() + + output[user][key] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["chage"] = { + "cmd": """cat /etc/passwd | awk '{split($0,a,":"); print a[1]}' | xargs -I {} sh -c "echo '>>> User: {}'; chage -l {}" """, + "description": "Users password expiration information", + "parser": parser, + } diff --git a/modules/update_alternatives.py b/modules/update_alternatives.py new file mode 100644 index 0000000..9d4d476 --- /dev/null +++ b/modules/update_alternatives.py @@ -0,0 +1,31 @@ +import re + + +def parser(stdout, stderr, to_camelcase): + output = [] + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + lineMatch = re.search(r"^(\S+)\s+(.*)\s+(\S+)$", line) + if lineMatch: + output.append( + { + "name": lineMatch.group(1).strip(), + "mode": lineMatch.group(2).strip(), + "link": lineMatch.group(3).strip(), + } + ) + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["update_alternatives"] = { + "cmd": "update-alternatives --get-selections", + "description": "Symbolic links determining default commands", + "parser": parser, + } From 28996d3adeb6d2ad83422274adf61d047f7c91ed Mon Sep 17 00:00:00 2001 From: Petr Vavrin Date: Fri, 5 Aug 2022 09:56:21 +0200 Subject: [PATCH 3/9] added missing parameter -c to readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9dea176..3208a19 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ positional arguments: optional arguments: -h, --help Show this help message and exit --all, -a Execute all commands. + --camel-case, -c Convert keys to CamelCase. --error, -e Show only error outputs from commands. --export-only Export output from commands without processing. --export-dir PATH Path to the directory for saving output from commands. From 5962e5c0a20fd86a7b066c226229020c78a54017 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Lichnovsk=C3=BD?= Date: Fri, 5 Aug 2022 11:13:06 +0200 Subject: [PATCH 4/9] feat: added Makefile, Dockerfiles, testing requirements and tests folder --- Makefile | 57 ++ docker/build.Dockerfile | 43 + docker/test.Dockerfile | 44 ++ requirements-test.txt | 34 + setup.cfg | 16 + setup.py | 7 +- __init__.py => src/sysinfo/__init__.py | 0 {modules => src/sysinfo/modules}/__init__.py | 0 {modules => src/sysinfo/modules}/arp.py | 40 +- {modules => src/sysinfo/modules}/blkid.py | 70 +- {modules => src/sysinfo/modules}/blockdev.py | 98 +-- {modules => src/sysinfo/modules}/busctl.py | 200 ++--- {modules => src/sysinfo/modules}/chage.py | 72 +- {modules => src/sysinfo/modules}/chrt.py | 104 +-- {modules => src/sysinfo/modules}/compgen.py | 130 +-- {modules => src/sysinfo/modules}/dev_disk.py | 84 +- {modules => src/sysinfo/modules}/dev_input.py | 84 +- {modules => src/sysinfo/modules}/df.py | 0 {modules => src/sysinfo/modules}/dmidecode.py | 334 ++++---- {modules => src/sysinfo/modules}/dnf.py | 162 ++-- {modules => src/sysinfo/modules}/env.py | 50 +- .../sysinfo/modules}/etc_default.py | 108 +-- {modules => src/sysinfo/modules}/etc_fstab.py | 70 +- {modules => src/sysinfo/modules}/etc_group.py | 34 +- {modules => src/sysinfo/modules}/etc_hosts.py | 140 ++-- .../sysinfo/modules}/etc_locale_gen.py | 52 +- {modules => src/sysinfo/modules}/etc_mtab.py | 92 +-- .../sysinfo/modules}/etc_passwd.py | 32 +- .../sysinfo/modules}/etc_release.py | 56 +- .../sysinfo/modules}/etc_shadow.py | 52 +- .../sysinfo/modules}/etc_timezone.py | 30 +- {modules => src/sysinfo/modules}/fbset.py | 238 +++--- {modules => src/sysinfo/modules}/findmnt.py | 72 +- {modules => src/sysinfo/modules}/free.py | 78 +- {modules => src/sysinfo/modules}/getconf.py | 58 +- .../sysinfo/modules}/hostnamectl.py | 58 +- {modules => src/sysinfo/modules}/ifconfig.py | 172 ++-- {modules => src/sysinfo/modules}/lsblk.py | 76 +- {modules => src/sysinfo/modules}/lscpu.py | 60 +- {modules => src/sysinfo/modules}/lsmod.py | 76 +- {modules => src/sysinfo/modules}/lsns.py | 44 +- {modules => src/sysinfo/modules}/lsof.py | 210 ++--- {modules => src/sysinfo/modules}/lspci.py | 78 +- {modules => src/sysinfo/modules}/lsusb.py | 272 +++---- {modules => src/sysinfo/modules}/modinfo.py | 78 +- {modules => src/sysinfo/modules}/parted.py | 120 +-- .../sysinfo/modules}/proc_buddyinfo.py | 66 +- .../sysinfo/modules}/proc_bus_input.py | 164 ++-- .../sysinfo/modules}/proc_cgroups.py | 48 +- .../sysinfo/modules}/proc_cmdline.py | 72 +- .../sysinfo/modules}/proc_consoles.py | 116 +-- .../sysinfo/modules}/proc_cpuinfo.py | 80 +- .../sysinfo/modules}/proc_crypto.py | 68 +- .../sysinfo/modules}/proc_devices.py | 78 +- .../sysinfo/modules}/proc_diskstats.py | 94 +-- {modules => src/sysinfo/modules}/proc_dma.py | 56 +- .../sysinfo/modules}/proc_filesystems.py | 66 +- {modules => src/sysinfo/modules}/proc_fs.py | 112 +-- .../sysinfo/modules}/proc_iomem.py | 62 +- .../sysinfo/modules}/proc_ioports.py | 66 +- .../sysinfo/modules}/proc_loadavg.py | 60 +- .../sysinfo/modules}/proc_locks.py | 66 +- .../sysinfo/modules}/proc_meminfo.py | 74 +- .../sysinfo/modules}/proc_modules.py | 64 +- .../sysinfo/modules}/proc_mounts.py | 70 +- {modules => src/sysinfo/modules}/proc_net.py | 292 +++---- .../sysinfo/modules}/proc_partitions.py | 38 +- {modules => src/sysinfo/modules}/proc_scsi.py | 120 +-- .../sysinfo/modules}/proc_slabinfo.py | 142 ++-- {modules => src/sysinfo/modules}/proc_stat.py | 76 +- .../sysinfo/modules}/proc_swaps.py | 36 +- {modules => src/sysinfo/modules}/proc_sys.py | 96 +-- .../sysinfo/modules}/proc_uptime.py | 46 +- .../sysinfo/modules}/proc_version.py | 30 +- .../modules}/proc_version_signature.py | 0 .../sysinfo/modules}/proc_vmstat.py | 58 +- {modules => src/sysinfo/modules}/prtstat.py | 74 +- {modules => src/sysinfo/modules}/ps.py | 116 +-- {modules => src/sysinfo/modules}/python.py | 156 ++-- {modules => src/sysinfo/modules}/route.py | 44 +- {modules => src/sysinfo/modules}/rpm.py | 62 +- .../sysinfo/modules}/services_status.py | 100 +-- {modules => src/sysinfo/modules}/sysctl.py | 102 +-- .../sysinfo/modules}/sysinfo_lib.py | 310 ++++---- .../sysinfo/modules}/timedatectl.py | 70 +- {modules => src/sysinfo/modules}/udevadm.py | 282 +++---- {modules => src/sysinfo/modules}/uname.py | 0 .../sysinfo/modules}/update_alternatives.py | 62 +- {modules => src/sysinfo/modules}/vmstat.py | 288 +++---- {modules => src/sysinfo/modules}/yum.py | 164 ++-- sysinfo.py => src/sysinfo/sysinfo.py | 744 +++++++++--------- src/tests/__init__.py | 0 92 files changed, 4586 insertions(+), 4389 deletions(-) create mode 100644 Makefile create mode 100644 docker/build.Dockerfile create mode 100644 docker/test.Dockerfile create mode 100644 setup.cfg rename __init__.py => src/sysinfo/__init__.py (100%) rename {modules => src/sysinfo/modules}/__init__.py (100%) rename {modules => src/sysinfo/modules}/arp.py (96%) rename {modules => src/sysinfo/modules}/blkid.py (96%) rename {modules => src/sysinfo/modules}/blockdev.py (96%) rename {modules => src/sysinfo/modules}/busctl.py (96%) rename {modules => src/sysinfo/modules}/chage.py (96%) rename {modules => src/sysinfo/modules}/chrt.py (96%) rename {modules => src/sysinfo/modules}/compgen.py (96%) rename {modules => src/sysinfo/modules}/dev_disk.py (96%) rename {modules => src/sysinfo/modules}/dev_input.py (96%) rename {modules => src/sysinfo/modules}/df.py (100%) rename {modules => src/sysinfo/modules}/dmidecode.py (96%) rename {modules => src/sysinfo/modules}/dnf.py (96%) rename {modules => src/sysinfo/modules}/env.py (95%) rename {modules => src/sysinfo/modules}/etc_default.py (96%) rename {modules => src/sysinfo/modules}/etc_fstab.py (96%) rename {modules => src/sysinfo/modules}/etc_group.py (96%) rename {modules => src/sysinfo/modules}/etc_hosts.py (97%) rename {modules => src/sysinfo/modules}/etc_locale_gen.py (95%) rename {modules => src/sysinfo/modules}/etc_mtab.py (96%) rename {modules => src/sysinfo/modules}/etc_passwd.py (97%) rename {modules => src/sysinfo/modules}/etc_release.py (96%) rename {modules => src/sysinfo/modules}/etc_shadow.py (96%) rename {modules => src/sysinfo/modules}/etc_timezone.py (95%) rename {modules => src/sysinfo/modules}/fbset.py (97%) rename {modules => src/sysinfo/modules}/findmnt.py (95%) rename {modules => src/sysinfo/modules}/free.py (96%) rename {modules => src/sysinfo/modules}/getconf.py (96%) rename {modules => src/sysinfo/modules}/hostnamectl.py (96%) rename {modules => src/sysinfo/modules}/ifconfig.py (97%) rename {modules => src/sysinfo/modules}/lsblk.py (96%) rename {modules => src/sysinfo/modules}/lscpu.py (96%) rename {modules => src/sysinfo/modules}/lsmod.py (96%) rename {modules => src/sysinfo/modules}/lsns.py (96%) rename {modules => src/sysinfo/modules}/lsof.py (96%) rename {modules => src/sysinfo/modules}/lspci.py (96%) rename {modules => src/sysinfo/modules}/lsusb.py (96%) rename {modules => src/sysinfo/modules}/modinfo.py (96%) rename {modules => src/sysinfo/modules}/parted.py (96%) rename {modules => src/sysinfo/modules}/proc_buddyinfo.py (96%) rename {modules => src/sysinfo/modules}/proc_bus_input.py (96%) rename {modules => src/sysinfo/modules}/proc_cgroups.py (96%) rename {modules => src/sysinfo/modules}/proc_cmdline.py (96%) rename {modules => src/sysinfo/modules}/proc_consoles.py (97%) rename {modules => src/sysinfo/modules}/proc_cpuinfo.py (96%) rename {modules => src/sysinfo/modules}/proc_crypto.py (96%) rename {modules => src/sysinfo/modules}/proc_devices.py (96%) rename {modules => src/sysinfo/modules}/proc_diskstats.py (96%) rename {modules => src/sysinfo/modules}/proc_dma.py (95%) rename {modules => src/sysinfo/modules}/proc_filesystems.py (96%) rename {modules => src/sysinfo/modules}/proc_fs.py (96%) rename {modules => src/sysinfo/modules}/proc_iomem.py (96%) rename {modules => src/sysinfo/modules}/proc_ioports.py (96%) rename {modules => src/sysinfo/modules}/proc_loadavg.py (96%) rename {modules => src/sysinfo/modules}/proc_locks.py (96%) rename {modules => src/sysinfo/modules}/proc_meminfo.py (96%) rename {modules => src/sysinfo/modules}/proc_modules.py (96%) rename {modules => src/sysinfo/modules}/proc_mounts.py (96%) rename {modules => src/sysinfo/modules}/proc_net.py (96%) rename {modules => src/sysinfo/modules}/proc_partitions.py (96%) rename {modules => src/sysinfo/modules}/proc_scsi.py (97%) rename {modules => src/sysinfo/modules}/proc_slabinfo.py (96%) rename {modules => src/sysinfo/modules}/proc_stat.py (96%) rename {modules => src/sysinfo/modules}/proc_swaps.py (95%) rename {modules => src/sysinfo/modules}/proc_sys.py (96%) rename {modules => src/sysinfo/modules}/proc_uptime.py (96%) rename {modules => src/sysinfo/modules}/proc_version.py (96%) rename {modules => src/sysinfo/modules}/proc_version_signature.py (100%) rename {modules => src/sysinfo/modules}/proc_vmstat.py (96%) rename {modules => src/sysinfo/modules}/prtstat.py (96%) rename {modules => src/sysinfo/modules}/ps.py (96%) rename {modules => src/sysinfo/modules}/python.py (96%) rename {modules => src/sysinfo/modules}/route.py (96%) rename {modules => src/sysinfo/modules}/rpm.py (96%) rename {modules => src/sysinfo/modules}/services_status.py (97%) rename {modules => src/sysinfo/modules}/sysctl.py (96%) rename {modules => src/sysinfo/modules}/sysinfo_lib.py (96%) rename {modules => src/sysinfo/modules}/timedatectl.py (96%) rename {modules => src/sysinfo/modules}/udevadm.py (97%) rename {modules => src/sysinfo/modules}/uname.py (100%) rename {modules => src/sysinfo/modules}/update_alternatives.py (96%) rename {modules => src/sysinfo/modules}/vmstat.py (96%) rename {modules => src/sysinfo/modules}/yum.py (97%) rename sysinfo.py => src/sysinfo/sysinfo.py (96%) create mode 100644 src/tests/__init__.py diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f1c7483 --- /dev/null +++ b/Makefile @@ -0,0 +1,57 @@ +NAME=sysinfo +IMAGE_NAME=sysinfo + +ifndef VERSION +VERSION := $(shell python3 -m find_version src/sysinfo/__init__.py || echo 0.0.0) +endif + +ifndef BRANCH +BRANCH := $(shell git branch --show-current) +endif + +ifndef COMMIT +COMMIT := $(shell git log -n1 --format="%h") +endif + +ifndef SRC +SRC := src/sysinfo/*.py" +endif + +ifndef TESTS +TESTS := src/tests +endif + +BUILD_RUN=docker run --rm "$(IMAGE_NAME):$(COMMIT)" + +# .PHONY: git black lint build test coverage security +.PHONY: black lint build test coverage security + +# git: + # @echo "branch: $(BRANCH) commit: $(COMMIT)" + +black: + isort $(SRC) + black $(SRC) + autoflake --remove-all-unused-imports --remove-duplicate-keys --expand-star-imports --recursive --in-place $(SRC) + +lint: + flake8 --max-line-length=120 --max-complexity 8 $(SRC) + # interrogate $(SRC) + mypy $(SRC) + pylint -d C0301 -d R0902 $(SRC) + +build: + docker build -t $(IMAGE_NAME):$(COMMIT) . -f docker/build.Dockerfile + +test_docker: + docker build -t $(IMAGE_NAME):$(COMMIT) . -f docker/test.Dockerfile + +test: + pytest $(TESTS) + +coverage: + pytest --cov-report term-missing --cov=sysinfo $(TESTS) + +security: + safety check + bandit -r $(SRC) diff --git a/docker/build.Dockerfile b/docker/build.Dockerfile new file mode 100644 index 0000000..b0a2977 --- /dev/null +++ b/docker/build.Dockerfile @@ -0,0 +1,43 @@ +# TODO adjust docker file exaple +# FROM instruction chooses the parent image for Docker. +# This example uses Alpine. +# Alpine is a minimal Docker image very small in size +FROM alpine:3.3 +# LABEL instruction creates labels. +# The first label is maintainer with the value Linux Hint. +# The second label is appname with the value Flask Hello. World +# You can have as many key-to-value pairs as you want. +# You can also choose any name for the keys. +# The choice of maintainer and appname in this example +# is a personal choice. +LABEL "maintainer"="Linux Hint" "appname"="Flask Hello World" +# ENV instruction assigns environment variables. +# The /usr/src directory holds downloaded programs, +# be it source or binary before installing them. +ENV applocation /usr/src +# COPY instruction copies files or directories, +# from the Docker host to the Docker image. +# You'll copy the source code to the Docker image. +# The command below uses the set environment variable. +COPY sysinfo $applocation/sysinfo +# Using the ENV instruction again. +ENV flaskapp $applocation/sysinfo +# WORKDIR instruction changes the current directory in Docker image. +# The command below changes directory to /usr/src/flask-helloworld. +# The target directory uses the environment variable. +WORKDIR $flaskapp/ +# RUN instruction runs commands, +# just like you do on the terminal, +# but in the Docker image. +# The command below installs Python, pip and the app dependencies. +# The dependencies are in the requirements.txt file. +RUN apk add --update python py-pip +RUN pip install --upgrade pip +RUN pip install -r requirements.txt +# EXPOSE instruction opens the port for communicating with the Docker container. +# Flask app uses the port 5000, so you'll expose port 5000. +EXPOSE 5000 +# CMD instruction runs commands like RUN, +# but the commands run when the Docker container launches. +# Only one CMD instruction can be used. +CMD ["python", "sysinfo.py"] diff --git a/docker/test.Dockerfile b/docker/test.Dockerfile new file mode 100644 index 0000000..ca8aeae --- /dev/null +++ b/docker/test.Dockerfile @@ -0,0 +1,44 @@ +# TODO adjust docker file exaple +# FROM instruction chooses the parent image for Docker. +# This example uses Alpine. +# Alpine is a minimal Docker image very small in size +FROM alpine:3.3 +# LABEL instruction creates labels. +# The first label is maintainer with the value Linux Hint. +# The second label is appname with the value Flask Hello. World +# You can have as many key-to-value pairs as you want. +# You can also choose any name for the keys. +# The choice of maintainer and appname in this example +# is a personal choice. +LABEL "maintainer"="Linux Hint" "appname"="Flask Hello World" +# ENV instruction assigns environment variables. +# The /usr/src directory holds downloaded programs, +# be it source or binary before installing them. +ENV applocation /usr/src +# COPY instruction copies files or directories, +# from the Docker host to the Docker image. +# You'll copy the source code to the Docker image. +# The command below uses the set environment variable. +COPY src/sysinfo $applocation/sysinfo +COPY src/tests $applocation/tests +# Using the ENV instruction again. +ENV flaskapp $applocation/sysinfo +# WORKDIR instruction changes the current directory in Docker image. +# The command below changes directory to /usr/src/flask-helloworld. +# The target directory uses the environment variable. +WORKDIR $flaskapp/ +# RUN instruction runs commands, +# just like you do on the terminal, +# but in the Docker image. +# The command below installs Python, pip and the app dependencies. +# The dependencies are in the requirements.txt file. +RUN apk add --update python py-pip +RUN pip install --upgrade pip +RUN pip install -r requirements-test.txt +# EXPOSE instruction opens the port for communicating with the Docker container. +# Flask app uses the port 5000, so you'll expose port 5000. +EXPOSE 5000 +# CMD instruction runs commands like RUN, +# but the commands run when the Docker container launches. +# Only one CMD instruction can be used. +CMD ["python", "sysinfo.py"] diff --git a/requirements-test.txt b/requirements-test.txt index e69de29..fe2d492 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -0,0 +1,34 @@ +coverage +bandit +pytest +pytest-aiohttp +pytest-asyncio +pytest-cov +pytest-coverage +pytest-datafiles +autoflake +black +flake8 +isort +pylint +pylint-exit +autoflake +bandit +certifi +coverage +flake8 +flake8-polyfill +isort +lazy-object-proxy +mccabe +mypy +mypy-extensions +pre-commit +py +pycodestyle +pyflakes +pylint +pyparsing +safety +types-requests +typing-extensions diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..546845a --- /dev/null +++ b/setup.cfg @@ -0,0 +1,16 @@ +[flake8] +extend-ignore = E203 + +[mypy] +follow_imports = silent +strict_optional = True +warn_redundant_casts = True +warn_unused_ignores = True +disallow_any_generics = True +check_untyped_defs = True +no_implicit_reexport = True +disallow_untyped_defs = True +ignore_missing_imports = True + +[mypy-tests.*] +ignore_errors = True diff --git a/setup.py b/setup.py index 87243fd..9f02461 100644 --- a/setup.py +++ b/setup.py @@ -3,11 +3,14 @@ import os import re +import sys from distutils.core import setup from pathlib import Path from setuptools import find_packages, setup +sys.path.append("src") + def find_version(fname): """Attempts to find the version number in the file names fname. Raises RuntimeError if not found. @@ -35,7 +38,7 @@ def requirements(fname): # We use the version to construct the DOWNLOAD_URL. -VERSION = find_version("__init__.py") +VERSION = find_version("src/sysifo/__init__.py") # URL to the repository on Github. REPO_URL = 'https://github.com/peterbay/sysinfo' @@ -74,7 +77,7 @@ def requirements(fname): 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 2.7', ], - package_dir={"": "."}, + package_dir={"": "src"}, packages=find_packages(), install_requires=INSTALL_REQUIRES, include_package_data=True, diff --git a/__init__.py b/src/sysinfo/__init__.py similarity index 100% rename from __init__.py rename to src/sysinfo/__init__.py diff --git a/modules/__init__.py b/src/sysinfo/modules/__init__.py similarity index 100% rename from modules/__init__.py rename to src/sysinfo/modules/__init__.py diff --git a/modules/arp.py b/src/sysinfo/modules/arp.py similarity index 96% rename from modules/arp.py rename to src/sysinfo/modules/arp.py index cbd64e7..1406f3b 100644 --- a/modules/arp.py +++ b/src/sysinfo/modules/arp.py @@ -1,20 +1,20 @@ -import re -from sysinfo_lib import parseTable, tableToDict, camelCase - - -def parser(stdout, stderr, to_camelcase): - output = parseTable( - stdout, - header_pattern=r"^(Address\s+)\s(HWtype\s+)\s(HWaddress\s+)\s(Flags Mask\s+)\s(Iface\s*)", - to_camelcase=to_camelcase, - ) - - return {"output": output, "unprocessed": []} - - -def register(main): - main["arp"] = { - "cmd": """arp""", - "description": "System ARP cache", - "parser": parser, - } +import re +from sysinfo_lib import parseTable, tableToDict, camelCase + + +def parser(stdout, stderr, to_camelcase): + output = parseTable( + stdout, + header_pattern=r"^(Address\s+)\s(HWtype\s+)\s(HWaddress\s+)\s(Flags Mask\s+)\s(Iface\s*)", + to_camelcase=to_camelcase, + ) + + return {"output": output, "unprocessed": []} + + +def register(main): + main["arp"] = { + "cmd": """arp""", + "description": "System ARP cache", + "parser": parser, + } diff --git a/modules/blkid.py b/src/sysinfo/modules/blkid.py similarity index 96% rename from modules/blkid.py rename to src/sysinfo/modules/blkid.py index 1f00422..7046625 100644 --- a/modules/blkid.py +++ b/src/sysinfo/modules/blkid.py @@ -1,35 +1,35 @@ -import re -from sysinfo_lib import camelCase - - -def parser(stdout, stderr, to_camelcase): - output = {} - unprocessed = [] - - if stdout: - device = "" - for line in stdout.splitlines(): - dev = re.search(r"^>>> Device: (\S+)", line) - if dev: - device = dev.group(1) - output[device] = {} - continue - - kv = re.search(r"^(\w[^=]+)=(.*)$", line) - if kv: - key = camelCase(kv.group(1), to_camelcase) - value = kv.group(2) - output[device][key] = value - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["blkid"] = { - "cmd": """blkid -o device | xargs -n 1 -I {} sh -c "echo '>>> Device: {}'; blkid -o export -p {}; blkid -o export -i {}" """, - "description": "Block device attributes", - "parser": parser, - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + device = "" + for line in stdout.splitlines(): + dev = re.search(r"^>>> Device: (\S+)", line) + if dev: + device = dev.group(1) + output[device] = {} + continue + + kv = re.search(r"^(\w[^=]+)=(.*)$", line) + if kv: + key = camelCase(kv.group(1), to_camelcase) + value = kv.group(2) + output[device][key] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["blkid"] = { + "cmd": """blkid -o device | xargs -n 1 -I {} sh -c "echo '>>> Device: {}'; blkid -o export -p {}; blkid -o export -i {}" """, + "description": "Block device attributes", + "parser": parser, + } diff --git a/modules/blockdev.py b/src/sysinfo/modules/blockdev.py similarity index 96% rename from modules/blockdev.py rename to src/sysinfo/modules/blockdev.py index 9dd8ec3..33831f5 100644 --- a/modules/blockdev.py +++ b/src/sysinfo/modules/blockdev.py @@ -1,49 +1,49 @@ -from sysinfo_lib import parseTable, camelCase -import re - - -def parser(stdout, stderr, to_camelcase): - output = {} - if stdout: - output = parseTable(stdout, to_camelcase=to_camelcase) - - return {"output": output, "unprocessed": []} - - -def parser_detail(stdout, stderr, to_camelcase): - output = {} - unprocessed = [] - - if stdout: - device = "" - for line in stdout.splitlines(): - dev = re.search(r"^>>> Device: (\S+)", line) - if dev: - device = dev.group(1) - output[device] = {} - continue - - kv = re.search(r"^get (\w[^:]+): (.*)$", line) - if kv: - key = camelCase(kv.group(1), to_camelcase) - value = kv.group(2) - output[device][key] = value - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["blockdev"] = { - "cmd": "blockdev --report | column -t", - "description": "Block device ioctls", - "parser": parser, - } - - main["blockdev_detail"] = { - "cmd": """blkid -o device | xargs -n 1 -I {} sh -c "echo '>>> Device: {}'; blockdev -v --getalignoff --getbsz --getdiscardzeroes --getfra --getiomin --getioopt --getmaxsect --getpbsz --getra --getro --getsize64 --getss {}" """, - "description": "Block device ioctls details", - "parser": parser_detail, - } +from sysinfo_lib import parseTable, camelCase +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + if stdout: + output = parseTable(stdout, to_camelcase=to_camelcase) + + return {"output": output, "unprocessed": []} + + +def parser_detail(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + device = "" + for line in stdout.splitlines(): + dev = re.search(r"^>>> Device: (\S+)", line) + if dev: + device = dev.group(1) + output[device] = {} + continue + + kv = re.search(r"^get (\w[^:]+): (.*)$", line) + if kv: + key = camelCase(kv.group(1), to_camelcase) + value = kv.group(2) + output[device][key] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["blockdev"] = { + "cmd": "blockdev --report | column -t", + "description": "Block device ioctls", + "parser": parser, + } + + main["blockdev_detail"] = { + "cmd": """blkid -o device | xargs -n 1 -I {} sh -c "echo '>>> Device: {}'; blockdev -v --getalignoff --getbsz --getdiscardzeroes --getfra --getiomin --getioopt --getmaxsect --getpbsz --getra --getro --getsize64 --getss {}" """, + "description": "Block device ioctls details", + "parser": parser_detail, + } diff --git a/modules/busctl.py b/src/sysinfo/modules/busctl.py similarity index 96% rename from modules/busctl.py rename to src/sysinfo/modules/busctl.py index badd141..a0ba1dc 100644 --- a/modules/busctl.py +++ b/src/sysinfo/modules/busctl.py @@ -1,100 +1,100 @@ -import re -from sysinfo_lib import parseTable, camelCase - - -def parser(stdout, stderr, to_camelcase): - output = {} - if stdout: - output = parseTable(stdout, to_camelcase=to_camelcase) - - return {"output": output, "unprocessed": []} - - -def parser_tree(stdout, stderr, to_camelcase): - output = {} - unprocessed = [] - - if stdout: - name = "" - for line in stdout.splitlines(): - header = re.search(r"^(\S+) (.+):", line) - - if header: - name = header.group(2) - output[name] = [] - continue - - tree = re.search(r"^\/(.+)$", line) - if tree and name: - output[name].append(tree.group(1)) - continue - - if line == "" or line == "/": - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def parser_status(stdout, stderr, to_camelcase): - output = {} - key = "" - is_array = False - unprocessed = [] - - if stdout: - device = "" - for line in stdout.splitlines(): - dev = re.search(r"^>>> Device: (\S+)", line) - if dev: - device = dev.group(1) - output[device] = {} - key = "" - is_array = False - continue - - kv = re.search(r"^(\w[^=]+)=(.*)$", line) - if kv: - key = camelCase(kv.group(1), to_camelcase) - value = kv.group(2).strip() - - if re.match(r"^cap_", value): - is_array = True - output[device][key] = value.split(r" ") - print(value.split(r" ")) - - else: - output[device][key] = value - - continue - - cont = re.search(r"^\s\s+(.*)$", line) - if cont and key and is_array: - key = camelCase(key, to_camelcase) - output[device][key] += cont.group(1).strip().split(r" ") - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["busctl"] = { - "cmd": "busctl --no-pager | column -t", - "description": "Introspect the bus", - "parser": parser, - } - - main["busctl_tree"] = { - "cmd": "busctl --no-pager --list tree", - "description": "Object tree for services", - "parser": parser_tree, - } - - main["busctl_status"] = { - "cmd": """busctl list | awk '!/^(NAME)/ {print $1}' | xargs -n 1 -I {} sh -c "echo '>>> Device: {}'; busctl --no-pager status {}" """, - "description": "Process information and credentials of a bus service", - "parser": parser_status, - } +import re +from sysinfo_lib import parseTable, camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + if stdout: + output = parseTable(stdout, to_camelcase=to_camelcase) + + return {"output": output, "unprocessed": []} + + +def parser_tree(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + name = "" + for line in stdout.splitlines(): + header = re.search(r"^(\S+) (.+):", line) + + if header: + name = header.group(2) + output[name] = [] + continue + + tree = re.search(r"^\/(.+)$", line) + if tree and name: + output[name].append(tree.group(1)) + continue + + if line == "" or line == "/": + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def parser_status(stdout, stderr, to_camelcase): + output = {} + key = "" + is_array = False + unprocessed = [] + + if stdout: + device = "" + for line in stdout.splitlines(): + dev = re.search(r"^>>> Device: (\S+)", line) + if dev: + device = dev.group(1) + output[device] = {} + key = "" + is_array = False + continue + + kv = re.search(r"^(\w[^=]+)=(.*)$", line) + if kv: + key = camelCase(kv.group(1), to_camelcase) + value = kv.group(2).strip() + + if re.match(r"^cap_", value): + is_array = True + output[device][key] = value.split(r" ") + print(value.split(r" ")) + + else: + output[device][key] = value + + continue + + cont = re.search(r"^\s\s+(.*)$", line) + if cont and key and is_array: + key = camelCase(key, to_camelcase) + output[device][key] += cont.group(1).strip().split(r" ") + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["busctl"] = { + "cmd": "busctl --no-pager | column -t", + "description": "Introspect the bus", + "parser": parser, + } + + main["busctl_tree"] = { + "cmd": "busctl --no-pager --list tree", + "description": "Object tree for services", + "parser": parser_tree, + } + + main["busctl_status"] = { + "cmd": """busctl list | awk '!/^(NAME)/ {print $1}' | xargs -n 1 -I {} sh -c "echo '>>> Device: {}'; busctl --no-pager status {}" """, + "description": "Process information and credentials of a bus service", + "parser": parser_status, + } diff --git a/modules/chage.py b/src/sysinfo/modules/chage.py similarity index 96% rename from modules/chage.py rename to src/sysinfo/modules/chage.py index cb80519..81d8fa9 100644 --- a/modules/chage.py +++ b/src/sysinfo/modules/chage.py @@ -1,36 +1,36 @@ -import re -from sysinfo_lib import camelCase - - -def parser(stdout, stderr, to_camelcase): - output = {} - unprocessed = [] - user = None - - if stdout: - for line in stdout.splitlines(): - user_match = re.search(r"^>>> User:\s+(.*)$", line) - if user_match: - user = user_match.group(1) - output[user] = {"name": user} - continue - - kv = re.search(r"^([^:]+):\s*(.*)$", line) - if user and kv: - key = camelCase(kv.group(1).strip(), to_camelcase) - value = kv.group(2).strip() - - output[user][key] = value - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["chage"] = { - "cmd": """cat /etc/passwd | awk '{split($0,a,":"); print a[1]}' | xargs -I {} sh -c "echo '>>> User: {}'; chage -l {}" """, - "description": "Users password expiration information", - "parser": parser, - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + user = None + + if stdout: + for line in stdout.splitlines(): + user_match = re.search(r"^>>> User:\s+(.*)$", line) + if user_match: + user = user_match.group(1) + output[user] = {"name": user} + continue + + kv = re.search(r"^([^:]+):\s*(.*)$", line) + if user and kv: + key = camelCase(kv.group(1).strip(), to_camelcase) + value = kv.group(2).strip() + + output[user][key] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["chage"] = { + "cmd": """cat /etc/passwd | awk '{split($0,a,":"); print a[1]}' | xargs -I {} sh -c "echo '>>> User: {}'; chage -l {}" """, + "description": "Users password expiration information", + "parser": parser, + } diff --git a/modules/chrt.py b/src/sysinfo/modules/chrt.py similarity index 96% rename from modules/chrt.py rename to src/sysinfo/modules/chrt.py index 9c46ca1..495193c 100644 --- a/modules/chrt.py +++ b/src/sysinfo/modules/chrt.py @@ -1,52 +1,52 @@ -import re -from sysinfo_lib import camelCase - - -def parser(stdout, stderr, to_camelcase): - output = {} - pid = None - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - - pidSearch = re.search(r"^>>>\s+PID:\s+(\S+)", line) - if pidSearch: - pid = pidSearch.group(1) - output[pid] = {"pid": pid, "scheduling": {}, "current": {}} - continue - - if pid: - sched = re.search(r"^SCHED_(\S+)[^:]+:\s*(\S+)", line) - if sched: - key = camelCase(sched.group(1).strip(), to_camelcase) - value = sched.group(2).strip() - - output[pid]["scheduling"][key] = value - continue - - current = re.search(r"current scheduling (\S+).*:\s*(\S+)", line) - if current: - key = camelCase(current.group(1).strip(), to_camelcase) - value = current.group(2).strip() - - if re.match(r"^SCHED_", value): - value = camelCase(value.replace("SCHED_", ""), to_camelcase) - - output[pid]["current"][key] = value - continue - - if line.strip("-") == "": - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["chrt"] = { - "cmd": """ps -eo pid | grep -vi pid | xargs -I {} sh -c "echo '>>> PID: {}'; chrt -a --pid {}; echo '----'; chrt -m --pid {};" """, - "description": "Scheduling attributes of all the tasks (threads)", - "parser": parser, - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + pid = None + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + + pidSearch = re.search(r"^>>>\s+PID:\s+(\S+)", line) + if pidSearch: + pid = pidSearch.group(1) + output[pid] = {"pid": pid, "scheduling": {}, "current": {}} + continue + + if pid: + sched = re.search(r"^SCHED_(\S+)[^:]+:\s*(\S+)", line) + if sched: + key = camelCase(sched.group(1).strip(), to_camelcase) + value = sched.group(2).strip() + + output[pid]["scheduling"][key] = value + continue + + current = re.search(r"current scheduling (\S+).*:\s*(\S+)", line) + if current: + key = camelCase(current.group(1).strip(), to_camelcase) + value = current.group(2).strip() + + if re.match(r"^SCHED_", value): + value = camelCase(value.replace("SCHED_", ""), to_camelcase) + + output[pid]["current"][key] = value + continue + + if line.strip("-") == "": + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["chrt"] = { + "cmd": """ps -eo pid | grep -vi pid | xargs -I {} sh -c "echo '>>> PID: {}'; chrt -a --pid {}; echo '----'; chrt -m --pid {};" """, + "description": "Scheduling attributes of all the tasks (threads)", + "parser": parser, + } diff --git a/modules/compgen.py b/src/sysinfo/modules/compgen.py similarity index 96% rename from modules/compgen.py rename to src/sysinfo/modules/compgen.py index fb36bfd..c7c0537 100644 --- a/modules/compgen.py +++ b/src/sysinfo/modules/compgen.py @@ -1,65 +1,65 @@ -from sysinfo_lib import sortedList - - -def parser(stdout, stderr, to_camelcase): - if stdout: - return {"output": sortedList(stdout), "unprocessed": []} - - else: - return {} - - -def register(main): - main["shell_alias"] = { - "cmd": '$(which bash) -c "compgen -a"', - "description": "Shell alias names (compgen)", - "parser": parser, - } - - main["shell_builtins"] = { - "cmd": '$(which bash) -c "compgen -b"', - "description": "Names of shell builtin commands (compgen)", - "parser": parser, - } - - main["shell_all_commands"] = { - "cmd": '$(which bash) -c "compgen -c"', - "description": "Shell command names (compgen)", - "parser": parser, - } - - main["shell_exported_variables"] = { - "cmd": '$(which bash) -c "compgen -e"', - "description": "Names of exported shell variables (compgen)", - "parser": parser, - } - - main["shell_variables"] = { - "cmd": '$(which bash) -c "compgen -v"', - "description": "Names of all shell variables (compgen)", - "parser": parser, - } - - main["groups"] = { - "cmd": '$(which bash) -c "compgen -g"', - "description": "Group names (compgen)", - "parser": parser, - } - - main["jobs"] = { - "cmd": '$(which bash) -c "compgen -j"', - "description": "Job names, if job control is active (compgen)", - "parser": parser, - } - - main["services"] = { - "cmd": '$(which bash) -c "compgen -s"', - "description": "Service names (compgen)", - "parser": parser, - } - - main["users"] = { - "cmd": '$(which bash) -c "compgen -u"', - "description": "User names (compgen)", - "parser": parser, - } +from sysinfo_lib import sortedList + + +def parser(stdout, stderr, to_camelcase): + if stdout: + return {"output": sortedList(stdout), "unprocessed": []} + + else: + return {} + + +def register(main): + main["shell_alias"] = { + "cmd": '$(which bash) -c "compgen -a"', + "description": "Shell alias names (compgen)", + "parser": parser, + } + + main["shell_builtins"] = { + "cmd": '$(which bash) -c "compgen -b"', + "description": "Names of shell builtin commands (compgen)", + "parser": parser, + } + + main["shell_all_commands"] = { + "cmd": '$(which bash) -c "compgen -c"', + "description": "Shell command names (compgen)", + "parser": parser, + } + + main["shell_exported_variables"] = { + "cmd": '$(which bash) -c "compgen -e"', + "description": "Names of exported shell variables (compgen)", + "parser": parser, + } + + main["shell_variables"] = { + "cmd": '$(which bash) -c "compgen -v"', + "description": "Names of all shell variables (compgen)", + "parser": parser, + } + + main["groups"] = { + "cmd": '$(which bash) -c "compgen -g"', + "description": "Group names (compgen)", + "parser": parser, + } + + main["jobs"] = { + "cmd": '$(which bash) -c "compgen -j"', + "description": "Job names, if job control is active (compgen)", + "parser": parser, + } + + main["services"] = { + "cmd": '$(which bash) -c "compgen -s"', + "description": "Service names (compgen)", + "parser": parser, + } + + main["users"] = { + "cmd": '$(which bash) -c "compgen -u"', + "description": "User names (compgen)", + "parser": parser, + } diff --git a/modules/dev_disk.py b/src/sysinfo/modules/dev_disk.py similarity index 96% rename from modules/dev_disk.py rename to src/sysinfo/modules/dev_disk.py index df7b5e7..7a759fe 100644 --- a/modules/dev_disk.py +++ b/src/sysinfo/modules/dev_disk.py @@ -1,42 +1,42 @@ -import re - - -def parser(stdout, stderr, to_camelcase): - output = {"all": {}} - unprocessed = [] - - if stdout: - typeName = "" - for line in stdout.splitlines(): - matchType = re.search(r"^\/dev\/disk\/by-(.*):\s*$", line) - if matchType: - typeName = matchType.group(1) - output[typeName] = {} - continue - - matchEntry = re.search(r"\s(\S+)\s+->\s+[\.\/]+(.*)$", line) - if matchEntry and typeName: - key = matchEntry.group(1).strip() - value = matchEntry.group(2).strip() - output[typeName][key] = value - - if not value in output["all"]: - output["all"][value] = {} - - output["all"][value][typeName] = key - continue - - if line == "" or re.match(r"^total", line): - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["dev_disk"] = { - "cmd": "ls -l /dev/disk/by-*", - "description": "Disk devices mapping", - "parser": parser, - } +import re + + +def parser(stdout, stderr, to_camelcase): + output = {"all": {}} + unprocessed = [] + + if stdout: + typeName = "" + for line in stdout.splitlines(): + matchType = re.search(r"^\/dev\/disk\/by-(.*):\s*$", line) + if matchType: + typeName = matchType.group(1) + output[typeName] = {} + continue + + matchEntry = re.search(r"\s(\S+)\s+->\s+[\.\/]+(.*)$", line) + if matchEntry and typeName: + key = matchEntry.group(1).strip() + value = matchEntry.group(2).strip() + output[typeName][key] = value + + if not value in output["all"]: + output["all"][value] = {} + + output["all"][value][typeName] = key + continue + + if line == "" or re.match(r"^total", line): + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["dev_disk"] = { + "cmd": "ls -l /dev/disk/by-*", + "description": "Disk devices mapping", + "parser": parser, + } diff --git a/modules/dev_input.py b/src/sysinfo/modules/dev_input.py similarity index 96% rename from modules/dev_input.py rename to src/sysinfo/modules/dev_input.py index 85f56ab..e71519f 100644 --- a/modules/dev_input.py +++ b/src/sysinfo/modules/dev_input.py @@ -1,42 +1,42 @@ -import re - - -def parser(stdout, stderr, to_camelcase): - output = {"all": {}} - unprocessed = [] - - if stdout: - typeName = "" - for line in stdout.splitlines(): - matchType = re.search(r"^\/dev\/input\/by-(.*):\s*$", line) - if matchType: - typeName = matchType.group(1) - output[typeName] = {} - continue - - matchEntry = re.search(r"\s(\S+)\s+->\s+[\.\/]+(.*)$", line) - if matchEntry and typeName: - key = matchEntry.group(1).strip() - value = matchEntry.group(2).strip() - output[typeName][key] = value - - if not value in output["all"]: - output["all"][value] = {} - - output["all"][value][typeName] = key - continue - - if line == "" or re.match(r"^total", line): - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["dev_input"] = { - "cmd": "ls -l /dev/input/by-*", - "description": "Input devices mapping", - "parser": parser, - } +import re + + +def parser(stdout, stderr, to_camelcase): + output = {"all": {}} + unprocessed = [] + + if stdout: + typeName = "" + for line in stdout.splitlines(): + matchType = re.search(r"^\/dev\/input\/by-(.*):\s*$", line) + if matchType: + typeName = matchType.group(1) + output[typeName] = {} + continue + + matchEntry = re.search(r"\s(\S+)\s+->\s+[\.\/]+(.*)$", line) + if matchEntry and typeName: + key = matchEntry.group(1).strip() + value = matchEntry.group(2).strip() + output[typeName][key] = value + + if not value in output["all"]: + output["all"][value] = {} + + output["all"][value][typeName] = key + continue + + if line == "" or re.match(r"^total", line): + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["dev_input"] = { + "cmd": "ls -l /dev/input/by-*", + "description": "Input devices mapping", + "parser": parser, + } diff --git a/modules/df.py b/src/sysinfo/modules/df.py similarity index 100% rename from modules/df.py rename to src/sysinfo/modules/df.py diff --git a/modules/dmidecode.py b/src/sysinfo/modules/dmidecode.py similarity index 96% rename from modules/dmidecode.py rename to src/sysinfo/modules/dmidecode.py index 94aaa04..57aeddd 100644 --- a/modules/dmidecode.py +++ b/src/sysinfo/modules/dmidecode.py @@ -1,167 +1,167 @@ -import re -from sysinfo_lib import camelCase - - -def parser(stdout, stderr, to_camelcase): - dmiSections = { - "0": "BIOS", - "1": "System", - "2": "Base Board", - "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", - "126": "Disabled entry", - "127": "End of table", - } - handle = None - output = {} - unprocessed = [] - - if stdout: - - # fix multiline - stdout = re.sub(r"\n\t\t", " ", stdout) - - for line in stdout.splitlines(): - if line.strip() == "": - handle = None - - handleSearch = re.search( - r"^Handle\s+([^,]+),\s+DMI type\s+([^,]+),", line, re.IGNORECASE - ) - if handleSearch: - handle = handleSearch.group(1) - dmiType = handleSearch.group(2) - intDmiType = int(dmiType) - - if intDmiType > 127 and intDmiType < 256: - output[handle] = {"__dmiType": dmiType, "__section": "OEM Specific"} - continue - - if dmiType in dmiSections: - output[handle] = { - "__dmiType": dmiType, - "__section": dmiSections[dmiType], - } - continue - - output[handle] = {"__dmiType": dmiType, "__section": "Unknown"} - continue - - if handle and re.match(r"^\S", line): - output[handle]["__type"] = line - continue - - entry = re.search(r"^\s+([^:]+):\s+(.*)$", line) - if handle and entry: - key = camelCase(entry.group(1), to_camelcase) - value = entry.group(2).strip() - - output[handle][key] = value - continue - - if line == "": - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["dmidecode"] = { - "cmd": "dmidecode", - "description": "Dumping all information from DMI (SMBIOS)", - "parser": parser, - } - - main["dmidecode_bios"] = { - "cmd": "dmidecode -t bios", - "description": "Dumping BIOS information from DMI (SMBIOS)", - "parser": parser, - } - - main["dmidecode_system"] = { - "cmd": "dmidecode -t system", - "description": "Dumping SYSTEM information from DMI (SMBIOS)", - "parser": parser, - } - - main["dmidecode_baseboard"] = { - "cmd": "dmidecode -t baseboard", - "description": "Dumping BASEBOARD information from DMI (SMBIOS)", - "parser": parser, - } - - main["dmidecode_chassis"] = { - "cmd": "dmidecode -t chassis", - "description": "Dumping CHASSIS information from DMI (SMBIOS)", - "parser": parser, - } - - main["dmidecode_processor"] = { - "cmd": "dmidecode -t processor", - "description": "Dumping CHASSIS information from DMI (SMBIOS)", - "parser": parser, - } - - main["dmidecode_memory"] = { - "cmd": "dmidecode -t memory", - "description": "Dumping MEMORY information from DMI (SMBIOS)", - "parser": parser, - } - - main["dmidecode_cache"] = { - "cmd": "dmidecode -t cache", - "description": "Dumping CACHE information from DMI (SMBIOS)", - "parser": parser, - } - - main["dmidecode_connector"] = { - "cmd": "dmidecode -t connector", - "description": "Dumping CONNECTOR information from DMI (SMBIOS)", - "parser": parser, - } - - main["dmidecode_slot"] = { - "cmd": "dmidecode -t slot", - "description": "Dumping SLOT information from DMI (SMBIOS)", - "parser": parser, - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + dmiSections = { + "0": "BIOS", + "1": "System", + "2": "Base Board", + "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", + "126": "Disabled entry", + "127": "End of table", + } + handle = None + output = {} + unprocessed = [] + + if stdout: + + # fix multiline + stdout = re.sub(r"\n\t\t", " ", stdout) + + for line in stdout.splitlines(): + if line.strip() == "": + handle = None + + handleSearch = re.search( + r"^Handle\s+([^,]+),\s+DMI type\s+([^,]+),", line, re.IGNORECASE + ) + if handleSearch: + handle = handleSearch.group(1) + dmiType = handleSearch.group(2) + intDmiType = int(dmiType) + + if intDmiType > 127 and intDmiType < 256: + output[handle] = {"__dmiType": dmiType, "__section": "OEM Specific"} + continue + + if dmiType in dmiSections: + output[handle] = { + "__dmiType": dmiType, + "__section": dmiSections[dmiType], + } + continue + + output[handle] = {"__dmiType": dmiType, "__section": "Unknown"} + continue + + if handle and re.match(r"^\S", line): + output[handle]["__type"] = line + continue + + entry = re.search(r"^\s+([^:]+):\s+(.*)$", line) + if handle and entry: + key = camelCase(entry.group(1), to_camelcase) + value = entry.group(2).strip() + + output[handle][key] = value + continue + + if line == "": + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["dmidecode"] = { + "cmd": "dmidecode", + "description": "Dumping all information from DMI (SMBIOS)", + "parser": parser, + } + + main["dmidecode_bios"] = { + "cmd": "dmidecode -t bios", + "description": "Dumping BIOS information from DMI (SMBIOS)", + "parser": parser, + } + + main["dmidecode_system"] = { + "cmd": "dmidecode -t system", + "description": "Dumping SYSTEM information from DMI (SMBIOS)", + "parser": parser, + } + + main["dmidecode_baseboard"] = { + "cmd": "dmidecode -t baseboard", + "description": "Dumping BASEBOARD information from DMI (SMBIOS)", + "parser": parser, + } + + main["dmidecode_chassis"] = { + "cmd": "dmidecode -t chassis", + "description": "Dumping CHASSIS information from DMI (SMBIOS)", + "parser": parser, + } + + main["dmidecode_processor"] = { + "cmd": "dmidecode -t processor", + "description": "Dumping CHASSIS information from DMI (SMBIOS)", + "parser": parser, + } + + main["dmidecode_memory"] = { + "cmd": "dmidecode -t memory", + "description": "Dumping MEMORY information from DMI (SMBIOS)", + "parser": parser, + } + + main["dmidecode_cache"] = { + "cmd": "dmidecode -t cache", + "description": "Dumping CACHE information from DMI (SMBIOS)", + "parser": parser, + } + + main["dmidecode_connector"] = { + "cmd": "dmidecode -t connector", + "description": "Dumping CONNECTOR information from DMI (SMBIOS)", + "parser": parser, + } + + main["dmidecode_slot"] = { + "cmd": "dmidecode -t slot", + "description": "Dumping SLOT information from DMI (SMBIOS)", + "parser": parser, + } diff --git a/modules/dnf.py b/src/sysinfo/modules/dnf.py similarity index 96% rename from modules/dnf.py rename to src/sysinfo/modules/dnf.py index f5e9a07..977561f 100644 --- a/modules/dnf.py +++ b/src/sysinfo/modules/dnf.py @@ -1,81 +1,81 @@ -import re - - -def parser_repolist(stdout, stderr, to_camelcase): - output = {"repos": [], "errors": []} - - insideTable = False - col1 = None - col2 = None - if stdout: - for line in stdout.splitlines(): - tableHeader = re.search( - r"^(repo id\s+)(repo name\s+)status", line, re.IGNORECASE - ) - - if col1 and col2: - tableRow = re.search(r"^(.{%s})(.{%s})(.*)$" % (col1, col2), line) - - if insideTable and tableRow: - output["repos"].append( - { - "repo": tableRow.group(1).strip(), - "repo_name": tableRow.group(2).strip(), - "status": tableRow.group(3).strip(), - } - ) - continue - - if tableHeader: - insideTable = True - col1 = len(tableHeader.group(1)) - col2 = len(tableHeader.group(2)) - - else: - insideTable = False - - if stderr: - for line in stderr.splitlines(): - if re.search(r"http.*error .*", line, re.IGNORECASE): - if not line in output["errors"]: - output["errors"].append(line) - - return {"output": output} - - -def parser_installed(stdout, stderr, to_camelcase): - output = {"packages": [], "errors": []} - if stdout: - for line in stdout.splitlines(): - package = re.search(r"^([\S\.]+)\.(\S+)\s+(\S+\.\S+)\s+(\S+.*)$", line) - if package: - output["packages"].append( - { - "name": package.group(1).strip(), - "arch": package.group(2).strip(), - "version": package.group(3).strip(), - "status": package.group(4).strip(), - } - ) - - if stderr: - for line in stderr.splitlines(): - if re.search(r"http.*error .*", line, re.IGNORECASE): - if not line in output["errors"]: - output["errors"].append(line) - - return {"output": output} - - -def register(main): - main["dnf_repolist"] = { - "cmd": "dnf repolist --all", - "description": "DNF - defined repositories", - "parser": parser_repolist, - } - - main["dnf_installed"] = { - "cmd": "dnf list installed", - "description": "DNF - list installed packages", - "parser": parser_installed, - } +import re + + +def parser_repolist(stdout, stderr, to_camelcase): + output = {"repos": [], "errors": []} + + insideTable = False + col1 = None + col2 = None + if stdout: + for line in stdout.splitlines(): + tableHeader = re.search( + r"^(repo id\s+)(repo name\s+)status", line, re.IGNORECASE + ) + + if col1 and col2: + tableRow = re.search(r"^(.{%s})(.{%s})(.*)$" % (col1, col2), line) + + if insideTable and tableRow: + output["repos"].append( + { + "repo": tableRow.group(1).strip(), + "repo_name": tableRow.group(2).strip(), + "status": tableRow.group(3).strip(), + } + ) + continue + + if tableHeader: + insideTable = True + col1 = len(tableHeader.group(1)) + col2 = len(tableHeader.group(2)) + + else: + insideTable = False + + if stderr: + for line in stderr.splitlines(): + if re.search(r"http.*error .*", line, re.IGNORECASE): + if not line in output["errors"]: + output["errors"].append(line) + + return {"output": output} + + +def parser_installed(stdout, stderr, to_camelcase): + output = {"packages": [], "errors": []} + if stdout: + for line in stdout.splitlines(): + package = re.search(r"^([\S\.]+)\.(\S+)\s+(\S+\.\S+)\s+(\S+.*)$", line) + if package: + output["packages"].append( + { + "name": package.group(1).strip(), + "arch": package.group(2).strip(), + "version": package.group(3).strip(), + "status": package.group(4).strip(), + } + ) + + if stderr: + for line in stderr.splitlines(): + if re.search(r"http.*error .*", line, re.IGNORECASE): + if not line in output["errors"]: + output["errors"].append(line) + + return {"output": output} + + +def register(main): + main["dnf_repolist"] = { + "cmd": "dnf repolist --all", + "description": "DNF - defined repositories", + "parser": parser_repolist, + } + + main["dnf_installed"] = { + "cmd": "dnf list installed", + "description": "DNF - list installed packages", + "parser": parser_installed, + } diff --git a/modules/env.py b/src/sysinfo/modules/env.py similarity index 95% rename from modules/env.py rename to src/sysinfo/modules/env.py index 4749e56..388d416 100644 --- a/modules/env.py +++ b/src/sysinfo/modules/env.py @@ -1,25 +1,25 @@ -import re - - -def parser(stdout, stderr, to_camelcase): - output = {} - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - lineMatch = re.search(r"^([^=]+)=(.*)$", line) - if lineMatch: - output[lineMatch.group(1)] = lineMatch.group(2) - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["env"] = { - "cmd": "env", - "description": "Environment variables", - "parser": parser, - } +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + lineMatch = re.search(r"^([^=]+)=(.*)$", line) + if lineMatch: + output[lineMatch.group(1)] = lineMatch.group(2) + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["env"] = { + "cmd": "env", + "description": "Environment variables", + "parser": parser, + } diff --git a/modules/etc_default.py b/src/sysinfo/modules/etc_default.py similarity index 96% rename from modules/etc_default.py rename to src/sysinfo/modules/etc_default.py index 4ec06f2..a38658e 100644 --- a/modules/etc_default.py +++ b/src/sysinfo/modules/etc_default.py @@ -1,54 +1,54 @@ -import re - - -def setPathValue(data, path, value): - pathRest = None - pathParts = re.search(r"^([^\/]+)\/?(.*)$", path) - if pathParts: - path = pathParts.group(1) - pathRest = pathParts.group(2) - - if not path in data: - data[path] = {} - - if pathRest: - setPathValue(data[path], pathRest, value) - - else: - if isinstance(data[path], dict): - data[path] = [] - data[path].append(value) - - -def parser(stdout, stderr, to_camelcase): - output = {} - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - pathValue = re.search(r"^\/etc\/default\/([^:]+):(.*)$", line) - if pathValue: - path = pathValue.group(1) - value = pathValue.group(2) - if value.strip() == "": - continue - - if not re.search(r"^\s*#", value): - setPathValue(output, path, value) - continue - - if re.match(r"^\s*#", value): - # ignore line with comment - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["etc_default"] = { - "cmd": 'find /etc/default -type f -follow -print | xargs grep ""', - "description": "Default configuration for programs", - "parser": parser, - } +import re + + +def setPathValue(data, path, value): + pathRest = None + pathParts = re.search(r"^([^\/]+)\/?(.*)$", path) + if pathParts: + path = pathParts.group(1) + pathRest = pathParts.group(2) + + if not path in data: + data[path] = {} + + if pathRest: + setPathValue(data[path], pathRest, value) + + else: + if isinstance(data[path], dict): + data[path] = [] + data[path].append(value) + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + pathValue = re.search(r"^\/etc\/default\/([^:]+):(.*)$", line) + if pathValue: + path = pathValue.group(1) + value = pathValue.group(2) + if value.strip() == "": + continue + + if not re.search(r"^\s*#", value): + setPathValue(output, path, value) + continue + + if re.match(r"^\s*#", value): + # ignore line with comment + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["etc_default"] = { + "cmd": 'find /etc/default -type f -follow -print | xargs grep ""', + "description": "Default configuration for programs", + "parser": parser, + } diff --git a/modules/etc_fstab.py b/src/sysinfo/modules/etc_fstab.py similarity index 96% rename from modules/etc_fstab.py rename to src/sysinfo/modules/etc_fstab.py index ec748b6..ff57d23 100644 --- a/modules/etc_fstab.py +++ b/src/sysinfo/modules/etc_fstab.py @@ -1,35 +1,35 @@ -import re - - -def parser(stdout, stderr, to_camelcase): - output = {} - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - if re.match(r"^\s*#", line): - continue - - lineMatch = re.split(r"\s+", line) - if lineMatch and len(lineMatch) > 5: - output[lineMatch[0]] = { - "location": lineMatch[0], - "mountPoint": lineMatch[1], - "type": lineMatch[2], - "security": lineMatch[3], - "dump": lineMatch[4], - "fsckOrder": lineMatch[5], - } - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["etc_fstab"] = { - "cmd": "cat /etc/fstab", - "description": "Filesystems mounted on boot", - "parser": parser, - } +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + if re.match(r"^\s*#", line): + continue + + lineMatch = re.split(r"\s+", line) + if lineMatch and len(lineMatch) > 5: + output[lineMatch[0]] = { + "location": lineMatch[0], + "mountPoint": lineMatch[1], + "type": lineMatch[2], + "security": lineMatch[3], + "dump": lineMatch[4], + "fsckOrder": lineMatch[5], + } + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["etc_fstab"] = { + "cmd": "cat /etc/fstab", + "description": "Filesystems mounted on boot", + "parser": parser, + } diff --git a/modules/etc_group.py b/src/sysinfo/modules/etc_group.py similarity index 96% rename from modules/etc_group.py rename to src/sysinfo/modules/etc_group.py index 74be8c7..15f56d1 100644 --- a/modules/etc_group.py +++ b/src/sysinfo/modules/etc_group.py @@ -1,17 +1,17 @@ -from sysinfo_lib import parseCharDelimitedTable, tableToDict - - -def parser(stdout, stderr, to_camelcase): - columnsNames = ["groupName", "password", "gid", "groupList"] - output = parseCharDelimitedTable(stdout, ":", columnsNames) - output = tableToDict(output, "groupName") - - return {"output": output, "unprocessed": []} - - -def register(main): - main["etc_group"] = { - "cmd": "cat /etc/group", - "description": "Groups essential information", - "parser": parser, - } +from sysinfo_lib import parseCharDelimitedTable, tableToDict + + +def parser(stdout, stderr, to_camelcase): + columnsNames = ["groupName", "password", "gid", "groupList"] + output = parseCharDelimitedTable(stdout, ":", columnsNames) + output = tableToDict(output, "groupName") + + return {"output": output, "unprocessed": []} + + +def register(main): + main["etc_group"] = { + "cmd": "cat /etc/group", + "description": "Groups essential information", + "parser": parser, + } diff --git a/modules/etc_hosts.py b/src/sysinfo/modules/etc_hosts.py similarity index 97% rename from modules/etc_hosts.py rename to src/sysinfo/modules/etc_hosts.py index 6ee525c..55ae435 100644 --- a/modules/etc_hosts.py +++ b/src/sysinfo/modules/etc_hosts.py @@ -1,70 +1,70 @@ -import re - - -def parser(stdout, stderr, to_camelcase): - output = {} - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - values = re.search(r"^\/etc\/([^\:]+):\s*(.*)$", line) - if values: - group = values.group(1) - value = values.group(2).strip() - - if value == "": - continue - - if re.match(r"\s*#", value): - # ignore line with comment - continue - - if group not in output: - output[group] = [] - - if group in ["hosts"]: - parts = re.search(r"^(\S+)\s+([^#]+)#?(.*)$", value) - if parts: - ip = parts.group(1).strip() - hostnames = parts.group(2).strip() - comment = parts.group(3).strip() - - output[group].append( - { - "ip": ip, - "hostnames": re.split(r"\s+", hostnames), - "comment": comment, - } - ) - continue - - if group in ["hosts.allow", "hosts.deny"]: - print("value", value) - parts = re.search(r"^([^:]+):\s*([^:]+):?([^#]+)#?(.*)$", value) - if parts: - daemon_list = parts.group(1).strip().split(",") - client_list = parts.group(2).strip().split(",") - command = parts.group(3).strip() - comment = parts.group(4).strip() - - output[group].append( - { - "daemonList": daemon_list, - "clientList": client_list, - "command": command, - "comment": comment, - } - ) - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["etc_hosts"] = { - "cmd": """grep "" /etc/hosts*""", - "description": "Maps hostnames to IP addresses", - "parser": parser, - } +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + values = re.search(r"^\/etc\/([^\:]+):\s*(.*)$", line) + if values: + group = values.group(1) + value = values.group(2).strip() + + if value == "": + continue + + if re.match(r"\s*#", value): + # ignore line with comment + continue + + if group not in output: + output[group] = [] + + if group in ["hosts"]: + parts = re.search(r"^(\S+)\s+([^#]+)#?(.*)$", value) + if parts: + ip = parts.group(1).strip() + hostnames = parts.group(2).strip() + comment = parts.group(3).strip() + + output[group].append( + { + "ip": ip, + "hostnames": re.split(r"\s+", hostnames), + "comment": comment, + } + ) + continue + + if group in ["hosts.allow", "hosts.deny"]: + print("value", value) + parts = re.search(r"^([^:]+):\s*([^:]+):?([^#]+)#?(.*)$", value) + if parts: + daemon_list = parts.group(1).strip().split(",") + client_list = parts.group(2).strip().split(",") + command = parts.group(3).strip() + comment = parts.group(4).strip() + + output[group].append( + { + "daemonList": daemon_list, + "clientList": client_list, + "command": command, + "comment": comment, + } + ) + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["etc_hosts"] = { + "cmd": """grep "" /etc/hosts*""", + "description": "Maps hostnames to IP addresses", + "parser": parser, + } diff --git a/modules/etc_locale_gen.py b/src/sysinfo/modules/etc_locale_gen.py similarity index 95% rename from modules/etc_locale_gen.py rename to src/sysinfo/modules/etc_locale_gen.py index b1960d0..7ae0d18 100644 --- a/modules/etc_locale_gen.py +++ b/src/sysinfo/modules/etc_locale_gen.py @@ -1,26 +1,26 @@ -import re - - -def parser(stdout, stderr, to_camelcase): - output = [] - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - values = re.search(r"^\s*([^#]+)", line) - if not values: - continue - - value = values.group(1).strip() - if value != "": - output.append(value) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["etc_locale_gen"] = { - "cmd": "cat /etc/locale.gen", - "description": "Configuration file for locale-gen", - "parser": parser, - } +import re + + +def parser(stdout, stderr, to_camelcase): + output = [] + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + values = re.search(r"^\s*([^#]+)", line) + if not values: + continue + + value = values.group(1).strip() + if value != "": + output.append(value) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["etc_locale_gen"] = { + "cmd": "cat /etc/locale.gen", + "description": "Configuration file for locale-gen", + "parser": parser, + } diff --git a/modules/etc_mtab.py b/src/sysinfo/modules/etc_mtab.py similarity index 96% rename from modules/etc_mtab.py rename to src/sysinfo/modules/etc_mtab.py index 6845c16..4972582 100644 --- a/modules/etc_mtab.py +++ b/src/sysinfo/modules/etc_mtab.py @@ -1,46 +1,46 @@ -import re - - -def parse_mount_options(value): - output = {} - for option in re.split(r"\s*,\s*", value): - dir = re.search(r"^([^=]+)=(.*)$", option) - - if dir: - output[dir.group(1)] = dir.group(2).split(":") - - else: - output[option] = True - - return output - - -def parser(stdout, stderr, to_camelcase): - output = {} - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - values = re.split(r"\s+", line) - if len(values) > 5: - output[values[1]] = { - "partition": values[0], - "mountPoint": values[1], - "fileSystem": values[2], - "mountOptions": parse_mount_options(values[3]), - "dump": values[4], - "fsckOrder": values[5], - } - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["etc_mtab"] = { - "cmd": "cat /etc/mtab", - "description": "Currently mounted filesystems", - "parser": parser, - } +import re + + +def parse_mount_options(value): + output = {} + for option in re.split(r"\s*,\s*", value): + dir = re.search(r"^([^=]+)=(.*)$", option) + + if dir: + output[dir.group(1)] = dir.group(2).split(":") + + else: + output[option] = True + + return output + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + values = re.split(r"\s+", line) + if len(values) > 5: + output[values[1]] = { + "partition": values[0], + "mountPoint": values[1], + "fileSystem": values[2], + "mountOptions": parse_mount_options(values[3]), + "dump": values[4], + "fsckOrder": values[5], + } + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["etc_mtab"] = { + "cmd": "cat /etc/mtab", + "description": "Currently mounted filesystems", + "parser": parser, + } diff --git a/modules/etc_passwd.py b/src/sysinfo/modules/etc_passwd.py similarity index 97% rename from modules/etc_passwd.py rename to src/sysinfo/modules/etc_passwd.py index b5dd72d..adbfe9c 100644 --- a/modules/etc_passwd.py +++ b/src/sysinfo/modules/etc_passwd.py @@ -1,16 +1,16 @@ -from sysinfo_lib import parseCharDelimitedTable, tableToDict - - -def parser(stdout, stderr, to_camelcase): - columnsNames = ["username", "password", "uid", "gid", "idInfo", "homeDir", "shell"] - output = parseCharDelimitedTable(stdout, ":", columnsNames) - output = tableToDict(output, "username") - return {"output": output, "unprocessed": []} - - -def register(main): - main["etc_passwd"] = { - "cmd": "cat /etc/passwd", - "description": "Attributes of each user or account on a computer", - "parser": parser, - } +from sysinfo_lib import parseCharDelimitedTable, tableToDict + + +def parser(stdout, stderr, to_camelcase): + columnsNames = ["username", "password", "uid", "gid", "idInfo", "homeDir", "shell"] + output = parseCharDelimitedTable(stdout, ":", columnsNames) + output = tableToDict(output, "username") + return {"output": output, "unprocessed": []} + + +def register(main): + main["etc_passwd"] = { + "cmd": "cat /etc/passwd", + "description": "Attributes of each user or account on a computer", + "parser": parser, + } diff --git a/modules/etc_release.py b/src/sysinfo/modules/etc_release.py similarity index 96% rename from modules/etc_release.py rename to src/sysinfo/modules/etc_release.py index a0aebac..8583b93 100644 --- a/modules/etc_release.py +++ b/src/sysinfo/modules/etc_release.py @@ -1,28 +1,28 @@ -import re -from sysinfo_lib import camelCase - - -def parser(stdout, stderr, to_camelcase): - output = {} - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - values = re.search(r"^([^=]+)=(.*)$", line) - if values: - key = camelCase(values.group(1), to_camelcase) - value = values.group(2).strip().strip('"') - output[key] = value - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["etc_release"] = { - "cmd": "cat /etc/*release", - "description": "OS release info", - "parser": parser, - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + values = re.search(r"^([^=]+)=(.*)$", line) + if values: + key = camelCase(values.group(1), to_camelcase) + value = values.group(2).strip().strip('"') + output[key] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["etc_release"] = { + "cmd": "cat /etc/*release", + "description": "OS release info", + "parser": parser, + } diff --git a/modules/etc_shadow.py b/src/sysinfo/modules/etc_shadow.py similarity index 96% rename from modules/etc_shadow.py rename to src/sysinfo/modules/etc_shadow.py index 4d5529a..30117e6 100644 --- a/modules/etc_shadow.py +++ b/src/sysinfo/modules/etc_shadow.py @@ -1,26 +1,26 @@ -from sysinfo_lib import parseCharDelimitedTable, tableToDict - - -def parser(stdout, stderr, to_camelcase): - columnsNames = [ - "username", - "password", - "lastPasswordChange", - "minimum", - "maximum", - "warn", - "inactive", - "expire", - ] - output = parseCharDelimitedTable(stdout, ":", columnsNames) - output = tableToDict(output, "username") - - return {"output": output, "unprocessed": []} - - -def register(main): - main["etc_shadow"] = { - "cmd": "cat /etc/shadow", - "description": "Shadow database of the passwd file", - "parser": parser, - } +from sysinfo_lib import parseCharDelimitedTable, tableToDict + + +def parser(stdout, stderr, to_camelcase): + columnsNames = [ + "username", + "password", + "lastPasswordChange", + "minimum", + "maximum", + "warn", + "inactive", + "expire", + ] + output = parseCharDelimitedTable(stdout, ":", columnsNames) + output = tableToDict(output, "username") + + return {"output": output, "unprocessed": []} + + +def register(main): + main["etc_shadow"] = { + "cmd": "cat /etc/shadow", + "description": "Shadow database of the passwd file", + "parser": parser, + } diff --git a/modules/etc_timezone.py b/src/sysinfo/modules/etc_timezone.py similarity index 95% rename from modules/etc_timezone.py rename to src/sysinfo/modules/etc_timezone.py index f230423..d975a84 100644 --- a/modules/etc_timezone.py +++ b/src/sysinfo/modules/etc_timezone.py @@ -1,15 +1,15 @@ -def parser(stdout, stderr, to_camelcase): - output = "" - - if stdout: - output = stdout.strip() - - return {"output": output, "unprocessed": []} - - -def register(main): - main["etc_timezone"] = { - "cmd": "cat /etc/timezone", - "description": "Timezone settings", - "parser": parser, - } +def parser(stdout, stderr, to_camelcase): + output = "" + + if stdout: + output = stdout.strip() + + return {"output": output, "unprocessed": []} + + +def register(main): + main["etc_timezone"] = { + "cmd": "cat /etc/timezone", + "description": "Timezone settings", + "parser": parser, + } diff --git a/modules/fbset.py b/src/sysinfo/modules/fbset.py similarity index 97% rename from modules/fbset.py rename to src/sysinfo/modules/fbset.py index 616e39e..32e2718 100644 --- a/modules/fbset.py +++ b/src/sysinfo/modules/fbset.py @@ -1,119 +1,119 @@ -import re - - -def parser(stdout, stderr, to_camelcase): - output = {} - modeName = "" - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - mode = re.search(r'^\s*mode "([^"]+)\s*"$', line) - if mode: - modeName = mode.group(1) - output[modeName] = {} - continue - - endmode = re.search(r"^\s*endmode", line) - if endmode: - modeName = "" - continue - - if modeName: - geometry = re.search( - r"^\s+geometry\s*(\d+)\s*(\d+)\s*(\d+)\s*(\d+)\s*(\d+)\s*$", line - ) - if geometry: - output[modeName]["geometry"] = { - "xres": geometry.group(1), - "yres": geometry.group(2), - "xresVirtual": geometry.group(3), - "yresVirtual": geometry.group(4), - "bitsPerPixel": geometry.group(5), - } - continue - - timings = re.search( - r"^\s+timings\s*(\d+)\s*(\d+)\s*(\d+)\s*(\d+)\s*(\d+)\s*(\d+)\s*(\d+)\s*$", - line, - ) - if timings: - output[modeName]["timings"] = { - "pixclock": timings.group(1), - "leftMargin": timings.group(2), - "rightMargin": timings.group(3), - "upperMargin": timings.group(4), - "lowerMargin": timings.group(5), - "hsyncLen": timings.group(6), - "vsyncLen": timings.group(7), - } - continue - - rgba = re.search( - r"^\s+rgba\s*(\d+)\/(\d+),(\d+)\/(\d+),(\d+)\/(\d+),(\d+)\/(\d+)\s*$", - line, - ) - if rgba: - output[modeName]["rgba"] = { - "redLength": rgba.group(1), - "redOffset": rgba.group(2), - "greenLength": rgba.group(3), - "greenOffset": rgba.group(4), - "blueLength": rgba.group(5), - "blueOffset": rgba.group(6), - "transpLength": rgba.group(7), - "transpOffset": rgba.group(8), - } - continue - - state = re.search( - r"^\s+(interlaced|double|vsync|hsync|csync|extsync)\s+(\S+)\s*$", - line, - ) - if state: - output[modeName][state.group(1)] = state.group(2) - continue - - kv = re.search(r"^\s+(\S+)\s+(.*)$", line) - if kv: - output[modeName][kv.group(1)] = kv.group(2) - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def parserInfo(stdout, stderr, to_camelcase): - output = parser(stdout, stderr, to_camelcase) - output["output"]["info"] = {} - - informationBlock = False - if stdout: - for line in stdout.splitlines(): - info = re.search(r"^\s*Frame buffer device information:\s*$", line) - if info: - informationBlock = True - continue - - if informationBlock: - keyValue = re.search(r"^\s+(\S+)\s*:\s+(.*)\s*$", line) - if keyValue: - output["output"]["info"][keyValue.group(1)] = keyValue.group(2) - continue - - return output - - -def register(main): - main["fbset"] = { - "cmd": "fbset -a", - "description": "Show frame buffer device settings", - "parser": parser, - } - - main["fbset_info"] = { - "cmd": "fbset -i", - "description": "Show frame buffer device information", - "parser": parserInfo, - } +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + modeName = "" + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + mode = re.search(r'^\s*mode "([^"]+)\s*"$', line) + if mode: + modeName = mode.group(1) + output[modeName] = {} + continue + + endmode = re.search(r"^\s*endmode", line) + if endmode: + modeName = "" + continue + + if modeName: + geometry = re.search( + r"^\s+geometry\s*(\d+)\s*(\d+)\s*(\d+)\s*(\d+)\s*(\d+)\s*$", line + ) + if geometry: + output[modeName]["geometry"] = { + "xres": geometry.group(1), + "yres": geometry.group(2), + "xresVirtual": geometry.group(3), + "yresVirtual": geometry.group(4), + "bitsPerPixel": geometry.group(5), + } + continue + + timings = re.search( + r"^\s+timings\s*(\d+)\s*(\d+)\s*(\d+)\s*(\d+)\s*(\d+)\s*(\d+)\s*(\d+)\s*$", + line, + ) + if timings: + output[modeName]["timings"] = { + "pixclock": timings.group(1), + "leftMargin": timings.group(2), + "rightMargin": timings.group(3), + "upperMargin": timings.group(4), + "lowerMargin": timings.group(5), + "hsyncLen": timings.group(6), + "vsyncLen": timings.group(7), + } + continue + + rgba = re.search( + r"^\s+rgba\s*(\d+)\/(\d+),(\d+)\/(\d+),(\d+)\/(\d+),(\d+)\/(\d+)\s*$", + line, + ) + if rgba: + output[modeName]["rgba"] = { + "redLength": rgba.group(1), + "redOffset": rgba.group(2), + "greenLength": rgba.group(3), + "greenOffset": rgba.group(4), + "blueLength": rgba.group(5), + "blueOffset": rgba.group(6), + "transpLength": rgba.group(7), + "transpOffset": rgba.group(8), + } + continue + + state = re.search( + r"^\s+(interlaced|double|vsync|hsync|csync|extsync)\s+(\S+)\s*$", + line, + ) + if state: + output[modeName][state.group(1)] = state.group(2) + continue + + kv = re.search(r"^\s+(\S+)\s+(.*)$", line) + if kv: + output[modeName][kv.group(1)] = kv.group(2) + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def parserInfo(stdout, stderr, to_camelcase): + output = parser(stdout, stderr, to_camelcase) + output["output"]["info"] = {} + + informationBlock = False + if stdout: + for line in stdout.splitlines(): + info = re.search(r"^\s*Frame buffer device information:\s*$", line) + if info: + informationBlock = True + continue + + if informationBlock: + keyValue = re.search(r"^\s+(\S+)\s*:\s+(.*)\s*$", line) + if keyValue: + output["output"]["info"][keyValue.group(1)] = keyValue.group(2) + continue + + return output + + +def register(main): + main["fbset"] = { + "cmd": "fbset -a", + "description": "Show frame buffer device settings", + "parser": parser, + } + + main["fbset_info"] = { + "cmd": "fbset -i", + "description": "Show frame buffer device information", + "parser": parserInfo, + } diff --git a/modules/findmnt.py b/src/sysinfo/modules/findmnt.py similarity index 95% rename from modules/findmnt.py rename to src/sysinfo/modules/findmnt.py index bbb3811..5b9079f 100644 --- a/modules/findmnt.py +++ b/src/sysinfo/modules/findmnt.py @@ -1,36 +1,36 @@ -from sysinfo_lib import parseTable -import re - - -def parse_mount_options(value): - output = {} - for option in re.split(r"\s*,\s*", value): - dir = re.search(r"^([^=]+)=(.*)$", option) - - if dir: - output[dir.group(1)] = dir.group(2).split(":") - - else: - output[option] = True - - return output - - -def parser(stdout, stderr, to_camelcase): - output = {} - if stdout: - output = parseTable(stdout, to_camelcase=to_camelcase) - - for entry in output: - if "options" in entry: - entry["options"] = parse_mount_options(entry["options"]) - - return {"output": output, "unprocessed": []} - - -def register(main): - main["findmnt"] = { - "cmd": "findmnt -Al | column -t", - "description": "List all mounted filesytems", - "parser": parser, - } +from sysinfo_lib import parseTable +import re + + +def parse_mount_options(value): + output = {} + for option in re.split(r"\s*,\s*", value): + dir = re.search(r"^([^=]+)=(.*)$", option) + + if dir: + output[dir.group(1)] = dir.group(2).split(":") + + else: + output[option] = True + + return output + + +def parser(stdout, stderr, to_camelcase): + output = {} + if stdout: + output = parseTable(stdout, to_camelcase=to_camelcase) + + for entry in output: + if "options" in entry: + entry["options"] = parse_mount_options(entry["options"]) + + return {"output": output, "unprocessed": []} + + +def register(main): + main["findmnt"] = { + "cmd": "findmnt -Al | column -t", + "description": "List all mounted filesytems", + "parser": parser, + } diff --git a/modules/free.py b/src/sysinfo/modules/free.py similarity index 96% rename from modules/free.py rename to src/sysinfo/modules/free.py index 9042fd2..cb7dd42 100644 --- a/modules/free.py +++ b/src/sysinfo/modules/free.py @@ -1,39 +1,39 @@ -import re -from sysinfo_lib import camelCase - - -def parser(stdout, stderr, to_camelcase): - output = {} - columns = None - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - if re.search(r"total\s+used", line, re.IGNORECASE): - columns = re.split(r"\s+", line.strip()) - continue - - entrySearch = re.search(r"^([^:]+):\s+(.*)$", line) - if columns and entrySearch: - type = camelCase(entrySearch.group(1), to_camelcase) - output[type] = {} - for idx, value in enumerate( - re.split(r"\s+", entrySearch.group(2).strip()) - ): - if idx < len(columns): - key = camelCase(columns[idx], to_camelcase) - output[type][key] = value - - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["free"] = { - "cmd": "free -b -l -w", - "description": "Amount of free and used memory in the system", - "parser": parser, - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + columns = None + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + if re.search(r"total\s+used", line, re.IGNORECASE): + columns = re.split(r"\s+", line.strip()) + continue + + entrySearch = re.search(r"^([^:]+):\s+(.*)$", line) + if columns and entrySearch: + type = camelCase(entrySearch.group(1), to_camelcase) + output[type] = {} + for idx, value in enumerate( + re.split(r"\s+", entrySearch.group(2).strip()) + ): + if idx < len(columns): + key = camelCase(columns[idx], to_camelcase) + output[type][key] = value + + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["free"] = { + "cmd": "free -b -l -w", + "description": "Amount of free and used memory in the system", + "parser": parser, + } diff --git a/modules/getconf.py b/src/sysinfo/modules/getconf.py similarity index 96% rename from modules/getconf.py rename to src/sysinfo/modules/getconf.py index cd90800..ddd0904 100644 --- a/modules/getconf.py +++ b/src/sysinfo/modules/getconf.py @@ -1,29 +1,29 @@ -import re -from sysinfo_lib import camelCase - - -def parser(stdout, stderr, to_camelcase): - output = {} - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - kv = re.search(r"^(\S+)\s*(.*)$", line) - if kv: - key = camelCase(kv.group(1), to_camelcase) - value = kv.group(2).strip() - - output[key] = value - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["getconf"] = { - "cmd": "getconf -a", - "description": "Configuration variables for the current system and their values", - "parser": parser, - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + kv = re.search(r"^(\S+)\s*(.*)$", line) + if kv: + key = camelCase(kv.group(1), to_camelcase) + value = kv.group(2).strip() + + output[key] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["getconf"] = { + "cmd": "getconf -a", + "description": "Configuration variables for the current system and their values", + "parser": parser, + } diff --git a/modules/hostnamectl.py b/src/sysinfo/modules/hostnamectl.py similarity index 96% rename from modules/hostnamectl.py rename to src/sysinfo/modules/hostnamectl.py index 1b9d637..88b8255 100644 --- a/modules/hostnamectl.py +++ b/src/sysinfo/modules/hostnamectl.py @@ -1,29 +1,29 @@ -import re -from sysinfo_lib import camelCase - - -def parser(stdout, stderr, to_camelcase): - output = {} - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - kv = re.search(r"^([^:]+):\s*(.*)", line) - if kv: - key = camelCase(kv.group(1), to_camelcase) - value = kv.group(2) - - output[key] = value - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["hostnamectl"] = { - "cmd": "hostnamectl status", - "description": "Current system hostname and related information", - "parser": parser, - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + kv = re.search(r"^([^:]+):\s*(.*)", line) + if kv: + key = camelCase(kv.group(1), to_camelcase) + value = kv.group(2) + + output[key] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["hostnamectl"] = { + "cmd": "hostnamectl status", + "description": "Current system hostname and related information", + "parser": parser, + } diff --git a/modules/ifconfig.py b/src/sysinfo/modules/ifconfig.py similarity index 97% rename from modules/ifconfig.py rename to src/sysinfo/modules/ifconfig.py index 5b777ca..b377c58 100644 --- a/modules/ifconfig.py +++ b/src/sysinfo/modules/ifconfig.py @@ -1,86 +1,86 @@ -import re -from sysinfo_lib import camelCase - - -def extractValue(data, line, key, regExp): - search = re.search(regExp, line, re.IGNORECASE) - if search: - data[key] = search.group(1) - return data - - -def extractValues(data, line, to_camelcase): - for pair in re.split(r"\s\s+", line): - desc = re.search(r"^(.*)\((.*)\)$", pair.strip()) - if desc: - data["description"] = desc.group(2) - if desc.group(1): - pair = desc.group(1).strip() - else: - continue - - kv = re.search(r"^([^\s]+)\s(\S.*)$", pair) - if kv: - key = camelCase(kv.group(1), to_camelcase) - value = kv.group(2).strip() - valueFix = re.search(r"^(\S+)\s+(\S+)\s(\S+)$", value) - - if valueFix: - data[key] = valueFix.group(1) - data[valueFix.group(2)] = valueFix.group(3) - else: - data[key] = value - - return extractValues - - -def parser(stdout, stderr, to_camelcase): - output = {} - blockData = {} - unprocessed = [] - - if stdout: - for block in re.split(r"\r\r|\n\n|\r\n\r\n", stdout): - blockData = {"entries": [], "rx": {}, "tx": {}} - - for line in block.splitlines(): - header = re.search(r"^(\S[^:]+):\s*(.*)$", line) - if header: - name = header.group(1) - blockData["name"] = name - extractValue(blockData, line, "flags", r"flags=(\S+)") - extractValues(blockData, header.group(2), to_camelcase) - output[name] = blockData - continue - - rxTx = re.search(r"^\s+([rt]x)\s+(.*)$", line, re.IGNORECASE) - if rxTx: - type = rxTx.group(1).lower() - extractValues(blockData[type], rxTx.group(2), to_camelcase) - continue - - sub = re.search(r"^\s+(\S+)\s\s(.*)$", line, re.IGNORECASE) - if sub: - subData = {"type": sub.group(1)} - extractValues(subData, sub.group(2), to_camelcase) - blockData["entries"].append(subData) - continue - - sub = re.search(r"^\s+(\S+)\s(\S+)\s\s(.*)$", line, re.IGNORECASE) - if sub: - subData = {"type": sub.group(1), "value": sub.group(2)} - extractValues(subData, sub.group(3), to_camelcase) - blockData["entries"].append(subData) - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["ifconfig"] = { - "cmd": "ifconfig -a -v", - "description": "List all interfaces which are currently available, even if down", - "parser": parser, - } +import re +from sysinfo_lib import camelCase + + +def extractValue(data, line, key, regExp): + search = re.search(regExp, line, re.IGNORECASE) + if search: + data[key] = search.group(1) + return data + + +def extractValues(data, line, to_camelcase): + for pair in re.split(r"\s\s+", line): + desc = re.search(r"^(.*)\((.*)\)$", pair.strip()) + if desc: + data["description"] = desc.group(2) + if desc.group(1): + pair = desc.group(1).strip() + else: + continue + + kv = re.search(r"^([^\s]+)\s(\S.*)$", pair) + if kv: + key = camelCase(kv.group(1), to_camelcase) + value = kv.group(2).strip() + valueFix = re.search(r"^(\S+)\s+(\S+)\s(\S+)$", value) + + if valueFix: + data[key] = valueFix.group(1) + data[valueFix.group(2)] = valueFix.group(3) + else: + data[key] = value + + return extractValues + + +def parser(stdout, stderr, to_camelcase): + output = {} + blockData = {} + unprocessed = [] + + if stdout: + for block in re.split(r"\r\r|\n\n|\r\n\r\n", stdout): + blockData = {"entries": [], "rx": {}, "tx": {}} + + for line in block.splitlines(): + header = re.search(r"^(\S[^:]+):\s*(.*)$", line) + if header: + name = header.group(1) + blockData["name"] = name + extractValue(blockData, line, "flags", r"flags=(\S+)") + extractValues(blockData, header.group(2), to_camelcase) + output[name] = blockData + continue + + rxTx = re.search(r"^\s+([rt]x)\s+(.*)$", line, re.IGNORECASE) + if rxTx: + type = rxTx.group(1).lower() + extractValues(blockData[type], rxTx.group(2), to_camelcase) + continue + + sub = re.search(r"^\s+(\S+)\s\s(.*)$", line, re.IGNORECASE) + if sub: + subData = {"type": sub.group(1)} + extractValues(subData, sub.group(2), to_camelcase) + blockData["entries"].append(subData) + continue + + sub = re.search(r"^\s+(\S+)\s(\S+)\s\s(.*)$", line, re.IGNORECASE) + if sub: + subData = {"type": sub.group(1), "value": sub.group(2)} + extractValues(subData, sub.group(3), to_camelcase) + blockData["entries"].append(subData) + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["ifconfig"] = { + "cmd": "ifconfig -a -v", + "description": "List all interfaces which are currently available, even if down", + "parser": parser, + } diff --git a/modules/lsblk.py b/src/sysinfo/modules/lsblk.py similarity index 96% rename from modules/lsblk.py rename to src/sysinfo/modules/lsblk.py index ca06026..1dd7f52 100644 --- a/modules/lsblk.py +++ b/src/sysinfo/modules/lsblk.py @@ -1,38 +1,38 @@ -import re -from sysinfo_lib import camelCase - - -def parser(stdout, stderr, to_camelcase): - output = {} - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - entry = {} - kv = re.findall(r'(\S[^=]+)=\"([^"]*)\"', line) - if kv: - for pair in kv: - key = camelCase(pair[0], to_camelcase) - value = pair[1].strip() - - entry[key] = value - - if "name" in entry: - output[entry["name"]] = entry - continue - - elif "NAME" in entry: - output[entry["NAME"]] = entry - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["lsblk"] = { - "cmd": "lsblk -P -o NAME,KNAME,MAJ:MIN,FSTYPE,MOUNTPOINT,LABEL,UUID,PARTLABEL,PARTUUID,RA,RO,RM,MODEL,SERIAL,SIZE,STATE,OWNER,GROUP,MODE,ALIGNMENT,MIN-IO,OPT-IO,PHY-SEC,LOG-SEC,ROTA,SCHED,RQ-SIZE,TYPE,DISC-ALN,DISC-GRAN,DISC-MAX,DISC-ZERO,WSAME,WWN,RAND,PKNAME,HCTL,TRAN,REV,VENDOR", - "description": "Lists information about all block devices", - "parser": parser, - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + entry = {} + kv = re.findall(r'(\S[^=]+)=\"([^"]*)\"', line) + if kv: + for pair in kv: + key = camelCase(pair[0], to_camelcase) + value = pair[1].strip() + + entry[key] = value + + if "name" in entry: + output[entry["name"]] = entry + continue + + elif "NAME" in entry: + output[entry["NAME"]] = entry + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["lsblk"] = { + "cmd": "lsblk -P -o NAME,KNAME,MAJ:MIN,FSTYPE,MOUNTPOINT,LABEL,UUID,PARTLABEL,PARTUUID,RA,RO,RM,MODEL,SERIAL,SIZE,STATE,OWNER,GROUP,MODE,ALIGNMENT,MIN-IO,OPT-IO,PHY-SEC,LOG-SEC,ROTA,SCHED,RQ-SIZE,TYPE,DISC-ALN,DISC-GRAN,DISC-MAX,DISC-ZERO,WSAME,WWN,RAND,PKNAME,HCTL,TRAN,REV,VENDOR", + "description": "Lists information about all block devices", + "parser": parser, + } diff --git a/modules/lscpu.py b/src/sysinfo/modules/lscpu.py similarity index 96% rename from modules/lscpu.py rename to src/sysinfo/modules/lscpu.py index 49cba41..40399d6 100644 --- a/modules/lscpu.py +++ b/src/sysinfo/modules/lscpu.py @@ -1,30 +1,30 @@ -import re -from sysinfo_lib import camelCase - - -def parser(stdout, stderr, to_camelcase): - output = {} - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - line = re.sub(r"\(s\)", "s", line) - kv = re.search(r"^([^:]+):\s*(.*)", line) - if kv: - key = camelCase(kv.group(1), to_camelcase) - value = kv.group(2) - - output[key] = value - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["lscpu"] = { - "cmd": "lscpu", - "description": "Information about the CPU architecture", - "parser": parser, - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + line = re.sub(r"\(s\)", "s", line) + kv = re.search(r"^([^:]+):\s*(.*)", line) + if kv: + key = camelCase(kv.group(1), to_camelcase) + value = kv.group(2) + + output[key] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["lscpu"] = { + "cmd": "lscpu", + "description": "Information about the CPU architecture", + "parser": parser, + } diff --git a/modules/lsmod.py b/src/sysinfo/modules/lsmod.py similarity index 96% rename from modules/lsmod.py rename to src/sysinfo/modules/lsmod.py index 2ffc99c..31e9f2c 100644 --- a/modules/lsmod.py +++ b/src/sysinfo/modules/lsmod.py @@ -1,38 +1,38 @@ -import re - - -def parser(stdout, stderr, to_camelcase): - output = {} - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - if re.match(r"Module.*Size", line): - continue - - lineMatch = re.search(r"^(^\S+)\s*(\d+)\s*(\d+)\s*(.*)$", line) - if lineMatch: - used_by = lineMatch.group(4).split(",") - if len(used_by) == 1: - if used_by[0] == "": - used_by = [] - - output[lineMatch.group(1)] = { - "module": lineMatch.group(1), - "size": lineMatch.group(2), - "usedNumber": lineMatch.group(3), - "usedBy": used_by, - } - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["lsmod"] = { - "cmd": "lsmod", - "description": "Show the status of modules in the Linux Kernel", - "parser": parser, - } +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + if re.match(r"Module.*Size", line): + continue + + lineMatch = re.search(r"^(^\S+)\s*(\d+)\s*(\d+)\s*(.*)$", line) + if lineMatch: + used_by = lineMatch.group(4).split(",") + if len(used_by) == 1: + if used_by[0] == "": + used_by = [] + + output[lineMatch.group(1)] = { + "module": lineMatch.group(1), + "size": lineMatch.group(2), + "usedNumber": lineMatch.group(3), + "usedBy": used_by, + } + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["lsmod"] = { + "cmd": "lsmod", + "description": "Show the status of modules in the Linux Kernel", + "parser": parser, + } diff --git a/modules/lsns.py b/src/sysinfo/modules/lsns.py similarity index 96% rename from modules/lsns.py rename to src/sysinfo/modules/lsns.py index a573e1a..ff0a4ee 100644 --- a/modules/lsns.py +++ b/src/sysinfo/modules/lsns.py @@ -1,22 +1,22 @@ -from sysinfo_lib import parseTable - - -def parser(stdout, stderr, to_camelcase): - output = {} - - if stdout: - output = parseTable( - stdout, - header_pattern=r"^(\s*NS)(\sTYPE\s+)(\sPATH\s*)(\s\s*NPROCS)(\s*\sPID)(\s*\sPPID)(\s*\sUID)(\sUSER\s*)(\sCOMMAND\s*)", - to_camelcase=to_camelcase, - ) - - return {"output": output, "unprocessed": []} - - -def register(main): - main["lsns"] = { - "cmd": "lsns -o NS,TYPE,PATH,NPROCS,PID,PPID,UID,USER,COMMAND", - "description": "Block device ioctls", - "parser": parser, - } +from sysinfo_lib import parseTable + + +def parser(stdout, stderr, to_camelcase): + output = {} + + if stdout: + output = parseTable( + stdout, + header_pattern=r"^(\s*NS)(\sTYPE\s+)(\sPATH\s*)(\s\s*NPROCS)(\s*\sPID)(\s*\sPPID)(\s*\sUID)(\sUSER\s*)(\sCOMMAND\s*)", + to_camelcase=to_camelcase, + ) + + return {"output": output, "unprocessed": []} + + +def register(main): + main["lsns"] = { + "cmd": "lsns -o NS,TYPE,PATH,NPROCS,PID,PPID,UID,USER,COMMAND", + "description": "Block device ioctls", + "parser": parser, + } diff --git a/modules/lsof.py b/src/sysinfo/modules/lsof.py similarity index 96% rename from modules/lsof.py rename to src/sysinfo/modules/lsof.py index 017417b..d5b9191 100644 --- a/modules/lsof.py +++ b/src/sysinfo/modules/lsof.py @@ -1,105 +1,105 @@ -import re - -opField = { - "a": "accessMode", - "c": "commandName", - "C": "structureShareCount", - "d": "deviceCharacterCode", - "D": "majorMinorDeviceNumber", - "f": "fileDescriptor", - "F": "structureAddress", - "g": "processGroupId", - "G": "flags", - "i": "inodeNumber", - "k": "linkCount", - "K": "taskId", - "l": "lockStatus", - "L": "loginName", - "m": "markerBetweenRepeatedOutput", - "n": "name", - "N": "nodeIdentifier", - "o": "fileOffset", - "p": "processId", - "P": "protocolName", - "r": "rawDeviceNumber", - "R": "parentPid", - "s": "fileSize", - "S": "streamModuleAndDeviceNames", - "t": "fileType", - "T": "tcpTpiInfo", - "u": "userId", - "z": "zoneName", - "Z": "selinuxSecurityContext", -} - -tcptpiField = { - "QR": "readQueueSize", - "QS": "sendQueueSize", - "SO": "socketOptionsAndValues", - "SS": "socketStates", - "ST": "connectionState", - "TF": "tcpFlagsAndValues", - "WR": "windowReadSize", - "WW": "windowWriteSize", -} - - -def parseElements(elements): - global opField - global tcptpiField - output = {} - for el in elements: - ident = el[0:1] - content = el[1:].strip() - - identType = opField.get(ident, ident) - if identType: - if not identType in output: - output[identType] = {} - - if ident == "T": - fifc = (content + "=").split("=") - fifcType = tcptpiField.get(fifc[0], fifc[0]) - - output[identType][fifcType] = fifc[1] - - else: - output[identType] = content - - return output - - -def parser(stdout, stderr, to_camelcase): - output = {} - pid = None - - if stdout: - for line in re.split(r"\x00\n", stdout): - line = re.sub(r"^[\s\x00]*", "", line) - elements = re.split(r"\x00", line) - if not elements: - continue - - first = elements.pop(0) - if first: - ident = first[0:1] - content = first[1:] - - if ident == "p": - pid = content - output[pid] = parseElements(elements) - output[pid]["pid"] = pid - output[pid]["files"] = [] - - if pid and ident == "f": - output[pid]["files"].append(parseElements(elements)) - - return {"output": output, "unprocessed": []} - - -def register(main): - main["lsof"] = { - "cmd": "lsof -F0", - "description": "Information about files opened by processes", - "parser": parser, - } +import re + +opField = { + "a": "accessMode", + "c": "commandName", + "C": "structureShareCount", + "d": "deviceCharacterCode", + "D": "majorMinorDeviceNumber", + "f": "fileDescriptor", + "F": "structureAddress", + "g": "processGroupId", + "G": "flags", + "i": "inodeNumber", + "k": "linkCount", + "K": "taskId", + "l": "lockStatus", + "L": "loginName", + "m": "markerBetweenRepeatedOutput", + "n": "name", + "N": "nodeIdentifier", + "o": "fileOffset", + "p": "processId", + "P": "protocolName", + "r": "rawDeviceNumber", + "R": "parentPid", + "s": "fileSize", + "S": "streamModuleAndDeviceNames", + "t": "fileType", + "T": "tcpTpiInfo", + "u": "userId", + "z": "zoneName", + "Z": "selinuxSecurityContext", +} + +tcptpiField = { + "QR": "readQueueSize", + "QS": "sendQueueSize", + "SO": "socketOptionsAndValues", + "SS": "socketStates", + "ST": "connectionState", + "TF": "tcpFlagsAndValues", + "WR": "windowReadSize", + "WW": "windowWriteSize", +} + + +def parseElements(elements): + global opField + global tcptpiField + output = {} + for el in elements: + ident = el[0:1] + content = el[1:].strip() + + identType = opField.get(ident, ident) + if identType: + if not identType in output: + output[identType] = {} + + if ident == "T": + fifc = (content + "=").split("=") + fifcType = tcptpiField.get(fifc[0], fifc[0]) + + output[identType][fifcType] = fifc[1] + + else: + output[identType] = content + + return output + + +def parser(stdout, stderr, to_camelcase): + output = {} + pid = None + + if stdout: + for line in re.split(r"\x00\n", stdout): + line = re.sub(r"^[\s\x00]*", "", line) + elements = re.split(r"\x00", line) + if not elements: + continue + + first = elements.pop(0) + if first: + ident = first[0:1] + content = first[1:] + + if ident == "p": + pid = content + output[pid] = parseElements(elements) + output[pid]["pid"] = pid + output[pid]["files"] = [] + + if pid and ident == "f": + output[pid]["files"].append(parseElements(elements)) + + return {"output": output, "unprocessed": []} + + +def register(main): + main["lsof"] = { + "cmd": "lsof -F0", + "description": "Information about files opened by processes", + "parser": parser, + } diff --git a/modules/lspci.py b/src/sysinfo/modules/lspci.py similarity index 96% rename from modules/lspci.py rename to src/sysinfo/modules/lspci.py index 9b9bf05..83ee1b3 100644 --- a/modules/lspci.py +++ b/src/sysinfo/modules/lspci.py @@ -1,39 +1,39 @@ -import re -from sysinfo_lib import camelCase - - -def parser(stdout, stderr, to_camelcase): - output = {} - slot = None - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - if line.strip() == "": - continue - - slotSearch = re.search(r"^Slot:\s+(.*)$", line, re.IGNORECASE) - if slotSearch: - slot = slotSearch.group(1).strip() - output[slot] = {} - continue - - kv = re.search(r"^(\S[^:]+):\s+(.*)$", line) - if slot and kv: - key = camelCase(kv.group(1), to_camelcase) - value = kv.group(2).strip() - - output[slot][key] = value - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["lspci"] = { - "cmd": "lspci -mm -vvv", - "description": "List all PCI devices", - "parser": parser, - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + slot = None + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + if line.strip() == "": + continue + + slotSearch = re.search(r"^Slot:\s+(.*)$", line, re.IGNORECASE) + if slotSearch: + slot = slotSearch.group(1).strip() + output[slot] = {} + continue + + kv = re.search(r"^(\S[^:]+):\s+(.*)$", line) + if slot and kv: + key = camelCase(kv.group(1), to_camelcase) + value = kv.group(2).strip() + + output[slot][key] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["lspci"] = { + "cmd": "lspci -mm -vvv", + "description": "List all PCI devices", + "parser": parser, + } diff --git a/modules/lsusb.py b/src/sysinfo/modules/lsusb.py similarity index 96% rename from modules/lsusb.py rename to src/sysinfo/modules/lsusb.py index c8b622d..85578f3 100644 --- a/modules/lsusb.py +++ b/src/sysinfo/modules/lsusb.py @@ -1,136 +1,136 @@ -import re -from sysinfo_lib import camelCase - - -def extractDescriptors(data, lineNumber, offset, to_camelcase): - output = {} - ln = lineNumber - descOffset = 0 - - while ln < len(data): - line = data[ln] - - searchOffset = re.search(r"^(\s*)", line) - if searchOffset: - lineOffset = len(searchOffset.group(1)) - - if lineOffset < offset: - ln -= 1 - break - - searchDesc = re.search(r"^(\s*)(.*Descriptor):\s*$", line, re.IGNORECASE) - if searchDesc: - descOffset = len(searchDesc.group(1)) + 2 - desc, ln = extractDescriptors(data, ln + 1, descOffset, to_camelcase) - name = camelCase(searchDesc.group(2).strip(), to_camelcase) - output[name] = desc - ln += 1 - continue - - searchStatus = re.search(r"^(\s*)(.*Status):\s*(.*)$", line, re.IGNORECASE) - if searchStatus: - statusOffset = len(searchStatus.group(1)) + 2 - desc, ln = extractDescriptors(data, ln + 1, statusOffset, to_camelcase) - name = camelCase(searchStatus.group(2).strip(), to_camelcase) - if searchStatus.group(3).strip() != "": - desc["value"] = searchStatus.group(3).strip() - - if name == "hubPortStatus": - print("desc", desc) - output[name] = desc - ln += 1 - continue - - searchKeyIndexValue = re.search(r"^\s*(\S+)\s+([0-9]+):\s+(.*)$", line) - if searchKeyIndexValue: - key = camelCase(searchKeyIndexValue.group(1), to_camelcase) - number = searchKeyIndexValue.group(2) - value = searchKeyIndexValue.group(3).strip() - - valueSplit = re.search(r"^(\S+)\s+(\S.*)$", value) - if valueSplit: - value = [valueSplit.group(1), valueSplit.group(2)] - - if not key in output: - output[key] = {} - - output[key][number] = value - - ln += 1 - continue - - searchKeyValue = re.search(r"^\s*(\S+)\s+([0-9].*)$", line) - if searchKeyValue: - key = camelCase(searchKeyValue.group(1).strip(":"), to_camelcase) - value = searchKeyValue.group(2).strip() - - valueSplit = re.search(r"^(\S+)\s+(\S.*)$", value) - if valueSplit: - value = [valueSplit.group(1), valueSplit.group(2)] - - if key in output: - output[key] = [output[key], value] - else: - output[key] = value - - ln += 1 - continue - - if not "data" in output: - output["data"] = [] - - output["data"].append(line.strip()) - - ln += 1 - return output, ln - - -def parseBlock(data, to_camelcase): - output = {} - lines = data.split("\n") - - while lines[0].strip() == "": - lines.pop(0) - - firstLine = lines.pop(0) - busDevice = re.search( - r"Bus\s+(\S+)\s+Device\s+([^:]+):\s+ID\s+([^:]+):(\S+)\s*(.*)$", - firstLine, - re.IGNORECASE, - ) - if busDevice: - output["bus"] = busDevice.group(1) - output["device"] = busDevice.group(2) - output["idVendor"] = busDevice.group(3) - output["idProduct"] = busDevice.group(4) - output["vendorProduct"] = busDevice.group(5) - - output["desc"], tmp = extractDescriptors(lines, 0, 0, to_camelcase) - - return output - - -def parser(stdout, stderr, to_camelcase): - output = {} - - if stdout: - delimiter = "-" * 20 - blocks = re.split( - delimiter, re.sub(r"\n\nBus", "\n\n" + delimiter + "Bus", stdout) - ) - if blocks: - for block in blocks: - blockData = parseBlock(block, to_camelcase) - if "bus" in blockData and "device" in blockData: - id = blockData["bus"] + "/" + blockData["device"] - output[id] = blockData - - return {"output": output, "unprocessed": []} - - -def register(main): - main["lsusb"] = { - "cmd": "lsusb -v", - "description": "List USB devices", - "parser": parser, - } +import re +from sysinfo_lib import camelCase + + +def extractDescriptors(data, lineNumber, offset, to_camelcase): + output = {} + ln = lineNumber + descOffset = 0 + + while ln < len(data): + line = data[ln] + + searchOffset = re.search(r"^(\s*)", line) + if searchOffset: + lineOffset = len(searchOffset.group(1)) + + if lineOffset < offset: + ln -= 1 + break + + searchDesc = re.search(r"^(\s*)(.*Descriptor):\s*$", line, re.IGNORECASE) + if searchDesc: + descOffset = len(searchDesc.group(1)) + 2 + desc, ln = extractDescriptors(data, ln + 1, descOffset, to_camelcase) + name = camelCase(searchDesc.group(2).strip(), to_camelcase) + output[name] = desc + ln += 1 + continue + + searchStatus = re.search(r"^(\s*)(.*Status):\s*(.*)$", line, re.IGNORECASE) + if searchStatus: + statusOffset = len(searchStatus.group(1)) + 2 + desc, ln = extractDescriptors(data, ln + 1, statusOffset, to_camelcase) + name = camelCase(searchStatus.group(2).strip(), to_camelcase) + if searchStatus.group(3).strip() != "": + desc["value"] = searchStatus.group(3).strip() + + if name == "hubPortStatus": + print("desc", desc) + output[name] = desc + ln += 1 + continue + + searchKeyIndexValue = re.search(r"^\s*(\S+)\s+([0-9]+):\s+(.*)$", line) + if searchKeyIndexValue: + key = camelCase(searchKeyIndexValue.group(1), to_camelcase) + number = searchKeyIndexValue.group(2) + value = searchKeyIndexValue.group(3).strip() + + valueSplit = re.search(r"^(\S+)\s+(\S.*)$", value) + if valueSplit: + value = [valueSplit.group(1), valueSplit.group(2)] + + if not key in output: + output[key] = {} + + output[key][number] = value + + ln += 1 + continue + + searchKeyValue = re.search(r"^\s*(\S+)\s+([0-9].*)$", line) + if searchKeyValue: + key = camelCase(searchKeyValue.group(1).strip(":"), to_camelcase) + value = searchKeyValue.group(2).strip() + + valueSplit = re.search(r"^(\S+)\s+(\S.*)$", value) + if valueSplit: + value = [valueSplit.group(1), valueSplit.group(2)] + + if key in output: + output[key] = [output[key], value] + else: + output[key] = value + + ln += 1 + continue + + if not "data" in output: + output["data"] = [] + + output["data"].append(line.strip()) + + ln += 1 + return output, ln + + +def parseBlock(data, to_camelcase): + output = {} + lines = data.split("\n") + + while lines[0].strip() == "": + lines.pop(0) + + firstLine = lines.pop(0) + busDevice = re.search( + r"Bus\s+(\S+)\s+Device\s+([^:]+):\s+ID\s+([^:]+):(\S+)\s*(.*)$", + firstLine, + re.IGNORECASE, + ) + if busDevice: + output["bus"] = busDevice.group(1) + output["device"] = busDevice.group(2) + output["idVendor"] = busDevice.group(3) + output["idProduct"] = busDevice.group(4) + output["vendorProduct"] = busDevice.group(5) + + output["desc"], tmp = extractDescriptors(lines, 0, 0, to_camelcase) + + return output + + +def parser(stdout, stderr, to_camelcase): + output = {} + + if stdout: + delimiter = "-" * 20 + blocks = re.split( + delimiter, re.sub(r"\n\nBus", "\n\n" + delimiter + "Bus", stdout) + ) + if blocks: + for block in blocks: + blockData = parseBlock(block, to_camelcase) + if "bus" in blockData and "device" in blockData: + id = blockData["bus"] + "/" + blockData["device"] + output[id] = blockData + + return {"output": output, "unprocessed": []} + + +def register(main): + main["lsusb"] = { + "cmd": "lsusb -v", + "description": "List USB devices", + "parser": parser, + } diff --git a/modules/modinfo.py b/src/sysinfo/modules/modinfo.py similarity index 96% rename from modules/modinfo.py rename to src/sysinfo/modules/modinfo.py index edd5bbd..247c38e 100644 --- a/modules/modinfo.py +++ b/src/sysinfo/modules/modinfo.py @@ -1,39 +1,39 @@ -import re -from sysinfo_lib import camelCase - - -def parser(stdout, stderr, to_camelcase): - output = {} - moduleName = None - unprocessed = [] - - if stdout: - stdout_fix = re.sub(r"\n[\t]+", " ", stdout) - - for line in stdout_fix.splitlines(): - kv = re.search(r"^([^:]+):\s+(.*)$", line) - if kv: - key = kv.group(1) - value = kv.group(2) - - if key == ">>> moduleName": - moduleName = value - output[moduleName] = {} - continue - - if moduleName: - key = camelCase(key, to_camelcase) - output[moduleName][key] = value.strip() - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["modinfo"] = { - "cmd": """lsmod | grep -v "Module" | sed 's/ .*//g' | xargs -I {} -n 1 sh -c "echo '>>> moduleName: {}'; modinfo {}" """, - "description": "Information about a Linux Kernel modules", - "parser": parser, - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + moduleName = None + unprocessed = [] + + if stdout: + stdout_fix = re.sub(r"\n[\t]+", " ", stdout) + + for line in stdout_fix.splitlines(): + kv = re.search(r"^([^:]+):\s+(.*)$", line) + if kv: + key = kv.group(1) + value = kv.group(2) + + if key == ">>> moduleName": + moduleName = value + output[moduleName] = {} + continue + + if moduleName: + key = camelCase(key, to_camelcase) + output[moduleName][key] = value.strip() + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["modinfo"] = { + "cmd": """lsmod | grep -v "Module" | sed 's/ .*//g' | xargs -I {} -n 1 sh -c "echo '>>> moduleName: {}'; modinfo {}" """, + "description": "Information about a Linux Kernel modules", + "parser": parser, + } diff --git a/modules/parted.py b/src/sysinfo/modules/parted.py similarity index 96% rename from modules/parted.py rename to src/sysinfo/modules/parted.py index 4974976..8483f4b 100644 --- a/modules/parted.py +++ b/src/sysinfo/modules/parted.py @@ -1,60 +1,60 @@ -import re - - -def parser(stdout, stderr, to_camelcase): - output = {} - defaultUnit = None - path = None - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - if line.strip() == "": - defaultUnit = None - path = None - continue - - unitSearch = re.search(r"^(\S+);$", line) - if unitSearch: - defaultUnit = unitSearch.group(1) - continue - - lineSplit = (line.strip(";") + (":" * 10)).split(":") - - if defaultUnit and re.search(r"^(\/[^:]+)", line): - path = lineSplit[0] - output[path] = { - "path": lineSplit[0], - "defaultUnit": defaultUnit, - "end": lineSplit[1], - "devType": lineSplit[2], - "sectorSize": lineSplit[3], - "physSectorSize": lineSplit[4], - "ptName": lineSplit[5], - "model": lineSplit[6], - "diskFlags": lineSplit[7], - "table": {}, - } - continue - - if path and re.search(r"^(\d+):", line): - output[path]["table"][lineSplit[0]] = { - "start": lineSplit[1], - "end": lineSplit[2], - "size": lineSplit[3], - "fileSystem": lineSplit[4], - "flags": lineSplit[5], - } - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["parted"] = { - "cmd": "parted -m -l print", - "description": "Lists partition layout on all block devices", - "parser": parser, - } +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + defaultUnit = None + path = None + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + if line.strip() == "": + defaultUnit = None + path = None + continue + + unitSearch = re.search(r"^(\S+);$", line) + if unitSearch: + defaultUnit = unitSearch.group(1) + continue + + lineSplit = (line.strip(";") + (":" * 10)).split(":") + + if defaultUnit and re.search(r"^(\/[^:]+)", line): + path = lineSplit[0] + output[path] = { + "path": lineSplit[0], + "defaultUnit": defaultUnit, + "end": lineSplit[1], + "devType": lineSplit[2], + "sectorSize": lineSplit[3], + "physSectorSize": lineSplit[4], + "ptName": lineSplit[5], + "model": lineSplit[6], + "diskFlags": lineSplit[7], + "table": {}, + } + continue + + if path and re.search(r"^(\d+):", line): + output[path]["table"][lineSplit[0]] = { + "start": lineSplit[1], + "end": lineSplit[2], + "size": lineSplit[3], + "fileSystem": lineSplit[4], + "flags": lineSplit[5], + } + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["parted"] = { + "cmd": "parted -m -l print", + "description": "Lists partition layout on all block devices", + "parser": parser, + } diff --git a/modules/proc_buddyinfo.py b/src/sysinfo/modules/proc_buddyinfo.py similarity index 96% rename from modules/proc_buddyinfo.py rename to src/sysinfo/modules/proc_buddyinfo.py index fdf47ad..500a296 100644 --- a/modules/proc_buddyinfo.py +++ b/src/sysinfo/modules/proc_buddyinfo.py @@ -1,33 +1,33 @@ -import re -from sysinfo_lib import camelCase - - -def parser(stdout, stderr, to_camelcase): - output = {"nodes": {}} - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - row = re.search(r"Node\s([^,]+),\szone\s+(\S+)\s*(.*)$", line) - if row: - node = row.group(1) - zone = row.group(2) - value = re.split(r"\s+", row.group(3).strip()) - - if not node in output["nodes"]: - output["nodes"][node] = {} - - output["nodes"][node][zone] = value - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["proc_buddyinfo"] = { - "cmd": "cat /proc/buddyinfo", - "description": "Memory fragmentation", - "parser": parser, - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {"nodes": {}} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + row = re.search(r"Node\s([^,]+),\szone\s+(\S+)\s*(.*)$", line) + if row: + node = row.group(1) + zone = row.group(2) + value = re.split(r"\s+", row.group(3).strip()) + + if not node in output["nodes"]: + output["nodes"][node] = {} + + output["nodes"][node][zone] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_buddyinfo"] = { + "cmd": "cat /proc/buddyinfo", + "description": "Memory fragmentation", + "parser": parser, + } diff --git a/modules/proc_bus_input.py b/src/sysinfo/modules/proc_bus_input.py similarity index 96% rename from modules/proc_bus_input.py rename to src/sysinfo/modules/proc_bus_input.py index 692aee8..9b4326d 100644 --- a/modules/proc_bus_input.py +++ b/src/sysinfo/modules/proc_bus_input.py @@ -1,82 +1,82 @@ -import re -from sysinfo_lib import camelCase - - -def extract_params(entry, params, to_camelcase): - patterns = [ - r"(\S[^=]+)=(\S+)", - r'(\S[^=]+)=\"([^"]*)\"', - r"(\S[^=]+)=(\s|$)", - ] - - for pattern in patterns: - kv = re.findall(pattern, params) - if kv: - for pair in kv: - key = camelCase(pair[0], to_camelcase) - value = pair[1] - entry[key] = value - - -def parser(stdout, stderr, to_camelcase): - output = {"devices": [], "handlers": {}} - unprocessed = [] - types = { - "I": "deviceId", - "N": "name", - "P": "physicalPath", - "S": "sysfsPath", - "U": "uid", - "H": "inputHandlers", - "B": "bitmaps", - } - - if stdout: - [devices, handlers] = stdout.split(">>> handlers") - - print(devices) - - for block in re.split(r"\r\r|\n\n|\r\n\r\n", devices): - blockData = {} - - for line in block.splitlines(): - parts = re.search(r"^(\w):\s+(.*)$", line) - if parts: - type = parts.group(1).strip() - params = parts.group(2).strip() - - if type in types: - type_label = types[type] - if not type_label in blockData: - blockData[type_label] = {} - - extract_params(blockData[type_label], params, to_camelcase) - - output["devices"].append(blockData) - - for line in handlers.splitlines(): - line = re.sub(r"^N: ", "", line) - - kv = re.findall(r"(\S[^=]+)=(\S+)", line) - if kv: - entry = {} - for pair in kv: - key = camelCase(pair[0], to_camelcase) - value = pair[1] - entry[key] = value - - if "name" in entry: - output["handlers"][entry["name"]] = entry - - if "Name" in entry: - output["handlers"][entry["Name"]] = entry - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["proc_bus_input"] = { - "cmd": 'cat /proc/bus/input/devices; echo ">>> handlers"; cat /proc/bus/input/handlers;', - "description": "Input devices", - "parser": parser, - } +import re +from sysinfo_lib import camelCase + + +def extract_params(entry, params, to_camelcase): + patterns = [ + r"(\S[^=]+)=(\S+)", + r'(\S[^=]+)=\"([^"]*)\"', + r"(\S[^=]+)=(\s|$)", + ] + + for pattern in patterns: + kv = re.findall(pattern, params) + if kv: + for pair in kv: + key = camelCase(pair[0], to_camelcase) + value = pair[1] + entry[key] = value + + +def parser(stdout, stderr, to_camelcase): + output = {"devices": [], "handlers": {}} + unprocessed = [] + types = { + "I": "deviceId", + "N": "name", + "P": "physicalPath", + "S": "sysfsPath", + "U": "uid", + "H": "inputHandlers", + "B": "bitmaps", + } + + if stdout: + [devices, handlers] = stdout.split(">>> handlers") + + print(devices) + + for block in re.split(r"\r\r|\n\n|\r\n\r\n", devices): + blockData = {} + + for line in block.splitlines(): + parts = re.search(r"^(\w):\s+(.*)$", line) + if parts: + type = parts.group(1).strip() + params = parts.group(2).strip() + + if type in types: + type_label = types[type] + if not type_label in blockData: + blockData[type_label] = {} + + extract_params(blockData[type_label], params, to_camelcase) + + output["devices"].append(blockData) + + for line in handlers.splitlines(): + line = re.sub(r"^N: ", "", line) + + kv = re.findall(r"(\S[^=]+)=(\S+)", line) + if kv: + entry = {} + for pair in kv: + key = camelCase(pair[0], to_camelcase) + value = pair[1] + entry[key] = value + + if "name" in entry: + output["handlers"][entry["name"]] = entry + + if "Name" in entry: + output["handlers"][entry["Name"]] = entry + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_bus_input"] = { + "cmd": 'cat /proc/bus/input/devices; echo ">>> handlers"; cat /proc/bus/input/handlers;', + "description": "Input devices", + "parser": parser, + } diff --git a/modules/proc_cgroups.py b/src/sysinfo/modules/proc_cgroups.py similarity index 96% rename from modules/proc_cgroups.py rename to src/sysinfo/modules/proc_cgroups.py index 8d8430e..757cb95 100644 --- a/modules/proc_cgroups.py +++ b/src/sysinfo/modules/proc_cgroups.py @@ -1,24 +1,24 @@ -from sysinfo_lib import parseSpaceTable, tableToDict - - -def parser(stdout, stderr, to_camelcase): - output = {} - - if stdout: - stdout = stdout.replace("#subsys_name", "subsys_name") - - output = parseSpaceTable(stdout, to_camelcase=to_camelcase) - if to_camelcase: - output = tableToDict(output, "subsysName") - else: - output = tableToDict(output, "subsys_name") - - return {"output": output, "unprocessed": []} - - -def register(main): - main["proc_cgroups"] = { - "cmd": "cat /proc/cgroups", - "description": "Control groups", - "parser": parser, - } +from sysinfo_lib import parseSpaceTable, tableToDict + + +def parser(stdout, stderr, to_camelcase): + output = {} + + if stdout: + stdout = stdout.replace("#subsys_name", "subsys_name") + + output = parseSpaceTable(stdout, to_camelcase=to_camelcase) + if to_camelcase: + output = tableToDict(output, "subsysName") + else: + output = tableToDict(output, "subsys_name") + + return {"output": output, "unprocessed": []} + + +def register(main): + main["proc_cgroups"] = { + "cmd": "cat /proc/cgroups", + "description": "Control groups", + "parser": parser, + } diff --git a/modules/proc_cmdline.py b/src/sysinfo/modules/proc_cmdline.py similarity index 96% rename from modules/proc_cmdline.py rename to src/sysinfo/modules/proc_cmdline.py index c2a699b..799c623 100644 --- a/modules/proc_cmdline.py +++ b/src/sysinfo/modules/proc_cmdline.py @@ -1,36 +1,36 @@ -import re -from sysinfo_lib import camelCase - - -def parser(stdout, stderr, to_camelcase): - output = {} - - if stdout: - for kv in re.split(r"[\s\t]+", stdout.strip()): - splitted = re.search(r"^([^=]+)=(.*)$", kv) - if splitted: - key = camelCase(splitted.group(1), to_camelcase) - value = splitted.group(2) - - else: - key = kv - value = "" - - if key in output: - if isinstance(output[key], str): - output[key] = [output[key]] - - output[key].append(value) - - else: - output[key] = value - - return {"output": output, "unprocessed": []} - - -def register(main): - main["proc_cmdline"] = { - "cmd": "cat /proc/cmdline", - "description": "Parameters passed to the kernel at the time it is started", - "parser": parser, - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + + if stdout: + for kv in re.split(r"[\s\t]+", stdout.strip()): + splitted = re.search(r"^([^=]+)=(.*)$", kv) + if splitted: + key = camelCase(splitted.group(1), to_camelcase) + value = splitted.group(2) + + else: + key = kv + value = "" + + if key in output: + if isinstance(output[key], str): + output[key] = [output[key]] + + output[key].append(value) + + else: + output[key] = value + + return {"output": output, "unprocessed": []} + + +def register(main): + main["proc_cmdline"] = { + "cmd": "cat /proc/cmdline", + "description": "Parameters passed to the kernel at the time it is started", + "parser": parser, + } diff --git a/modules/proc_consoles.py b/src/sysinfo/modules/proc_consoles.py similarity index 97% rename from modules/proc_consoles.py rename to src/sysinfo/modules/proc_consoles.py index 8a8b0ec..998cf9f 100644 --- a/modules/proc_consoles.py +++ b/src/sysinfo/modules/proc_consoles.py @@ -1,58 +1,58 @@ -import re - - -def parser(stdout, stderr, to_camelcase): - """ - The columns are: - device name of the device - operations R = can do read operations - W = can do write operations - U = can do unblank - flags E = it is enabled - C = it is preferred console - B = it is primary boot console - p = it is used for printk buffer - b = it is not a TTY but a Braille device - a = it is safe to use when cpu is offline - major:minor major and minor number of the device separated by a colon - """ - - output = {} - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - values = re.search(r"^(\S+)\s+(.*)\s+(\S+):(\S+)", line) - if values: - params = values.group(2).strip() - output[values.group(1)] = { - "device": values.group(1), - "operations": { - "read": "R" in params, - "write": "W" in params, - "unblank": "U" in params, - }, - "flags": { - "enabled": "E" in params, - "preferred": "C" in params, - "primaryBoot": "B" in params, - "printkBuffer": "p" in params, - "braile": "b" in params, - "safeCpuOffline": "a" in params, - }, - "major": values.group(3), - "minor": values.group(4), - } - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["proc_consoles"] = { - "cmd": "cat /proc/consoles", - "description": "Information about current consoles including tty", - "parser": parser, - } +import re + + +def parser(stdout, stderr, to_camelcase): + """ + The columns are: + device name of the device + operations R = can do read operations + W = can do write operations + U = can do unblank + flags E = it is enabled + C = it is preferred console + B = it is primary boot console + p = it is used for printk buffer + b = it is not a TTY but a Braille device + a = it is safe to use when cpu is offline + major:minor major and minor number of the device separated by a colon + """ + + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + values = re.search(r"^(\S+)\s+(.*)\s+(\S+):(\S+)", line) + if values: + params = values.group(2).strip() + output[values.group(1)] = { + "device": values.group(1), + "operations": { + "read": "R" in params, + "write": "W" in params, + "unblank": "U" in params, + }, + "flags": { + "enabled": "E" in params, + "preferred": "C" in params, + "primaryBoot": "B" in params, + "printkBuffer": "p" in params, + "braile": "b" in params, + "safeCpuOffline": "a" in params, + }, + "major": values.group(3), + "minor": values.group(4), + } + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_consoles"] = { + "cmd": "cat /proc/consoles", + "description": "Information about current consoles including tty", + "parser": parser, + } diff --git a/modules/proc_cpuinfo.py b/src/sysinfo/modules/proc_cpuinfo.py similarity index 96% rename from modules/proc_cpuinfo.py rename to src/sysinfo/modules/proc_cpuinfo.py index c97ba77..ff3e449 100644 --- a/modules/proc_cpuinfo.py +++ b/src/sysinfo/modules/proc_cpuinfo.py @@ -1,40 +1,40 @@ -import re -from sysinfo_lib import camelCase - - -def parser(stdout, stderr, to_camelcase): - output = {"processor": {}, "hardware": {}, "oth": {}} - unprocessed = [] - - if stdout: - for block in re.split(r"\r\r|\n\n|\r\n\r\n", stdout): - sub = {} - for line in block.splitlines(): - kv = re.search(r"([^\t]+)\s*:\s*(.*)$", line) - if kv: - key = camelCase(kv.group(1).strip(), to_camelcase) - value = kv.group(2).strip() - - sub[key] = value - continue - - unprocessed.append(line) - - if "processor" in sub: - output["processor"][sub["processor"]] = sub - - elif "hardware" in sub: - output["hardware"] = sub - - else: - output["oth"] = sub - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["proc_cpuinfo"] = { - "cmd": "cat /proc/cpuinfo", - "description": "Type of processor used by your system", - "parser": parser, - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {"processor": {}, "hardware": {}, "oth": {}} + unprocessed = [] + + if stdout: + for block in re.split(r"\r\r|\n\n|\r\n\r\n", stdout): + sub = {} + for line in block.splitlines(): + kv = re.search(r"([^\t]+)\s*:\s*(.*)$", line) + if kv: + key = camelCase(kv.group(1).strip(), to_camelcase) + value = kv.group(2).strip() + + sub[key] = value + continue + + unprocessed.append(line) + + if "processor" in sub: + output["processor"][sub["processor"]] = sub + + elif "hardware" in sub: + output["hardware"] = sub + + else: + output["oth"] = sub + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_cpuinfo"] = { + "cmd": "cat /proc/cpuinfo", + "description": "Type of processor used by your system", + "parser": parser, + } diff --git a/modules/proc_crypto.py b/src/sysinfo/modules/proc_crypto.py similarity index 96% rename from modules/proc_crypto.py rename to src/sysinfo/modules/proc_crypto.py index 6d27263..c2c0a13 100644 --- a/modules/proc_crypto.py +++ b/src/sysinfo/modules/proc_crypto.py @@ -1,34 +1,34 @@ -import re -from sysinfo_lib import camelCase - - -def parser(stdout, stderr, to_camelcase): - output = {} - unprocessed = [] - - if stdout: - for block in re.split(r"\r\r|\n\n|\r\n\r\n", stdout): - sub = {} - for line in block.splitlines(): - kv = re.search(r"([^\t]+)\s*:\s*(.*)$", line) - if kv: - key = camelCase(kv.group(1).strip(), to_camelcase) - value = kv.group(2).strip() - - sub[key] = value - continue - - unprocessed.append(line) - - if "name" in sub: - output[sub["name"]] = sub - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["proc_crypto"] = { - "cmd": "cat /proc/crypto", - "description": "Installed cryptographic ciphers used by the Linux kernel", - "parser": parser, - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for block in re.split(r"\r\r|\n\n|\r\n\r\n", stdout): + sub = {} + for line in block.splitlines(): + kv = re.search(r"([^\t]+)\s*:\s*(.*)$", line) + if kv: + key = camelCase(kv.group(1).strip(), to_camelcase) + value = kv.group(2).strip() + + sub[key] = value + continue + + unprocessed.append(line) + + if "name" in sub: + output[sub["name"]] = sub + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_crypto"] = { + "cmd": "cat /proc/crypto", + "description": "Installed cryptographic ciphers used by the Linux kernel", + "parser": parser, + } diff --git a/modules/proc_devices.py b/src/sysinfo/modules/proc_devices.py similarity index 96% rename from modules/proc_devices.py rename to src/sysinfo/modules/proc_devices.py index b65e691..5ade0d5 100644 --- a/modules/proc_devices.py +++ b/src/sysinfo/modules/proc_devices.py @@ -1,39 +1,39 @@ -import re -from sysinfo_lib import camelCase - - -def parser(stdout, stderr, to_camelcase): - output = {} - deviceType = None - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - dt = re.search(r"^([^:]+):", line) - if dt: - deviceType = camelCase(dt.group(1), to_camelcase) - output[deviceType] = {} - continue - - dv = re.search(r"^\s*(\d+)\s*(.*)$", line) - if dv and deviceType: - id = dv.group(1) - name = dv.group(2) - - if not name in output[deviceType]: - output[deviceType][name] = [] - - output[deviceType][name].append(id) - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["proc_devices"] = { - "cmd": "cat /proc/devices", - "description": "Installed cryptographic ciphers used by the Linux kernel", - "parser": parser, - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + deviceType = None + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + dt = re.search(r"^([^:]+):", line) + if dt: + deviceType = camelCase(dt.group(1), to_camelcase) + output[deviceType] = {} + continue + + dv = re.search(r"^\s*(\d+)\s*(.*)$", line) + if dv and deviceType: + id = dv.group(1) + name = dv.group(2) + + if not name in output[deviceType]: + output[deviceType][name] = [] + + output[deviceType][name].append(id) + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_devices"] = { + "cmd": "cat /proc/devices", + "description": "Installed cryptographic ciphers used by the Linux kernel", + "parser": parser, + } diff --git a/modules/proc_diskstats.py b/src/sysinfo/modules/proc_diskstats.py similarity index 96% rename from modules/proc_diskstats.py rename to src/sysinfo/modules/proc_diskstats.py index 9374451..dd90720 100644 --- a/modules/proc_diskstats.py +++ b/src/sysinfo/modules/proc_diskstats.py @@ -1,47 +1,47 @@ -import re -from sysinfo_lib import camelCase - - -def parser(stdout, stderr, to_camelcase): - output = {} - columnNames = [ - "majorNumber", - "minorNumber", - "deviceName", - "readsCompletedSuccessfully", - "readsMerged", - "sectorsRead", - "timeSpentReading", - "writesCompleted", - "writesMerged", - "sectorsWritten", - "timeSpentWriting", - "IOsCurrentlyInProgress", - "timeSpentDoingIOs", - "weightedTimeSpentDoingIOs", - ] - lenColumnNames = len(columnNames) - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - line = line.strip() - columns = re.split(r"\s+", line) - if columns: - output[columns[2]] = {} - for num, val in enumerate(columns, start=0): - if num < lenColumnNames: - output[columns[2]][columnNames[num]] = val - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["proc_diskstats"] = { - "cmd": "cat /proc/diskstats", - "description": "I/O statistics of block devices", - "parser": parser, - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + columnNames = [ + "majorNumber", + "minorNumber", + "deviceName", + "readsCompletedSuccessfully", + "readsMerged", + "sectorsRead", + "timeSpentReading", + "writesCompleted", + "writesMerged", + "sectorsWritten", + "timeSpentWriting", + "IOsCurrentlyInProgress", + "timeSpentDoingIOs", + "weightedTimeSpentDoingIOs", + ] + lenColumnNames = len(columnNames) + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + line = line.strip() + columns = re.split(r"\s+", line) + if columns: + output[columns[2]] = {} + for num, val in enumerate(columns, start=0): + if num < lenColumnNames: + output[columns[2]][columnNames[num]] = val + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_diskstats"] = { + "cmd": "cat /proc/diskstats", + "description": "I/O statistics of block devices", + "parser": parser, + } diff --git a/modules/proc_dma.py b/src/sysinfo/modules/proc_dma.py similarity index 95% rename from modules/proc_dma.py rename to src/sysinfo/modules/proc_dma.py index 85f95ff..629a288 100644 --- a/modules/proc_dma.py +++ b/src/sysinfo/modules/proc_dma.py @@ -1,28 +1,28 @@ -import re - - -def parser(stdout, stderr, to_camelcase): - output = {} - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - kv = re.search(r"^\s*([^:]+):\s*(.*)$", line) - if kv: - key = kv.group(1).strip() - value = kv.group(2).strip() - - output[key] = value - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["proc_dma"] = { - "cmd": "cat /proc/dma", - "description": "List of the registered ISA DMA channels in use", - "parser": parser, - } +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + kv = re.search(r"^\s*([^:]+):\s*(.*)$", line) + if kv: + key = kv.group(1).strip() + value = kv.group(2).strip() + + output[key] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_dma"] = { + "cmd": "cat /proc/dma", + "description": "List of the registered ISA DMA channels in use", + "parser": parser, + } diff --git a/modules/proc_filesystems.py b/src/sysinfo/modules/proc_filesystems.py similarity index 96% rename from modules/proc_filesystems.py rename to src/sysinfo/modules/proc_filesystems.py index 11d5903..c192a48 100644 --- a/modules/proc_filesystems.py +++ b/src/sysinfo/modules/proc_filesystems.py @@ -1,33 +1,33 @@ -import re - - -def parser(stdout, stderr, to_camelcase): - output = {} - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - kv = re.search(r"^(\S+)\s+(\S+)", line) - if kv: - key = kv.group(2).strip() - value = kv.group(1).strip() - - output[key] = value - continue - - k = re.search(r"^\s+(\S+)$", line) - if k: - output[k.group(1).strip()] = "" - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["proc_filesystems"] = { - "cmd": "cat /proc/filesystems", - "description": "List of the file system types currently supported by the kernel", - "parser": parser, - } +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + kv = re.search(r"^(\S+)\s+(\S+)", line) + if kv: + key = kv.group(2).strip() + value = kv.group(1).strip() + + output[key] = value + continue + + k = re.search(r"^\s+(\S+)$", line) + if k: + output[k.group(1).strip()] = "" + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_filesystems"] = { + "cmd": "cat /proc/filesystems", + "description": "List of the file system types currently supported by the kernel", + "parser": parser, + } diff --git a/modules/proc_fs.py b/src/sysinfo/modules/proc_fs.py similarity index 96% rename from modules/proc_fs.py rename to src/sysinfo/modules/proc_fs.py index c06a1d1..6be60fd 100644 --- a/modules/proc_fs.py +++ b/src/sysinfo/modules/proc_fs.py @@ -1,56 +1,56 @@ -import re -from sysinfo_lib import camelCase - - -def setPathValue(data, path, value): - pathRest = None - pathParts = re.search(r"^([^\/]+)\/?(.*)$", path) - if pathParts: - path = camelCase(pathParts.group(1)) - pathRest = pathParts.group(2) - - if not path in data: - data[path] = {} - - if pathRest: - setPathValue(data[path], pathRest, value) - - else: - path = camelCase(path) - if isinstance(data[path], dict): - data[path] = [] - - data[path].append(value) - - -def parser(stdout, stderr, to_camelcase): - output = {} - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - pathValue = re.search(r"^\/proc\/fs\/([^:]+):(.*)$", line) - if pathValue: - path = pathValue.group(1) - value = pathValue.group(2) - - print(path, value) - # if not re.search(r"^\s*#", value): - # setPathValue(output, path, value) - - # continue - - # else: - # print(line) - - # unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["proc_fs"] = { - "cmd": """find /proc/fs -type f -follow -print | xargs grep "" """, - "description": "File system parameters", - "parser": parser, - } +import re +from sysinfo_lib import camelCase + + +def setPathValue(data, path, value): + pathRest = None + pathParts = re.search(r"^([^\/]+)\/?(.*)$", path) + if pathParts: + path = camelCase(pathParts.group(1)) + pathRest = pathParts.group(2) + + if not path in data: + data[path] = {} + + if pathRest: + setPathValue(data[path], pathRest, value) + + else: + path = camelCase(path) + if isinstance(data[path], dict): + data[path] = [] + + data[path].append(value) + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + pathValue = re.search(r"^\/proc\/fs\/([^:]+):(.*)$", line) + if pathValue: + path = pathValue.group(1) + value = pathValue.group(2) + + print(path, value) + # if not re.search(r"^\s*#", value): + # setPathValue(output, path, value) + + # continue + + # else: + # print(line) + + # unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_fs"] = { + "cmd": """find /proc/fs -type f -follow -print | xargs grep "" """, + "description": "File system parameters", + "parser": parser, + } diff --git a/modules/proc_iomem.py b/src/sysinfo/modules/proc_iomem.py similarity index 96% rename from modules/proc_iomem.py rename to src/sysinfo/modules/proc_iomem.py index 6edfdfe..27baba3 100644 --- a/modules/proc_iomem.py +++ b/src/sysinfo/modules/proc_iomem.py @@ -1,31 +1,31 @@ -import re - - -def parser(stdout, stderr, to_camelcase): - output = [] - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - values = re.search(r"^\s*([^-]+)-(\S+)\s*:\s*(.*)$", line) - if values: - output.append( - { - "from": values.group(1), - "to": values.group(2), - "device": values.group(3), - } - ) - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["proc_iomem"] = { - "cmd": "cat /proc/iomem", - "description": """Map of the system's memory for each physical device""", - "parser": parser, - } +import re + + +def parser(stdout, stderr, to_camelcase): + output = [] + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + values = re.search(r"^\s*([^-]+)-(\S+)\s*:\s*(.*)$", line) + if values: + output.append( + { + "from": values.group(1), + "to": values.group(2), + "device": values.group(3), + } + ) + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_iomem"] = { + "cmd": "cat /proc/iomem", + "description": """Map of the system's memory for each physical device""", + "parser": parser, + } diff --git a/modules/proc_ioports.py b/src/sysinfo/modules/proc_ioports.py similarity index 96% rename from modules/proc_ioports.py rename to src/sysinfo/modules/proc_ioports.py index 580993c..bdc145e 100644 --- a/modules/proc_ioports.py +++ b/src/sysinfo/modules/proc_ioports.py @@ -1,33 +1,33 @@ -import re - - -def parser(stdout, stderr, to_camelcase): - output = [] - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - entrySearch = re.search( - r"^\s*([^-]+)-(\S+)\s*:\s*(.*)$", line, re.IGNORECASE - ) - if entrySearch: - output.append( - { - "from": entrySearch.group(1), - "to": entrySearch.group(2), - "device": entrySearch.group(3), - } - ) - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["proc_ioports"] = { - "cmd": "cat /proc/ioports", - "description": "List of currently registered port regions used for input or output communication with a device", - "parser": parser, - } +import re + + +def parser(stdout, stderr, to_camelcase): + output = [] + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + entrySearch = re.search( + r"^\s*([^-]+)-(\S+)\s*:\s*(.*)$", line, re.IGNORECASE + ) + if entrySearch: + output.append( + { + "from": entrySearch.group(1), + "to": entrySearch.group(2), + "device": entrySearch.group(3), + } + ) + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_ioports"] = { + "cmd": "cat /proc/ioports", + "description": "List of currently registered port regions used for input or output communication with a device", + "parser": parser, + } diff --git a/modules/proc_loadavg.py b/src/sysinfo/modules/proc_loadavg.py similarity index 96% rename from modules/proc_loadavg.py rename to src/sysinfo/modules/proc_loadavg.py index 80bf8ce..9b467ee 100644 --- a/modules/proc_loadavg.py +++ b/src/sysinfo/modules/proc_loadavg.py @@ -1,30 +1,30 @@ -import re - - -def parser(stdout, stderr, to_camelcase): - output = {} - unprocessed = [] - - if stdout: - values = re.search(r"^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)", stdout.strip()) - if values: - output = { - "periodLast": values.group(1), - "period5minute": values.group(2), - "period15minute": values.group(3), - "processes": values.group(4), - "lastPid": values.group(5), - } - - else: - unprocessed.append(stdout) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["proc_loadavg"] = { - "cmd": "cat /proc/loadavg", - "description": "Load average in regard to both the CPU and IO over time", - "parser": parser, - } +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + values = re.search(r"^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)", stdout.strip()) + if values: + output = { + "periodLast": values.group(1), + "period5minute": values.group(2), + "period15minute": values.group(3), + "processes": values.group(4), + "lastPid": values.group(5), + } + + else: + unprocessed.append(stdout) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_loadavg"] = { + "cmd": "cat /proc/loadavg", + "description": "Load average in regard to both the CPU and IO over time", + "parser": parser, + } diff --git a/modules/proc_locks.py b/src/sysinfo/modules/proc_locks.py similarity index 96% rename from modules/proc_locks.py rename to src/sysinfo/modules/proc_locks.py index 38d97e0..5127c57 100644 --- a/modules/proc_locks.py +++ b/src/sysinfo/modules/proc_locks.py @@ -1,33 +1,33 @@ -import re - - -def parser(stdout, stderr, to_camelcase): - output = {} - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - lineSplit = re.split(r"[\s\t]+", line) - if lineSplit and len(lineSplit) > 5: - output[lineSplit[0]] = { - "uid": lineSplit[0], - "class": lineSplit[1], - "lockType": lineSplit[2], - "allowAccessType": lineSplit[3], - "pid": lineSplit[4], - "fileID": lineSplit[5], - "lockedRegion": lineSplit[6], - } - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["proc_locks"] = { - "cmd": "cat /proc/locks", - "description": "Files currently locked by the kernel", - "parser": parser, - } +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + lineSplit = re.split(r"[\s\t]+", line) + if lineSplit and len(lineSplit) > 5: + output[lineSplit[0]] = { + "uid": lineSplit[0], + "class": lineSplit[1], + "lockType": lineSplit[2], + "allowAccessType": lineSplit[3], + "pid": lineSplit[4], + "fileID": lineSplit[5], + "lockedRegion": lineSplit[6], + } + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_locks"] = { + "cmd": "cat /proc/locks", + "description": "Files currently locked by the kernel", + "parser": parser, + } diff --git a/modules/proc_meminfo.py b/src/sysinfo/modules/proc_meminfo.py similarity index 96% rename from modules/proc_meminfo.py rename to src/sysinfo/modules/proc_meminfo.py index e71f48a..f6a2183 100644 --- a/modules/proc_meminfo.py +++ b/src/sysinfo/modules/proc_meminfo.py @@ -1,37 +1,37 @@ -import re -from sysinfo_lib import camelCase - - -def parser(stdout, stderr, to_camelcase): - output = {} - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - kv = re.search(r"^([^:]+):\s*(.*)$", line, re.IGNORECASE) - if kv: - key = camelCase(kv.group(1).strip(":"), to_camelcase) - value = kv.group(2).strip() - - valueSearch = re.search(r"(.*)\s+(.*)$", value) - if valueSearch: - output[key] = { - "value": valueSearch.group(1), - "type": valueSearch.group(2), - } - else: - output[key] = {"value": value, "type": ""} - - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": []} - - -def register(main): - main["proc_meminfo"] = { - "cmd": "cat /proc/meminfo", - "description": "Reports a large amount of valuable information about the systems RAM usage", - "parser": parser, - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + kv = re.search(r"^([^:]+):\s*(.*)$", line, re.IGNORECASE) + if kv: + key = camelCase(kv.group(1).strip(":"), to_camelcase) + value = kv.group(2).strip() + + valueSearch = re.search(r"(.*)\s+(.*)$", value) + if valueSearch: + output[key] = { + "value": valueSearch.group(1), + "type": valueSearch.group(2), + } + else: + output[key] = {"value": value, "type": ""} + + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": []} + + +def register(main): + main["proc_meminfo"] = { + "cmd": "cat /proc/meminfo", + "description": "Reports a large amount of valuable information about the systems RAM usage", + "parser": parser, + } diff --git a/modules/proc_modules.py b/src/sysinfo/modules/proc_modules.py similarity index 96% rename from modules/proc_modules.py rename to src/sysinfo/modules/proc_modules.py index 1fa121a..6d7110d 100644 --- a/modules/proc_modules.py +++ b/src/sysinfo/modules/proc_modules.py @@ -1,32 +1,32 @@ -import re - - -def parser(stdout, stderr, to_camelcase): - output = {} - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - lineSplit = re.split(r"[\s\t]+", line) - if lineSplit and len(lineSplit) > 5: - output[lineSplit[0]] = { - "moduleName": lineSplit[0], - "moduleMemorySize": lineSplit[1], - "numInstancesLoaded": lineSplit[2], - "depends": lineSplit[3].strip(",").split(","), - "state": lineSplit[4], - "kernelMemoryOffset": lineSplit[5], - } - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["proc_modules"] = { - "cmd": "cat /proc/modules", - "description": "List of all modules loaded into the kernel", - "parser": parser, - } +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + lineSplit = re.split(r"[\s\t]+", line) + if lineSplit and len(lineSplit) > 5: + output[lineSplit[0]] = { + "moduleName": lineSplit[0], + "moduleMemorySize": lineSplit[1], + "numInstancesLoaded": lineSplit[2], + "depends": lineSplit[3].strip(",").split(","), + "state": lineSplit[4], + "kernelMemoryOffset": lineSplit[5], + } + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_modules"] = { + "cmd": "cat /proc/modules", + "description": "List of all modules loaded into the kernel", + "parser": parser, + } diff --git a/modules/proc_mounts.py b/src/sysinfo/modules/proc_mounts.py similarity index 96% rename from modules/proc_mounts.py rename to src/sysinfo/modules/proc_mounts.py index dd46a25..71b90e5 100644 --- a/modules/proc_mounts.py +++ b/src/sysinfo/modules/proc_mounts.py @@ -1,35 +1,35 @@ -import re - - -def parser(stdout, stderr, to_camelcase): - output = {} - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - lineSplit = re.split(r"[\s\t]+", line) - if lineSplit and len(lineSplit) > 4: - accessValues = {} - for access in re.split(r",", lineSplit[3]): - accessSplit = re.split(r"=", access + "=") - accessValues[accessSplit[0]] = accessSplit[1] - - output[lineSplit[1]] = { - "device": lineSplit[0], - "mountPoint": lineSplit[1], - "type": lineSplit[2], - "access": accessValues, - } - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["proc_mounts"] = { - "cmd": "cat /proc/mounts", - "description": "List mounted filesystems (info provides from kernel)", - "parser": parser, - } +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + lineSplit = re.split(r"[\s\t]+", line) + if lineSplit and len(lineSplit) > 4: + accessValues = {} + for access in re.split(r",", lineSplit[3]): + accessSplit = re.split(r"=", access + "=") + accessValues[accessSplit[0]] = accessSplit[1] + + output[lineSplit[1]] = { + "device": lineSplit[0], + "mountPoint": lineSplit[1], + "type": lineSplit[2], + "access": accessValues, + } + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_mounts"] = { + "cmd": "cat /proc/mounts", + "description": "List mounted filesystems (info provides from kernel)", + "parser": parser, + } diff --git a/modules/proc_net.py b/src/sysinfo/modules/proc_net.py similarity index 96% rename from modules/proc_net.py rename to src/sysinfo/modules/proc_net.py index 9ed3f67..339aa89 100644 --- a/modules/proc_net.py +++ b/src/sysinfo/modules/proc_net.py @@ -1,146 +1,146 @@ -import struct -import socket -from sysinfo_lib import parseSpaceTable, tableToDict - - -def parser_route(stdout, stderr, to_camelcase): - output = {} - - if stdout: - output = parseSpaceTable(stdout, to_camelcase=to_camelcase) - if to_camelcase: - output = tableToDict(output, "iface") - else: - output = tableToDict(output, "Iface") - - return {"output": output, "unprocessed": []} - - -def split_every_n(data, n): - return [data[i : i + n] for i in range(0, len(data), n)] - - -def parse_ipv4_address(address): - hex_addr, hex_port = address.split(":") - - addr_list = split_every_n(hex_addr, 2) - addr_list.reverse() - addr = ".".join(map(lambda x: str(int(x, 16)), addr_list)) - port = str(int(hex_port, 16)) - - return addr, port - - -def parse_ipv6_address(address): - hex_addr, hex_port = address.split(":") - - addr = bytes.fromhex(hex_addr) - addr = struct.unpack(">IIII", addr) - addr = struct.pack("@IIII", *addr) - addr = socket.inet_ntop(socket.AF_INET6, addr) - port = str(int(hex_port, 16)) - - return addr, port - - -def extend_address4(entry, name, name_addr, name_port): - if name in entry: - address, port = parse_ipv4_address(entry[name]) - entry[name_addr] = address - entry[name_port] = port - - -def extend_address6(entry, name, name_addr, name_port): - if name in entry: - address, port = parse_ipv6_address(entry[name]) - entry[name_addr] = address - entry[name_port] = port - - -def parser_tcp_udp(stdout, stderr, to_camelcase): - output = {} - - if stdout: - output = parseSpaceTable(stdout, to_camelcase=to_camelcase) - - for entry in output: - extend_address4(entry, "local_address", "local_addr", "local_port") - extend_address4(entry, "rem_address", "rem_addr", "rem_port") - extend_address4(entry, "localAddress", "localAddr", "localPort") - extend_address4(entry, "remAddress", "remAddr", "remPort") - - return {"output": output, "unprocessed": []} - - -def parser_tcp_udp_6(stdout, stderr, to_camelcase): - output = {} - - if stdout: - output = parseSpaceTable(stdout, to_camelcase=to_camelcase) - - for entry in output: - extend_address6(entry, "local_address", "local_addr", "local_port") - extend_address6(entry, "rem_address", "rem_addr", "rem_port") - extend_address6(entry, "localAddress", "localAddr", "localPort") - extend_address6(entry, "remAddress", "remAddr", "remPort") - - return {"output": output, "unprocessed": []} - - -def parser_arp(stdout, stderr, to_camelcase): - output = {} - - if stdout: - output = parseSpaceTable(stdout, to_camelcase=to_camelcase) - - return {"output": output, "unprocessed": []} - - -def register(main): - main["proc_net_route"] = { - "cmd": "cat /proc/net/route", - "description": "IP routing information", - "parser": parser_route, - } - - main["proc_net_ax25_route"] = { - "cmd": "cat /proc/net/ax25_route", - "description": "AX25 routing information", - "parser": parser_route, - } - - main["proc_net_ipx_route"] = { - "cmd": "cat /proc/net/ipx_route", - "description": "IPX routing information", - "parser": parser_route, - } - - main["proc_net_tcp"] = { - "cmd": "cat /proc/net/tcp", - "description": "TCP socket table", - "parser": parser_tcp_udp, - } - - main["proc_net_udp"] = { - "cmd": "cat /proc/net/udp", - "description": "UDP socket table", - "parser": parser_tcp_udp, - } - - main["proc_net_tcp6"] = { - "cmd": "cat /proc/net/tcp6", - "description": "TCP6 socket table", - "parser": parser_tcp_udp_6, - } - - main["proc_net_udp6"] = { - "cmd": "cat /proc/net/udp6", - "description": "UDP6 socket table", - "parser": parser_tcp_udp_6, - } - - main["proc_net_arp"] = { - "cmd": "cat /proc/net/arp", - "description": "ARP ", - "parser": parser_arp, - } +import struct +import socket +from sysinfo_lib import parseSpaceTable, tableToDict + + +def parser_route(stdout, stderr, to_camelcase): + output = {} + + if stdout: + output = parseSpaceTable(stdout, to_camelcase=to_camelcase) + if to_camelcase: + output = tableToDict(output, "iface") + else: + output = tableToDict(output, "Iface") + + return {"output": output, "unprocessed": []} + + +def split_every_n(data, n): + return [data[i : i + n] for i in range(0, len(data), n)] + + +def parse_ipv4_address(address): + hex_addr, hex_port = address.split(":") + + addr_list = split_every_n(hex_addr, 2) + addr_list.reverse() + addr = ".".join(map(lambda x: str(int(x, 16)), addr_list)) + port = str(int(hex_port, 16)) + + return addr, port + + +def parse_ipv6_address(address): + hex_addr, hex_port = address.split(":") + + addr = bytes.fromhex(hex_addr) + addr = struct.unpack(">IIII", addr) + addr = struct.pack("@IIII", *addr) + addr = socket.inet_ntop(socket.AF_INET6, addr) + port = str(int(hex_port, 16)) + + return addr, port + + +def extend_address4(entry, name, name_addr, name_port): + if name in entry: + address, port = parse_ipv4_address(entry[name]) + entry[name_addr] = address + entry[name_port] = port + + +def extend_address6(entry, name, name_addr, name_port): + if name in entry: + address, port = parse_ipv6_address(entry[name]) + entry[name_addr] = address + entry[name_port] = port + + +def parser_tcp_udp(stdout, stderr, to_camelcase): + output = {} + + if stdout: + output = parseSpaceTable(stdout, to_camelcase=to_camelcase) + + for entry in output: + extend_address4(entry, "local_address", "local_addr", "local_port") + extend_address4(entry, "rem_address", "rem_addr", "rem_port") + extend_address4(entry, "localAddress", "localAddr", "localPort") + extend_address4(entry, "remAddress", "remAddr", "remPort") + + return {"output": output, "unprocessed": []} + + +def parser_tcp_udp_6(stdout, stderr, to_camelcase): + output = {} + + if stdout: + output = parseSpaceTable(stdout, to_camelcase=to_camelcase) + + for entry in output: + extend_address6(entry, "local_address", "local_addr", "local_port") + extend_address6(entry, "rem_address", "rem_addr", "rem_port") + extend_address6(entry, "localAddress", "localAddr", "localPort") + extend_address6(entry, "remAddress", "remAddr", "remPort") + + return {"output": output, "unprocessed": []} + + +def parser_arp(stdout, stderr, to_camelcase): + output = {} + + if stdout: + output = parseSpaceTable(stdout, to_camelcase=to_camelcase) + + return {"output": output, "unprocessed": []} + + +def register(main): + main["proc_net_route"] = { + "cmd": "cat /proc/net/route", + "description": "IP routing information", + "parser": parser_route, + } + + main["proc_net_ax25_route"] = { + "cmd": "cat /proc/net/ax25_route", + "description": "AX25 routing information", + "parser": parser_route, + } + + main["proc_net_ipx_route"] = { + "cmd": "cat /proc/net/ipx_route", + "description": "IPX routing information", + "parser": parser_route, + } + + main["proc_net_tcp"] = { + "cmd": "cat /proc/net/tcp", + "description": "TCP socket table", + "parser": parser_tcp_udp, + } + + main["proc_net_udp"] = { + "cmd": "cat /proc/net/udp", + "description": "UDP socket table", + "parser": parser_tcp_udp, + } + + main["proc_net_tcp6"] = { + "cmd": "cat /proc/net/tcp6", + "description": "TCP6 socket table", + "parser": parser_tcp_udp_6, + } + + main["proc_net_udp6"] = { + "cmd": "cat /proc/net/udp6", + "description": "UDP6 socket table", + "parser": parser_tcp_udp_6, + } + + main["proc_net_arp"] = { + "cmd": "cat /proc/net/arp", + "description": "ARP ", + "parser": parser_arp, + } diff --git a/modules/proc_partitions.py b/src/sysinfo/modules/proc_partitions.py similarity index 96% rename from modules/proc_partitions.py rename to src/sysinfo/modules/proc_partitions.py index 14d021e..3e674a2 100644 --- a/modules/proc_partitions.py +++ b/src/sysinfo/modules/proc_partitions.py @@ -1,19 +1,19 @@ -from sysinfo_lib import parseSpaceTable, tableToDict - - -def parser(stdout, stderr, to_camelcase): - output = {} - - if stdout: - output = parseSpaceTable(stdout, to_camelcase=to_camelcase) - output = tableToDict(output, "name") - - return {"output": output, "unprocessed": []} - - -def register(main): - main["proc_partitions"] = { - "cmd": "cat /proc/partitions", - "description": "Partition block allocation information", - "parser": parser, - } +from sysinfo_lib import parseSpaceTable, tableToDict + + +def parser(stdout, stderr, to_camelcase): + output = {} + + if stdout: + output = parseSpaceTable(stdout, to_camelcase=to_camelcase) + output = tableToDict(output, "name") + + return {"output": output, "unprocessed": []} + + +def register(main): + main["proc_partitions"] = { + "cmd": "cat /proc/partitions", + "description": "Partition block allocation information", + "parser": parser, + } diff --git a/modules/proc_scsi.py b/src/sysinfo/modules/proc_scsi.py similarity index 97% rename from modules/proc_scsi.py rename to src/sysinfo/modules/proc_scsi.py index 3b0c0f6..4d75637 100644 --- a/modules/proc_scsi.py +++ b/src/sysinfo/modules/proc_scsi.py @@ -1,60 +1,60 @@ -import re - - -def parser(stdout, stderr, to_camelcase): - output = {} - path = None - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - hostSearch = re.search( - r"^Host:\s+(\S+)\s+Channel:\s+(\S+)\s+Id:\s+(\S+)\s+Lun:\s+(\S+)$", - line, - re.IGNORECASE, - ) - if hostSearch: - host = hostSearch.group(1) - channel = hostSearch.group(2) - id = hostSearch.group(3) - lun = hostSearch.group(4) - path = "%s:%s:%s:%s" % (host.replace("scsi", ""), channel, id, lun) - output[path] = {"host": host, "channel": channel, "id": id, "lun": lun} - continue - - if path: - vendorSearch = re.search( - r"^\s+Vendor:\s+(.*)\s+Model:\s+(.*)\s+Rev:\s+(.*)$", - line, - re.IGNORECASE, - ) - if vendorSearch: - output[path]["vendor"] = vendorSearch.group(1).strip() - output[path]["model"] = vendorSearch.group(2).strip() - output[path]["rev"] = vendorSearch.group(3).strip() - continue - - typeSearch = re.search( - r"^\s+Type:\s+(.*)\s+ANSI\s+SCSI\s+revision:\s+(.*)$", - line, - re.IGNORECASE, - ) - if typeSearch: - output[path]["type"] = typeSearch.group(1).strip() - output[path]["revision"] = typeSearch.group(2).strip() - continue - - if re.match(r"Attached devices", line): - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["proc_scsi"] = { - "cmd": "cat /proc/scsi/scsi", - "description": "List of every recognized SCSI device", - "parser": parser, - } +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + path = None + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + hostSearch = re.search( + r"^Host:\s+(\S+)\s+Channel:\s+(\S+)\s+Id:\s+(\S+)\s+Lun:\s+(\S+)$", + line, + re.IGNORECASE, + ) + if hostSearch: + host = hostSearch.group(1) + channel = hostSearch.group(2) + id = hostSearch.group(3) + lun = hostSearch.group(4) + path = "%s:%s:%s:%s" % (host.replace("scsi", ""), channel, id, lun) + output[path] = {"host": host, "channel": channel, "id": id, "lun": lun} + continue + + if path: + vendorSearch = re.search( + r"^\s+Vendor:\s+(.*)\s+Model:\s+(.*)\s+Rev:\s+(.*)$", + line, + re.IGNORECASE, + ) + if vendorSearch: + output[path]["vendor"] = vendorSearch.group(1).strip() + output[path]["model"] = vendorSearch.group(2).strip() + output[path]["rev"] = vendorSearch.group(3).strip() + continue + + typeSearch = re.search( + r"^\s+Type:\s+(.*)\s+ANSI\s+SCSI\s+revision:\s+(.*)$", + line, + re.IGNORECASE, + ) + if typeSearch: + output[path]["type"] = typeSearch.group(1).strip() + output[path]["revision"] = typeSearch.group(2).strip() + continue + + if re.match(r"Attached devices", line): + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_scsi"] = { + "cmd": "cat /proc/scsi/scsi", + "description": "List of every recognized SCSI device", + "parser": parser, + } diff --git a/modules/proc_slabinfo.py b/src/sysinfo/modules/proc_slabinfo.py similarity index 96% rename from modules/proc_slabinfo.py rename to src/sysinfo/modules/proc_slabinfo.py index 17b8ed9..9ebb01a 100644 --- a/modules/proc_slabinfo.py +++ b/src/sysinfo/modules/proc_slabinfo.py @@ -1,71 +1,71 @@ -import re -from sysinfo_lib import camelCase - - -def extract_key_value(keys, data): - entry = {} - - if len(keys) == len(data): - for key_index, key in enumerate(keys): - entry[key] = data[key_index] - - return entry - - -def parser(stdout, stderr, to_camelcase): - output = {} - key_names = [] - has_keys = False - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - if re.match(r"^slabinfo - version", line): - continue - - header = re.search(r"^# name\s+(.*)$", line) - if header: - parts = header.group(1).strip().split(":") - for part in parts: - part = part.strip() - part = re.sub(r"(tunables|slabdata)\s+", "", part) - part = part.replace("<", "").replace(">", "") - part_columns = re.split(r"\s+", part) - part_columns = [ - camelCase(key, to_camelcase) for key in part_columns - ] - - key_names.append(part_columns) - - has_keys = True - continue - - row = re.search(r"^(\S+)\s+(.*)\s:\stunables(.*)\s:\sslabdata(.*)$", line) - if has_keys and row: - name = row.group(1) - statistics_data = re.split(r"\s+", row.group(2).strip()) - tunables_data = re.split(r"\s+", row.group(3).strip()) - slabdata_data = re.split(r"\s+", row.group(4).strip()) - - statistics = extract_key_value(key_names[0], statistics_data) - tunables = extract_key_value(key_names[1], tunables_data) - slabdata = extract_key_value(key_names[2], slabdata_data) - - output[name] = { - "statistics": statistics, - "tunables": tunables, - "slabdata": slabdata, - } - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["proc_slabinfo"] = { - "cmd": "cat /proc/slabinfo", - "description": "Kernel caches informations", - "parser": parser, - } +import re +from sysinfo_lib import camelCase + + +def extract_key_value(keys, data): + entry = {} + + if len(keys) == len(data): + for key_index, key in enumerate(keys): + entry[key] = data[key_index] + + return entry + + +def parser(stdout, stderr, to_camelcase): + output = {} + key_names = [] + has_keys = False + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + if re.match(r"^slabinfo - version", line): + continue + + header = re.search(r"^# name\s+(.*)$", line) + if header: + parts = header.group(1).strip().split(":") + for part in parts: + part = part.strip() + part = re.sub(r"(tunables|slabdata)\s+", "", part) + part = part.replace("<", "").replace(">", "") + part_columns = re.split(r"\s+", part) + part_columns = [ + camelCase(key, to_camelcase) for key in part_columns + ] + + key_names.append(part_columns) + + has_keys = True + continue + + row = re.search(r"^(\S+)\s+(.*)\s:\stunables(.*)\s:\sslabdata(.*)$", line) + if has_keys and row: + name = row.group(1) + statistics_data = re.split(r"\s+", row.group(2).strip()) + tunables_data = re.split(r"\s+", row.group(3).strip()) + slabdata_data = re.split(r"\s+", row.group(4).strip()) + + statistics = extract_key_value(key_names[0], statistics_data) + tunables = extract_key_value(key_names[1], tunables_data) + slabdata = extract_key_value(key_names[2], slabdata_data) + + output[name] = { + "statistics": statistics, + "tunables": tunables, + "slabdata": slabdata, + } + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_slabinfo"] = { + "cmd": "cat /proc/slabinfo", + "description": "Kernel caches informations", + "parser": parser, + } diff --git a/modules/proc_stat.py b/src/sysinfo/modules/proc_stat.py similarity index 96% rename from modules/proc_stat.py rename to src/sysinfo/modules/proc_stat.py index b6dd55b..50ba415 100644 --- a/modules/proc_stat.py +++ b/src/sysinfo/modules/proc_stat.py @@ -1,38 +1,38 @@ -import re -from sysinfo_lib import camelCase - - -def parser(stdout, stderr, to_camelcase): - output = {} - - if stdout: - for line in stdout.splitlines(): - parts = re.split(r"\s+", line) - key = parts.pop(0) - - if re.match(r"^cpu", key) and len(parts) == 10: - output[key] = { - "user": parts[0], - "nice": parts[1], - "system": parts[2], - "idle": parts[3], - "iowait": parts[4], - "irq": parts[5], - "softirq": parts[6], - "steal": parts[7], - "guest": parts[8], - "guest_nice": parts[9], - } - continue - - output[key] = " ".join(parts) - - return {"output": output, "unprocessed": []} - - -def register(main): - main["proc_stat"] = { - "cmd": "cat /proc/stat", - "description": "Kernel/system statistics", - "parser": parser, - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + + if stdout: + for line in stdout.splitlines(): + parts = re.split(r"\s+", line) + key = parts.pop(0) + + if re.match(r"^cpu", key) and len(parts) == 10: + output[key] = { + "user": parts[0], + "nice": parts[1], + "system": parts[2], + "idle": parts[3], + "iowait": parts[4], + "irq": parts[5], + "softirq": parts[6], + "steal": parts[7], + "guest": parts[8], + "guest_nice": parts[9], + } + continue + + output[key] = " ".join(parts) + + return {"output": output, "unprocessed": []} + + +def register(main): + main["proc_stat"] = { + "cmd": "cat /proc/stat", + "description": "Kernel/system statistics", + "parser": parser, + } diff --git a/modules/proc_swaps.py b/src/sysinfo/modules/proc_swaps.py similarity index 95% rename from modules/proc_swaps.py rename to src/sysinfo/modules/proc_swaps.py index dcddab5..075eeb7 100644 --- a/modules/proc_swaps.py +++ b/src/sysinfo/modules/proc_swaps.py @@ -1,18 +1,18 @@ -from sysinfo_lib import parseSpaceTable - - -def parser(stdout, stderr, to_camelcase): - output = {} - - if stdout: - output = parseSpaceTable(stdout, to_camelcase=to_camelcase) - - return {"output": output, "unprocessed": []} - - -def register(main): - main["proc_swaps"] = { - "cmd": "cat /proc/swaps", - "description": "Measures swap space and its utilization", - "parser": parser, - } +from sysinfo_lib import parseSpaceTable + + +def parser(stdout, stderr, to_camelcase): + output = {} + + if stdout: + output = parseSpaceTable(stdout, to_camelcase=to_camelcase) + + return {"output": output, "unprocessed": []} + + +def register(main): + main["proc_swaps"] = { + "cmd": "cat /proc/swaps", + "description": "Measures swap space and its utilization", + "parser": parser, + } diff --git a/modules/proc_sys.py b/src/sysinfo/modules/proc_sys.py similarity index 96% rename from modules/proc_sys.py rename to src/sysinfo/modules/proc_sys.py index feceaf9..004fcd4 100644 --- a/modules/proc_sys.py +++ b/src/sysinfo/modules/proc_sys.py @@ -1,48 +1,48 @@ -import re -from sysinfo_lib import camelCase - - -def setPathValue(data, path, value, to_camelcase): - pathRest = None - pathParts = re.search(r"^([^\/]+)\/?(.*)$", path) - if pathParts: - path = camelCase(pathParts.group(1), to_camelcase) - pathRest = pathParts.group(2) - - else: - path = camelCase(path) - - if not path in data: - data[path] = {} - - if pathRest: - setPathValue(data[path], pathRest, value, to_camelcase) - else: - key = camelCase(path, to_camelcase) - data[key] = value - - -def parser(stdout, stderr, to_camelcase): - output = {} - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - pathValue = re.search(r"^\/proc\/sys\/([^:]+):(.*)$", line) - if pathValue: - path = pathValue.group(1) - value = pathValue.group(2) - setPathValue(output, path, value, to_camelcase) - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["proc_sys"] = { - "cmd": """find /proc/sys -type f -follow -print 2>/dev/null | xargs -n 1 -I {} sh -c 'VAL=$(cat {} 2>/dev/null); echo {}:$VAL;'""", - "description": "Information about the system and kernel features", - "parser": parser, - } +import re +from sysinfo_lib import camelCase + + +def setPathValue(data, path, value, to_camelcase): + pathRest = None + pathParts = re.search(r"^([^\/]+)\/?(.*)$", path) + if pathParts: + path = camelCase(pathParts.group(1), to_camelcase) + pathRest = pathParts.group(2) + + else: + path = camelCase(path) + + if not path in data: + data[path] = {} + + if pathRest: + setPathValue(data[path], pathRest, value, to_camelcase) + else: + key = camelCase(path, to_camelcase) + data[key] = value + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + pathValue = re.search(r"^\/proc\/sys\/([^:]+):(.*)$", line) + if pathValue: + path = pathValue.group(1) + value = pathValue.group(2) + setPathValue(output, path, value, to_camelcase) + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_sys"] = { + "cmd": """find /proc/sys -type f -follow -print 2>/dev/null | xargs -n 1 -I {} sh -c 'VAL=$(cat {} 2>/dev/null); echo {}:$VAL;'""", + "description": "Information about the system and kernel features", + "parser": parser, + } diff --git a/modules/proc_uptime.py b/src/sysinfo/modules/proc_uptime.py similarity index 96% rename from modules/proc_uptime.py rename to src/sysinfo/modules/proc_uptime.py index f04aaaf..86ff841 100644 --- a/modules/proc_uptime.py +++ b/src/sysinfo/modules/proc_uptime.py @@ -1,23 +1,23 @@ -import re - - -def parser(stdout, stderr, to_camelcase): - output = {} - - if stdout: - splitted = re.split(r"\s+", stdout.strip()) - if len(splitted) > 0: - output["systemUp"] = splitted[0] - - if len(splitted) > 1: - output["sumCoresIdle"] = splitted[1] - - return {"output": output, "unprocessed": []} - - -def register(main): - main["proc_uptime"] = { - "cmd": "cat /proc/uptime", - "description": "Information detailing how long the system has been on since its last restart", - "parser": parser, - } +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + + if stdout: + splitted = re.split(r"\s+", stdout.strip()) + if len(splitted) > 0: + output["systemUp"] = splitted[0] + + if len(splitted) > 1: + output["sumCoresIdle"] = splitted[1] + + return {"output": output, "unprocessed": []} + + +def register(main): + main["proc_uptime"] = { + "cmd": "cat /proc/uptime", + "description": "Information detailing how long the system has been on since its last restart", + "parser": parser, + } diff --git a/modules/proc_version.py b/src/sysinfo/modules/proc_version.py similarity index 96% rename from modules/proc_version.py rename to src/sysinfo/modules/proc_version.py index 2f2e2e3..dfcd145 100644 --- a/modules/proc_version.py +++ b/src/sysinfo/modules/proc_version.py @@ -1,15 +1,15 @@ -def parser(stdout, stderr, to_camelcase): - output = {} - - if stdout: - output = stdout.strip() - - return {"output": output, "unprocessed": []} - - -def register(main): - main["proc_version"] = { - "cmd": "cat /proc/version", - "description": "Version of the Linux kernel, the version of gcc used to compile the kernel, and the time of kernel compilation", - "parser": parser, - } +def parser(stdout, stderr, to_camelcase): + output = {} + + if stdout: + output = stdout.strip() + + return {"output": output, "unprocessed": []} + + +def register(main): + main["proc_version"] = { + "cmd": "cat /proc/version", + "description": "Version of the Linux kernel, the version of gcc used to compile the kernel, and the time of kernel compilation", + "parser": parser, + } diff --git a/modules/proc_version_signature.py b/src/sysinfo/modules/proc_version_signature.py similarity index 100% rename from modules/proc_version_signature.py rename to src/sysinfo/modules/proc_version_signature.py diff --git a/modules/proc_vmstat.py b/src/sysinfo/modules/proc_vmstat.py similarity index 96% rename from modules/proc_vmstat.py rename to src/sysinfo/modules/proc_vmstat.py index 6e8d299..cc5adcc 100644 --- a/modules/proc_vmstat.py +++ b/src/sysinfo/modules/proc_vmstat.py @@ -1,29 +1,29 @@ -import re -from sysinfo_lib import camelCase - - -def parser(stdout, stderr, to_camelcase): - output = {} - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - lineMatch = re.search(r"^([^\s+]+)\s(.*)$", line) - if lineMatch: - key = camelCase(lineMatch.group(1), to_camelcase) - value = lineMatch.group(2) - - output[key] = value - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["proc_vmstat"] = { - "cmd": "cat /proc/vmstat", - "description": "Detailed virtual memory statistics from the kernel", - "parser": parser, - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + lineMatch = re.search(r"^([^\s+]+)\s(.*)$", line) + if lineMatch: + key = camelCase(lineMatch.group(1), to_camelcase) + value = lineMatch.group(2) + + output[key] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["proc_vmstat"] = { + "cmd": "cat /proc/vmstat", + "description": "Detailed virtual memory statistics from the kernel", + "parser": parser, + } diff --git a/modules/prtstat.py b/src/sysinfo/modules/prtstat.py similarity index 96% rename from modules/prtstat.py rename to src/sysinfo/modules/prtstat.py index a4a484b..4752104 100644 --- a/modules/prtstat.py +++ b/src/sysinfo/modules/prtstat.py @@ -1,37 +1,37 @@ -import re -from sysinfo_lib import camelCase - - -def parser(stdout, stderr, to_camelcase): - output = {} - pid = "" - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - processed = False - pairs = re.findall(r"(\S+):\s(\S+)", line) - for kv in pairs: - if kv[0] == "pid": - pid = kv[1] - output[pid] = {} - - if pid != "": - key = camelCase(kv[0], to_camelcase) - value = kv[1].strip() - - output[pid][key] = value - processed = True - - if not processed: - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["prtstat"] = { - "cmd": "ps -eo pid | xargs -I {} prtstat -r {}", - "description": "Print statistics of a processes", - "parser": parser, - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + pid = "" + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + processed = False + pairs = re.findall(r"(\S+):\s(\S+)", line) + for kv in pairs: + if kv[0] == "pid": + pid = kv[1] + output[pid] = {} + + if pid != "": + key = camelCase(kv[0], to_camelcase) + value = kv[1].strip() + + output[pid][key] = value + processed = True + + if not processed: + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["prtstat"] = { + "cmd": "ps -eo pid | xargs -I {} prtstat -r {}", + "description": "Print statistics of a processes", + "parser": parser, + } diff --git a/modules/ps.py b/src/sysinfo/modules/ps.py similarity index 96% rename from modules/ps.py rename to src/sysinfo/modules/ps.py index 839de03..34f0653 100644 --- a/modules/ps.py +++ b/src/sysinfo/modules/ps.py @@ -1,58 +1,58 @@ -import re - - -def parser(stdout, stderr, to_camelcase): - output = {} - unprocessed = [] - columnsNames = [ - "user", - "ruser", - "group", - "rgroup", - "pid", - "ppid", - "pgid", - "cpu", - "size", - "bytes", - "nice", - "time", - "stime", - "tty", - "args", - ] - columnsCount = len(columnsNames) - - if stdout: - for line in stdout.splitlines(): - if re.search(r"ps --cols 12288 -eo", line) or re.search( - r"USER.*RUSER.*GROUP", line - ): - continue - - cols = re.split(r"\s+", line) - if cols: - entry = {} - for num, val in enumerate(cols, start=0): - if num < columnsCount: - name = columnsNames[num] - entry[name] = val - - elif "args" in entry: - entry["args"] += " " + val - - if "pid" in entry: - output[entry["pid"]] = entry - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["ps"] = { - "cmd": "ps --cols 12288 -eo user:256,ruser:256,group:256,rgroup:256,pid,ppid,pgid,pcpu,vsz,nice,etime,time,stime,tty,args 2>/dev/null", - "description": "Report a snapshot of the current processes", - "parser": parser, - } +import re + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + columnsNames = [ + "user", + "ruser", + "group", + "rgroup", + "pid", + "ppid", + "pgid", + "cpu", + "size", + "bytes", + "nice", + "time", + "stime", + "tty", + "args", + ] + columnsCount = len(columnsNames) + + if stdout: + for line in stdout.splitlines(): + if re.search(r"ps --cols 12288 -eo", line) or re.search( + r"USER.*RUSER.*GROUP", line + ): + continue + + cols = re.split(r"\s+", line) + if cols: + entry = {} + for num, val in enumerate(cols, start=0): + if num < columnsCount: + name = columnsNames[num] + entry[name] = val + + elif "args" in entry: + entry["args"] += " " + val + + if "pid" in entry: + output[entry["pid"]] = entry + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["ps"] = { + "cmd": "ps --cols 12288 -eo user:256,ruser:256,group:256,rgroup:256,pid,ppid,pgid,pcpu,vsz,nice,etime,time,stime,tty,args 2>/dev/null", + "description": "Report a snapshot of the current processes", + "parser": parser, + } diff --git a/modules/python.py b/src/sysinfo/modules/python.py similarity index 96% rename from modules/python.py rename to src/sysinfo/modules/python.py index 4862140..d729166 100644 --- a/modules/python.py +++ b/src/sysinfo/modules/python.py @@ -1,78 +1,78 @@ -import platform - -from modules.sysinfo_lib import camelCase - - -try: - import pkg_resources - - loaded_pkg_resources = True -except: - loaded_pkg_resources = False - - -def python_pip_packages(to_camelcase): - output = {} - - if loaded_pkg_resources: - for pkg in pkg_resources.working_set: - package = {} - for key in [ - "location", - "project_name", - "key", - "version", - "parsed_version", - "py_version", - "platform", - "precedence", - ]: - if hasattr(pkg, key): - key_case = camelCase(key, to_camelcase) - package[key_case] = str(getattr(pkg, key)) - - if "key" in package: - output[package["key"]] = package - - return {"output": output, "unprocessed": []} - - -def python_platform(to_camelcase): - output = { - "architecture": platform.architecture(), - "machine": platform.machine(), - "node": platform.node(), - "platform": { - "normal": platform.platform(), - "aliased": platform.platform(aliased=True), - "terse": platform.platform(terse=True), - }, - "processor": platform.processor(), - "python": { - "branch": platform.python_branch(), - "build": platform.python_build(), - "compiler": platform.python_compiler(), - "implementation": platform.python_implementation(), - "revision": platform.python_revision(), - "version": platform.python_version(), - "versionTuple": platform.python_version_tuple(), - }, - "release": platform.release(), - "system": platform.system(), - "version": platform.version(), - "uname": platform.uname(), - } - return {"output": output, "unprocessed": []} - - -def register(main): - if loaded_pkg_resources: - main["python_pip_packages"] = { - "function": python_pip_packages, - "description": "List available python modules", - } - - main["python_platform"] = { - "function": python_platform, - "description": "Probe the underlying platform's hardware, operating system, and Python interpreter version information", - } +import platform + +from modules.sysinfo_lib import camelCase + + +try: + import pkg_resources + + loaded_pkg_resources = True +except: + loaded_pkg_resources = False + + +def python_pip_packages(to_camelcase): + output = {} + + if loaded_pkg_resources: + for pkg in pkg_resources.working_set: + package = {} + for key in [ + "location", + "project_name", + "key", + "version", + "parsed_version", + "py_version", + "platform", + "precedence", + ]: + if hasattr(pkg, key): + key_case = camelCase(key, to_camelcase) + package[key_case] = str(getattr(pkg, key)) + + if "key" in package: + output[package["key"]] = package + + return {"output": output, "unprocessed": []} + + +def python_platform(to_camelcase): + output = { + "architecture": platform.architecture(), + "machine": platform.machine(), + "node": platform.node(), + "platform": { + "normal": platform.platform(), + "aliased": platform.platform(aliased=True), + "terse": platform.platform(terse=True), + }, + "processor": platform.processor(), + "python": { + "branch": platform.python_branch(), + "build": platform.python_build(), + "compiler": platform.python_compiler(), + "implementation": platform.python_implementation(), + "revision": platform.python_revision(), + "version": platform.python_version(), + "versionTuple": platform.python_version_tuple(), + }, + "release": platform.release(), + "system": platform.system(), + "version": platform.version(), + "uname": platform.uname(), + } + return {"output": output, "unprocessed": []} + + +def register(main): + if loaded_pkg_resources: + main["python_pip_packages"] = { + "function": python_pip_packages, + "description": "List available python modules", + } + + main["python_platform"] = { + "function": python_platform, + "description": "Probe the underlying platform's hardware, operating system, and Python interpreter version information", + } diff --git a/modules/route.py b/src/sysinfo/modules/route.py similarity index 96% rename from modules/route.py rename to src/sysinfo/modules/route.py index 808820b..aee5cd9 100644 --- a/modules/route.py +++ b/src/sysinfo/modules/route.py @@ -1,22 +1,22 @@ -from sysinfo_lib import parseTable - - -def parser(stdout, stderr, to_camelcase): - output = {} - - if stdout: - output = parseTable( - stdout, - header_pattern=r"^(Destination\s*)(\sGateway\s*)(\sGenmask\s*)(\sFlags\s*)(\sMetric\s*)(\sRef\s)(\s*Use)(\sIface\s*)(\sMSS\s*)(\sWindow\s*)(\sirtt\s*)", - to_camelcase=to_camelcase, - ) - - return {"output": output, "unprocessed": []} - - -def register(main): - main["route"] = { - "cmd": "route -ee", - "description": "IP routing table", - "parser": parser, - } +from sysinfo_lib import parseTable + + +def parser(stdout, stderr, to_camelcase): + output = {} + + if stdout: + output = parseTable( + stdout, + header_pattern=r"^(Destination\s*)(\sGateway\s*)(\sGenmask\s*)(\sFlags\s*)(\sMetric\s*)(\sRef\s)(\s*Use)(\sIface\s*)(\sMSS\s*)(\sWindow\s*)(\sirtt\s*)", + to_camelcase=to_camelcase, + ) + + return {"output": output, "unprocessed": []} + + +def register(main): + main["route"] = { + "cmd": "route -ee", + "description": "IP routing table", + "parser": parser, + } diff --git a/modules/rpm.py b/src/sysinfo/modules/rpm.py similarity index 96% rename from modules/rpm.py rename to src/sysinfo/modules/rpm.py index f066d2c..3429168 100644 --- a/modules/rpm.py +++ b/src/sysinfo/modules/rpm.py @@ -1,31 +1,31 @@ -from sysinfo_lib import parseCharDelimitedTable, tableToDict - - -def parser(stdout, stderr, to_camelcase): - output = {} - columns = [ - "installtime", - "buildtime", - "name", - "version", - "release", - "arch", - "vendor", - "packager", - "distribution", - "disttag", - ] - - if stdout: - output = parseCharDelimitedTable(stdout, "|", columns) - output = tableToDict(output, "name") - - return {"output": output, "unprocessed": []} - - -def register(main): - main["rpm"] = { - "cmd": 'rpm -q -a --queryformat "%{INSTALLTIME}|%{BUILDTIME}|%{NAME}|%{VERSION}|%{RELEASE}|%{arch}|%{VENDOR}|%{PACKAGER}|%{DISTRIBUTION}|%{DISTTAG}\n"', - "description": "Querying all RPM packages", - "parser": parser, - } +from sysinfo_lib import parseCharDelimitedTable, tableToDict + + +def parser(stdout, stderr, to_camelcase): + output = {} + columns = [ + "installtime", + "buildtime", + "name", + "version", + "release", + "arch", + "vendor", + "packager", + "distribution", + "disttag", + ] + + if stdout: + output = parseCharDelimitedTable(stdout, "|", columns) + output = tableToDict(output, "name") + + return {"output": output, "unprocessed": []} + + +def register(main): + main["rpm"] = { + "cmd": 'rpm -q -a --queryformat "%{INSTALLTIME}|%{BUILDTIME}|%{NAME}|%{VERSION}|%{RELEASE}|%{arch}|%{VENDOR}|%{PACKAGER}|%{DISTRIBUTION}|%{DISTTAG}\n"', + "description": "Querying all RPM packages", + "parser": parser, + } diff --git a/modules/services_status.py b/src/sysinfo/modules/services_status.py similarity index 97% rename from modules/services_status.py rename to src/sysinfo/modules/services_status.py index 78c49e7..2114de6 100644 --- a/modules/services_status.py +++ b/src/sysinfo/modules/services_status.py @@ -1,50 +1,50 @@ -import re -from sysinfo_lib import parseTable, tableToDict, camelCase - - -def parser_services(stdout, stderr, to_camelcase): - output = parseTable(stdout, to_camelcase=to_camelcase) - output = tableToDict(output, "unit") - - return {"output": output, "unprocessed": []} - - -def parser_services_params(stdout, stderr, to_camelcase): - output = {} - service = None - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - service_search = re.search(r"^>>>\s*Service:\s*(.*)$", line) - if service_search: - service = service_search.group(1).strip() - output[service] = {} - continue - - if service: - kv = re.search(r"^([^=]+)=(.*)$", line) - if kv: - key = camelCase(kv.group(1), to_camelcase) - value = kv.group(2).strip() - - output[service][key] = value - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["services_list"] = { - "cmd": """systemctl -l --type service --all --plain | grep -i -e ".service\|description" | sed 's/^\s*//g' """, - "description": "Displays services with status", - "parser": parser_services, - } - - main["services_params"] = { - "cmd": """systemctl -l --type service --all --plain | sed -E 's/^\s*(\\S+.service).*$/\\1/g' | grep -i -e ".service" | xargs -I '{}' sh -c "echo '>>> Service: {}'; systemctl show {} --no-page" """, - "description": "Displays services with params", - "parser": parser_services_params, - } +import re +from sysinfo_lib import parseTable, tableToDict, camelCase + + +def parser_services(stdout, stderr, to_camelcase): + output = parseTable(stdout, to_camelcase=to_camelcase) + output = tableToDict(output, "unit") + + return {"output": output, "unprocessed": []} + + +def parser_services_params(stdout, stderr, to_camelcase): + output = {} + service = None + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + service_search = re.search(r"^>>>\s*Service:\s*(.*)$", line) + if service_search: + service = service_search.group(1).strip() + output[service] = {} + continue + + if service: + kv = re.search(r"^([^=]+)=(.*)$", line) + if kv: + key = camelCase(kv.group(1), to_camelcase) + value = kv.group(2).strip() + + output[service][key] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["services_list"] = { + "cmd": """systemctl -l --type service --all --plain | grep -i -e ".service\|description" | sed 's/^\s*//g' """, + "description": "Displays services with status", + "parser": parser_services, + } + + main["services_params"] = { + "cmd": """systemctl -l --type service --all --plain | sed -E 's/^\s*(\\S+.service).*$/\\1/g' | grep -i -e ".service" | xargs -I '{}' sh -c "echo '>>> Service: {}'; systemctl show {} --no-page" """, + "description": "Displays services with params", + "parser": parser_services_params, + } diff --git a/modules/sysctl.py b/src/sysinfo/modules/sysctl.py similarity index 96% rename from modules/sysctl.py rename to src/sysinfo/modules/sysctl.py index bd6dbec..8a7c5ed 100644 --- a/modules/sysctl.py +++ b/src/sysinfo/modules/sysctl.py @@ -1,51 +1,51 @@ -import re -from sysinfo_lib import camelCase - - -def set_path_value(data, path, value, to_camelcase): - pathRest = None - pathParts = re.search(r"^([^\.]+)\.?(.*)$", path) - if pathParts: - path = camelCase(pathParts.group(1), to_camelcase) - pathRest = pathParts.group(2) - - if not path in data: - data[path] = {} - - if pathRest: - set_path_value(data[path], pathRest, value, to_camelcase) - else: - data[path] = value - - -def parser(stdout, stderr, to_camelcase): - output = {} - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - kv = re.search(r"^([^=]+)=(.*)$", line) - if kv: - key = kv.group(1).strip() - value = kv.group(2).strip() - - set_path_value(output, key, value, to_camelcase) - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["sysctl"] = { - "cmd": "sysctl -a -e", - "description": "Runtime kernel parameters", - "parser": parser, - } - - main["sysctl_system"] = { - "cmd": "sysctl -a -e --system", - "description": "Runtime kernel parameters from all system configuration files", - "parser": parser, - } +import re +from sysinfo_lib import camelCase + + +def set_path_value(data, path, value, to_camelcase): + pathRest = None + pathParts = re.search(r"^([^\.]+)\.?(.*)$", path) + if pathParts: + path = camelCase(pathParts.group(1), to_camelcase) + pathRest = pathParts.group(2) + + if not path in data: + data[path] = {} + + if pathRest: + set_path_value(data[path], pathRest, value, to_camelcase) + else: + data[path] = value + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + kv = re.search(r"^([^=]+)=(.*)$", line) + if kv: + key = kv.group(1).strip() + value = kv.group(2).strip() + + set_path_value(output, key, value, to_camelcase) + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["sysctl"] = { + "cmd": "sysctl -a -e", + "description": "Runtime kernel parameters", + "parser": parser, + } + + main["sysctl_system"] = { + "cmd": "sysctl -a -e --system", + "description": "Runtime kernel parameters from all system configuration files", + "parser": parser, + } diff --git a/modules/sysinfo_lib.py b/src/sysinfo/modules/sysinfo_lib.py similarity index 96% rename from modules/sysinfo_lib.py rename to src/sysinfo/modules/sysinfo_lib.py index acc6e9e..437eb83 100644 --- a/modules/sysinfo_lib.py +++ b/src/sysinfo/modules/sysinfo_lib.py @@ -1,155 +1,155 @@ -import sys -import re -from struct import pack, unpack - -PY2 = sys.version_info[0] == 2 -PY3 = sys.version_info[0] == 3 - - -def sortedList(st): - values = list(set(st.splitlines())) - values.sort() - return values - -def camelCase_cb(matchobj): - return " ".join([matchobj.group(1), matchobj.group(2)]) - -def camelCase(st, to_camelcase): - if not to_camelcase: - return st - - st = re.sub(r"([a-z])([A-Z])", camelCase_cb, st) - - output = "".join(x for x in st.title() if x.isalnum()) - if len(output) == 1: - return output.lower() - - elif len(output) > 1: - return output[0].lower() + output[1:] - - else: - return "" - - -def parseTable( - input, header_pattern=None, end_pattern=None, ignore_empty=True, to_camelcase=False -): - output = [] - colNames = [] - colLengths = [] - header = None - lines = input.splitlines() - - if len(lines) == 0: - return output - - while len(lines) > 0 and lines[0].strip() == "": - lines.pop(0) - - if header_pattern: - while len(lines) > 0 and not re.search(header_pattern, lines[0], re.IGNORECASE): - lines.pop(0) - - if len(lines) == 0: - return output - - header = re.search(header_pattern, lines.pop(0), re.IGNORECASE) - if header: - header = header.groups() - - else: - header = re.findall(r"(\S+\s*)", lines.pop(0), re.IGNORECASE) - - if header: - for value in header: - colNames.append(camelCase(value.strip(), to_camelcase)) - colLengths.append(len(value)) - - if len(colNames) > 0: - colLengths[-1] = 8192 - totalLength = sum(colLengths) - packTemplate = "".join([str(s) + "s" for s in colLengths]) - - for line in lines: - if ignore_empty == True and line.strip() == "": - continue - - row = {} - if end_pattern and re.match(end_pattern, line): - break - - if PY2: - cols = unpack(packTemplate, line + (" " * (totalLength - len(line)))) - else: - cols = unpack( - packTemplate, - bytes(line + (" " * (totalLength - len(line))), "utf-8"), - ) - - for num, val in enumerate(cols, start=0): - if PY2: - row[colNames[num]] = val.strip() - else: - row[colNames[num]] = str(val.strip(), "utf-8") - - output.append(row) - - return output - - -def parseSpaceTable(input, ignore_empty=True, to_camelcase=False): - output = [] - colNames = [] - lines = input.splitlines() - - if len(lines) == 0: - return output - - while len(lines) > 0 and lines[0].strip() == "": - lines.pop(0) - - header = re.findall(r"(\S+[\s\t]*)", lines.pop(0), re.IGNORECASE) - if header: - for value in header: - colNames.append(camelCase(value.strip(), to_camelcase)) - - if len(colNames) > 0: - for line in lines: - if ignore_empty == True and line.strip() == "": - continue - row = {} - cols = re.split(r"\s+", line.strip()) - for num, val in enumerate(cols, start=0): - if num < len(colNames): - row[colNames[num]] = val.strip() - - output.append(row) - - return output - - -def parseCharDelimitedTable(input, delimiter, columnsNames): - output = [] - if input: - columns = len(columnsNames) + 1 - for line in input.splitlines(): - values = re.split(re.escape(delimiter), line + (delimiter * columns)) - row = {} - for num, val in enumerate(columnsNames, start=0): - if num < columns and num < len(values): - row[val] = values[num] - output.append(row) - return output - - -def tableToDict(input, key): - output = {} - - for row in input: - if isinstance(row, dict): - if key in row: - output[row[key]] = row - else: - return input - - return output +import sys +import re +from struct import pack, unpack + +PY2 = sys.version_info[0] == 2 +PY3 = sys.version_info[0] == 3 + + +def sortedList(st): + values = list(set(st.splitlines())) + values.sort() + return values + +def camelCase_cb(matchobj): + return " ".join([matchobj.group(1), matchobj.group(2)]) + +def camelCase(st, to_camelcase): + if not to_camelcase: + return st + + st = re.sub(r"([a-z])([A-Z])", camelCase_cb, st) + + output = "".join(x for x in st.title() if x.isalnum()) + if len(output) == 1: + return output.lower() + + elif len(output) > 1: + return output[0].lower() + output[1:] + + else: + return "" + + +def parseTable( + input, header_pattern=None, end_pattern=None, ignore_empty=True, to_camelcase=False +): + output = [] + colNames = [] + colLengths = [] + header = None + lines = input.splitlines() + + if len(lines) == 0: + return output + + while len(lines) > 0 and lines[0].strip() == "": + lines.pop(0) + + if header_pattern: + while len(lines) > 0 and not re.search(header_pattern, lines[0], re.IGNORECASE): + lines.pop(0) + + if len(lines) == 0: + return output + + header = re.search(header_pattern, lines.pop(0), re.IGNORECASE) + if header: + header = header.groups() + + else: + header = re.findall(r"(\S+\s*)", lines.pop(0), re.IGNORECASE) + + if header: + for value in header: + colNames.append(camelCase(value.strip(), to_camelcase)) + colLengths.append(len(value)) + + if len(colNames) > 0: + colLengths[-1] = 8192 + totalLength = sum(colLengths) + packTemplate = "".join([str(s) + "s" for s in colLengths]) + + for line in lines: + if ignore_empty == True and line.strip() == "": + continue + + row = {} + if end_pattern and re.match(end_pattern, line): + break + + if PY2: + cols = unpack(packTemplate, line + (" " * (totalLength - len(line)))) + else: + cols = unpack( + packTemplate, + bytes(line + (" " * (totalLength - len(line))), "utf-8"), + ) + + for num, val in enumerate(cols, start=0): + if PY2: + row[colNames[num]] = val.strip() + else: + row[colNames[num]] = str(val.strip(), "utf-8") + + output.append(row) + + return output + + +def parseSpaceTable(input, ignore_empty=True, to_camelcase=False): + output = [] + colNames = [] + lines = input.splitlines() + + if len(lines) == 0: + return output + + while len(lines) > 0 and lines[0].strip() == "": + lines.pop(0) + + header = re.findall(r"(\S+[\s\t]*)", lines.pop(0), re.IGNORECASE) + if header: + for value in header: + colNames.append(camelCase(value.strip(), to_camelcase)) + + if len(colNames) > 0: + for line in lines: + if ignore_empty == True and line.strip() == "": + continue + row = {} + cols = re.split(r"\s+", line.strip()) + for num, val in enumerate(cols, start=0): + if num < len(colNames): + row[colNames[num]] = val.strip() + + output.append(row) + + return output + + +def parseCharDelimitedTable(input, delimiter, columnsNames): + output = [] + if input: + columns = len(columnsNames) + 1 + for line in input.splitlines(): + values = re.split(re.escape(delimiter), line + (delimiter * columns)) + row = {} + for num, val in enumerate(columnsNames, start=0): + if num < columns and num < len(values): + row[val] = values[num] + output.append(row) + return output + + +def tableToDict(input, key): + output = {} + + for row in input: + if isinstance(row, dict): + if key in row: + output[row[key]] = row + else: + return input + + return output diff --git a/modules/timedatectl.py b/src/sysinfo/modules/timedatectl.py similarity index 96% rename from modules/timedatectl.py rename to src/sysinfo/modules/timedatectl.py index 8711e9b..dad6dec 100644 --- a/modules/timedatectl.py +++ b/src/sysinfo/modules/timedatectl.py @@ -1,35 +1,35 @@ -import re -from sysinfo_lib import camelCase - - -def parser(stdout, stderr, to_camelcase): - output = {} - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - lineMatch = re.search(r"^([^:]+):\s*(.*)", line) - if lineMatch: - key = camelCase(lineMatch.group(1).strip(), to_camelcase) - value = lineMatch.group(2).strip() - - output[key] = value - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["timedatectl"] = { - "cmd": "timedatectl status", - "description": "System time and date", - "parser": parser, - } - - main["timedatectl_timesync"] = { - "cmd": "timedatectl timesync-status", - "description": "Status of systemd-timesyncd.service", - "parser": parser, - } +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + lineMatch = re.search(r"^([^:]+):\s*(.*)", line) + if lineMatch: + key = camelCase(lineMatch.group(1).strip(), to_camelcase) + value = lineMatch.group(2).strip() + + output[key] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["timedatectl"] = { + "cmd": "timedatectl status", + "description": "System time and date", + "parser": parser, + } + + main["timedatectl_timesync"] = { + "cmd": "timedatectl timesync-status", + "description": "Status of systemd-timesyncd.service", + "parser": parser, + } diff --git a/modules/udevadm.py b/src/sysinfo/modules/udevadm.py similarity index 97% rename from modules/udevadm.py rename to src/sysinfo/modules/udevadm.py index 9aff430..57deb11 100644 --- a/modules/udevadm.py +++ b/src/sysinfo/modules/udevadm.py @@ -1,141 +1,141 @@ -import re -from sysinfo_lib import camelCase - - -def parse_looking_entry(line, entry, to_camelcase): - key_value = re.search(r'^\s+([^=]+)=="([^"]*)"', line) - if key_value: - key = key_value.group(1).lower() - value = key_value.group(2) - - multiple_values = re.match(r"^(\s+\d+)+$", value) - if multiple_values: - value = re.split(r"\s+", value.strip()) - - key_attr = re.match(r"^(\S+){([^}]+)}", key, re.IGNORECASE) - if key_attr: - attrType = camelCase(key_attr.group(1), to_camelcase) - - if not attrType in entry: - entry[attrType] = {} - - path = key_attr.group(2).split("/") - - if len(path) == 1: - key_case = camelCase(path[0], to_camelcase) - entry[attrType][key_case] = value - - else: - sub_entry = entry[attrType] - - for part in path[0:-1]: - part_case = camelCase(part, to_camelcase) - - if not part_case in sub_entry: - sub_entry[part_case] = {} - - sub_entry = sub_entry[part_case] - - key_case = camelCase(path[-1], to_camelcase) - sub_entry[key_case] = value - - else: - entry[key] = value - - return True - - return False - - -def parser(stdout, stderr, to_camelcase): - output = {"devices": {}, "parents": {}} - types = {"P": "path", "N": "node", "L": "linkPriority", "E": "entry", "S": "link"} - device = None - parent = None - looking_entry = None - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - deviceSearch = re.search(r"^>>> Device: (\S+)", line) - if deviceSearch: - device = deviceSearch.group(1) - output["devices"][device] = {"parents": [], "entry": {}, "link": []} - parent = None - continue - - if not device: - continue - - if line.strip() == "": - looking_entry = None - continue - - if re.match( - r"^.*(Udevadm info starts|chain of parent|the udev rules|rule to match|single parent device)", - line, - ): - continue - - keyValue = re.search(r"^(\S):\s+(.*)$", line) - if keyValue: - key = keyValue.group(1) - value = keyValue.group(2).strip() - if key in types: - key = types[key] - - if key == "entry": - valueSearch = re.search(r"^([^=]+)=(.*)$", value) - if valueSearch: - subkey = camelCase(valueSearch.group(1), to_camelcase) - subvalue = valueSearch.group(2).strip() - output["devices"][device]["entry"][subkey] = subvalue - - elif key == "link": - output["devices"][device]["link"].append(value) - - else: - output["devices"][device][key] = value - - continue - - deviceLook = re.search(r"^\s+looking at device \'([^\']+)", line) - if deviceLook: - looking_entry = output["devices"][device] - continue - - parentDeviceLook = re.search( - r"^\s+looking at parent device \'([^\']+)", line - ) - if parentDeviceLook: - parent = parentDeviceLook.group(1) - output["devices"][device]["parents"].append(parent) - - if not parent in output["parents"]: - output["parents"][parent] = {} - - looking_entry = output["parents"][parent] - continue - - if isinstance(looking_entry, dict): - processed = parse_looking_entry(line, looking_entry, to_camelcase) - if processed: - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["udevadm"] = { - "cmd": """udevadm info --export-db | grep "DEVNAME" | cut -d "=" -f2 | xargs -n 1 -I {} sh -c "echo '>>> Device: {}'; udevadm info --query=all --name={}; udevadm info --attribute-walk --name={}" """, - "description": "Queries the udev database for device information stored in the udev database", - "parser": parser, - } - - main["udevadm_block_devices"] = { - "cmd": """find /dev/ -type b | xargs -n 1 -I {} sh -c "echo '>>> Device: {}'; udevadm info --query=all --name={}; udevadm info --attribute-walk --name={}" """, - "description": "Queries the udev database for block device information stored in the udev database", - "parser": parser, - } +import re +from sysinfo_lib import camelCase + + +def parse_looking_entry(line, entry, to_camelcase): + key_value = re.search(r'^\s+([^=]+)=="([^"]*)"', line) + if key_value: + key = key_value.group(1).lower() + value = key_value.group(2) + + multiple_values = re.match(r"^(\s+\d+)+$", value) + if multiple_values: + value = re.split(r"\s+", value.strip()) + + key_attr = re.match(r"^(\S+){([^}]+)}", key, re.IGNORECASE) + if key_attr: + attrType = camelCase(key_attr.group(1), to_camelcase) + + if not attrType in entry: + entry[attrType] = {} + + path = key_attr.group(2).split("/") + + if len(path) == 1: + key_case = camelCase(path[0], to_camelcase) + entry[attrType][key_case] = value + + else: + sub_entry = entry[attrType] + + for part in path[0:-1]: + part_case = camelCase(part, to_camelcase) + + if not part_case in sub_entry: + sub_entry[part_case] = {} + + sub_entry = sub_entry[part_case] + + key_case = camelCase(path[-1], to_camelcase) + sub_entry[key_case] = value + + else: + entry[key] = value + + return True + + return False + + +def parser(stdout, stderr, to_camelcase): + output = {"devices": {}, "parents": {}} + types = {"P": "path", "N": "node", "L": "linkPriority", "E": "entry", "S": "link"} + device = None + parent = None + looking_entry = None + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + deviceSearch = re.search(r"^>>> Device: (\S+)", line) + if deviceSearch: + device = deviceSearch.group(1) + output["devices"][device] = {"parents": [], "entry": {}, "link": []} + parent = None + continue + + if not device: + continue + + if line.strip() == "": + looking_entry = None + continue + + if re.match( + r"^.*(Udevadm info starts|chain of parent|the udev rules|rule to match|single parent device)", + line, + ): + continue + + keyValue = re.search(r"^(\S):\s+(.*)$", line) + if keyValue: + key = keyValue.group(1) + value = keyValue.group(2).strip() + if key in types: + key = types[key] + + if key == "entry": + valueSearch = re.search(r"^([^=]+)=(.*)$", value) + if valueSearch: + subkey = camelCase(valueSearch.group(1), to_camelcase) + subvalue = valueSearch.group(2).strip() + output["devices"][device]["entry"][subkey] = subvalue + + elif key == "link": + output["devices"][device]["link"].append(value) + + else: + output["devices"][device][key] = value + + continue + + deviceLook = re.search(r"^\s+looking at device \'([^\']+)", line) + if deviceLook: + looking_entry = output["devices"][device] + continue + + parentDeviceLook = re.search( + r"^\s+looking at parent device \'([^\']+)", line + ) + if parentDeviceLook: + parent = parentDeviceLook.group(1) + output["devices"][device]["parents"].append(parent) + + if not parent in output["parents"]: + output["parents"][parent] = {} + + looking_entry = output["parents"][parent] + continue + + if isinstance(looking_entry, dict): + processed = parse_looking_entry(line, looking_entry, to_camelcase) + if processed: + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["udevadm"] = { + "cmd": """udevadm info --export-db | grep "DEVNAME" | cut -d "=" -f2 | xargs -n 1 -I {} sh -c "echo '>>> Device: {}'; udevadm info --query=all --name={}; udevadm info --attribute-walk --name={}" """, + "description": "Queries the udev database for device information stored in the udev database", + "parser": parser, + } + + main["udevadm_block_devices"] = { + "cmd": """find /dev/ -type b | xargs -n 1 -I {} sh -c "echo '>>> Device: {}'; udevadm info --query=all --name={}; udevadm info --attribute-walk --name={}" """, + "description": "Queries the udev database for block device information stored in the udev database", + "parser": parser, + } diff --git a/modules/uname.py b/src/sysinfo/modules/uname.py similarity index 100% rename from modules/uname.py rename to src/sysinfo/modules/uname.py diff --git a/modules/update_alternatives.py b/src/sysinfo/modules/update_alternatives.py similarity index 96% rename from modules/update_alternatives.py rename to src/sysinfo/modules/update_alternatives.py index 9d4d476..736a467 100644 --- a/modules/update_alternatives.py +++ b/src/sysinfo/modules/update_alternatives.py @@ -1,31 +1,31 @@ -import re - - -def parser(stdout, stderr, to_camelcase): - output = [] - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - lineMatch = re.search(r"^(\S+)\s+(.*)\s+(\S+)$", line) - if lineMatch: - output.append( - { - "name": lineMatch.group(1).strip(), - "mode": lineMatch.group(2).strip(), - "link": lineMatch.group(3).strip(), - } - ) - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def register(main): - main["update_alternatives"] = { - "cmd": "update-alternatives --get-selections", - "description": "Symbolic links determining default commands", - "parser": parser, - } +import re + + +def parser(stdout, stderr, to_camelcase): + output = [] + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + lineMatch = re.search(r"^(\S+)\s+(.*)\s+(\S+)$", line) + if lineMatch: + output.append( + { + "name": lineMatch.group(1).strip(), + "mode": lineMatch.group(2).strip(), + "link": lineMatch.group(3).strip(), + } + ) + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main["update_alternatives"] = { + "cmd": "update-alternatives --get-selections", + "description": "Symbolic links determining default commands", + "parser": parser, + } diff --git a/modules/vmstat.py b/src/sysinfo/modules/vmstat.py similarity index 96% rename from modules/vmstat.py rename to src/sysinfo/modules/vmstat.py index 0603fc9..f987295 100644 --- a/modules/vmstat.py +++ b/src/sysinfo/modules/vmstat.py @@ -1,144 +1,144 @@ -import re -import sys -from struct import pack, unpack -from sysinfo_lib import camelCase - -PY2 = sys.version_info[0] == 2 -PY3 = sys.version_info[0] == 3 - - -def parser_stats(stdout, stderr, to_camelcase): - output = {} - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - entry = re.search(r"^\s*(\d+)\s+(.*)$", line) - if entry: - key = camelCase(entry.group(2).strip(), to_camelcase) - value = entry.group(1).strip() - output[key] = value - - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def parser_disk(stdout, stderr, to_camelcase): - output = {} - sectionsNames = [] - sectionsMask = "" - totalLength = 0 - columnPaths = [] - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - if re.match(r"disk.*reads", line, re.IGNORECASE): - topHeader = re.split(r"\s+", line) - if topHeader: - for value in topHeader: - sectionsNames.append(value.strip().strip("-").lower()) - totalLength += len(value) + 1 - sectionsMask += str(len(value) + 1) + "s" - continue - - if sectionsMask: - if re.match(r".*total.*merged.*sectors.*", line): - lineFix = line + (" " * (totalLength - len(line))) - if PY3: - lineFix = bytes(lineFix, "utf-8") - - sectionData = unpack(sectionsMask, lineFix) - if sectionData: - for index, sec in enumerate(sectionData): - if PY2: - secStrip = sec.strip() - else: - secStrip = str(sec.strip(), "utf-8") - - topColumns = re.split(r"\s+", secStrip) - for column in topColumns: - if column: - columnPaths.append( - camelCase( - "%s %s" - % ( - sectionsNames[index], - column, - ), - to_camelcase, - ) - ) - else: - columnPaths.append("%s" % (sectionsNames[index],)) - - else: - entry = {} - columns = re.split(r"\s+", line) - for ci, cv in enumerate(columns): - if ci < len(columnPaths): - entry[columnPaths[ci]] = cv - - if "disk" in entry: - output[entry["disk"]] = entry - - return {"output": output, "unprocessed": unprocessed} - - -def parser_disk_sum(stdout, stderr, to_camelcase): - output = {} - unprocessed = [] - - if stdout: - for line in stdout.splitlines(): - entry = re.search(r"^\s*(\d+)\s+(.*)$", line) - if entry: - key = camelCase(entry.group(2).strip(), to_camelcase) - value = entry.group(1).strip() - - output[key] = value - continue - - unprocessed.append(line) - - return {"output": output, "unprocessed": unprocessed} - - -def parser_forks(stdout, stderr, to_camelcase): - output = {} - - if stdout: - forks = re.search(r"\s*(\d+)\s*forks", stdout) - if forks: - output["forks"] = forks.group(1) - - return {"output": output, "unprocessed": []} - - -def register(main): - main["vmstat_stats"] = { - "cmd": "vmstat -s", - "description": "Displays a table of various event counters and memory statistics", - "parser": parser_stats, - } - - main["vmstat_disk"] = { - "cmd": "vmstat -dwn", - "description": "Report disk statistics", - "parser": parser_disk, - } - - main["vmstat_disk_sum"] = { - "cmd": "vmstat -D", - "description": "Report some summary statistics about disk activity", - "parser": parser_disk_sum, - } - - main["vmstat_forks"] = { - "cmd": "vmstat -f", - "description": "Displays the number of forks since boot", - "parser": parser_forks, - } +import re +import sys +from struct import pack, unpack +from sysinfo_lib import camelCase + +PY2 = sys.version_info[0] == 2 +PY3 = sys.version_info[0] == 3 + + +def parser_stats(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + entry = re.search(r"^\s*(\d+)\s+(.*)$", line) + if entry: + key = camelCase(entry.group(2).strip(), to_camelcase) + value = entry.group(1).strip() + output[key] = value + + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def parser_disk(stdout, stderr, to_camelcase): + output = {} + sectionsNames = [] + sectionsMask = "" + totalLength = 0 + columnPaths = [] + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + if re.match(r"disk.*reads", line, re.IGNORECASE): + topHeader = re.split(r"\s+", line) + if topHeader: + for value in topHeader: + sectionsNames.append(value.strip().strip("-").lower()) + totalLength += len(value) + 1 + sectionsMask += str(len(value) + 1) + "s" + continue + + if sectionsMask: + if re.match(r".*total.*merged.*sectors.*", line): + lineFix = line + (" " * (totalLength - len(line))) + if PY3: + lineFix = bytes(lineFix, "utf-8") + + sectionData = unpack(sectionsMask, lineFix) + if sectionData: + for index, sec in enumerate(sectionData): + if PY2: + secStrip = sec.strip() + else: + secStrip = str(sec.strip(), "utf-8") + + topColumns = re.split(r"\s+", secStrip) + for column in topColumns: + if column: + columnPaths.append( + camelCase( + "%s %s" + % ( + sectionsNames[index], + column, + ), + to_camelcase, + ) + ) + else: + columnPaths.append("%s" % (sectionsNames[index],)) + + else: + entry = {} + columns = re.split(r"\s+", line) + for ci, cv in enumerate(columns): + if ci < len(columnPaths): + entry[columnPaths[ci]] = cv + + if "disk" in entry: + output[entry["disk"]] = entry + + return {"output": output, "unprocessed": unprocessed} + + +def parser_disk_sum(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + for line in stdout.splitlines(): + entry = re.search(r"^\s*(\d+)\s+(.*)$", line) + if entry: + key = camelCase(entry.group(2).strip(), to_camelcase) + value = entry.group(1).strip() + + output[key] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def parser_forks(stdout, stderr, to_camelcase): + output = {} + + if stdout: + forks = re.search(r"\s*(\d+)\s*forks", stdout) + if forks: + output["forks"] = forks.group(1) + + return {"output": output, "unprocessed": []} + + +def register(main): + main["vmstat_stats"] = { + "cmd": "vmstat -s", + "description": "Displays a table of various event counters and memory statistics", + "parser": parser_stats, + } + + main["vmstat_disk"] = { + "cmd": "vmstat -dwn", + "description": "Report disk statistics", + "parser": parser_disk, + } + + main["vmstat_disk_sum"] = { + "cmd": "vmstat -D", + "description": "Report some summary statistics about disk activity", + "parser": parser_disk_sum, + } + + main["vmstat_forks"] = { + "cmd": "vmstat -f", + "description": "Displays the number of forks since boot", + "parser": parser_forks, + } diff --git a/modules/yum.py b/src/sysinfo/modules/yum.py similarity index 97% rename from modules/yum.py rename to src/sysinfo/modules/yum.py index 1f3206e..1d73f7a 100644 --- a/modules/yum.py +++ b/src/sysinfo/modules/yum.py @@ -1,82 +1,82 @@ -import re - - -def parser_repolist(stdout, stderr, to_camelcase): - output = {"mirrors": [], "repos": [], "errors": []} - insideTable = False - if stdout: - for line in stdout.splitlines(): - mirrors = re.search(r"^\s*\*\s*([^:]+):\s*(.*)$", line) - if mirrors: - output["mirrors"].append( - {"repo": mirrors.group(1).strip(), "host": mirrors.group(2).strip()} - ) - - tableHeader = re.search( - r"^repo id\s+repo name\s+status", line, re.IGNORECASE - ) - tableRow = re.search( - r"^([^\/]+)\/([^\/]+)\/(.*)\s\s+(\S+.*)\s\s+(\S+.*)$", line - ) - if tableHeader: - insideTable = True - - elif insideTable and tableRow: - output["repos"].append( - { - "repo": tableRow.group(1).strip(), - "version": tableRow.group(2).strip(), - "arch": tableRow.group(3).strip(), - "repo_name": tableRow.group(4).strip(), - "status": tableRow.group(5).strip(), - } - ) - - else: - insideTable = False - - if stderr: - for line in stderr.splitlines(): - if re.search(r"http.*error .*", line, re.IGNORECASE): - if not line in output["errors"]: - output["errors"].append(line) - - return {"output": output} - - -def parser_installed(stdout, stderr, to_camelcase): - output = {"packages": [], "errors": []} - if stdout: - for line in stdout.splitlines(): - package = re.search(r"^([\S\.]+)\.(\S+)\s+(\S+\.\S+)\s+(\S+.*)$", line) - if package: - output["packages"].append( - { - "name": package.group(1).strip(), - "arch": package.group(2).strip(), - "version": package.group(3).strip(), - "status": package.group(4).strip(), - } - ) - - if stderr: - for line in stderr.splitlines(): - if re.search(r"http.*error .*", line, re.IGNORECASE): - if not line in output["errors"]: - output["errors"].append(line) - - return {"output": output} - - -def register(main): - main["yum_repolist"] = { - "cmd": "yum repolist all", - "description": "YUM - defined repositories", - "parser": parser_repolist, - } - - main["yum_installed"] = { - "cmd": "yum list installed", - "description": "YUM - list installed packages", - "parser": parser_installed, - } +import re + + +def parser_repolist(stdout, stderr, to_camelcase): + output = {"mirrors": [], "repos": [], "errors": []} + insideTable = False + if stdout: + for line in stdout.splitlines(): + mirrors = re.search(r"^\s*\*\s*([^:]+):\s*(.*)$", line) + if mirrors: + output["mirrors"].append( + {"repo": mirrors.group(1).strip(), "host": mirrors.group(2).strip()} + ) + + tableHeader = re.search( + r"^repo id\s+repo name\s+status", line, re.IGNORECASE + ) + tableRow = re.search( + r"^([^\/]+)\/([^\/]+)\/(.*)\s\s+(\S+.*)\s\s+(\S+.*)$", line + ) + if tableHeader: + insideTable = True + + elif insideTable and tableRow: + output["repos"].append( + { + "repo": tableRow.group(1).strip(), + "version": tableRow.group(2).strip(), + "arch": tableRow.group(3).strip(), + "repo_name": tableRow.group(4).strip(), + "status": tableRow.group(5).strip(), + } + ) + + else: + insideTable = False + + if stderr: + for line in stderr.splitlines(): + if re.search(r"http.*error .*", line, re.IGNORECASE): + if not line in output["errors"]: + output["errors"].append(line) + + return {"output": output} + + +def parser_installed(stdout, stderr, to_camelcase): + output = {"packages": [], "errors": []} + if stdout: + for line in stdout.splitlines(): + package = re.search(r"^([\S\.]+)\.(\S+)\s+(\S+\.\S+)\s+(\S+.*)$", line) + if package: + output["packages"].append( + { + "name": package.group(1).strip(), + "arch": package.group(2).strip(), + "version": package.group(3).strip(), + "status": package.group(4).strip(), + } + ) + + if stderr: + for line in stderr.splitlines(): + if re.search(r"http.*error .*", line, re.IGNORECASE): + if not line in output["errors"]: + output["errors"].append(line) + + return {"output": output} + + +def register(main): + main["yum_repolist"] = { + "cmd": "yum repolist all", + "description": "YUM - defined repositories", + "parser": parser_repolist, + } + + main["yum_installed"] = { + "cmd": "yum list installed", + "description": "YUM - list installed packages", + "parser": parser_installed, + } diff --git a/sysinfo.py b/src/sysinfo/sysinfo.py similarity index 96% rename from sysinfo.py rename to src/sysinfo/sysinfo.py index 58cd0d9..ef4b3c1 100644 --- a/sysinfo.py +++ b/src/sysinfo/sysinfo.py @@ -1,372 +1,372 @@ -""" - * - * sysinfo - Python based scripts for obtaining system information from Linux. - * - * Petr Vavrin (peterbay) pvavrin@gmail.com - * https://github.com/peterbay - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * -""" - -import os -import sys -import glob -import json -import argparse -import subprocess -from threading import Timer -from multiprocessing import Pool -from os.path import dirname, basename, isfile, join - -sys.path.append(join(dirname(__file__), "modules")) - -siModules = {} -PY2 = sys.version_info[0] == 2 -PY3 = sys.version_info[0] == 3 - - -def loadModules(): - global siModules - global PY2 - global PY3 - modules = glob.glob(join(dirname(__file__), "modules", "*.py")) - for f in modules: - if isfile(f) and not f.endswith("__init__.py"): - if PY2: - import imp - - lib = imp.load_source(basename(f)[:-3], f) - if hasattr(lib, "register"): - lib.register(siModules) - else: - from importlib import import_module - - lib = __import__(basename(f)[:-3]) - if hasattr(lib, "register"): - lib.register(siModules) - - -def readFile(pathToFile): - try: - f = open(pathToFile, "r") - content = f.read() - f.close() - return content, None - - except Exception as err: - return None, err - - -def writeToFile(pathToFile, content): - try: - f = open(pathToFile, "w") - f.write(content) - f.close() - - except Exception as err: - sys.stdout.write("ERROR: Can't write to file '%s': %s\n" % (pathToFile, err)) - - -def pathCheck(args): - if args.export_dir: - if not os.access(args.export_dir, os.W_OK): - sys.stdout.write( - "ERROR: Export directory '%s' not exist or is not writable\n" - % (args.export_dir,) - ) - exit(1) - - if args.import_dir: - if not os.access(args.import_dir, os.R_OK): - sys.stdout.write( - "ERROR: Import directory '%s' not exist or is not readable\n" - % (args.import_dir,) - ) - exit(1) - - -def kill(process): - return process.kill() - - -def executeCmd(cmd): - try: - command = cmd.get("cmd", None) - if not command: - cmd["error"] = "Empty command" - return - - proc = subprocess.Popen( - command, - shell=True, - executable="/usr/bin/bash", - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - ) - cmdTimer = Timer(int(cmd.get("timeout", 30)), kill, [proc]) - - try: - cmdTimer.start() - outs, errs = proc.communicate() - - except Exception as err: - print(err) - proc.kill() - outs, errs = proc.communicate() - cmd["error"] = err - - finally: - cmdTimer.cancel() - - except Exception as err: - print(err) - cmd["error"] = err - - if proc: - procPoll = proc.poll() - if procPoll != 0: - cmd["rc"] = procPoll - if not "error" in cmd: - cmd["error"] = "Unknown error" - - if PY2: - cmd["stdout"] = outs - cmd["stderr"] = errs - else: - cmd["stdout"] = str(outs, "utf-8") - cmd["stderr"] = str(errs, "utf-8") - - -def execute(cmd): - if not isinstance(cmd, dict): - return {} - - if "import_dir" in cmd: - commandImportPath = join(cmd.get("import_dir", ""), cmd.get("name", "")) - cmd["stdout"], cmd["stderr"] = readFile(commandImportPath) - - else: - outs, errs = "", "" - to_camelcase = cmd.get("to_camelcase", None) - - if "function" in cmd: - moduleFunction = cmd.get("function", None) - if moduleFunction and callable(moduleFunction): - outs = moduleFunction(to_camelcase) - - cmd["stdout"] = outs - cmd["stderr"] = errs - return cmd - - elif "cmd" in cmd: - executeCmd(cmd) - - return cmd - - -def run(args): - poolSize = int(args.pool) - loadModules() - p = Pool(poolSize) - selectedModules = [] - executeModules = False - results = {} - - to_camelcase = args.camel_case - - for name, settings in sorted(siModules.items()): - if args.list: - sys.stdout.write( - "%-25s - %s\n" - % ( - name, - settings.get("description", ""), - ) - ) - - elif args.info: - if "function" in settings: - info = "built-in function" - else: - info = settings.get("cmd", "") - - sys.stdout.write( - "%-25s - %s\n" - % ( - name, - info, - ) - ) - - elif args.all or name in args.commands: - settings["name"] = name - if args.import_dir: - settings["import_dir"] = args.import_dir - - settings["to_camelcase"] = args.camel_case - selectedModules.append(settings) - executeModules = True - - if executeModules: - for result in p.map(execute, selectedModules): - name = result.get("name", None) - if not name: - continue - - if args.error and not result.get("error", None): - continue - - if args.export_dir: - commandExportPath = join(args.export_dir, name) - writeToFile(commandExportPath, result.get("stdout", None)) - - if args.export_only: - continue - - parser = result.get("parser", None) - if parser and callable(parser): - try: - parsed = parser( - result.get("stdout", None), - result.get("stderr", None), - to_camelcase, - ) - - if isinstance(parsed, dict): - result["output"] = parsed.get("output", None) - result["unprocessed"] = parsed.get("unprocessed", None) - - except Exception as err: - result["parser_error"] = str(err) - - else: - stdout = result.get("stdout", None) - if isinstance(stdout, dict): - result["output"] = stdout.get("output", None) - result["unprocessed"] = stdout.get("unprocessed", None) - - else: - result["output"] = stdout - result["unprocessed"] = [] - - result.pop("parser", None) - result.pop("function", None) - - if not args.verbose and not args.error: - result.pop("stdout", None) - result.pop("stderr", None) - result.pop("rc", None) - result.pop("cmd", None) - result.pop("description", None) - result.pop("name", None) - result.pop("unprocessed", None) - result.pop("import_dir", None) - - results[name] = result - - if not args.export_only: - if args.output: - writeToFile(args.output, json.dumps(results, indent=4, sort_keys=True)) - - else: - sys.stdout.write(json.dumps(results, indent=4, sort_keys=True) + "\n") - - elif not args.list and not args.info: - sys.stdout.write("No commands to execute\n") - - -def argsError(error): - pass - - -def main(argv): - parser = argparse.ArgumentParser() - parser.error = argsError - - parser.add_argument( - "--all", "-a", action="store_true", default=False, help="Execute all commands." - ) - - parser.add_argument( - "--camel-case", - "-c", - action="store_true", - default=False, - help="Convert keys to CamelCase.", - ) - - parser.add_argument( - "--error", - "-e", - action="store_true", - default=False, - help="Show only error outputs from commands.", - ) - - parser.add_argument( - "--export-only", - action="store_true", - default=False, - help="Export output from commands without processing.", - ) - - parser.add_argument( - "--export-dir", help="Path to the directory for saving output from commands." - ) - - parser.add_argument( - "--import-dir", - help="Path to the directory for reading the stored outputs of commands.", - ) - - parser.add_argument( - "--info", - "-i", - action="store_true", - default=False, - help="List all commands with command line arguments.", - ) - - parser.add_argument( - "--list", "-l", action="store_true", default=False, help="List all commands." - ) - - parser.add_argument("--output", "-o", help="Path to the output file.") - - parser.add_argument( - "--pool", - "-p", - default="5", - type=int, - help="Pool size for parallel execution of commands. (default value is 5)", - ) - - parser.add_argument( - "--verbose", - "-v", - action="store_true", - default=False, - help="Add more info to output - options, commands, raw command result.", - ) - - parser.add_argument("commands", nargs="*", help="Commands") - - args = parser.parse_args() - pathCheck(args) - run(args) - - -if __name__ == "__main__": - main(sys.argv) +""" + * + * sysinfo - Python based scripts for obtaining system information from Linux. + * + * Petr Vavrin (peterbay) pvavrin@gmail.com + * https://github.com/peterbay + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * +""" + +import os +import sys +import glob +import json +import argparse +import subprocess +from threading import Timer +from multiprocessing import Pool +from os.path import dirname, basename, isfile, join + +sys.path.append(join(dirname(__file__), "modules")) + +siModules = {} +PY2 = sys.version_info[0] == 2 +PY3 = sys.version_info[0] == 3 + + +def loadModules(): + global siModules + global PY2 + global PY3 + modules = glob.glob(join(dirname(__file__), "modules", "*.py")) + for f in modules: + if isfile(f) and not f.endswith("__init__.py"): + if PY2: + import imp + + lib = imp.load_source(basename(f)[:-3], f) + if hasattr(lib, "register"): + lib.register(siModules) + else: + from importlib import import_module + + lib = __import__(basename(f)[:-3]) + if hasattr(lib, "register"): + lib.register(siModules) + + +def readFile(pathToFile): + try: + f = open(pathToFile, "r") + content = f.read() + f.close() + return content, None + + except Exception as err: + return None, err + + +def writeToFile(pathToFile, content): + try: + f = open(pathToFile, "w") + f.write(content) + f.close() + + except Exception as err: + sys.stdout.write("ERROR: Can't write to file '%s': %s\n" % (pathToFile, err)) + + +def pathCheck(args): + if args.export_dir: + if not os.access(args.export_dir, os.W_OK): + sys.stdout.write( + "ERROR: Export directory '%s' not exist or is not writable\n" + % (args.export_dir,) + ) + exit(1) + + if args.import_dir: + if not os.access(args.import_dir, os.R_OK): + sys.stdout.write( + "ERROR: Import directory '%s' not exist or is not readable\n" + % (args.import_dir,) + ) + exit(1) + + +def kill(process): + return process.kill() + + +def executeCmd(cmd): + try: + command = cmd.get("cmd", None) + if not command: + cmd["error"] = "Empty command" + return + + proc = subprocess.Popen( + command, + shell=True, + executable="/usr/bin/bash", + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + cmdTimer = Timer(int(cmd.get("timeout", 30)), kill, [proc]) + + try: + cmdTimer.start() + outs, errs = proc.communicate() + + except Exception as err: + print(err) + proc.kill() + outs, errs = proc.communicate() + cmd["error"] = err + + finally: + cmdTimer.cancel() + + except Exception as err: + print(err) + cmd["error"] = err + + if proc: + procPoll = proc.poll() + if procPoll != 0: + cmd["rc"] = procPoll + if not "error" in cmd: + cmd["error"] = "Unknown error" + + if PY2: + cmd["stdout"] = outs + cmd["stderr"] = errs + else: + cmd["stdout"] = str(outs, "utf-8") + cmd["stderr"] = str(errs, "utf-8") + + +def execute(cmd): + if not isinstance(cmd, dict): + return {} + + if "import_dir" in cmd: + commandImportPath = join(cmd.get("import_dir", ""), cmd.get("name", "")) + cmd["stdout"], cmd["stderr"] = readFile(commandImportPath) + + else: + outs, errs = "", "" + to_camelcase = cmd.get("to_camelcase", None) + + if "function" in cmd: + moduleFunction = cmd.get("function", None) + if moduleFunction and callable(moduleFunction): + outs = moduleFunction(to_camelcase) + + cmd["stdout"] = outs + cmd["stderr"] = errs + return cmd + + elif "cmd" in cmd: + executeCmd(cmd) + + return cmd + + +def run(args): + poolSize = int(args.pool) + loadModules() + p = Pool(poolSize) + selectedModules = [] + executeModules = False + results = {} + + to_camelcase = args.camel_case + + for name, settings in sorted(siModules.items()): + if args.list: + sys.stdout.write( + "%-25s - %s\n" + % ( + name, + settings.get("description", ""), + ) + ) + + elif args.info: + if "function" in settings: + info = "built-in function" + else: + info = settings.get("cmd", "") + + sys.stdout.write( + "%-25s - %s\n" + % ( + name, + info, + ) + ) + + elif args.all or name in args.commands: + settings["name"] = name + if args.import_dir: + settings["import_dir"] = args.import_dir + + settings["to_camelcase"] = args.camel_case + selectedModules.append(settings) + executeModules = True + + if executeModules: + for result in p.map(execute, selectedModules): + name = result.get("name", None) + if not name: + continue + + if args.error and not result.get("error", None): + continue + + if args.export_dir: + commandExportPath = join(args.export_dir, name) + writeToFile(commandExportPath, result.get("stdout", None)) + + if args.export_only: + continue + + parser = result.get("parser", None) + if parser and callable(parser): + try: + parsed = parser( + result.get("stdout", None), + result.get("stderr", None), + to_camelcase, + ) + + if isinstance(parsed, dict): + result["output"] = parsed.get("output", None) + result["unprocessed"] = parsed.get("unprocessed", None) + + except Exception as err: + result["parser_error"] = str(err) + + else: + stdout = result.get("stdout", None) + if isinstance(stdout, dict): + result["output"] = stdout.get("output", None) + result["unprocessed"] = stdout.get("unprocessed", None) + + else: + result["output"] = stdout + result["unprocessed"] = [] + + result.pop("parser", None) + result.pop("function", None) + + if not args.verbose and not args.error: + result.pop("stdout", None) + result.pop("stderr", None) + result.pop("rc", None) + result.pop("cmd", None) + result.pop("description", None) + result.pop("name", None) + result.pop("unprocessed", None) + result.pop("import_dir", None) + + results[name] = result + + if not args.export_only: + if args.output: + writeToFile(args.output, json.dumps(results, indent=4, sort_keys=True)) + + else: + sys.stdout.write(json.dumps(results, indent=4, sort_keys=True) + "\n") + + elif not args.list and not args.info: + sys.stdout.write("No commands to execute\n") + + +def argsError(error): + pass + + +def main(argv): + parser = argparse.ArgumentParser() + parser.error = argsError + + parser.add_argument( + "--all", "-a", action="store_true", default=False, help="Execute all commands." + ) + + parser.add_argument( + "--camel-case", + "-c", + action="store_true", + default=False, + help="Convert keys to CamelCase.", + ) + + parser.add_argument( + "--error", + "-e", + action="store_true", + default=False, + help="Show only error outputs from commands.", + ) + + parser.add_argument( + "--export-only", + action="store_true", + default=False, + help="Export output from commands without processing.", + ) + + parser.add_argument( + "--export-dir", help="Path to the directory for saving output from commands." + ) + + parser.add_argument( + "--import-dir", + help="Path to the directory for reading the stored outputs of commands.", + ) + + parser.add_argument( + "--info", + "-i", + action="store_true", + default=False, + help="List all commands with command line arguments.", + ) + + parser.add_argument( + "--list", "-l", action="store_true", default=False, help="List all commands." + ) + + parser.add_argument("--output", "-o", help="Path to the output file.") + + parser.add_argument( + "--pool", + "-p", + default="5", + type=int, + help="Pool size for parallel execution of commands. (default value is 5)", + ) + + parser.add_argument( + "--verbose", + "-v", + action="store_true", + default=False, + help="Add more info to output - options, commands, raw command result.", + ) + + parser.add_argument("commands", nargs="*", help="Commands") + + args = parser.parse_args() + pathCheck(args) + run(args) + + +if __name__ == "__main__": + main(sys.argv) diff --git a/src/tests/__init__.py b/src/tests/__init__.py new file mode 100644 index 0000000..e69de29 From 1f9e34bf6d9855e15c6f7c18828292112ed6da26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Lichnovsk=C3=BD?= Date: Fri, 5 Aug 2022 15:51:20 +0200 Subject: [PATCH 5/9] fix: fixed Makefile, docker files and requirements for tests --- Makefile | 19 ++++++++----- docker/build.Dockerfile | 45 ++++++------------------------ docker/test.Dockerfile | 62 +++++++++++++++-------------------------- requirements-test.txt | 7 +---- setup.py | 4 +-- src/sysinfo/__init__.py | 4 ++- src/sysinfo/sysinfo.py | 12 ++++---- 7 files changed, 55 insertions(+), 98 deletions(-) diff --git a/Makefile b/Makefile index f1c7483..cd4ce96 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ NAME=sysinfo IMAGE_NAME=sysinfo ifndef VERSION -VERSION := $(shell python3 -m find_version src/sysinfo/__init__.py || echo 0.0.0) +VERSION := $(shell python3 -c "from setup import find_version;find_version("src/sysinfo/__init__.py")" || echo 0.0.0) endif ifndef BRANCH @@ -14,7 +14,7 @@ COMMIT := $(shell git log -n1 --format="%h") endif ifndef SRC -SRC := src/sysinfo/*.py" +SRC := src/sysinfo/*.py endif ifndef TESTS @@ -23,11 +23,10 @@ endif BUILD_RUN=docker run --rm "$(IMAGE_NAME):$(COMMIT)" -# .PHONY: git black lint build test coverage security -.PHONY: black lint build test coverage security +.PHONY: git black lint build test coverage security -# git: - # @echo "branch: $(BRANCH) commit: $(COMMIT)" +git: + @echo $(branch: [$(BRANCH)] commit: [$(COMMIT)]) black: isort $(SRC) @@ -36,11 +35,17 @@ black: lint: flake8 --max-line-length=120 --max-complexity 8 $(SRC) - # interrogate $(SRC) + interrogate $(SRC) mypy $(SRC) pylint -d C0301 -d R0902 $(SRC) build: + python setup.py build + +install: + python setup.py install + +build_docker: docker build -t $(IMAGE_NAME):$(COMMIT) . -f docker/build.Dockerfile test_docker: diff --git a/docker/build.Dockerfile b/docker/build.Dockerfile index b0a2977..8f468d1 100644 --- a/docker/build.Dockerfile +++ b/docker/build.Dockerfile @@ -1,43 +1,14 @@ -# TODO adjust docker file exaple -# FROM instruction chooses the parent image for Docker. -# This example uses Alpine. -# Alpine is a minimal Docker image very small in size -FROM alpine:3.3 +FROM python:3.10-alpine # LABEL instruction creates labels. -# The first label is maintainer with the value Linux Hint. -# The second label is appname with the value Flask Hello. World -# You can have as many key-to-value pairs as you want. -# You can also choose any name for the keys. -# The choice of maintainer and appname in this example -# is a personal choice. -LABEL "maintainer"="Linux Hint" "appname"="Flask Hello World" -# ENV instruction assigns environment variables. -# The /usr/src directory holds downloaded programs, -# be it source or binary before installing them. +LABEL "maintainer"="Petr Vavrin" "appname"="sysinfo" + ENV applocation /usr/src -# COPY instruction copies files or directories, -# from the Docker host to the Docker image. -# You'll copy the source code to the Docker image. -# The command below uses the set environment variable. -COPY sysinfo $applocation/sysinfo -# Using the ENV instruction again. -ENV flaskapp $applocation/sysinfo -# WORKDIR instruction changes the current directory in Docker image. -# The command below changes directory to /usr/src/flask-helloworld. -# The target directory uses the environment variable. -WORKDIR $flaskapp/ -# RUN instruction runs commands, -# just like you do on the terminal, -# but in the Docker image. -# The command below installs Python, pip and the app dependencies. -# The dependencies are in the requirements.txt file. +COPY src/sysinfo $applocation/sysinfo +ENV app $applocation/sysinfo +WORKDIR $app/ + RUN apk add --update python py-pip RUN pip install --upgrade pip RUN pip install -r requirements.txt -# EXPOSE instruction opens the port for communicating with the Docker container. -# Flask app uses the port 5000, so you'll expose port 5000. -EXPOSE 5000 -# CMD instruction runs commands like RUN, -# but the commands run when the Docker container launches. -# Only one CMD instruction can be used. +#EXPOSE 5000 CMD ["python", "sysinfo.py"] diff --git a/docker/test.Dockerfile b/docker/test.Dockerfile index ca8aeae..40155e4 100644 --- a/docker/test.Dockerfile +++ b/docker/test.Dockerfile @@ -1,44 +1,28 @@ -# TODO adjust docker file exaple -# FROM instruction chooses the parent image for Docker. -# This example uses Alpine. -# Alpine is a minimal Docker image very small in size -FROM alpine:3.3 +FROM python:3.10-alpine # LABEL instruction creates labels. -# The first label is maintainer with the value Linux Hint. -# The second label is appname with the value Flask Hello. World -# You can have as many key-to-value pairs as you want. -# You can also choose any name for the keys. -# The choice of maintainer and appname in this example -# is a personal choice. -LABEL "maintainer"="Linux Hint" "appname"="Flask Hello World" -# ENV instruction assigns environment variables. -# The /usr/src directory holds downloaded programs, -# be it source or binary before installing them. +LABEL "maintainer"="Petr Vavrin" "appname"="sysinfo" + ENV applocation /usr/src -# COPY instruction copies files or directories, -# from the Docker host to the Docker image. -# You'll copy the source code to the Docker image. -# The command below uses the set environment variable. COPY src/sysinfo $applocation/sysinfo COPY src/tests $applocation/tests -# Using the ENV instruction again. -ENV flaskapp $applocation/sysinfo -# WORKDIR instruction changes the current directory in Docker image. -# The command below changes directory to /usr/src/flask-helloworld. -# The target directory uses the environment variable. -WORKDIR $flaskapp/ -# RUN instruction runs commands, -# just like you do on the terminal, -# but in the Docker image. -# The command below installs Python, pip and the app dependencies. -# The dependencies are in the requirements.txt file. -RUN apk add --update python py-pip -RUN pip install --upgrade pip -RUN pip install -r requirements-test.txt -# EXPOSE instruction opens the port for communicating with the Docker container. -# Flask app uses the port 5000, so you'll expose port 5000. -EXPOSE 5000 -# CMD instruction runs commands like RUN, -# but the commands run when the Docker container launches. -# Only one CMD instruction can be used. +ENV app $applocation/sysinfo +ENV tests $applocation/tests +WORKDIR $app/ + +RUN apk add --update python py-pip && \ + pip install --upgrade pip && \ + pip install -r requirements-test.txt && \ + isort $app && \ + black $app && \ + autoflake --remove-all-unused-imports --remove-duplicate-keys --expand-star-imports --recursive --in-place $app && \ + flake8 --max-line-length=120 --max-complexity 8 $app && \ + interrogate $app && \ + mypy $app && \ + pylint -d C0301 -d R0902 $app && \ + pytest $tests && \ + pytest --cov-report term-missing --cov=sysinfo $tests && \ + safety check && \ + bandit -r $app + +#EXPOSE 5000 CMD ["python", "sysinfo.py"] diff --git a/requirements-test.txt b/requirements-test.txt index fe2d492..3fca4d8 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -1,5 +1,4 @@ coverage -bandit pytest pytest-aiohttp pytest-asyncio @@ -8,14 +7,10 @@ pytest-coverage pytest-datafiles autoflake black -flake8 -isort pylint pylint-exit -autoflake bandit certifi -coverage flake8 flake8-polyfill isort @@ -27,8 +22,8 @@ pre-commit py pycodestyle pyflakes -pylint pyparsing safety types-requests typing-extensions +interrogate diff --git a/setup.py b/setup.py index 9f02461..e2c5284 100644 --- a/setup.py +++ b/setup.py @@ -38,7 +38,7 @@ def requirements(fname): # We use the version to construct the DOWNLOAD_URL. -VERSION = find_version("src/sysifo/__init__.py") +VERSION = find_version("src/sysinfo/__init__.py") # URL to the repository on Github. REPO_URL = 'https://github.com/peterbay/sysinfo' @@ -49,7 +49,7 @@ def requirements(fname): INSTALL_REQUIRES = requirements("requirements.txt") EXTRAS_REQUIRE = { - "test": requirements("requirements-dev.txt"), + "test": requirements("requirements-test.txt"), } try: diff --git a/src/sysinfo/__init__.py b/src/sysinfo/__init__.py index 62dae51..04bdaf8 100644 --- a/src/sysinfo/__init__.py +++ b/src/sysinfo/__init__.py @@ -26,7 +26,9 @@ __program__ = "sysinfo" __executable__ = "sysinfo" -__description__ = "sysinfo - Python based scripts for obtaining system information from Linux." +__description__ = ( + "sysinfo - Python based scripts for obtaining system information from Linux." +) __author__ = "Petr Vavrin" __email__ = "pvavrin@gmail.com" __version__ = "0.0.1" diff --git a/src/sysinfo/sysinfo.py b/src/sysinfo/sysinfo.py index ef4b3c1..9346e5e 100644 --- a/src/sysinfo/sysinfo.py +++ b/src/sysinfo/sysinfo.py @@ -20,15 +20,15 @@ * """ -import os -import sys +import argparse import glob import json -import argparse +import os import subprocess -from threading import Timer +import sys from multiprocessing import Pool -from os.path import dirname, basename, isfile, join +from os.path import basename, dirname, isfile, join +from threading import Timer sys.path.append(join(dirname(__file__), "modules")) @@ -51,7 +51,7 @@ def loadModules(): if hasattr(lib, "register"): lib.register(siModules) else: - from importlib import import_module + pass lib = __import__(basename(f)[:-3]) if hasattr(lib, "register"): From 2dc5feb14a19d2e7e7c9b948518aedecefa6aad7 Mon Sep 17 00:00:00 2001 From: Petr Vavrin Date: Fri, 5 Aug 2022 20:19:59 +0200 Subject: [PATCH 6/9] added modules: assoc and ethtool, fixed execution under windows, added argument --system for enforcing system type --- README.md | 60 +++++-- src/sysinfo/modules/arp.py | 14 +- src/sysinfo/modules/assoc.py | 33 ++++ src/sysinfo/modules/blkid.py | 14 +- src/sysinfo/modules/blockdev.py | 30 ++-- src/sysinfo/modules/busctl.py | 46 +++-- src/sysinfo/modules/chage.py | 14 +- src/sysinfo/modules/chrt.py | 14 +- src/sysinfo/modules/compgen.py | 126 +++++++++----- src/sysinfo/modules/dev_disk.py | 14 +- src/sysinfo/modules/dev_input.py | 14 +- src/sysinfo/modules/df.py | 14 +- src/sysinfo/modules/dmidecode.py | 158 +++++++++++------- src/sysinfo/modules/dnf.py | 30 ++-- src/sysinfo/modules/env.py | 14 +- src/sysinfo/modules/etc_default.py | 14 +- src/sysinfo/modules/etc_fstab.py | 14 +- src/sysinfo/modules/etc_group.py | 14 +- src/sysinfo/modules/etc_hosts.py | 14 +- src/sysinfo/modules/etc_locale_gen.py | 14 +- src/sysinfo/modules/etc_mtab.py | 14 +- src/sysinfo/modules/etc_passwd.py | 14 +- src/sysinfo/modules/etc_release.py | 14 +- src/sysinfo/modules/etc_shadow.py | 14 +- src/sysinfo/modules/etc_timezone.py | 14 +- src/sysinfo/modules/ethtool.py | 40 +++++ src/sysinfo/modules/fbset.py | 30 ++-- src/sysinfo/modules/findmnt.py | 14 +- src/sysinfo/modules/free.py | 14 +- src/sysinfo/modules/getconf.py | 14 +- src/sysinfo/modules/hostnamectl.py | 14 +- src/sysinfo/modules/ifconfig.py | 14 +- src/sysinfo/modules/lsblk.py | 14 +- src/sysinfo/modules/lscpu.py | 14 +- src/sysinfo/modules/lsmod.py | 14 +- src/sysinfo/modules/lsns.py | 14 +- src/sysinfo/modules/lsof.py | 14 +- src/sysinfo/modules/lspci.py | 14 +- src/sysinfo/modules/lsusb.py | 14 +- src/sysinfo/modules/modinfo.py | 14 +- src/sysinfo/modules/parted.py | 14 +- src/sysinfo/modules/proc_buddyinfo.py | 14 +- src/sysinfo/modules/proc_bus_input.py | 14 +- src/sysinfo/modules/proc_cgroups.py | 14 +- src/sysinfo/modules/proc_cmdline.py | 14 +- src/sysinfo/modules/proc_consoles.py | 14 +- src/sysinfo/modules/proc_cpuinfo.py | 14 +- src/sysinfo/modules/proc_crypto.py | 14 +- src/sysinfo/modules/proc_devices.py | 14 +- src/sysinfo/modules/proc_diskstats.py | 14 +- src/sysinfo/modules/proc_dma.py | 14 +- src/sysinfo/modules/proc_filesystems.py | 14 +- src/sysinfo/modules/proc_fs.py | 16 +- src/sysinfo/modules/proc_iomem.py | 14 +- src/sysinfo/modules/proc_ioports.py | 14 +- src/sysinfo/modules/proc_loadavg.py | 14 +- src/sysinfo/modules/proc_locks.py | 14 +- src/sysinfo/modules/proc_meminfo.py | 14 +- src/sysinfo/modules/proc_modules.py | 14 +- src/sysinfo/modules/proc_mounts.py | 14 +- src/sysinfo/modules/proc_net.py | 126 ++++++++------ src/sysinfo/modules/proc_partitions.py | 14 +- src/sysinfo/modules/proc_scsi.py | 14 +- src/sysinfo/modules/proc_slabinfo.py | 14 +- src/sysinfo/modules/proc_stat.py | 14 +- src/sysinfo/modules/proc_swaps.py | 14 +- src/sysinfo/modules/proc_sys.py | 14 +- src/sysinfo/modules/proc_uptime.py | 14 +- src/sysinfo/modules/proc_version.py | 14 +- src/sysinfo/modules/proc_version_signature.py | 14 +- src/sysinfo/modules/proc_vmstat.py | 14 +- src/sysinfo/modules/prtstat.py | 14 +- src/sysinfo/modules/ps.py | 14 +- src/sysinfo/modules/python.py | 24 ++- src/sysinfo/modules/route.py | 14 +- src/sysinfo/modules/rpm.py | 14 +- src/sysinfo/modules/services_status.py | 30 ++-- src/sysinfo/modules/sysctl.py | 30 ++-- src/sysinfo/modules/timedatectl.py | 30 ++-- src/sysinfo/modules/udevadm.py | 30 ++-- src/sysinfo/modules/uname.py | 126 ++++++++------ src/sysinfo/modules/update_alternatives.py | 14 +- src/sysinfo/modules/vmstat.py | 62 ++++--- src/sysinfo/modules/yum.py | 28 ++-- src/sysinfo/sysinfo.py | 62 +++++-- 85 files changed, 1330 insertions(+), 697 deletions(-) create mode 100644 src/sysinfo/modules/assoc.py create mode 100644 src/sysinfo/modules/ethtool.py diff --git a/README.md b/README.md index 3208a19..c813e8e 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ optional arguments: --list, -l List all commands. --output OUTPUT, -o OUTPUT Path to the output file. --pool POOL, -p POOL Pool size for parallel execution of commands. (default value is 5) + --system SYSTEM, -s SYSTEM Execute or parse commands for selected system [linux, darwin, java, windows]. --verbose, -v Add more info to output - options, commands, raw command result. ``` ## Examples @@ -103,11 +104,17 @@ sudo python sysinfo.py --import-dir ./out blkid ## Available commands ``` +arp - System ARP cache blkid - Block device attributes blockdev - Block device ioctls +blockdev_detail - Block device ioctls details busctl - Introspect the bus +busctl_status - Process information and credentials of a bus service +busctl_tree - Object tree for services +chage - Users password expiration information chrt - Scheduling attributes of all the tasks (threads) dev_disk - Disk devices mapping +dev_input - Input devices mapping df - Report file system disk space usage dmidecode - Dumping all information from DMI (SMBIOS) dmidecode_baseboard - Dumping BASEBOARD information from DMI (SMBIOS) @@ -137,14 +144,14 @@ fbset_info - Show frame buffer device information findmnt - List all mounted filesytems free - Amount of free and used memory in the system getconf - Configuration variables for the current system and their values -groups - Group names -hardware_platform - Hardware platform +groups - Group names (compgen) +hardware_platform - Hardware platform (uname) hostnamectl - Current system hostname and related information ifconfig - List all interfaces which are currently available, even if down -jobs - Job names, if job control is active -kernel_name - Kernel name -kernel_release - Kernel release -kernel_version - Kernel version +jobs - Job names, if job control is active (compgen) +kernel_name - Kernel name (uname) +kernel_release - Kernel release (uname) +kernel_version - Kernel version (uname) lsblk - Lists information about all block devices lscpu - Information about the CPU architecture lsmod - Show the status of modules in the Linux Kernel @@ -152,11 +159,14 @@ lsns - Block device ioctls lsof - Information about files opened by processes lspci - List all PCI devices lsusb - List USB devices -machine - Machine hardware name +machine - Machine hardware name (uname) modinfo - Information about a Linux Kernel modules -nodename - Network node hostname -operating_system - Operating system +nodename - Network node hostname (uname) +operating_system - Operating system (uname) parted - Lists partition layout on all block devices +proc_buddyinfo - Memory fragmentation +proc_bus_input - Input devices +proc_cgroups - Control groups proc_cmdline - Parameters passed to the kernel at the time it is started proc_consoles - Information about current consoles including tty proc_cpuinfo - Type of processor used by your system @@ -173,33 +183,47 @@ proc_locks - Files currently locked by the kernel proc_meminfo - Reports a large amount of valuable information about the systems RAM usage proc_modules - List of all modules loaded into the kernel proc_mounts - List mounted filesystems (info provides from kernel) +proc_net_arp - ARP +proc_net_ax25_route - AX25 routing information +proc_net_ipx_route - IPX routing information +proc_net_route - IP routing information +proc_net_tcp - TCP socket table +proc_net_tcp6 - TCP6 socket table +proc_net_udp - UDP socket table +proc_net_udp6 - UDP6 socket table proc_partitions - Partition block allocation information proc_scsi - List of every recognized SCSI device +proc_slabinfo - Kernel caches informations +proc_stat - Kernel/system statistics proc_swaps - Measures swap space and its utilization proc_sys - Information about the system and kernel features proc_uptime - Information detailing how long the system has been on since its last restart proc_version - Version of the Linux kernel, the version of gcc used to compile the kernel, and the time of kernel compilation +proc_version_signature - OS version signature proc_vmstat - Detailed virtual memory statistics from the kernel -processor - Processor type +processor - Processor type (uname) prtstat - Print statistics of a processes ps - Report a snapshot of the current processes python_pip_packages - List available python modules python_platform - Probe the underlying platform's hardware, operating system, and Python interpreter version information +route - IP routing table rpm - Querying all RPM packages -services - Service names +services - Service names (compgen) services_list - Displays services with status -services_params - Displays services with status -shell_alias - Shell alias names -shell_all_commands - Shell command names -shell_builtins - Names of shell builtin commands -shell_exported_variables - Names of exported shell variables -shell_variables - Names of all shell variables +services_params - Displays services with params +shell_alias - Shell alias names (compgen) +shell_all_commands - Shell command names (compgen) +shell_builtins - Names of shell builtin commands (compgen) +shell_exported_variables - Names of exported shell variables (compgen) +shell_variables - Names of all shell variables (compgen) sysctl - Runtime kernel parameters sysctl_system - Runtime kernel parameters from all system configuration files timedatectl - System time and date +timedatectl_timesync - Status of systemd-timesyncd.service udevadm - Queries the udev database for device information stored in the udev database udevadm_block_devices - Queries the udev database for block device information stored in the udev database -users - User names +update_alternatives - Symbolic links determining default commands +users - User names (compgen) vmstat_disk - Report disk statistics vmstat_disk_sum - Report some summary statistics about disk activity vmstat_forks - Displays the number of forks since boot diff --git a/src/sysinfo/modules/arp.py b/src/sysinfo/modules/arp.py index 1406f3b..ad06a82 100644 --- a/src/sysinfo/modules/arp.py +++ b/src/sysinfo/modules/arp.py @@ -13,8 +13,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["arp"] = { - "cmd": """arp""", - "description": "System ARP cache", - "parser": parser, - } + main.register( + { + "name": "arp", + "system": ["linux"], + "cmd": "arp", + "description": "System ARP cache", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/assoc.py b/src/sysinfo/modules/assoc.py new file mode 100644 index 0000000..869ee03 --- /dev/null +++ b/src/sysinfo/modules/assoc.py @@ -0,0 +1,33 @@ +import re +from sysinfo_lib import parseTable, tableToDict, camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + + if stdout: + device = "" + for line in stdout.splitlines(): + kv = re.search(r"^([^=]+)=(.*)$", line) + if kv: + key = kv.group(1) + value = kv.group(2) + output[key] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main.register( + { + "name": "assoc", + "system": ["windows"], + "cmd": "assoc", + "description": "File associations", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/blkid.py b/src/sysinfo/modules/blkid.py index 7046625..d2334af 100644 --- a/src/sysinfo/modules/blkid.py +++ b/src/sysinfo/modules/blkid.py @@ -28,8 +28,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["blkid"] = { - "cmd": """blkid -o device | xargs -n 1 -I {} sh -c "echo '>>> Device: {}'; blkid -o export -p {}; blkid -o export -i {}" """, - "description": "Block device attributes", - "parser": parser, - } + main.register( + { + "name": "blkid", + "system": ["linux"], + "cmd": """blkid -o device | xargs -n 1 -I {} sh -c "echo '>>> Device: {}'; blkid -o export -p {}; blkid -o export -i {}" """, + "description": "Block device attributes", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/blockdev.py b/src/sysinfo/modules/blockdev.py index 33831f5..bae3b54 100644 --- a/src/sysinfo/modules/blockdev.py +++ b/src/sysinfo/modules/blockdev.py @@ -36,14 +36,22 @@ def parser_detail(stdout, stderr, to_camelcase): def register(main): - main["blockdev"] = { - "cmd": "blockdev --report | column -t", - "description": "Block device ioctls", - "parser": parser, - } - - main["blockdev_detail"] = { - "cmd": """blkid -o device | xargs -n 1 -I {} sh -c "echo '>>> Device: {}'; blockdev -v --getalignoff --getbsz --getdiscardzeroes --getfra --getiomin --getioopt --getmaxsect --getpbsz --getra --getro --getsize64 --getss {}" """, - "description": "Block device ioctls details", - "parser": parser_detail, - } + main.register( + { + "name": "blockdev", + "system": ["linux"], + "cmd": "blockdev --report | column -t", + "description": "Block device ioctls", + "parser": parser, + } + ) + + main.register( + { + "name": "blockdev_detail", + "system": ["linux"], + "cmd": """blkid -o device | xargs -n 1 -I {} sh -c "echo '>>> Device: {}'; blockdev -v --getalignoff --getbsz --getdiscardzeroes --getfra --getiomin --getioopt --getmaxsect --getpbsz --getra --getro --getsize64 --getss {}" """, + "description": "Block device ioctls details", + "parser": parser_detail, + } + ) diff --git a/src/sysinfo/modules/busctl.py b/src/sysinfo/modules/busctl.py index a0ba1dc..7d3a107 100644 --- a/src/sysinfo/modules/busctl.py +++ b/src/sysinfo/modules/busctl.py @@ -81,20 +81,32 @@ def parser_status(stdout, stderr, to_camelcase): def register(main): - main["busctl"] = { - "cmd": "busctl --no-pager | column -t", - "description": "Introspect the bus", - "parser": parser, - } - - main["busctl_tree"] = { - "cmd": "busctl --no-pager --list tree", - "description": "Object tree for services", - "parser": parser_tree, - } - - main["busctl_status"] = { - "cmd": """busctl list | awk '!/^(NAME)/ {print $1}' | xargs -n 1 -I {} sh -c "echo '>>> Device: {}'; busctl --no-pager status {}" """, - "description": "Process information and credentials of a bus service", - "parser": parser_status, - } + main.register( + { + "name": "busctl", + "system": ["linux"], + "cmd": "busctl --no-pager | column -t", + "description": "Introspect the bus", + "parser": parser, + } + ) + + main.register( + { + "name": "busctl_tree", + "system": ["linux"], + "cmd": "busctl --no-pager --list tree", + "description": "Object tree for services", + "parser": parser_tree, + } + ) + + main.register( + { + "name": "busctl_status", + "system": ["linux"], + "cmd": """busctl list | awk '!/^(NAME)/ {print $1}' | xargs -n 1 -I {} sh -c "echo '>>> Device: {}'; busctl --no-pager status {}" """, + "description": "Process information and credentials of a bus service", + "parser": parser_status, + } + ) diff --git a/src/sysinfo/modules/chage.py b/src/sysinfo/modules/chage.py index 81d8fa9..d766867 100644 --- a/src/sysinfo/modules/chage.py +++ b/src/sysinfo/modules/chage.py @@ -29,8 +29,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["chage"] = { - "cmd": """cat /etc/passwd | awk '{split($0,a,":"); print a[1]}' | xargs -I {} sh -c "echo '>>> User: {}'; chage -l {}" """, - "description": "Users password expiration information", - "parser": parser, - } + main.register( + { + "name": "chage", + "system": ["linux"], + "cmd": """cat /etc/passwd | awk '{split($0,a,":"); print a[1]}' | xargs -I {} sh -c "echo '>>> User: {}'; chage -l {}" """, + "description": "Users password expiration information", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/chrt.py b/src/sysinfo/modules/chrt.py index 495193c..b27e22e 100644 --- a/src/sysinfo/modules/chrt.py +++ b/src/sysinfo/modules/chrt.py @@ -45,8 +45,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["chrt"] = { - "cmd": """ps -eo pid | grep -vi pid | xargs -I {} sh -c "echo '>>> PID: {}'; chrt -a --pid {}; echo '----'; chrt -m --pid {};" """, - "description": "Scheduling attributes of all the tasks (threads)", - "parser": parser, - } + main.register( + { + "name": "chrt", + "system": ["linux"], + "cmd": """ps -eo pid | grep -vi pid | xargs -I {} sh -c "echo '>>> PID: {}'; chrt -a --pid {}; echo '----'; chrt -m --pid {};" """, + "description": "Scheduling attributes of all the tasks (threads)", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/compgen.py b/src/sysinfo/modules/compgen.py index c7c0537..89454f2 100644 --- a/src/sysinfo/modules/compgen.py +++ b/src/sysinfo/modules/compgen.py @@ -10,56 +10,92 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["shell_alias"] = { - "cmd": '$(which bash) -c "compgen -a"', - "description": "Shell alias names (compgen)", - "parser": parser, - } + main.register( + { + "name": "shell_alias", + "system": ["linux"], + "cmd": '$(which bash) -c "compgen -a"', + "description": "Shell alias names (compgen)", + "parser": parser, + } + ) - main["shell_builtins"] = { - "cmd": '$(which bash) -c "compgen -b"', - "description": "Names of shell builtin commands (compgen)", - "parser": parser, - } + main.register( + { + "name": "shell_builtins", + "system": ["linux"], + "cmd": '$(which bash) -c "compgen -b"', + "description": "Names of shell builtin commands (compgen)", + "parser": parser, + } + ) - main["shell_all_commands"] = { - "cmd": '$(which bash) -c "compgen -c"', - "description": "Shell command names (compgen)", - "parser": parser, - } + main.register( + { + "name": "shell_all_commands", + "system": ["linux"], + "cmd": '$(which bash) -c "compgen -c"', + "description": "Shell command names (compgen)", + "parser": parser, + } + ) - main["shell_exported_variables"] = { - "cmd": '$(which bash) -c "compgen -e"', - "description": "Names of exported shell variables (compgen)", - "parser": parser, - } + main.register( + { + "name": "shell_exported_variables", + "system": ["linux"], + "cmd": '$(which bash) -c "compgen -e"', + "description": "Names of exported shell variables (compgen)", + "parser": parser, + } + ) - main["shell_variables"] = { - "cmd": '$(which bash) -c "compgen -v"', - "description": "Names of all shell variables (compgen)", - "parser": parser, - } + main.register( + { + "name": "shell_variables", + "system": ["linux"], + "cmd": '$(which bash) -c "compgen -v"', + "description": "Names of all shell variables (compgen)", + "parser": parser, + } + ) - main["groups"] = { - "cmd": '$(which bash) -c "compgen -g"', - "description": "Group names (compgen)", - "parser": parser, - } + main.register( + { + "name": "groups", + "system": ["linux"], + "cmd": '$(which bash) -c "compgen -g"', + "description": "Group names (compgen)", + "parser": parser, + } + ) - main["jobs"] = { - "cmd": '$(which bash) -c "compgen -j"', - "description": "Job names, if job control is active (compgen)", - "parser": parser, - } + main.register( + { + "name": "jobs", + "system": ["linux"], + "cmd": '$(which bash) -c "compgen -j"', + "description": "Job names, if job control is active (compgen)", + "parser": parser, + } + ) - main["services"] = { - "cmd": '$(which bash) -c "compgen -s"', - "description": "Service names (compgen)", - "parser": parser, - } + main.register( + { + "name": "services", + "system": ["linux"], + "cmd": '$(which bash) -c "compgen -s"', + "description": "Service names (compgen)", + "parser": parser, + } + ) - main["users"] = { - "cmd": '$(which bash) -c "compgen -u"', - "description": "User names (compgen)", - "parser": parser, - } + main.register( + { + "name": "users", + "system": ["linux"], + "cmd": '$(which bash) -c "compgen -u"', + "description": "User names (compgen)", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/dev_disk.py b/src/sysinfo/modules/dev_disk.py index 7a759fe..9d16c4f 100644 --- a/src/sysinfo/modules/dev_disk.py +++ b/src/sysinfo/modules/dev_disk.py @@ -35,8 +35,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["dev_disk"] = { - "cmd": "ls -l /dev/disk/by-*", - "description": "Disk devices mapping", - "parser": parser, - } + main.register( + { + "name": "dev_disk", + "system": ["linux"], + "cmd": "ls -l /dev/disk/by-*", + "description": "Disk devices mapping", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/dev_input.py b/src/sysinfo/modules/dev_input.py index e71519f..8d37464 100644 --- a/src/sysinfo/modules/dev_input.py +++ b/src/sysinfo/modules/dev_input.py @@ -35,8 +35,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["dev_input"] = { - "cmd": "ls -l /dev/input/by-*", - "description": "Input devices mapping", - "parser": parser, - } + main.register( + { + "name": "dev_input", + "system": ["linux"], + "cmd": "ls -l /dev/input/by-*", + "description": "Input devices mapping", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/df.py b/src/sysinfo/modules/df.py index 163c045..800eeb5 100644 --- a/src/sysinfo/modules/df.py +++ b/src/sysinfo/modules/df.py @@ -38,8 +38,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["df"] = { - "cmd": "df -a --output=source,fstype,itotal,iused,iavail,ipcent,size,used,avail,pcent,file,target", - "description": "Report file system disk space usage", - "parser": parser, - } + main.register( + { + "name": "df", + "system": ["linux"], + "cmd": "df -a --output=source,fstype,itotal,iused,iavail,ipcent,size,used,avail,pcent,file,target", + "description": "Report file system disk space usage", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/dmidecode.py b/src/sysinfo/modules/dmidecode.py index 57aeddd..fc78adb 100644 --- a/src/sysinfo/modules/dmidecode.py +++ b/src/sysinfo/modules/dmidecode.py @@ -106,62 +106,102 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["dmidecode"] = { - "cmd": "dmidecode", - "description": "Dumping all information from DMI (SMBIOS)", - "parser": parser, - } - - main["dmidecode_bios"] = { - "cmd": "dmidecode -t bios", - "description": "Dumping BIOS information from DMI (SMBIOS)", - "parser": parser, - } - - main["dmidecode_system"] = { - "cmd": "dmidecode -t system", - "description": "Dumping SYSTEM information from DMI (SMBIOS)", - "parser": parser, - } - - main["dmidecode_baseboard"] = { - "cmd": "dmidecode -t baseboard", - "description": "Dumping BASEBOARD information from DMI (SMBIOS)", - "parser": parser, - } - - main["dmidecode_chassis"] = { - "cmd": "dmidecode -t chassis", - "description": "Dumping CHASSIS information from DMI (SMBIOS)", - "parser": parser, - } - - main["dmidecode_processor"] = { - "cmd": "dmidecode -t processor", - "description": "Dumping CHASSIS information from DMI (SMBIOS)", - "parser": parser, - } - - main["dmidecode_memory"] = { - "cmd": "dmidecode -t memory", - "description": "Dumping MEMORY information from DMI (SMBIOS)", - "parser": parser, - } - - main["dmidecode_cache"] = { - "cmd": "dmidecode -t cache", - "description": "Dumping CACHE information from DMI (SMBIOS)", - "parser": parser, - } - - main["dmidecode_connector"] = { - "cmd": "dmidecode -t connector", - "description": "Dumping CONNECTOR information from DMI (SMBIOS)", - "parser": parser, - } - - main["dmidecode_slot"] = { - "cmd": "dmidecode -t slot", - "description": "Dumping SLOT information from DMI (SMBIOS)", - "parser": parser, - } + main.register( + { + "name": "dmidecode", + "system": ["linux"], + "cmd": "dmidecode", + "description": "Dumping all information from DMI (SMBIOS)", + "parser": parser, + } + ) + + main.register( + { + "name": "dmidecode_bios", + "system": ["linux"], + "cmd": "dmidecode -t bios", + "description": "Dumping BIOS information from DMI (SMBIOS)", + "parser": parser, + } + ) + + main.register( + { + "name": "dmidecode_system", + "system": ["linux"], + "cmd": "dmidecode -t system", + "description": "Dumping SYSTEM information from DMI (SMBIOS)", + "parser": parser, + } + ) + + main.register( + { + "name": "dmidecode_baseboard", + "system": ["linux"], + "cmd": "dmidecode -t baseboard", + "description": "Dumping BASEBOARD information from DMI (SMBIOS)", + "parser": parser, + } + ) + + main.register( + { + "name": "dmidecode_chassis", + "system": ["linux"], + "cmd": "dmidecode -t chassis", + "description": "Dumping CHASSIS information from DMI (SMBIOS)", + "parser": parser, + } + ) + + main.register( + { + "name": "dmidecode_processor", + "system": ["linux"], + "cmd": "dmidecode -t processor", + "description": "Dumping CHASSIS information from DMI (SMBIOS)", + "parser": parser, + } + ) + + main.register( + { + "name": "dmidecode_memory", + "system": ["linux"], + "cmd": "dmidecode -t memory", + "description": "Dumping MEMORY information from DMI (SMBIOS)", + "parser": parser, + } + ) + + main.register( + { + "name": "dmidecode_cache", + "system": ["linux"], + "cmd": "dmidecode -t cache", + "description": "Dumping CACHE information from DMI (SMBIOS)", + "parser": parser, + } + ) + + main.register( + { + "name": "dmidecode_connector", + "system": ["linux"], + "cmd": "dmidecode -t connector", + "description": "Dumping CONNECTOR information from DMI (SMBIOS)", + "parser": parser, + } + ) + + main.register( + { + "name": "dmidecode_slot", + "system": ["linux"], + "cmd": "dmidecode -t slot", + "description": "Dumping SLOT information from DMI (SMBIOS)", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/dnf.py b/src/sysinfo/modules/dnf.py index 977561f..fb71b2c 100644 --- a/src/sysinfo/modules/dnf.py +++ b/src/sysinfo/modules/dnf.py @@ -68,14 +68,22 @@ def parser_installed(stdout, stderr, to_camelcase): def register(main): - main["dnf_repolist"] = { - "cmd": "dnf repolist --all", - "description": "DNF - defined repositories", - "parser": parser_repolist, - } - - main["dnf_installed"] = { - "cmd": "dnf list installed", - "description": "DNF - list installed packages", - "parser": parser_installed, - } + main.register( + { + "name": "dnf_repolist", + "system": ["linux"], + "cmd": "dnf repolist --all", + "description": "DNF - defined repositories", + "parser": parser_repolist, + } + ) + + main.register( + { + "name": "dnf_installed", + "system": ["linux"], + "cmd": "dnf list installed", + "description": "DNF - list installed packages", + "parser": parser_installed, + } + ) diff --git a/src/sysinfo/modules/env.py b/src/sysinfo/modules/env.py index 388d416..55f17f8 100644 --- a/src/sysinfo/modules/env.py +++ b/src/sysinfo/modules/env.py @@ -18,8 +18,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["env"] = { - "cmd": "env", - "description": "Environment variables", - "parser": parser, - } + main.register( + { + "name": "env", + "system": ["linux"], + "cmd": "env", + "description": "Environment variables", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/etc_default.py b/src/sysinfo/modules/etc_default.py index a38658e..0f28803 100644 --- a/src/sysinfo/modules/etc_default.py +++ b/src/sysinfo/modules/etc_default.py @@ -47,8 +47,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["etc_default"] = { - "cmd": 'find /etc/default -type f -follow -print | xargs grep ""', - "description": "Default configuration for programs", - "parser": parser, - } + main.register( + { + "name": "etc_default", + "system": ["linux"], + "cmd": 'find /etc/default -type f -follow -print | xargs grep ""', + "description": "Default configuration for programs", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/etc_fstab.py b/src/sysinfo/modules/etc_fstab.py index ff57d23..a7fbde0 100644 --- a/src/sysinfo/modules/etc_fstab.py +++ b/src/sysinfo/modules/etc_fstab.py @@ -28,8 +28,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["etc_fstab"] = { - "cmd": "cat /etc/fstab", - "description": "Filesystems mounted on boot", - "parser": parser, - } + main.register( + { + "name": "etc_fstab", + "system": ["linux"], + "cmd": "cat /etc/fstab", + "description": "Filesystems mounted on boot", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/etc_group.py b/src/sysinfo/modules/etc_group.py index 15f56d1..0f4e3e4 100644 --- a/src/sysinfo/modules/etc_group.py +++ b/src/sysinfo/modules/etc_group.py @@ -10,8 +10,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["etc_group"] = { - "cmd": "cat /etc/group", - "description": "Groups essential information", - "parser": parser, - } + main.register( + { + "name": "etc_group", + "system": ["linux"], + "cmd": "cat /etc/group", + "description": "Groups essential information", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/etc_hosts.py b/src/sysinfo/modules/etc_hosts.py index 55ae435..1c07c48 100644 --- a/src/sysinfo/modules/etc_hosts.py +++ b/src/sysinfo/modules/etc_hosts.py @@ -63,8 +63,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["etc_hosts"] = { - "cmd": """grep "" /etc/hosts*""", - "description": "Maps hostnames to IP addresses", - "parser": parser, - } + main.register( + { + "name": "etc_hosts", + "system": ["linux"], + "cmd": """grep "" /etc/hosts*""", + "description": "Maps hostnames to IP addresses", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/etc_locale_gen.py b/src/sysinfo/modules/etc_locale_gen.py index 7ae0d18..6792e8f 100644 --- a/src/sysinfo/modules/etc_locale_gen.py +++ b/src/sysinfo/modules/etc_locale_gen.py @@ -19,8 +19,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["etc_locale_gen"] = { - "cmd": "cat /etc/locale.gen", - "description": "Configuration file for locale-gen", - "parser": parser, - } + main.register( + { + "name": "etc_locale_gen", + "system": ["linux"], + "cmd": "cat /etc/locale.gen", + "description": "Configuration file for locale-gen", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/etc_mtab.py b/src/sysinfo/modules/etc_mtab.py index 4972582..f08ed57 100644 --- a/src/sysinfo/modules/etc_mtab.py +++ b/src/sysinfo/modules/etc_mtab.py @@ -39,8 +39,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["etc_mtab"] = { - "cmd": "cat /etc/mtab", - "description": "Currently mounted filesystems", - "parser": parser, - } + main.register( + { + "name": "etc_mtab", + "system": ["linux"], + "cmd": "cat /etc/mtab", + "description": "Currently mounted filesystems", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/etc_passwd.py b/src/sysinfo/modules/etc_passwd.py index adbfe9c..e053172 100644 --- a/src/sysinfo/modules/etc_passwd.py +++ b/src/sysinfo/modules/etc_passwd.py @@ -9,8 +9,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["etc_passwd"] = { - "cmd": "cat /etc/passwd", - "description": "Attributes of each user or account on a computer", - "parser": parser, - } + main.register( + { + "name": "etc_passwd", + "system": ["linux"], + "cmd": "cat /etc/passwd", + "description": "Attributes of each user or account on a computer", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/etc_release.py b/src/sysinfo/modules/etc_release.py index 8583b93..91cb598 100644 --- a/src/sysinfo/modules/etc_release.py +++ b/src/sysinfo/modules/etc_release.py @@ -21,8 +21,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["etc_release"] = { - "cmd": "cat /etc/*release", - "description": "OS release info", - "parser": parser, - } + main.register( + { + "name": "etc_release", + "system": ["linux"], + "cmd": "cat /etc/*release", + "description": "OS release info", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/etc_shadow.py b/src/sysinfo/modules/etc_shadow.py index 30117e6..fd7ba57 100644 --- a/src/sysinfo/modules/etc_shadow.py +++ b/src/sysinfo/modules/etc_shadow.py @@ -19,8 +19,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["etc_shadow"] = { - "cmd": "cat /etc/shadow", - "description": "Shadow database of the passwd file", - "parser": parser, - } + main.register( + { + "name": "etc_shadow", + "system": ["linux"], + "cmd": "cat /etc/shadow", + "description": "Shadow database of the passwd file", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/etc_timezone.py b/src/sysinfo/modules/etc_timezone.py index d975a84..49f009c 100644 --- a/src/sysinfo/modules/etc_timezone.py +++ b/src/sysinfo/modules/etc_timezone.py @@ -8,8 +8,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["etc_timezone"] = { - "cmd": "cat /etc/timezone", - "description": "Timezone settings", - "parser": parser, - } + main.register( + { + "name": "etc_timezone", + "system": ["linux"], + "cmd": "cat /etc/timezone", + "description": "Timezone settings", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/ethtool.py b/src/sysinfo/modules/ethtool.py new file mode 100644 index 0000000..a795321 --- /dev/null +++ b/src/sysinfo/modules/ethtool.py @@ -0,0 +1,40 @@ +import re +from sysinfo_lib import camelCase + + +def parser(stdout, stderr, to_camelcase): + output = {} + unprocessed = [] + user = None + + if stdout: + for line in stdout.splitlines(): + user_match = re.search(r"^>>> User:\s+(.*)$", line) + if user_match: + user = user_match.group(1) + output[user] = {"name": user} + continue + + kv = re.search(r"^([^:]+):\s*(.*)$", line) + if user and kv: + key = camelCase(kv.group(1).strip(), to_camelcase) + value = kv.group(2).strip() + + output[user][key] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + main.register( + { + "name": "chage", + "system": ["linux"], + "cmd": """ifconfig -a -s | grep -v "Iface" | awk '{split($0,a," "); print a[1]}' | xargs -I {} sh -c "echo '>>> Device: {}'; ethtool -i {}" """, + "description": "Users password expiration information", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/fbset.py b/src/sysinfo/modules/fbset.py index 32e2718..9f44b7a 100644 --- a/src/sysinfo/modules/fbset.py +++ b/src/sysinfo/modules/fbset.py @@ -106,14 +106,22 @@ def parserInfo(stdout, stderr, to_camelcase): def register(main): - main["fbset"] = { - "cmd": "fbset -a", - "description": "Show frame buffer device settings", - "parser": parser, - } - - main["fbset_info"] = { - "cmd": "fbset -i", - "description": "Show frame buffer device information", - "parser": parserInfo, - } + main.register( + { + "name": "fbset", + "system": ["linux"], + "cmd": "fbset -a", + "description": "Show frame buffer device settings", + "parser": parser, + } + ) + + main.register( + { + "name": "fbset_info", + "system": ["linux"], + "cmd": "fbset -i", + "description": "Show frame buffer device information", + "parser": parserInfo, + } + ) diff --git a/src/sysinfo/modules/findmnt.py b/src/sysinfo/modules/findmnt.py index 5b9079f..66790ae 100644 --- a/src/sysinfo/modules/findmnt.py +++ b/src/sysinfo/modules/findmnt.py @@ -29,8 +29,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["findmnt"] = { - "cmd": "findmnt -Al | column -t", - "description": "List all mounted filesytems", - "parser": parser, - } + main.register( + { + "name": "findmnt", + "system": ["linux"], + "cmd": "findmnt -Al | column -t", + "description": "List all mounted filesytems", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/free.py b/src/sysinfo/modules/free.py index cb7dd42..684f284 100644 --- a/src/sysinfo/modules/free.py +++ b/src/sysinfo/modules/free.py @@ -32,8 +32,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["free"] = { - "cmd": "free -b -l -w", - "description": "Amount of free and used memory in the system", - "parser": parser, - } + main.register( + { + "name": "free", + "system": ["linux"], + "cmd": "free -b -l -w", + "description": "Amount of free and used memory in the system", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/getconf.py b/src/sysinfo/modules/getconf.py index ddd0904..2c2c00a 100644 --- a/src/sysinfo/modules/getconf.py +++ b/src/sysinfo/modules/getconf.py @@ -22,8 +22,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["getconf"] = { - "cmd": "getconf -a", - "description": "Configuration variables for the current system and their values", - "parser": parser, - } + main.register( + { + "name": "getconf", + "system": ["linux"], + "cmd": "getconf -a", + "description": "Configuration variables for the current system and their values", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/hostnamectl.py b/src/sysinfo/modules/hostnamectl.py index 88b8255..fb95070 100644 --- a/src/sysinfo/modules/hostnamectl.py +++ b/src/sysinfo/modules/hostnamectl.py @@ -22,8 +22,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["hostnamectl"] = { - "cmd": "hostnamectl status", - "description": "Current system hostname and related information", - "parser": parser, - } + main.register( + { + "name": "hostnamectl", + "system": ["linux"], + "cmd": "hostnamectl status", + "description": "Current system hostname and related information", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/ifconfig.py b/src/sysinfo/modules/ifconfig.py index b377c58..7f4d9ea 100644 --- a/src/sysinfo/modules/ifconfig.py +++ b/src/sysinfo/modules/ifconfig.py @@ -79,8 +79,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["ifconfig"] = { - "cmd": "ifconfig -a -v", - "description": "List all interfaces which are currently available, even if down", - "parser": parser, - } + main.register( + { + "name": "ifconfig", + "system": ["linux"], + "cmd": "ifconfig -a -v", + "description": "List all interfaces which are currently available, even if down", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/lsblk.py b/src/sysinfo/modules/lsblk.py index 1dd7f52..ab07659 100644 --- a/src/sysinfo/modules/lsblk.py +++ b/src/sysinfo/modules/lsblk.py @@ -31,8 +31,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["lsblk"] = { - "cmd": "lsblk -P -o NAME,KNAME,MAJ:MIN,FSTYPE,MOUNTPOINT,LABEL,UUID,PARTLABEL,PARTUUID,RA,RO,RM,MODEL,SERIAL,SIZE,STATE,OWNER,GROUP,MODE,ALIGNMENT,MIN-IO,OPT-IO,PHY-SEC,LOG-SEC,ROTA,SCHED,RQ-SIZE,TYPE,DISC-ALN,DISC-GRAN,DISC-MAX,DISC-ZERO,WSAME,WWN,RAND,PKNAME,HCTL,TRAN,REV,VENDOR", - "description": "Lists information about all block devices", - "parser": parser, - } + main.register( + { + "name": "lsblk", + "system": ["linux"], + "cmd": "lsblk -P -o NAME,KNAME,MAJ:MIN,FSTYPE,MOUNTPOINT,LABEL,UUID,PARTLABEL,PARTUUID,RA,RO,RM,MODEL,SERIAL,SIZE,STATE,OWNER,GROUP,MODE,ALIGNMENT,MIN-IO,OPT-IO,PHY-SEC,LOG-SEC,ROTA,SCHED,RQ-SIZE,TYPE,DISC-ALN,DISC-GRAN,DISC-MAX,DISC-ZERO,WSAME,WWN,RAND,PKNAME,HCTL,TRAN,REV,VENDOR", + "description": "Lists information about all block devices", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/lscpu.py b/src/sysinfo/modules/lscpu.py index 40399d6..a079b13 100644 --- a/src/sysinfo/modules/lscpu.py +++ b/src/sysinfo/modules/lscpu.py @@ -23,8 +23,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["lscpu"] = { - "cmd": "lscpu", - "description": "Information about the CPU architecture", - "parser": parser, - } + main.register( + { + "name": "lscpu", + "system": ["linux"], + "cmd": "lscpu", + "description": "Information about the CPU architecture", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/lsmod.py b/src/sysinfo/modules/lsmod.py index 31e9f2c..d86416e 100644 --- a/src/sysinfo/modules/lsmod.py +++ b/src/sysinfo/modules/lsmod.py @@ -31,8 +31,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["lsmod"] = { - "cmd": "lsmod", - "description": "Show the status of modules in the Linux Kernel", - "parser": parser, - } + main.register( + { + "name": "lsmod", + "system": ["linux"], + "cmd": "lsmod", + "description": "Show the status of modules in the Linux Kernel", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/lsns.py b/src/sysinfo/modules/lsns.py index ff0a4ee..55964cb 100644 --- a/src/sysinfo/modules/lsns.py +++ b/src/sysinfo/modules/lsns.py @@ -15,8 +15,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["lsns"] = { - "cmd": "lsns -o NS,TYPE,PATH,NPROCS,PID,PPID,UID,USER,COMMAND", - "description": "Block device ioctls", - "parser": parser, - } + main.register( + { + "name": "lsns", + "system": ["linux"], + "cmd": "lsns -o NS,TYPE,PATH,NPROCS,PID,PPID,UID,USER,COMMAND", + "description": "Block device ioctls", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/lsof.py b/src/sysinfo/modules/lsof.py index d5b9191..64e3f69 100644 --- a/src/sysinfo/modules/lsof.py +++ b/src/sysinfo/modules/lsof.py @@ -98,8 +98,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["lsof"] = { - "cmd": "lsof -F0", - "description": "Information about files opened by processes", - "parser": parser, - } + main.register( + { + "name": "lsof", + "system": ["linux"], + "cmd": "lsof -F0", + "description": "Information about files opened by processes", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/lspci.py b/src/sysinfo/modules/lspci.py index 83ee1b3..69292ef 100644 --- a/src/sysinfo/modules/lspci.py +++ b/src/sysinfo/modules/lspci.py @@ -32,8 +32,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["lspci"] = { - "cmd": "lspci -mm -vvv", - "description": "List all PCI devices", - "parser": parser, - } + main.register( + { + "name": "lspci", + "system": ["linux"], + "cmd": "lspci -mm -vvv", + "description": "List all PCI devices", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/lsusb.py b/src/sysinfo/modules/lsusb.py index 85578f3..611559e 100644 --- a/src/sysinfo/modules/lsusb.py +++ b/src/sysinfo/modules/lsusb.py @@ -129,8 +129,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["lsusb"] = { - "cmd": "lsusb -v", - "description": "List USB devices", - "parser": parser, - } + main.register( + { + "name": "lsusb", + "system": ["linux"], + "cmd": "lsusb -v", + "description": "List USB devices", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/modinfo.py b/src/sysinfo/modules/modinfo.py index 247c38e..02bdfa2 100644 --- a/src/sysinfo/modules/modinfo.py +++ b/src/sysinfo/modules/modinfo.py @@ -32,8 +32,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["modinfo"] = { - "cmd": """lsmod | grep -v "Module" | sed 's/ .*//g' | xargs -I {} -n 1 sh -c "echo '>>> moduleName: {}'; modinfo {}" """, - "description": "Information about a Linux Kernel modules", - "parser": parser, - } + main.register( + { + "name": "modinfo", + "system": ["linux"], + "cmd": """lsmod | grep -v "Module" | sed 's/ .*//g' | xargs -I {} -n 1 sh -c "echo '>>> moduleName: {}'; modinfo {}" """, + "description": "Information about a Linux Kernel modules", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/parted.py b/src/sysinfo/modules/parted.py index 8483f4b..8267ece 100644 --- a/src/sysinfo/modules/parted.py +++ b/src/sysinfo/modules/parted.py @@ -53,8 +53,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["parted"] = { - "cmd": "parted -m -l print", - "description": "Lists partition layout on all block devices", - "parser": parser, - } + main.register( + { + "name": "parted", + "system": ["linux"], + "cmd": "parted -m -l print", + "description": "Lists partition layout on all block devices", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/proc_buddyinfo.py b/src/sysinfo/modules/proc_buddyinfo.py index 500a296..13826f7 100644 --- a/src/sysinfo/modules/proc_buddyinfo.py +++ b/src/sysinfo/modules/proc_buddyinfo.py @@ -26,8 +26,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["proc_buddyinfo"] = { - "cmd": "cat /proc/buddyinfo", - "description": "Memory fragmentation", - "parser": parser, - } + main.register( + { + "name": "proc_buddyinfo", + "system": ["linux"], + "cmd": "cat /proc/buddyinfo", + "description": "Memory fragmentation", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/proc_bus_input.py b/src/sysinfo/modules/proc_bus_input.py index 9b4326d..1b77207 100644 --- a/src/sysinfo/modules/proc_bus_input.py +++ b/src/sysinfo/modules/proc_bus_input.py @@ -75,8 +75,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["proc_bus_input"] = { - "cmd": 'cat /proc/bus/input/devices; echo ">>> handlers"; cat /proc/bus/input/handlers;', - "description": "Input devices", - "parser": parser, - } + main.register( + { + "name": "proc_bus_input", + "system": ["linux"], + "cmd": 'cat /proc/bus/input/devices; echo ">>> handlers"; cat /proc/bus/input/handlers;', + "description": "Input devices", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/proc_cgroups.py b/src/sysinfo/modules/proc_cgroups.py index 757cb95..bd63d3d 100644 --- a/src/sysinfo/modules/proc_cgroups.py +++ b/src/sysinfo/modules/proc_cgroups.py @@ -17,8 +17,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["proc_cgroups"] = { - "cmd": "cat /proc/cgroups", - "description": "Control groups", - "parser": parser, - } + main.register( + { + "name": "proc_cgroups", + "system": ["linux"], + "cmd": "cat /proc/cgroups", + "description": "Control groups", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/proc_cmdline.py b/src/sysinfo/modules/proc_cmdline.py index 799c623..8331c4c 100644 --- a/src/sysinfo/modules/proc_cmdline.py +++ b/src/sysinfo/modules/proc_cmdline.py @@ -29,8 +29,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["proc_cmdline"] = { - "cmd": "cat /proc/cmdline", - "description": "Parameters passed to the kernel at the time it is started", - "parser": parser, - } + main.register( + { + "name": "proc_cmdline", + "system": ["linux"], + "cmd": "cat /proc/cmdline", + "description": "Parameters passed to the kernel at the time it is started", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/proc_consoles.py b/src/sysinfo/modules/proc_consoles.py index 998cf9f..5b0e4ad 100644 --- a/src/sysinfo/modules/proc_consoles.py +++ b/src/sysinfo/modules/proc_consoles.py @@ -51,8 +51,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["proc_consoles"] = { - "cmd": "cat /proc/consoles", - "description": "Information about current consoles including tty", - "parser": parser, - } + main.register( + { + "name": "proc_consoles", + "system": ["linux"], + "cmd": "cat /proc/consoles", + "description": "Information about current consoles including tty", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/proc_cpuinfo.py b/src/sysinfo/modules/proc_cpuinfo.py index ff3e449..b992895 100644 --- a/src/sysinfo/modules/proc_cpuinfo.py +++ b/src/sysinfo/modules/proc_cpuinfo.py @@ -33,8 +33,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["proc_cpuinfo"] = { - "cmd": "cat /proc/cpuinfo", - "description": "Type of processor used by your system", - "parser": parser, - } + main.register( + { + "name": "proc_cpuinfo", + "system": ["linux"], + "cmd": "cat /proc/cpuinfo", + "description": "Type of processor used by your system", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/proc_crypto.py b/src/sysinfo/modules/proc_crypto.py index c2c0a13..3734989 100644 --- a/src/sysinfo/modules/proc_crypto.py +++ b/src/sysinfo/modules/proc_crypto.py @@ -27,8 +27,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["proc_crypto"] = { - "cmd": "cat /proc/crypto", - "description": "Installed cryptographic ciphers used by the Linux kernel", - "parser": parser, - } + main.register( + { + "name": "proc_crypto", + "system": ["linux"], + "cmd": "cat /proc/crypto", + "description": "Installed cryptographic ciphers used by the Linux kernel", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/proc_devices.py b/src/sysinfo/modules/proc_devices.py index 5ade0d5..4c629e2 100644 --- a/src/sysinfo/modules/proc_devices.py +++ b/src/sysinfo/modules/proc_devices.py @@ -32,8 +32,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["proc_devices"] = { - "cmd": "cat /proc/devices", - "description": "Installed cryptographic ciphers used by the Linux kernel", - "parser": parser, - } + main.register( + { + "name": "proc_devices", + "system": ["linux"], + "cmd": "cat /proc/devices", + "description": "Installed cryptographic ciphers used by the Linux kernel", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/proc_diskstats.py b/src/sysinfo/modules/proc_diskstats.py index dd90720..1555471 100644 --- a/src/sysinfo/modules/proc_diskstats.py +++ b/src/sysinfo/modules/proc_diskstats.py @@ -40,8 +40,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["proc_diskstats"] = { - "cmd": "cat /proc/diskstats", - "description": "I/O statistics of block devices", - "parser": parser, - } + main.register( + { + "name": "proc_diskstats", + "system": ["linux"], + "cmd": "cat /proc/diskstats", + "description": "I/O statistics of block devices", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/proc_dma.py b/src/sysinfo/modules/proc_dma.py index 629a288..be7745a 100644 --- a/src/sysinfo/modules/proc_dma.py +++ b/src/sysinfo/modules/proc_dma.py @@ -21,8 +21,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["proc_dma"] = { - "cmd": "cat /proc/dma", - "description": "List of the registered ISA DMA channels in use", - "parser": parser, - } + main.register( + { + "name": "proc_dma", + "system": ["linux"], + "cmd": "cat /proc/dma", + "description": "List of the registered ISA DMA channels in use", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/proc_filesystems.py b/src/sysinfo/modules/proc_filesystems.py index c192a48..b72bfd9 100644 --- a/src/sysinfo/modules/proc_filesystems.py +++ b/src/sysinfo/modules/proc_filesystems.py @@ -26,8 +26,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["proc_filesystems"] = { - "cmd": "cat /proc/filesystems", - "description": "List of the file system types currently supported by the kernel", - "parser": parser, - } + main.register( + { + "name": "proc_filesystems", + "system": ["linux"], + "cmd": "cat /proc/filesystems", + "description": "List of the file system types currently supported by the kernel", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/proc_fs.py b/src/sysinfo/modules/proc_fs.py index 6be60fd..a53e5c1 100644 --- a/src/sysinfo/modules/proc_fs.py +++ b/src/sysinfo/modules/proc_fs.py @@ -39,7 +39,7 @@ def parser(stdout, stderr, to_camelcase): # setPathValue(output, path, value) # continue - + # else: # print(line) @@ -49,8 +49,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["proc_fs"] = { - "cmd": """find /proc/fs -type f -follow -print | xargs grep "" """, - "description": "File system parameters", - "parser": parser, - } + main.register( + { + "name": "proc_fs", + "system": ["linux"], + "cmd": """find /proc/fs -type f -follow -print | xargs grep "" """, + "description": "File system parameters", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/proc_iomem.py b/src/sysinfo/modules/proc_iomem.py index 27baba3..e98c4b6 100644 --- a/src/sysinfo/modules/proc_iomem.py +++ b/src/sysinfo/modules/proc_iomem.py @@ -24,8 +24,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["proc_iomem"] = { - "cmd": "cat /proc/iomem", - "description": """Map of the system's memory for each physical device""", - "parser": parser, - } + main.register( + { + "name": "proc_iomem", + "system": ["linux"], + "cmd": "cat /proc/iomem", + "description": """Map of the system's memory for each physical device""", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/proc_ioports.py b/src/sysinfo/modules/proc_ioports.py index bdc145e..5ec0abd 100644 --- a/src/sysinfo/modules/proc_ioports.py +++ b/src/sysinfo/modules/proc_ioports.py @@ -26,8 +26,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["proc_ioports"] = { - "cmd": "cat /proc/ioports", - "description": "List of currently registered port regions used for input or output communication with a device", - "parser": parser, - } + main.register( + { + "name": "proc_ioports", + "system": ["linux"], + "cmd": "cat /proc/ioports", + "description": "List of currently registered port regions used for input or output communication with a device", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/proc_loadavg.py b/src/sysinfo/modules/proc_loadavg.py index 9b467ee..67afe9e 100644 --- a/src/sysinfo/modules/proc_loadavg.py +++ b/src/sysinfo/modules/proc_loadavg.py @@ -23,8 +23,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["proc_loadavg"] = { - "cmd": "cat /proc/loadavg", - "description": "Load average in regard to both the CPU and IO over time", - "parser": parser, - } + main.register( + { + "name": "proc_loadavg", + "system": ["linux"], + "cmd": "cat /proc/loadavg", + "description": "Load average in regard to both the CPU and IO over time", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/proc_locks.py b/src/sysinfo/modules/proc_locks.py index 5127c57..46483d9 100644 --- a/src/sysinfo/modules/proc_locks.py +++ b/src/sysinfo/modules/proc_locks.py @@ -26,8 +26,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["proc_locks"] = { - "cmd": "cat /proc/locks", - "description": "Files currently locked by the kernel", - "parser": parser, - } + main.register( + { + "name": "proc_locks", + "system": ["linux"], + "cmd": "cat /proc/locks", + "description": "Files currently locked by the kernel", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/proc_meminfo.py b/src/sysinfo/modules/proc_meminfo.py index f6a2183..f0ece86 100644 --- a/src/sysinfo/modules/proc_meminfo.py +++ b/src/sysinfo/modules/proc_meminfo.py @@ -30,8 +30,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["proc_meminfo"] = { - "cmd": "cat /proc/meminfo", - "description": "Reports a large amount of valuable information about the systems RAM usage", - "parser": parser, - } + main.register( + { + "name": "proc_meminfo", + "system": ["linux"], + "cmd": "cat /proc/meminfo", + "description": "Reports a large amount of valuable information about the systems RAM usage", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/proc_modules.py b/src/sysinfo/modules/proc_modules.py index 6d7110d..8ea2431 100644 --- a/src/sysinfo/modules/proc_modules.py +++ b/src/sysinfo/modules/proc_modules.py @@ -25,8 +25,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["proc_modules"] = { - "cmd": "cat /proc/modules", - "description": "List of all modules loaded into the kernel", - "parser": parser, - } + main.register( + { + "name": "proc_modules", + "system": ["linux"], + "cmd": "cat /proc/modules", + "description": "List of all modules loaded into the kernel", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/proc_mounts.py b/src/sysinfo/modules/proc_mounts.py index 71b90e5..5835a84 100644 --- a/src/sysinfo/modules/proc_mounts.py +++ b/src/sysinfo/modules/proc_mounts.py @@ -28,8 +28,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["proc_mounts"] = { - "cmd": "cat /proc/mounts", - "description": "List mounted filesystems (info provides from kernel)", - "parser": parser, - } + main.register( + { + "name": "proc_mounts", + "system": ["linux"], + "cmd": "cat /proc/mounts", + "description": "List mounted filesystems (info provides from kernel)", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/proc_net.py b/src/sysinfo/modules/proc_net.py index 339aa89..759e658 100644 --- a/src/sysinfo/modules/proc_net.py +++ b/src/sysinfo/modules/proc_net.py @@ -97,50 +97,82 @@ def parser_arp(stdout, stderr, to_camelcase): def register(main): - main["proc_net_route"] = { - "cmd": "cat /proc/net/route", - "description": "IP routing information", - "parser": parser_route, - } - - main["proc_net_ax25_route"] = { - "cmd": "cat /proc/net/ax25_route", - "description": "AX25 routing information", - "parser": parser_route, - } - - main["proc_net_ipx_route"] = { - "cmd": "cat /proc/net/ipx_route", - "description": "IPX routing information", - "parser": parser_route, - } - - main["proc_net_tcp"] = { - "cmd": "cat /proc/net/tcp", - "description": "TCP socket table", - "parser": parser_tcp_udp, - } - - main["proc_net_udp"] = { - "cmd": "cat /proc/net/udp", - "description": "UDP socket table", - "parser": parser_tcp_udp, - } - - main["proc_net_tcp6"] = { - "cmd": "cat /proc/net/tcp6", - "description": "TCP6 socket table", - "parser": parser_tcp_udp_6, - } - - main["proc_net_udp6"] = { - "cmd": "cat /proc/net/udp6", - "description": "UDP6 socket table", - "parser": parser_tcp_udp_6, - } - - main["proc_net_arp"] = { - "cmd": "cat /proc/net/arp", - "description": "ARP ", - "parser": parser_arp, - } + main.register( + { + "name": "proc_net_route", + "system": ["linux"], + "cmd": "cat /proc/net/route", + "description": "IP routing information", + "parser": parser_route, + } + ) + + main.register( + { + "name": "proc_net_ax25_route", + "system": ["linux"], + "cmd": "cat /proc/net/ax25_route", + "description": "AX25 routing information", + "parser": parser_route, + } + ) + + main.register( + { + "name": "proc_net_ipx_route", + "system": ["linux"], + "cmd": "cat /proc/net/ipx_route", + "description": "IPX routing information", + "parser": parser_route, + } + ) + + main.register( + { + "name": "proc_net_tcp", + "system": ["linux"], + "cmd": "cat /proc/net/tcp", + "description": "TCP socket table", + "parser": parser_tcp_udp, + } + ) + + main.register( + { + "name": "proc_net_udp", + "system": ["linux"], + "cmd": "cat /proc/net/udp", + "description": "UDP socket table", + "parser": parser_tcp_udp, + } + ) + + main.register( + { + "name": "proc_net_tcp6", + "system": ["linux"], + "cmd": "cat /proc/net/tcp6", + "description": "TCP6 socket table", + "parser": parser_tcp_udp_6, + } + ) + + main.register( + { + "name": "proc_net_udp6", + "system": ["linux"], + "cmd": "cat /proc/net/udp6", + "description": "UDP6 socket table", + "parser": parser_tcp_udp_6, + } + ) + + main.register( + { + "name": "proc_net_arp", + "system": ["linux"], + "cmd": "cat /proc/net/arp", + "description": "ARP ", + "parser": parser_arp, + } + ) diff --git a/src/sysinfo/modules/proc_partitions.py b/src/sysinfo/modules/proc_partitions.py index 3e674a2..ef93029 100644 --- a/src/sysinfo/modules/proc_partitions.py +++ b/src/sysinfo/modules/proc_partitions.py @@ -12,8 +12,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["proc_partitions"] = { - "cmd": "cat /proc/partitions", - "description": "Partition block allocation information", - "parser": parser, - } + main.register( + { + "name": "proc_partitions", + "system": ["linux"], + "cmd": "cat /proc/partitions", + "description": "Partition block allocation information", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/proc_scsi.py b/src/sysinfo/modules/proc_scsi.py index 4d75637..a69b8e1 100644 --- a/src/sysinfo/modules/proc_scsi.py +++ b/src/sysinfo/modules/proc_scsi.py @@ -53,8 +53,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["proc_scsi"] = { - "cmd": "cat /proc/scsi/scsi", - "description": "List of every recognized SCSI device", - "parser": parser, - } + main.register( + { + "name": "proc_scsi", + "system": ["linux"], + "cmd": "cat /proc/scsi/scsi", + "description": "List of every recognized SCSI device", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/proc_slabinfo.py b/src/sysinfo/modules/proc_slabinfo.py index 9ebb01a..9558a37 100644 --- a/src/sysinfo/modules/proc_slabinfo.py +++ b/src/sysinfo/modules/proc_slabinfo.py @@ -64,8 +64,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["proc_slabinfo"] = { - "cmd": "cat /proc/slabinfo", - "description": "Kernel caches informations", - "parser": parser, - } + main.register( + { + "name": "proc_slabinfo", + "system": ["linux"], + "cmd": "cat /proc/slabinfo", + "description": "Kernel caches informations", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/proc_stat.py b/src/sysinfo/modules/proc_stat.py index 50ba415..705f418 100644 --- a/src/sysinfo/modules/proc_stat.py +++ b/src/sysinfo/modules/proc_stat.py @@ -31,8 +31,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["proc_stat"] = { - "cmd": "cat /proc/stat", - "description": "Kernel/system statistics", - "parser": parser, - } + main.register( + { + "name": "proc_stat", + "system": ["linux"], + "cmd": "cat /proc/stat", + "description": "Kernel/system statistics", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/proc_swaps.py b/src/sysinfo/modules/proc_swaps.py index 075eeb7..032bd7b 100644 --- a/src/sysinfo/modules/proc_swaps.py +++ b/src/sysinfo/modules/proc_swaps.py @@ -11,8 +11,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["proc_swaps"] = { - "cmd": "cat /proc/swaps", - "description": "Measures swap space and its utilization", - "parser": parser, - } + main.register( + { + "name": "proc_swaps", + "system": ["linux"], + "cmd": "cat /proc/swaps", + "description": "Measures swap space and its utilization", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/proc_sys.py b/src/sysinfo/modules/proc_sys.py index 004fcd4..8619a23 100644 --- a/src/sysinfo/modules/proc_sys.py +++ b/src/sysinfo/modules/proc_sys.py @@ -41,8 +41,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["proc_sys"] = { - "cmd": """find /proc/sys -type f -follow -print 2>/dev/null | xargs -n 1 -I {} sh -c 'VAL=$(cat {} 2>/dev/null); echo {}:$VAL;'""", - "description": "Information about the system and kernel features", - "parser": parser, - } + main.register( + { + "name": "proc_sys", + "system": ["linux"], + "cmd": """find /proc/sys -type f -follow -print 2>/dev/null | xargs -n 1 -I {} sh -c 'VAL=$(cat {} 2>/dev/null); echo {}:$VAL;'""", + "description": "Information about the system and kernel features", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/proc_uptime.py b/src/sysinfo/modules/proc_uptime.py index 86ff841..f05445c 100644 --- a/src/sysinfo/modules/proc_uptime.py +++ b/src/sysinfo/modules/proc_uptime.py @@ -16,8 +16,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["proc_uptime"] = { - "cmd": "cat /proc/uptime", - "description": "Information detailing how long the system has been on since its last restart", - "parser": parser, - } + main.register( + { + "name": "proc_uptime", + "system": ["linux"], + "cmd": "cat /proc/uptime", + "description": "Information detailing how long the system has been on since its last restart", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/proc_version.py b/src/sysinfo/modules/proc_version.py index dfcd145..c068d69 100644 --- a/src/sysinfo/modules/proc_version.py +++ b/src/sysinfo/modules/proc_version.py @@ -8,8 +8,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["proc_version"] = { - "cmd": "cat /proc/version", - "description": "Version of the Linux kernel, the version of gcc used to compile the kernel, and the time of kernel compilation", - "parser": parser, - } + main.register( + { + "name": "proc_version", + "system": ["linux"], + "cmd": "cat /proc/version", + "description": "Version of the Linux kernel, the version of gcc used to compile the kernel, and the time of kernel compilation", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/proc_version_signature.py b/src/sysinfo/modules/proc_version_signature.py index dfa042a..382fccd 100644 --- a/src/sysinfo/modules/proc_version_signature.py +++ b/src/sysinfo/modules/proc_version_signature.py @@ -12,8 +12,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["proc_version_signature"] = { - "cmd": "cat /proc/version_signature", - "description": "OS version signature", - "parser": parser, - } + main.register( + { + "name": "proc_version_signature", + "system": ["linux"], + "cmd": "cat /proc/version_signature", + "description": "OS version signature", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/proc_vmstat.py b/src/sysinfo/modules/proc_vmstat.py index cc5adcc..cba3d2d 100644 --- a/src/sysinfo/modules/proc_vmstat.py +++ b/src/sysinfo/modules/proc_vmstat.py @@ -22,8 +22,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["proc_vmstat"] = { - "cmd": "cat /proc/vmstat", - "description": "Detailed virtual memory statistics from the kernel", - "parser": parser, - } + main.register( + { + "name": "proc_vmstat", + "system": ["linux"], + "cmd": "cat /proc/vmstat", + "description": "Detailed virtual memory statistics from the kernel", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/prtstat.py b/src/sysinfo/modules/prtstat.py index 4752104..fc96362 100644 --- a/src/sysinfo/modules/prtstat.py +++ b/src/sysinfo/modules/prtstat.py @@ -30,8 +30,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["prtstat"] = { - "cmd": "ps -eo pid | xargs -I {} prtstat -r {}", - "description": "Print statistics of a processes", - "parser": parser, - } + main.register( + { + "name": "prtstat", + "system": ["linux"], + "cmd": "ps -eo pid | xargs -I {} prtstat -r {}", + "description": "Print statistics of a processes", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/ps.py b/src/sysinfo/modules/ps.py index 34f0653..76d830d 100644 --- a/src/sysinfo/modules/ps.py +++ b/src/sysinfo/modules/ps.py @@ -51,8 +51,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["ps"] = { - "cmd": "ps --cols 12288 -eo user:256,ruser:256,group:256,rgroup:256,pid,ppid,pgid,pcpu,vsz,nice,etime,time,stime,tty,args 2>/dev/null", - "description": "Report a snapshot of the current processes", - "parser": parser, - } + main.register( + { + "name": "ps", + "system": ["linux"], + "cmd": "ps --cols 12288 -eo user:256,ruser:256,group:256,rgroup:256,pid,ppid,pgid,pcpu,vsz,nice,etime,time,stime,tty,args 2>/dev/null", + "description": "Report a snapshot of the current processes", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/python.py b/src/sysinfo/modules/python.py index d729166..feeca6a 100644 --- a/src/sysinfo/modules/python.py +++ b/src/sysinfo/modules/python.py @@ -67,12 +67,20 @@ def python_platform(to_camelcase): def register(main): if loaded_pkg_resources: - main["python_pip_packages"] = { - "function": python_pip_packages, - "description": "List available python modules", - } + main.register( + { + "name": "python_pip_packages", + "system": ["linux"], + "function": python_pip_packages, + "description": "List available python modules", + } + ) - main["python_platform"] = { - "function": python_platform, - "description": "Probe the underlying platform's hardware, operating system, and Python interpreter version information", - } + main.register( + { + "name": "python_platform", + "system": ["linux"], + "function": python_platform, + "description": "Probe the underlying platform's hardware, operating system, and Python interpreter version information", + } + ) diff --git a/src/sysinfo/modules/route.py b/src/sysinfo/modules/route.py index aee5cd9..ba9fe07 100644 --- a/src/sysinfo/modules/route.py +++ b/src/sysinfo/modules/route.py @@ -15,8 +15,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["route"] = { - "cmd": "route -ee", - "description": "IP routing table", - "parser": parser, - } + main.register( + { + "name": "route", + "system": ["linux"], + "cmd": "route -ee", + "description": "IP routing table", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/rpm.py b/src/sysinfo/modules/rpm.py index 3429168..dc968d0 100644 --- a/src/sysinfo/modules/rpm.py +++ b/src/sysinfo/modules/rpm.py @@ -24,8 +24,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["rpm"] = { - "cmd": 'rpm -q -a --queryformat "%{INSTALLTIME}|%{BUILDTIME}|%{NAME}|%{VERSION}|%{RELEASE}|%{arch}|%{VENDOR}|%{PACKAGER}|%{DISTRIBUTION}|%{DISTTAG}\n"', - "description": "Querying all RPM packages", - "parser": parser, - } + main.register( + { + "name": "rpm", + "system": ["linux"], + "cmd": 'rpm -q -a --queryformat "%{INSTALLTIME}|%{BUILDTIME}|%{NAME}|%{VERSION}|%{RELEASE}|%{arch}|%{VENDOR}|%{PACKAGER}|%{DISTRIBUTION}|%{DISTTAG}\n"', + "description": "Querying all RPM packages", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/services_status.py b/src/sysinfo/modules/services_status.py index 2114de6..d0bc2ab 100644 --- a/src/sysinfo/modules/services_status.py +++ b/src/sysinfo/modules/services_status.py @@ -37,14 +37,22 @@ def parser_services_params(stdout, stderr, to_camelcase): def register(main): - main["services_list"] = { - "cmd": """systemctl -l --type service --all --plain | grep -i -e ".service\|description" | sed 's/^\s*//g' """, - "description": "Displays services with status", - "parser": parser_services, - } - - main["services_params"] = { - "cmd": """systemctl -l --type service --all --plain | sed -E 's/^\s*(\\S+.service).*$/\\1/g' | grep -i -e ".service" | xargs -I '{}' sh -c "echo '>>> Service: {}'; systemctl show {} --no-page" """, - "description": "Displays services with params", - "parser": parser_services_params, - } + main.register( + { + "name": "services_list", + "system": ["linux"], + "cmd": """systemctl -l --type service --all --plain | grep -i -e ".service\|description" | sed 's/^\s*//g' """, + "description": "Displays services with status", + "parser": parser_services, + } + ) + + main.register( + { + "name": "services_params", + "system": ["linux"], + "cmd": """systemctl -l --type service --all --plain | sed -E 's/^\s*(\\S+.service).*$/\\1/g' | grep -i -e ".service" | xargs -I '{}' sh -c "echo '>>> Service: {}'; systemctl show {} --no-page" """, + "description": "Displays services with params", + "parser": parser_services_params, + } + ) diff --git a/src/sysinfo/modules/sysctl.py b/src/sysinfo/modules/sysctl.py index 8a7c5ed..0d482e6 100644 --- a/src/sysinfo/modules/sysctl.py +++ b/src/sysinfo/modules/sysctl.py @@ -38,14 +38,22 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["sysctl"] = { - "cmd": "sysctl -a -e", - "description": "Runtime kernel parameters", - "parser": parser, - } - - main["sysctl_system"] = { - "cmd": "sysctl -a -e --system", - "description": "Runtime kernel parameters from all system configuration files", - "parser": parser, - } + main.register( + { + "name": "sysctl", + "system": ["linux"], + "cmd": "sysctl -a -e", + "description": "Runtime kernel parameters", + "parser": parser, + } + ) + + main.register( + { + "name": "sysctl_system", + "system": ["linux"], + "cmd": "sysctl -a -e --system", + "description": "Runtime kernel parameters from all system configuration files", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/timedatectl.py b/src/sysinfo/modules/timedatectl.py index dad6dec..7e3f338 100644 --- a/src/sysinfo/modules/timedatectl.py +++ b/src/sysinfo/modules/timedatectl.py @@ -22,14 +22,22 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["timedatectl"] = { - "cmd": "timedatectl status", - "description": "System time and date", - "parser": parser, - } - - main["timedatectl_timesync"] = { - "cmd": "timedatectl timesync-status", - "description": "Status of systemd-timesyncd.service", - "parser": parser, - } + main.register( + { + "name": "timedatectl", + "system": ["linux"], + "cmd": "timedatectl status", + "description": "System time and date", + "parser": parser, + } + ) + + main.register( + { + "name": "timedatectl_timesync", + "system": ["linux"], + "cmd": "timedatectl timesync-status", + "description": "Status of systemd-timesyncd.service", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/udevadm.py b/src/sysinfo/modules/udevadm.py index 57deb11..a9e24bf 100644 --- a/src/sysinfo/modules/udevadm.py +++ b/src/sysinfo/modules/udevadm.py @@ -128,14 +128,22 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["udevadm"] = { - "cmd": """udevadm info --export-db | grep "DEVNAME" | cut -d "=" -f2 | xargs -n 1 -I {} sh -c "echo '>>> Device: {}'; udevadm info --query=all --name={}; udevadm info --attribute-walk --name={}" """, - "description": "Queries the udev database for device information stored in the udev database", - "parser": parser, - } - - main["udevadm_block_devices"] = { - "cmd": """find /dev/ -type b | xargs -n 1 -I {} sh -c "echo '>>> Device: {}'; udevadm info --query=all --name={}; udevadm info --attribute-walk --name={}" """, - "description": "Queries the udev database for block device information stored in the udev database", - "parser": parser, - } + main.register( + { + "name": "udevadm", + "system": ["linux"], + "cmd": """udevadm info --export-db | grep "DEVNAME" | cut -d "=" -f2 | xargs -n 1 -I {} sh -c "echo '>>> Device: {}'; udevadm info --query=all --name={}; udevadm info --attribute-walk --name={}" """, + "description": "Queries the udev database for device information stored in the udev database", + "parser": parser, + } + ) + + main.register( + { + "name": "udevadm_block_devices", + "system": ["linux"], + "cmd": """find /dev/ -type b | xargs -n 1 -I {} sh -c "echo '>>> Device: {}'; udevadm info --query=all --name={}; udevadm info --attribute-walk --name={}" """, + "description": "Queries the udev database for block device information stored in the udev database", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/uname.py b/src/sysinfo/modules/uname.py index 624e08c..c58e4d9 100644 --- a/src/sysinfo/modules/uname.py +++ b/src/sysinfo/modules/uname.py @@ -12,50 +12,82 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["kernel_name"] = { - "cmd": "uname -s", - "description": "Kernel name (uname)", - "parser": parser, - } - - main["kernel_release"] = { - "cmd": "uname -r", - "description": "Kernel release (uname)", - "parser": parser, - } - - main["kernel_version"] = { - "cmd": "uname -v", - "description": "Kernel version (uname)", - "parser": parser, - } - - main["nodename"] = { - "cmd": "uname -n", - "description": "Network node hostname (uname)", - "parser": parser, - } - - main["machine"] = { - "cmd": "uname -m", - "description": "Machine hardware name (uname)", - "parser": parser, - } - - main["processor"] = { - "cmd": "uname -p", - "description": "Processor type (uname)", - "parser": parser, - } - - main["hardware_platform"] = { - "cmd": "uname -i", - "description": "Hardware platform (uname)", - "parser": parser, - } - - main["operating_system"] = { - "cmd": "uname -o", - "description": "Operating system (uname)", - "parser": parser, - } + main.register( + { + "name": "kernel_name", + "system": ["linux"], + "cmd": "uname -s", + "description": "Kernel name (uname)", + "parser": parser, + } + ) + + main.register( + { + "name": "kernel_release", + "system": ["linux"], + "cmd": "uname -r", + "description": "Kernel release (uname)", + "parser": parser, + } + ) + + main.register( + { + "name": "kernel_version", + "system": ["linux"], + "cmd": "uname -v", + "description": "Kernel version (uname)", + "parser": parser, + } + ) + + main.register( + { + "name": "nodename", + "system": ["linux"], + "cmd": "uname -n", + "description": "Network node hostname (uname)", + "parser": parser, + } + ) + + main.register( + { + "name": "machine", + "system": ["linux"], + "cmd": "uname -m", + "description": "Machine hardware name (uname)", + "parser": parser, + } + ) + + main.register( + { + "name": "processor", + "system": ["linux"], + "cmd": "uname -p", + "description": "Processor type (uname)", + "parser": parser, + } + ) + + main.register( + { + "name": "hardware_platform", + "system": ["linux"], + "cmd": "uname -i", + "description": "Hardware platform (uname)", + "parser": parser, + } + ) + + main.register( + { + "name": "operating_system", + "system": ["linux"], + "cmd": "uname -o", + "description": "Operating system (uname)", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/update_alternatives.py b/src/sysinfo/modules/update_alternatives.py index 736a467..60d8dc0 100644 --- a/src/sysinfo/modules/update_alternatives.py +++ b/src/sysinfo/modules/update_alternatives.py @@ -24,8 +24,12 @@ def parser(stdout, stderr, to_camelcase): def register(main): - main["update_alternatives"] = { - "cmd": "update-alternatives --get-selections", - "description": "Symbolic links determining default commands", - "parser": parser, - } + main.register( + { + "name": "update_alternatives", + "system": ["linux"], + "cmd": "update-alternatives --get-selections", + "description": "Symbolic links determining default commands", + "parser": parser, + } + ) diff --git a/src/sysinfo/modules/vmstat.py b/src/sysinfo/modules/vmstat.py index f987295..c556f89 100644 --- a/src/sysinfo/modules/vmstat.py +++ b/src/sysinfo/modules/vmstat.py @@ -119,26 +119,42 @@ def parser_forks(stdout, stderr, to_camelcase): def register(main): - main["vmstat_stats"] = { - "cmd": "vmstat -s", - "description": "Displays a table of various event counters and memory statistics", - "parser": parser_stats, - } - - main["vmstat_disk"] = { - "cmd": "vmstat -dwn", - "description": "Report disk statistics", - "parser": parser_disk, - } - - main["vmstat_disk_sum"] = { - "cmd": "vmstat -D", - "description": "Report some summary statistics about disk activity", - "parser": parser_disk_sum, - } - - main["vmstat_forks"] = { - "cmd": "vmstat -f", - "description": "Displays the number of forks since boot", - "parser": parser_forks, - } + main.register( + { + "name": "vmstat_stats", + "system": ["linux"], + "cmd": "vmstat -s", + "description": "Displays a table of various event counters and memory statistics", + "parser": parser_stats, + } + ) + + main.register( + { + "name": "vmstat_disk", + "system": ["linux"], + "cmd": "vmstat -dwn", + "description": "Report disk statistics", + "parser": parser_disk, + } + ) + + main.register( + { + "name": "vmstat_disk_sum", + "system": ["linux"], + "cmd": "vmstat -D", + "description": "Report some summary statistics about disk activity", + "parser": parser_disk_sum, + } + ) + + main.register( + { + "name": "vmstat_forks", + "system": ["linux"], + "cmd": "vmstat -f", + "description": "Displays the number of forks since boot", + "parser": parser_forks, + } + ) diff --git a/src/sysinfo/modules/yum.py b/src/sysinfo/modules/yum.py index 1d73f7a..03c62b1 100644 --- a/src/sysinfo/modules/yum.py +++ b/src/sysinfo/modules/yum.py @@ -69,14 +69,22 @@ def parser_installed(stdout, stderr, to_camelcase): def register(main): - main["yum_repolist"] = { - "cmd": "yum repolist all", - "description": "YUM - defined repositories", - "parser": parser_repolist, - } + main.register( + { + "name": "yum_repolist", + "system": ["linux"], + "cmd": "yum repolist all", + "description": "YUM - defined repositories", + "parser": parser_repolist, + } + ) - main["yum_installed"] = { - "cmd": "yum list installed", - "description": "YUM - list installed packages", - "parser": parser_installed, - } + main.register( + { + "name": "yum_installed", + "system": ["linux"], + "cmd": "yum list installed", + "description": "YUM - list installed packages", + "parser": parser_installed, + } + ) diff --git a/src/sysinfo/sysinfo.py b/src/sysinfo/sysinfo.py index 9346e5e..b1e7eb9 100644 --- a/src/sysinfo/sysinfo.py +++ b/src/sysinfo/sysinfo.py @@ -20,19 +20,41 @@ * """ -import argparse +import os +import sys import glob import json -import os +import argparse +import platform import subprocess -import sys -from multiprocessing import Pool -from os.path import basename, dirname, isfile, join from threading import Timer +from multiprocessing import Pool +from os.path import dirname, basename, isfile, join sys.path.append(join(dirname(__file__), "modules")) -siModules = {} + +class systemInfoModules: + modules = {} + + def __init__(self, system): + self.system = system + + def register(self, definition): + if "system" in definition: + if not self.system in definition["system"]: + return + + if not "name" in definition: + return + + self.modules[definition["name"]] = definition + + def items(self): + return self.modules.items() + + +siModules = None PY2 = sys.version_info[0] == 2 PY3 = sys.version_info[0] == 3 @@ -51,7 +73,7 @@ def loadModules(): if hasattr(lib, "register"): lib.register(siModules) else: - pass + from importlib import import_module lib = __import__(basename(f)[:-3]) if hasattr(lib, "register"): @@ -102,6 +124,10 @@ def kill(process): def executeCmd(cmd): + proc = None + outs = None + errs = None + try: command = cmd.get("cmd", None) if not command: @@ -111,7 +137,7 @@ def executeCmd(cmd): proc = subprocess.Popen( command, shell=True, - executable="/usr/bin/bash", + # executable="/usr/bin/bash", stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) @@ -122,17 +148,15 @@ def executeCmd(cmd): outs, errs = proc.communicate() except Exception as err: - print(err) proc.kill() outs, errs = proc.communicate() - cmd["error"] = err + cmd["error"] = str(err) finally: cmdTimer.cancel() except Exception as err: - print(err) - cmd["error"] = err + cmd["error"] = str(err) if proc: procPoll = proc.poll() @@ -145,8 +169,8 @@ def executeCmd(cmd): cmd["stdout"] = outs cmd["stderr"] = errs else: - cmd["stdout"] = str(outs, "utf-8") - cmd["stderr"] = str(errs, "utf-8") + cmd["stdout"] = str(outs, "utf-8") if outs else None + cmd["stderr"] = str(errs, "utf-8") if errs else None def execute(cmd): @@ -292,6 +316,7 @@ def argsError(error): def main(argv): + global siModules parser = argparse.ArgumentParser() parser.error = argsError @@ -353,6 +378,13 @@ def main(argv): help="Pool size for parallel execution of commands. (default value is 5)", ) + parser.add_argument( + "--system", + "-s", + default=platform.system().lower(), + help="Execute or parse commands for selected system [linux, darwin, java, windows].", + ) + parser.add_argument( "--verbose", "-v", @@ -362,9 +394,9 @@ def main(argv): ) parser.add_argument("commands", nargs="*", help="Commands") - args = parser.parse_args() pathCheck(args) + siModules = systemInfoModules(args.system) run(args) From 033d57653b019d431c4f7a6aed86d08e01243681 Mon Sep 17 00:00:00 2001 From: Petr Vavrin Date: Sat, 6 Aug 2022 10:46:19 +0200 Subject: [PATCH 7/9] added change of codepage for windows commands, added command arp for windows --- src/sysinfo/modules/arp.py | 46 ++++++++++++++++++++++++++++++++++++++ src/sysinfo/sysinfo.py | 22 +++++++++++++++--- 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/src/sysinfo/modules/arp.py b/src/sysinfo/modules/arp.py index ad06a82..4463ec9 100644 --- a/src/sysinfo/modules/arp.py +++ b/src/sysinfo/modules/arp.py @@ -12,6 +12,42 @@ def parser(stdout, stderr, to_camelcase): return {"output": output, "unprocessed": []} +def parser_win(stdout, stderr, to_camelcase): + output = [] + unprocessed = [] + interface = None + + if stdout: + for line in stdout.splitlines(): + interface_match = re.search(r"^Interface:\s*(\S+)\s*---\s*(\S+)$", line) + if interface_match: + interface = { + "ip": interface_match.group(1).strip(), + "id": interface_match.group(2).strip(), + "entries": [], + } + output.append(interface) + continue + + if re.match(r"^.*Physical\s*Address", line, re.IGNORECASE): + continue + + entry_match = re.search(r"^\s+(\S+)\s+(\S+)\s+(\S+)", line) + if entry_match and interface: + interface["entries"].append( + { + "intenetAddress": entry_match.group(1).strip(), + "physicalAddress": entry_match.group(2).strip(), + "type": entry_match.group(3).strip(), + } + ) + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + def register(main): main.register( { @@ -22,3 +58,13 @@ def register(main): "parser": parser, } ) + + main.register( + { + "name": "arp", + "system": ["windows"], + "cmd": "%SystemRoot%\\system32\\arp -a", + "description": "System ARP cache", + "parser": parser_win, + } + ) diff --git a/src/sysinfo/sysinfo.py b/src/sysinfo/sysinfo.py index b1e7eb9..07933f6 100644 --- a/src/sysinfo/sysinfo.py +++ b/src/sysinfo/sysinfo.py @@ -24,6 +24,7 @@ import sys import glob import json +import locale import argparse import platform import subprocess @@ -134,6 +135,16 @@ def executeCmd(cmd): cmd["error"] = "Empty command" return + system = cmd.get("system", None) + if system: + if system == "windows": + subprocess.call( + ["chcp", "65001"], + shell=True, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + proc = subprocess.Popen( command, shell=True, @@ -169,8 +180,11 @@ def executeCmd(cmd): cmd["stdout"] = outs cmd["stderr"] = errs else: - cmd["stdout"] = str(outs, "utf-8") if outs else None - cmd["stderr"] = str(errs, "utf-8") if errs else None + try: + cmd["stdout"] = str(outs, "utf-8") if outs else None + cmd["stderr"] = str(errs, "utf-8") if errs else None + except Exception as e: + cmd["error"] = str(e) def execute(cmd): @@ -239,7 +253,8 @@ def run(args): if args.import_dir: settings["import_dir"] = args.import_dir - settings["to_camelcase"] = args.camel_case + settings["to_camelcase"] = to_camelcase + settings["system"] = args.system selectedModules.append(settings) executeModules = True @@ -297,6 +312,7 @@ def run(args): result.pop("name", None) result.pop("unprocessed", None) result.pop("import_dir", None) + result.pop("system", None) results[name] = result From f1f2c49c1bfb723cb72b38c6b81a09631ce4aaf6 Mon Sep 17 00:00:00 2001 From: Petr Vavrin Date: Sun, 7 Aug 2022 14:19:52 +0200 Subject: [PATCH 8/9] added function fixMultilineAndSplit, added windows commands - tasklist, tasklist_services, tasklist_apps, tasklist_modules --- src/sysinfo/modules/sysinfo_lib.py | 28 ++++++++++ src/sysinfo/modules/tasklist.py | 82 ++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 src/sysinfo/modules/tasklist.py diff --git a/src/sysinfo/modules/sysinfo_lib.py b/src/sysinfo/modules/sysinfo_lib.py index 437eb83..ace01be 100644 --- a/src/sysinfo/modules/sysinfo_lib.py +++ b/src/sysinfo/modules/sysinfo_lib.py @@ -11,9 +11,11 @@ def sortedList(st): values.sort() return values + def camelCase_cb(matchobj): return " ".join([matchobj.group(1), matchobj.group(2)]) + def camelCase(st, to_camelcase): if not to_camelcase: return st @@ -153,3 +155,29 @@ def tableToDict(input, key): return input return output + + +def fixMultilineAndSplit(data, match, delimiter): + output = [] + last_line = None + + for line in data.splitlines(): + if last_line == None: + last_line = line + continue + + if line.strip() == "": + continue + + if re.match(r"^\s+", line): + line = line.strip() + last_line = f"{last_line}{delimiter}{line}" + + else: + output.append(last_line) + last_line = line + + if not last_line == None: + output.append(last_line) + + return output diff --git a/src/sysinfo/modules/tasklist.py b/src/sysinfo/modules/tasklist.py new file mode 100644 index 0000000..55bee38 --- /dev/null +++ b/src/sysinfo/modules/tasklist.py @@ -0,0 +1,82 @@ +import re +from sysinfo_lib import camelCase, fixMultilineAndSplit + + +def parser_fo(stdout, stderr, to_camelcase): + output = [] + unprocessed = [] + image = {} + + if stdout: + data = fixMultilineAndSplit(stdout, r"^\s+", ", ") + + for line in data: + if line.strip() == "": + continue + + kv = re.search(r"^([^:]+):\s*(.*)$", line) + if kv: + key = camelCase(kv.group(1).strip(), to_camelcase) + value = kv.group(2).strip().replace("\u00a0", "") + + if key == "imageName" or key == "Image Name": + image = {} + output.append(image) + + if ( + key == "modules" + or key == "Modules" + or key == "services" + or key == "Services" + ): + value = value.split(", ") + + image[key] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + + main.register( + { + "name": "tasklist", + "system": ["windows"], + "cmd": "%SystemRoot%\\system32\\tasklist.exe /fo list", + "description": "Get currently running processes", + "parser": parser_fo, + } + ) + + main.register( + { + "name": "tasklist_services", + "system": ["windows"], + "cmd": "%SystemRoot%\\system32\\tasklist.exe /svc /fo list", + "description": "Get services hosted in each process", + "parser": parser_fo, + } + ) + + main.register( + { + "name": "tasklist_apps", + "system": ["windows"], + "cmd": "%SystemRoot%\\system32\\tasklist.exe /apps /fo list", + "description": "Get services hosted in each process", + "parser": parser_fo, + } + ) + + main.register( + { + "name": "tasklist_modules", + "system": ["windows"], + "cmd": "%SystemRoot%\\system32\\tasklist.exe /m /fo list", + "description": "Get modules loaded in each process", + "parser": parser_fo, + } + ) From f8557f58a1e0bd9b81ed7eb35d65986b423828cb Mon Sep 17 00:00:00 2001 From: Petr Vavrin Date: Wed, 17 Aug 2022 07:10:06 +0200 Subject: [PATCH 9/9] added driverquery and driverquery_signed command for windows, added list of windows commands, fixed python2 in readme --- README.md | 22 +++++++++-- src/sysinfo/modules/driverquery.py | 59 ++++++++++++++++++++++++++++++ src/sysinfo/sysinfo.py | 2 + 3 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 src/sysinfo/modules/driverquery.py diff --git a/README.md b/README.md index c813e8e..072fe82 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ optional arguments: ### Standart JSON output ``` -python2 sysinfo.py lscpu +python sysinfo.py lscpu ``` ```json { @@ -68,7 +68,7 @@ python2 sysinfo.py lscpu ### Get single value ``` -python2 sysinfo.py lscpu | jq -r ".lscpu.output.modelName" +python sysinfo.py lscpu | jq -r ".lscpu.output.modelName" ``` ``` ARM1176 @@ -76,7 +76,7 @@ ARM1176 ### Output in CSV format ``` -python2 sysinfo.py lsblk | jq -r ".lsblk.output[] | [.name, .label, .size, +python sysinfo.py lsblk | jq -r ".lsblk.output[] | [.name, .label, .size, .mountpoint] | @csv" ``` @@ -103,6 +103,9 @@ sudo python sysinfo.py --import-dir ./out blkid * [jq](https://stedolan.github.io/jq/) ## Available commands + +### Linux + ``` arp - System ARP cache blkid - Block device attributes @@ -231,3 +234,16 @@ vmstat_stats - Displays a table of various event counters and memor yum_installed - YUM - list installed packages yum_repolist - YUM - defined repositories ``` + +### Windows + +``` +arp - System ARP cache +assoc - File associations +driverquery - List of installed device drivers. +driverquery_signed - List of installed device signed drivers. +tasklist - Get currently running processes +tasklist_apps - Get services hosted in each process +tasklist_modules - Get modules loaded in each process +tasklist_services - Get services hosted in each process +``` diff --git a/src/sysinfo/modules/driverquery.py b/src/sysinfo/modules/driverquery.py new file mode 100644 index 0000000..e6dc62f --- /dev/null +++ b/src/sysinfo/modules/driverquery.py @@ -0,0 +1,59 @@ +import re +from sysinfo_lib import camelCase, fixMultilineAndSplit + + +def parser_fo(stdout, stderr, to_camelcase): + output = [] + unprocessed = [] + image = {} + + if stdout: + data = fixMultilineAndSplit(stdout, r"^\s+", ", ") + + for line in data: + if line.strip() == "": + continue + + kv = re.search(r"^([^:]+):\s*(.*)$", line) + if kv: + key = camelCase(kv.group(1).strip(), to_camelcase) + value = kv.group(2).strip().replace("\u00a0", "") + + if ( + key == "moduleName" + or key == "Module Name" + or key == "deviceName" + or key == "DeviceName" + ): + image = {} + output.append(image) + + image[key] = value + continue + + unprocessed.append(line) + + return {"output": output, "unprocessed": unprocessed} + + +def register(main): + + main.register( + { + "name": "driverquery", + "system": ["windows"], + "cmd": "%SystemRoot%\\system32\\driverquery.exe /v /fo list", + "description": "List of installed device drivers.", + "parser": parser_fo, + } + ) + + main.register( + { + "name": "driverquery_signed", + "system": ["windows"], + "cmd": "%SystemRoot%\\system32\\driverquery.exe /si /fo list", + "description": "List of installed device signed drivers.", + "parser": parser_fo, + } + ) diff --git a/src/sysinfo/sysinfo.py b/src/sysinfo/sysinfo.py index 07933f6..e324243 100644 --- a/src/sysinfo/sysinfo.py +++ b/src/sysinfo/sysinfo.py @@ -1,3 +1,5 @@ +#!/usr/bin/python3 + """ * * sysinfo - Python based scripts for obtaining system information from Linux.