From 491fce7052093b8360c6e2326ab5a769e4f609f8 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Tue, 13 Dec 2022 17:31:05 -0800 Subject: [PATCH] add openvpn-status.log file parser --- README.md | 1 + completions/jc_bash_completion.sh | 2 +- completions/jc_zsh_completion.sh | 3 +- jc/lib.py | 1 + jc/parsers/openvpn.py | 302 +++++++++++++++++++++ man/jc.1 | 5 + tests/fixtures/generic/openvpn-status.json | 1 + tests/fixtures/generic/openvpn-status.log | 26 ++ tests/test_openvpn.py | 47 ++++ 9 files changed, 386 insertions(+), 2 deletions(-) create mode 100644 jc/parsers/openvpn.py create mode 100644 tests/fixtures/generic/openvpn-status.json create mode 100644 tests/fixtures/generic/openvpn-status.log create mode 100644 tests/test_openvpn.py diff --git a/README.md b/README.md index 7564422e..89f33c75 100644 --- a/README.md +++ b/README.md @@ -226,6 +226,7 @@ option. | ` --netstat` | `netstat` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/netstat) | | ` --nmcli` | `nmcli` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/nmcli) | | ` --ntpq` | `ntpq -p` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/ntpq) | +| ` --openvpn` | openvpn-status.log file parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/openvpn) | | ` --os-prober` | `os-prober` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/os_prober) | | ` --passwd` | `/etc/passwd` file parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/passwd) | | ` --pci-ids` | `pci.ids` file parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/pci_ids) | diff --git a/completions/jc_bash_completion.sh b/completions/jc_bash_completion.sh index e8b5cba7..6bda7edb 100644 --- a/completions/jc_bash_completion.sh +++ b/completions/jc_bash_completion.sh @@ -4,7 +4,7 @@ _jc() jc_about_options jc_about_mod_options jc_help_options jc_special_options jc_commands=(acpi airport arp blkid cbt chage cksum crontab date df dig dmidecode dpkg du env file findmnt finger free git gpg hciconfig id ifconfig iostat iptables iw jobs last lastb ls lsblk lsmod lsof lspci lsusb md5 md5sum mdadm mount mpstat netstat nmcli ntpq os-prober pidstat ping ping6 pip pip3 postconf printenv ps route rpm rsync sfdisk sha1sum sha224sum sha256sum sha384sum sha512sum shasum ss sshd stat sum sysctl systemctl systeminfo timedatectl top tracepath tracepath6 traceroute traceroute6 udevadm ufw uname update-alternatives upower uptime vdir vmstat w wc who xrandr zipinfo) - jc_parsers=(--acpi --airport --airport-s --arp --asciitable --asciitable-m --blkid --cbt --cef --cef-s --chage --cksum --clf --clf-s --crontab --crontab-u --csv --csv-s --date --datetime-iso --df --dig --dir --dmidecode --dpkg-l --du --email-address --env --file --findmnt --finger --free --fstab --git-log --git-log-s --git-ls-remote --gpg --group --gshadow --hash --hashsum --hciconfig --history --hosts --id --ifconfig --ini --iostat --iostat-s --ip-address --iptables --iw-scan --jar-manifest --jobs --jwt --kv --last --ls --ls-s --lsblk --lsmod --lsof --lspci --lsusb --m3u --mdadm --mount --mpstat --mpstat-s --netstat --nmcli --ntpq --os-prober --passwd --pci-ids --pgpass --pidstat --pidstat-s --ping --ping-s --pip-list --pip-show --plist --postconf --proc --proc-buddyinfo --proc-consoles --proc-cpuinfo --proc-crypto --proc-devices --proc-diskstats --proc-filesystems --proc-interrupts --proc-iomem --proc-ioports --proc-loadavg --proc-locks --proc-meminfo --proc-modules --proc-mtrr --proc-pagetypeinfo --proc-partitions --proc-slabinfo --proc-softirqs --proc-stat --proc-swaps --proc-uptime --proc-version --proc-vmallocinfo --proc-vmstat --proc-zoneinfo --proc-driver-rtc --proc-net-arp --proc-net-dev --proc-net-dev-mcast --proc-net-if-inet6 --proc-net-igmp --proc-net-igmp6 --proc-net-ipv6-route --proc-net-netlink --proc-net-netstat --proc-net-packet --proc-net-protocols --proc-net-route --proc-net-unix --proc-pid-fdinfo --proc-pid-io --proc-pid-maps --proc-pid-mountinfo --proc-pid-numa-maps --proc-pid-smaps --proc-pid-stat --proc-pid-statm --proc-pid-status --ps --route --rpm-qi --rsync --rsync-s --semver --sfdisk --shadow --ss --sshd-conf --stat --stat-s --sysctl --syslog --syslog-s --syslog-bsd --syslog-bsd-s --systemctl --systemctl-lj --systemctl-ls --systemctl-luf --systeminfo --time --timedatectl --timestamp --top --top-s --tracepath --traceroute --udevadm --ufw --ufw-appinfo --uname --update-alt-gs --update-alt-q --upower --uptime --url --vmstat --vmstat-s --w --wc --who --x509-cert --xml --xrandr --yaml --zipinfo) + jc_parsers=(--acpi --airport --airport-s --arp --asciitable --asciitable-m --blkid --cbt --cef --cef-s --chage --cksum --clf --clf-s --crontab --crontab-u --csv --csv-s --date --datetime-iso --df --dig --dir --dmidecode --dpkg-l --du --email-address --env --file --findmnt --finger --free --fstab --git-log --git-log-s --git-ls-remote --gpg --group --gshadow --hash --hashsum --hciconfig --history --hosts --id --ifconfig --ini --iostat --iostat-s --ip-address --iptables --iw-scan --jar-manifest --jobs --jwt --kv --last --ls --ls-s --lsblk --lsmod --lsof --lspci --lsusb --m3u --mdadm --mount --mpstat --mpstat-s --netstat --nmcli --ntpq --openvpn --os-prober --passwd --pci-ids --pgpass --pidstat --pidstat-s --ping --ping-s --pip-list --pip-show --plist --postconf --proc --proc-buddyinfo --proc-consoles --proc-cpuinfo --proc-crypto --proc-devices --proc-diskstats --proc-filesystems --proc-interrupts --proc-iomem --proc-ioports --proc-loadavg --proc-locks --proc-meminfo --proc-modules --proc-mtrr --proc-pagetypeinfo --proc-partitions --proc-slabinfo --proc-softirqs --proc-stat --proc-swaps --proc-uptime --proc-version --proc-vmallocinfo --proc-vmstat --proc-zoneinfo --proc-driver-rtc --proc-net-arp --proc-net-dev --proc-net-dev-mcast --proc-net-if-inet6 --proc-net-igmp --proc-net-igmp6 --proc-net-ipv6-route --proc-net-netlink --proc-net-netstat --proc-net-packet --proc-net-protocols --proc-net-route --proc-net-unix --proc-pid-fdinfo --proc-pid-io --proc-pid-maps --proc-pid-mountinfo --proc-pid-numa-maps --proc-pid-smaps --proc-pid-stat --proc-pid-statm --proc-pid-status --ps --route --rpm-qi --rsync --rsync-s --semver --sfdisk --shadow --ss --sshd-conf --stat --stat-s --sysctl --syslog --syslog-s --syslog-bsd --syslog-bsd-s --systemctl --systemctl-lj --systemctl-ls --systemctl-luf --systeminfo --time --timedatectl --timestamp --top --top-s --tracepath --traceroute --udevadm --ufw --ufw-appinfo --uname --update-alt-gs --update-alt-q --upower --uptime --url --vmstat --vmstat-s --w --wc --who --x509-cert --xml --xrandr --yaml --zipinfo) jc_options=(--force-color -C --debug -d --monochrome -m --meta-out -M --pretty -p --quiet -q --raw -r --unbuffer -u --yaml-out -y) jc_about_options=(--about -a) jc_about_mod_options=(--pretty -p --yaml-out -y --monochrome -m --force-color -C) diff --git a/completions/jc_zsh_completion.sh b/completions/jc_zsh_completion.sh index 7f357a2a..31e19145 100644 --- a/completions/jc_zsh_completion.sh +++ b/completions/jc_zsh_completion.sh @@ -101,7 +101,7 @@ _jc() { 'xrandr:run "xrandr" command with magic syntax.' 'zipinfo:run "zipinfo" command with magic syntax.' ) - jc_parsers=(--acpi --airport --airport-s --arp --asciitable --asciitable-m --blkid --cbt --cef --cef-s --chage --cksum --clf --clf-s --crontab --crontab-u --csv --csv-s --date --datetime-iso --df --dig --dir --dmidecode --dpkg-l --du --email-address --env --file --findmnt --finger --free --fstab --git-log --git-log-s --git-ls-remote --gpg --group --gshadow --hash --hashsum --hciconfig --history --hosts --id --ifconfig --ini --iostat --iostat-s --ip-address --iptables --iw-scan --jar-manifest --jobs --jwt --kv --last --ls --ls-s --lsblk --lsmod --lsof --lspci --lsusb --m3u --mdadm --mount --mpstat --mpstat-s --netstat --nmcli --ntpq --os-prober --passwd --pci-ids --pgpass --pidstat --pidstat-s --ping --ping-s --pip-list --pip-show --plist --postconf --proc --proc-buddyinfo --proc-consoles --proc-cpuinfo --proc-crypto --proc-devices --proc-diskstats --proc-filesystems --proc-interrupts --proc-iomem --proc-ioports --proc-loadavg --proc-locks --proc-meminfo --proc-modules --proc-mtrr --proc-pagetypeinfo --proc-partitions --proc-slabinfo --proc-softirqs --proc-stat --proc-swaps --proc-uptime --proc-version --proc-vmallocinfo --proc-vmstat --proc-zoneinfo --proc-driver-rtc --proc-net-arp --proc-net-dev --proc-net-dev-mcast --proc-net-if-inet6 --proc-net-igmp --proc-net-igmp6 --proc-net-ipv6-route --proc-net-netlink --proc-net-netstat --proc-net-packet --proc-net-protocols --proc-net-route --proc-net-unix --proc-pid-fdinfo --proc-pid-io --proc-pid-maps --proc-pid-mountinfo --proc-pid-numa-maps --proc-pid-smaps --proc-pid-stat --proc-pid-statm --proc-pid-status --ps --route --rpm-qi --rsync --rsync-s --semver --sfdisk --shadow --ss --sshd-conf --stat --stat-s --sysctl --syslog --syslog-s --syslog-bsd --syslog-bsd-s --systemctl --systemctl-lj --systemctl-ls --systemctl-luf --systeminfo --time --timedatectl --timestamp --top --top-s --tracepath --traceroute --udevadm --ufw --ufw-appinfo --uname --update-alt-gs --update-alt-q --upower --uptime --url --vmstat --vmstat-s --w --wc --who --x509-cert --xml --xrandr --yaml --zipinfo) + jc_parsers=(--acpi --airport --airport-s --arp --asciitable --asciitable-m --blkid --cbt --cef --cef-s --chage --cksum --clf --clf-s --crontab --crontab-u --csv --csv-s --date --datetime-iso --df --dig --dir --dmidecode --dpkg-l --du --email-address --env --file --findmnt --finger --free --fstab --git-log --git-log-s --git-ls-remote --gpg --group --gshadow --hash --hashsum --hciconfig --history --hosts --id --ifconfig --ini --iostat --iostat-s --ip-address --iptables --iw-scan --jar-manifest --jobs --jwt --kv --last --ls --ls-s --lsblk --lsmod --lsof --lspci --lsusb --m3u --mdadm --mount --mpstat --mpstat-s --netstat --nmcli --ntpq --openvpn --os-prober --passwd --pci-ids --pgpass --pidstat --pidstat-s --ping --ping-s --pip-list --pip-show --plist --postconf --proc --proc-buddyinfo --proc-consoles --proc-cpuinfo --proc-crypto --proc-devices --proc-diskstats --proc-filesystems --proc-interrupts --proc-iomem --proc-ioports --proc-loadavg --proc-locks --proc-meminfo --proc-modules --proc-mtrr --proc-pagetypeinfo --proc-partitions --proc-slabinfo --proc-softirqs --proc-stat --proc-swaps --proc-uptime --proc-version --proc-vmallocinfo --proc-vmstat --proc-zoneinfo --proc-driver-rtc --proc-net-arp --proc-net-dev --proc-net-dev-mcast --proc-net-if-inet6 --proc-net-igmp --proc-net-igmp6 --proc-net-ipv6-route --proc-net-netlink --proc-net-netstat --proc-net-packet --proc-net-protocols --proc-net-route --proc-net-unix --proc-pid-fdinfo --proc-pid-io --proc-pid-maps --proc-pid-mountinfo --proc-pid-numa-maps --proc-pid-smaps --proc-pid-stat --proc-pid-statm --proc-pid-status --ps --route --rpm-qi --rsync --rsync-s --semver --sfdisk --shadow --ss --sshd-conf --stat --stat-s --sysctl --syslog --syslog-s --syslog-bsd --syslog-bsd-s --systemctl --systemctl-lj --systemctl-ls --systemctl-luf --systeminfo --time --timedatectl --timestamp --top --top-s --tracepath --traceroute --udevadm --ufw --ufw-appinfo --uname --update-alt-gs --update-alt-q --upower --uptime --url --vmstat --vmstat-s --w --wc --who --x509-cert --xml --xrandr --yaml --zipinfo) jc_parsers_describe=( '--acpi:`acpi` command parser' '--airport:`airport -I` command parser' @@ -175,6 +175,7 @@ _jc() { '--netstat:`netstat` command parser' '--nmcli:`nmcli` command parser' '--ntpq:`ntpq -p` command parser' + '--openvpn:openvpn-status.log file parser' '--os-prober:`os-prober` command parser' '--passwd:`/etc/passwd` file parser' '--pci-ids:`pci.ids` file parser' diff --git a/jc/lib.py b/jc/lib.py index 9f2215fd..ab0a544c 100644 --- a/jc/lib.py +++ b/jc/lib.py @@ -85,6 +85,7 @@ parsers: List[str] = [ 'netstat', 'nmcli', 'ntpq', + 'openvpn', 'os-prober', 'passwd', 'pci-ids', diff --git a/jc/parsers/openvpn.py b/jc/parsers/openvpn.py new file mode 100644 index 00000000..56257ae9 --- /dev/null +++ b/jc/parsers/openvpn.py @@ -0,0 +1,302 @@ +"""jc - JSON Convert openvpn-status.log file parser + +The `*_epoch` calculated timestamp fields are naive. (i.e. based on +the local time of the system the parser is run on) + +The `*_epoch_utc` calculated timestamp fields are timezone-aware and +is only available if the timestamp has a UTC timezone. + +Usage (cli): + + $ cat openvpn-status.log | jc --openvpn + +Usage (module): + + import jc + result = jc.parse('openvpn', openvpn_status_log_file_output) + +Schema: + + { + "clients": [ + { + "common_name": string, + "real_address": string, + "bytes_received": integer, + "bytes_sent": integer, + "connected_since": string, + "updated": string, + "connected_since_epoch": integer, + "connected_since_epoch_utc": integer, + "updated_epoch": integer, + "updated_epoch_utc": integer + } + ], + "routing_table": [ + { + "virtual_address": string, + "common_name": string, + "real_address": string, + "last_reference": string, + "last_reference_epoch": integer, + "last_reference_epoch_utc": integer + } + ], + "global_stats": { + "max_bcast_mcast_queue_len": integer + } + } + +Examples: + + $ cat openvpn-status.log | jc --openvpn -p + { + "clients": [ + { + "common_name": "foo@example.com", + "real_address": "10.10.10.10:49502", + "bytes_received": 334948, + "bytes_sent": 1973012, + "connected_since": "Thu Jun 18 04:23:03 2015", + "updated": "Thu Jun 18 08:12:15 2015", + "connected_since_epoch": 1434626583, + "connected_since_epoch_utc": null, + "updated_epoch": 1434640335, + "updated_epoch_utc": null + }, + { + "common_name": "foo@example.com", + "real_address": "10.10.10.10:49503", + "bytes_received": 334948, + "bytes_sent": 1973012, + "connected_since": "Thu Jun 18 04:23:03 2015", + "updated": "Thu Jun 18 08:12:15 2015", + "connected_since_epoch": 1434626583, + "connected_since_epoch_utc": null, + "updated_epoch": 1434640335, + "updated_epoch_utc": null + } + ], + "routing_table": [ + { + "virtual_address": "192.168.255.118", + "common_name": "baz@example.com", + "real_address": "10.10.10.10:63414", + "last_reference": "Thu Jun 18 08:12:09 2015", + "last_reference_epoch": 1434640329, + "last_reference_epoch_utc": null + }, + { + "virtual_address": "10.200.0.0/16", + "common_name": "baz@example.com", + "real_address": "10.10.10.10:63414", + "last_reference": "Thu Jun 18 08:12:09 2015", + "last_reference_epoch": 1434640329, + "last_reference_epoch_utc": null + } + ], + "global_stats": { + "max_bcast_mcast_queue_len": 0 + } + } + + $ cat openvpn-status.log | jc --openvpn -p -r + { + "clients": [ + { + "common_name": "foo@example.com", + "real_address": "10.10.10.10:49502", + "bytes_received": "334948", + "bytes_sent": "1973012", + "connected_since": "Thu Jun 18 04:23:03 2015", + "updated": "Thu Jun 18 08:12:15 2015" + }, + { + "common_name": "foo@example.com", + "real_address": "10.10.10.10:49503", + "bytes_received": "334948", + "bytes_sent": "1973012", + "connected_since": "Thu Jun 18 04:23:03 2015", + "updated": "Thu Jun 18 08:12:15 2015" + } + ], + "routing_table": [ + { + "virtual_address": "192.168.255.118", + "common_name": "baz@example.com", + "real_address": "10.10.10.10:63414", + "last_reference": "Thu Jun 18 08:12:09 2015" + }, + { + "virtual_address": "10.200.0.0/16", + "common_name": "baz@example.com", + "real_address": "10.10.10.10:63414", + "last_reference": "Thu Jun 18 08:12:09 2015" + } + ], + "global_stats": { + "max_bcast_mcast_queue_len": "0" + } + } +""" +from typing import List, Dict +from jc.jc_types import JSONDictType +import jc.utils + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = 'openvpn-status.log file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'] + + +__version__ = info.version + + +def _process(proc_data: JSONDictType) -> JSONDictType: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (Dictionary) raw structured data to process + + Returns: + + Dictionary. Structured to conform to the schema. + """ + int_list = {'bytes_received', 'bytes_sent', 'max_bcast_mcast_queue_len'} + date_fields = {'connected_since', 'updated', 'last_reference'} + + if 'clients' in proc_data: + for item in proc_data['clients']: + for k, v in item.copy().items(): + if k in int_list: + item[k] = jc.utils.convert_to_int(v) + + if k in date_fields: + dt = jc.utils.timestamp(item[k], format_hint=(1000,)) + item[k + '_epoch'] = dt.naive + item[k + '_epoch_utc'] = dt.utc + + if 'routing_table' in proc_data: + for item in proc_data['routing_table']: + for k, v in item.copy(). items(): + if k in date_fields: + dt = jc.utils.timestamp(item[k], format_hint=(1000,)) + item[k + '_epoch'] = dt.naive + item[k + '_epoch_utc'] = dt.utc + + if 'global_stats' in proc_data: + for k, v in proc_data['global_stats'].items(): + if k in int_list: + if k in int_list: + proc_data['global_stats'][k] = jc.utils.convert_to_int(v) + + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> JSONDictType: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + Dictionary. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: Dict = {} + clients: List[Dict] = [] + routing_table: List[Dict] = [] + global_stats: Dict = {} + section: str = '' # clients, routing, stats + updated: str = '' + + if jc.utils.has_data(data): + + for line in filter(None, data.splitlines()): + + if line.startswith('OpenVPN CLIENT LIST'): + section = 'clients' + continue + + if line.startswith('ROUTING TABLE'): + section = 'routing' + continue + + if line.startswith('GLOBAL STATS'): + section = 'stats' + continue + + if line.startswith('END'): + break + + if section == 'clients' and line.startswith('Updated,'): + _, updated = line.split(',', maxsplit=1) + continue + + if section == 'clients' and line.startswith('Common Name,Real Address,'): + continue + + if section == 'clients': + c_name, real_addr, r_bytes, s_bytes, connected = line.split(',', maxsplit=5) + clients.append( + { + 'common_name': c_name, + 'real_address': real_addr, + 'bytes_received': r_bytes, + 'bytes_sent': s_bytes, + 'connected_since': connected, + 'updated': updated + } + ) + continue + + if section == 'routing' and line.startswith('Virtual Address,Common Name,'): + continue + + if section == 'routing': + # Virtual Address,Common Name,Real Address,Last Ref + # 192.168.255.118,baz@example.com,10.10.10.10:63414,Thu Jun 18 08:12:09 2015 + virt_addr, c_name, real_addr, last_ref = line.split(',', maxsplit=4) + route = { + 'virtual_address': virt_addr, + 'common_name': c_name, + 'real_address': real_addr, + 'last_reference': last_ref + } + + # fixup for virtual addresses ending in "C" + if 'virtual_address' in route: + if route['virtual_address'].endswith('C'): + route['virtual_address'] = route['virtual_address'][:-1] + + routing_table.append(route) + continue + + if section == "stats": + if line.startswith('Max bcast/mcast queue length'): + global_stats['max_bcast_mcast_queue_len'] = line.split(',', maxsplit=1)[1] + continue + + raw_output['clients'] = clients + raw_output['routing_table'] = routing_table + raw_output['global_stats'] = {} + raw_output['global_stats'].update(global_stats) + + return raw_output if raw else _process(raw_output) diff --git a/man/jc.1 b/man/jc.1 index 93f36ea2..62958be8 100644 --- a/man/jc.1 +++ b/man/jc.1 @@ -395,6 +395,11 @@ M3U and M3U8 file parser \fB--ntpq\fP `ntpq -p` command parser +.TP +.B +\fB--openvpn\fP +openvpn-status.log file parser + .TP .B \fB--os-prober\fP diff --git a/tests/fixtures/generic/openvpn-status.json b/tests/fixtures/generic/openvpn-status.json new file mode 100644 index 00000000..361566eb --- /dev/null +++ b/tests/fixtures/generic/openvpn-status.json @@ -0,0 +1 @@ +{"clients":[{"common_name":"foo@example.com","real_address":"10.10.10.10:49502","bytes_received":334948,"bytes_sent":1973012,"connected_since":"Thu Jun 18 04:23:03 2015","updated":"Thu Jun 18 08:12:15 2015","connected_since_epoch":1434626583,"connected_since_epoch_utc":null,"updated_epoch":1434640335,"updated_epoch_utc":null},{"common_name":"foo@example.com","real_address":"10.10.10.10:49503","bytes_received":334948,"bytes_sent":1973012,"connected_since":"Thu Jun 18 04:23:03 2015","updated":"Thu Jun 18 08:12:15 2015","connected_since_epoch":1434626583,"connected_since_epoch_utc":null,"updated_epoch":1434640335,"updated_epoch_utc":null},{"common_name":"bar@example.com","real_address":"10.10.10.10:64169","bytes_received":1817262,"bytes_sent":28981224,"connected_since":"Thu Jun 18 04:08:39 2015","updated":"Thu Jun 18 08:12:15 2015","connected_since_epoch":1434625719,"connected_since_epoch_utc":null,"updated_epoch":1434640335,"updated_epoch_utc":null},{"common_name":"baz@example.com","real_address":"10.10.10.10:63414","bytes_received":111183,"bytes_sent":1202203,"connected_since":"Thu Jun 18 07:57:25 2015","updated":"Thu Jun 18 08:12:15 2015","connected_since_epoch":1434639445,"connected_since_epoch_utc":null,"updated_epoch":1434640335,"updated_epoch_utc":null},{"common_name":"tap@example.com","real_address":"10.0.0.100:55712","bytes_received":0,"bytes_sent":0,"connected_since":"Thu Oct 19 20:14:19 2017","updated":"Thu Jun 18 08:12:15 2015","connected_since_epoch":1508469259,"connected_since_epoch_utc":null,"updated_epoch":1434640335,"updated_epoch_utc":null},{"common_name":"baz@example.com","real_address":"10.10.10.10","bytes_received":111183,"bytes_sent":1202203,"connected_since":"Thu Jun 18 07:57:25 2015","updated":"Thu Jun 18 08:12:15 2015","connected_since_epoch":1434639445,"connected_since_epoch_utc":null,"updated_epoch":1434640335,"updated_epoch_utc":null}],"routing_table":[{"virtual_address":"192.168.255.118","common_name":"baz@example.com","real_address":"10.10.10.10:63414","last_reference":"Thu Jun 18 08:12:09 2015","last_reference_epoch":1434640329,"last_reference_epoch_utc":null},{"virtual_address":"10.200.0.0/16","common_name":"baz@example.com","real_address":"10.10.10.10:63414","last_reference":"Thu Jun 18 08:12:09 2015","last_reference_epoch":1434640329,"last_reference_epoch_utc":null},{"virtual_address":"2001:db8::1000/124","common_name":"baz@example.com","real_address":"10.10.10.10:63414","last_reference":"Thu Jun 18 08:12:09 2015","last_reference_epoch":1434640329,"last_reference_epoch_utc":null},{"virtual_address":"192.168.255.134","common_name":"foo@example.com","real_address":"10.10.10.10:49502","last_reference":"Thu Jun 18 08:12:09 2015","last_reference_epoch":1434640329,"last_reference_epoch_utc":null},{"virtual_address":"192.168.255.135","common_name":"foo@example.com","real_address":"10.10.10.10:49503","last_reference":"Thu Jun 18 08:12:09 2015","last_reference_epoch":1434640329,"last_reference_epoch_utc":null},{"virtual_address":"192.168.255.126","common_name":"bar@example.com","real_address":"10.10.10.10:64169","last_reference":"Thu Jun 18 08:11:55 2015","last_reference_epoch":1434640315,"last_reference_epoch_utc":null},{"virtual_address":"22:1d:63:bf:62:38","common_name":"tap@example.com","real_address":"10.0.0.100:55712","last_reference":"Thu Oct 19 20:14:19 2017","last_reference_epoch":1508469259,"last_reference_epoch_utc":null},{"virtual_address":"192.168.255.126","common_name":"bar@example.com","real_address":"10.10.10.10:64169","last_reference":"Thu Jun 18 08:11:55 2015","last_reference_epoch":1434640315,"last_reference_epoch_utc":null},{"virtual_address":"192.168.255.16","common_name":"bar@example.com","real_address":"10.10.10.10:64169","last_reference":"Thu Jun 18 08:11:55 2015","last_reference_epoch":1434640315,"last_reference_epoch_utc":null},{"virtual_address":"192.168.255.1","common_name":"bar@example.com","real_address":"10.10.10.10:64169","last_reference":"Thu Jun 18 08:11:55 2015","last_reference_epoch":1434640315,"last_reference_epoch_utc":null},{"virtual_address":"192.168.255.1","common_name":"baz@example.com","real_address":"10.10.10.10","last_reference":"Thu Jun 18 08:11:55 2015","last_reference_epoch":1434640315,"last_reference_epoch_utc":null}],"global_stats":{"max_bcast_mcast_queue_len":0}} diff --git a/tests/fixtures/generic/openvpn-status.log b/tests/fixtures/generic/openvpn-status.log new file mode 100644 index 00000000..171e08a3 --- /dev/null +++ b/tests/fixtures/generic/openvpn-status.log @@ -0,0 +1,26 @@ +OpenVPN CLIENT LIST +Updated,Thu Jun 18 08:12:15 2015 +Common Name,Real Address,Bytes Received,Bytes Sent,Connected Since +foo@example.com,10.10.10.10:49502,334948,1973012,Thu Jun 18 04:23:03 2015 +foo@example.com,10.10.10.10:49503,334948,1973012,Thu Jun 18 04:23:03 2015 +bar@example.com,10.10.10.10:64169,1817262,28981224,Thu Jun 18 04:08:39 2015 +baz@example.com,10.10.10.10:63414,111183,1202203,Thu Jun 18 07:57:25 2015 +tap@example.com,10.0.0.100:55712,0,0,Thu Oct 19 20:14:19 2017 +baz@example.com,10.10.10.10,111183,1202203,Thu Jun 18 07:57:25 2015 +ROUTING TABLE +Virtual Address,Common Name,Real Address,Last Ref +192.168.255.118,baz@example.com,10.10.10.10:63414,Thu Jun 18 08:12:09 2015 +10.200.0.0/16,baz@example.com,10.10.10.10:63414,Thu Jun 18 08:12:09 2015 +2001:db8::1000/124,baz@example.com,10.10.10.10:63414,Thu Jun 18 08:12:09 2015 +192.168.255.134,foo@example.com,10.10.10.10:49502,Thu Jun 18 08:12:09 2015 +192.168.255.135,foo@example.com,10.10.10.10:49503,Thu Jun 18 08:12:09 2015 +192.168.255.126,bar@example.com,10.10.10.10:64169,Thu Jun 18 08:11:55 2015 +22:1d:63:bf:62:38,tap@example.com,10.0.0.100:55712,Thu Oct 19 20:14:19 2017 +192.168.255.126C,bar@example.com,10.10.10.10:64169,Thu Jun 18 08:11:55 2015 +192.168.255.16C,bar@example.com,10.10.10.10:64169,Thu Jun 18 08:11:55 2015 +192.168.255.1C,bar@example.com,10.10.10.10:64169,Thu Jun 18 08:11:55 2015 +192.168.255.1,baz@example.com,10.10.10.10,Thu Jun 18 08:11:55 2015 +GLOBAL STATS +Max bcast/mcast queue length,0 +END + diff --git a/tests/test_openvpn.py b/tests/test_openvpn.py new file mode 100644 index 00000000..b9b6ceef --- /dev/null +++ b/tests/test_openvpn.py @@ -0,0 +1,47 @@ +import os +import unittest +import json +from typing import Dict +from jc.parsers.openvpn import parse + +THIS_DIR = os.path.dirname(os.path.abspath(__file__)) + + +class MyTests(unittest.TestCase): + f_in: Dict = {} + f_json: Dict = {} + + @classmethod + def setUpClass(cls): + fixtures = { + 'openvpn': ( + 'fixtures/generic/openvpn-status.log', + 'fixtures/generic/openvpn-status.json') + } + + for file, filepaths in fixtures.items(): + with open(os.path.join(THIS_DIR, filepaths[0]), 'r', encoding='utf-8') as a, \ + open(os.path.join(THIS_DIR, filepaths[1]), 'r', encoding='utf-8') as b: + cls.f_in[file] = a.read() + cls.f_json[file] = json.loads(b.read()) + + + def test_openvpn_nodata(self): + """ + Test 'openvpn' with no data + """ + self.assertEqual(parse('', quiet=True), {}) + + + def test_openvpn(self): + """ + Test 'openvpn' + """ + self.assertEqual( + parse(self.f_in['openvpn'], quiet=True), + self.f_json['openvpn'] + ) + + +if __name__ == '__main__': + unittest.main()