diff --git a/jc/cli.py b/jc/cli.py index 70d4b1fb..d0ecc25c 100644 --- a/jc/cli.py +++ b/jc/cli.py @@ -30,6 +30,7 @@ import jc.parsers.route import jc.parsers.ss import jc.parsers.stat import jc.parsers.systemctl +import jc.parsers.systemctl_luf import jc.parsers.uname import jc.parsers.uptime import jc.parsers.w @@ -46,37 +47,38 @@ def helptext(message): Usage: jc PARSER [OPTIONS] Parsers: - --arp arp parser - --df df parser - --dig dig parser - --env env parser - --free free parser - --fstab /etc/fstab file parser - --history history parser - --hosts /etc/hosts file parser - --ifconfig iconfig parser - --iptables iptables parser - --jobs jobs parser - --ls ls parser - --lsblk lsblk parser - --lsmod lsmod parser - --lsof lsof parser - --mount mount parser - --netstat netstat parser - --ps ps parser - --route route parser - --ss ss parser - --stat stat parser - --systemctl systemctl parser - --uname uname -a parser - --uptime uptime parser - --w w parser + --arp arp parser + --df df parser + --dig dig parser + --env env parser + --free free parser + --fstab /etc/fstab file parser + --history history parser + --hosts /etc/hosts file parser + --ifconfig iconfig parser + --iptables iptables parser + --jobs jobs parser + --ls ls parser + --lsblk lsblk parser + --lsmod lsmod parser + --lsof lsof parser + --mount mount parser + --netstat netstat parser + --ps ps parser + --route route parser + --ss ss parser + --stat stat parser + --systemctl systemctl parser + --systemctl-luf systemctl parser + --uname uname -a parser + --uptime uptime parser + --w w parser Options: - -d debug - show trace messages - -p pretty print output - -q quiet - suppress warnings - -r raw JSON output + -d debug - show trace messages + -p pretty print output + -q quiet - suppress warnings + -r raw JSON output Example: ls -al | jc --ls -p @@ -134,6 +136,7 @@ def main(): '--ss': jc.parsers.ss.parse, '--stat': jc.parsers.stat.parse, '--systemctl': jc.parsers.systemctl.parse, + '--systemctl-luf': jc.parsers.systemctl_luf.parse, '--uname': jc.parsers.uname.parse, '--uptime': jc.parsers.uptime.parse, '--w': jc.parsers.w.parse diff --git a/jc/parsers/systemctl_luf.py b/jc/parsers/systemctl_luf.py new file mode 100644 index 00000000..9840a9df --- /dev/null +++ b/jc/parsers/systemctl_luf.py @@ -0,0 +1,110 @@ +"""jc - JSON CLI output utility systemctl-luf Parser + +Usage: + specify --systemctl-luf as the first argument if the piped input is coming from systemctl --list-unit-files + +Examples: + + $ systemctl -a | jc --systemctl -p + [ + { + "unit": "proc-sys-fs-binfmt_misc.automount", + "load": "loaded", + "active": "active", + "sub": "waiting", + "description": "Arbitrary Executable File Formats File System Automount Point" + }, + { + "unit": "dev-block-8:2.device", + "load": "loaded", + "active": "active", + "sub": "plugged", + "description": "LVM PV 3klkIj-w1qk-DkJi-0XBJ-y3o7-i2Ac-vHqWBM on /dev/sda2 2" + }, + { + "unit": "dev-cdrom.device", + "load": "loaded", + "active": "active", + "sub": "plugged", + "description": "VMware_Virtual_IDE_CDROM_Drive" + }, + ... + ] +""" +import jc.utils + + +def process(proc_data): + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (dictionary) raw structured data to process + + Returns: + + dictionary structured data with the following schema: + + [ + { + "unit": string, + "load": string, + "active": string, + "sub": string, + "description": string + } + ] + """ + # nothing more to process + return proc_data + + +def parse(data, raw=False, quiet=False): + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) output preprocessed JSON if True + quiet: (boolean) suppress warning messages if True + + Returns: + + dictionary raw or processed structured data + """ + + # compatible options: linux, darwin, cygwin, win32, aix, systemctlbsd + compatible = ['linux'] + + if not quiet: + jc.utils.compatibility(__name__, compatible) + + linedata = data.splitlines() + # Clear any blank lines + linedata = list(filter(None, linedata)) + # clean up non-ascii characters, if any + cleandata = [] + for entry in linedata: + cleandata.append(entry.encode('ascii', errors='ignore').decode()) + + header_text = cleandata[0] + header_text = header_text.lower().replace('unit file', 'unit_file') + header_list = header_text.split() + + raw_output = [] + + for entry in cleandata[1:]: + if entry.find('unit files listed.') != -1: + break + + else: + entry_list = entry.split(maxsplit=4) + output_line = dict(zip(header_list, entry_list)) + raw_output.append(output_line) + + if raw: + return raw_output + else: + return process(raw_output)