mirror of
https://github.com/kellyjonbrazil/jc.git
synced 2026-04-03 17:44:07 +02:00
Compare commits
78 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f2cd81ca7 | ||
|
|
6c8aafa2c5 | ||
|
|
41e2e16436 | ||
|
|
20b625860e | ||
|
|
0d703cd3a8 | ||
|
|
7b3d345d62 | ||
|
|
53b6f1b329 | ||
|
|
ecc267b3cb | ||
|
|
5d2496b5f7 | ||
|
|
810eeba724 | ||
|
|
fb5c1b9c94 | ||
|
|
f797127ca9 | ||
|
|
56bd860a5e | ||
|
|
9fe659d625 | ||
|
|
128e36404d | ||
|
|
2f9377cb67 | ||
|
|
585ff83a2e | ||
|
|
45b23e8b3c | ||
|
|
b9eec1a5cd | ||
|
|
47545833ed | ||
|
|
6f8e4fb2ed | ||
|
|
4f7821ac8e | ||
|
|
7f2722ff96 | ||
|
|
1d19de3005 | ||
|
|
e01287b329 | ||
|
|
441bcbde80 | ||
|
|
936432d879 | ||
|
|
51543437d7 | ||
|
|
dd9229f161 | ||
|
|
3d9554baec | ||
|
|
e33a81269c | ||
|
|
f3352352ed | ||
|
|
1c0a35dff8 | ||
|
|
8ba75794a6 | ||
|
|
77af5ac9d3 | ||
|
|
4067bfed9f | ||
|
|
0363ddcc6a | ||
|
|
04303efa75 | ||
|
|
956f74358b | ||
|
|
4fe3377029 | ||
|
|
1944a7145e | ||
|
|
3d698e50c0 | ||
|
|
5945ded816 | ||
|
|
ecd0e03c66 | ||
|
|
9fd13e6987 | ||
|
|
1feb000231 | ||
|
|
d270ddc6ce | ||
|
|
07ef285b06 | ||
|
|
467ad60e20 | ||
|
|
91b3572ead | ||
|
|
60caa17eb9 | ||
|
|
eea31ddbe4 | ||
|
|
61793bba31 | ||
|
|
51e4a476ba | ||
|
|
883f0c9cf7 | ||
|
|
ffaf455d43 | ||
|
|
b520532578 | ||
|
|
3b1af1a9b6 | ||
|
|
0fa5f7f67f | ||
|
|
a77298e560 | ||
|
|
5f75df2e4b | ||
|
|
38d169f4d0 | ||
|
|
e737dde9e0 | ||
|
|
6e49c87575 | ||
|
|
6afa6b449e | ||
|
|
424d9c1347 | ||
|
|
10d1ab1c74 | ||
|
|
5db256c3e7 | ||
|
|
7f7dcc35ec | ||
|
|
edcde58cb9 | ||
|
|
3a7ca118ff | ||
|
|
f36c713110 | ||
|
|
0db2ad2f5e | ||
|
|
816c38e1fe | ||
|
|
e4cf7b502e | ||
|
|
4ca7179481 | ||
|
|
bebd6a60fb | ||
|
|
5d7940a89b |
115
.github/workflows/pythonapp.yml
vendored
115
.github/workflows/pythonapp.yml
vendored
@@ -9,69 +9,14 @@ on:
|
||||
- "**/*.py"
|
||||
|
||||
jobs:
|
||||
very_old_python:
|
||||
if: github.event.pull_request.draft == false
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-13, windows-2019]
|
||||
python-version: ["3.6"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: "Set up timezone to America/Los_Angeles"
|
||||
uses: szenius/set-timezone@v1.2
|
||||
with:
|
||||
timezoneLinux: "America/Los_Angeles"
|
||||
timezoneMacos: "America/Los_Angeles"
|
||||
timezoneWindows: "Pacific Standard Time"
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r requirements.txt
|
||||
- name: Test with unittest
|
||||
run: |
|
||||
python -m unittest discover tests
|
||||
|
||||
old_python:
|
||||
if: github.event.pull_request.draft == false
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-13, ubuntu-22.04, windows-2019]
|
||||
python-version: ["3.7", "3.8", "3.9", "3.10"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: "Set up timezone to America/Los_Angeles"
|
||||
uses: szenius/set-timezone@v1.2
|
||||
with:
|
||||
timezoneLinux: "America/Los_Angeles"
|
||||
timezoneMacos: "America/Los_Angeles"
|
||||
timezoneWindows: "Pacific Standard Time"
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r requirements.txt
|
||||
- name: Test with unittest
|
||||
run: |
|
||||
python -m unittest discover tests
|
||||
|
||||
latest_python:
|
||||
if: github.event.pull_request.draft == false
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-latest, ubuntu-latest, windows-latest]
|
||||
python-version: ["3.11", "3.12"]
|
||||
os: [macos-15-intel, macos-latest, ubuntu-latest, ubuntu-24.04-arm, windows-latest]
|
||||
python-version: ["3.11", "3.12", "3.13", "3.14"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@@ -92,3 +37,59 @@ jobs:
|
||||
- name: Test with unittest
|
||||
run: |
|
||||
python -m unittest discover tests
|
||||
|
||||
# very_old_python:
|
||||
# if: github.event.pull_request.draft == false
|
||||
# runs-on: ${{ matrix.os }}
|
||||
# strategy:
|
||||
# matrix:
|
||||
# os: [macos-13, windows-2022]
|
||||
# python-version: ["3.6"]
|
||||
|
||||
# steps:
|
||||
# - uses: actions/checkout@v3
|
||||
# - name: "Set up timezone to America/Los_Angeles"
|
||||
# uses: szenius/set-timezone@v1.2
|
||||
# with:
|
||||
# timezoneLinux: "America/Los_Angeles"
|
||||
# timezoneMacos: "America/Los_Angeles"
|
||||
# timezoneWindows: "Pacific Standard Time"
|
||||
# - name: Set up Python ${{ matrix.python-version }}
|
||||
# uses: actions/setup-python@v4
|
||||
# with:
|
||||
# python-version: ${{ matrix.python-version }}
|
||||
# - name: Install dependencies
|
||||
# run: |
|
||||
# python -m pip install --upgrade pip
|
||||
# pip install -r requirements.txt
|
||||
# - name: Test with unittest
|
||||
# run: |
|
||||
# python -m unittest discover tests
|
||||
|
||||
# old_python:
|
||||
# if: github.event.pull_request.draft == false
|
||||
# runs-on: ${{ matrix.os }}
|
||||
# strategy:
|
||||
# matrix:
|
||||
# os: [macos-13, ubuntu-22.04, windows-2022]
|
||||
# python-version: ["3.7", "3.8", "3.9", "3.10"]
|
||||
|
||||
# steps:
|
||||
# - uses: actions/checkout@v3
|
||||
# - name: "Set up timezone to America/Los_Angeles"
|
||||
# uses: szenius/set-timezone@v1.2
|
||||
# with:
|
||||
# timezoneLinux: "America/Los_Angeles"
|
||||
# timezoneMacos: "America/Los_Angeles"
|
||||
# timezoneWindows: "Pacific Standard Time"
|
||||
# - name: Set up Python ${{ matrix.python-version }}
|
||||
# uses: actions/setup-python@v4
|
||||
# with:
|
||||
# python-version: ${{ matrix.python-version }}
|
||||
# - name: Install dependencies
|
||||
# run: |
|
||||
# python -m pip install --upgrade pip
|
||||
# pip install -r requirements.txt
|
||||
# - name: Test with unittest
|
||||
# run: |
|
||||
# python -m unittest discover tests
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,3 +7,4 @@ build/
|
||||
.vscode/
|
||||
_config.yml
|
||||
.venv
|
||||
.DS_Store
|
||||
|
||||
25
CHANGELOG
25
CHANGELOG
@@ -1,5 +1,30 @@
|
||||
jc changelog
|
||||
|
||||
20260330 v1.25.7
|
||||
- Add `typeset` and `declare` Bash internal command parser to convert variables
|
||||
simple arrays, and associative arrays along with object metadata
|
||||
- Enhance `pip-show` command parser to add `-f` show files support
|
||||
- Enhance `rsync` and `rsync-s` parsers to add `--stats` or `--info=stats[1-3]` fields
|
||||
- Fix `hashsum` command parser to correctly parse the `mode` indicator
|
||||
- Fix `dir` command parser for incorrect stripping of the `D:` drive letter
|
||||
- Fix `proc-pid-smaps` proc parser when unknown VmFlags are output
|
||||
- Fix `ifconfig` command parser for incorrect stripping of leading zeros in some hex numbers
|
||||
- Fix `iptables` command parser when Target is blank and verbose output is used
|
||||
|
||||
20251012 v1.25.6
|
||||
- Add `net-localgroup` Windows command parser
|
||||
- Add `net-user` Windows command parser
|
||||
- Add `route-print` Windows command parser
|
||||
- Add `traceroute-s` streaming command parser
|
||||
- Add `max_hops` and `data_bytes` fields to `traceroute` command parser
|
||||
- Add `x509-crl` file parser to support Certificate Revocation List PEM and DER files
|
||||
- Add `yay` as a magic command for the `pacman` command parser
|
||||
- Fix `bluetoothctl` command parser to support output with the `cable_pairing` attribute
|
||||
- Fix `nmcli` command parser to support blank `team.config` JSON value and `team-port.config` JSON value
|
||||
- Fix `top` command parsers to correct memory size field parsing. Several new unit
|
||||
and byte conversion fields have been added
|
||||
- Fix `who` command parser to support the `process` field on Debian13
|
||||
|
||||
20250503 v1.25.5
|
||||
- Add `amixer` command parser
|
||||
- Enhance `iptables` command parser to add default policy statistics fields
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
[](https://github.com/kellyjonbrazil/jc/actions)
|
||||
[](https://pypi.org/project/jc/)
|
||||
|
||||
> Check out the `jc` Python [package documentation](https://github.com/kellyjonbrazil/jc/tree/master/docs) for developers
|
||||
@@ -124,6 +123,7 @@ pip3 install jc
|
||||
| FreeBSD | `portsnap fetch update && cd /usr/ports/textproc/py-jc && make install clean` |
|
||||
| Ansible filter plugin | `ansible-galaxy collection install community.general` |
|
||||
| FortiSOAR connector | Install from FortiSOAR Connector Marketplace |
|
||||
| Mise-en-place (Linux/MacOS) | `mise use -g jc@latest` |
|
||||
|
||||
> For more OS Packages, see https://repology.org/project/jc/versions.
|
||||
|
||||
@@ -246,6 +246,8 @@ option.
|
||||
| `--mpstat-s` | `mpstat` command streaming parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/mpstat_s) |
|
||||
| `--needrestart` | `needrestart -b` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/needrestart) |
|
||||
| `--netstat` | `netstat` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/netstat) |
|
||||
| `--net-localgroup` | `net localgroup` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/net_localgroup) |
|
||||
| `--net-user` | `net user` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/net_user) |
|
||||
| `--nmcli` | `nmcli` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/nmcli) |
|
||||
| `--nsd-control` | `nsd-control` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/nsd_control) |
|
||||
| `--ntpq` | `ntpq -p` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/ntpq) |
|
||||
@@ -272,6 +274,7 @@ option.
|
||||
| `--ps` | `ps` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/ps) |
|
||||
| `--resolve-conf` | `/etc/resolve.conf` file parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/resolve_conf) |
|
||||
| `--route` | `route` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/route) |
|
||||
| `--route-print` | `route print` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/route_print) |
|
||||
| `--rpm-qi` | `rpm -qi` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/rpm_qi) |
|
||||
| `--rsync` | `rsync` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/rsync) |
|
||||
| `--rsync-s` | `rsync` command streaming parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/rsync_s) |
|
||||
@@ -303,6 +306,7 @@ option.
|
||||
| `--top-s` | `top -b` command streaming parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/top_s) |
|
||||
| `--tracepath` | `tracepath` and `tracepath6` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/tracepath) |
|
||||
| `--traceroute` | `traceroute` and `traceroute6` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/traceroute) |
|
||||
| `--traceroute-s` | `traceroute` and `traceroute6` command streaming parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/traceroute_s) |
|
||||
| `--tune2fs` | `tune2fs -l` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/tune2fs) |
|
||||
| `--udevadm` | `udevadm info` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/udevadm) |
|
||||
| `--ufw` | `ufw status` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/ufw) |
|
||||
@@ -322,6 +326,7 @@ option.
|
||||
| `--wg-show` | `wg show` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/wg_show) |
|
||||
| `--who` | `who` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/who) |
|
||||
| `--x509-cert` | X.509 PEM and DER certificate file parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/x509_cert) |
|
||||
| `--x509-crl` | X.509 PEM and DER certificate revocation list file parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/x509_crl) |
|
||||
| `--x509-csr` | X.509 PEM and DER certificate request file parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/x509_csr) |
|
||||
| `--xml` | XML file parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/xml) |
|
||||
| `--xrandr` | `xrandr` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/xrandr) |
|
||||
|
||||
@@ -3,8 +3,8 @@ _jc()
|
||||
local cur prev words cword jc_commands jc_parsers jc_options \
|
||||
jc_about_options jc_about_mod_options jc_help_options jc_special_options
|
||||
|
||||
jc_commands=(acpi airport amixer apt-cache apt-get arp blkid bluetoothctl cbt certbot chage cksum crontab curl date debconf-show df dig dmidecode dpkg du efibootmgr env ethtool file findmnt finger free git gpg hciconfig host id ifconfig iostat ip ipconfig iptables iw iwconfig jobs last lastb ls lsattr lsb_release lsblk lsmod lsof lspci lsusb md5 md5sum mdadm mount mpstat needrestart netstat nmcli nsd-control ntpq os-prober pacman pidstat ping ping6 pip pip3 postconf printenv ps route rpm rsync sfdisk sha1sum sha224sum sha256sum sha384sum sha512sum shasum ss ssh sshd stat sum swapon sysctl systemctl systeminfo timedatectl top tracepath tracepath6 traceroute traceroute6 tune2fs udevadm ufw uname update-alternatives upower uptime vdir veracrypt vmstat w wc wg who xrandr zipinfo zpool)
|
||||
jc_parsers=(--acpi --airport --airport-s --amixer --apt-cache-show --apt-get-sqq --arp --asciitable --asciitable-m --blkid --bluetoothctl --cbt --cef --cef-s --certbot --chage --cksum --clf --clf-s --crontab --crontab-u --csv --csv-s --curl-head --date --datetime-iso --debconf-show --df --dig --dir --dmidecode --dpkg-l --du --efibootmgr --email-address --env --ethtool --file --find --findmnt --finger --free --fstab --git-log --git-log-s --git-ls-remote --gpg --group --gshadow --hash --hashsum --hciconfig --history --host --hosts --http-headers --id --ifconfig --ini --ini-dup --iostat --iostat-s --ip-address --ipconfig --iptables --ip-route --iw-scan --iwconfig --jar-manifest --jobs --jwt --kv --kv-dup --last --ls --ls-s --lsattr --lsb-release --lsblk --lsmod --lsof --lspci --lsusb --m3u --mdadm --mount --mpstat --mpstat-s --needrestart --netstat --nmcli --nsd-control --ntpq --openvpn --os-prober --os-release --pacman --passwd --path --path-list --pci-ids --pgpass --pidstat --pidstat-s --ping --ping-s --pip-list --pip-show --pkg-index-apk --pkg-index-deb --plist --postconf --proc --proc-buddyinfo --proc-cmdline --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-tcp --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 --resolve-conf --route --rpm-qi --rsync --rsync-s --semver --sfdisk --shadow --srt --ss --ssh-conf --sshd-conf --stat --stat-s --swapon --sysctl --syslog --syslog-s --syslog-bsd --syslog-bsd-s --systemctl --systemctl-lj --systemctl-ls --systemctl-luf --systeminfo --time --timedatectl --timestamp --toml --top --top-s --tracepath --traceroute --tune2fs --udevadm --ufw --ufw-appinfo --uname --update-alt-gs --update-alt-q --upower --uptime --url --ver --veracrypt --vmstat --vmstat-s --w --wc --wg-show --who --x509-cert --x509-csr --xml --xrandr --yaml --zipinfo --zpool-iostat --zpool-status)
|
||||
jc_commands=(acpi airport amixer apt-cache apt-get arp blkid bluetoothctl cbt certbot chage cksum crontab curl date debconf-show df dig dmidecode dpkg du efibootmgr env ethtool file findmnt finger free git gpg hciconfig host id ifconfig iostat ip ipconfig iptables iw iwconfig jobs last lastb ls lsattr lsb_release lsblk lsmod lsof lspci lsusb md5 md5sum mdadm mount mpstat needrestart net netstat nmcli nsd-control ntpq os-prober pacman pidstat ping ping6 pip pip3 postconf printenv ps route rpm rsync sfdisk sha1sum sha224sum sha256sum sha384sum sha512sum shasum ss ssh sshd stat sum swapon sysctl systemctl systeminfo timedatectl top tracepath tracepath6 traceroute traceroute6 tune2fs udevadm ufw uname update-alternatives upower uptime vdir veracrypt vmstat w wc wg who xrandr yay zipinfo zpool)
|
||||
jc_parsers=(--acpi --airport --airport-s --amixer --apt-cache-show --apt-get-sqq --arp --asciitable --asciitable-m --blkid --bluetoothctl --cbt --cef --cef-s --certbot --chage --cksum --clf --clf-s --crontab --crontab-u --csv --csv-s --curl-head --date --datetime-iso --debconf-show --df --dig --dir --dmidecode --dpkg-l --du --efibootmgr --email-address --env --ethtool --file --find --findmnt --finger --free --fstab --git-log --git-log-s --git-ls-remote --gpg --group --gshadow --hash --hashsum --hciconfig --history --host --hosts --http-headers --id --ifconfig --ini --ini-dup --iostat --iostat-s --ip-address --ipconfig --iptables --ip-route --iw-scan --iwconfig --jar-manifest --jobs --jwt --kv --kv-dup --last --ls --ls-s --lsattr --lsb-release --lsblk --lsmod --lsof --lspci --lsusb --m3u --mdadm --mount --mpstat --mpstat-s --needrestart --netstat --net-localgroup --net-user --nmcli --nsd-control --ntpq --openvpn --os-prober --os-release --pacman --passwd --path --path-list --pci-ids --pgpass --pidstat --pidstat-s --ping --ping-s --pip-list --pip-show --pkg-index-apk --pkg-index-deb --plist --postconf --proc --proc-buddyinfo --proc-cmdline --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-tcp --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 --resolve-conf --route --route-print --rpm-qi --rsync --rsync-s --semver --sfdisk --shadow --srt --ss --ssh-conf --sshd-conf --stat --stat-s --swapon --sysctl --syslog --syslog-s --syslog-bsd --syslog-bsd-s --systemctl --systemctl-lj --systemctl-ls --systemctl-luf --systeminfo --time --timedatectl --timestamp --toml --top --top-s --tracepath --traceroute --traceroute-s --tune2fs --udevadm --ufw --ufw-appinfo --uname --update-alt-gs --update-alt-q --upower --uptime --url --ver --veracrypt --vmstat --vmstat-s --w --wc --wg-show --who --x509-cert --x509-crl --x509-csr --xml --xrandr --yaml --zipinfo --zpool-iostat --zpool-status)
|
||||
jc_options=(--force-color -C --debug -d --monochrome -m --meta-out -M --pretty -p --quiet -q --raw -r --slurp -s --unbuffer -u --yaml-out -y)
|
||||
jc_about_options=(--about -a)
|
||||
jc_about_mod_options=(--pretty -p --yaml-out -y --monochrome -m --force-color -C)
|
||||
|
||||
@@ -9,7 +9,7 @@ _jc() {
|
||||
jc_help_options jc_help_options_describe \
|
||||
jc_special_options jc_special_options_describe
|
||||
|
||||
jc_commands=(acpi airport amixer apt-cache apt-get arp blkid bluetoothctl cbt certbot chage cksum crontab curl date debconf-show df dig dmidecode dpkg du efibootmgr env ethtool file findmnt finger free git gpg hciconfig host id ifconfig iostat ip ipconfig iptables iw iwconfig jobs last lastb ls lsattr lsb_release lsblk lsmod lsof lspci lsusb md5 md5sum mdadm mount mpstat needrestart netstat nmcli nsd-control ntpq os-prober pacman pidstat ping ping6 pip pip3 postconf printenv ps route rpm rsync sfdisk sha1sum sha224sum sha256sum sha384sum sha512sum shasum ss ssh sshd stat sum swapon sysctl systemctl systeminfo timedatectl top tracepath tracepath6 traceroute traceroute6 tune2fs udevadm ufw uname update-alternatives upower uptime vdir veracrypt vmstat w wc wg who xrandr zipinfo zpool)
|
||||
jc_commands=(acpi airport amixer apt-cache apt-get arp blkid bluetoothctl cbt certbot chage cksum crontab curl date debconf-show df dig dmidecode dpkg du efibootmgr env ethtool file findmnt finger free git gpg hciconfig host id ifconfig iostat ip ipconfig iptables iw iwconfig jobs last lastb ls lsattr lsb_release lsblk lsmod lsof lspci lsusb md5 md5sum mdadm mount mpstat needrestart net netstat nmcli nsd-control ntpq os-prober pacman pidstat ping ping6 pip pip3 postconf printenv ps route rpm rsync sfdisk sha1sum sha224sum sha256sum sha384sum sha512sum shasum ss ssh sshd stat sum swapon sysctl systemctl systeminfo timedatectl top tracepath tracepath6 traceroute traceroute6 tune2fs udevadm ufw uname update-alternatives upower uptime vdir veracrypt vmstat w wc wg who xrandr yay zipinfo zpool)
|
||||
jc_commands_describe=(
|
||||
'acpi:run "acpi" command with magic syntax.'
|
||||
'airport:run "airport" command with magic syntax.'
|
||||
@@ -68,6 +68,7 @@ _jc() {
|
||||
'mount:run "mount" command with magic syntax.'
|
||||
'mpstat:run "mpstat" command with magic syntax.'
|
||||
'needrestart:run "needrestart" command with magic syntax.'
|
||||
'net:run "net" command with magic syntax.'
|
||||
'netstat:run "netstat" command with magic syntax.'
|
||||
'nmcli:run "nmcli" command with magic syntax.'
|
||||
'nsd-control:run "nsd-control" command with magic syntax.'
|
||||
@@ -122,10 +123,11 @@ _jc() {
|
||||
'wg:run "wg" command with magic syntax.'
|
||||
'who:run "who" command with magic syntax.'
|
||||
'xrandr:run "xrandr" command with magic syntax.'
|
||||
'yay:run "yay" command with magic syntax.'
|
||||
'zipinfo:run "zipinfo" command with magic syntax.'
|
||||
'zpool:run "zpool" command with magic syntax.'
|
||||
)
|
||||
jc_parsers=(--acpi --airport --airport-s --amixer --apt-cache-show --apt-get-sqq --arp --asciitable --asciitable-m --blkid --bluetoothctl --cbt --cef --cef-s --certbot --chage --cksum --clf --clf-s --crontab --crontab-u --csv --csv-s --curl-head --date --datetime-iso --debconf-show --df --dig --dir --dmidecode --dpkg-l --du --efibootmgr --email-address --env --ethtool --file --find --findmnt --finger --free --fstab --git-log --git-log-s --git-ls-remote --gpg --group --gshadow --hash --hashsum --hciconfig --history --host --hosts --http-headers --id --ifconfig --ini --ini-dup --iostat --iostat-s --ip-address --ipconfig --iptables --ip-route --iw-scan --iwconfig --jar-manifest --jobs --jwt --kv --kv-dup --last --ls --ls-s --lsattr --lsb-release --lsblk --lsmod --lsof --lspci --lsusb --m3u --mdadm --mount --mpstat --mpstat-s --needrestart --netstat --nmcli --nsd-control --ntpq --openvpn --os-prober --os-release --pacman --passwd --path --path-list --pci-ids --pgpass --pidstat --pidstat-s --ping --ping-s --pip-list --pip-show --pkg-index-apk --pkg-index-deb --plist --postconf --proc --proc-buddyinfo --proc-cmdline --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-tcp --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 --resolve-conf --route --rpm-qi --rsync --rsync-s --semver --sfdisk --shadow --srt --ss --ssh-conf --sshd-conf --stat --stat-s --swapon --sysctl --syslog --syslog-s --syslog-bsd --syslog-bsd-s --systemctl --systemctl-lj --systemctl-ls --systemctl-luf --systeminfo --time --timedatectl --timestamp --toml --top --top-s --tracepath --traceroute --tune2fs --udevadm --ufw --ufw-appinfo --uname --update-alt-gs --update-alt-q --upower --uptime --url --ver --veracrypt --vmstat --vmstat-s --w --wc --wg-show --who --x509-cert --x509-csr --xml --xrandr --yaml --zipinfo --zpool-iostat --zpool-status)
|
||||
jc_parsers=(--acpi --airport --airport-s --amixer --apt-cache-show --apt-get-sqq --arp --asciitable --asciitable-m --blkid --bluetoothctl --cbt --cef --cef-s --certbot --chage --cksum --clf --clf-s --crontab --crontab-u --csv --csv-s --curl-head --date --datetime-iso --debconf-show --df --dig --dir --dmidecode --dpkg-l --du --efibootmgr --email-address --env --ethtool --file --find --findmnt --finger --free --fstab --git-log --git-log-s --git-ls-remote --gpg --group --gshadow --hash --hashsum --hciconfig --history --host --hosts --http-headers --id --ifconfig --ini --ini-dup --iostat --iostat-s --ip-address --ipconfig --iptables --ip-route --iw-scan --iwconfig --jar-manifest --jobs --jwt --kv --kv-dup --last --ls --ls-s --lsattr --lsb-release --lsblk --lsmod --lsof --lspci --lsusb --m3u --mdadm --mount --mpstat --mpstat-s --needrestart --netstat --net-localgroup --net-user --nmcli --nsd-control --ntpq --openvpn --os-prober --os-release --pacman --passwd --path --path-list --pci-ids --pgpass --pidstat --pidstat-s --ping --ping-s --pip-list --pip-show --pkg-index-apk --pkg-index-deb --plist --postconf --proc --proc-buddyinfo --proc-cmdline --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-tcp --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 --resolve-conf --route --route-print --rpm-qi --rsync --rsync-s --semver --sfdisk --shadow --srt --ss --ssh-conf --sshd-conf --stat --stat-s --swapon --sysctl --syslog --syslog-s --syslog-bsd --syslog-bsd-s --systemctl --systemctl-lj --systemctl-ls --systemctl-luf --systeminfo --time --timedatectl --timestamp --toml --top --top-s --tracepath --traceroute --traceroute-s --tune2fs --udevadm --ufw --ufw-appinfo --uname --update-alt-gs --update-alt-q --upower --uptime --url --ver --veracrypt --vmstat --vmstat-s --w --wc --wg-show --who --x509-cert --x509-crl --x509-csr --xml --xrandr --yaml --zipinfo --zpool-iostat --zpool-status)
|
||||
jc_parsers_describe=(
|
||||
'--acpi:`acpi` command parser'
|
||||
'--airport:`airport -I` command parser'
|
||||
@@ -217,6 +219,8 @@ _jc() {
|
||||
'--mpstat-s:`mpstat` command streaming parser'
|
||||
'--needrestart:`needrestart -b` command parser'
|
||||
'--netstat:`netstat` command parser'
|
||||
'--net-localgroup:`net localgroup` command parser'
|
||||
'--net-user:`net user` command parser'
|
||||
'--nmcli:`nmcli` command parser'
|
||||
'--nsd-control:`nsd-control` command parser'
|
||||
'--ntpq:`ntpq -p` command parser'
|
||||
@@ -294,6 +298,7 @@ _jc() {
|
||||
'--ps:`ps` command parser'
|
||||
'--resolve-conf:`/etc/resolve.conf` file parser'
|
||||
'--route:`route` command parser'
|
||||
'--route-print:`route print` command parser'
|
||||
'--rpm-qi:`rpm -qi` command parser'
|
||||
'--rsync:`rsync` command parser'
|
||||
'--rsync-s:`rsync` command streaming parser'
|
||||
@@ -325,6 +330,7 @@ _jc() {
|
||||
'--top-s:`top -b` command streaming parser'
|
||||
'--tracepath:`tracepath` and `tracepath6` command parser'
|
||||
'--traceroute:`traceroute` and `traceroute6` command parser'
|
||||
'--traceroute-s:`traceroute` and `traceroute6` command streaming parser'
|
||||
'--tune2fs:`tune2fs -l` command parser'
|
||||
'--udevadm:`udevadm info` command parser'
|
||||
'--ufw:`ufw status` command parser'
|
||||
@@ -344,6 +350,7 @@ _jc() {
|
||||
'--wg-show:`wg show` command parser'
|
||||
'--who:`who` command parser'
|
||||
'--x509-cert:X.509 PEM and DER certificate file parser'
|
||||
'--x509-crl:X.509 PEM and DER certificate revocation list file parser'
|
||||
'--x509-csr:X.509 PEM and DER certificate request file parser'
|
||||
'--xml:XML file parser'
|
||||
'--xrandr:`xrandr` command parser'
|
||||
|
||||
12
docs/lib.md
12
docs/lib.md
@@ -36,7 +36,7 @@ returned.
|
||||
|
||||
Parameters:
|
||||
|
||||
documentation: (boolean) include parser docstrings if True
|
||||
documentation: (boolean) include parser docstrings if `True`
|
||||
show_hidden: (boolean) also show parsers marked as hidden
|
||||
in their info metadata.
|
||||
show_deprecated: (boolean) also show parsers marked as
|
||||
@@ -172,17 +172,17 @@ Parameters:
|
||||
variants of the module name.
|
||||
|
||||
A Module object can also be passed
|
||||
directly or via get_parser()
|
||||
directly or via `get_parser()`
|
||||
|
||||
data: (string or data to parse (string or bytes for
|
||||
bytes or standard parsers, iterable of
|
||||
iterable) strings for streaming parsers)
|
||||
|
||||
raw: (boolean) output preprocessed JSON if True
|
||||
raw: (boolean) output preprocessed JSON if `True`
|
||||
|
||||
quiet: (boolean) suppress warning messages if True
|
||||
quiet: (boolean) suppress warning messages if `True`
|
||||
|
||||
ignore_exceptions: (boolean) ignore parsing exceptions if True
|
||||
ignore_exceptions: (boolean) ignore parsing exceptions if `True`
|
||||
(streaming parsers only)
|
||||
|
||||
Returns:
|
||||
@@ -209,7 +209,7 @@ Parameters:
|
||||
variants of the module name as well
|
||||
as a parser module object.
|
||||
|
||||
documentation: (boolean) include parser docstring if True
|
||||
documentation: (boolean) include parser docstring if `True`
|
||||
|
||||
<a id="jc.lib.parser_mod_list"></a>
|
||||
|
||||
|
||||
@@ -69,6 +69,7 @@ a controller and a device but there might be fields corresponding to one entity.
|
||||
"blocked": string,
|
||||
"connected": string,
|
||||
"legacy_pairing": string,
|
||||
"cable_pairing": string,
|
||||
"rssi": int,
|
||||
"txpower": int,
|
||||
"uuids": array,
|
||||
@@ -136,4 +137,4 @@ Compatibility: linux
|
||||
|
||||
Source: [`jc/parsers/bluetoothctl.py`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/bluetoothctl.py)
|
||||
|
||||
Version 1.4 by Jake Ob (iakopap at gmail.com)
|
||||
Version 1.5 by Jake Ob (iakopap at gmail.com)
|
||||
|
||||
81
docs/parsers/net_localgroup.md
Normal file
81
docs/parsers/net_localgroup.md
Normal file
@@ -0,0 +1,81 @@
|
||||
[Home](https://kellyjonbrazil.github.io/jc/)
|
||||
<a id="jc.parsers.net_localgroup"></a>
|
||||
|
||||
# jc.parsers.net_localgroup
|
||||
|
||||
jc - JSON Convert `net localgroup` command output parser
|
||||
|
||||
Usage (cli):
|
||||
|
||||
$ net localgroup | jc --net-localgroup
|
||||
$ net localgroup /domain | jc --net-localgroup
|
||||
$ net localgroup Administrators | jc --net-localgroup
|
||||
$ net localgroup Administrators /domain | jc --net-localgroup
|
||||
|
||||
Usage (module):
|
||||
|
||||
import jc
|
||||
result = jc.parse('net_localgroup', net_localgroup_command_output)
|
||||
|
||||
Schema:
|
||||
|
||||
{
|
||||
"account_origin": string,
|
||||
"domain": string,
|
||||
"comment": string,
|
||||
"groups": [
|
||||
{
|
||||
"name": string
|
||||
"members": [
|
||||
string
|
||||
]
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
Examples:
|
||||
|
||||
$ net localgroup | jc --net-localgroup -p
|
||||
{
|
||||
"account_origin": null,
|
||||
"comment": null,
|
||||
"domain": null,
|
||||
"groups": [
|
||||
{
|
||||
"name": "Administrators",
|
||||
"members": [
|
||||
"Administrator",
|
||||
"Operator",
|
||||
"ansible",
|
||||
"user1"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
<a id="jc.parsers.net_localgroup.parse"></a>
|
||||
|
||||
### parse
|
||||
|
||||
```python
|
||||
def parse(data, raw=False, quiet=False)
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
Parsed dictionary. The raw and processed data structures are the same.
|
||||
|
||||
### Parser Information
|
||||
Compatibility: win32
|
||||
|
||||
Source: [`jc/parsers/net_localgroup.py`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/net_localgroup.py)
|
||||
|
||||
Version 1.0 by joehacksalot (joehacksalot@gmail.com)
|
||||
212
docs/parsers/net_user.md
Normal file
212
docs/parsers/net_user.md
Normal file
@@ -0,0 +1,212 @@
|
||||
[Home](https://kellyjonbrazil.github.io/jc/)
|
||||
<a id="jc.parsers.net_user"></a>
|
||||
|
||||
# jc.parsers.net_user
|
||||
|
||||
jc - JSON Convert `net user` command output parser
|
||||
|
||||
|
||||
Usage (cli):
|
||||
|
||||
$ net users | jc --net-user
|
||||
$ net users /domain | jc --net-user
|
||||
$ net users User1 | jc --net-user
|
||||
$ net users User1 /domain | jc --net-user
|
||||
|
||||
Usage (module):
|
||||
|
||||
import jc
|
||||
result = jc.parse('net_user', net_user_command_output)
|
||||
|
||||
Schema:
|
||||
|
||||
{
|
||||
"domain": string,
|
||||
"account_origin": string,
|
||||
"user_accounts": [
|
||||
{
|
||||
"user_name": string,
|
||||
"full_name": string,
|
||||
"comment": string,
|
||||
"user_comment": string,
|
||||
"country_region_code": string,
|
||||
"account_active": boolean,
|
||||
"account_expires": string,
|
||||
"password_last_set": string,
|
||||
"password_expires": string,
|
||||
"password_changeable": string,
|
||||
"password_required": boolean,
|
||||
"user_may_change_password": boolean,
|
||||
"workstations_allowed": string,
|
||||
"logon_script": string,
|
||||
"user_profile": string,
|
||||
"home_directory": string,
|
||||
"last_logon": string,
|
||||
"logon_hours_allowed": string,
|
||||
"local_group_memberships": [
|
||||
string,
|
||||
],
|
||||
"global_group_memberships": [
|
||||
string,
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
Examples:
|
||||
|
||||
$ net users | jc --net-user -p
|
||||
{
|
||||
"account_origin": "\\\\WIN-SERVER16",
|
||||
"domain": "",
|
||||
"user_accounts": [
|
||||
{
|
||||
"user_name": "Administrator"
|
||||
},
|
||||
{
|
||||
"user_name": "DefaultAccount"
|
||||
},
|
||||
{
|
||||
"user_name": "Guest"
|
||||
},
|
||||
{
|
||||
"user_name": "pentera_BnlLQVnd7p"
|
||||
},
|
||||
{
|
||||
"user_name": "user1"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
$ net users /domain | jc --net-user -p
|
||||
{
|
||||
"account_origin": "\\\\DESKTOP-WIN10-PRO.somecompany.corp",
|
||||
"domain": "somecompany.corp",
|
||||
"user_accounts": [
|
||||
{
|
||||
"user_name": "aaron"
|
||||
},
|
||||
{
|
||||
"user_name": "addison"
|
||||
},
|
||||
{
|
||||
"user_name": "Administrator"
|
||||
},
|
||||
{
|
||||
"user_name": "ansible"
|
||||
},
|
||||
{
|
||||
"user_name": "da"
|
||||
},
|
||||
{
|
||||
"user_name": "DefaultAccount"
|
||||
},
|
||||
{
|
||||
"user_name": "Guest"
|
||||
},
|
||||
{
|
||||
"user_name": "harrison"
|
||||
},
|
||||
{
|
||||
"user_name": "james"
|
||||
},
|
||||
{
|
||||
"user_name": "krbtgt"
|
||||
},
|
||||
{
|
||||
"user_name": "liam"
|
||||
},
|
||||
{
|
||||
"user_name": "localadmin"
|
||||
},
|
||||
{
|
||||
"user_name": "tiffany"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
$ net users Administrator | jc --net-user -p
|
||||
{
|
||||
"domain": "",
|
||||
"user_accounts": [
|
||||
{
|
||||
"account_active": true,
|
||||
"account_expires": "Never",
|
||||
"comment": "Built-in account for administering the computer/domain",
|
||||
"country_region_code": "000 (System Default)",
|
||||
"global_group_memberships": [],
|
||||
"last_logon": "2024-08-23T13:47:11",
|
||||
"local_group_memberships": [
|
||||
"Administrators"
|
||||
],
|
||||
"logon_hours_allowed": "All",
|
||||
"password_changeable": "2021-12-17T11:07:14",
|
||||
"password_expires": "2022-01-27T11:07:14",
|
||||
"password_last_set": "2021-12-16T11:07:14",
|
||||
"password_required": true,
|
||||
"user_may_change_password": true,
|
||||
"user_name": "Administrators",
|
||||
"workstations_allowed": "All"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
$ net users Administrator /domain | jc --net-user -p | jq
|
||||
{
|
||||
"domain": "somecompany.corp",
|
||||
"user_accounts": [
|
||||
{
|
||||
"account_active": true,
|
||||
"account_expires": "Never",
|
||||
"comment": "Built-in account for administering the computer/domain",
|
||||
"country_region_code": "000 (System Default)",
|
||||
"global_group_memberships": [
|
||||
"Domain Admins",
|
||||
"Domain Users",
|
||||
"Group Policy Creator",
|
||||
"Enterprise Admins",
|
||||
"Schema Admins"
|
||||
],
|
||||
"last_logon": "2024-07-17T13:46:12",
|
||||
"local_group_memberships": [
|
||||
"Administrators"
|
||||
],
|
||||
"logon_hours_allowed": "All",
|
||||
"password_changeable": "2023-09-30T11:44:26",
|
||||
"password_expires": "Never",
|
||||
"password_last_set": "2023-09-29T11:44:26",
|
||||
"password_required": true,
|
||||
"user_may_change_password": true,
|
||||
"user_name": "Administrators",
|
||||
"workstations_allowed": "All"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
<a id="jc.parsers.net_user.parse"></a>
|
||||
|
||||
### parse
|
||||
|
||||
```python
|
||||
def parse(data, raw=False, quiet=False)
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
Parsed dictionary. The raw and processed data structures are the same.
|
||||
|
||||
### Parser Information
|
||||
Compatibility: win32
|
||||
|
||||
Source: [`jc/parsers/net_user.py`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/net_user.py)
|
||||
|
||||
Version 1.0 by joehacksalot (joehacksalot@gmail.com)
|
||||
@@ -41,7 +41,8 @@ These are documented below.
|
||||
[
|
||||
{
|
||||
"<key>": string/integer/float, # [0]
|
||||
"team_config": object,
|
||||
"team_config": object/null,
|
||||
"team_port_config": object/null,
|
||||
"dhcp4_option_x": {
|
||||
"name": string,
|
||||
"value": string/integer/float,
|
||||
@@ -171,4 +172,4 @@ Compatibility: linux
|
||||
|
||||
Source: [`jc/parsers/nmcli.py`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/nmcli.py)
|
||||
|
||||
Version 1.1 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
|
||||
@@ -205,4 +205,4 @@ Compatibility: linux, darwin, cygwin, win32, aix, freebsd
|
||||
|
||||
Source: [`jc/parsers/pacman.py`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/pacman.py)
|
||||
|
||||
Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
Version 1.1 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
|
||||
204
docs/parsers/route_print.md
Normal file
204
docs/parsers/route_print.md
Normal file
@@ -0,0 +1,204 @@
|
||||
[Home](https://kellyjonbrazil.github.io/jc/)
|
||||
<a id="jc.parsers.route_print"></a>
|
||||
|
||||
# jc.parsers.route_print
|
||||
|
||||
jc - JSON Convert `route print` command output parser
|
||||
|
||||
See also: the `route` command parser
|
||||
|
||||
Usage (cli):
|
||||
|
||||
$ route print | jc --route-print
|
||||
|
||||
Usage (module):
|
||||
|
||||
import jc
|
||||
result = jc.parse('route_print', route_print_command_output)
|
||||
|
||||
Schema:
|
||||
|
||||
{
|
||||
"interface_list": [
|
||||
{
|
||||
"interface_index": integer,
|
||||
"mac_address": string,
|
||||
"description": string
|
||||
}
|
||||
],
|
||||
"ipv4_route_table": {
|
||||
"active_routes": [
|
||||
{
|
||||
"network_destination": string,
|
||||
"netmask": string,
|
||||
"gateway": string,
|
||||
"interface": string,
|
||||
"metric": integer, # [0]
|
||||
"metric_set_to_default": boolean # [1]
|
||||
}
|
||||
],
|
||||
"persistent_routes": [
|
||||
{
|
||||
"network_address": string,
|
||||
"netmask": string,
|
||||
"gateway_address": string,
|
||||
"metric": integer # [0]
|
||||
"metric_set_to_default": boolean # [1]
|
||||
}
|
||||
]
|
||||
},
|
||||
"ipv6_route_table": {
|
||||
"active_routes": [
|
||||
{
|
||||
"interface": integer,
|
||||
"metric": integer, # [0]
|
||||
"metric_set_to_default": boolean, # [1]
|
||||
"network_destination": string,
|
||||
"gateway": string
|
||||
}
|
||||
],
|
||||
"persistent_routes": [
|
||||
{
|
||||
"interface": integer,
|
||||
"metric": integer, # [0]
|
||||
"metric_set_to_default": boolean, # [1]
|
||||
"network_destination": string,
|
||||
"gateway": string
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
[0] Null/None if "metric" = "Default"
|
||||
[1] True if "metric" = "Default"
|
||||
|
||||
Examples:
|
||||
|
||||
$ route print | jc --route-print -p
|
||||
{
|
||||
"interface_list": [
|
||||
{
|
||||
"interface_index": 28,
|
||||
"mac_address": null,
|
||||
"description": "Tailscale Tunnel"
|
||||
},
|
||||
{
|
||||
"interface_index": 12,
|
||||
"mac_address": "00:1c:42:da:01:6a",
|
||||
"description": "Parallels VirtIO Ethernet Adapter"
|
||||
},
|
||||
{
|
||||
"interface_index": 1,
|
||||
"mac_address": null,
|
||||
"description": "Software Loopback Interface 1"
|
||||
}
|
||||
],
|
||||
"ipv4_route_table": {
|
||||
"active_routes": [
|
||||
{
|
||||
"network_destination": "0.0.0.0",
|
||||
"netmask": "0.0.0.0",
|
||||
"gateway": "10.211.55.1",
|
||||
"interface": "10.211.55.3",
|
||||
"metric": 15,
|
||||
"metric_set_to_default": false
|
||||
},
|
||||
{
|
||||
"network_destination": "10.0.0.0",
|
||||
"netmask": "255.0.0.0",
|
||||
"gateway": "192.168.22.1",
|
||||
"interface": "10.211.55.3",
|
||||
"metric": 16,
|
||||
"metric_set_to_default": false
|
||||
},
|
||||
...
|
||||
{
|
||||
"network_destination": "255.255.255.255",
|
||||
"netmask": "255.255.255.255",
|
||||
"gateway": "On-link",
|
||||
"interface": "10.211.55.3",
|
||||
"metric": null,
|
||||
"metric_set_to_default": true
|
||||
}
|
||||
],
|
||||
"persistent_routes": [
|
||||
{
|
||||
"network_address": "10.0.1.0",
|
||||
"netmask": "255.255.255.0",
|
||||
"gateway_address": "192.168.22.1",
|
||||
"metric": 1,
|
||||
"metric_set_to_default": false
|
||||
},
|
||||
{
|
||||
"network_address": "10.0.3.0",
|
||||
"netmask": "255.255.255.0",
|
||||
"gateway_address": "192.168.22.1",
|
||||
"metric": 1,
|
||||
"metric_set_to_default": false
|
||||
},
|
||||
...
|
||||
]
|
||||
},
|
||||
"ipv6_route_table": {
|
||||
"active_routes": [
|
||||
{
|
||||
"interface": 1,
|
||||
"metric": 331,
|
||||
"network_destination": "::1/128",
|
||||
"gateway": "On-link",
|
||||
"metric_set_to_default": false
|
||||
},
|
||||
{
|
||||
"interface": 12,
|
||||
"metric": 271,
|
||||
"network_destination": "2001:db8::/64",
|
||||
"gateway": "fe80::1",
|
||||
"metric_set_to_default": false
|
||||
},
|
||||
...
|
||||
{
|
||||
"interface": 12,
|
||||
"metric": 271,
|
||||
"network_destination": "ff00::/8",
|
||||
"gateway": "On-link",
|
||||
"metric_set_to_default": false
|
||||
}
|
||||
],
|
||||
"persistent_routes": [
|
||||
{
|
||||
"interface": 0,
|
||||
"metric": 4294967295,
|
||||
"network_destination": "2001:db8::/64",
|
||||
"gateway": "fe80::1",
|
||||
"metric_set_to_default": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
<a id="jc.parsers.route_print.parse"></a>
|
||||
|
||||
### parse
|
||||
|
||||
```python
|
||||
def parse(data, raw=False, quiet=False)
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
Parsed dictionary. The raw and processed data structures are the same.
|
||||
|
||||
### Parser Information
|
||||
Compatibility: win32
|
||||
|
||||
Source: [`jc/parsers/route_print.py`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/route_print.py)
|
||||
|
||||
Version 1.0 by joehacksalot (joehacksalot@gmail.com)
|
||||
@@ -50,23 +50,31 @@ All `-` values are converted to `null`
|
||||
"cpu_hardware": float,
|
||||
"cpu_software": float,
|
||||
"cpu_steal": float,
|
||||
"mem_total": float, # [0]
|
||||
"mem_free": float, # [0]
|
||||
"mem_used": float, # [0]
|
||||
"mem_buff_cache": float, # [0]
|
||||
"swap_total": float, # [0]
|
||||
"swap_free": float, # [0]
|
||||
"swap_used": float, # [0]
|
||||
"mem_available": float, # [0]
|
||||
"mem_unit": string,
|
||||
"mem_total": float,
|
||||
"mem_free": float,
|
||||
"mem_used": float,
|
||||
"mem_buff_cache": float,
|
||||
"swap_unit": string,
|
||||
"swap_total": float,
|
||||
"swap_free": float,
|
||||
"swap_used": float,
|
||||
"mem_available": float,
|
||||
"processes": [
|
||||
{
|
||||
"pid": integer,
|
||||
"user": string,
|
||||
"priority": integer,
|
||||
"nice": integer,
|
||||
"virtual_mem": float, # [1]
|
||||
"resident_mem": float, # [1]
|
||||
"shared_mem": float, # [1]
|
||||
"virtual_mem": float,
|
||||
"virtual_mem_bytes": integer,
|
||||
"virtual_mem_unit": string,
|
||||
"resident_mem": float,
|
||||
"resident_mem_bytes": integer,
|
||||
"resident_mem_unit": string,
|
||||
"shared_mem": float,
|
||||
"shared_mem_bytes": integer,
|
||||
"shared_mem_unit": string,
|
||||
"status": string,
|
||||
"percent_cpu": float,
|
||||
"percent_mem": float,
|
||||
@@ -87,9 +95,15 @@ All `-` values are converted to `null`
|
||||
"thread_count": integer,
|
||||
"last_used_processor": integer,
|
||||
"time": string,
|
||||
"swap": float, # [1]
|
||||
"code": float, # [1]
|
||||
"data": float, # [1]
|
||||
"swap": float,
|
||||
"swap_bytes": integer,
|
||||
"swap_unit": string,
|
||||
"code": float,
|
||||
"code_bytes": integer,
|
||||
"code_unit": string,
|
||||
"data": float,
|
||||
"data_bytes": integer,
|
||||
"data_unit": string,
|
||||
"major_page_fault_count": integer,
|
||||
"minor_page_fault_count": integer,
|
||||
"dirty_pages_count": integer,
|
||||
@@ -108,7 +122,9 @@ All `-` values are converted to `null`
|
||||
]
|
||||
"major_page_fault_count_delta": integer,
|
||||
"minor_page_fault_count_delta": integer,
|
||||
"used": float, # [1]
|
||||
"used": float,
|
||||
"used_bytes": integer,
|
||||
"used_unit": string,
|
||||
"ipc_namespace_inode": integer,
|
||||
"mount_namespace_inode": integer,
|
||||
"net_namespace_inode": integer,
|
||||
@@ -129,9 +145,6 @@ All `-` values are converted to `null`
|
||||
}
|
||||
]
|
||||
|
||||
[0] Values are in the units output by `top`
|
||||
[1] Unit suffix stripped during float conversion
|
||||
|
||||
Examples:
|
||||
|
||||
$ top -b -n 3 | jc --top -p
|
||||
@@ -338,4 +351,4 @@ Compatibility: linux
|
||||
|
||||
Source: [`jc/parsers/top.py`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/top.py)
|
||||
|
||||
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
|
||||
@@ -48,23 +48,39 @@ Schema:
|
||||
"cpu_hardware": float,
|
||||
"cpu_software": float,
|
||||
"cpu_steal": float,
|
||||
"mem_total": float, # [0]
|
||||
"mem_free": float, # [0]
|
||||
"mem_used": float, # [0]
|
||||
"mem_buff_cache": float, # [0]
|
||||
"swap_total": float, # [0]
|
||||
"swap_free": float, # [0]
|
||||
"swap_used": float, # [0]
|
||||
"mem_available": float, # [0]
|
||||
"mem_unit": string,
|
||||
"swap_unit": string,
|
||||
"mem_total": float,
|
||||
"mem_total_bytes": integer,
|
||||
"mem_free": float,
|
||||
"mem_free_bytes": integer,
|
||||
"mem_used": float,
|
||||
"mem_used_bytes": integer,
|
||||
"mem_buff_cache": float,
|
||||
"mem_buff_cache_bytes": integer,
|
||||
"swap_total": float,
|
||||
"swap_total_bytes": integer,
|
||||
"swap_free": float,
|
||||
"swap_free_bytes": integer,
|
||||
"swap_used": float,
|
||||
"swap_used_bytes": integer,
|
||||
"mem_available": float,
|
||||
"mem_available_bytes": integer,
|
||||
"processes": [
|
||||
{
|
||||
"pid": integer,
|
||||
"user": string,
|
||||
"priority": integer,
|
||||
"nice": integer,
|
||||
"virtual_mem": float, # [1]
|
||||
"resident_mem": float, # [1]
|
||||
"shared_mem": float, # [1]
|
||||
"virtual_mem": float,
|
||||
"virtual_mem_unit": string,
|
||||
"virtual_mem_bytes": integer,
|
||||
"resident_mem": float,
|
||||
"resident_mem_unit": string,
|
||||
"resident_mem_bytes": integer,
|
||||
"shared_mem": float,
|
||||
"shared_mem_unit": string,
|
||||
"shared_mem_bytes": integer,
|
||||
"status": string,
|
||||
"percent_cpu": float,
|
||||
"percent_mem": float,
|
||||
@@ -85,9 +101,15 @@ Schema:
|
||||
"thread_count": integer,
|
||||
"last_used_processor": integer,
|
||||
"time": string,
|
||||
"swap": float, # [1]
|
||||
"code": float, # [1]
|
||||
"data": float, # [1]
|
||||
"swap": float,
|
||||
"swap_unit": string,
|
||||
"swap_bytes": integer,
|
||||
"code": float,
|
||||
"code_unit": string,
|
||||
"code_bytes": integer
|
||||
"data": float,
|
||||
"data_unit": string,
|
||||
"data_bytes": integer,
|
||||
"major_page_fault_count": integer,
|
||||
"minor_page_fault_count": integer,
|
||||
"dirty_pages_count": integer,
|
||||
@@ -106,7 +128,9 @@ Schema:
|
||||
]
|
||||
"major_page_fault_count_delta": integer,
|
||||
"minor_page_fault_count_delta": integer,
|
||||
"used": float, # [1]
|
||||
"used": float,
|
||||
"used_unit": string,
|
||||
"used_bytes": integer,
|
||||
"ipc_namespace_inode": integer,
|
||||
"mount_namespace_inode": integer,
|
||||
"net_namespace_inode": integer,
|
||||
@@ -133,9 +157,6 @@ Schema:
|
||||
}
|
||||
}
|
||||
|
||||
[0] Values are in the units output by `top`
|
||||
[1] Unit suffix stripped during float conversion
|
||||
|
||||
Examples:
|
||||
|
||||
$ top -b | jc --top-s
|
||||
@@ -178,4 +199,4 @@ Compatibility: linux
|
||||
|
||||
Source: [`jc/parsers/top_s.py`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/top_s.py)
|
||||
|
||||
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
|
||||
@@ -32,6 +32,8 @@ Schema:
|
||||
{
|
||||
"destination_ip": string,
|
||||
"destination_name": string,
|
||||
"max_hops": integer,
|
||||
"data_bytes": integer,
|
||||
"hops": [
|
||||
{
|
||||
"hop": integer,
|
||||
@@ -54,6 +56,8 @@ Examples:
|
||||
{
|
||||
"destination_ip": "216.58.194.46",
|
||||
"destination_name": "google.com",
|
||||
"max_hops": 64,
|
||||
"data_bytes": 50,
|
||||
"hops": [
|
||||
{
|
||||
"hop": 1,
|
||||
@@ -89,6 +93,8 @@ Examples:
|
||||
{
|
||||
"destination_ip": "216.58.194.46",
|
||||
"destination_name": "google.com",
|
||||
"max_hops": "64",
|
||||
"data_bytes": "50",
|
||||
"hops": [
|
||||
{
|
||||
"hop": "1",
|
||||
@@ -145,4 +151,4 @@ Compatibility: linux, darwin, freebsd
|
||||
|
||||
Source: [`jc/parsers/traceroute.py`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/traceroute.py)
|
||||
|
||||
Version 1.8 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
Version 1.9 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
|
||||
167
docs/parsers/traceroute_s.md
Normal file
167
docs/parsers/traceroute_s.md
Normal file
@@ -0,0 +1,167 @@
|
||||
[Home](https://kellyjonbrazil.github.io/jc/)
|
||||
<a id="jc.parsers.traceroute_s"></a>
|
||||
|
||||
# jc.parsers.traceroute_s
|
||||
|
||||
jc - JSON Convert `traceroute` command output streaming parser
|
||||
|
||||
> This streaming parser outputs JSON Lines (cli) or returns an Iterable of
|
||||
> Dictionaries (module)
|
||||
|
||||
Supports `traceroute` and `traceroute6` output.
|
||||
|
||||
> Note: On some operating systems you will need to redirect `STDERR` to
|
||||
> `STDOUT` for destination info since the header line is sent to
|
||||
> `STDERR`. A warning message will be printed to `STDERR` if the
|
||||
> header row is not found.
|
||||
>
|
||||
> e.g. `$ traceroute 8.8.8.8 2>&1 | jc --traceroute-s`
|
||||
|
||||
Usage (cli):
|
||||
|
||||
$ traceroute 1.2.3.4 | jc --traceroute-s
|
||||
|
||||
Usage (module):
|
||||
|
||||
import jc
|
||||
result = jc.parse('traceroute_s', traceroute_command_output.splitlines())
|
||||
for item in result:
|
||||
# do something
|
||||
|
||||
Schema:
|
||||
|
||||
{
|
||||
# 'header' or 'hop'
|
||||
"type": string,
|
||||
|
||||
# 'header' type has the fields below:
|
||||
"destination_ip": string,
|
||||
"destination_name": string,
|
||||
"max_hops": integer,
|
||||
"data_bytes": integer,
|
||||
|
||||
# 'hop' type has the fields below:
|
||||
"hop": integer,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": string,
|
||||
"asn": integer,
|
||||
"ip": string,
|
||||
"name": string,
|
||||
"rtt": float
|
||||
}
|
||||
]
|
||||
|
||||
# below object only exists if using -qq or ignore_exceptions=True
|
||||
"_jc_meta": {
|
||||
"success": boolean, # false if error parsing
|
||||
"error": string, # exists if "success" is false
|
||||
"line": string # exists if "success" is false
|
||||
}
|
||||
}
|
||||
|
||||
Examples:
|
||||
|
||||
$ traceroute google.com | jc --traceroute-s -p
|
||||
{
|
||||
"type": "header",
|
||||
"destination_ip": "216.58.194.46",
|
||||
"destination_name": "google.com",
|
||||
"max_hops": 30,
|
||||
"data_bytes": 60
|
||||
}
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 1,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "216.230.231.141",
|
||||
"name": "216-230-231-141.static.houston.tx.oplink.net",
|
||||
"rtt": 198.574
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "216.230.231.141",
|
||||
"name": "216-230-231-141.static.houston.tx.oplink.net",
|
||||
"rtt": null
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "216.230.231.141",
|
||||
"name": "216-230-231-141.static.houston.tx.oplink.net",
|
||||
"rtt": 198.65
|
||||
}
|
||||
]
|
||||
}
|
||||
...
|
||||
|
||||
$ traceroute google.com | jc --traceroute-s -p -r
|
||||
{
|
||||
"type": "header",
|
||||
"destination_ip": "216.58.194.46",
|
||||
"destination_name": "google.com",
|
||||
"max_hops": "30",
|
||||
"data_bytes": "60"
|
||||
}
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": "1",
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "216.230.231.141",
|
||||
"name": "216-230-231-141.static.houston.tx.oplink.net",
|
||||
"rtt": "198.574"
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "216.230.231.141",
|
||||
"name": "216-230-231-141.static.houston.tx.oplink.net",
|
||||
"rtt": null
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "216.230.231.141",
|
||||
"name": "216-230-231-141.static.houston.tx.oplink.net",
|
||||
"rtt": "198.650"
|
||||
}
|
||||
]
|
||||
}
|
||||
...
|
||||
|
||||
<a id="jc.parsers.traceroute_s.parse"></a>
|
||||
|
||||
### parse
|
||||
|
||||
```python
|
||||
def parse(data, raw=False, quiet=False, ignore_exceptions=False)
|
||||
```
|
||||
|
||||
Main text parsing function. Returns an iterable object.
|
||||
|
||||
Parameters:
|
||||
|
||||
data: (iterable) line-based text data to parse
|
||||
(e.g. sys.stdin or str.splitlines())
|
||||
|
||||
raw: (boolean) unprocessed output if True
|
||||
quiet: (boolean) suppress warning messages if True
|
||||
ignore_exceptions: (boolean) ignore parsing exceptions if True
|
||||
|
||||
Returns:
|
||||
|
||||
Iterable of Dictionaries
|
||||
|
||||
### Parser Information
|
||||
Compatibility: linux, darwin, freebsd
|
||||
|
||||
Source: [`jc/parsers/traceroute_s.py`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/traceroute_s.py)
|
||||
|
||||
Version 1.0 by Shintaro Kojima (goodies@codeout.net)
|
||||
@@ -30,6 +30,7 @@ Schema:
|
||||
"user": string,
|
||||
"event": string,
|
||||
"writeable_tty": string,
|
||||
"process": string,
|
||||
"tty": string,
|
||||
"time": string,
|
||||
"epoch": integer, # [0]
|
||||
@@ -160,4 +161,4 @@ Compatibility: linux, darwin, cygwin, aix, freebsd
|
||||
|
||||
Source: [`jc/parsers/who.py`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/who.py)
|
||||
|
||||
Version 1.8 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
Version 1.9 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
|
||||
304
docs/parsers/x509_crl.md
Normal file
304
docs/parsers/x509_crl.md
Normal file
@@ -0,0 +1,304 @@
|
||||
[Home](https://kellyjonbrazil.github.io/jc/)
|
||||
<a id="jc.parsers.x509_crl"></a>
|
||||
|
||||
# jc.parsers.x509_crl
|
||||
|
||||
jc - JSON Convert X.509 Certificate Revocation List format file parser
|
||||
|
||||
This parser will convert DER and PEM encoded X.509 certificate revocation
|
||||
list files.
|
||||
|
||||
Usage (cli):
|
||||
|
||||
$ cat certificateRevocationList.pem | jc --x509-crl
|
||||
$ cat certificateRevocationList.der | jc --x509-crl
|
||||
|
||||
Usage (module):
|
||||
|
||||
import jc
|
||||
result = jc.parse('x509_crl', x509_crl_file_output)
|
||||
|
||||
Schema:
|
||||
|
||||
{
|
||||
"tbs_cert_list": {
|
||||
"version": string,
|
||||
"signature": {
|
||||
"algorithm": string,
|
||||
"parameters": string/null
|
||||
},
|
||||
"issuer": {
|
||||
"organization_name": string,
|
||||
"organizational_unit_name": string,
|
||||
"common_name": string
|
||||
},
|
||||
"this_update": integer, # [1]
|
||||
"next_update": integer, # [1]
|
||||
"revoked_certificates": [
|
||||
{
|
||||
"user_certificate": integer,
|
||||
"revocation_date": integer, # [1]
|
||||
"crl_entry_extensions": [
|
||||
{
|
||||
"extn_id": string,
|
||||
"critical": boolean,
|
||||
"extn_value": string,
|
||||
"extn_value_iso": string
|
||||
},
|
||||
"revocation_date_iso": string
|
||||
}
|
||||
],
|
||||
"crl_extensions": [
|
||||
{
|
||||
"extn_id": string,
|
||||
"critical": boolean,
|
||||
"extn_value": array/object/string/integer # [2]
|
||||
}
|
||||
],
|
||||
"this_update_iso": string,
|
||||
"next_update_iso": string
|
||||
},
|
||||
"signature_algorithm": {
|
||||
"algorithm": string,
|
||||
"parameters": string/null
|
||||
},
|
||||
"signature": string # [0]
|
||||
}
|
||||
|
||||
[0] in colon-delimited hex notation
|
||||
[1] time-zone-aware (UTC) epoch timestamp
|
||||
[2] See below for well-known Extension schemas:
|
||||
|
||||
Basic Constraints:
|
||||
{
|
||||
"extn_id": "basic_constraints",
|
||||
"critical": boolean,
|
||||
"extn_value": {
|
||||
"ca": boolean,
|
||||
"path_len_constraint": string/null
|
||||
}
|
||||
}
|
||||
|
||||
Key Usage:
|
||||
{
|
||||
"extn_id": "key_usage",
|
||||
"critical": boolean,
|
||||
"extn_value": [
|
||||
string
|
||||
]
|
||||
}
|
||||
|
||||
Key Identifier:
|
||||
{
|
||||
"extn_id": "key_identifier",
|
||||
"critical": boolean,
|
||||
"extn_value": string # [0]
|
||||
}
|
||||
|
||||
Authority Key Identifier:
|
||||
{
|
||||
"extn_id": "authority_key_identifier",
|
||||
"critical": boolean,
|
||||
"extn_value": {
|
||||
"key_identifier": string, # [0]
|
||||
"authority_cert_issuer": string/null,
|
||||
"authority_cert_serial_number": string/null
|
||||
}
|
||||
}
|
||||
|
||||
Subject Alternative Name:
|
||||
{
|
||||
"extn_id": "subject_alt_name",
|
||||
"critical": boolean,
|
||||
"extn_value": [
|
||||
string
|
||||
]
|
||||
}
|
||||
|
||||
Certificate Policies:
|
||||
{
|
||||
"extn_id": "certificate_policies",
|
||||
"critical": boolean,
|
||||
"extn_value": [
|
||||
{
|
||||
"policy_identifier": string,
|
||||
"policy_qualifiers": [ array or null
|
||||
{
|
||||
"policy_qualifier_id": string,
|
||||
"qualifier": string
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Signed Certificate Timestamp List:
|
||||
{
|
||||
"extn_id": "signed_certificate_timestamp_list",
|
||||
"critical": boolean,
|
||||
"extn_value": string # [0]
|
||||
}
|
||||
|
||||
Examples:
|
||||
|
||||
$ cat sample-crl.pem | jc --x509-crl -p
|
||||
{
|
||||
"tbs_cert_list": {
|
||||
"version": "v2",
|
||||
"signature": {
|
||||
"algorithm": "sha1_rsa",
|
||||
"parameters": null
|
||||
},
|
||||
"issuer": {
|
||||
"organization_name": "Sample Signer Organization",
|
||||
"organizational_unit_name": "Sample Signer Unit",
|
||||
"common_name": "Sample Signer Cert"
|
||||
},
|
||||
"this_update": 1361183520,
|
||||
"next_update": 1361184120,
|
||||
"revoked_certificates": [
|
||||
{
|
||||
"user_certificate": 1341767,
|
||||
"revocation_date": 1361182932,
|
||||
"crl_entry_extensions": [
|
||||
{
|
||||
"extn_id": "crl_reason",
|
||||
"critical": false,
|
||||
"extn_value": "affiliation_changed"
|
||||
},
|
||||
{
|
||||
"extn_id": "invalidity_date",
|
||||
"critical": false,
|
||||
"extn_value": 1361182920,
|
||||
"extn_value_iso": "2013-02-18T10:22:00+00:00"
|
||||
}
|
||||
],
|
||||
"revocation_date_iso": "2013-02-18T10:22:12+00:00"
|
||||
},
|
||||
{
|
||||
"user_certificate": 1341768,
|
||||
"revocation_date": 1361182942,
|
||||
"crl_entry_extensions": [
|
||||
{
|
||||
"extn_id": "crl_reason",
|
||||
"critical": false,
|
||||
"extn_value": "certificate_hold"
|
||||
},
|
||||
{
|
||||
"extn_id": "invalidity_date",
|
||||
"critical": false,
|
||||
"extn_value": 1361182920,
|
||||
"extn_value_iso": "2013-02-18T10:22:00+00:00"
|
||||
}
|
||||
],
|
||||
"revocation_date_iso": "2013-02-18T10:22:22+00:00"
|
||||
},
|
||||
{
|
||||
"user_certificate": 1341769,
|
||||
"revocation_date": 1361182952,
|
||||
"crl_entry_extensions": [
|
||||
{
|
||||
"extn_id": "crl_reason",
|
||||
"critical": false,
|
||||
"extn_value": "superseded"
|
||||
},
|
||||
{
|
||||
"extn_id": "invalidity_date",
|
||||
"critical": false,
|
||||
"extn_value": 1361182920,
|
||||
"extn_value_iso": "2013-02-18T10:22:00+00:00"
|
||||
}
|
||||
],
|
||||
"revocation_date_iso": "2013-02-18T10:22:32+00:00"
|
||||
},
|
||||
{
|
||||
"user_certificate": 1341770,
|
||||
"revocation_date": 1361182962,
|
||||
"crl_entry_extensions": [
|
||||
{
|
||||
"extn_id": "crl_reason",
|
||||
"critical": false,
|
||||
"extn_value": "key_compromise"
|
||||
},
|
||||
{
|
||||
"extn_id": "invalidity_date",
|
||||
"critical": false,
|
||||
"extn_value": 1361182920,
|
||||
"extn_value_iso": "2013-02-18T10:22:00+00:00"
|
||||
}
|
||||
],
|
||||
"revocation_date_iso": "2013-02-18T10:22:42+00:00"
|
||||
},
|
||||
{
|
||||
"user_certificate": 1341771,
|
||||
"revocation_date": 1361182971,
|
||||
"crl_entry_extensions": [
|
||||
{
|
||||
"extn_id": "crl_reason",
|
||||
"critical": false,
|
||||
"extn_value": "cessation_of_operation"
|
||||
},
|
||||
{
|
||||
"extn_id": "invalidity_date",
|
||||
"critical": false,
|
||||
"extn_value": 1361182920,
|
||||
"extn_value_iso": "2013-02-18T10:22:00+00:00"
|
||||
}
|
||||
],
|
||||
"revocation_date_iso": "2013-02-18T10:22:51+00:00"
|
||||
}
|
||||
],
|
||||
"crl_extensions": [
|
||||
{
|
||||
"extn_id": "authority_key_identifier",
|
||||
"critical": false,
|
||||
"extn_value": {
|
||||
"key_identifier": "be:12:01:cc:aa:ea:11:80:da:2e:ad:b2...",
|
||||
"authority_cert_issuer": null,
|
||||
"authority_cert_serial_number": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"extn_id": "crl_number",
|
||||
"critical": false,
|
||||
"extn_value": 3
|
||||
}
|
||||
],
|
||||
"this_update_iso": "2013-02-18T10:32:00+00:00",
|
||||
"next_update_iso": "2013-02-18T10:42:00+00:00"
|
||||
},
|
||||
"signature_algorithm": {
|
||||
"algorithm": "sha1_rsa",
|
||||
"parameters": null
|
||||
},
|
||||
"signature": "42:21:be:81:f1:c3:79:76:66:5b:ce:21:13:8a:68:a..."
|
||||
}
|
||||
|
||||
<a id="jc.parsers.x509_crl.parse"></a>
|
||||
|
||||
### parse
|
||||
|
||||
```python
|
||||
def parse(data: Union[str, bytes],
|
||||
raw: bool = False,
|
||||
quiet: bool = False) -> Dict
|
||||
```
|
||||
|
||||
Main text parsing function
|
||||
|
||||
Parameters:
|
||||
|
||||
data: (string or bytes) text or binary data to parse
|
||||
raw: (boolean) unprocessed output if True
|
||||
quiet: (boolean) suppress warning messages if True
|
||||
|
||||
Returns:
|
||||
|
||||
Dictionary. Raw or processed structured data.
|
||||
|
||||
### Parser Information
|
||||
Compatibility: linux, darwin, cygwin, win32, aix, freebsd
|
||||
|
||||
Source: [`jc/parsers/x509_crl.py`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/x509_crl.py)
|
||||
|
||||
Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
@@ -23,8 +23,9 @@ jc - JSON Convert streaming utils
|
||||
def add_jc_meta(func: ~F) -> ~F
|
||||
```
|
||||
|
||||
Decorator for streaming parsers to add stream_success and stream_error
|
||||
objects. This simplifies the yield lines in the streaming parsers.
|
||||
Decorator for streaming parsers to add `stream_success` and
|
||||
`stream_error` objects. This simplifies the `yield` lines in the
|
||||
streaming parsers.
|
||||
|
||||
With the decorator on parse():
|
||||
|
||||
@@ -58,7 +59,7 @@ In all cases above:
|
||||
successfully parse.
|
||||
|
||||
ignore_exceptions: (bool) continue processing lines and ignore
|
||||
exceptions if True.
|
||||
exceptions if `True`.
|
||||
|
||||
<a id="jc.streaming.raise_or_yield"></a>
|
||||
|
||||
@@ -69,8 +70,8 @@ def raise_or_yield(ignore_exceptions: bool, e: BaseException,
|
||||
line: str) -> Tuple[BaseException, str]
|
||||
```
|
||||
|
||||
Return the exception object and line string if ignore_exceptions is
|
||||
True. Otherwise, re-raise the exception from the exception object with
|
||||
Return the exception object and line string if `ignore_exceptions` is
|
||||
`True`. Otherwise, re-raise the exception from the exception object with
|
||||
an annotation.
|
||||
|
||||
<a id="jc.streaming.stream_error"></a>
|
||||
|
||||
@@ -44,7 +44,7 @@ Parameters:
|
||||
the parser. compatible options:
|
||||
linux, darwin, cygwin, win32, aix, freebsd
|
||||
|
||||
quiet: (bool) suppress compatibility message if True
|
||||
quiet: (bool) suppress compatibility message if `True`
|
||||
|
||||
Returns:
|
||||
|
||||
@@ -181,7 +181,7 @@ Parameters:
|
||||
|
||||
Returns:
|
||||
|
||||
None - just prints output to STDERR
|
||||
None - just prints output to `STDERR`
|
||||
|
||||
<a id="jc.utils.has_data"></a>
|
||||
|
||||
@@ -194,7 +194,7 @@ def has_data(data: Union[str, bytes]) -> bool
|
||||
Checks if the string input contains data. If there are any
|
||||
non-whitespace characters then return `True`, else return `False`.
|
||||
|
||||
For bytes, returns True if there is any data.
|
||||
For bytes, returns `True` if there is any data.
|
||||
|
||||
Parameters:
|
||||
|
||||
@@ -202,9 +202,9 @@ Parameters:
|
||||
|
||||
Returns:
|
||||
|
||||
Boolean True if input string (data) contains non-whitespace
|
||||
characters, otherwise False. For bytes data, returns
|
||||
True if there is any data, otherwise False.
|
||||
Boolean `True` if input string (data) contains non-whitespace
|
||||
characters, otherwise `False`. For bytes data, returns
|
||||
`True` if there is any data, otherwise `False`.
|
||||
|
||||
<a id="jc.utils.input_type_check"></a>
|
||||
|
||||
|
||||
16
jc/cli.py
16
jc/cli.py
@@ -300,8 +300,8 @@ class JcCli():
|
||||
Pages the parser documentation if a parser is found in the arguments,
|
||||
otherwise the general help text is printed.
|
||||
"""
|
||||
self.indent = 4
|
||||
self.pad = 22
|
||||
self.indent = 2
|
||||
self.pad = 21
|
||||
|
||||
if self.show_categories:
|
||||
utils._safe_print(self.parser_categories_text())
|
||||
@@ -569,7 +569,11 @@ class JcCli():
|
||||
if self.debug:
|
||||
raise
|
||||
|
||||
error_msg = os.strerror(e.errno)
|
||||
if e.errno:
|
||||
error_msg = os.strerror(e.errno)
|
||||
else:
|
||||
error_msg = "no further information provided"
|
||||
|
||||
utils.error_message([
|
||||
f'"{file}" file could not be opened: {error_msg}.'
|
||||
])
|
||||
@@ -594,7 +598,11 @@ class JcCli():
|
||||
if self.debug:
|
||||
raise
|
||||
|
||||
error_msg = os.strerror(e.errno)
|
||||
if e.errno:
|
||||
error_msg = os.strerror(e.errno)
|
||||
else:
|
||||
error_msg = "no further information provided"
|
||||
|
||||
utils.error_message([
|
||||
f'"{self.magic_run_command_str}" command could not be run: {error_msg}.'
|
||||
])
|
||||
|
||||
@@ -62,52 +62,52 @@ jc converts the output of many commands, file-types, and strings to JSON or YAML
|
||||
|
||||
Usage:
|
||||
|
||||
Standard syntax:
|
||||
Standard syntax:
|
||||
|
||||
COMMAND | jc [SLICE] [OPTIONS] PARSER
|
||||
COMMAND | jc [SLICE] [OPTIONS] PARSER
|
||||
|
||||
cat FILE | jc [SLICE] [OPTIONS] PARSER
|
||||
cat FILE | jc [SLICE] [OPTIONS] PARSER
|
||||
|
||||
echo STRING | jc [SLICE] [OPTIONS] PARSER
|
||||
echo STRING | jc [SLICE] [OPTIONS] PARSER
|
||||
|
||||
Magic syntax:
|
||||
Magic syntax:
|
||||
|
||||
jc [SLICE] [OPTIONS] COMMAND
|
||||
jc [SLICE] [OPTIONS] COMMAND
|
||||
|
||||
jc [SLICE] [OPTIONS] /proc/<path-to-procfile>
|
||||
jc [SLICE] [OPTIONS] /proc/<path-to-procfile>
|
||||
|
||||
Parsers:
|
||||
'''
|
||||
|
||||
slicetext_string: str = '''\
|
||||
Slice:
|
||||
[start]:[end]
|
||||
[start]:[end]
|
||||
|
||||
start: [[-]index] - Zero-based start line, negative index for
|
||||
counting from the end
|
||||
start: [[-]index] - Zero-based start line, negative index for
|
||||
counting from the end
|
||||
|
||||
end: [[-]index] - Zero-based end line (excluding the index),
|
||||
negative index for counting from the end
|
||||
end: [[-]index] - Zero-based end line (excluding the index),
|
||||
negative index for counting from the end
|
||||
'''
|
||||
|
||||
helptext_end_string: str = '''\
|
||||
Examples:
|
||||
Standard Syntax:
|
||||
$ dig www.google.com | jc --pretty --dig
|
||||
$ cat /proc/meminfo | jc --pretty --proc
|
||||
Standard Syntax:
|
||||
$ dig www.google.com | jc --pretty --dig
|
||||
$ cat /proc/meminfo | jc --pretty --proc
|
||||
|
||||
Magic Syntax:
|
||||
$ jc --pretty dig www.google.com
|
||||
$ jc --pretty /proc/meminfo
|
||||
Magic Syntax:
|
||||
$ jc --pretty dig www.google.com
|
||||
$ jc --pretty /proc/meminfo
|
||||
|
||||
Line Slicing:
|
||||
$ cat output.txt | jc 4:15 --parser # Parse from line 4 to 14
|
||||
with parser (zero-based)
|
||||
Line Slicing:
|
||||
$ cat output.txt | jc 4:15 --<PARSER> # Parse from line 4 to 14
|
||||
# with <PARSER> (zero-based)
|
||||
|
||||
Parser Documentation:
|
||||
$ jc --help --dig
|
||||
Parser Documentation:
|
||||
$ jc --help --dig
|
||||
|
||||
More Help:
|
||||
$ jc -hh # show hidden parsers
|
||||
$ jc -hhh # list parsers by category tags
|
||||
More Help:
|
||||
$ jc -hh # show hidden parsers
|
||||
$ jc -hhh # list parsers by category tags
|
||||
'''
|
||||
29
jc/lib.py
29
jc/lib.py
@@ -10,7 +10,7 @@ from jc import appdirs
|
||||
from jc import utils
|
||||
|
||||
|
||||
__version__ = '1.25.5'
|
||||
__version__ = '1.25.7'
|
||||
|
||||
parsers: List[str] = [
|
||||
'acpi',
|
||||
@@ -103,6 +103,8 @@ parsers: List[str] = [
|
||||
'mpstat-s',
|
||||
'needrestart',
|
||||
'netstat',
|
||||
'net-localgroup',
|
||||
'net-user',
|
||||
'nmcli',
|
||||
'nsd-control',
|
||||
'ntpq',
|
||||
@@ -180,6 +182,7 @@ parsers: List[str] = [
|
||||
'ps',
|
||||
'resolve-conf',
|
||||
'route',
|
||||
'route-print',
|
||||
'rpm-qi',
|
||||
'rsync',
|
||||
'rsync-s',
|
||||
@@ -211,7 +214,9 @@ parsers: List[str] = [
|
||||
'top-s',
|
||||
'tracepath',
|
||||
'traceroute',
|
||||
'traceroute-s',
|
||||
'tune2fs',
|
||||
'typeset',
|
||||
'udevadm',
|
||||
'ufw',
|
||||
'ufw-appinfo',
|
||||
@@ -230,6 +235,7 @@ parsers: List[str] = [
|
||||
'wg-show',
|
||||
'who',
|
||||
'x509-cert',
|
||||
'x509-crl',
|
||||
'x509-csr',
|
||||
'xml',
|
||||
'xrandr',
|
||||
@@ -346,7 +352,8 @@ def _get_parser(parser_mod_name: str) -> ModuleType:
|
||||
|
||||
def _parser_is_slurpable(parser: ModuleType) -> bool:
|
||||
"""
|
||||
Returns True if this parser can use the `--slurp` command option, else False
|
||||
Returns `True` if this parser can use the `--slurp` command option, else
|
||||
`False`
|
||||
|
||||
parser is a parser module object.
|
||||
"""
|
||||
@@ -358,7 +365,7 @@ def _parser_is_slurpable(parser: ModuleType) -> bool:
|
||||
|
||||
def _parser_is_streaming(parser: ModuleType) -> bool:
|
||||
"""
|
||||
Returns True if this is a streaming parser, else False
|
||||
Returns `True` if this is a streaming parser, else `False`
|
||||
|
||||
parser is a parser module object.
|
||||
"""
|
||||
@@ -369,7 +376,7 @@ def _parser_is_streaming(parser: ModuleType) -> bool:
|
||||
|
||||
def _parser_is_hidden(parser: ModuleType) -> bool:
|
||||
"""
|
||||
Returns True if this is a hidden parser, else False
|
||||
Returns `True` if this is a hidden parser, else `False`
|
||||
|
||||
parser is a parser module object.
|
||||
"""
|
||||
@@ -380,7 +387,7 @@ def _parser_is_hidden(parser: ModuleType) -> bool:
|
||||
|
||||
def _parser_is_deprecated(parser: ModuleType) -> bool:
|
||||
"""
|
||||
Returns True if this is a deprecated parser, else False
|
||||
Returns `True` if this is a deprecated parser, else `False`
|
||||
|
||||
parser is a parser module object.
|
||||
"""
|
||||
@@ -467,17 +474,17 @@ def parse(
|
||||
variants of the module name.
|
||||
|
||||
A Module object can also be passed
|
||||
directly or via get_parser()
|
||||
directly or via `get_parser()`
|
||||
|
||||
data: (string or data to parse (string or bytes for
|
||||
bytes or standard parsers, iterable of
|
||||
iterable) strings for streaming parsers)
|
||||
|
||||
raw: (boolean) output preprocessed JSON if True
|
||||
raw: (boolean) output preprocessed JSON if `True`
|
||||
|
||||
quiet: (boolean) suppress warning messages if True
|
||||
quiet: (boolean) suppress warning messages if `True`
|
||||
|
||||
ignore_exceptions: (boolean) ignore parsing exceptions if True
|
||||
ignore_exceptions: (boolean) ignore parsing exceptions if `True`
|
||||
(streaming parsers only)
|
||||
|
||||
Returns:
|
||||
@@ -627,7 +634,7 @@ def parser_info(
|
||||
variants of the module name as well
|
||||
as a parser module object.
|
||||
|
||||
documentation: (boolean) include parser docstring if True
|
||||
documentation: (boolean) include parser docstring if `True`
|
||||
"""
|
||||
parser_mod = get_parser(parser_mod_name)
|
||||
parser_mod_name = parser_mod.__name__.split('.')[-1]
|
||||
@@ -664,7 +671,7 @@ def all_parser_info(
|
||||
|
||||
Parameters:
|
||||
|
||||
documentation: (boolean) include parser docstrings if True
|
||||
documentation: (boolean) include parser docstrings if `True`
|
||||
show_hidden: (boolean) also show parsers marked as hidden
|
||||
in their info metadata.
|
||||
show_deprecated: (boolean) also show parsers marked as
|
||||
|
||||
@@ -64,6 +64,7 @@ a controller and a device but there might be fields corresponding to one entity.
|
||||
"blocked": string,
|
||||
"connected": string,
|
||||
"legacy_pairing": string,
|
||||
"cable_pairing": string,
|
||||
"rssi": int,
|
||||
"txpower": int,
|
||||
"uuids": array,
|
||||
@@ -112,7 +113,7 @@ import jc.utils
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.4'
|
||||
version = '1.5'
|
||||
description = '`bluetoothctl` command parser'
|
||||
author = 'Jake Ob'
|
||||
author_email = 'iakopap at gmail.com'
|
||||
@@ -165,6 +166,7 @@ try:
|
||||
"blocked": str,
|
||||
"connected": str,
|
||||
"legacy_pairing": str,
|
||||
"cable_pairing": str,
|
||||
"rssi": int,
|
||||
"txpower": int,
|
||||
"uuids": List[str],
|
||||
@@ -302,6 +304,7 @@ _device_line_pattern = (
|
||||
+ r"|\s*TxPower:\s*(?P<txpower>.+)"
|
||||
+ r"|\s*Battery\sPercentage:\s*0[xX][0-9a-fA-F]*\s*\((?P<battery_percentage>[0-9]+)\)"
|
||||
+ r"|\s*UUID:\s*(?P<uuid>.+))"
|
||||
+ r"|\s*CablePairing:\s*(?P<cable_pairing>.+)"
|
||||
)
|
||||
|
||||
|
||||
@@ -335,6 +338,7 @@ def _parse_device(next_lines: List[str], quiet: bool) -> Optional[Device]:
|
||||
"blocked": '',
|
||||
"connected": '',
|
||||
"legacy_pairing": '',
|
||||
"cable_pairing": '',
|
||||
"rssi": 0,
|
||||
"txpower": 0,
|
||||
"uuids": [],
|
||||
@@ -383,6 +387,8 @@ def _parse_device(next_lines: List[str], quiet: bool) -> Optional[Device]:
|
||||
device["connected"] = matches["connected"]
|
||||
elif matches["legacy_pairing"]:
|
||||
device["legacy_pairing"] = matches["legacy_pairing"]
|
||||
elif matches["cable_pairing"]:
|
||||
device["cable_pairing"] = matches["cable_pairing"]
|
||||
elif matches["rssi"]:
|
||||
rssi = matches["rssi"]
|
||||
try:
|
||||
|
||||
@@ -121,7 +121,7 @@ import jc.utils
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.6'
|
||||
version = '1.7'
|
||||
description = '`dir` command parser'
|
||||
author = 'Rasheed Elsaleh'
|
||||
author_email = 'rasheed@rebelliondefense.com'
|
||||
@@ -183,8 +183,8 @@ def parse(data, raw=False, quiet=False):
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
for line in data.splitlines():
|
||||
if line.startswith(" Directory of"):
|
||||
parent_dir = line.lstrip(" Directory of ")
|
||||
if line.startswith(" Directory of "):
|
||||
parent_dir = line[len(" Directory of "):]
|
||||
continue
|
||||
# skip lines that don't start with a date
|
||||
if not re.match(r'^\d{2}/\d{2}/\d{4}', line):
|
||||
|
||||
@@ -28,6 +28,7 @@ Schema:
|
||||
[
|
||||
{
|
||||
"filename": string,
|
||||
"mode": string,
|
||||
"hash": string,
|
||||
}
|
||||
]
|
||||
@@ -38,37 +39,44 @@ Examples:
|
||||
[
|
||||
{
|
||||
"filename": "devtoolset-3-gcc-4.9.2-6.el7.x86_64.rpm",
|
||||
"mode": "text",
|
||||
"hash": "65fc958c1add637ec23c4b137aecf3d3"
|
||||
},
|
||||
{
|
||||
"filename": "digout",
|
||||
"mode": "text",
|
||||
"hash": "5b9312ee5aff080927753c63a347707d"
|
||||
},
|
||||
{
|
||||
"filename": "dmidecode.out",
|
||||
"mode": "text",
|
||||
"hash": "716fd11c2ac00db109281f7110b8fb9d"
|
||||
},
|
||||
{
|
||||
"filename": "file with spaces in the name",
|
||||
"mode": "text",
|
||||
"hash": "d41d8cd98f00b204e9800998ecf8427e"
|
||||
},
|
||||
{
|
||||
"filename": "id-centos.out",
|
||||
"mode": "text",
|
||||
"hash": "4295be239a14ad77ef3253103de976d2"
|
||||
},
|
||||
{
|
||||
"filename": "ifcfg.json",
|
||||
"mode": "text",
|
||||
"hash": "01fda0d9ba9a75618b072e64ff512b43"
|
||||
},
|
||||
...
|
||||
]
|
||||
"""
|
||||
import re
|
||||
import jc.utils
|
||||
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.2'
|
||||
version = '1.3'
|
||||
description = 'hashsum command parser (`md5sum`, `shasum`, etc.)'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -81,6 +89,15 @@ class info():
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
_mode_friendly_names = {
|
||||
" ": "text",
|
||||
"*": "binary",
|
||||
# Perl shasum -- specific
|
||||
"U": "universal",
|
||||
"^": "bits",
|
||||
# BSD-style format only supports binary mode
|
||||
None: "binary"
|
||||
}
|
||||
|
||||
def _process(proc_data):
|
||||
"""
|
||||
@@ -95,7 +112,9 @@ def _process(proc_data):
|
||||
List of Dictionaries. Structured data to conform to the schema.
|
||||
"""
|
||||
|
||||
# no further processing for this parser
|
||||
for entry in proc_data:
|
||||
entry['mode'] = _mode_friendly_names.get(entry['mode'],entry['mode'])
|
||||
|
||||
return proc_data
|
||||
|
||||
|
||||
@@ -127,18 +146,20 @@ def parse(data, raw=False, quiet=False):
|
||||
file_name = line.split('=', maxsplit=1)[0].strip()
|
||||
file_name = file_name[5:]
|
||||
file_name = file_name[:-1]
|
||||
# filler, legacy md5 always uses binary mode
|
||||
file_mode = None
|
||||
# standard md5sum and shasum command output
|
||||
else:
|
||||
file_hash = line.split(maxsplit=1)[0]
|
||||
file_name = line.split(maxsplit=1)[1]
|
||||
m = re.match('([0-9a-f]+) (.)(.*)$', line)
|
||||
if not m:
|
||||
raise ValueError(f'Invalid line format: "{line}"')
|
||||
file_hash, file_mode, file_name = m.groups()
|
||||
|
||||
item = {
|
||||
'filename': file_name,
|
||||
'mode': file_mode,
|
||||
'hash': file_hash
|
||||
}
|
||||
raw_output.append(item)
|
||||
|
||||
if raw:
|
||||
return raw_output
|
||||
else:
|
||||
return _process(raw_output)
|
||||
return raw_output if raw else _process(raw_output)
|
||||
|
||||
@@ -219,7 +219,7 @@ import jc.utils
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '2.4'
|
||||
version = '2.5'
|
||||
description = '`ifconfig` command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -264,7 +264,7 @@ def _process(proc_data: List[JSONDictType]) -> List[JSONDictType]:
|
||||
try:
|
||||
if entry['ipv4_mask'].startswith('0x'):
|
||||
new_mask = entry['ipv4_mask']
|
||||
new_mask = new_mask.lstrip('0x')
|
||||
new_mask = new_mask[2:]
|
||||
new_mask = '.'.join(str(int(i, 16)) for i in [new_mask[i:i + 2] for i in range(0, len(new_mask), 2)])
|
||||
entry['ipv4_mask'] = new_mask
|
||||
except (ValueError, TypeError, AttributeError):
|
||||
@@ -289,7 +289,7 @@ def _process(proc_data: List[JSONDictType]) -> List[JSONDictType]:
|
||||
try:
|
||||
if ip_address['mask'].startswith('0x'):
|
||||
new_mask = ip_address['mask']
|
||||
new_mask = new_mask.lstrip('0x')
|
||||
new_mask = new_mask[2:]
|
||||
new_mask = '.'.join(str(int(i, 16)) for i in [new_mask[i:i + 2] for i in range(0, len(new_mask), 2)])
|
||||
ip_address['mask'] = new_mask
|
||||
except (ValueError, TypeError, AttributeError):
|
||||
|
||||
@@ -173,7 +173,7 @@ import jc.utils
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.12'
|
||||
version = '1.13'
|
||||
description = '`iptables` command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -294,9 +294,16 @@ def parse(data, raw=False, quiet=False):
|
||||
|
||||
else:
|
||||
# sometimes the "target" column is blank. Stuff in a dummy character
|
||||
if headers[0] == 'target' and line.startswith(' '):
|
||||
opt_values = {'--', '-f', '!f'}
|
||||
line_split = line.split()
|
||||
if headers[0] == 'target' and line.startswith(' '): # standard output
|
||||
line = '\u2063' + line
|
||||
|
||||
elif headers[0] == 'pkts' and line_split[3] in opt_values: # verbose output
|
||||
first_section = line_split[:2]
|
||||
second_section = line_split[2:]
|
||||
line = ' '.join(first_section) + ' \u2063 ' + ' '.join(second_section)
|
||||
|
||||
rule = line.split(maxsplit=len(headers) - 1)
|
||||
temp_rule = dict(zip(headers, rule))
|
||||
if temp_rule:
|
||||
|
||||
194
jc/parsers/net_localgroup.py
Normal file
194
jc/parsers/net_localgroup.py
Normal file
@@ -0,0 +1,194 @@
|
||||
r"""jc - JSON Convert `net localgroup` command output parser
|
||||
|
||||
Usage (cli):
|
||||
|
||||
$ net localgroup | jc --net-localgroup
|
||||
$ net localgroup /domain | jc --net-localgroup
|
||||
$ net localgroup Administrators | jc --net-localgroup
|
||||
$ net localgroup Administrators /domain | jc --net-localgroup
|
||||
|
||||
Usage (module):
|
||||
|
||||
import jc
|
||||
result = jc.parse('net_localgroup', net_localgroup_command_output)
|
||||
|
||||
Schema:
|
||||
|
||||
{
|
||||
"account_origin": string,
|
||||
"domain": string,
|
||||
"comment": string,
|
||||
"groups": [
|
||||
{
|
||||
"name": string
|
||||
"members": [
|
||||
string
|
||||
]
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
Examples:
|
||||
|
||||
$ net localgroup | jc --net-localgroup -p
|
||||
{
|
||||
"account_origin": null,
|
||||
"comment": null,
|
||||
"domain": null,
|
||||
"groups": [
|
||||
{
|
||||
"name": "Administrators",
|
||||
"members": [
|
||||
"Administrator",
|
||||
"Operator",
|
||||
"ansible",
|
||||
"user1"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
import re
|
||||
import jc.utils
|
||||
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.0'
|
||||
description = '`net localgroup` command parser'
|
||||
author = 'joehacksalot'
|
||||
author_email = 'joehacksalot@gmail.com'
|
||||
compatible = ['win32']
|
||||
magic_commands = ['net localgroup']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
|
||||
def parse(data, raw=False, quiet=False):
|
||||
"""
|
||||
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:
|
||||
|
||||
Parsed dictionary. The raw and processed data structures are the same.
|
||||
"""
|
||||
jc.utils.compatibility(__name__, info.compatible, quiet)
|
||||
jc.utils.input_type_check(data)
|
||||
|
||||
raw_output = {}
|
||||
if jc.utils.has_data(data):
|
||||
# Initialize the parsed output dictionary with all fields set to None or empty lists
|
||||
raw_output = _parse(data)
|
||||
|
||||
return raw_output if raw else _process(raw_output)
|
||||
|
||||
def _process(proc_data):
|
||||
"""
|
||||
Final processing to conform to the schema.
|
||||
|
||||
Parameters:
|
||||
|
||||
proc_data: (Dictionary) raw structured data to process
|
||||
|
||||
Returns:
|
||||
|
||||
Processed Dictionary. Structured data to conform to the schema.
|
||||
"""
|
||||
return proc_data
|
||||
|
||||
|
||||
class _PushbackIterator:
|
||||
def __init__(self, iterator):
|
||||
self.iterator = iterator
|
||||
self.pushback_stack = []
|
||||
def __iter__(self):
|
||||
return self
|
||||
def __next__(self):
|
||||
if self.pushback_stack:
|
||||
return self.pushback_stack.pop()
|
||||
else:
|
||||
return next(self.iterator)
|
||||
def pushback(self, value):
|
||||
self.pushback_stack.append(value)
|
||||
|
||||
def _parse_net_localgroup_list(line_iter, expect_asterisk):
|
||||
name_list = []
|
||||
while True:
|
||||
try:
|
||||
line = next(line_iter)
|
||||
if not line.strip():
|
||||
continue # Skip empty lines
|
||||
|
||||
# Check if the line starts with an asterisk
|
||||
if line == 'The command completed successfully.':
|
||||
break
|
||||
elif expect_asterisk and line.startswith('*'):
|
||||
name_list.append(line[1:].strip())
|
||||
else:
|
||||
name_list.append(line)
|
||||
except StopIteration:
|
||||
break
|
||||
return name_list
|
||||
|
||||
|
||||
def _parse(data):
|
||||
lines = data.splitlines()
|
||||
parse_type = None # Can be 'groups_list' or 'members'
|
||||
|
||||
result = {
|
||||
"account_origin": None,
|
||||
"domain": None,
|
||||
"comment": None,
|
||||
"groups": []
|
||||
}
|
||||
|
||||
group_name = ""
|
||||
lines = data.splitlines()
|
||||
lines = [line.rstrip() for line in lines if line.strip() != ""]
|
||||
|
||||
line_iter = _PushbackIterator(iter(lines))
|
||||
for line in line_iter:
|
||||
line = line.rstrip()
|
||||
|
||||
# Skip empty lines
|
||||
if not line.strip():
|
||||
continue
|
||||
|
||||
match_domain_processed = re.match(r"^The request will be processed at a domain controller for domain (.+)", line, re.IGNORECASE)
|
||||
match_localgroup_list = re.match(r"^Aliases for[\s]*([^:]+)", line, re.IGNORECASE) # "Aliases for \\DESKTOP-WIN11:"
|
||||
match_localgroup_members = re.match(r"^Alias name[\s]*([^:]+)", line, re.IGNORECASE) # "Alias name administrators:"
|
||||
if match_domain_processed:
|
||||
# Extract the domain name
|
||||
result["domain"] = match_domain_processed.group(1).strip()
|
||||
elif match_localgroup_list:
|
||||
# Extract the account origin
|
||||
result["account_origin"] = match_localgroup_list.group(1).strip()
|
||||
parse_type = 'groups_list' # Prepare to read groups
|
||||
elif match_localgroup_members:
|
||||
# We are querying a specific group
|
||||
group_name = match_localgroup_members.group(1).strip()
|
||||
parse_type = 'members_list' # Prepare to read members
|
||||
elif line.startswith('Comment'):
|
||||
comment_line = line.split('Comment', 1)[1].strip()
|
||||
result["comment"] = comment_line if comment_line else None
|
||||
elif line.startswith('---'):
|
||||
# Start of a section (groups or members)
|
||||
if parse_type == 'groups_list':
|
||||
names_list = _parse_net_localgroup_list(line_iter, expect_asterisk=True)
|
||||
result["groups"] = [{"name": group_name, "members": []} for group_name in names_list]
|
||||
elif parse_type == 'members_list':
|
||||
names_list = _parse_net_localgroup_list(line_iter, expect_asterisk=False)
|
||||
result["groups"] = [{
|
||||
"name": group_name,
|
||||
"members": names_list
|
||||
}]
|
||||
|
||||
return result
|
||||
441
jc/parsers/net_user.py
Normal file
441
jc/parsers/net_user.py
Normal file
@@ -0,0 +1,441 @@
|
||||
r"""jc - JSON Convert `net user` command output parser
|
||||
|
||||
|
||||
Usage (cli):
|
||||
|
||||
$ net users | jc --net-user
|
||||
$ net users /domain | jc --net-user
|
||||
$ net users User1 | jc --net-user
|
||||
$ net users User1 /domain | jc --net-user
|
||||
|
||||
Usage (module):
|
||||
|
||||
import jc
|
||||
result = jc.parse('net_user', net_user_command_output)
|
||||
|
||||
Schema:
|
||||
|
||||
{
|
||||
"domain": string,
|
||||
"account_origin": string,
|
||||
"user_accounts": [
|
||||
{
|
||||
"user_name": string,
|
||||
"full_name": string,
|
||||
"comment": string,
|
||||
"user_comment": string,
|
||||
"country_region_code": string,
|
||||
"account_active": boolean,
|
||||
"account_expires": string,
|
||||
"password_last_set": string,
|
||||
"password_expires": string,
|
||||
"password_changeable": string,
|
||||
"password_required": boolean,
|
||||
"user_may_change_password": boolean,
|
||||
"workstations_allowed": string,
|
||||
"logon_script": string,
|
||||
"user_profile": string,
|
||||
"home_directory": string,
|
||||
"last_logon": string,
|
||||
"logon_hours_allowed": string,
|
||||
"local_group_memberships": [
|
||||
string,
|
||||
],
|
||||
"global_group_memberships": [
|
||||
string,
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
Examples:
|
||||
|
||||
$ net users | jc --net-user -p
|
||||
{
|
||||
"account_origin": "\\\\WIN-SERVER16",
|
||||
"domain": "",
|
||||
"user_accounts": [
|
||||
{
|
||||
"user_name": "Administrator"
|
||||
},
|
||||
{
|
||||
"user_name": "DefaultAccount"
|
||||
},
|
||||
{
|
||||
"user_name": "Guest"
|
||||
},
|
||||
{
|
||||
"user_name": "pentera_BnlLQVnd7p"
|
||||
},
|
||||
{
|
||||
"user_name": "user1"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
$ net users /domain | jc --net-user -p
|
||||
{
|
||||
"account_origin": "\\\\DESKTOP-WIN10-PRO.somecompany.corp",
|
||||
"domain": "somecompany.corp",
|
||||
"user_accounts": [
|
||||
{
|
||||
"user_name": "aaron"
|
||||
},
|
||||
{
|
||||
"user_name": "addison"
|
||||
},
|
||||
{
|
||||
"user_name": "Administrator"
|
||||
},
|
||||
{
|
||||
"user_name": "ansible"
|
||||
},
|
||||
{
|
||||
"user_name": "da"
|
||||
},
|
||||
{
|
||||
"user_name": "DefaultAccount"
|
||||
},
|
||||
{
|
||||
"user_name": "Guest"
|
||||
},
|
||||
{
|
||||
"user_name": "harrison"
|
||||
},
|
||||
{
|
||||
"user_name": "james"
|
||||
},
|
||||
{
|
||||
"user_name": "krbtgt"
|
||||
},
|
||||
{
|
||||
"user_name": "liam"
|
||||
},
|
||||
{
|
||||
"user_name": "localadmin"
|
||||
},
|
||||
{
|
||||
"user_name": "tiffany"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
$ net users Administrator | jc --net-user -p
|
||||
{
|
||||
"domain": "",
|
||||
"user_accounts": [
|
||||
{
|
||||
"account_active": true,
|
||||
"account_expires": "Never",
|
||||
"comment": "Built-in account for administering the computer/domain",
|
||||
"country_region_code": "000 (System Default)",
|
||||
"global_group_memberships": [],
|
||||
"last_logon": "2024-08-23T13:47:11",
|
||||
"local_group_memberships": [
|
||||
"Administrators"
|
||||
],
|
||||
"logon_hours_allowed": "All",
|
||||
"password_changeable": "2021-12-17T11:07:14",
|
||||
"password_expires": "2022-01-27T11:07:14",
|
||||
"password_last_set": "2021-12-16T11:07:14",
|
||||
"password_required": true,
|
||||
"user_may_change_password": true,
|
||||
"user_name": "Administrators",
|
||||
"workstations_allowed": "All"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
$ net users Administrator /domain | jc --net-user -p | jq
|
||||
{
|
||||
"domain": "somecompany.corp",
|
||||
"user_accounts": [
|
||||
{
|
||||
"account_active": true,
|
||||
"account_expires": "Never",
|
||||
"comment": "Built-in account for administering the computer/domain",
|
||||
"country_region_code": "000 (System Default)",
|
||||
"global_group_memberships": [
|
||||
"Domain Admins",
|
||||
"Domain Users",
|
||||
"Group Policy Creator",
|
||||
"Enterprise Admins",
|
||||
"Schema Admins"
|
||||
],
|
||||
"last_logon": "2024-07-17T13:46:12",
|
||||
"local_group_memberships": [
|
||||
"Administrators"
|
||||
],
|
||||
"logon_hours_allowed": "All",
|
||||
"password_changeable": "2023-09-30T11:44:26",
|
||||
"password_expires": "Never",
|
||||
"password_last_set": "2023-09-29T11:44:26",
|
||||
"password_required": true,
|
||||
"user_may_change_password": true,
|
||||
"user_name": "Administrators",
|
||||
"workstations_allowed": "All"
|
||||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
from datetime import datetime
|
||||
import re
|
||||
import jc.utils
|
||||
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.0'
|
||||
description = '`net user` command parser'
|
||||
author = 'joehacksalot'
|
||||
author_email = 'joehacksalot@gmail.com'
|
||||
compatible = ['win32']
|
||||
magic_commands = ['net user']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
|
||||
def parse(data, raw=False, quiet=False):
|
||||
"""
|
||||
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:
|
||||
|
||||
Parsed dictionary. The raw and processed data structures are the same.
|
||||
"""
|
||||
jc.utils.compatibility(__name__, info.compatible, quiet)
|
||||
jc.utils.input_type_check(data)
|
||||
|
||||
raw_output = {}
|
||||
if jc.utils.has_data(data):
|
||||
raw_output = _parse(data)
|
||||
|
||||
if not raw_output:
|
||||
raw_output = {}
|
||||
|
||||
return raw_output if raw else _process(raw_output)
|
||||
|
||||
def _set_if_not_none(output_dict, key, value):
|
||||
if value is not None:
|
||||
output_dict[key] = value
|
||||
|
||||
def _process_string_is_yes(text):
|
||||
if text:
|
||||
return text.lower() == "yes"
|
||||
else:
|
||||
return None
|
||||
|
||||
def _process_date(s):
|
||||
if s is not None:
|
||||
for fmt in ('%m/%d/%Y %I:%M:%S %p', '%m/%d/%Y %H:%M:%S %p'):
|
||||
try:
|
||||
return datetime.strptime(s, fmt).isoformat()
|
||||
except ValueError:
|
||||
continue
|
||||
return s # Return the original string if parsing fails
|
||||
|
||||
def _process(proc_data):
|
||||
"""
|
||||
Final processing to conform to the schema.
|
||||
|
||||
Parameters:
|
||||
|
||||
proc_data: (Dictionary) raw structured data to process
|
||||
|
||||
Returns:
|
||||
|
||||
Processed Dictionary. Structured data to conform to the schema.
|
||||
"""
|
||||
for user_account in proc_data.get("user_accounts", []):
|
||||
_set_if_not_none(user_account, "account_active", _process_string_is_yes(user_account.get("account_active", None)))
|
||||
_set_if_not_none(user_account, "password_last_set", _process_date(user_account.get("password_last_set", None)))
|
||||
_set_if_not_none(user_account, "password_expires", _process_date(user_account.get("password_expires", None)))
|
||||
_set_if_not_none(user_account, "password_changeable", _process_date(user_account.get("password_changeable", None)))
|
||||
_set_if_not_none(user_account, "password_required", _process_string_is_yes(user_account.get("password_required", None)))
|
||||
_set_if_not_none(user_account, "user_may_change_password", _process_string_is_yes(user_account.get("user_may_change_password", None)))
|
||||
_set_if_not_none(user_account, "last_logon", _process_date(user_account.get("last_logon", None)))
|
||||
|
||||
if not proc_data:
|
||||
proc_data = {}
|
||||
|
||||
return proc_data
|
||||
|
||||
|
||||
class _PushbackIterator:
|
||||
def __init__(self, iterator):
|
||||
self.iterator = iterator
|
||||
self.pushback_stack = []
|
||||
def __iter__(self):
|
||||
return self
|
||||
def __next__(self):
|
||||
if self.pushback_stack:
|
||||
return self.pushback_stack.pop()
|
||||
else:
|
||||
return next(self.iterator)
|
||||
def pushback(self, value):
|
||||
self.pushback_stack.append(value)
|
||||
|
||||
def _parse_user_account_keypairs(keypair_dict):
|
||||
user_account_parsed = {}
|
||||
_set_if_not_none(user_account_parsed, "user_name", keypair_dict.get("user_name", None))
|
||||
_set_if_not_none(user_account_parsed, "full_name", keypair_dict.get("full_name", None))
|
||||
_set_if_not_none(user_account_parsed, "comment", keypair_dict.get("comment", None))
|
||||
_set_if_not_none(user_account_parsed, "users_comment", keypair_dict.get("users_comment", None))
|
||||
_set_if_not_none(user_account_parsed, "country_region_code", keypair_dict.get("country_region_code", None))
|
||||
_set_if_not_none(user_account_parsed, "account_active", keypair_dict.get("account_active", None))
|
||||
_set_if_not_none(user_account_parsed, "account_expires", keypair_dict.get("account_expires", None))
|
||||
_set_if_not_none(user_account_parsed, "password_last_set", keypair_dict.get("password_last_set", None))
|
||||
_set_if_not_none(user_account_parsed, "password_expires", keypair_dict.get("password_expires", None))
|
||||
_set_if_not_none(user_account_parsed, "password_changeable", keypair_dict.get("password_changeable", None))
|
||||
_set_if_not_none(user_account_parsed, "password_required", keypair_dict.get("password_required", None))
|
||||
_set_if_not_none(user_account_parsed, "user_may_change_password", keypair_dict.get("user_may_change_password", None))
|
||||
_set_if_not_none(user_account_parsed, "workstations_allowed", keypair_dict.get("workstations_allowed", None))
|
||||
_set_if_not_none(user_account_parsed, "logon_script", keypair_dict.get("logon_script", None))
|
||||
_set_if_not_none(user_account_parsed, "user_profile", keypair_dict.get("user_profile", None))
|
||||
_set_if_not_none(user_account_parsed, "home_directory", keypair_dict.get("home_directory", None))
|
||||
_set_if_not_none(user_account_parsed, "last_logon", keypair_dict.get("last_logon", None))
|
||||
_set_if_not_none(user_account_parsed, "logon_hours_allowed", keypair_dict.get("logon_hours_allowed", None))
|
||||
_set_if_not_none(user_account_parsed, "local_group_memberships", keypair_dict.get("local_group_memberships", None))
|
||||
_set_if_not_none(user_account_parsed, "global_group_memberships", keypair_dict.get("global_group_memberships", None))
|
||||
return user_account_parsed
|
||||
|
||||
|
||||
def _parse_groups(line_iter):
|
||||
group_list = []
|
||||
# Process additional lines that belong to the current entry (e.g., additional DNS servers, DNS Suffix Search List)
|
||||
while True:
|
||||
try:
|
||||
next_line = next(line_iter).strip()
|
||||
if not next_line:
|
||||
continue # Skip empty lines
|
||||
|
||||
# Check if the line is indented (starts with whitespace)
|
||||
if next_line.startswith('*'):
|
||||
groups = next_line.split("*")
|
||||
groups = [group.strip() for group in groups if group.strip() != ""]
|
||||
if "None" in groups:
|
||||
groups.remove("None")
|
||||
# It's an indented line; append the stripped line to entry_list
|
||||
group_list.extend(groups)
|
||||
else:
|
||||
# Not an indented line; push it back and exit
|
||||
line_iter.pushback(next_line)
|
||||
break
|
||||
except StopIteration:
|
||||
break
|
||||
return group_list
|
||||
|
||||
def _parse(data):
|
||||
result = {
|
||||
"domain": "",
|
||||
"user_accounts": []
|
||||
}
|
||||
|
||||
lines = data.splitlines()
|
||||
lines = [line.rstrip() for line in lines if line.strip() != ""]
|
||||
|
||||
line_iter = _PushbackIterator(iter(lines))
|
||||
for line in line_iter:
|
||||
line = line.rstrip()
|
||||
|
||||
# Skip empty lines
|
||||
if not line.strip():
|
||||
continue
|
||||
|
||||
match_domain_processed = re.match(r"^The request will be processed at a domain controller for domain (.+)\.$", line, re.IGNORECASE)
|
||||
if match_domain_processed:
|
||||
result["domain"] = match_domain_processed.group(1).strip()
|
||||
# Check if the text is of the first type (detailed user info)
|
||||
elif "User name" in line:
|
||||
line_iter.pushback(line)
|
||||
user_account_keypairs = {}
|
||||
|
||||
# Regular expression to match key-value pairs
|
||||
kv_pattern = re.compile(r'^([\w\s\/\'\-]{1,29})\s*(.+)?$')
|
||||
key = None
|
||||
|
||||
while True:
|
||||
# Process each line
|
||||
# Break when done
|
||||
try:
|
||||
line = next(line_iter)
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue # Skip empty lines
|
||||
|
||||
match = kv_pattern.match(line)
|
||||
if "The command completed" in line:
|
||||
break
|
||||
elif match:
|
||||
key_raw = match.group(1).strip()
|
||||
key = key_raw.lower().replace(" ", "_").replace("'", "").replace("/", "_").replace("-", "_")
|
||||
if len(match.groups()) == 2 and match.group(2) is not None:
|
||||
value = match.group(2).strip()
|
||||
if key in ["local_group_memberships", "global_group_memberships"]:
|
||||
line_iter.pushback(value)
|
||||
user_account_keypairs[key] = _parse_groups(line_iter)
|
||||
else:
|
||||
user_account_keypairs[key] = value
|
||||
else:
|
||||
# Line without value, it's a key with empty value
|
||||
user_account_keypairs[key] = None
|
||||
else:
|
||||
raise ValueError(f"Unexpected line: {line}")
|
||||
except StopIteration:
|
||||
break
|
||||
|
||||
# Convert specific fields
|
||||
result["user_accounts"].append(_parse_user_account_keypairs(user_account_keypairs))
|
||||
elif "User accounts for" in line:
|
||||
line_iter.pushback(line)
|
||||
collecting_users = False
|
||||
|
||||
while True:
|
||||
# Process each line
|
||||
# Break when done
|
||||
try:
|
||||
line = next(line_iter)
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue # Skip empty lines
|
||||
|
||||
# Check for domain line
|
||||
domain_pattern = re.compile(r'^User accounts for (.+)$')
|
||||
account_origin_match = domain_pattern.match(line)
|
||||
if account_origin_match:
|
||||
result["account_origin"] = account_origin_match.group(1)
|
||||
continue
|
||||
|
||||
# Check for the line of dashes indicating start of user list
|
||||
if line.startswith('---'):
|
||||
collecting_users = True
|
||||
continue
|
||||
|
||||
# Check for the completion message
|
||||
if line.startswith('The command completed'):
|
||||
break
|
||||
|
||||
if collecting_users:
|
||||
# Split the line into usernames
|
||||
user_matches = re.match(r'(.{1,20})(\s+.{1,20})?(\s+.{1,20})?', line)
|
||||
if user_matches:
|
||||
for username in user_matches.groups():
|
||||
if username:
|
||||
username = username.strip()
|
||||
user_account = {"user_name": username}
|
||||
result["user_accounts"].append(user_account)
|
||||
except StopIteration:
|
||||
break
|
||||
else:
|
||||
raise ValueError(f"Unexpected line: {line}")
|
||||
|
||||
return result
|
||||
@@ -36,7 +36,8 @@ These are documented below.
|
||||
[
|
||||
{
|
||||
"<key>": string/integer/float, # [0]
|
||||
"team_config": object,
|
||||
"team_config": object/null,
|
||||
"team_port_config": object/null,
|
||||
"dhcp4_option_x": {
|
||||
"name": string,
|
||||
"value": string/integer/float,
|
||||
@@ -151,7 +152,7 @@ from jc.exceptions import ParseError
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.1'
|
||||
version = '1.2'
|
||||
description = '`nmcli` command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -320,23 +321,32 @@ def _connection_show_x_parse(data: str) -> List[Dict]:
|
||||
|
||||
for line in filter(None, data.splitlines()):
|
||||
|
||||
# fix for team.config, which is multi-line JSON
|
||||
if line.startswith('team.config:'):
|
||||
# fix for team.config and team-port.config, which are multi-line JSON
|
||||
if line.startswith('team.config:') or line.startswith('team-port.config:'):
|
||||
key, value = line.split(':', maxsplit=1)
|
||||
key_team = _normalize_key(key)
|
||||
value_team = value.strip()
|
||||
|
||||
if value_team == '--':
|
||||
team_config_value = []
|
||||
item[key_team] = None
|
||||
continue
|
||||
|
||||
in_team_config = True
|
||||
_, value = line.split(':', maxsplit=1)
|
||||
team_config_value.append(value.strip())
|
||||
item['team_config'] = {}
|
||||
team_config_value.append(value_team)
|
||||
item[key_team] = {}
|
||||
continue
|
||||
|
||||
if not line.startswith('team.') and in_team_config:
|
||||
STARTSWITH_TEAM = line.startswith('team.') or line.startswith('team-port.')
|
||||
if not STARTSWITH_TEAM and in_team_config:
|
||||
team_config_value.append(line.strip())
|
||||
continue
|
||||
|
||||
in_team_config = False
|
||||
|
||||
if team_config_value:
|
||||
# team.config value should always be JSON
|
||||
item['team_config'] = json.loads(''.join(team_config_value))
|
||||
# team.config and team-port.config values should always be JSON
|
||||
item[key_team] = json.loads(''.join(team_config_value))
|
||||
team_config_value = []
|
||||
|
||||
key, value = line.split(':', maxsplit=1)
|
||||
|
||||
@@ -180,13 +180,13 @@ import jc.utils
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.0'
|
||||
version = '1.1'
|
||||
description = '`pacman` command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
|
||||
tags = ['command', 'file']
|
||||
magic_commands = ['pacman']
|
||||
magic_commands = ['pacman', 'yay']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -26,7 +26,10 @@ Schema:
|
||||
"license": string,
|
||||
"location": string,
|
||||
"requires": string,
|
||||
"required_by": string
|
||||
"required_by": string,
|
||||
"files": [
|
||||
string
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -60,13 +63,13 @@ Examples:
|
||||
}
|
||||
]
|
||||
"""
|
||||
from typing import List, Dict, Optional
|
||||
from typing import List, Dict
|
||||
import jc.utils
|
||||
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.5'
|
||||
version = '1.6'
|
||||
description = '`pip show` command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -120,6 +123,22 @@ def parse(
|
||||
last_key: str = ''
|
||||
last_key_data: List = []
|
||||
|
||||
def flush_last_key_data() -> None:
|
||||
"""Append buffered continuation lines to the previous field."""
|
||||
nonlocal last_key_data
|
||||
|
||||
if not last_key_data:
|
||||
return
|
||||
|
||||
if last_key == 'files':
|
||||
package[last_key].extend(last_key_data)
|
||||
else:
|
||||
if not isinstance(package[last_key], str):
|
||||
package[last_key] = ''
|
||||
package[last_key] = package[last_key] + '\n' + '\n'.join(last_key_data)
|
||||
|
||||
last_key_data = []
|
||||
|
||||
# Clear any blank lines
|
||||
cleandata = list(filter(None, data.splitlines()))
|
||||
|
||||
@@ -127,8 +146,7 @@ def parse(
|
||||
|
||||
for row in cleandata:
|
||||
if row.startswith('---'):
|
||||
if last_key_data:
|
||||
package[last_key] = package[last_key] + '\n' + '\n'.join(last_key_data)
|
||||
flush_last_key_data()
|
||||
|
||||
raw_output.append(package)
|
||||
package = {}
|
||||
@@ -137,17 +155,17 @@ def parse(
|
||||
continue
|
||||
|
||||
if not row.startswith(' '):
|
||||
item_key = row.split(': ', maxsplit=1)[0].lower().replace('-', '_')
|
||||
item_value: Optional[str] = row.split(': ', maxsplit=1)[1]
|
||||
item_key, item_value = row.split(':', maxsplit=1)
|
||||
item_key = item_key.lower().replace('-', '_')
|
||||
item_value = item_value.lstrip()
|
||||
|
||||
if item_value == '':
|
||||
if item_key == 'files':
|
||||
item_value = []
|
||||
elif item_value == '':
|
||||
item_value = None
|
||||
|
||||
if last_key_data and last_key != item_key:
|
||||
if not isinstance(package[last_key], str):
|
||||
package[last_key] = ''
|
||||
package[last_key] = package[last_key] + '\n' + '\n'.join(last_key_data)
|
||||
last_key_data = []
|
||||
flush_last_key_data()
|
||||
|
||||
package[item_key] = item_value
|
||||
last_key = item_key
|
||||
@@ -158,8 +176,7 @@ def parse(
|
||||
continue
|
||||
|
||||
if package:
|
||||
if last_key_data:
|
||||
package[last_key] = package[last_key] + '\n' + '\n'.join(last_key_data)
|
||||
flush_last_key_data()
|
||||
|
||||
raw_output.append(package)
|
||||
|
||||
|
||||
@@ -168,7 +168,7 @@ import jc.utils
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.0'
|
||||
version = '1.1'
|
||||
description = '`/proc/<pid>/smaps` file parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -205,33 +205,46 @@ def _process(proc_data: List[Dict]) -> List[Dict]:
|
||||
|
||||
vmflags_map = {
|
||||
'rd': 'readable',
|
||||
'wr': 'writeable',
|
||||
'ex': 'executable',
|
||||
'sh': 'shared',
|
||||
'mr': 'may read',
|
||||
'mw': 'may write',
|
||||
'me': 'may execute',
|
||||
'ms': 'may share',
|
||||
'mp': 'MPX-specific VMA',
|
||||
'gd': 'stack segment growns down',
|
||||
'pf': 'pure PFN range',
|
||||
'dw': 'disabled write to the mapped file',
|
||||
'lo': 'pages are locked in memory',
|
||||
'io': 'memory mapped I/O area',
|
||||
'sr': 'sequential read advise provided',
|
||||
'rr': 'random read advise provided',
|
||||
'dc': 'do not copy area on fork',
|
||||
'de': 'do not expand area on remapping',
|
||||
'ac': 'area is accountable',
|
||||
'nr': 'swap space is not reserved for the area',
|
||||
'ht': 'area uses huge tlb pages',
|
||||
'ar': 'architecture specific flag',
|
||||
'dd': 'do not include area into core dump',
|
||||
'sd': 'soft-dirty flag',
|
||||
'mm': 'mixed map area',
|
||||
'hg': 'huge page advise flag',
|
||||
'nh': 'no-huge page advise flag',
|
||||
'mg': 'mergable advise flag'
|
||||
'wr': 'writeable',
|
||||
'ex': 'executable',
|
||||
'sh': 'shared',
|
||||
'mr': 'may read',
|
||||
'mw': 'may write',
|
||||
'me': 'may execute',
|
||||
'ms': 'may share',
|
||||
'mp': 'MPX-specific VMA',
|
||||
'gd': 'stack segment growns down',
|
||||
'pf': 'pure PFN range',
|
||||
'dw': 'disabled write to the mapped file',
|
||||
'lo': 'pages are locked in memory',
|
||||
'io': 'memory mapped I/O area',
|
||||
'sr': 'sequential read advise provided',
|
||||
'rr': 'random read advise provided',
|
||||
'dc': 'do not copy area on fork',
|
||||
'de': 'do not expand area on remapping',
|
||||
'ac': 'area is accountable',
|
||||
'nr': 'swap space is not reserved for the area',
|
||||
'ht': 'area uses huge tlb pages',
|
||||
'sf': 'perform synchronous page faults',
|
||||
'nl': 'non-linear mapping',
|
||||
'ar': 'architecture specific flag',
|
||||
'wf': 'wipe on fork',
|
||||
'dd': 'do not include area into core dump',
|
||||
'sd': 'soft-dirty flag',
|
||||
'mm': 'mixed map area',
|
||||
'hg': 'huge page advise flag',
|
||||
'nh': 'no-huge page advise flag',
|
||||
'mg': 'mergable advise flag',
|
||||
'bt': 'arm64 BTI guarded page',
|
||||
'mt': 'arm64 MTE allocation tags are enabled',
|
||||
'um': 'userfaultfd missing pages tracking',
|
||||
'uw': 'userfaultfd wprotect pages tracking',
|
||||
'ui': 'userfaultfd minor fault',
|
||||
'ss': 'shadow/guarded control stack page',
|
||||
'sl': 'sealed',
|
||||
'lf': 'lock on fault pages',
|
||||
'dp': 'always lazily freeable mapping',
|
||||
'gu': 'maybe contains guard regions'
|
||||
}
|
||||
|
||||
for entry in proc_data:
|
||||
@@ -245,7 +258,7 @@ def _process(proc_data: List[Dict]) -> List[Dict]:
|
||||
|
||||
if 'VmFlags' in entry:
|
||||
entry['VmFlags'] = entry['VmFlags'].split()
|
||||
entry['VmFlags_pretty'] = [vmflags_map[x] for x in entry['VmFlags']]
|
||||
entry['VmFlags_pretty'] = [vmflags_map.get(x, x) for x in entry['VmFlags']]
|
||||
|
||||
return proc_data
|
||||
|
||||
|
||||
@@ -111,8 +111,6 @@ Examples:
|
||||
]
|
||||
"""
|
||||
import jc.utils
|
||||
import jc.parsers.universal
|
||||
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
|
||||
455
jc/parsers/route_print.py
Normal file
455
jc/parsers/route_print.py
Normal file
@@ -0,0 +1,455 @@
|
||||
r"""jc - JSON Convert `route print` command output parser
|
||||
|
||||
See also: the `route` command parser
|
||||
|
||||
Usage (cli):
|
||||
|
||||
$ route print | jc --route-print
|
||||
|
||||
Usage (module):
|
||||
|
||||
import jc
|
||||
result = jc.parse('route_print', route_print_command_output)
|
||||
|
||||
Schema:
|
||||
|
||||
{
|
||||
"interface_list": [
|
||||
{
|
||||
"interface_index": integer,
|
||||
"mac_address": string,
|
||||
"description": string
|
||||
}
|
||||
],
|
||||
"ipv4_route_table": {
|
||||
"active_routes": [
|
||||
{
|
||||
"network_destination": string,
|
||||
"netmask": string,
|
||||
"gateway": string,
|
||||
"interface": string,
|
||||
"metric": integer, # [0]
|
||||
"metric_set_to_default": boolean # [1]
|
||||
}
|
||||
],
|
||||
"persistent_routes": [
|
||||
{
|
||||
"network_address": string,
|
||||
"netmask": string,
|
||||
"gateway_address": string,
|
||||
"metric": integer # [0]
|
||||
"metric_set_to_default": boolean # [1]
|
||||
}
|
||||
]
|
||||
},
|
||||
"ipv6_route_table": {
|
||||
"active_routes": [
|
||||
{
|
||||
"interface": integer,
|
||||
"metric": integer, # [0]
|
||||
"metric_set_to_default": boolean, # [1]
|
||||
"network_destination": string,
|
||||
"gateway": string
|
||||
}
|
||||
],
|
||||
"persistent_routes": [
|
||||
{
|
||||
"interface": integer,
|
||||
"metric": integer, # [0]
|
||||
"metric_set_to_default": boolean, # [1]
|
||||
"network_destination": string,
|
||||
"gateway": string
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
[0] Null/None if "metric" = "Default"
|
||||
[1] True if "metric" = "Default"
|
||||
|
||||
Examples:
|
||||
|
||||
$ route print | jc --route-print -p
|
||||
{
|
||||
"interface_list": [
|
||||
{
|
||||
"interface_index": 28,
|
||||
"mac_address": null,
|
||||
"description": "Tailscale Tunnel"
|
||||
},
|
||||
{
|
||||
"interface_index": 12,
|
||||
"mac_address": "00:1c:42:da:01:6a",
|
||||
"description": "Parallels VirtIO Ethernet Adapter"
|
||||
},
|
||||
{
|
||||
"interface_index": 1,
|
||||
"mac_address": null,
|
||||
"description": "Software Loopback Interface 1"
|
||||
}
|
||||
],
|
||||
"ipv4_route_table": {
|
||||
"active_routes": [
|
||||
{
|
||||
"network_destination": "0.0.0.0",
|
||||
"netmask": "0.0.0.0",
|
||||
"gateway": "10.211.55.1",
|
||||
"interface": "10.211.55.3",
|
||||
"metric": 15,
|
||||
"metric_set_to_default": false
|
||||
},
|
||||
{
|
||||
"network_destination": "10.0.0.0",
|
||||
"netmask": "255.0.0.0",
|
||||
"gateway": "192.168.22.1",
|
||||
"interface": "10.211.55.3",
|
||||
"metric": 16,
|
||||
"metric_set_to_default": false
|
||||
},
|
||||
...
|
||||
{
|
||||
"network_destination": "255.255.255.255",
|
||||
"netmask": "255.255.255.255",
|
||||
"gateway": "On-link",
|
||||
"interface": "10.211.55.3",
|
||||
"metric": null,
|
||||
"metric_set_to_default": true
|
||||
}
|
||||
],
|
||||
"persistent_routes": [
|
||||
{
|
||||
"network_address": "10.0.1.0",
|
||||
"netmask": "255.255.255.0",
|
||||
"gateway_address": "192.168.22.1",
|
||||
"metric": 1,
|
||||
"metric_set_to_default": false
|
||||
},
|
||||
{
|
||||
"network_address": "10.0.3.0",
|
||||
"netmask": "255.255.255.0",
|
||||
"gateway_address": "192.168.22.1",
|
||||
"metric": 1,
|
||||
"metric_set_to_default": false
|
||||
},
|
||||
...
|
||||
]
|
||||
},
|
||||
"ipv6_route_table": {
|
||||
"active_routes": [
|
||||
{
|
||||
"interface": 1,
|
||||
"metric": 331,
|
||||
"network_destination": "::1/128",
|
||||
"gateway": "On-link",
|
||||
"metric_set_to_default": false
|
||||
},
|
||||
{
|
||||
"interface": 12,
|
||||
"metric": 271,
|
||||
"network_destination": "2001:db8::/64",
|
||||
"gateway": "fe80::1",
|
||||
"metric_set_to_default": false
|
||||
},
|
||||
...
|
||||
{
|
||||
"interface": 12,
|
||||
"metric": 271,
|
||||
"network_destination": "ff00::/8",
|
||||
"gateway": "On-link",
|
||||
"metric_set_to_default": false
|
||||
}
|
||||
],
|
||||
"persistent_routes": [
|
||||
{
|
||||
"interface": 0,
|
||||
"metric": 4294967295,
|
||||
"network_destination": "2001:db8::/64",
|
||||
"gateway": "fe80::1",
|
||||
"metric_set_to_default": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
"""
|
||||
import re
|
||||
import jc.utils
|
||||
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.0'
|
||||
description = '`route print` command parser'
|
||||
author = 'joehacksalot'
|
||||
author_email = 'joehacksalot@gmail.com'
|
||||
details = 'See also: `route` command parser'
|
||||
compatible = ['win32']
|
||||
magic_commands = ['route print']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
|
||||
def parse(data, raw=False, quiet=False):
|
||||
"""
|
||||
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:
|
||||
|
||||
Parsed dictionary. The raw and processed data structures are the same.
|
||||
"""
|
||||
jc.utils.compatibility(__name__, info.compatible, quiet)
|
||||
jc.utils.input_type_check(data)
|
||||
|
||||
raw_output = {}
|
||||
if jc.utils.has_data(data):
|
||||
raw_data = {
|
||||
"interface_list": [],
|
||||
"ipv4_route_table": {
|
||||
"active_routes": [],
|
||||
"persistent_routes": []
|
||||
},
|
||||
"ipv6_route_table": {
|
||||
"active_routes": [],
|
||||
"persistent_routes": []
|
||||
}
|
||||
}
|
||||
|
||||
lines = data.splitlines()
|
||||
_parse_interface_list(raw_data, _PushbackIterator(iter(lines)))
|
||||
_parse_ipv4_route_table(raw_data, _PushbackIterator(iter(lines)))
|
||||
_parse_ipv6_route_table(raw_data, _PushbackIterator(iter(lines)))
|
||||
raw_output = raw_data
|
||||
return raw_output if raw else _process(raw_output)
|
||||
|
||||
def _process(proc_data):
|
||||
"""
|
||||
Final processing to conform to the schema.
|
||||
|
||||
Parameters:
|
||||
|
||||
proc_data: (Dictionary) raw structured data to process
|
||||
|
||||
Returns:
|
||||
|
||||
Processed Dictionary. Structured data to conform to the schema.
|
||||
"""
|
||||
if not proc_data:
|
||||
return {}
|
||||
|
||||
for interface in proc_data['interface_list']:
|
||||
if interface["mac_address"] == '' or interface["mac_address"] == '00 00 00 00 00 00 00 e0': # Placeholder MAC address for virtual adapters
|
||||
mac_address = None
|
||||
else:
|
||||
mac_address = interface["mac_address"].replace(" ", ":")
|
||||
|
||||
interface["mac_address"] = mac_address
|
||||
|
||||
interface["interface_index"] = jc.utils.convert_to_int(interface["interface_index"])
|
||||
|
||||
for ipv4_active_route in proc_data['ipv4_route_table']['active_routes']:
|
||||
if ipv4_active_route["metric"] != "Default":
|
||||
ipv4_active_route["metric"] = jc.utils.convert_to_int(ipv4_active_route["metric"])
|
||||
ipv4_active_route["metric_set_to_default"] = False
|
||||
else:
|
||||
ipv4_active_route["metric"] = None
|
||||
ipv4_active_route["metric_set_to_default"] = True
|
||||
|
||||
for ipv4_persistent_route in proc_data['ipv4_route_table']['persistent_routes']:
|
||||
if ipv4_persistent_route["metric"] != "Default":
|
||||
ipv4_persistent_route["metric"] = jc.utils.convert_to_int(ipv4_persistent_route["metric"])
|
||||
ipv4_persistent_route["metric_set_to_default"] = False
|
||||
else:
|
||||
ipv4_persistent_route["metric"] = None
|
||||
ipv4_persistent_route["metric_set_to_default"] = True
|
||||
|
||||
for ipv6_active_route in proc_data['ipv6_route_table']['active_routes']:
|
||||
ipv6_active_route["interface"] = jc.utils.convert_to_int(ipv6_active_route["interface"])
|
||||
|
||||
if ipv6_active_route["metric"] != "Default":
|
||||
ipv6_active_route["metric"] = jc.utils.convert_to_int(ipv6_active_route["metric"])
|
||||
ipv6_active_route["metric_set_to_default"] = False
|
||||
else:
|
||||
ipv6_active_route["metric"] = None
|
||||
ipv6_active_route["metric_set_to_default"] = True
|
||||
|
||||
for ipv6_persistent_route in proc_data['ipv6_route_table']['persistent_routes']:
|
||||
ipv6_persistent_route["interface"] = jc.utils.convert_to_int(ipv6_persistent_route["interface"])
|
||||
|
||||
if ipv6_persistent_route["metric"] != "Default":
|
||||
ipv6_persistent_route["metric"] = jc.utils.convert_to_int(ipv6_persistent_route["metric"])
|
||||
ipv6_persistent_route["metric_set_to_default"] = False
|
||||
else:
|
||||
ipv6_persistent_route["metric"] = None
|
||||
ipv6_persistent_route["metric_set_to_default"] = True
|
||||
|
||||
return proc_data
|
||||
|
||||
|
||||
class _PushbackIterator:
|
||||
"""Iterator that allows pushing back values onto the iterator. Supports handing off
|
||||
parsing to localized parsers while maintaining line synchonization."""
|
||||
|
||||
def __init__(self, iterator):
|
||||
self.iterator = iterator
|
||||
self.pushback_stack = []
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
if self.pushback_stack:
|
||||
return self.pushback_stack.pop()
|
||||
else:
|
||||
return next(self.iterator)
|
||||
|
||||
def pushback(self, value):
|
||||
self.pushback_stack.append(value)
|
||||
|
||||
def contains(self, pattern):
|
||||
iter_lines = list(self.iterator)
|
||||
list_lines = self.pushback_stack.copy()
|
||||
list_lines.extend(iter_lines)
|
||||
self.iterator = iter(list_lines)
|
||||
self.pushback_stack = []
|
||||
|
||||
# Check the pushback stack first
|
||||
for line in list_lines:
|
||||
if re.match(pattern, line):
|
||||
return True
|
||||
return False
|
||||
|
||||
def skip_until(self, pattern):
|
||||
for line in self:
|
||||
if re.match(pattern, line):
|
||||
return line
|
||||
return None
|
||||
|
||||
|
||||
def _parse_interface_list(data, lines_iter):
|
||||
start_of_interface_list_pattern = r'^Interface List'
|
||||
if lines_iter.contains(start_of_interface_list_pattern):
|
||||
line = lines_iter.skip_until(start_of_interface_list_pattern)
|
||||
for line in lines_iter:
|
||||
if re.match(r'^=+$', line):
|
||||
break # End of interface list
|
||||
interface_index = line[:5].replace(".", "").strip()
|
||||
mac_address = line[5:30].replace(".","").strip()
|
||||
description = line[30:].strip()
|
||||
data['interface_list'].append({
|
||||
"interface_index": interface_index,
|
||||
"mac_address": mac_address,
|
||||
"description": description
|
||||
})
|
||||
|
||||
def _parse_ipv4_route_table(data, lines_iter):
|
||||
def _parse_ipv4_active_routes(data, lines_iter):
|
||||
line = lines_iter.skip_until(r'^Active Routes')
|
||||
line = next(lines_iter, '') # Skip the header line
|
||||
if line.strip() == 'None':
|
||||
return
|
||||
for line in lines_iter:
|
||||
if re.match(r'^=+$', line):
|
||||
break # End of interface list
|
||||
if 'Default Gateway' in line:
|
||||
continue
|
||||
lines_split = line.split()
|
||||
network_destination = lines_split[0]
|
||||
netmask = lines_split[1]
|
||||
gateway = lines_split[2]
|
||||
interface = lines_split[3]
|
||||
metric = lines_split[4]
|
||||
data['ipv4_route_table']["active_routes"].append({
|
||||
"network_destination": network_destination,
|
||||
"netmask": netmask,
|
||||
"gateway": gateway,
|
||||
"interface": interface,
|
||||
"metric": metric
|
||||
})
|
||||
|
||||
def _parse_ipv4_persistent_routes(data, lines_iter):
|
||||
line = lines_iter.skip_until(r'^Persistent Routes')
|
||||
line = next(lines_iter, '') # line is either "None" and we abort parsing this section or we skip header line
|
||||
if line.strip() == 'None':
|
||||
return
|
||||
for line in lines_iter:
|
||||
if re.match(r'^=+$', line):
|
||||
break
|
||||
lines_split = line.split()
|
||||
network_address = lines_split[0]
|
||||
netmask = lines_split[1]
|
||||
gateway_address = lines_split[2]
|
||||
metric = lines_split[3]
|
||||
data['ipv4_route_table']["persistent_routes"].append({
|
||||
"network_address": network_address,
|
||||
"netmask": netmask,
|
||||
"gateway_address": gateway_address,
|
||||
"metric": metric
|
||||
})
|
||||
|
||||
start_of_ipv4_route_table_pattern = r'^IPv4 Route Table'
|
||||
if lines_iter.contains(start_of_ipv4_route_table_pattern):
|
||||
line = lines_iter.skip_until(start_of_ipv4_route_table_pattern)
|
||||
line = next(lines_iter, '') # Skip the separator line
|
||||
_parse_ipv4_active_routes(data, lines_iter)
|
||||
_parse_ipv4_persistent_routes(data, lines_iter)
|
||||
|
||||
def _parse_ipv6_route_table(data, lines_iter):
|
||||
def _parse_ipv6_active_routes(data, lines_iter):
|
||||
line = lines_iter.skip_until(r'^Active Routes')
|
||||
line = next(lines_iter, '') # line is either "None" and we abort parsing this section or we skip header line
|
||||
if line.strip() == 'None':
|
||||
return
|
||||
for line in lines_iter:
|
||||
if re.match(r'^=+$', line):
|
||||
break
|
||||
split_line = line.split()
|
||||
interface = split_line[0]
|
||||
metric = split_line[1]
|
||||
network_destination = split_line[2]
|
||||
if len(split_line) > 3:
|
||||
gateway = split_line[3]
|
||||
else:
|
||||
gateway = next(lines_iter, '').strip()
|
||||
data['ipv6_route_table']["active_routes"].append({
|
||||
"interface": interface,
|
||||
"metric": metric,
|
||||
"network_destination": network_destination,
|
||||
"gateway": gateway
|
||||
})
|
||||
|
||||
def _parse_ipv6_persistent_routes(data, lines_iter):
|
||||
line = lines_iter.skip_until(r'^Persistent Routes')
|
||||
line = next(lines_iter, '') # line is either "None" and we abort parsing this section or we skip header line
|
||||
if line.strip() == 'None':
|
||||
return
|
||||
for line in lines_iter:
|
||||
if re.match(r'^=+$', line):
|
||||
break
|
||||
split_line = line.split()
|
||||
interface = split_line[0]
|
||||
metric = split_line[1]
|
||||
network_destination = split_line[2]
|
||||
if len(split_line) > 3:
|
||||
gateway = split_line[3]
|
||||
else:
|
||||
gateway = next(lines_iter, '').strip()
|
||||
data['ipv6_route_table']["persistent_routes"].append({
|
||||
"interface": interface,
|
||||
"metric": metric,
|
||||
"network_destination": network_destination,
|
||||
"gateway": gateway
|
||||
})
|
||||
|
||||
start_of_ipv6_route_table_pattern = r'^IPv6 Route Table'
|
||||
if lines_iter.contains(start_of_ipv6_route_table_pattern):
|
||||
line = lines_iter.skip_until(start_of_ipv6_route_table_pattern)
|
||||
line = next(lines_iter, '') # Skip the separator line
|
||||
_parse_ipv6_active_routes(data, lines_iter)
|
||||
_parse_ipv6_persistent_routes(data, lines_iter)
|
||||
@@ -4,6 +4,8 @@ Supports the `-i` or `--itemize-changes` options with all levels of
|
||||
verbosity. This parser will process the `STDOUT` output or a log file
|
||||
generated with the `--log-file` option.
|
||||
|
||||
The `--stats` or `--info=stats[1-3]` options are also supported.
|
||||
|
||||
Usage (cli):
|
||||
|
||||
$ rsync -i -a source/ dest | jc --rsync
|
||||
@@ -37,7 +39,21 @@ Schema:
|
||||
"false_alarms": integer,
|
||||
"data": integer,
|
||||
"bytes_sec": float,
|
||||
"speedup": float
|
||||
"speedup": float,
|
||||
"total_files": integer,
|
||||
"regular_files": integer,
|
||||
"dir_files": integer,
|
||||
"total_created_files": integer,
|
||||
"created_regular_files": integer,
|
||||
"created_dir_files": integer,
|
||||
"deleted_files": integer,
|
||||
"transferred_files": integer,
|
||||
"transferred_file_size": integer,
|
||||
"literal_data": integer,
|
||||
"matched_data": integer,
|
||||
"file_list_size": integer,
|
||||
"file_list_generation_time": float,
|
||||
"file_list_transfer_time": float,
|
||||
},
|
||||
"files": [
|
||||
{
|
||||
@@ -62,6 +78,8 @@ Schema:
|
||||
}
|
||||
]
|
||||
|
||||
Size values are in bytes.
|
||||
|
||||
[0] 'file sent', 'file received', 'local change or creation',
|
||||
'hard link', 'not updated', 'message'
|
||||
[1] 'file', 'directory', 'symlink', 'device', 'special file'
|
||||
@@ -137,7 +155,7 @@ import jc.utils
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.2'
|
||||
version = '1.3'
|
||||
description = '`rsync` command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -163,10 +181,16 @@ def _process(proc_data: List[Dict]) -> List[Dict]:
|
||||
"""
|
||||
int_list = {
|
||||
'process', 'sent', 'received', 'total_size', 'matches', 'hash_hits',
|
||||
'false_alarms', 'data'
|
||||
'false_alarms', 'data', 'total_files', 'regular_files', 'dir_files',
|
||||
'total_created_files', 'created_regular_files', 'created_dir_files',
|
||||
'deleted_files', 'transferred_files', 'transferred_file_size',
|
||||
'literal_data', 'matched_data', 'file_list_size'
|
||||
}
|
||||
|
||||
float_list = {'bytes_sec', 'speedup'}
|
||||
float_list = {
|
||||
'bytes_sec', 'speedup', 'file_list_generation_time',
|
||||
'file_list_transfer_time'
|
||||
}
|
||||
|
||||
for item in proc_data:
|
||||
for key in item['summary']:
|
||||
@@ -338,6 +362,17 @@ def parse(
|
||||
stat2_line_log_v_re = re.compile(r'(?P<date>\d\d\d\d/\d\d/\d\d)\s+(?P<time>\d\d:\d\d:\d\d)\s+\[(?P<process>\d+)\]\s+sent\s+(?P<sent>[\d,]+)\s+bytes\s+received\s+(?P<received>[\d,]+)\s+bytes\s+(?P<bytes_sec>[\d,.]+)\s+bytes/sec')
|
||||
stat3_line_log_v_re = re.compile(r'(?P<date>\d\d\d\d/\d\d/\d\d)\s+(?P<time>\d\d:\d\d:\d\d)\s+\[(?P<process>\d+)]\s+total\s+size\s+is\s+(?P<total_size>[\d,]+)\s+speedup\s+is\s+(?P<speedup>[\d,.]+)')
|
||||
|
||||
stat_ex_files_number_re = re.compile(r'Number\sof\sfiles:\s(?P<files_total>[,0123456789]+)\s\(reg:\s(?P<files_regular>[,0123456789]+),\sdir:\s(?P<files_dir>[,0123456789]+)\)$')
|
||||
stat_ex_files_created_re = re.compile(r'Number\sof\screated\sfiles:\s(?P<files_created_total>[,0123456789]+)\s\(reg:\s(?P<files_created_regular>[,0123456789]+),\sdir:\s(?P<files_created_dir>[,0123456789]+)\)$')
|
||||
stat_ex_files_deleted_re = re.compile(r'Number\sof\sdeleted\sfiles:\s(?P<files_deleted>[,0123456789]+)$')
|
||||
stat_ex_files_transferred_re = re.compile(r'Number\sof\sregular\sfiles\stransferred:\s(?P<files_transferred>[,0123456789]+)$')
|
||||
stat_ex_files_transferred_size_re = re.compile(r'Total\sfile\ssize:\s(?P<files_transferred_size>[,.0123456789]+\S?)\sbytes$')
|
||||
stat_ex_literal_data_re = re.compile(r'Literal\sdata:\s(?P<literal_data>[,.0123456789]+\S?)\sbytes$')
|
||||
stat_ex_matched_data_re = re.compile(r'Matched\sdata:\s(?P<matched_data>[,.0123456789]+\S?)\sbytes$')
|
||||
stat_ex_file_list_size_re = re.compile(r'File\slist\ssize:\s(?P<file_list_size>[,.0123456789]+\S?)$')
|
||||
stat_ex_file_list_generation_time_re = re.compile(r'File\slist\sgeneration\stime:\s(?P<file_list_generation_time>[,.0123456789]+\S?)\sseconds$')
|
||||
stat_ex_file_list_transfer_time_re = re.compile(r'File\slist\stransfer\stime:\s(?P<file_list_transfer_time>[,.0123456789]+\S?)\sseconds$')
|
||||
|
||||
if jc.utils.has_data(data):
|
||||
for line in filter(None, data.splitlines()):
|
||||
|
||||
@@ -451,11 +486,11 @@ def parse(
|
||||
|
||||
stat1_line = stat1_line_re.match(line)
|
||||
if stat1_line:
|
||||
rsync_run['summary'] = {
|
||||
rsync_run['summary'].update({
|
||||
'sent': stat1_line.group('sent'),
|
||||
'received': stat1_line.group('received'),
|
||||
'bytes_sec': stat1_line.group('bytes_sec')
|
||||
}
|
||||
})
|
||||
continue
|
||||
|
||||
stat2_line = stat2_line_re.match(line)
|
||||
@@ -466,11 +501,11 @@ def parse(
|
||||
|
||||
stat1_line_simple = stat1_line_simple_re.match(line)
|
||||
if stat1_line_simple:
|
||||
rsync_run['summary'] = {
|
||||
rsync_run['summary'].update({
|
||||
'sent': stat1_line_simple.group('sent'),
|
||||
'received': stat1_line_simple.group('received'),
|
||||
'bytes_sec': stat1_line_simple.group('bytes_sec')
|
||||
}
|
||||
})
|
||||
continue
|
||||
|
||||
stat2_line_simple = stat2_line_simple_re.match(line)
|
||||
@@ -481,19 +516,19 @@ def parse(
|
||||
|
||||
stat_line_log = stat_line_log_re.match(line)
|
||||
if stat_line_log:
|
||||
rsync_run['summary'] = {
|
||||
rsync_run['summary'].update({
|
||||
'date': stat_line_log.group('date'),
|
||||
'time': stat_line_log.group('time'),
|
||||
'process': stat_line_log.group('process'),
|
||||
'sent': stat_line_log.group('sent'),
|
||||
'received': stat_line_log.group('received'),
|
||||
'total_size': stat_line_log.group('total_size')
|
||||
}
|
||||
})
|
||||
continue
|
||||
|
||||
stat1_line_log_v = stat1_line_log_v_re.match(line)
|
||||
if stat1_line_log_v:
|
||||
rsync_run['summary'] = {
|
||||
rsync_run['summary'].update({
|
||||
'date': stat1_line_log_v.group('date'),
|
||||
'time': stat1_line_log_v.group('time'),
|
||||
'process': stat1_line_log_v.group('process'),
|
||||
@@ -501,7 +536,7 @@ def parse(
|
||||
'hash_hits': stat1_line_log_v.group('hash_hits'),
|
||||
'false_alarms': stat1_line_log_v.group('false_alarms'),
|
||||
'data': stat1_line_log_v.group('data')
|
||||
}
|
||||
})
|
||||
continue
|
||||
|
||||
stat2_line_log_v = stat2_line_log_v_re.match(line)
|
||||
@@ -517,6 +552,61 @@ def parse(
|
||||
rsync_run['summary']['speedup'] = stat3_line_log_v.group('speedup')
|
||||
continue
|
||||
|
||||
# extra stats lines when using rsync --stats or --info=stats[1-3]
|
||||
stat_ex_files_number_v = stat_ex_files_number_re.match(line)
|
||||
if stat_ex_files_number_v:
|
||||
rsync_run['summary']['total_files'] = stat_ex_files_number_v.group('files_total')
|
||||
rsync_run['summary']['regular_files'] = stat_ex_files_number_v.group('files_regular')
|
||||
rsync_run['summary']['dir_files'] = stat_ex_files_number_v.group('files_dir')
|
||||
continue
|
||||
|
||||
stat_ex_files_created_v = stat_ex_files_created_re.match(line)
|
||||
if stat_ex_files_created_v:
|
||||
rsync_run['summary']['total_created_files'] = stat_ex_files_created_v.group('files_created_total')
|
||||
rsync_run['summary']['created_regular_files'] = stat_ex_files_created_v.group('files_created_regular')
|
||||
rsync_run['summary']['created_dir_files'] = stat_ex_files_created_v.group('files_created_dir')
|
||||
continue
|
||||
|
||||
stat_ex_files_deleted_v = stat_ex_files_deleted_re.match(line)
|
||||
if stat_ex_files_deleted_v:
|
||||
rsync_run['summary']['deleted_files'] = stat_ex_files_deleted_v.group('files_deleted')
|
||||
continue
|
||||
|
||||
stat_ex_files_transferred_v = stat_ex_files_transferred_re.match(line)
|
||||
if stat_ex_files_transferred_v:
|
||||
rsync_run['summary']['transferred_files'] = stat_ex_files_transferred_v.group('files_transferred')
|
||||
continue
|
||||
|
||||
stat_ex_files_transferred_size_v = stat_ex_files_transferred_size_re.match(line)
|
||||
if stat_ex_files_transferred_size_v:
|
||||
rsync_run['summary']['transferred_file_size'] = stat_ex_files_transferred_size_v.group('files_transferred_size')
|
||||
continue
|
||||
|
||||
stat_ex_literal_data_v = stat_ex_literal_data_re.match(line)
|
||||
if stat_ex_literal_data_v:
|
||||
rsync_run['summary']['literal_data'] = stat_ex_literal_data_v.group('literal_data')
|
||||
continue
|
||||
|
||||
stat_ex_matched_data_v = stat_ex_matched_data_re.match(line)
|
||||
if stat_ex_matched_data_v:
|
||||
rsync_run['summary']['matched_data'] = stat_ex_matched_data_v.group('matched_data')
|
||||
continue
|
||||
|
||||
stat_ex_file_list_size_v = stat_ex_file_list_size_re.match(line)
|
||||
if stat_ex_file_list_size_v:
|
||||
rsync_run['summary']['file_list_size'] = stat_ex_file_list_size_v.group('file_list_size')
|
||||
continue
|
||||
|
||||
stat_ex_file_list_generation_time_v = stat_ex_file_list_generation_time_re.match(line)
|
||||
if stat_ex_file_list_generation_time_v:
|
||||
rsync_run['summary']['file_list_generation_time'] = stat_ex_file_list_generation_time_v.group('file_list_generation_time')
|
||||
continue
|
||||
|
||||
stat_ex_file_list_transfer_time_v = stat_ex_file_list_transfer_time_re.match(line)
|
||||
if stat_ex_file_list_transfer_time_v:
|
||||
rsync_run['summary']['file_list_transfer_time'] = stat_ex_file_list_transfer_time_v.group('file_list_transfer_time')
|
||||
continue
|
||||
|
||||
raw_output.append(rsync_run)
|
||||
|
||||
# cleanup blank entries
|
||||
|
||||
@@ -7,6 +7,8 @@ Supports the `-i` or `--itemize-changes` options with all levels of
|
||||
verbosity. This parser will process the `STDOUT` output or a log file
|
||||
generated with the `--log-file` option.
|
||||
|
||||
The `--stats` or `--info=stats[1-3]` options are also supported.
|
||||
|
||||
Usage (cli):
|
||||
|
||||
$ rsync -i -a source/ dest | jc --rsync-s
|
||||
@@ -64,6 +66,8 @@ Schema:
|
||||
}
|
||||
}
|
||||
|
||||
Size values are in bytes.
|
||||
|
||||
[0] 'file sent', 'file received', 'local change or creation',
|
||||
'hard link', 'not updated', 'message'
|
||||
[1] 'file', 'directory', 'symlink', 'device', 'special file'
|
||||
@@ -88,7 +92,7 @@ from jc.streaming import (
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.3'
|
||||
version = '1.4'
|
||||
description = '`rsync` command streaming parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -114,10 +118,16 @@ def _process(proc_data: Dict) -> Dict:
|
||||
"""
|
||||
int_list = {
|
||||
'process', 'sent', 'received', 'total_size', 'matches', 'hash_hits',
|
||||
'false_alarms', 'data'
|
||||
'false_alarms', 'data', 'total_files', 'regular_files', 'dir_files',
|
||||
'total_created_files', 'created_regular_files', 'created_dir_files',
|
||||
'deleted_files', 'transferred_files', 'transferred_file_size',
|
||||
'literal_data', 'matched_data', 'file_list_size'
|
||||
}
|
||||
|
||||
float_list = {'bytes_sec', 'speedup'}
|
||||
float_list = {
|
||||
'bytes_sec', 'speedup', 'file_list_generation_time',
|
||||
'file_list_transfer_time'
|
||||
}
|
||||
|
||||
for key in proc_data.copy():
|
||||
if key in int_list:
|
||||
@@ -281,6 +291,17 @@ def parse(
|
||||
stat2_line_log_v_re = re.compile(r'(?P<date>\d\d\d\d/\d\d/\d\d)\s+(?P<time>\d\d:\d\d:\d\d)\s+\[(?P<process>\d+)\]\s+sent\s+(?P<sent>[\d,]+)\s+bytes\s+received\s+(?P<received>[\d,]+)\s+bytes\s+(?P<bytes_sec>[\d,.]+)\s+bytes/sec')
|
||||
stat3_line_log_v_re = re.compile(r'(?P<date>\d\d\d\d/\d\d/\d\d)\s+(?P<time>\d\d:\d\d:\d\d)\s+\[(?P<process>\d+)]\s+total\s+size\s+is\s+(?P<total_size>[\d,]+)\s+speedup\s+is\s+(?P<speedup>[\d,.]+)')
|
||||
|
||||
stat_ex_files_number_re = re.compile(r'Number\sof\sfiles:\s(?P<files_total>[,0123456789]+)\s\(reg:\s(?P<files_regular>[,0123456789]+),\sdir:\s(?P<files_dir>[,0123456789]+)\)$')
|
||||
stat_ex_files_created_re = re.compile(r'Number\sof\screated\sfiles:\s(?P<files_created_total>[,0123456789]+)\s\(reg:\s(?P<files_created_regular>[,0123456789]+),\sdir:\s(?P<files_created_dir>[,0123456789]+)\)$')
|
||||
stat_ex_files_deleted_re = re.compile(r'Number\sof\sdeleted\sfiles:\s(?P<files_deleted>[,0123456789]+)$')
|
||||
stat_ex_files_transferred_re = re.compile(r'Number\sof\sregular\sfiles\stransferred:\s(?P<files_transferred>[,0123456789]+)$')
|
||||
stat_ex_files_transferred_size_re = re.compile(r'Total\sfile\ssize:\s(?P<files_transferred_size>[,.0123456789]+\S?)\sbytes$')
|
||||
stat_ex_literal_data_re = re.compile(r'Literal\sdata:\s(?P<literal_data>[,.0123456789]+\S?)\sbytes$')
|
||||
stat_ex_matched_data_re = re.compile(r'Matched\sdata:\s(?P<matched_data>[,.0123456789]+\S?)\sbytes$')
|
||||
stat_ex_file_list_size_re = re.compile(r'File\slist\ssize:\s(?P<file_list_size>[,.0123456789]+\S?)$')
|
||||
stat_ex_file_list_generation_time_re = re.compile(r'File\slist\sgeneration\stime:\s(?P<file_list_generation_time>[,.0123456789]+\S?)\sseconds$')
|
||||
stat_ex_file_list_transfer_time_re = re.compile(r'File\slist\stransfer\stime:\s(?P<file_list_transfer_time>[,.0123456789]+\S?)\sseconds$')
|
||||
|
||||
for line in data:
|
||||
try:
|
||||
streaming_line_input_type_check(line)
|
||||
@@ -408,12 +429,12 @@ def parse(
|
||||
|
||||
stat1_line = stat1_line_re.match(line)
|
||||
if stat1_line:
|
||||
summary = {
|
||||
summary.update({
|
||||
'type': 'summary',
|
||||
'sent': stat1_line.group('sent'),
|
||||
'received': stat1_line.group('received'),
|
||||
'bytes_sec': stat1_line.group('bytes_sec')
|
||||
}
|
||||
})
|
||||
continue
|
||||
|
||||
stat2_line = stat2_line_re.match(line)
|
||||
@@ -424,12 +445,12 @@ def parse(
|
||||
|
||||
stat1_line_simple = stat1_line_simple_re.match(line)
|
||||
if stat1_line_simple:
|
||||
summary = {
|
||||
summary.update({
|
||||
'type': 'summary',
|
||||
'sent': stat1_line_simple.group('sent'),
|
||||
'received': stat1_line_simple.group('received'),
|
||||
'bytes_sec': stat1_line_simple.group('bytes_sec')
|
||||
}
|
||||
})
|
||||
continue
|
||||
|
||||
stat2_line_simple = stat2_line_simple_re.match(line)
|
||||
@@ -440,7 +461,7 @@ def parse(
|
||||
|
||||
stat_line_log = stat_line_log_re.match(line)
|
||||
if stat_line_log:
|
||||
summary = {
|
||||
summary.update({
|
||||
'type': 'summary',
|
||||
'date': stat_line_log.group('date'),
|
||||
'time': stat_line_log.group('time'),
|
||||
@@ -448,12 +469,12 @@ def parse(
|
||||
'sent': stat_line_log.group('sent'),
|
||||
'received': stat_line_log.group('received'),
|
||||
'total_size': stat_line_log.group('total_size')
|
||||
}
|
||||
})
|
||||
continue
|
||||
|
||||
stat1_line_log_v = stat1_line_log_v_re.match(line)
|
||||
if stat1_line_log_v:
|
||||
summary = {
|
||||
summary.update({
|
||||
'type': 'summary',
|
||||
'date': stat1_line_log_v.group('date'),
|
||||
'time': stat1_line_log_v.group('time'),
|
||||
@@ -462,7 +483,7 @@ def parse(
|
||||
'hash_hits': stat1_line_log_v.group('hash_hits'),
|
||||
'false_alarms': stat1_line_log_v.group('false_alarms'),
|
||||
'data': stat1_line_log_v.group('data')
|
||||
}
|
||||
})
|
||||
continue
|
||||
|
||||
stat2_line_log_v = stat2_line_log_v_re.match(line)
|
||||
@@ -478,6 +499,61 @@ def parse(
|
||||
summary['speedup'] = stat3_line_log_v.group('speedup')
|
||||
continue
|
||||
|
||||
# extra stats lines when using rsync --stats or --info=stats[1-3]
|
||||
stat_ex_files_number_v = stat_ex_files_number_re.match(line)
|
||||
if stat_ex_files_number_v:
|
||||
summary['total_files'] = stat_ex_files_number_v.group('files_total')
|
||||
summary['regular_files'] = stat_ex_files_number_v.group('files_regular')
|
||||
summary['dir_files'] = stat_ex_files_number_v.group('files_dir')
|
||||
continue
|
||||
|
||||
stat_ex_files_created_v = stat_ex_files_created_re.match(line)
|
||||
if stat_ex_files_created_v:
|
||||
summary['total_created_files'] = stat_ex_files_created_v.group('files_created_total')
|
||||
summary['created_regular_files'] = stat_ex_files_created_v.group('files_created_regular')
|
||||
summary['created_dir_files'] = stat_ex_files_created_v.group('files_created_dir')
|
||||
continue
|
||||
|
||||
stat_ex_files_deleted_v = stat_ex_files_deleted_re.match(line)
|
||||
if stat_ex_files_deleted_v:
|
||||
summary['deleted_files'] = stat_ex_files_deleted_v.group('files_deleted')
|
||||
continue
|
||||
|
||||
stat_ex_files_transferred_v = stat_ex_files_transferred_re.match(line)
|
||||
if stat_ex_files_transferred_v:
|
||||
summary['transferred_files'] = stat_ex_files_transferred_v.group('files_transferred')
|
||||
continue
|
||||
|
||||
stat_ex_files_transferred_size_v = stat_ex_files_transferred_size_re.match(line)
|
||||
if stat_ex_files_transferred_size_v:
|
||||
summary['transferred_file_size'] = stat_ex_files_transferred_size_v.group('files_transferred_size')
|
||||
continue
|
||||
|
||||
stat_ex_literal_data_v = stat_ex_literal_data_re.match(line)
|
||||
if stat_ex_literal_data_v:
|
||||
summary['literal_data'] = stat_ex_literal_data_v.group('literal_data')
|
||||
continue
|
||||
|
||||
stat_ex_matched_data_v = stat_ex_matched_data_re.match(line)
|
||||
if stat_ex_matched_data_v:
|
||||
summary['matched_data'] = stat_ex_matched_data_v.group('matched_data')
|
||||
continue
|
||||
|
||||
stat_ex_file_list_size_v = stat_ex_file_list_size_re.match(line)
|
||||
if stat_ex_file_list_size_v:
|
||||
summary['file_list_size'] = stat_ex_file_list_size_v.group('file_list_size')
|
||||
continue
|
||||
|
||||
stat_ex_file_list_generation_time_v = stat_ex_file_list_generation_time_re.match(line)
|
||||
if stat_ex_file_list_generation_time_v:
|
||||
summary['file_list_generation_time'] = stat_ex_file_list_generation_time_v.group('file_list_generation_time')
|
||||
continue
|
||||
|
||||
stat_ex_file_list_transfer_time_v = stat_ex_file_list_transfer_time_re.match(line)
|
||||
if stat_ex_file_list_transfer_time_v:
|
||||
summary['file_list_transfer_time'] = stat_ex_file_list_transfer_time_v.group('file_list_transfer_time')
|
||||
continue
|
||||
|
||||
except Exception as e:
|
||||
yield raise_or_yield(ignore_exceptions, e, line)
|
||||
|
||||
@@ -488,3 +564,6 @@ def parse(
|
||||
|
||||
except Exception as e:
|
||||
yield raise_or_yield(ignore_exceptions, e, '')
|
||||
|
||||
# unused return for Mypy
|
||||
return []
|
||||
|
||||
@@ -45,23 +45,31 @@ All `-` values are converted to `null`
|
||||
"cpu_hardware": float,
|
||||
"cpu_software": float,
|
||||
"cpu_steal": float,
|
||||
"mem_total": float, # [0]
|
||||
"mem_free": float, # [0]
|
||||
"mem_used": float, # [0]
|
||||
"mem_buff_cache": float, # [0]
|
||||
"swap_total": float, # [0]
|
||||
"swap_free": float, # [0]
|
||||
"swap_used": float, # [0]
|
||||
"mem_available": float, # [0]
|
||||
"mem_unit": string,
|
||||
"mem_total": float,
|
||||
"mem_free": float,
|
||||
"mem_used": float,
|
||||
"mem_buff_cache": float,
|
||||
"swap_unit": string,
|
||||
"swap_total": float,
|
||||
"swap_free": float,
|
||||
"swap_used": float,
|
||||
"mem_available": float,
|
||||
"processes": [
|
||||
{
|
||||
"pid": integer,
|
||||
"user": string,
|
||||
"priority": integer,
|
||||
"nice": integer,
|
||||
"virtual_mem": float, # [1]
|
||||
"resident_mem": float, # [1]
|
||||
"shared_mem": float, # [1]
|
||||
"virtual_mem": float,
|
||||
"virtual_mem_bytes": integer,
|
||||
"virtual_mem_unit": string,
|
||||
"resident_mem": float,
|
||||
"resident_mem_bytes": integer,
|
||||
"resident_mem_unit": string,
|
||||
"shared_mem": float,
|
||||
"shared_mem_bytes": integer,
|
||||
"shared_mem_unit": string,
|
||||
"status": string,
|
||||
"percent_cpu": float,
|
||||
"percent_mem": float,
|
||||
@@ -82,9 +90,15 @@ All `-` values are converted to `null`
|
||||
"thread_count": integer,
|
||||
"last_used_processor": integer,
|
||||
"time": string,
|
||||
"swap": float, # [1]
|
||||
"code": float, # [1]
|
||||
"data": float, # [1]
|
||||
"swap": float,
|
||||
"swap_bytes": integer,
|
||||
"swap_unit": string,
|
||||
"code": float,
|
||||
"code_bytes": integer,
|
||||
"code_unit": string,
|
||||
"data": float,
|
||||
"data_bytes": integer,
|
||||
"data_unit": string,
|
||||
"major_page_fault_count": integer,
|
||||
"minor_page_fault_count": integer,
|
||||
"dirty_pages_count": integer,
|
||||
@@ -103,7 +117,9 @@ All `-` values are converted to `null`
|
||||
]
|
||||
"major_page_fault_count_delta": integer,
|
||||
"minor_page_fault_count_delta": integer,
|
||||
"used": float, # [1]
|
||||
"used": float,
|
||||
"used_bytes": integer,
|
||||
"used_unit": string,
|
||||
"ipc_namespace_inode": integer,
|
||||
"mount_namespace_inode": integer,
|
||||
"net_namespace_inode": integer,
|
||||
@@ -124,9 +140,6 @@ All `-` values are converted to `null`
|
||||
}
|
||||
]
|
||||
|
||||
[0] Values are in the units output by `top`
|
||||
[1] Unit suffix stripped during float conversion
|
||||
|
||||
Examples:
|
||||
|
||||
$ top -b -n 3 | jc --top -p
|
||||
@@ -316,7 +329,7 @@ from jc.parsers.universal import sparse_table_parse as parse_table
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.2'
|
||||
version = '1.3'
|
||||
description = '`top -b` command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -440,13 +453,25 @@ def _process(proc_data: List[Dict], quiet=False) -> List[Dict]:
|
||||
'mem_available', 'virtual_mem', 'resident_mem', 'shared_mem', 'swap', 'code', 'data', 'used'
|
||||
}
|
||||
|
||||
bytes_list: Set = {
|
||||
'mem_total', 'mem_free', 'mem_used', 'mem_available', 'mem_buff_cache',
|
||||
'swap_total', 'swap_free', 'swap_used', 'virtual_mem', 'resident_mem',
|
||||
'shared_mem', 'swap', 'code', 'data', 'used'
|
||||
}
|
||||
|
||||
for idx, item in enumerate(proc_data):
|
||||
for key in item:
|
||||
for key in item.copy():
|
||||
# root truncation warnings
|
||||
if isinstance(item[key], str) and item[key].endswith('+') and not quiet:
|
||||
jc.utils.warning_message([f'item[{idx}]["{key}"] was truncated by top'])
|
||||
|
||||
# root int and float conversions
|
||||
if key in bytes_list:
|
||||
if key.startswith('mem_'):
|
||||
item[key + '_bytes'] = jc.utils.convert_size_to_int(item[key] + item['mem_unit'])
|
||||
if key.startswith('swap_'):
|
||||
item[key + '_bytes'] = jc.utils.convert_size_to_int(item[key] + item['swap_unit'])
|
||||
|
||||
if key in int_list:
|
||||
item[key] = jc.utils.convert_to_int(item[key])
|
||||
|
||||
@@ -463,7 +488,8 @@ def _process(proc_data: List[Dict], quiet=False) -> List[Dict]:
|
||||
jc.utils.warning_message([f'Unknown field detected at item[{idx}]["processes"]: {old_key}'])
|
||||
|
||||
# cleanup values
|
||||
for key in proc.keys():
|
||||
proc_copy = proc.copy()
|
||||
for key in proc_copy.keys():
|
||||
|
||||
# set dashes to nulls
|
||||
if proc[key] == '-':
|
||||
@@ -482,6 +508,13 @@ def _process(proc_data: List[Dict], quiet=False) -> List[Dict]:
|
||||
|
||||
# do int/float conversions for the process objects
|
||||
if proc[key]:
|
||||
if key in bytes_list:
|
||||
if proc[key][-1] not in ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'):
|
||||
proc[key + '_unit'] = proc[key][-1]
|
||||
else:
|
||||
proc[key + '_unit'] = 'b'
|
||||
proc[key + '_bytes'] = jc.utils.convert_size_to_int(proc[key], posix_mode=True)
|
||||
|
||||
if key in int_list:
|
||||
proc[key] = jc.utils.convert_to_int(proc[key])
|
||||
|
||||
@@ -604,6 +637,7 @@ def parse(
|
||||
line_list = line.split()
|
||||
item_obj.update(
|
||||
{
|
||||
'mem_unit': line_list[0],
|
||||
'mem_total': line_list[3],
|
||||
'mem_free': line_list[5],
|
||||
'mem_used': line_list[7],
|
||||
@@ -617,6 +651,7 @@ def parse(
|
||||
line_list = line.split()
|
||||
item_obj.update(
|
||||
{
|
||||
'swap_unit': line_list[0],
|
||||
'swap_total': line_list[2],
|
||||
'swap_free': line_list[4],
|
||||
'swap_used': line_list[6],
|
||||
|
||||
@@ -43,23 +43,39 @@ Schema:
|
||||
"cpu_hardware": float,
|
||||
"cpu_software": float,
|
||||
"cpu_steal": float,
|
||||
"mem_total": float, # [0]
|
||||
"mem_free": float, # [0]
|
||||
"mem_used": float, # [0]
|
||||
"mem_buff_cache": float, # [0]
|
||||
"swap_total": float, # [0]
|
||||
"swap_free": float, # [0]
|
||||
"swap_used": float, # [0]
|
||||
"mem_available": float, # [0]
|
||||
"mem_unit": string,
|
||||
"swap_unit": string,
|
||||
"mem_total": float,
|
||||
"mem_total_bytes": integer,
|
||||
"mem_free": float,
|
||||
"mem_free_bytes": integer,
|
||||
"mem_used": float,
|
||||
"mem_used_bytes": integer,
|
||||
"mem_buff_cache": float,
|
||||
"mem_buff_cache_bytes": integer,
|
||||
"swap_total": float,
|
||||
"swap_total_bytes": integer,
|
||||
"swap_free": float,
|
||||
"swap_free_bytes": integer,
|
||||
"swap_used": float,
|
||||
"swap_used_bytes": integer,
|
||||
"mem_available": float,
|
||||
"mem_available_bytes": integer,
|
||||
"processes": [
|
||||
{
|
||||
"pid": integer,
|
||||
"user": string,
|
||||
"priority": integer,
|
||||
"nice": integer,
|
||||
"virtual_mem": float, # [1]
|
||||
"resident_mem": float, # [1]
|
||||
"shared_mem": float, # [1]
|
||||
"virtual_mem": float,
|
||||
"virtual_mem_unit": string,
|
||||
"virtual_mem_bytes": integer,
|
||||
"resident_mem": float,
|
||||
"resident_mem_unit": string,
|
||||
"resident_mem_bytes": integer,
|
||||
"shared_mem": float,
|
||||
"shared_mem_unit": string,
|
||||
"shared_mem_bytes": integer,
|
||||
"status": string,
|
||||
"percent_cpu": float,
|
||||
"percent_mem": float,
|
||||
@@ -80,9 +96,15 @@ Schema:
|
||||
"thread_count": integer,
|
||||
"last_used_processor": integer,
|
||||
"time": string,
|
||||
"swap": float, # [1]
|
||||
"code": float, # [1]
|
||||
"data": float, # [1]
|
||||
"swap": float,
|
||||
"swap_unit": string,
|
||||
"swap_bytes": integer,
|
||||
"code": float,
|
||||
"code_unit": string,
|
||||
"code_bytes": integer
|
||||
"data": float,
|
||||
"data_unit": string,
|
||||
"data_bytes": integer,
|
||||
"major_page_fault_count": integer,
|
||||
"minor_page_fault_count": integer,
|
||||
"dirty_pages_count": integer,
|
||||
@@ -101,7 +123,9 @@ Schema:
|
||||
]
|
||||
"major_page_fault_count_delta": integer,
|
||||
"minor_page_fault_count_delta": integer,
|
||||
"used": float, # [1]
|
||||
"used": float,
|
||||
"used_unit": string,
|
||||
"used_bytes": integer,
|
||||
"ipc_namespace_inode": integer,
|
||||
"mount_namespace_inode": integer,
|
||||
"net_namespace_inode": integer,
|
||||
@@ -128,9 +152,6 @@ Schema:
|
||||
}
|
||||
}
|
||||
|
||||
[0] Values are in the units output by `top`
|
||||
[1] Unit suffix stripped during float conversion
|
||||
|
||||
Examples:
|
||||
|
||||
$ top -b | jc --top-s
|
||||
@@ -153,7 +174,7 @@ from jc.parsers.universal import sparse_table_parse as parse_table
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.2'
|
||||
version = '1.3'
|
||||
description = '`top -b` command streaming parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -277,12 +298,24 @@ def _process(proc_data: Dict, idx=0, quiet=False) -> Dict:
|
||||
'mem_available', 'virtual_mem', 'resident_mem', 'shared_mem', 'swap', 'code', 'data', 'used'
|
||||
}
|
||||
|
||||
for key in proc_data:
|
||||
bytes_list: Set = {
|
||||
'mem_total', 'mem_free', 'mem_used', 'mem_available', 'mem_buff_cache',
|
||||
'swap_total', 'swap_free', 'swap_used', 'virtual_mem', 'resident_mem',
|
||||
'shared_mem', 'swap', 'code', 'data', 'used'
|
||||
}
|
||||
|
||||
for key in proc_data.copy():
|
||||
# root truncation warnings
|
||||
if isinstance(proc_data[key], str) and proc_data[key].endswith('+') and not quiet:
|
||||
jc.utils.warning_message([f'item[{idx}]["{key}"] was truncated by top'])
|
||||
|
||||
# root int and float conversions
|
||||
if key in bytes_list:
|
||||
if key.startswith('mem_'):
|
||||
proc_data[key + '_bytes'] = jc.utils.convert_size_to_int(proc_data[key] + proc_data['mem_unit'])
|
||||
if key.startswith('swap_'):
|
||||
proc_data[key + '_bytes'] = jc.utils.convert_size_to_int(proc_data[key] + proc_data['swap_unit'])
|
||||
|
||||
if key in int_list:
|
||||
proc_data[key] = jc.utils.convert_to_int(proc_data[key])
|
||||
|
||||
@@ -299,7 +332,8 @@ def _process(proc_data: Dict, idx=0, quiet=False) -> Dict:
|
||||
jc.utils.warning_message([f'Unknown field detected at item[{idx}]["processes"]: {old_key}'])
|
||||
|
||||
# cleanup values
|
||||
for key in proc.keys():
|
||||
proc_copy = proc.copy()
|
||||
for key in proc_copy.keys():
|
||||
|
||||
# set dashes to nulls
|
||||
if proc[key] == '-':
|
||||
@@ -318,6 +352,13 @@ def _process(proc_data: Dict, idx=0, quiet=False) -> Dict:
|
||||
|
||||
# do int/float conversions for the process objects
|
||||
if proc[key]:
|
||||
if key in bytes_list:
|
||||
if proc[key][-1] not in ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'):
|
||||
proc[key + '_unit'] = proc[key][-1]
|
||||
else:
|
||||
proc[key + '_unit'] = 'b'
|
||||
proc[key + '_bytes'] = jc.utils.convert_size_to_int(proc[key], posix_mode=True)
|
||||
|
||||
if key in int_list:
|
||||
proc[key] = jc.utils.convert_to_int(proc[key])
|
||||
|
||||
@@ -448,6 +489,7 @@ def parse(
|
||||
line_list = line.split()
|
||||
output_line.update(
|
||||
{
|
||||
'mem_unit': line_list[0],
|
||||
'mem_total': line_list[3],
|
||||
'mem_free': line_list[5],
|
||||
'mem_used': line_list[7],
|
||||
@@ -461,6 +503,7 @@ def parse(
|
||||
line_list = line.split()
|
||||
output_line.update(
|
||||
{
|
||||
'swap_unit': line_list[0],
|
||||
'swap_total': line_list[2],
|
||||
'swap_free': line_list[4],
|
||||
'swap_used': line_list[6],
|
||||
@@ -489,3 +532,5 @@ def parse(
|
||||
if process_list:
|
||||
output_line['processes'] = parse_table(process_list)
|
||||
yield output_line if raw else _process(output_line, idx=idx, quiet=quiet)
|
||||
|
||||
return None
|
||||
|
||||
@@ -27,6 +27,8 @@ Schema:
|
||||
{
|
||||
"destination_ip": string,
|
||||
"destination_name": string,
|
||||
"max_hops": integer,
|
||||
"data_bytes": integer,
|
||||
"hops": [
|
||||
{
|
||||
"hop": integer,
|
||||
@@ -49,6 +51,8 @@ Examples:
|
||||
{
|
||||
"destination_ip": "216.58.194.46",
|
||||
"destination_name": "google.com",
|
||||
"max_hops": 64,
|
||||
"data_bytes": 50,
|
||||
"hops": [
|
||||
{
|
||||
"hop": 1,
|
||||
@@ -84,6 +88,8 @@ Examples:
|
||||
{
|
||||
"destination_ip": "216.58.194.46",
|
||||
"destination_name": "google.com",
|
||||
"max_hops": "64",
|
||||
"data_bytes": "50",
|
||||
"hops": [
|
||||
{
|
||||
"hop": "1",
|
||||
@@ -119,11 +125,12 @@ import re
|
||||
from decimal import Decimal
|
||||
import jc.utils
|
||||
from copy import deepcopy
|
||||
from jc.exceptions import ParseError
|
||||
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.8'
|
||||
version = '1.9'
|
||||
description = '`traceroute` and `traceroute6` command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -164,7 +171,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
'''
|
||||
|
||||
RE_HEADER = re.compile(r'(\S+)\s+\((\d+\.\d+\.\d+\.\d+|[0-9a-fA-F:]+)\)')
|
||||
RE_HEADER = re.compile(r'traceroute6? to (\S+)\s+\((\d+\.\d+\.\d+\.\d+|[0-9a-fA-F:]+)\)')
|
||||
RE_HEADER_HOPS_BYTES = re.compile(r'(\d+) hops max, (\d+) byte packets')
|
||||
RE_PROBE_NAME_IP = re.compile(r'(\S+)\s+\((\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|[0-9a-fA-F:]+)\)+')
|
||||
RE_PROBE_IP_ONLY = re.compile(r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+([^\(])')
|
||||
RE_PROBE_IPV6_ONLY = re.compile(r'(([a-f0-9]*:)+[a-f0-9]+)')
|
||||
@@ -175,9 +183,11 @@ RE_PROBE_RTT_ANNOTATION = re.compile(r'(?:(\d+(?:\.?\d+)?)\s+ms|(\s+\*\s+))\s*(!
|
||||
|
||||
|
||||
class _Traceroute(object):
|
||||
def __init__(self, dest_name, dest_ip):
|
||||
def __init__(self, dest_name, dest_ip, max_hops=None, data_bytes=None):
|
||||
self.dest_name = dest_name
|
||||
self.dest_ip = dest_ip
|
||||
self.max_hops = max_hops
|
||||
self.data_bytes = data_bytes
|
||||
self.hops = []
|
||||
|
||||
def add_hop(self, hop):
|
||||
@@ -291,8 +301,23 @@ def _get_probes(hop_string: str):
|
||||
return probes
|
||||
|
||||
|
||||
def _loads(data):
|
||||
lines = data.splitlines()
|
||||
def _loads(data: str, quiet: bool):
|
||||
lines = []
|
||||
|
||||
# remove any warning lines
|
||||
for data_line in data.splitlines():
|
||||
if 'traceroute: Warning: ' not in data_line and 'traceroute6: Warning: ' not in data_line:
|
||||
lines.append(data_line)
|
||||
else:
|
||||
continue
|
||||
|
||||
# check if header row exists, otherwise add a dummy header
|
||||
if not lines[0].startswith('traceroute to ') and not lines[0].startswith('traceroute6 to '):
|
||||
lines[:0] = ['traceroute to <<_>> (<<_>>), ? hops max, ? byte packets']
|
||||
|
||||
# print warning to STDERR
|
||||
if not quiet:
|
||||
jc.utils.warning_message(['No header row found. For destination info redirect STDERR to STDOUT'])
|
||||
|
||||
# Get headers
|
||||
match_dest = RE_HEADER.search(lines[0])
|
||||
@@ -301,8 +326,15 @@ def _loads(data):
|
||||
dest_name = match_dest.group(1)
|
||||
dest_ip = match_dest.group(2)
|
||||
|
||||
m = RE_HEADER_HOPS_BYTES.search(lines[0])
|
||||
max_hops = None
|
||||
data_bytes = None
|
||||
if m:
|
||||
max_hops = m.group(1)
|
||||
data_bytes = m.group(2)
|
||||
|
||||
# The Traceroute node is the root of the tree
|
||||
traceroute = _Traceroute(dest_name, dest_ip)
|
||||
traceroute = _Traceroute(dest_name, dest_ip, max_hops, data_bytes)
|
||||
|
||||
# Parse the remaining lines, they should be only hops/probes
|
||||
for line in lines[1:]:
|
||||
@@ -312,16 +344,17 @@ def _loads(data):
|
||||
|
||||
hop_match = RE_HOP.match(line)
|
||||
|
||||
if hop_match.group(1):
|
||||
hop_index = int(hop_match.group(1))
|
||||
else:
|
||||
hop_index = None
|
||||
if hop_match:
|
||||
if hop_match.group(1):
|
||||
hop_index = int(hop_match.group(1))
|
||||
else:
|
||||
hop_index = None
|
||||
|
||||
if hop_index is not None:
|
||||
hop = _Hop(hop_index)
|
||||
traceroute.add_hop(hop)
|
||||
if hop_index is not None:
|
||||
hop = _Hop(hop_index)
|
||||
traceroute.add_hop(hop)
|
||||
|
||||
hop_string = hop_match.group(2)
|
||||
hop_string = hop_match.group(2)
|
||||
|
||||
probes = _get_probes(hop_string)
|
||||
for probe in probes:
|
||||
@@ -330,11 +363,25 @@ def _loads(data):
|
||||
return traceroute
|
||||
|
||||
|
||||
class ParseError(Exception):
|
||||
pass
|
||||
def _serialize_hop(hop: _Hop):
|
||||
hop_obj = {}
|
||||
hop_obj['hop'] = str(hop.idx)
|
||||
probe_list = []
|
||||
|
||||
if hop.probes:
|
||||
for probe in hop.probes:
|
||||
probe_obj = {
|
||||
'annotation': probe.annotation,
|
||||
'asn': None if probe.asn is None else str(probe.asn),
|
||||
'ip': probe.ip,
|
||||
'name': probe.name,
|
||||
'rtt': None if probe.rtt is None else str(probe.rtt)
|
||||
}
|
||||
probe_list.append(probe_obj)
|
||||
|
||||
########################################################################################
|
||||
hop_obj['probes'] = probe_list
|
||||
|
||||
return hop_obj
|
||||
|
||||
|
||||
def _process(proc_data):
|
||||
@@ -349,26 +396,20 @@ def _process(proc_data):
|
||||
|
||||
Dictionary. Structured to conform to the schema.
|
||||
"""
|
||||
int_list = {'hop', 'asn'}
|
||||
int_list = {'hop', 'asn', 'max_hops', 'data_bytes'}
|
||||
float_list = {'rtt'}
|
||||
|
||||
if 'hops' in proc_data:
|
||||
for entry in proc_data['hops']:
|
||||
for key in entry:
|
||||
if key in int_list:
|
||||
entry[key] = jc.utils.convert_to_int(entry[key])
|
||||
for entry in proc_data.get('hops', []):
|
||||
_process(entry)
|
||||
for entry in proc_data.get('probes', []):
|
||||
_process(entry)
|
||||
|
||||
if key in float_list:
|
||||
entry[key] = jc.utils.convert_to_float(entry[key])
|
||||
for key in proc_data:
|
||||
if key in int_list:
|
||||
proc_data[key] = jc.utils.convert_to_int(proc_data[key])
|
||||
|
||||
if 'probes' in entry:
|
||||
for item in entry['probes']:
|
||||
for key in item:
|
||||
if key in int_list:
|
||||
item[key] = jc.utils.convert_to_int(item[key])
|
||||
|
||||
if key in float_list:
|
||||
item[key] = jc.utils.convert_to_float(item[key])
|
||||
if key in float_list:
|
||||
proc_data[key] = jc.utils.convert_to_float(proc_data[key])
|
||||
|
||||
return proc_data
|
||||
|
||||
@@ -393,52 +434,17 @@ def parse(data, raw=False, quiet=False):
|
||||
raw_output = {}
|
||||
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
# remove any warning lines
|
||||
new_data = []
|
||||
for data_line in data.splitlines():
|
||||
if 'traceroute: Warning: ' not in data_line and 'traceroute6: Warning: ' not in data_line:
|
||||
new_data.append(data_line)
|
||||
else:
|
||||
continue
|
||||
|
||||
# check if header row exists, otherwise add a dummy header
|
||||
if not new_data[0].startswith('traceroute to ') and not new_data[0].startswith('traceroute6 to '):
|
||||
new_data[:0] = ['traceroute to <<_>> (<<_>>), 30 hops max, 60 byte packets']
|
||||
|
||||
# print warning to STDERR
|
||||
if not quiet:
|
||||
jc.utils.warning_message(['No header row found. For destination info redirect STDERR to STDOUT'])
|
||||
|
||||
data = '\n'.join(new_data)
|
||||
|
||||
tr = _loads(data)
|
||||
hops = tr.hops
|
||||
tr = _loads(data, quiet)
|
||||
hops_list = []
|
||||
|
||||
if hops:
|
||||
for hop in hops:
|
||||
hop_obj = {}
|
||||
hop_obj['hop'] = str(hop.idx)
|
||||
probe_list = []
|
||||
|
||||
if hop.probes:
|
||||
for probe in hop.probes:
|
||||
probe_obj = {
|
||||
'annotation': probe.annotation,
|
||||
'asn': None if probe.asn is None else str(probe.asn),
|
||||
'ip': probe.ip,
|
||||
'name': probe.name,
|
||||
'rtt': None if probe.rtt is None else str(probe.rtt)
|
||||
}
|
||||
probe_list.append(probe_obj)
|
||||
|
||||
hop_obj['probes'] = probe_list
|
||||
hops_list.append(hop_obj)
|
||||
for hop in tr.hops:
|
||||
hops_list.append(_serialize_hop(hop))
|
||||
|
||||
raw_output = {
|
||||
'destination_ip': tr.dest_ip,
|
||||
'destination_name': tr.dest_name,
|
||||
'max_hops': tr.max_hops,
|
||||
'data_bytes': tr.data_bytes,
|
||||
'hops': hops_list
|
||||
}
|
||||
|
||||
|
||||
277
jc/parsers/traceroute_s.py
Normal file
277
jc/parsers/traceroute_s.py
Normal file
@@ -0,0 +1,277 @@
|
||||
r"""jc - JSON Convert `traceroute` command output streaming parser
|
||||
|
||||
> This streaming parser outputs JSON Lines (cli) or returns an Iterable of
|
||||
> Dictionaries (module)
|
||||
|
||||
Supports `traceroute` and `traceroute6` output.
|
||||
|
||||
> Note: On some operating systems you will need to redirect `STDERR` to
|
||||
> `STDOUT` for destination info since the header line is sent to
|
||||
> `STDERR`. A warning message will be printed to `STDERR` if the
|
||||
> header row is not found.
|
||||
>
|
||||
> e.g. `$ traceroute 8.8.8.8 2>&1 | jc --traceroute-s`
|
||||
|
||||
Usage (cli):
|
||||
|
||||
$ traceroute 1.2.3.4 | jc --traceroute-s
|
||||
|
||||
Usage (module):
|
||||
|
||||
import jc
|
||||
result = jc.parse('traceroute_s', traceroute_command_output.splitlines())
|
||||
for item in result:
|
||||
# do something
|
||||
|
||||
Schema:
|
||||
|
||||
{
|
||||
# 'header' or 'hop'
|
||||
"type": string,
|
||||
|
||||
# 'header' type has the fields below:
|
||||
"destination_ip": string,
|
||||
"destination_name": string,
|
||||
"max_hops": integer,
|
||||
"data_bytes": integer,
|
||||
|
||||
# 'hop' type has the fields below:
|
||||
"hop": integer,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": string,
|
||||
"asn": integer,
|
||||
"ip": string,
|
||||
"name": string,
|
||||
"rtt": float
|
||||
}
|
||||
]
|
||||
|
||||
# below object only exists if using -qq or ignore_exceptions=True
|
||||
"_jc_meta": {
|
||||
"success": boolean, # false if error parsing
|
||||
"error": string, # exists if "success" is false
|
||||
"line": string # exists if "success" is false
|
||||
}
|
||||
}
|
||||
|
||||
Examples:
|
||||
|
||||
$ traceroute google.com | jc --traceroute-s -p
|
||||
{
|
||||
"type": "header",
|
||||
"destination_ip": "216.58.194.46",
|
||||
"destination_name": "google.com",
|
||||
"max_hops": 30,
|
||||
"data_bytes": 60
|
||||
}
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 1,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "216.230.231.141",
|
||||
"name": "216-230-231-141.static.houston.tx.oplink.net",
|
||||
"rtt": 198.574
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "216.230.231.141",
|
||||
"name": "216-230-231-141.static.houston.tx.oplink.net",
|
||||
"rtt": null
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "216.230.231.141",
|
||||
"name": "216-230-231-141.static.houston.tx.oplink.net",
|
||||
"rtt": 198.65
|
||||
}
|
||||
]
|
||||
}
|
||||
...
|
||||
|
||||
$ traceroute google.com | jc --traceroute-s -p -r
|
||||
{
|
||||
"type": "header",
|
||||
"destination_ip": "216.58.194.46",
|
||||
"destination_name": "google.com",
|
||||
"max_hops": "30",
|
||||
"data_bytes": "60"
|
||||
}
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": "1",
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "216.230.231.141",
|
||||
"name": "216-230-231-141.static.houston.tx.oplink.net",
|
||||
"rtt": "198.574"
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "216.230.231.141",
|
||||
"name": "216-230-231-141.static.houston.tx.oplink.net",
|
||||
"rtt": null
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "216.230.231.141",
|
||||
"name": "216-230-231-141.static.houston.tx.oplink.net",
|
||||
"rtt": "198.650"
|
||||
}
|
||||
]
|
||||
}
|
||||
...
|
||||
"""
|
||||
from typing import Optional
|
||||
|
||||
import jc.utils
|
||||
from jc.exceptions import ParseError
|
||||
from jc.streaming import (
|
||||
add_jc_meta, streaming_input_type_check, streaming_line_input_type_check, raise_or_yield
|
||||
)
|
||||
from .traceroute import RE_HEADER, RE_HOP, RE_HEADER_HOPS_BYTES, _Hop, _loads, _process, _serialize_hop
|
||||
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.0'
|
||||
description = '`traceroute` and `traceroute6` command streaming parser'
|
||||
author = 'Shintaro Kojima'
|
||||
author_email = 'goodies@codeout.net'
|
||||
compatible = ['linux', 'darwin', 'freebsd']
|
||||
tags = ['command']
|
||||
streaming = True
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
'''
|
||||
Copyright (C) 2015 Luis Benitez
|
||||
|
||||
Parses the output of a traceroute execution into an AST (Abstract Syntax Tree).
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Luis Benitez
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
'''
|
||||
|
||||
|
||||
def _hop_output(hop: _Hop, raw: bool):
|
||||
raw_output = {
|
||||
'type': 'hop',
|
||||
**_serialize_hop(hop),
|
||||
}
|
||||
|
||||
return raw_output if raw else _process(raw_output)
|
||||
|
||||
|
||||
@add_jc_meta
|
||||
def parse(data, raw=False, quiet=False, ignore_exceptions=False):
|
||||
"""
|
||||
Main text parsing function. Returns an iterable object.
|
||||
|
||||
Parameters:
|
||||
|
||||
data: (iterable) line-based text data to parse
|
||||
(e.g. sys.stdin or str.splitlines())
|
||||
|
||||
raw: (boolean) unprocessed output if True
|
||||
quiet: (boolean) suppress warning messages if True
|
||||
ignore_exceptions: (boolean) ignore parsing exceptions if True
|
||||
|
||||
Returns:
|
||||
|
||||
Iterable of Dictionaries
|
||||
"""
|
||||
jc.utils.compatibility(__name__, info.compatible, quiet)
|
||||
streaming_input_type_check(data)
|
||||
|
||||
# Estimated number of probe packets per hop. See `traceroute -q` on Linux, for example.
|
||||
queries = 0
|
||||
# Accumulated hop across multiple lines
|
||||
hop_cache: Optional[_Hop] = None
|
||||
|
||||
for line in data: # type: str
|
||||
try:
|
||||
streaming_line_input_type_check(line)
|
||||
|
||||
if RE_HEADER.search(line):
|
||||
tr = _loads(line, quiet)
|
||||
raw_output = {
|
||||
'type': 'header',
|
||||
'destination_ip': tr.dest_ip,
|
||||
'destination_name': tr.dest_name,
|
||||
'max_hops': tr.max_hops,
|
||||
'data_bytes': tr.data_bytes
|
||||
}
|
||||
|
||||
yield raw_output if raw else _process(raw_output)
|
||||
|
||||
else:
|
||||
m = RE_HOP.match(line)
|
||||
if not m:
|
||||
continue
|
||||
|
||||
# A single hop can wrap across multiple lines, e.g.:
|
||||
#
|
||||
# 6 [AS0] 94.142.122.45 (94.142.122.45) 42.790 ms 46.352 ms
|
||||
# [AS0] 94.142.122.44 (94.142.122.44) 41.479 ms
|
||||
#
|
||||
if not m.group(1):
|
||||
if not hop_cache:
|
||||
raise ParseError('No hop index found')
|
||||
|
||||
# If the hop index is not found, prepend the hop index (6) to the following lines before parsing.
|
||||
line = f"{hop_cache.idx} {line}"
|
||||
# Specify quiet=True to suppress the 'No header row found' warning for hop lines
|
||||
tr = _loads(line, quiet=True)
|
||||
if not tr.hops:
|
||||
continue
|
||||
|
||||
hop_cache.probes.extend(tr.hops[0].probes)
|
||||
|
||||
else:
|
||||
# if the hop index is found, yield the previous hop
|
||||
if hop_cache:
|
||||
yield _hop_output(hop_cache, raw)
|
||||
hop_cache = None
|
||||
|
||||
# Specify quiet=True to suppress the 'No header row found' warning for hop lines
|
||||
tr = _loads(line, quiet=True)
|
||||
if not tr.hops:
|
||||
continue
|
||||
|
||||
hop_cache = tr.hops[0]
|
||||
|
||||
except Exception as e:
|
||||
yield raise_or_yield(ignore_exceptions, e, line)
|
||||
|
||||
if hop_cache:
|
||||
yield _hop_output(hop_cache, raw)
|
||||
335
jc/parsers/typeset.py
Normal file
335
jc/parsers/typeset.py
Normal file
@@ -0,0 +1,335 @@
|
||||
r"""jc - JSON Convert `typeset` and `declare` Bash internal command output parser
|
||||
|
||||
Convert `typeset` and `declare` bash internal commands with no options or the
|
||||
following: `-a`, `-A`, `-i`, `-l`, `-p`, `-r`, `-u`, and `-x`
|
||||
|
||||
Note: function parsing is not supported (e.g. `-f` or `-F`)
|
||||
|
||||
Usage (cli):
|
||||
|
||||
$ typeset | jc --typeset
|
||||
|
||||
Usage (module):
|
||||
|
||||
import jc
|
||||
result = jc.parse('typeset', typeset_command_output)
|
||||
|
||||
Schema:
|
||||
|
||||
[
|
||||
{
|
||||
"name": string,
|
||||
"value": string/integer/array/object/null, # [0]
|
||||
"type": string, # [1]
|
||||
"readonly": boolean/null,
|
||||
"integer": boolean/null,
|
||||
"lowercase": boolean/null,
|
||||
"uppercase": boolean/null,
|
||||
"exported": boolean/null
|
||||
}
|
||||
]
|
||||
|
||||
Key/value pairs other than `name`, `value`, and `type` will only be non-null
|
||||
when the information is available from the `typeset` or `declare` output.
|
||||
|
||||
If declare options are not given to `jc` within the `typeset` output, then
|
||||
it will assume all arrays are simple `array` type.
|
||||
|
||||
[0] Based on type. `variable` type is null if not set, a string when the
|
||||
bash variable is set unless the `integer` field is set to `True`, then
|
||||
the type is integer. `array` type is an array of strings or integers as
|
||||
above. `associative` type is an object of key/value pairs where values
|
||||
are strings or integers as above. Objects have the schema of:
|
||||
|
||||
{
|
||||
"<key1>": string/integer,
|
||||
"<key2>": string/integer
|
||||
}
|
||||
|
||||
[1] Possible values: `variable`, `array`, or `associative`
|
||||
|
||||
Examples:
|
||||
|
||||
$ typeset -p | jc --typeset -p
|
||||
[
|
||||
{
|
||||
"name": "associative_array",
|
||||
"value": {
|
||||
"key2": "abc",
|
||||
"key3": "1 2 3",
|
||||
"key1": "hello \"world\""
|
||||
},
|
||||
"type": "associative",
|
||||
"readonly": false,
|
||||
"integer": false,
|
||||
"lowercase": false,
|
||||
"uppercase": false,
|
||||
"exported": false
|
||||
},
|
||||
{
|
||||
"name": "integers_associative_array",
|
||||
"value": {
|
||||
"one": 1,
|
||||
"two": 500,
|
||||
"three": 999
|
||||
},
|
||||
"type": "associative",
|
||||
"readonly": false,
|
||||
"integer": true,
|
||||
"lowercase": false,
|
||||
"uppercase": false,
|
||||
"exported": false
|
||||
}
|
||||
]
|
||||
|
||||
$ typeset -p | jc --typeset -p -r
|
||||
[
|
||||
{
|
||||
"name": "associative_array",
|
||||
"value": {
|
||||
"key2": "abc",
|
||||
"key3": "1 2 3",
|
||||
"key1": "hello \"world\""
|
||||
},
|
||||
"type": "associative",
|
||||
"readonly": false,
|
||||
"integer": false,
|
||||
"lowercase": false,
|
||||
"uppercase": false,
|
||||
"exported": false
|
||||
},
|
||||
{
|
||||
"name": "integers_associative_array",
|
||||
"value": {
|
||||
"one": "1",
|
||||
"two": "500",
|
||||
"three": "999"
|
||||
},
|
||||
"type": "associative",
|
||||
"readonly": false,
|
||||
"integer": true,
|
||||
"lowercase": false,
|
||||
"uppercase": false,
|
||||
"exported": false
|
||||
}
|
||||
]
|
||||
"""
|
||||
import shlex
|
||||
import re
|
||||
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 = '`typeset` and `declare` command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
VAR_DEF_PATTERN = re.compile(r'(?P<name>[a-zA-Z_][a-zA-Z0-9_]*)=(?P<val>[^(][^[].+)$')
|
||||
SIMPLE_ARRAY_DEF_PATTERN = re.compile(r'(?P<name>[a-zA-Z_][a-zA-Z0-9_]*)=(?P<body>\(\[\d+\]=.+\))$')
|
||||
ASSOCIATIVE_ARRAY_DEF_PATTERN = re.compile(r'(?P<name>[a-zA-Z_][a-zA-Z0-9_]*)=(?P<body>\(\[[a-zA-Z_][a-zA-Z0-9_]*\]=.+\))$')
|
||||
EMPTY_ARRAY_DEF_PATTERN = re.compile(r'(?P<name>[a-zA-Z_][a-zA-Z0-9_]*)=\(\)$')
|
||||
EMPTY_VAR_DEF_PATTERN = re.compile(r'declare\s.+\s(?P<name>[a-zA-Z_][a-zA-Z0-9_]*)$')
|
||||
DECLARE_OPTS_PATTERN = re.compile(r'declare\s(?P<options>.+?)\s[a-zA-Z_][a-zA-Z0-9_]*')
|
||||
|
||||
|
||||
def _process(proc_data: List[JSONDictType]) -> List[JSONDictType]:
|
||||
"""
|
||||
Final processing to conform to the schema.
|
||||
|
||||
Parameters:
|
||||
|
||||
proc_data: (List of Dictionaries) raw structured data to process
|
||||
|
||||
Returns:
|
||||
|
||||
List of Dictionaries. Structured to conform to the schema.
|
||||
"""
|
||||
for item in proc_data:
|
||||
if item['type'] == 'variable' and item['integer']:
|
||||
item['value'] = jc.utils.convert_to_int(item['value'])
|
||||
|
||||
elif item['type'] == 'array' and item['integer'] \
|
||||
and isinstance(item['value'], list):
|
||||
|
||||
new_num_list = []
|
||||
for number in item['value']:
|
||||
new_num_list.append(jc.utils.convert_to_int(number))
|
||||
|
||||
item['value'] = new_num_list
|
||||
|
||||
elif (item['type'] == 'array' and item['integer'] \
|
||||
and isinstance(item['value'], dict)) \
|
||||
or (item['type'] == 'associative' and item['integer']):
|
||||
|
||||
new_num_dict: Dict[str, int] = {}
|
||||
for key, val in item['value'].items():
|
||||
new_num_dict.update({key: jc.utils.convert_to_int(val)})
|
||||
|
||||
item['value'] = new_num_dict
|
||||
|
||||
return proc_data
|
||||
|
||||
|
||||
def _get_simple_array_vals(body: str) -> List[str]:
|
||||
body = _remove_bookends(body)
|
||||
body_split = shlex.split(body)
|
||||
values = []
|
||||
for item in body_split:
|
||||
_, val = item.split('=', maxsplit=1)
|
||||
values.append(_remove_quotes(val))
|
||||
return values
|
||||
|
||||
|
||||
def _get_associative_array_vals(body: str) -> Dict[str, str]:
|
||||
body = _remove_bookends(body)
|
||||
body_split = shlex.split(body)
|
||||
values: Dict = {}
|
||||
for item in body_split:
|
||||
key, val = item.split('=', maxsplit=1)
|
||||
key = _remove_bookends(key, '[', ']')
|
||||
values.update({key: val})
|
||||
return values
|
||||
|
||||
|
||||
def _get_declare_options(line: str, type_hint: str = 'variable') -> Dict:
|
||||
opts = {
|
||||
'type': type_hint,
|
||||
'readonly': None,
|
||||
'integer': None,
|
||||
'lowercase': None,
|
||||
'uppercase': None,
|
||||
'exported': None
|
||||
}
|
||||
|
||||
opts_map = {
|
||||
'r': 'readonly',
|
||||
'i': 'integer',
|
||||
'l': 'lowercase',
|
||||
'u': 'uppercase',
|
||||
'x': 'exported'
|
||||
}
|
||||
|
||||
declare_opts_match = re.match(DECLARE_OPTS_PATTERN, line)
|
||||
if declare_opts_match:
|
||||
for opt in declare_opts_match['options']:
|
||||
if opt in opts_map:
|
||||
opts[opts_map[opt]] = True
|
||||
continue
|
||||
if 'a' in declare_opts_match['options']:
|
||||
opts['type'] = 'array'
|
||||
elif 'A' in declare_opts_match['options']:
|
||||
opts['type'] = 'associative'
|
||||
|
||||
# flip all remaining Nones to False
|
||||
for option in opts.items():
|
||||
key, val = option
|
||||
if val is None:
|
||||
opts[key] = False
|
||||
return opts
|
||||
|
||||
|
||||
def _remove_bookends(data: str, start_char: str = '(', end_char: str = ')') -> str:
|
||||
if data.startswith(start_char) and data.endswith(end_char):
|
||||
return data[1:-1]
|
||||
return data
|
||||
|
||||
|
||||
def _remove_quotes(data: str, remove_char: str ='"') -> str:
|
||||
if data.startswith(remove_char) and data.endswith(remove_char):
|
||||
return data[1:-1]
|
||||
return data
|
||||
|
||||
|
||||
def parse(
|
||||
data: str,
|
||||
raw: bool = False,
|
||||
quiet: bool = False
|
||||
) -> List[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:
|
||||
|
||||
List of Dictionaries. Raw or processed structured data.
|
||||
"""
|
||||
jc.utils.compatibility(__name__, info.compatible, quiet)
|
||||
jc.utils.input_type_check(data)
|
||||
|
||||
raw_output: List[Dict] = []
|
||||
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
for line in filter(None, data.splitlines()):
|
||||
|
||||
item = {
|
||||
"name": '',
|
||||
"value": '',
|
||||
"type": None,
|
||||
"readonly": None,
|
||||
"integer": None,
|
||||
"lowercase": None,
|
||||
"uppercase": None,
|
||||
"exported": None
|
||||
}
|
||||
|
||||
# regular variable
|
||||
var_def_match = re.search(VAR_DEF_PATTERN, line)
|
||||
if var_def_match:
|
||||
item['name'] = var_def_match['name']
|
||||
item['value'] = _remove_quotes(var_def_match['val'])
|
||||
item.update(_get_declare_options(line, 'variable'))
|
||||
raw_output.append(item)
|
||||
continue
|
||||
|
||||
# empty variable
|
||||
empty_var_def_match = re.search(EMPTY_VAR_DEF_PATTERN, line)
|
||||
if empty_var_def_match:
|
||||
item['name'] = empty_var_def_match['name']
|
||||
item['value'] = None
|
||||
item.update(_get_declare_options(line, 'variable'))
|
||||
raw_output.append(item)
|
||||
continue
|
||||
|
||||
# simple array
|
||||
simple_arr_def_match = re.search(SIMPLE_ARRAY_DEF_PATTERN, line)
|
||||
if simple_arr_def_match:
|
||||
item['name'] = simple_arr_def_match['name']
|
||||
item['value'] = _get_simple_array_vals(simple_arr_def_match['body'])
|
||||
item.update(_get_declare_options(line, 'array'))
|
||||
raw_output.append(item)
|
||||
continue
|
||||
|
||||
# associative array
|
||||
associative_arr_def_match = re.search(ASSOCIATIVE_ARRAY_DEF_PATTERN, line)
|
||||
if associative_arr_def_match:
|
||||
item['name'] = associative_arr_def_match['name']
|
||||
item['value'] = _get_associative_array_vals(associative_arr_def_match['body'])
|
||||
item.update(_get_declare_options(line, 'associative'))
|
||||
raw_output.append(item)
|
||||
continue
|
||||
|
||||
# empty array
|
||||
empty_arr_def_match = re.search(EMPTY_ARRAY_DEF_PATTERN, line)
|
||||
if empty_arr_def_match:
|
||||
item['name'] = empty_arr_def_match['name']
|
||||
item['value'] = []
|
||||
item.update(_get_declare_options(line, 'array'))
|
||||
raw_output.append(item)
|
||||
continue
|
||||
|
||||
return raw_output if raw else _process(raw_output)
|
||||
@@ -25,6 +25,7 @@ Schema:
|
||||
"user": string,
|
||||
"event": string,
|
||||
"writeable_tty": string,
|
||||
"process": string,
|
||||
"tty": string,
|
||||
"time": string,
|
||||
"epoch": integer, # [0]
|
||||
@@ -136,7 +137,7 @@ import jc.utils
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.8'
|
||||
version = '1.9'
|
||||
description = '`who` command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@@ -254,6 +255,12 @@ def parse(data, raw=False, quiet=False):
|
||||
raw_output.append(output_line)
|
||||
continue
|
||||
|
||||
# some output contains process name between the username and pts
|
||||
# pull the process name for use later if we can find it
|
||||
user_process = None
|
||||
if re.match(r'^\S+\s+[^ +-]+\s+pts\/\d+\s', line):
|
||||
user_process = linedata.pop(1)
|
||||
|
||||
# user logins
|
||||
output_line['user'] = linedata.pop(0)
|
||||
|
||||
@@ -262,6 +269,9 @@ def parse(data, raw=False, quiet=False):
|
||||
|
||||
output_line['tty'] = linedata.pop(0)
|
||||
|
||||
if user_process:
|
||||
output_line['process'] = user_process
|
||||
|
||||
# mac
|
||||
if re.match(r'[JFMASOND][aepuco][nbrynlgptvc]', linedata[0]):
|
||||
output_line['time'] = ' '.join([linedata.pop(0),
|
||||
|
||||
333
jc/parsers/x509_crl.py
Normal file
333
jc/parsers/x509_crl.py
Normal file
@@ -0,0 +1,333 @@
|
||||
r"""jc - JSON Convert X.509 Certificate Revocation List format file parser
|
||||
|
||||
This parser will convert DER and PEM encoded X.509 certificate revocation
|
||||
list files.
|
||||
|
||||
Usage (cli):
|
||||
|
||||
$ cat certificateRevocationList.pem | jc --x509-crl
|
||||
$ cat certificateRevocationList.der | jc --x509-crl
|
||||
|
||||
Usage (module):
|
||||
|
||||
import jc
|
||||
result = jc.parse('x509_crl', x509_crl_file_output)
|
||||
|
||||
Schema:
|
||||
|
||||
{
|
||||
"tbs_cert_list": {
|
||||
"version": string,
|
||||
"signature": {
|
||||
"algorithm": string,
|
||||
"parameters": string/null
|
||||
},
|
||||
"issuer": {
|
||||
"organization_name": string,
|
||||
"organizational_unit_name": string,
|
||||
"common_name": string
|
||||
},
|
||||
"this_update": integer, # [1]
|
||||
"next_update": integer, # [1]
|
||||
"revoked_certificates": [
|
||||
{
|
||||
"user_certificate": integer,
|
||||
"revocation_date": integer, # [1]
|
||||
"crl_entry_extensions": [
|
||||
{
|
||||
"extn_id": string,
|
||||
"critical": boolean,
|
||||
"extn_value": string,
|
||||
"extn_value_iso": string
|
||||
},
|
||||
"revocation_date_iso": string
|
||||
}
|
||||
],
|
||||
"crl_extensions": [
|
||||
{
|
||||
"extn_id": string,
|
||||
"critical": boolean,
|
||||
"extn_value": array/object/string/integer # [2]
|
||||
}
|
||||
],
|
||||
"this_update_iso": string,
|
||||
"next_update_iso": string
|
||||
},
|
||||
"signature_algorithm": {
|
||||
"algorithm": string,
|
||||
"parameters": string/null
|
||||
},
|
||||
"signature": string # [0]
|
||||
}
|
||||
|
||||
[0] in colon-delimited hex notation
|
||||
[1] time-zone-aware (UTC) epoch timestamp
|
||||
[2] See below for well-known Extension schemas:
|
||||
|
||||
Basic Constraints:
|
||||
{
|
||||
"extn_id": "basic_constraints",
|
||||
"critical": boolean,
|
||||
"extn_value": {
|
||||
"ca": boolean,
|
||||
"path_len_constraint": string/null
|
||||
}
|
||||
}
|
||||
|
||||
Key Usage:
|
||||
{
|
||||
"extn_id": "key_usage",
|
||||
"critical": boolean,
|
||||
"extn_value": [
|
||||
string
|
||||
]
|
||||
}
|
||||
|
||||
Key Identifier:
|
||||
{
|
||||
"extn_id": "key_identifier",
|
||||
"critical": boolean,
|
||||
"extn_value": string # [0]
|
||||
}
|
||||
|
||||
Authority Key Identifier:
|
||||
{
|
||||
"extn_id": "authority_key_identifier",
|
||||
"critical": boolean,
|
||||
"extn_value": {
|
||||
"key_identifier": string, # [0]
|
||||
"authority_cert_issuer": string/null,
|
||||
"authority_cert_serial_number": string/null
|
||||
}
|
||||
}
|
||||
|
||||
Subject Alternative Name:
|
||||
{
|
||||
"extn_id": "subject_alt_name",
|
||||
"critical": boolean,
|
||||
"extn_value": [
|
||||
string
|
||||
]
|
||||
}
|
||||
|
||||
Certificate Policies:
|
||||
{
|
||||
"extn_id": "certificate_policies",
|
||||
"critical": boolean,
|
||||
"extn_value": [
|
||||
{
|
||||
"policy_identifier": string,
|
||||
"policy_qualifiers": [ array or null
|
||||
{
|
||||
"policy_qualifier_id": string,
|
||||
"qualifier": string
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Signed Certificate Timestamp List:
|
||||
{
|
||||
"extn_id": "signed_certificate_timestamp_list",
|
||||
"critical": boolean,
|
||||
"extn_value": string # [0]
|
||||
}
|
||||
|
||||
Examples:
|
||||
|
||||
$ cat sample-crl.pem | jc --x509-crl -p
|
||||
{
|
||||
"tbs_cert_list": {
|
||||
"version": "v2",
|
||||
"signature": {
|
||||
"algorithm": "sha1_rsa",
|
||||
"parameters": null
|
||||
},
|
||||
"issuer": {
|
||||
"organization_name": "Sample Signer Organization",
|
||||
"organizational_unit_name": "Sample Signer Unit",
|
||||
"common_name": "Sample Signer Cert"
|
||||
},
|
||||
"this_update": 1361183520,
|
||||
"next_update": 1361184120,
|
||||
"revoked_certificates": [
|
||||
{
|
||||
"user_certificate": 1341767,
|
||||
"revocation_date": 1361182932,
|
||||
"crl_entry_extensions": [
|
||||
{
|
||||
"extn_id": "crl_reason",
|
||||
"critical": false,
|
||||
"extn_value": "affiliation_changed"
|
||||
},
|
||||
{
|
||||
"extn_id": "invalidity_date",
|
||||
"critical": false,
|
||||
"extn_value": 1361182920,
|
||||
"extn_value_iso": "2013-02-18T10:22:00+00:00"
|
||||
}
|
||||
],
|
||||
"revocation_date_iso": "2013-02-18T10:22:12+00:00"
|
||||
},
|
||||
{
|
||||
"user_certificate": 1341768,
|
||||
"revocation_date": 1361182942,
|
||||
"crl_entry_extensions": [
|
||||
{
|
||||
"extn_id": "crl_reason",
|
||||
"critical": false,
|
||||
"extn_value": "certificate_hold"
|
||||
},
|
||||
{
|
||||
"extn_id": "invalidity_date",
|
||||
"critical": false,
|
||||
"extn_value": 1361182920,
|
||||
"extn_value_iso": "2013-02-18T10:22:00+00:00"
|
||||
}
|
||||
],
|
||||
"revocation_date_iso": "2013-02-18T10:22:22+00:00"
|
||||
},
|
||||
{
|
||||
"user_certificate": 1341769,
|
||||
"revocation_date": 1361182952,
|
||||
"crl_entry_extensions": [
|
||||
{
|
||||
"extn_id": "crl_reason",
|
||||
"critical": false,
|
||||
"extn_value": "superseded"
|
||||
},
|
||||
{
|
||||
"extn_id": "invalidity_date",
|
||||
"critical": false,
|
||||
"extn_value": 1361182920,
|
||||
"extn_value_iso": "2013-02-18T10:22:00+00:00"
|
||||
}
|
||||
],
|
||||
"revocation_date_iso": "2013-02-18T10:22:32+00:00"
|
||||
},
|
||||
{
|
||||
"user_certificate": 1341770,
|
||||
"revocation_date": 1361182962,
|
||||
"crl_entry_extensions": [
|
||||
{
|
||||
"extn_id": "crl_reason",
|
||||
"critical": false,
|
||||
"extn_value": "key_compromise"
|
||||
},
|
||||
{
|
||||
"extn_id": "invalidity_date",
|
||||
"critical": false,
|
||||
"extn_value": 1361182920,
|
||||
"extn_value_iso": "2013-02-18T10:22:00+00:00"
|
||||
}
|
||||
],
|
||||
"revocation_date_iso": "2013-02-18T10:22:42+00:00"
|
||||
},
|
||||
{
|
||||
"user_certificate": 1341771,
|
||||
"revocation_date": 1361182971,
|
||||
"crl_entry_extensions": [
|
||||
{
|
||||
"extn_id": "crl_reason",
|
||||
"critical": false,
|
||||
"extn_value": "cessation_of_operation"
|
||||
},
|
||||
{
|
||||
"extn_id": "invalidity_date",
|
||||
"critical": false,
|
||||
"extn_value": 1361182920,
|
||||
"extn_value_iso": "2013-02-18T10:22:00+00:00"
|
||||
}
|
||||
],
|
||||
"revocation_date_iso": "2013-02-18T10:22:51+00:00"
|
||||
}
|
||||
],
|
||||
"crl_extensions": [
|
||||
{
|
||||
"extn_id": "authority_key_identifier",
|
||||
"critical": false,
|
||||
"extn_value": {
|
||||
"key_identifier": "be:12:01:cc:aa:ea:11:80:da:2e:ad:b2...",
|
||||
"authority_cert_issuer": null,
|
||||
"authority_cert_serial_number": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"extn_id": "crl_number",
|
||||
"critical": false,
|
||||
"extn_value": 3
|
||||
}
|
||||
],
|
||||
"this_update_iso": "2013-02-18T10:32:00+00:00",
|
||||
"next_update_iso": "2013-02-18T10:42:00+00:00"
|
||||
},
|
||||
"signature_algorithm": {
|
||||
"algorithm": "sha1_rsa",
|
||||
"parameters": null
|
||||
},
|
||||
"signature": "42:21:be:81:f1:c3:79:76:66:5b:ce:21:13:8a:68:a..."
|
||||
}
|
||||
"""
|
||||
from typing import List, Dict, Union
|
||||
import jc.utils
|
||||
from jc.parsers.asn1crypto import pem, crl, jc_global
|
||||
from jc.parsers.x509_cert import _fix_objects
|
||||
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.0'
|
||||
description = 'X.509 PEM and DER certificate revocation list file parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
details = 'Using the asn1crypto library at https://github.com/wbond/asn1crypto/releases/tag/1.5.1'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
|
||||
tags = ['standard', 'file', 'string', 'binary']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
|
||||
def parse(
|
||||
data: Union[str, bytes],
|
||||
raw: bool = False,
|
||||
quiet: bool = False
|
||||
) -> Dict:
|
||||
"""
|
||||
Main text parsing function
|
||||
|
||||
Parameters:
|
||||
|
||||
data: (string or bytes) text or binary 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_global.quiet = quiet # to inject quiet setting into asn1crypto library
|
||||
|
||||
raw_output: Dict = {}
|
||||
|
||||
if jc.utils.has_data(data):
|
||||
# convert to bytes, if not already, for PEM detection since that's
|
||||
# what pem.detect() needs. (cli.py will auto-convert to UTF-8 if it can)
|
||||
try:
|
||||
der_bytes = bytes(data, 'utf-8') # type: ignore
|
||||
except TypeError:
|
||||
der_bytes = data # type: ignore
|
||||
|
||||
if pem.detect(der_bytes):
|
||||
for type_name, headers, der_bytes in pem.unarmor(der_bytes, multiple=True):
|
||||
if type_name == 'X509 CRL':
|
||||
crl_obj = crl.CertificateList.load(der_bytes)
|
||||
break
|
||||
else:
|
||||
crl_obj = crl.CertificateList.load(der_bytes)
|
||||
|
||||
raw_output = _fix_objects(crl_obj.native)
|
||||
|
||||
return raw_output
|
||||
@@ -249,9 +249,6 @@ Examples:
|
||||
}
|
||||
]
|
||||
"""
|
||||
# import binascii
|
||||
# from collections import OrderedDict
|
||||
# from datetime import datetime
|
||||
from typing import List, Dict, Union
|
||||
import jc.utils
|
||||
from jc.parsers.asn1crypto import pem, csr, jc_global
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""jc - JSON Convert streaming utils"""
|
||||
|
||||
from functools import wraps
|
||||
from typing import Dict, Tuple, Union, Iterable, Callable, TypeVar, cast, Any
|
||||
from typing import Tuple, Union, Iterable, Callable, TypeVar, cast, Any
|
||||
from .jc_types import JSONDictType
|
||||
|
||||
|
||||
@@ -47,8 +47,9 @@ def stream_error(e: BaseException, line: str) -> JSONDictType:
|
||||
|
||||
def add_jc_meta(func: F) -> F:
|
||||
"""
|
||||
Decorator for streaming parsers to add stream_success and stream_error
|
||||
objects. This simplifies the yield lines in the streaming parsers.
|
||||
Decorator for streaming parsers to add `stream_success` and
|
||||
`stream_error` objects. This simplifies the `yield` lines in the
|
||||
streaming parsers.
|
||||
|
||||
With the decorator on parse():
|
||||
|
||||
@@ -82,7 +83,7 @@ def add_jc_meta(func: F) -> F:
|
||||
successfully parse.
|
||||
|
||||
ignore_exceptions: (bool) continue processing lines and ignore
|
||||
exceptions if True.
|
||||
exceptions if `True`.
|
||||
"""
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
@@ -109,8 +110,8 @@ def raise_or_yield(
|
||||
line: str
|
||||
) -> Tuple[BaseException, str]:
|
||||
"""
|
||||
Return the exception object and line string if ignore_exceptions is
|
||||
True. Otherwise, re-raise the exception from the exception object with
|
||||
Return the exception object and line string if `ignore_exceptions` is
|
||||
`True`. Otherwise, re-raise the exception from the exception object with
|
||||
an annotation.
|
||||
"""
|
||||
ignore_exceptions_msg = '... Use the ignore_exceptions option (-qq) to ignore streaming parser errors.'
|
||||
|
||||
12
jc/utils.py
12
jc/utils.py
@@ -100,7 +100,7 @@ def error_message(message_lines: List[str]) -> None:
|
||||
|
||||
Returns:
|
||||
|
||||
None - just prints output to STDERR
|
||||
None - just prints output to `STDERR`
|
||||
"""
|
||||
columns = shutil.get_terminal_size().columns
|
||||
|
||||
@@ -148,7 +148,7 @@ def compatibility(mod_name: str, compatible: List[str], quiet: bool = False) ->
|
||||
the parser. compatible options:
|
||||
linux, darwin, cygwin, win32, aix, freebsd
|
||||
|
||||
quiet: (bool) suppress compatibility message if True
|
||||
quiet: (bool) suppress compatibility message if `True`
|
||||
|
||||
Returns:
|
||||
|
||||
@@ -169,7 +169,7 @@ def has_data(data: Union[str, bytes]) -> bool:
|
||||
Checks if the string input contains data. If there are any
|
||||
non-whitespace characters then return `True`, else return `False`.
|
||||
|
||||
For bytes, returns True if there is any data.
|
||||
For bytes, returns `True` if there is any data.
|
||||
|
||||
Parameters:
|
||||
|
||||
@@ -177,9 +177,9 @@ def has_data(data: Union[str, bytes]) -> bool:
|
||||
|
||||
Returns:
|
||||
|
||||
Boolean True if input string (data) contains non-whitespace
|
||||
characters, otherwise False. For bytes data, returns
|
||||
True if there is any data, otherwise False.
|
||||
Boolean `True` if input string (data) contains non-whitespace
|
||||
characters, otherwise `False`. For bytes data, returns
|
||||
`True` if there is any data, otherwise `False`.
|
||||
"""
|
||||
if isinstance(data, str):
|
||||
return bool(data and not data.isspace())
|
||||
|
||||
27
man/jc.1
27
man/jc.1
@@ -1,4 +1,4 @@
|
||||
.TH jc 1 2025-05-10 1.25.5 "JSON Convert"
|
||||
.TH jc 1 2025-10-12 1.25.6 "JSON Convert"
|
||||
.SH NAME
|
||||
\fBjc\fP \- JSON Convert JSONifies the output of many CLI tools, file-types,
|
||||
and strings
|
||||
@@ -487,6 +487,16 @@ M3U and M3U8 file parser
|
||||
\fB--netstat\fP
|
||||
`netstat` command parser
|
||||
|
||||
.TP
|
||||
.B
|
||||
\fB--net-localgroup\fP
|
||||
`net localgroup` command parser
|
||||
|
||||
.TP
|
||||
.B
|
||||
\fB--net-user\fP
|
||||
`net user` command parser
|
||||
|
||||
.TP
|
||||
.B
|
||||
\fB--nmcli\fP
|
||||
@@ -872,6 +882,11 @@ PLIST file parser
|
||||
\fB--route\fP
|
||||
`route` command parser
|
||||
|
||||
.TP
|
||||
.B
|
||||
\fB--route-print\fP
|
||||
`route print` command parser
|
||||
|
||||
.TP
|
||||
.B
|
||||
\fB--rpm-qi\fP
|
||||
@@ -1027,6 +1042,11 @@ TOML file parser
|
||||
\fB--traceroute\fP
|
||||
`traceroute` and `traceroute6` command parser
|
||||
|
||||
.TP
|
||||
.B
|
||||
\fB--traceroute-s\fP
|
||||
`traceroute` and `traceroute6` command streaming parser
|
||||
|
||||
.TP
|
||||
.B
|
||||
\fB--tune2fs\fP
|
||||
@@ -1122,6 +1142,11 @@ Version string parser
|
||||
\fB--x509-cert\fP
|
||||
X.509 PEM and DER certificate file parser
|
||||
|
||||
.TP
|
||||
.B
|
||||
\fB--x509-crl\fP
|
||||
X.509 PEM and DER certificate revocation list file parser
|
||||
|
||||
.TP
|
||||
.B
|
||||
\fB--x509-csr\fP
|
||||
|
||||
3
setup.py
3
setup.py
@@ -1,11 +1,12 @@
|
||||
import setuptools
|
||||
|
||||
|
||||
with open('README.md', 'r') as f:
|
||||
long_description = f.read()
|
||||
|
||||
setuptools.setup(
|
||||
name='jc',
|
||||
version='1.25.5',
|
||||
version='1.25.7',
|
||||
author='Kelly Brazil',
|
||||
author_email='kellyjonbrazil@gmail.com',
|
||||
description='Converts the output of popular command-line tools and file-types to JSON.',
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
[](https://github.com/kellyjonbrazil/jc/actions)
|
||||
[](https://pypi.org/project/jc/)
|
||||
|
||||
> Check out the `jc` Python [package documentation](https://github.com/kellyjonbrazil/jc/tree/master/docs) for developers
|
||||
|
||||
1
tests/fixtures/centos-7.7/md5sum-raw.json
vendored
Normal file
1
tests/fixtures/centos-7.7/md5sum-raw.json
vendored
Normal file
File diff suppressed because one or more lines are too long
2
tests/fixtures/centos-7.7/md5sum.json
vendored
2
tests/fixtures/centos-7.7/md5sum.json
vendored
File diff suppressed because one or more lines are too long
1
tests/fixtures/centos-7.7/sha256sum-raw.json
vendored
Normal file
1
tests/fixtures/centos-7.7/sha256sum-raw.json
vendored
Normal file
File diff suppressed because one or more lines are too long
2
tests/fixtures/centos-7.7/sha256sum.json
vendored
2
tests/fixtures/centos-7.7/sha256sum.json
vendored
File diff suppressed because one or more lines are too long
1
tests/fixtures/centos-7.7/sha384sum-raw.json
vendored
Normal file
1
tests/fixtures/centos-7.7/sha384sum-raw.json
vendored
Normal file
File diff suppressed because one or more lines are too long
2
tests/fixtures/centos-7.7/sha384sum.json
vendored
2
tests/fixtures/centos-7.7/sha384sum.json
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
tests/fixtures/centos-7.7/top-b-n1-gib.json
vendored
2
tests/fixtures/centos-7.7/top-b-n1-gib.json
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
tests/fixtures/centos-7.7/top-b-n3.json
vendored
2
tests/fixtures/centos-7.7/top-b-n3.json
vendored
File diff suppressed because one or more lines are too long
291
tests/fixtures/centos-7.7/traceroute-streaming.json
vendored
Normal file
291
tests/fixtures/centos-7.7/traceroute-streaming.json
vendored
Normal file
@@ -0,0 +1,291 @@
|
||||
[
|
||||
{
|
||||
"type": "header",
|
||||
"destination_ip": "151.101.197.67",
|
||||
"destination_name": "www.cnn.com",
|
||||
"max_hops": 30,
|
||||
"data_bytes": 60
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 1,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "192.168.1.254",
|
||||
"name": "dsldevice.attlocal.net",
|
||||
"rtt": 4.024
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "192.168.1.254",
|
||||
"name": "dsldevice.attlocal.net",
|
||||
"rtt": 3.683
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "192.168.1.254",
|
||||
"name": "dsldevice.attlocal.net",
|
||||
"rtt": 3.706
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 2,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "76.220.24.1",
|
||||
"name": "76-220-24-1.lightspeed.sntcca.sbcglobal.net",
|
||||
"rtt": 24.038
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "76.220.24.1",
|
||||
"name": "76-220-24-1.lightspeed.sntcca.sbcglobal.net",
|
||||
"rtt": 23.911
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "76.220.24.1",
|
||||
"name": "76-220-24-1.lightspeed.sntcca.sbcglobal.net",
|
||||
"rtt": 23.724
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 3,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 4,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "12.122.149.186",
|
||||
"name": "12.122.149.186",
|
||||
"rtt": 42.273
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "12.122.149.186",
|
||||
"name": "12.122.149.186",
|
||||
"rtt": 42.213
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "12.122.149.186",
|
||||
"name": "12.122.149.186",
|
||||
"rtt": 42.083
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 5,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "12.122.2.77",
|
||||
"name": "12.122.2.77",
|
||||
"rtt": 36.789
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "12.122.2.77",
|
||||
"name": "12.122.2.77",
|
||||
"rtt": 43.691
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "12.122.2.77",
|
||||
"name": "12.122.2.77",
|
||||
"rtt": 36.597
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 6,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "12.122.2.94",
|
||||
"name": "sd2ca21crs.ip.att.net",
|
||||
"rtt": 41.587
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "12.122.2.94",
|
||||
"name": "sd2ca21crs.ip.att.net",
|
||||
"rtt": 40.24
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "12.122.2.94",
|
||||
"name": "sd2ca21crs.ip.att.net",
|
||||
"rtt": 44.659
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 7,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "12.123.215.161",
|
||||
"name": "12.123.215.161",
|
||||
"rtt": 37.858
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "12.123.215.161",
|
||||
"name": "12.123.215.161",
|
||||
"rtt": 37.321
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "12.123.215.161",
|
||||
"name": "12.123.215.161",
|
||||
"rtt": 37.092
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 8,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 9,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 10,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 11,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 12,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 13,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 14,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 15,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 16,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 17,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 18,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 19,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 20,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 21,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 22,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 23,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 24,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 25,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 26,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 27,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 28,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 29,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 30,
|
||||
"probes": []
|
||||
}
|
||||
]
|
||||
2
tests/fixtures/centos-7.7/traceroute.json
vendored
2
tests/fixtures/centos-7.7/traceroute.json
vendored
@@ -1 +1 @@
|
||||
{"destination_ip": "151.101.197.67", "destination_name": "www.cnn.com", "hops": [{"hop": 1, "probes": [{"annotation": null, "asn": null, "ip": "192.168.1.254", "name": "dsldevice.attlocal.net", "rtt": 4.024}, {"annotation": null, "asn": null, "ip": "192.168.1.254", "name": "dsldevice.attlocal.net", "rtt": 3.683}, {"annotation": null, "asn": null, "ip": "192.168.1.254", "name": "dsldevice.attlocal.net", "rtt": 3.706}]}, {"hop": 2, "probes": [{"annotation": null, "asn": null, "ip": "76.220.24.1", "name": "76-220-24-1.lightspeed.sntcca.sbcglobal.net", "rtt": 24.038}, {"annotation": null, "asn": null, "ip": "76.220.24.1", "name": "76-220-24-1.lightspeed.sntcca.sbcglobal.net", "rtt": 23.911}, {"annotation": null, "asn": null, "ip": "76.220.24.1", "name": "76-220-24-1.lightspeed.sntcca.sbcglobal.net", "rtt": 23.724}]}, {"hop": 3, "probes": []}, {"hop": 4, "probes": [{"annotation": null, "asn": null, "ip": "12.122.149.186", "name": "12.122.149.186", "rtt": 42.273}, {"annotation": null, "asn": null, "ip": "12.122.149.186", "name": "12.122.149.186", "rtt": 42.213}, {"annotation": null, "asn": null, "ip": "12.122.149.186", "name": "12.122.149.186", "rtt": 42.083}]}, {"hop": 5, "probes": [{"annotation": null, "asn": null, "ip": "12.122.2.77", "name": "12.122.2.77", "rtt": 36.789}, {"annotation": null, "asn": null, "ip": "12.122.2.77", "name": "12.122.2.77", "rtt": 43.691}, {"annotation": null, "asn": null, "ip": "12.122.2.77", "name": "12.122.2.77", "rtt": 36.597}]}, {"hop": 6, "probes": [{"annotation": null, "asn": null, "ip": "12.122.2.94", "name": "sd2ca21crs.ip.att.net", "rtt": 41.587}, {"annotation": null, "asn": null, "ip": "12.122.2.94", "name": "sd2ca21crs.ip.att.net", "rtt": 40.24}, {"annotation": null, "asn": null, "ip": "12.122.2.94", "name": "sd2ca21crs.ip.att.net", "rtt": 44.659}]}, {"hop": 7, "probes": [{"annotation": null, "asn": null, "ip": "12.123.215.161", "name": "12.123.215.161", "rtt": 37.858}, {"annotation": null, "asn": null, "ip": "12.123.215.161", "name": "12.123.215.161", "rtt": 37.321}, {"annotation": null, "asn": null, "ip": "12.123.215.161", "name": "12.123.215.161", "rtt": 37.092}]}, {"hop": 8, "probes": []}, {"hop": 9, "probes": []}, {"hop": 10, "probes": []}, {"hop": 11, "probes": []}, {"hop": 12, "probes": []}, {"hop": 13, "probes": []}, {"hop": 14, "probes": []}, {"hop": 15, "probes": []}, {"hop": 16, "probes": []}, {"hop": 17, "probes": []}, {"hop": 18, "probes": []}, {"hop": 19, "probes": []}, {"hop": 20, "probes": []}, {"hop": 21, "probes": []}, {"hop": 22, "probes": []}, {"hop": 23, "probes": []}, {"hop": 24, "probes": []}, {"hop": 25, "probes": []}, {"hop": 26, "probes": []}, {"hop": 27, "probes": []}, {"hop": 28, "probes": []}, {"hop": 29, "probes": []}, {"hop": 30, "probes": []}]}
|
||||
{"destination_ip":"151.101.197.67","destination_name":"www.cnn.com","max_hops":30,"data_bytes":60,"hops":[{"hop":1,"probes":[{"annotation":null,"asn":null,"ip":"192.168.1.254","name":"dsldevice.attlocal.net","rtt":4.024},{"annotation":null,"asn":null,"ip":"192.168.1.254","name":"dsldevice.attlocal.net","rtt":3.683},{"annotation":null,"asn":null,"ip":"192.168.1.254","name":"dsldevice.attlocal.net","rtt":3.706}]},{"hop":2,"probes":[{"annotation":null,"asn":null,"ip":"76.220.24.1","name":"76-220-24-1.lightspeed.sntcca.sbcglobal.net","rtt":24.038},{"annotation":null,"asn":null,"ip":"76.220.24.1","name":"76-220-24-1.lightspeed.sntcca.sbcglobal.net","rtt":23.911},{"annotation":null,"asn":null,"ip":"76.220.24.1","name":"76-220-24-1.lightspeed.sntcca.sbcglobal.net","rtt":23.724}]},{"hop":3,"probes":[]},{"hop":4,"probes":[{"annotation":null,"asn":null,"ip":"12.122.149.186","name":"12.122.149.186","rtt":42.273},{"annotation":null,"asn":null,"ip":"12.122.149.186","name":"12.122.149.186","rtt":42.213},{"annotation":null,"asn":null,"ip":"12.122.149.186","name":"12.122.149.186","rtt":42.083}]},{"hop":5,"probes":[{"annotation":null,"asn":null,"ip":"12.122.2.77","name":"12.122.2.77","rtt":36.789},{"annotation":null,"asn":null,"ip":"12.122.2.77","name":"12.122.2.77","rtt":43.691},{"annotation":null,"asn":null,"ip":"12.122.2.77","name":"12.122.2.77","rtt":36.597}]},{"hop":6,"probes":[{"annotation":null,"asn":null,"ip":"12.122.2.94","name":"sd2ca21crs.ip.att.net","rtt":41.587},{"annotation":null,"asn":null,"ip":"12.122.2.94","name":"sd2ca21crs.ip.att.net","rtt":40.24},{"annotation":null,"asn":null,"ip":"12.122.2.94","name":"sd2ca21crs.ip.att.net","rtt":44.659}]},{"hop":7,"probes":[{"annotation":null,"asn":null,"ip":"12.123.215.161","name":"12.123.215.161","rtt":37.858},{"annotation":null,"asn":null,"ip":"12.123.215.161","name":"12.123.215.161","rtt":37.321},{"annotation":null,"asn":null,"ip":"12.123.215.161","name":"12.123.215.161","rtt":37.092}]},{"hop":8,"probes":[]},{"hop":9,"probes":[]},{"hop":10,"probes":[]},{"hop":11,"probes":[]},{"hop":12,"probes":[]},{"hop":13,"probes":[]},{"hop":14,"probes":[]},{"hop":15,"probes":[]},{"hop":16,"probes":[]},{"hop":17,"probes":[]},{"hop":18,"probes":[]},{"hop":19,"probes":[]},{"hop":20,"probes":[]},{"hop":21,"probes":[]},{"hop":22,"probes":[]},{"hop":23,"probes":[]},{"hop":24,"probes":[]},{"hop":25,"probes":[]},{"hop":26,"probes":[]},{"hop":27,"probes":[]},{"hop":28,"probes":[]},{"hop":29,"probes":[]},{"hop":30,"probes":[]}]}
|
||||
|
||||
1
tests/fixtures/debian13/who.json
vendored
Normal file
1
tests/fixtures/debian13/who.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[{"user":"root","tty":"tty1","time":"Sep 1 12:20","epoch":null},{"user":"frenkye","tty":"pts/4","process":"sshd","time":"Sep 1 12:05","from":"x.x.x.x","epoch":null},{"user":"root","tty":"tty1","time":"Sep 1 12:25","epoch":null},{"user":"frenkye","tty":"pts/4","time":"Sep 1 12:05","from":"x.x.x.x","epoch":null},{"user":"frenkye","tty":"pts/443","process":"kelly","time":"Sep 1 12:05","from":"x.x.x.x","epoch":null}]
|
||||
5
tests/fixtures/debian13/who.out
vendored
Normal file
5
tests/fixtures/debian13/who.out
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
root tty1 Sep 1 12:20
|
||||
frenkye sshd pts/4 Sep 1 12:05 (x.x.x.x)
|
||||
root tty1 Sep 1 12:25
|
||||
frenkye pts/4 Sep 1 12:05 (x.x.x.x)
|
||||
frenkye kelly pts/443 Sep 1 12:05 (x.x.x.x)
|
||||
216
tests/fixtures/freebsd12/traceroute-streaming.json
vendored
Normal file
216
tests/fixtures/freebsd12/traceroute-streaming.json
vendored
Normal file
@@ -0,0 +1,216 @@
|
||||
[
|
||||
{
|
||||
"type": "header",
|
||||
"destination_ip": "8.8.8.8",
|
||||
"destination_name": "8.8.8.8",
|
||||
"max_hops": 64,
|
||||
"data_bytes": 40
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 1,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "192.168.1.254",
|
||||
"name": "dsldevice.attlocal.net",
|
||||
"rtt": 3.263
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "192.168.1.254",
|
||||
"name": "dsldevice.attlocal.net",
|
||||
"rtt": 4.146
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "192.168.1.254",
|
||||
"name": "dsldevice.attlocal.net",
|
||||
"rtt": 4.273
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 2,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "76.220.24.1",
|
||||
"name": "76-220-24-1.lightspeed.sntcca.sbcglobal.net",
|
||||
"rtt": 20.839
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "76.220.24.1",
|
||||
"name": "76-220-24-1.lightspeed.sntcca.sbcglobal.net",
|
||||
"rtt": 23.434
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "76.220.24.1",
|
||||
"name": "76-220-24-1.lightspeed.sntcca.sbcglobal.net",
|
||||
"rtt": 22.032
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 3,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 4,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "12.122.149.186",
|
||||
"name": "12.122.149.186",
|
||||
"rtt": 33.17
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "12.122.149.186",
|
||||
"name": "12.122.149.186",
|
||||
"rtt": 26.593
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "12.122.149.186",
|
||||
"name": "12.122.149.186",
|
||||
"rtt": 32.851
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 5,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "12.122.3.70",
|
||||
"name": "sffca22crs.ip.att.net",
|
||||
"rtt": 26.045
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "12.122.3.70",
|
||||
"name": "sffca22crs.ip.att.net",
|
||||
"rtt": 29.235
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "12.122.3.70",
|
||||
"name": "sffca22crs.ip.att.net",
|
||||
"rtt": 28.28
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 6,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "12.122.163.61",
|
||||
"name": "12.122.163.61",
|
||||
"rtt": 25.3
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "12.122.163.61",
|
||||
"name": "12.122.163.61",
|
||||
"rtt": 24.156
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "12.122.163.61",
|
||||
"name": "12.122.163.61",
|
||||
"rtt": 24.849
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 7,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "12.255.10.226",
|
||||
"name": "12.255.10.226",
|
||||
"rtt": 25.375
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "12.255.10.224",
|
||||
"name": "12.255.10.224",
|
||||
"rtt": 24.011
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "12.255.10.224",
|
||||
"name": "12.255.10.224",
|
||||
"rtt": 25.322
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 8,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "108.170.243.1",
|
||||
"name": "108.170.243.1",
|
||||
"rtt": 29.376
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 9,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "8.8.8.8",
|
||||
"name": "dns.google",
|
||||
"rtt": 23.228
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "209.85.252.251",
|
||||
"name": "209.85.252.251",
|
||||
"rtt": 24.548
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "108.170.237.23",
|
||||
"name": "108.170.237.23",
|
||||
"rtt": 24.332
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
2
tests/fixtures/freebsd12/traceroute.json
vendored
2
tests/fixtures/freebsd12/traceroute.json
vendored
@@ -1 +1 @@
|
||||
{"destination_ip": "8.8.8.8", "destination_name": "8.8.8.8", "hops": [{"hop": 1, "probes": [{"annotation": null, "asn": null, "ip": "192.168.1.254", "name": "dsldevice.attlocal.net", "rtt": 3.263}, {"annotation": null, "asn": null, "ip": "192.168.1.254", "name": "dsldevice.attlocal.net", "rtt": 4.146}, {"annotation": null, "asn": null, "ip": "192.168.1.254", "name": "dsldevice.attlocal.net", "rtt": 4.273}]}, {"hop": 2, "probes": [{"annotation": null, "asn": null, "ip": "76.220.24.1", "name": "76-220-24-1.lightspeed.sntcca.sbcglobal.net", "rtt": 20.839}, {"annotation": null, "asn": null, "ip": "76.220.24.1", "name": "76-220-24-1.lightspeed.sntcca.sbcglobal.net", "rtt": 23.434}, {"annotation": null, "asn": null, "ip": "76.220.24.1", "name": "76-220-24-1.lightspeed.sntcca.sbcglobal.net", "rtt": 22.032}]}, {"hop": 3, "probes": []}, {"hop": 4, "probes": [{"annotation": null, "asn": null, "ip": "12.122.149.186", "name": "12.122.149.186", "rtt": 33.17}, {"annotation": null, "asn": null, "ip": "12.122.149.186", "name": "12.122.149.186", "rtt": 26.593}, {"annotation": null, "asn": null, "ip": "12.122.149.186", "name": "12.122.149.186", "rtt": 32.851}]}, {"hop": 5, "probes": [{"annotation": null, "asn": null, "ip": "12.122.3.70", "name": "sffca22crs.ip.att.net", "rtt": 26.045}, {"annotation": null, "asn": null, "ip": "12.122.3.70", "name": "sffca22crs.ip.att.net", "rtt": 29.235}, {"annotation": null, "asn": null, "ip": "12.122.3.70", "name": "sffca22crs.ip.att.net", "rtt": 28.28}]}, {"hop": 6, "probes": [{"annotation": null, "asn": null, "ip": "12.122.163.61", "name": "12.122.163.61", "rtt": 25.3}, {"annotation": null, "asn": null, "ip": "12.122.163.61", "name": "12.122.163.61", "rtt": 24.156}, {"annotation": null, "asn": null, "ip": "12.122.163.61", "name": "12.122.163.61", "rtt": 24.849}]}, {"hop": 7, "probes": [{"annotation": null, "asn": null, "ip": "12.255.10.226", "name": "12.255.10.226", "rtt": 25.375}, {"annotation": null, "asn": null, "ip": "12.255.10.224", "name": "12.255.10.224", "rtt": 24.011}, {"annotation": null, "asn": null, "ip": "12.255.10.224", "name": "12.255.10.224", "rtt": 25.322}]}, {"hop": 8, "probes": [{"annotation": null, "asn": null, "ip": "108.170.243.1", "name": "108.170.243.1", "rtt": 29.376}]}, {"hop": 9, "probes": [{"annotation": null, "asn": null, "ip": "8.8.8.8", "name": "dns.google", "rtt": 23.228}, {"annotation": null, "asn": null, "ip": "209.85.252.251", "name": "209.85.252.251", "rtt": 24.548}, {"annotation": null, "asn": null, "ip": "108.170.237.23", "name": "108.170.237.23", "rtt": 24.332}]}]}
|
||||
{"destination_ip":"8.8.8.8","destination_name":"8.8.8.8","max_hops":64,"data_bytes":40,"hops":[{"hop":1,"probes":[{"annotation":null,"asn":null,"ip":"192.168.1.254","name":"dsldevice.attlocal.net","rtt":3.263},{"annotation":null,"asn":null,"ip":"192.168.1.254","name":"dsldevice.attlocal.net","rtt":4.146},{"annotation":null,"asn":null,"ip":"192.168.1.254","name":"dsldevice.attlocal.net","rtt":4.273}]},{"hop":2,"probes":[{"annotation":null,"asn":null,"ip":"76.220.24.1","name":"76-220-24-1.lightspeed.sntcca.sbcglobal.net","rtt":20.839},{"annotation":null,"asn":null,"ip":"76.220.24.1","name":"76-220-24-1.lightspeed.sntcca.sbcglobal.net","rtt":23.434},{"annotation":null,"asn":null,"ip":"76.220.24.1","name":"76-220-24-1.lightspeed.sntcca.sbcglobal.net","rtt":22.032}]},{"hop":3,"probes":[]},{"hop":4,"probes":[{"annotation":null,"asn":null,"ip":"12.122.149.186","name":"12.122.149.186","rtt":33.17},{"annotation":null,"asn":null,"ip":"12.122.149.186","name":"12.122.149.186","rtt":26.593},{"annotation":null,"asn":null,"ip":"12.122.149.186","name":"12.122.149.186","rtt":32.851}]},{"hop":5,"probes":[{"annotation":null,"asn":null,"ip":"12.122.3.70","name":"sffca22crs.ip.att.net","rtt":26.045},{"annotation":null,"asn":null,"ip":"12.122.3.70","name":"sffca22crs.ip.att.net","rtt":29.235},{"annotation":null,"asn":null,"ip":"12.122.3.70","name":"sffca22crs.ip.att.net","rtt":28.28}]},{"hop":6,"probes":[{"annotation":null,"asn":null,"ip":"12.122.163.61","name":"12.122.163.61","rtt":25.3},{"annotation":null,"asn":null,"ip":"12.122.163.61","name":"12.122.163.61","rtt":24.156},{"annotation":null,"asn":null,"ip":"12.122.163.61","name":"12.122.163.61","rtt":24.849}]},{"hop":7,"probes":[{"annotation":null,"asn":null,"ip":"12.255.10.226","name":"12.255.10.226","rtt":25.375},{"annotation":null,"asn":null,"ip":"12.255.10.224","name":"12.255.10.224","rtt":24.011},{"annotation":null,"asn":null,"ip":"12.255.10.224","name":"12.255.10.224","rtt":25.322}]},{"hop":8,"probes":[{"annotation":null,"asn":null,"ip":"108.170.243.1","name":"108.170.243.1","rtt":29.376}]},{"hop":9,"probes":[{"annotation":null,"asn":null,"ip":"8.8.8.8","name":"dns.google","rtt":23.228},{"annotation":null,"asn":null,"ip":"209.85.252.251","name":"209.85.252.251","rtt":24.548},{"annotation":null,"asn":null,"ip":"108.170.237.23","name":"108.170.237.23","rtt":24.332}]}]}
|
||||
|
||||
208
tests/fixtures/freebsd12/traceroute6-streaming.json
vendored
Normal file
208
tests/fixtures/freebsd12/traceroute6-streaming.json
vendored
Normal file
@@ -0,0 +1,208 @@
|
||||
[
|
||||
{
|
||||
"type": "header",
|
||||
"destination_ip": "2a04:4e42::323",
|
||||
"destination_name": "turner-tls.map.fastly.net",
|
||||
"max_hops": 64,
|
||||
"data_bytes": 20
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 1,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 2,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:506:6000:11b:71:156:212:143",
|
||||
"name": null,
|
||||
"rtt": 27.603
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:506:6000:11b:71:156:212:143",
|
||||
"name": null,
|
||||
"rtt": 28.659
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:506:6000:11b:71:156:212:143",
|
||||
"name": null,
|
||||
"rtt": 33.235
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 3,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 4,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:1890:ff:ff08:12:242:117:16",
|
||||
"name": null,
|
||||
"rtt": 36.731
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:1890:ff:ff08:12:242:117:16",
|
||||
"name": null,
|
||||
"rtt": 28.875
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:1890:ff:ff08:12:242:117:16",
|
||||
"name": null,
|
||||
"rtt": 28.959
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 5,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 6,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 7,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 8,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 9,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 10,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 11,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 12,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 13,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 14,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 15,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 16,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 17,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 18,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 19,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 20,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 21,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 22,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 23,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 24,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 25,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 26,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 27,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 28,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 29,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 30,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 31,
|
||||
"probes": []
|
||||
}
|
||||
]
|
||||
2
tests/fixtures/freebsd12/traceroute6.json
vendored
2
tests/fixtures/freebsd12/traceroute6.json
vendored
@@ -1 +1 @@
|
||||
{"destination_ip": "2a04:4e42::323", "destination_name": "turner-tls.map.fastly.net", "hops": [{"hop": 1, "probes": []}, {"hop": 2, "probes": [{"annotation": null, "asn": null, "ip": "2001:506:6000:11b:71:156:212:143", "name": null, "rtt": 27.603}, {"annotation": null, "asn": null, "ip": "2001:506:6000:11b:71:156:212:143", "name": null, "rtt": 28.659}, {"annotation": null, "asn": null, "ip": "2001:506:6000:11b:71:156:212:143", "name": null, "rtt": 33.235}]}, {"hop": 3, "probes": []}, {"hop": 4, "probes": [{"annotation": null, "asn": null, "ip": "2001:1890:ff:ff08:12:242:117:16", "name": null, "rtt": 36.731}, {"annotation": null, "asn": null, "ip": "2001:1890:ff:ff08:12:242:117:16", "name": null, "rtt": 28.875}, {"annotation": null, "asn": null, "ip": "2001:1890:ff:ff08:12:242:117:16", "name": null, "rtt": 28.959}]}, {"hop": 5, "probes": []}, {"hop": 6, "probes": []}, {"hop": 7, "probes": []}, {"hop": 8, "probes": []}, {"hop": 9, "probes": []}, {"hop": 10, "probes": []}, {"hop": 11, "probes": []}, {"hop": 12, "probes": []}, {"hop": 13, "probes": []}, {"hop": 14, "probes": []}, {"hop": 15, "probes": []}, {"hop": 16, "probes": []}, {"hop": 17, "probes": []}, {"hop": 18, "probes": []}, {"hop": 19, "probes": []}, {"hop": 20, "probes": []}, {"hop": 21, "probes": []}, {"hop": 22, "probes": []}, {"hop": 23, "probes": []}, {"hop": 24, "probes": []}, {"hop": 25, "probes": []}, {"hop": 26, "probes": []}, {"hop": 27, "probes": []}, {"hop": 28, "probes": []}, {"hop": 29, "probes": []}, {"hop": 30, "probes": []}, {"hop": 31, "probes": []}]}
|
||||
{"destination_ip":"2a04:4e42::323","destination_name":"turner-tls.map.fastly.net","max_hops":64,"data_bytes":20,"hops":[{"hop":1,"probes":[]},{"hop":2,"probes":[{"annotation":null,"asn":null,"ip":"2001:506:6000:11b:71:156:212:143","name":null,"rtt":27.603},{"annotation":null,"asn":null,"ip":"2001:506:6000:11b:71:156:212:143","name":null,"rtt":28.659},{"annotation":null,"asn":null,"ip":"2001:506:6000:11b:71:156:212:143","name":null,"rtt":33.235}]},{"hop":3,"probes":[]},{"hop":4,"probes":[{"annotation":null,"asn":null,"ip":"2001:1890:ff:ff08:12:242:117:16","name":null,"rtt":36.731},{"annotation":null,"asn":null,"ip":"2001:1890:ff:ff08:12:242:117:16","name":null,"rtt":28.875},{"annotation":null,"asn":null,"ip":"2001:1890:ff:ff08:12:242:117:16","name":null,"rtt":28.959}]},{"hop":5,"probes":[]},{"hop":6,"probes":[]},{"hop":7,"probes":[]},{"hop":8,"probes":[]},{"hop":9,"probes":[]},{"hop":10,"probes":[]},{"hop":11,"probes":[]},{"hop":12,"probes":[]},{"hop":13,"probes":[]},{"hop":14,"probes":[]},{"hop":15,"probes":[]},{"hop":16,"probes":[]},{"hop":17,"probes":[]},{"hop":18,"probes":[]},{"hop":19,"probes":[]},{"hop":20,"probes":[]},{"hop":21,"probes":[]},{"hop":22,"probes":[]},{"hop":23,"probes":[]},{"hop":24,"probes":[]},{"hop":25,"probes":[]},{"hop":26,"probes":[]},{"hop":27,"probes":[]},{"hop":28,"probes":[]},{"hop":29,"probes":[]},{"hop":30,"probes":[]},{"hop":31,"probes":[]}]}
|
||||
|
||||
1
tests/fixtures/generic/iptables-no-jump2.json
vendored
Normal file
1
tests/fixtures/generic/iptables-no-jump2.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[{"chain":"INPUT","default_policy":"ACCEPT","default_packets":0,"default_bytes":0,"rules":[{"pkts":17,"bytes":1172,"target":null,"prot":"all","opt":null,"in":"*","out":"*","source":"0.0.0.0/0","destination":"0.0.0.0/0"}]}]
|
||||
3
tests/fixtures/generic/iptables-no-jump2.out
vendored
Normal file
3
tests/fixtures/generic/iptables-no-jump2.out
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
|
||||
pkts bytes target prot opt in out source destination
|
||||
17 1172 all -- * * 0.0.0.0/0 0.0.0.0/0
|
||||
1
tests/fixtures/generic/nmcli-team-and-team-port-config.json
vendored
Normal file
1
tests/fixtures/generic/nmcli-team-and-team-port-config.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[{"connection_id":"Team connection 1","connection_uuid":"258e02c2-d9f9-44bb-8d27-887e11aa1828","connection_stable_id":null,"connection_type":"team","connection_interface_name":"team0","connection_autoconnect":"yes","connection_autoconnect_priority":0,"connection_autoconnect_retries":-1,"connection_autoconnect_retries_text":"default","connection_multi_connect":0,"connection_multi_connect_text":"default","connection_auth_retries":-1,"connection_timestamp":0,"connection_read_only":"no","connection_permissions":null,"connection_zone":null,"connection_master":null,"connection_slave_type":null,"connection_autoconnect_slaves":-1,"connection_autoconnect_slaves_text":"default","connection_secondaries":null,"connection_gateway_ping_timeout":0,"connection_metered":"unknown","connection_lldp":"default","connection_mdns":-1,"connection_mdns_text":"default","connection_llmnr":-1,"connection_llmnr_text":"default","connection_dns_over_tls":-1,"connection_dns_over_tls_text":"default","connection_wait_device_timeout":-1,"ipv4_method":"auto","ipv4_dns":null,"ipv4_dns_search":null,"ipv4_dns_options":null,"ipv4_dns_priority":0,"ipv4_addresses":null,"ipv4_gateway":null,"ipv4_routes":null,"ipv4_route_metric":-1,"ipv4_route_table":0,"ipv4_route_table_text":"unspec","ipv4_routing_rules":null,"ipv4_ignore_auto_routes":"no","ipv4_ignore_auto_dns":"no","ipv4_dhcp_client_id":null,"ipv4_dhcp_iaid":null,"ipv4_dhcp_timeout":0,"ipv4_dhcp_timeout_text":"default","ipv4_dhcp_send_hostname":"yes","ipv4_dhcp_hostname":null,"ipv4_dhcp_fqdn":null,"ipv4_dhcp_hostname_flags":"0x0","ipv4_dhcp_hostname_flags_text":"none","ipv4_never_default":"no","ipv4_may_fail":"yes","ipv4_required_timeout":-1,"ipv4_required_timeout_text":"default","ipv4_dad_timeout":-1,"ipv4_dad_timeout_text":"default","ipv4_dhcp_vendor_class_identifier":null,"ipv4_dhcp_reject_servers":null,"ipv6_method":"auto","ipv6_dns":null,"ipv6_dns_search":null,"ipv6_dns_options":null,"ipv6_dns_priority":0,"ipv6_addresses":null,"ipv6_gateway":null,"ipv6_routes":null,"ipv6_route_metric":-1,"ipv6_route_table":0,"ipv6_route_table_text":"unspec","ipv6_routing_rules":null,"ipv6_ignore_auto_routes":"no","ipv6_ignore_auto_dns":"no","ipv6_never_default":"no","ipv6_may_fail":"yes","ipv6_required_timeout":-1,"ipv6_required_timeout_text":"default","ipv6_ip6_privacy":-1,"ipv6_ip6_privacy_text":"unknown","ipv6_addr_gen_mode":"stable-privacy","ipv6_ra_timeout":0,"ipv6_ra_timeout_text":"default","ipv6_dhcp_duid":null,"ipv6_dhcp_iaid":null,"ipv6_dhcp_timeout":0,"ipv6_dhcp_timeout_text":"default","ipv6_dhcp_send_hostname":"yes","ipv6_dhcp_hostname":null,"ipv6_dhcp_hostname_flags":"0x0","ipv6_dhcp_hostname_flags_text":"none","ipv6_token":null,"team_config":{"runner":{"name":"roundrobin"},"link_watch":{"name":"ethtool"}},"team_notify_peers_count":-1,"team_notify_peers_count_text":"unset","team_notify_peers_interval":-1,"team_notify_peers_interval_text":"unset","team_mcast_rejoin_count":-1,"team_mcast_rejoin_count_text":"unset","team_mcast_rejoin_interval":-1,"team_mcast_rejoin_interval_text":"unset","team_runner":"roundrobin","team_runner_hwaddr_policy":null,"team_runner_tx_hash":null,"team_runner_tx_balancer":null,"team_runner_tx_balancer_interval":-1,"team_runner_tx_balancer_interval_text":"unset","team_runner_active":"yes","team_runner_fast_rate":"no","team_runner_sys_prio":-1,"team_runner_sys_prio_text":"unset","team_runner_min_ports":-1,"team_runner_min_ports_text":"unset","team_runner_agg_select_policy":null,"team_link_watchers":"name=ethtool","team_port_config":{"queue_id":0,"prio":0,"lacp_prio":0,"lacp_key":0},"team_port_queue_id":0,"team_port_queue_id_text":"default","team_port_prio":0,"team_port_prio_text":"unset","team_port_sticky":"no","team_port_lacp_prio":0,"team_port_lacp_key":0,"team_port_lacp_key_text":"default","team_port_link_watchers":null,"proxy_method":"none","proxy_browser_only":"no","proxy_pac_url":null,"proxy_pac_script":null}]
|
||||
116
tests/fixtures/generic/nmcli-team-and-team-port-config.out
vendored
Normal file
116
tests/fixtures/generic/nmcli-team-and-team-port-config.out
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
connection.id: Team connection 1
|
||||
connection.uuid: 258e02c2-d9f9-44bb-8d27-887e11aa1828
|
||||
connection.stable-id: --
|
||||
connection.type: team
|
||||
connection.interface-name: team0
|
||||
connection.autoconnect: yes
|
||||
connection.autoconnect-priority: 0
|
||||
connection.autoconnect-retries: -1 (default)
|
||||
connection.multi-connect: 0 (default)
|
||||
connection.auth-retries: -1
|
||||
connection.timestamp: 0
|
||||
connection.read-only: no
|
||||
connection.permissions: --
|
||||
connection.zone: --
|
||||
connection.master: --
|
||||
connection.slave-type: --
|
||||
connection.autoconnect-slaves: -1 (default)
|
||||
connection.secondaries: --
|
||||
connection.gateway-ping-timeout: 0
|
||||
connection.metered: unknown
|
||||
connection.lldp: default
|
||||
connection.mdns: -1 (default)
|
||||
connection.llmnr: -1 (default)
|
||||
connection.dns-over-tls: -1 (default)
|
||||
connection.wait-device-timeout: -1
|
||||
ipv4.method: auto
|
||||
ipv4.dns: --
|
||||
ipv4.dns-search: --
|
||||
ipv4.dns-options: --
|
||||
ipv4.dns-priority: 0
|
||||
ipv4.addresses: --
|
||||
ipv4.gateway: --
|
||||
ipv4.routes: --
|
||||
ipv4.route-metric: -1
|
||||
ipv4.route-table: 0 (unspec)
|
||||
ipv4.routing-rules: --
|
||||
ipv4.ignore-auto-routes: no
|
||||
ipv4.ignore-auto-dns: no
|
||||
ipv4.dhcp-client-id: --
|
||||
ipv4.dhcp-iaid: --
|
||||
ipv4.dhcp-timeout: 0 (default)
|
||||
ipv4.dhcp-send-hostname: yes
|
||||
ipv4.dhcp-hostname: --
|
||||
ipv4.dhcp-fqdn: --
|
||||
ipv4.dhcp-hostname-flags: 0x0 (none)
|
||||
ipv4.never-default: no
|
||||
ipv4.may-fail: yes
|
||||
ipv4.required-timeout: -1 (default)
|
||||
ipv4.dad-timeout: -1 (default)
|
||||
ipv4.dhcp-vendor-class-identifier: --
|
||||
ipv4.dhcp-reject-servers: --
|
||||
ipv6.method: auto
|
||||
ipv6.dns: --
|
||||
ipv6.dns-search: --
|
||||
ipv6.dns-options: --
|
||||
ipv6.dns-priority: 0
|
||||
ipv6.addresses: --
|
||||
ipv6.gateway: --
|
||||
ipv6.routes: --
|
||||
ipv6.route-metric: -1
|
||||
ipv6.route-table: 0 (unspec)
|
||||
ipv6.routing-rules: --
|
||||
ipv6.ignore-auto-routes: no
|
||||
ipv6.ignore-auto-dns: no
|
||||
ipv6.never-default: no
|
||||
ipv6.may-fail: yes
|
||||
ipv6.required-timeout: -1 (default)
|
||||
ipv6.ip6-privacy: -1 (unknown)
|
||||
ipv6.addr-gen-mode: stable-privacy
|
||||
ipv6.ra-timeout: 0 (default)
|
||||
ipv6.dhcp-duid: --
|
||||
ipv6.dhcp-iaid: --
|
||||
ipv6.dhcp-timeout: 0 (default)
|
||||
ipv6.dhcp-send-hostname: yes
|
||||
ipv6.dhcp-hostname: --
|
||||
ipv6.dhcp-hostname-flags: 0x0 (none)
|
||||
ipv6.token: --
|
||||
team.config: {
|
||||
"runner": {
|
||||
"name": "roundrobin"
|
||||
},
|
||||
"link_watch": {
|
||||
"name": "ethtool"
|
||||
}
|
||||
}
|
||||
team.notify-peers-count: -1 (unset)
|
||||
team.notify-peers-interval: -1 (unset)
|
||||
team.mcast-rejoin-count: -1 (unset)
|
||||
team.mcast-rejoin-interval: -1 (unset)
|
||||
team.runner: roundrobin
|
||||
team.runner-hwaddr-policy: --
|
||||
team.runner-tx-hash: --
|
||||
team.runner-tx-balancer: --
|
||||
team.runner-tx-balancer-interval: -1 (unset)
|
||||
team.runner-active: yes
|
||||
team.runner-fast-rate: no
|
||||
team.runner-sys-prio: -1 (unset)
|
||||
team.runner-min-ports: -1 (unset)
|
||||
team.runner-agg-select-policy: --
|
||||
team.link-watchers: name=ethtool
|
||||
team-port.config: {
|
||||
"queue_id": 0,
|
||||
"prio": 0,
|
||||
"lacp_prio": 0,
|
||||
"lacp_key": 0
|
||||
}
|
||||
team-port.queue-id: 0 (default)
|
||||
team-port.prio: 0 (unset)
|
||||
team-port.sticky: no
|
||||
team-port.lacp-prio: 0
|
||||
team-port.lacp-key: 0 (default)
|
||||
team-port.link-watchers: --
|
||||
proxy.method: none
|
||||
proxy.browser-only: no
|
||||
proxy.pac-url: --
|
||||
proxy.pac-script: --
|
||||
1
tests/fixtures/generic/nmcli-team-config-blank.json
vendored
Normal file
1
tests/fixtures/generic/nmcli-team-config-blank.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[{"connection_id":"Team connection 1","connection_uuid":"258e02c2-d9f9-44bb-8d27-887e11aa1828","connection_stable_id":null,"connection_type":"team","connection_interface_name":"team0","connection_autoconnect":"yes","connection_autoconnect_priority":0,"connection_autoconnect_retries":-1,"connection_autoconnect_retries_text":"default","connection_multi_connect":0,"connection_multi_connect_text":"default","connection_auth_retries":-1,"connection_timestamp":0,"connection_read_only":"no","connection_permissions":null,"connection_zone":null,"connection_master":null,"connection_slave_type":null,"connection_autoconnect_slaves":-1,"connection_autoconnect_slaves_text":"default","connection_secondaries":null,"connection_gateway_ping_timeout":0,"connection_metered":"unknown","connection_lldp":"default","connection_mdns":-1,"connection_mdns_text":"default","connection_llmnr":-1,"connection_llmnr_text":"default","connection_dns_over_tls":-1,"connection_dns_over_tls_text":"default","connection_wait_device_timeout":-1,"ipv4_method":"auto","ipv4_dns":null,"ipv4_dns_search":null,"ipv4_dns_options":null,"ipv4_dns_priority":0,"ipv4_addresses":null,"ipv4_gateway":null,"ipv4_routes":null,"ipv4_route_metric":-1,"ipv4_route_table":0,"ipv4_route_table_text":"unspec","ipv4_routing_rules":null,"ipv4_ignore_auto_routes":"no","ipv4_ignore_auto_dns":"no","ipv4_dhcp_client_id":null,"ipv4_dhcp_iaid":null,"ipv4_dhcp_timeout":0,"ipv4_dhcp_timeout_text":"default","ipv4_dhcp_send_hostname":"yes","ipv4_dhcp_hostname":null,"ipv4_dhcp_fqdn":null,"ipv4_dhcp_hostname_flags":"0x0","ipv4_dhcp_hostname_flags_text":"none","ipv4_never_default":"no","ipv4_may_fail":"yes","ipv4_required_timeout":-1,"ipv4_required_timeout_text":"default","ipv4_dad_timeout":-1,"ipv4_dad_timeout_text":"default","ipv4_dhcp_vendor_class_identifier":null,"ipv4_dhcp_reject_servers":null,"ipv6_method":"auto","ipv6_dns":null,"ipv6_dns_search":null,"ipv6_dns_options":null,"ipv6_dns_priority":0,"ipv6_addresses":null,"ipv6_gateway":null,"ipv6_routes":null,"ipv6_route_metric":-1,"ipv6_route_table":0,"ipv6_route_table_text":"unspec","ipv6_routing_rules":null,"ipv6_ignore_auto_routes":"no","ipv6_ignore_auto_dns":"no","ipv6_never_default":"no","ipv6_may_fail":"yes","ipv6_required_timeout":-1,"ipv6_required_timeout_text":"default","ipv6_ip6_privacy":-1,"ipv6_ip6_privacy_text":"unknown","ipv6_addr_gen_mode":"stable-privacy","ipv6_ra_timeout":0,"ipv6_ra_timeout_text":"default","ipv6_dhcp_duid":null,"ipv6_dhcp_iaid":null,"ipv6_dhcp_timeout":0,"ipv6_dhcp_timeout_text":"default","ipv6_dhcp_send_hostname":"yes","ipv6_dhcp_hostname":null,"ipv6_dhcp_hostname_flags":"0x0","ipv6_dhcp_hostname_flags_text":"none","ipv6_token":null,"team_config":null,"team_notify_peers_count":-1,"team_notify_peers_count_text":"unset","team_notify_peers_interval":-1,"team_notify_peers_interval_text":"unset","team_mcast_rejoin_count":-1,"team_mcast_rejoin_count_text":"unset","team_mcast_rejoin_interval":-1,"team_mcast_rejoin_interval_text":"unset","team_runner":"roundrobin","team_runner_hwaddr_policy":null,"team_runner_tx_hash":null,"team_runner_tx_balancer":null,"team_runner_tx_balancer_interval":-1,"team_runner_tx_balancer_interval_text":"unset","team_runner_active":"yes","team_runner_fast_rate":"no","team_runner_sys_prio":-1,"team_runner_sys_prio_text":"unset","team_runner_min_ports":-1,"team_runner_min_ports_text":"unset","team_runner_agg_select_policy":null,"team_link_watchers":"name=ethtool","proxy_method":"none","proxy_browser_only":"no","proxy_pac_url":null,"proxy_pac_script":null}]
|
||||
97
tests/fixtures/generic/nmcli-team-config-blank.out
vendored
Normal file
97
tests/fixtures/generic/nmcli-team-config-blank.out
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
connection.id: Team connection 1
|
||||
connection.uuid: 258e02c2-d9f9-44bb-8d27-887e11aa1828
|
||||
connection.stable-id: --
|
||||
connection.type: team
|
||||
connection.interface-name: team0
|
||||
connection.autoconnect: yes
|
||||
connection.autoconnect-priority: 0
|
||||
connection.autoconnect-retries: -1 (default)
|
||||
connection.multi-connect: 0 (default)
|
||||
connection.auth-retries: -1
|
||||
connection.timestamp: 0
|
||||
connection.read-only: no
|
||||
connection.permissions: --
|
||||
connection.zone: --
|
||||
connection.master: --
|
||||
connection.slave-type: --
|
||||
connection.autoconnect-slaves: -1 (default)
|
||||
connection.secondaries: --
|
||||
connection.gateway-ping-timeout: 0
|
||||
connection.metered: unknown
|
||||
connection.lldp: default
|
||||
connection.mdns: -1 (default)
|
||||
connection.llmnr: -1 (default)
|
||||
connection.dns-over-tls: -1 (default)
|
||||
connection.wait-device-timeout: -1
|
||||
ipv4.method: auto
|
||||
ipv4.dns: --
|
||||
ipv4.dns-search: --
|
||||
ipv4.dns-options: --
|
||||
ipv4.dns-priority: 0
|
||||
ipv4.addresses: --
|
||||
ipv4.gateway: --
|
||||
ipv4.routes: --
|
||||
ipv4.route-metric: -1
|
||||
ipv4.route-table: 0 (unspec)
|
||||
ipv4.routing-rules: --
|
||||
ipv4.ignore-auto-routes: no
|
||||
ipv4.ignore-auto-dns: no
|
||||
ipv4.dhcp-client-id: --
|
||||
ipv4.dhcp-iaid: --
|
||||
ipv4.dhcp-timeout: 0 (default)
|
||||
ipv4.dhcp-send-hostname: yes
|
||||
ipv4.dhcp-hostname: --
|
||||
ipv4.dhcp-fqdn: --
|
||||
ipv4.dhcp-hostname-flags: 0x0 (none)
|
||||
ipv4.never-default: no
|
||||
ipv4.may-fail: yes
|
||||
ipv4.required-timeout: -1 (default)
|
||||
ipv4.dad-timeout: -1 (default)
|
||||
ipv4.dhcp-vendor-class-identifier: --
|
||||
ipv4.dhcp-reject-servers: --
|
||||
ipv6.method: auto
|
||||
ipv6.dns: --
|
||||
ipv6.dns-search: --
|
||||
ipv6.dns-options: --
|
||||
ipv6.dns-priority: 0
|
||||
ipv6.addresses: --
|
||||
ipv6.gateway: --
|
||||
ipv6.routes: --
|
||||
ipv6.route-metric: -1
|
||||
ipv6.route-table: 0 (unspec)
|
||||
ipv6.routing-rules: --
|
||||
ipv6.ignore-auto-routes: no
|
||||
ipv6.ignore-auto-dns: no
|
||||
ipv6.never-default: no
|
||||
ipv6.may-fail: yes
|
||||
ipv6.required-timeout: -1 (default)
|
||||
ipv6.ip6-privacy: -1 (unknown)
|
||||
ipv6.addr-gen-mode: stable-privacy
|
||||
ipv6.ra-timeout: 0 (default)
|
||||
ipv6.dhcp-duid: --
|
||||
ipv6.dhcp-iaid: --
|
||||
ipv6.dhcp-timeout: 0 (default)
|
||||
ipv6.dhcp-send-hostname: yes
|
||||
ipv6.dhcp-hostname: --
|
||||
ipv6.dhcp-hostname-flags: 0x0 (none)
|
||||
ipv6.token: --
|
||||
team.config: --
|
||||
team.notify-peers-count: -1 (unset)
|
||||
team.notify-peers-interval: -1 (unset)
|
||||
team.mcast-rejoin-count: -1 (unset)
|
||||
team.mcast-rejoin-interval: -1 (unset)
|
||||
team.runner: roundrobin
|
||||
team.runner-hwaddr-policy: --
|
||||
team.runner-tx-hash: --
|
||||
team.runner-tx-balancer: --
|
||||
team.runner-tx-balancer-interval: -1 (unset)
|
||||
team.runner-active: yes
|
||||
team.runner-fast-rate: no
|
||||
team.runner-sys-prio: -1 (unset)
|
||||
team.runner-min-ports: -1 (unset)
|
||||
team.runner-agg-select-policy: --
|
||||
team.link-watchers: name=ethtool
|
||||
proxy.method: none
|
||||
proxy.browser-only: no
|
||||
proxy.pac-url: --
|
||||
proxy.pac-script: --
|
||||
1
tests/fixtures/generic/nmcli-team-config.json
vendored
Normal file
1
tests/fixtures/generic/nmcli-team-config.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[{"connection_id":"Team connection 1","connection_uuid":"258e02c2-d9f9-44bb-8d27-887e11aa1828","connection_stable_id":null,"connection_type":"team","connection_interface_name":"team0","connection_autoconnect":"yes","connection_autoconnect_priority":0,"connection_autoconnect_retries":-1,"connection_autoconnect_retries_text":"default","connection_multi_connect":0,"connection_multi_connect_text":"default","connection_auth_retries":-1,"connection_timestamp":0,"connection_read_only":"no","connection_permissions":null,"connection_zone":null,"connection_master":null,"connection_slave_type":null,"connection_autoconnect_slaves":-1,"connection_autoconnect_slaves_text":"default","connection_secondaries":null,"connection_gateway_ping_timeout":0,"connection_metered":"unknown","connection_lldp":"default","connection_mdns":-1,"connection_mdns_text":"default","connection_llmnr":-1,"connection_llmnr_text":"default","connection_dns_over_tls":-1,"connection_dns_over_tls_text":"default","connection_wait_device_timeout":-1,"ipv4_method":"auto","ipv4_dns":null,"ipv4_dns_search":null,"ipv4_dns_options":null,"ipv4_dns_priority":0,"ipv4_addresses":null,"ipv4_gateway":null,"ipv4_routes":null,"ipv4_route_metric":-1,"ipv4_route_table":0,"ipv4_route_table_text":"unspec","ipv4_routing_rules":null,"ipv4_ignore_auto_routes":"no","ipv4_ignore_auto_dns":"no","ipv4_dhcp_client_id":null,"ipv4_dhcp_iaid":null,"ipv4_dhcp_timeout":0,"ipv4_dhcp_timeout_text":"default","ipv4_dhcp_send_hostname":"yes","ipv4_dhcp_hostname":null,"ipv4_dhcp_fqdn":null,"ipv4_dhcp_hostname_flags":"0x0","ipv4_dhcp_hostname_flags_text":"none","ipv4_never_default":"no","ipv4_may_fail":"yes","ipv4_required_timeout":-1,"ipv4_required_timeout_text":"default","ipv4_dad_timeout":-1,"ipv4_dad_timeout_text":"default","ipv4_dhcp_vendor_class_identifier":null,"ipv4_dhcp_reject_servers":null,"ipv6_method":"auto","ipv6_dns":null,"ipv6_dns_search":null,"ipv6_dns_options":null,"ipv6_dns_priority":0,"ipv6_addresses":null,"ipv6_gateway":null,"ipv6_routes":null,"ipv6_route_metric":-1,"ipv6_route_table":0,"ipv6_route_table_text":"unspec","ipv6_routing_rules":null,"ipv6_ignore_auto_routes":"no","ipv6_ignore_auto_dns":"no","ipv6_never_default":"no","ipv6_may_fail":"yes","ipv6_required_timeout":-1,"ipv6_required_timeout_text":"default","ipv6_ip6_privacy":-1,"ipv6_ip6_privacy_text":"unknown","ipv6_addr_gen_mode":"stable-privacy","ipv6_ra_timeout":0,"ipv6_ra_timeout_text":"default","ipv6_dhcp_duid":null,"ipv6_dhcp_iaid":null,"ipv6_dhcp_timeout":0,"ipv6_dhcp_timeout_text":"default","ipv6_dhcp_send_hostname":"yes","ipv6_dhcp_hostname":null,"ipv6_dhcp_hostname_flags":"0x0","ipv6_dhcp_hostname_flags_text":"none","ipv6_token":null,"team_config":{"runner":{"name":"roundrobin"},"link_watch":{"name":"ethtool"}},"team_notify_peers_count":-1,"team_notify_peers_count_text":"unset","team_notify_peers_interval":-1,"team_notify_peers_interval_text":"unset","team_mcast_rejoin_count":-1,"team_mcast_rejoin_count_text":"unset","team_mcast_rejoin_interval":-1,"team_mcast_rejoin_interval_text":"unset","team_runner":"roundrobin","team_runner_hwaddr_policy":null,"team_runner_tx_hash":null,"team_runner_tx_balancer":null,"team_runner_tx_balancer_interval":-1,"team_runner_tx_balancer_interval_text":"unset","team_runner_active":"yes","team_runner_fast_rate":"no","team_runner_sys_prio":-1,"team_runner_sys_prio_text":"unset","team_runner_min_ports":-1,"team_runner_min_ports_text":"unset","team_runner_agg_select_policy":null,"team_link_watchers":"name=ethtool","proxy_method":"none","proxy_browser_only":"no","proxy_pac_url":null,"proxy_pac_script":null}]
|
||||
104
tests/fixtures/generic/nmcli-team-config.out
vendored
Normal file
104
tests/fixtures/generic/nmcli-team-config.out
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
connection.id: Team connection 1
|
||||
connection.uuid: 258e02c2-d9f9-44bb-8d27-887e11aa1828
|
||||
connection.stable-id: --
|
||||
connection.type: team
|
||||
connection.interface-name: team0
|
||||
connection.autoconnect: yes
|
||||
connection.autoconnect-priority: 0
|
||||
connection.autoconnect-retries: -1 (default)
|
||||
connection.multi-connect: 0 (default)
|
||||
connection.auth-retries: -1
|
||||
connection.timestamp: 0
|
||||
connection.read-only: no
|
||||
connection.permissions: --
|
||||
connection.zone: --
|
||||
connection.master: --
|
||||
connection.slave-type: --
|
||||
connection.autoconnect-slaves: -1 (default)
|
||||
connection.secondaries: --
|
||||
connection.gateway-ping-timeout: 0
|
||||
connection.metered: unknown
|
||||
connection.lldp: default
|
||||
connection.mdns: -1 (default)
|
||||
connection.llmnr: -1 (default)
|
||||
connection.dns-over-tls: -1 (default)
|
||||
connection.wait-device-timeout: -1
|
||||
ipv4.method: auto
|
||||
ipv4.dns: --
|
||||
ipv4.dns-search: --
|
||||
ipv4.dns-options: --
|
||||
ipv4.dns-priority: 0
|
||||
ipv4.addresses: --
|
||||
ipv4.gateway: --
|
||||
ipv4.routes: --
|
||||
ipv4.route-metric: -1
|
||||
ipv4.route-table: 0 (unspec)
|
||||
ipv4.routing-rules: --
|
||||
ipv4.ignore-auto-routes: no
|
||||
ipv4.ignore-auto-dns: no
|
||||
ipv4.dhcp-client-id: --
|
||||
ipv4.dhcp-iaid: --
|
||||
ipv4.dhcp-timeout: 0 (default)
|
||||
ipv4.dhcp-send-hostname: yes
|
||||
ipv4.dhcp-hostname: --
|
||||
ipv4.dhcp-fqdn: --
|
||||
ipv4.dhcp-hostname-flags: 0x0 (none)
|
||||
ipv4.never-default: no
|
||||
ipv4.may-fail: yes
|
||||
ipv4.required-timeout: -1 (default)
|
||||
ipv4.dad-timeout: -1 (default)
|
||||
ipv4.dhcp-vendor-class-identifier: --
|
||||
ipv4.dhcp-reject-servers: --
|
||||
ipv6.method: auto
|
||||
ipv6.dns: --
|
||||
ipv6.dns-search: --
|
||||
ipv6.dns-options: --
|
||||
ipv6.dns-priority: 0
|
||||
ipv6.addresses: --
|
||||
ipv6.gateway: --
|
||||
ipv6.routes: --
|
||||
ipv6.route-metric: -1
|
||||
ipv6.route-table: 0 (unspec)
|
||||
ipv6.routing-rules: --
|
||||
ipv6.ignore-auto-routes: no
|
||||
ipv6.ignore-auto-dns: no
|
||||
ipv6.never-default: no
|
||||
ipv6.may-fail: yes
|
||||
ipv6.required-timeout: -1 (default)
|
||||
ipv6.ip6-privacy: -1 (unknown)
|
||||
ipv6.addr-gen-mode: stable-privacy
|
||||
ipv6.ra-timeout: 0 (default)
|
||||
ipv6.dhcp-duid: --
|
||||
ipv6.dhcp-iaid: --
|
||||
ipv6.dhcp-timeout: 0 (default)
|
||||
ipv6.dhcp-send-hostname: yes
|
||||
ipv6.dhcp-hostname: --
|
||||
ipv6.dhcp-hostname-flags: 0x0 (none)
|
||||
ipv6.token: --
|
||||
team.config: {
|
||||
"runner": {
|
||||
"name": "roundrobin"
|
||||
},
|
||||
"link_watch": {
|
||||
"name": "ethtool"
|
||||
}
|
||||
}
|
||||
team.notify-peers-count: -1 (unset)
|
||||
team.notify-peers-interval: -1 (unset)
|
||||
team.mcast-rejoin-count: -1 (unset)
|
||||
team.mcast-rejoin-interval: -1 (unset)
|
||||
team.runner: roundrobin
|
||||
team.runner-hwaddr-policy: --
|
||||
team.runner-tx-hash: --
|
||||
team.runner-tx-balancer: --
|
||||
team.runner-tx-balancer-interval: -1 (unset)
|
||||
team.runner-active: yes
|
||||
team.runner-fast-rate: no
|
||||
team.runner-sys-prio: -1 (unset)
|
||||
team.runner-min-ports: -1 (unset)
|
||||
team.runner-agg-select-policy: --
|
||||
team.link-watchers: name=ethtool
|
||||
proxy.method: none
|
||||
proxy.browser-only: no
|
||||
proxy.pac-url: --
|
||||
proxy.pac-script: --
|
||||
1
tests/fixtures/generic/nmcli-team-port-config-blank.json
vendored
Normal file
1
tests/fixtures/generic/nmcli-team-port-config-blank.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[{"connection_id":"team1","connection_uuid":"a85e0eba-7140-4963-963d-ca9a0f6516ed","connection_stable_id":null,"connection_type":"802-3-ethernet","connection_interface_name":null,"connection_autoconnect":"yes","connection_autoconnect_priority":0,"connection_autoconnect_retries":-1,"connection_autoconnect_retries_text":"default","connection_multi_connect":0,"connection_multi_connect_text":"default","connection_auth_retries":-1,"connection_timestamp":0,"connection_read_only":"no","connection_permissions":null,"connection_zone":null,"connection_master":"d229f048-5c75-40f4-a7ff-61174546c506","connection_slave_type":"team","connection_autoconnect_slaves":-1,"connection_autoconnect_slaves_text":"default","connection_secondaries":null,"connection_gateway_ping_timeout":0,"connection_metered":"unknown","connection_lldp":"default","connection_mdns":-1,"connection_mdns_text":"default","connection_llmnr":-1,"connection_llmnr_text":"default","connection_dns_over_tls":-1,"connection_dns_over_tls_text":"default","connection_wait_device_timeout":-1,"802_3_ethernet_port":null,"802_3_ethernet_speed":0,"802_3_ethernet_duplex":null,"802_3_ethernet_auto_negotiate":"no","802_3_ethernet_mac_address":null,"802_3_ethernet_cloned_mac_address":null,"802_3_ethernet_generate_mac_address_mask":null,"802_3_ethernet_mac_address_blacklist":null,"802_3_ethernet_mtu":"auto","802_3_ethernet_s390_subchannels":null,"802_3_ethernet_s390_nettype":null,"802_3_ethernet_s390_options":null,"802_3_ethernet_wake_on_lan":"default","802_3_ethernet_wake_on_lan_password":null,"802_3_ethernet_accept_all_mac_addresses":-1,"802_3_ethernet_accept_all_mac_addresses_text":"default","team_port_config":null,"team_port_queue_id":0,"team_port_queue_id_text":"default","team_port_prio":0,"team_port_prio_text":"unset","team_port_sticky":"no","team_port_lacp_prio":0,"team_port_lacp_key":0,"team_port_lacp_key_text":"default","team_port_link_watchers":null}]
|
||||
47
tests/fixtures/generic/nmcli-team-port-config-blank.out
vendored
Normal file
47
tests/fixtures/generic/nmcli-team-port-config-blank.out
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
connection.id: team1
|
||||
connection.uuid: a85e0eba-7140-4963-963d-ca9a0f6516ed
|
||||
connection.stable-id: --
|
||||
connection.type: 802-3-ethernet
|
||||
connection.interface-name: --
|
||||
connection.autoconnect: yes
|
||||
connection.autoconnect-priority: 0
|
||||
connection.autoconnect-retries: -1 (default)
|
||||
connection.multi-connect: 0 (default)
|
||||
connection.auth-retries: -1
|
||||
connection.timestamp: 0
|
||||
connection.read-only: no
|
||||
connection.permissions: --
|
||||
connection.zone: --
|
||||
connection.master: d229f048-5c75-40f4-a7ff-61174546c506
|
||||
connection.slave-type: team
|
||||
connection.autoconnect-slaves: -1 (default)
|
||||
connection.secondaries: --
|
||||
connection.gateway-ping-timeout: 0
|
||||
connection.metered: unknown
|
||||
connection.lldp: default
|
||||
connection.mdns: -1 (default)
|
||||
connection.llmnr: -1 (default)
|
||||
connection.dns-over-tls: -1 (default)
|
||||
connection.wait-device-timeout: -1
|
||||
802-3-ethernet.port: --
|
||||
802-3-ethernet.speed: 0
|
||||
802-3-ethernet.duplex: --
|
||||
802-3-ethernet.auto-negotiate: no
|
||||
802-3-ethernet.mac-address: --
|
||||
802-3-ethernet.cloned-mac-address: --
|
||||
802-3-ethernet.generate-mac-address-mask:--
|
||||
802-3-ethernet.mac-address-blacklist: --
|
||||
802-3-ethernet.mtu: auto
|
||||
802-3-ethernet.s390-subchannels: --
|
||||
802-3-ethernet.s390-nettype: --
|
||||
802-3-ethernet.s390-options: --
|
||||
802-3-ethernet.wake-on-lan: default
|
||||
802-3-ethernet.wake-on-lan-password: --
|
||||
802-3-ethernet.accept-all-mac-addresses:-1 (default)
|
||||
team-port.config: --
|
||||
team-port.queue-id: 0 (default)
|
||||
team-port.prio: 0 (unset)
|
||||
team-port.sticky: no
|
||||
team-port.lacp-prio: 0
|
||||
team-port.lacp-key: 0 (default)
|
||||
team-port.link-watchers: --
|
||||
1
tests/fixtures/generic/nmcli-team-port-config.json
vendored
Normal file
1
tests/fixtures/generic/nmcli-team-port-config.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[{"connection_id":"team1","connection_uuid":"a85e0eba-7140-4963-963d-ca9a0f6516ed","connection_stable_id":null,"connection_type":"802-3-ethernet","connection_interface_name":null,"connection_autoconnect":"yes","connection_autoconnect_priority":0,"connection_autoconnect_retries":-1,"connection_autoconnect_retries_text":"default","connection_multi_connect":0,"connection_multi_connect_text":"default","connection_auth_retries":-1,"connection_timestamp":0,"connection_read_only":"no","connection_permissions":null,"connection_zone":null,"connection_master":"d229f048-5c75-40f4-a7ff-61174546c506","connection_slave_type":"team","connection_autoconnect_slaves":-1,"connection_autoconnect_slaves_text":"default","connection_secondaries":null,"connection_gateway_ping_timeout":0,"connection_metered":"unknown","connection_lldp":"default","connection_mdns":-1,"connection_mdns_text":"default","connection_llmnr":-1,"connection_llmnr_text":"default","connection_dns_over_tls":-1,"connection_dns_over_tls_text":"default","connection_wait_device_timeout":-1,"802_3_ethernet_port":null,"802_3_ethernet_speed":0,"802_3_ethernet_duplex":null,"802_3_ethernet_auto_negotiate":"no","802_3_ethernet_mac_address":null,"802_3_ethernet_cloned_mac_address":null,"802_3_ethernet_generate_mac_address_mask":null,"802_3_ethernet_mac_address_blacklist":null,"802_3_ethernet_mtu":"auto","802_3_ethernet_s390_subchannels":null,"802_3_ethernet_s390_nettype":null,"802_3_ethernet_s390_options":null,"802_3_ethernet_wake_on_lan":"default","802_3_ethernet_wake_on_lan_password":null,"802_3_ethernet_accept_all_mac_addresses":-1,"802_3_ethernet_accept_all_mac_addresses_text":"default","team_port_config":{"queue_id":0,"prio":0,"lacp_prio":0,"lacp_key":0},"team_port_queue_id":0,"team_port_queue_id_text":"default","team_port_prio":0,"team_port_prio_text":"unset","team_port_sticky":"no","team_port_lacp_prio":0,"team_port_lacp_key":0,"team_port_lacp_key_text":"default","team_port_link_watchers":null}]
|
||||
52
tests/fixtures/generic/nmcli-team-port-config.out
vendored
Normal file
52
tests/fixtures/generic/nmcli-team-port-config.out
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
connection.id: team1
|
||||
connection.uuid: a85e0eba-7140-4963-963d-ca9a0f6516ed
|
||||
connection.stable-id: --
|
||||
connection.type: 802-3-ethernet
|
||||
connection.interface-name: --
|
||||
connection.autoconnect: yes
|
||||
connection.autoconnect-priority: 0
|
||||
connection.autoconnect-retries: -1 (default)
|
||||
connection.multi-connect: 0 (default)
|
||||
connection.auth-retries: -1
|
||||
connection.timestamp: 0
|
||||
connection.read-only: no
|
||||
connection.permissions: --
|
||||
connection.zone: --
|
||||
connection.master: d229f048-5c75-40f4-a7ff-61174546c506
|
||||
connection.slave-type: team
|
||||
connection.autoconnect-slaves: -1 (default)
|
||||
connection.secondaries: --
|
||||
connection.gateway-ping-timeout: 0
|
||||
connection.metered: unknown
|
||||
connection.lldp: default
|
||||
connection.mdns: -1 (default)
|
||||
connection.llmnr: -1 (default)
|
||||
connection.dns-over-tls: -1 (default)
|
||||
connection.wait-device-timeout: -1
|
||||
802-3-ethernet.port: --
|
||||
802-3-ethernet.speed: 0
|
||||
802-3-ethernet.duplex: --
|
||||
802-3-ethernet.auto-negotiate: no
|
||||
802-3-ethernet.mac-address: --
|
||||
802-3-ethernet.cloned-mac-address: --
|
||||
802-3-ethernet.generate-mac-address-mask:--
|
||||
802-3-ethernet.mac-address-blacklist: --
|
||||
802-3-ethernet.mtu: auto
|
||||
802-3-ethernet.s390-subchannels: --
|
||||
802-3-ethernet.s390-nettype: --
|
||||
802-3-ethernet.s390-options: --
|
||||
802-3-ethernet.wake-on-lan: default
|
||||
802-3-ethernet.wake-on-lan-password: --
|
||||
802-3-ethernet.accept-all-mac-addresses:-1 (default)
|
||||
team-port.config: {
|
||||
"queue_id": 0,
|
||||
"prio": 0,
|
||||
"lacp_prio": 0,
|
||||
"lacp_key": 0
|
||||
}
|
||||
team-port.queue-id: 0 (default)
|
||||
team-port.prio: 0 (unset)
|
||||
team-port.sticky: no
|
||||
team-port.lacp-prio: 0
|
||||
team-port.lacp-key: 0 (default)
|
||||
team-port.link-watchers: --
|
||||
1
tests/fixtures/generic/rsync-i-stats-streaming.json
vendored
Normal file
1
tests/fixtures/generic/rsync-i-stats-streaming.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[{"total_files":23784,"regular_files":23191,"dir_files":593,"total_created_files":2651,"created_regular_files":2611,"created_dir_files":40,"deleted_files":0,"transferred_files":2629,"transferred_file_size":6880000000000,"literal_data":0,"matched_data":0,"file_list_size":98100,"file_list_generation_time":0.001,"file_list_transfer_time":0.0,"type":"summary","sent":8990,"received":1290000,"bytes_sec":370210.0,"total_size":6880000000000,"speedup":5311650.06}]
|
||||
1
tests/fixtures/generic/rsync-i-stats.json
vendored
Normal file
1
tests/fixtures/generic/rsync-i-stats.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[{"summary":{"total_files":23784,"regular_files":23191,"dir_files":593,"total_created_files":2651,"created_regular_files":2611,"created_dir_files":40,"deleted_files":0,"transferred_files":2629,"transferred_file_size":6880000000000,"literal_data":0,"matched_data":0,"file_list_size":98100,"file_list_generation_time":0.001,"file_list_transfer_time":0.0,"sent":8990,"received":1290000,"bytes_sec":370210.0,"total_size":6880000000000,"speedup":5311650.06},"files":[]}]
|
||||
56
tests/fixtures/generic/rsync-i-stats.out
vendored
Normal file
56
tests/fixtures/generic/rsync-i-stats.out
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
rsync[1817530] (server sender) heap statistics:
|
||||
arena: 1204224 (bytes from sbrk)
|
||||
ordblks: 46 (chunks not in use)
|
||||
|
||||
rsync[1007426] (receiver) heap statistics:
|
||||
arena: 9244672 (bytes from sbrk)
|
||||
ordblks: 57 (chunks not in use)
|
||||
smblks: 1 (free fastbin blocks)
|
||||
hblks: 1 (chunks from mmap)
|
||||
hblkhd: 266240 (bytes from mmap)
|
||||
allmem: 9510912 (bytes from sbrk + mmap)
|
||||
usmblks: 0 (always 0)
|
||||
fsmblks: 96 (bytes in freed fastbin blocks)
|
||||
uordblks: 486480 (bytes used)
|
||||
fordblks: 8758192 (bytes free)
|
||||
keepcost: 133856 (bytes in releasable chunk)
|
||||
smblks: 2 (free fastbin blocks)
|
||||
hblks: 1 (chunks from mmap)
|
||||
hblkhd: 266240 (bytes from mmap)
|
||||
allmem: 1470464 (bytes from sbrk + mmap)
|
||||
usmblks: 0 (always 0)
|
||||
fsmblks: 192 (bytes in freed fastbin blocks)
|
||||
uordblks: 478288 (bytes used)
|
||||
fordblks: 725936 (bytes free)
|
||||
keepcost: 427216 (bytes in releasable chunk)
|
||||
|
||||
rsync[1007424] (generator) heap statistics:
|
||||
arena: 1384448 (bytes from sbrk)
|
||||
ordblks: 6 (chunks not in use)
|
||||
smblks: 1 (free fastbin blocks)
|
||||
hblks: 1 (chunks from mmap)
|
||||
hblkhd: 266240 (bytes from mmap)
|
||||
allmem: 1650688 (bytes from sbrk + mmap)
|
||||
usmblks: 0 (always 0)
|
||||
fsmblks: 96 (bytes in freed fastbin blocks)
|
||||
uordblks: 486160 (bytes used)
|
||||
fordblks: 898288 (bytes free)
|
||||
keepcost: 132272 (bytes in releasable chunk)
|
||||
|
||||
Number of files: 23,784 (reg: 23,191, dir: 593)
|
||||
Number of created files: 2,651 (reg: 2,611, dir: 40)
|
||||
Number of deleted files: 0
|
||||
Number of regular files transferred: 2,629
|
||||
Total file size: 6.88T bytes
|
||||
Total transferred file size: 759.17G bytes
|
||||
Literal data: 0 bytes
|
||||
Matched data: 0 bytes
|
||||
File list size: 98.10K
|
||||
File list generation time: 0.001 seconds
|
||||
File list transfer time: 0.000 seconds
|
||||
Total bytes sent: 8.99K
|
||||
Total bytes received: 1.29M
|
||||
|
||||
sent 8.99K bytes received 1.29M bytes 370.21K bytes/sec
|
||||
total size is 6.88T speedup is 5,311,650.06 (DRY RUN)
|
||||
|
||||
78
tests/fixtures/generic/traceroute-long-ipv6-streaming.json
vendored
Normal file
78
tests/fixtures/generic/traceroute-long-ipv6-streaming.json
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
[
|
||||
{
|
||||
"type": "header",
|
||||
"destination_ip": "2a04:4e42:200::323",
|
||||
"destination_name": "turner-tls.map.fastly.net",
|
||||
"max_hops": 5,
|
||||
"data_bytes": 12
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 1,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 2,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": null,
|
||||
"name": null,
|
||||
"rtt": 27.635
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": null,
|
||||
"name": null,
|
||||
"rtt": 20.383
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": null,
|
||||
"name": null,
|
||||
"rtt": 23.438
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 3,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 4,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:1890:ff:ff08:12:242:117:16",
|
||||
"name": null,
|
||||
"rtt": 20.118
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:1890:ff:ff08:12:242:117:16",
|
||||
"name": null,
|
||||
"rtt": 20.327
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:1890:ff:ff08:12:242:117:16",
|
||||
"name": null,
|
||||
"rtt": 21.213
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 5,
|
||||
"probes": []
|
||||
}
|
||||
]
|
||||
1
tests/fixtures/generic/traceroute-long-ipv6.json
vendored
Normal file
1
tests/fixtures/generic/traceroute-long-ipv6.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"destination_ip":"2a04:4e42:200::323","destination_name":"turner-tls.map.fastly.net","max_hops":5,"data_bytes":12,"hops":[{"hop":1,"probes":[]},{"hop":2,"probes":[{"annotation":null,"asn":null,"ip":null,"name":null,"rtt":27.635},{"annotation":null,"asn":null,"ip":null,"name":null,"rtt":20.383},{"annotation":null,"asn":null,"ip":null,"name":null,"rtt":23.438}]},{"hop":3,"probes":[]},{"hop":4,"probes":[{"annotation":null,"asn":null,"ip":"2001:1890:ff:ff08:12:242:117:16","name":null,"rtt":20.118},{"annotation":null,"asn":null,"ip":"2001:1890:ff:ff08:12:242:117:16","name":null,"rtt":20.327},{"annotation":null,"asn":null,"ip":"2001:1890:ff:ff08:12:242:117:16","name":null,"rtt":21.213}]},{"hop":5,"probes":[]}]}
|
||||
6
tests/fixtures/generic/traceroute-long-ipv6.out
vendored
Normal file
6
tests/fixtures/generic/traceroute-long-ipv6.out
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
traceroute6 to turner-tls.map.fastly.net (2a04:4e42:200::323) from 2600:1700:bab0:d40:985:f00a:98bd:f142, 5 hops max, 12 byte packets
|
||||
1 * * *
|
||||
2 ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 27.635 ms 20.383 ms 23.438 ms
|
||||
3 * * *
|
||||
4 2001:1890:ff:ff08:12:242:117:16 20.118 ms 20.327 ms 21.213 ms
|
||||
5 * * *
|
||||
225
tests/fixtures/generic/traceroute-n-ipv4-streaming.json
vendored
Normal file
225
tests/fixtures/generic/traceroute-n-ipv4-streaming.json
vendored
Normal file
@@ -0,0 +1,225 @@
|
||||
[
|
||||
{
|
||||
"type": "header",
|
||||
"destination_ip": "199.58.80.40",
|
||||
"destination_name": "www.koumbit.org",
|
||||
"max_hops": 30,
|
||||
"data_bytes": 60
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 1,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "192.168.2.1",
|
||||
"name": null,
|
||||
"rtt": 0.967
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "192.168.2.1",
|
||||
"name": null,
|
||||
"rtt": 1.022
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "192.168.2.1",
|
||||
"name": null,
|
||||
"rtt": 1.204
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 2,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "24.212.242.17",
|
||||
"name": null,
|
||||
"rtt": 10.176
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "24.212.242.17",
|
||||
"name": null,
|
||||
"rtt": 18.136
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "24.212.242.17",
|
||||
"name": null,
|
||||
"rtt": 18.244
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 3,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "10.170.192.58",
|
||||
"name": null,
|
||||
"rtt": 19.396
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "10.170.192.58",
|
||||
"name": null,
|
||||
"rtt": 19.575
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "10.170.192.58",
|
||||
"name": null,
|
||||
"rtt": 19.572
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 4,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "192.171.61.61",
|
||||
"name": null,
|
||||
"rtt": 23.072
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "206.248.155.109",
|
||||
"name": null,
|
||||
"rtt": 17.073
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "192.171.63.17",
|
||||
"name": null,
|
||||
"rtt": 23.308
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 5,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "206.248.189.97",
|
||||
"name": null,
|
||||
"rtt": 20.521
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "206.248.189.97",
|
||||
"name": null,
|
||||
"rtt": 22.837
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "206.248.189.97",
|
||||
"name": null,
|
||||
"rtt": 23.194
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 6,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "198.179.18.41",
|
||||
"name": null,
|
||||
"rtt": 18.334
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "198.179.18.41",
|
||||
"name": null,
|
||||
"rtt": 17.894
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "198.179.18.41",
|
||||
"name": null,
|
||||
"rtt": 17.792
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 7,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "64.15.69.54",
|
||||
"name": null,
|
||||
"rtt": 17.056
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "64.15.69.54",
|
||||
"name": null,
|
||||
"rtt": 14.033
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "64.15.69.54",
|
||||
"name": null,
|
||||
"rtt": 12.351
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 8,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "199.58.80.40",
|
||||
"name": null,
|
||||
"rtt": 18.203
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "199.58.80.40",
|
||||
"name": null,
|
||||
"rtt": 18.789
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "199.58.80.40",
|
||||
"name": null,
|
||||
"rtt": 18.906
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -1 +1 @@
|
||||
{"destination_ip":"199.58.80.40","destination_name":"www.koumbit.org","hops":[{"hop":1,"probes":[{"annotation":null,"asn":null,"ip":"192.168.2.1","name":null,"rtt":0.967},{"annotation":null,"asn":null,"ip":"192.168.2.1","name":null,"rtt":1.022},{"annotation":null,"asn":null,"ip":"192.168.2.1","name":null,"rtt":1.204}]},{"hop":2,"probes":[{"annotation":null,"asn":null,"ip":"24.212.242.17","name":null,"rtt":10.176},{"annotation":null,"asn":null,"ip":"24.212.242.17","name":null,"rtt":18.136},{"annotation":null,"asn":null,"ip":"24.212.242.17","name":null,"rtt":18.244}]},{"hop":3,"probes":[{"annotation":null,"asn":null,"ip":"10.170.192.58","name":null,"rtt":19.396},{"annotation":null,"asn":null,"ip":"10.170.192.58","name":null,"rtt":19.575},{"annotation":null,"asn":null,"ip":"10.170.192.58","name":null,"rtt":19.572}]},{"hop":4,"probes":[{"annotation":null,"asn":null,"ip":"192.171.61.61","name":null,"rtt":23.072},{"annotation":null,"asn":null,"ip":"206.248.155.109","name":null,"rtt":17.073},{"annotation":null,"asn":null,"ip":"192.171.63.17","name":null,"rtt":23.308}]},{"hop":5,"probes":[{"annotation":null,"asn":null,"ip":"206.248.189.97","name":null,"rtt":20.521},{"annotation":null,"asn":null,"ip":"206.248.189.97","name":null,"rtt":22.837},{"annotation":null,"asn":null,"ip":"206.248.189.97","name":null,"rtt":23.194}]},{"hop":6,"probes":[{"annotation":null,"asn":null,"ip":"198.179.18.41","name":null,"rtt":18.334},{"annotation":null,"asn":null,"ip":"198.179.18.41","name":null,"rtt":17.894},{"annotation":null,"asn":null,"ip":"198.179.18.41","name":null,"rtt":17.792}]},{"hop":7,"probes":[{"annotation":null,"asn":null,"ip":"64.15.69.54","name":null,"rtt":17.056},{"annotation":null,"asn":null,"ip":"64.15.69.54","name":null,"rtt":14.033},{"annotation":null,"asn":null,"ip":"64.15.69.54","name":null,"rtt":12.351}]},{"hop":8,"probes":[{"annotation":null,"asn":null,"ip":"199.58.80.40","name":null,"rtt":18.203},{"annotation":null,"asn":null,"ip":"199.58.80.40","name":null,"rtt":18.789},{"annotation":null,"asn":null,"ip":"199.58.80.40","name":null,"rtt":18.906}]}]}
|
||||
{"destination_ip":"199.58.80.40","destination_name":"www.koumbit.org","max_hops":30,"data_bytes":60,"hops":[{"hop":1,"probes":[{"annotation":null,"asn":null,"ip":"192.168.2.1","name":null,"rtt":0.967},{"annotation":null,"asn":null,"ip":"192.168.2.1","name":null,"rtt":1.022},{"annotation":null,"asn":null,"ip":"192.168.2.1","name":null,"rtt":1.204}]},{"hop":2,"probes":[{"annotation":null,"asn":null,"ip":"24.212.242.17","name":null,"rtt":10.176},{"annotation":null,"asn":null,"ip":"24.212.242.17","name":null,"rtt":18.136},{"annotation":null,"asn":null,"ip":"24.212.242.17","name":null,"rtt":18.244}]},{"hop":3,"probes":[{"annotation":null,"asn":null,"ip":"10.170.192.58","name":null,"rtt":19.396},{"annotation":null,"asn":null,"ip":"10.170.192.58","name":null,"rtt":19.575},{"annotation":null,"asn":null,"ip":"10.170.192.58","name":null,"rtt":19.572}]},{"hop":4,"probes":[{"annotation":null,"asn":null,"ip":"192.171.61.61","name":null,"rtt":23.072},{"annotation":null,"asn":null,"ip":"206.248.155.109","name":null,"rtt":17.073},{"annotation":null,"asn":null,"ip":"192.171.63.17","name":null,"rtt":23.308}]},{"hop":5,"probes":[{"annotation":null,"asn":null,"ip":"206.248.189.97","name":null,"rtt":20.521},{"annotation":null,"asn":null,"ip":"206.248.189.97","name":null,"rtt":22.837},{"annotation":null,"asn":null,"ip":"206.248.189.97","name":null,"rtt":23.194}]},{"hop":6,"probes":[{"annotation":null,"asn":null,"ip":"198.179.18.41","name":null,"rtt":18.334},{"annotation":null,"asn":null,"ip":"198.179.18.41","name":null,"rtt":17.894},{"annotation":null,"asn":null,"ip":"198.179.18.41","name":null,"rtt":17.792}]},{"hop":7,"probes":[{"annotation":null,"asn":null,"ip":"64.15.69.54","name":null,"rtt":17.056},{"annotation":null,"asn":null,"ip":"64.15.69.54","name":null,"rtt":14.033},{"annotation":null,"asn":null,"ip":"64.15.69.54","name":null,"rtt":12.351}]},{"hop":8,"probes":[{"annotation":null,"asn":null,"ip":"199.58.80.40","name":null,"rtt":18.203},{"annotation":null,"asn":null,"ip":"199.58.80.40","name":null,"rtt":18.789},{"annotation":null,"asn":null,"ip":"199.58.80.40","name":null,"rtt":18.906}]}]}
|
||||
|
||||
333
tests/fixtures/generic/traceroute-n-ipv6-streaming.json
vendored
Normal file
333
tests/fixtures/generic/traceroute-n-ipv6-streaming.json
vendored
Normal file
@@ -0,0 +1,333 @@
|
||||
[
|
||||
{
|
||||
"type": "header",
|
||||
"destination_ip": "2607:f8b0:4020:806::2004",
|
||||
"destination_name": "www.google.com",
|
||||
"max_hops": 30,
|
||||
"data_bytes": 80
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 1,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2605:9000:402:6a01::1",
|
||||
"name": null,
|
||||
"rtt": 4.181
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2605:9000:402:6a01::1",
|
||||
"name": null,
|
||||
"rtt": 4.294
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2605:9000:402:6a01::1",
|
||||
"name": null,
|
||||
"rtt": 4.253
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 2,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2605:9000:0:400a::f1",
|
||||
"name": null,
|
||||
"rtt": 0.354
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2605:9000:0:400a::f1",
|
||||
"name": null,
|
||||
"rtt": 0.532
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2605:9000:0:400a::f1",
|
||||
"name": null,
|
||||
"rtt": 0.484
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 3,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:5a0:40:100::51",
|
||||
"name": null,
|
||||
"rtt": 15.284
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2605:9000:0:101::1",
|
||||
"name": null,
|
||||
"rtt": 4.864
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:5a0:40:100::51",
|
||||
"name": null,
|
||||
"rtt": 15.415
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 4,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:5a0:40:100::51",
|
||||
"name": null,
|
||||
"rtt": 15.379
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:5a0:300:200::202",
|
||||
"name": null,
|
||||
"rtt": 12.709
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:5a0:40:100::51",
|
||||
"name": null,
|
||||
"rtt": 15.289
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 5,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:5a0:1900:100::12",
|
||||
"name": null,
|
||||
"rtt": 10.02
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:5a0:1900:100::12",
|
||||
"name": null,
|
||||
"rtt": 10.212
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:5a0:1900:100::12",
|
||||
"name": null,
|
||||
"rtt": 10.163
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 6,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:5a0:1900:100::12",
|
||||
"name": null,
|
||||
"rtt": 10.113
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:5a0:400:700::17",
|
||||
"name": null,
|
||||
"rtt": 8.399
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:5a0:1900:100::12",
|
||||
"name": null,
|
||||
"rtt": 10.215
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 7,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:4860:0:1127::2",
|
||||
"name": null,
|
||||
"rtt": 9.11
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:5a0:400:700::17",
|
||||
"name": null,
|
||||
"rtt": 8.476
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:5a0:400:700::17",
|
||||
"name": null,
|
||||
"rtt": 8.38
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 8,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:4860::8:4000:cd80",
|
||||
"name": null,
|
||||
"rtt": 9.428
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:4860:0:1128::14",
|
||||
"name": null,
|
||||
"rtt": 9.36
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:4860::8:4000:cd80",
|
||||
"name": null,
|
||||
"rtt": 9.229
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 9,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:4860::9:4001:d508",
|
||||
"name": null,
|
||||
"rtt": 9.376
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:4860::c:4002:652a",
|
||||
"name": null,
|
||||
"rtt": 9.105
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:4860::c:4002:6523",
|
||||
"name": null,
|
||||
"rtt": 9.384
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 10,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:4860:0:11da::1",
|
||||
"name": null,
|
||||
"rtt": 8.489
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:4860::9:4001:d508",
|
||||
"name": null,
|
||||
"rtt": 8.978
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:4860::1c:4000:f5eb",
|
||||
"name": null,
|
||||
"rtt": 9.64
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 11,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:4860:0:1::c73",
|
||||
"name": null,
|
||||
"rtt": 9.596
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:4860:0:1::c73",
|
||||
"name": null,
|
||||
"rtt": 9.077
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2001:4860:0:1::c73",
|
||||
"name": null,
|
||||
"rtt": 9.724
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 12,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2607:f8b0:4020:806::2004",
|
||||
"name": null,
|
||||
"rtt": 8.086
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2607:f8b0:4020:806::2004",
|
||||
"name": null,
|
||||
"rtt": 8.091
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "2607:f8b0:4020:806::2004",
|
||||
"name": null,
|
||||
"rtt": 8.436
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -1 +1 @@
|
||||
{"destination_ip":"2607:f8b0:4020:806::2004","destination_name":"www.google.com","hops":[{"hop":1,"probes":[{"annotation":null,"asn":null,"ip":"2605:9000:402:6a01::1","name":null,"rtt":4.181},{"annotation":null,"asn":null,"ip":"2605:9000:402:6a01::1","name":null,"rtt":4.294},{"annotation":null,"asn":null,"ip":"2605:9000:402:6a01::1","name":null,"rtt":4.253}]},{"hop":2,"probes":[{"annotation":null,"asn":null,"ip":"2605:9000:0:400a::f1","name":null,"rtt":0.354},{"annotation":null,"asn":null,"ip":"2605:9000:0:400a::f1","name":null,"rtt":0.532},{"annotation":null,"asn":null,"ip":"2605:9000:0:400a::f1","name":null,"rtt":0.484}]},{"hop":3,"probes":[{"annotation":null,"asn":null,"ip":"2001:5a0:40:100::51","name":null,"rtt":15.284},{"annotation":null,"asn":null,"ip":"2605:9000:0:101::1","name":null,"rtt":4.864},{"annotation":null,"asn":null,"ip":"2001:5a0:40:100::51","name":null,"rtt":15.415}]},{"hop":4,"probes":[{"annotation":null,"asn":null,"ip":"2001:5a0:40:100::51","name":null,"rtt":15.379},{"annotation":null,"asn":null,"ip":"2001:5a0:300:200::202","name":null,"rtt":12.709},{"annotation":null,"asn":null,"ip":"2001:5a0:40:100::51","name":null,"rtt":15.289}]},{"hop":5,"probes":[{"annotation":null,"asn":null,"ip":"2001:5a0:1900:100::12","name":null,"rtt":10.02},{"annotation":null,"asn":null,"ip":"2001:5a0:1900:100::12","name":null,"rtt":10.212},{"annotation":null,"asn":null,"ip":"2001:5a0:1900:100::12","name":null,"rtt":10.163}]},{"hop":6,"probes":[{"annotation":null,"asn":null,"ip":"2001:5a0:1900:100::12","name":null,"rtt":10.113},{"annotation":null,"asn":null,"ip":"2001:5a0:400:700::17","name":null,"rtt":8.399},{"annotation":null,"asn":null,"ip":"2001:5a0:1900:100::12","name":null,"rtt":10.215}]},{"hop":7,"probes":[{"annotation":null,"asn":null,"ip":"2001:4860:0:1127::2","name":null,"rtt":9.11},{"annotation":null,"asn":null,"ip":"2001:5a0:400:700::17","name":null,"rtt":8.476},{"annotation":null,"asn":null,"ip":"2001:5a0:400:700::17","name":null,"rtt":8.38}]},{"hop":8,"probes":[{"annotation":null,"asn":null,"ip":"2001:4860::8:4000:cd80","name":null,"rtt":9.428},{"annotation":null,"asn":null,"ip":"2001:4860:0:1128::14","name":null,"rtt":9.36},{"annotation":null,"asn":null,"ip":"2001:4860::8:4000:cd80","name":null,"rtt":9.229}]},{"hop":9,"probes":[{"annotation":null,"asn":null,"ip":"2001:4860::9:4001:d508","name":null,"rtt":9.376},{"annotation":null,"asn":null,"ip":"2001:4860::c:4002:652a","name":null,"rtt":9.105},{"annotation":null,"asn":null,"ip":"2001:4860::c:4002:6523","name":null,"rtt":9.384}]},{"hop":10,"probes":[{"annotation":null,"asn":null,"ip":"2001:4860:0:11da::1","name":null,"rtt":8.489},{"annotation":null,"asn":null,"ip":"2001:4860::9:4001:d508","name":null,"rtt":8.978},{"annotation":null,"asn":null,"ip":"2001:4860::1c:4000:f5eb","name":null,"rtt":9.64}]},{"hop":11,"probes":[{"annotation":null,"asn":null,"ip":"2001:4860:0:1::c73","name":null,"rtt":9.596},{"annotation":null,"asn":null,"ip":"2001:4860:0:1::c73","name":null,"rtt":9.077},{"annotation":null,"asn":null,"ip":"2001:4860:0:1::c73","name":null,"rtt":9.724}]},{"hop":12,"probes":[{"annotation":null,"asn":null,"ip":"2607:f8b0:4020:806::2004","name":null,"rtt":8.086},{"annotation":null,"asn":null,"ip":"2607:f8b0:4020:806::2004","name":null,"rtt":8.091},{"annotation":null,"asn":null,"ip":"2607:f8b0:4020:806::2004","name":null,"rtt":8.436}]}]}
|
||||
{"destination_ip":"2607:f8b0:4020:806::2004","destination_name":"www.google.com","max_hops":30,"data_bytes":80,"hops":[{"hop":1,"probes":[{"annotation":null,"asn":null,"ip":"2605:9000:402:6a01::1","name":null,"rtt":4.181},{"annotation":null,"asn":null,"ip":"2605:9000:402:6a01::1","name":null,"rtt":4.294},{"annotation":null,"asn":null,"ip":"2605:9000:402:6a01::1","name":null,"rtt":4.253}]},{"hop":2,"probes":[{"annotation":null,"asn":null,"ip":"2605:9000:0:400a::f1","name":null,"rtt":0.354},{"annotation":null,"asn":null,"ip":"2605:9000:0:400a::f1","name":null,"rtt":0.532},{"annotation":null,"asn":null,"ip":"2605:9000:0:400a::f1","name":null,"rtt":0.484}]},{"hop":3,"probes":[{"annotation":null,"asn":null,"ip":"2001:5a0:40:100::51","name":null,"rtt":15.284},{"annotation":null,"asn":null,"ip":"2605:9000:0:101::1","name":null,"rtt":4.864},{"annotation":null,"asn":null,"ip":"2001:5a0:40:100::51","name":null,"rtt":15.415}]},{"hop":4,"probes":[{"annotation":null,"asn":null,"ip":"2001:5a0:40:100::51","name":null,"rtt":15.379},{"annotation":null,"asn":null,"ip":"2001:5a0:300:200::202","name":null,"rtt":12.709},{"annotation":null,"asn":null,"ip":"2001:5a0:40:100::51","name":null,"rtt":15.289}]},{"hop":5,"probes":[{"annotation":null,"asn":null,"ip":"2001:5a0:1900:100::12","name":null,"rtt":10.02},{"annotation":null,"asn":null,"ip":"2001:5a0:1900:100::12","name":null,"rtt":10.212},{"annotation":null,"asn":null,"ip":"2001:5a0:1900:100::12","name":null,"rtt":10.163}]},{"hop":6,"probes":[{"annotation":null,"asn":null,"ip":"2001:5a0:1900:100::12","name":null,"rtt":10.113},{"annotation":null,"asn":null,"ip":"2001:5a0:400:700::17","name":null,"rtt":8.399},{"annotation":null,"asn":null,"ip":"2001:5a0:1900:100::12","name":null,"rtt":10.215}]},{"hop":7,"probes":[{"annotation":null,"asn":null,"ip":"2001:4860:0:1127::2","name":null,"rtt":9.11},{"annotation":null,"asn":null,"ip":"2001:5a0:400:700::17","name":null,"rtt":8.476},{"annotation":null,"asn":null,"ip":"2001:5a0:400:700::17","name":null,"rtt":8.38}]},{"hop":8,"probes":[{"annotation":null,"asn":null,"ip":"2001:4860::8:4000:cd80","name":null,"rtt":9.428},{"annotation":null,"asn":null,"ip":"2001:4860:0:1128::14","name":null,"rtt":9.36},{"annotation":null,"asn":null,"ip":"2001:4860::8:4000:cd80","name":null,"rtt":9.229}]},{"hop":9,"probes":[{"annotation":null,"asn":null,"ip":"2001:4860::9:4001:d508","name":null,"rtt":9.376},{"annotation":null,"asn":null,"ip":"2001:4860::c:4002:652a","name":null,"rtt":9.105},{"annotation":null,"asn":null,"ip":"2001:4860::c:4002:6523","name":null,"rtt":9.384}]},{"hop":10,"probes":[{"annotation":null,"asn":null,"ip":"2001:4860:0:11da::1","name":null,"rtt":8.489},{"annotation":null,"asn":null,"ip":"2001:4860::9:4001:d508","name":null,"rtt":8.978},{"annotation":null,"asn":null,"ip":"2001:4860::1c:4000:f5eb","name":null,"rtt":9.64}]},{"hop":11,"probes":[{"annotation":null,"asn":null,"ip":"2001:4860:0:1::c73","name":null,"rtt":9.596},{"annotation":null,"asn":null,"ip":"2001:4860:0:1::c73","name":null,"rtt":9.077},{"annotation":null,"asn":null,"ip":"2001:4860:0:1::c73","name":null,"rtt":9.724}]},{"hop":12,"probes":[{"annotation":null,"asn":null,"ip":"2607:f8b0:4020:806::2004","name":null,"rtt":8.086},{"annotation":null,"asn":null,"ip":"2607:f8b0:4020:806::2004","name":null,"rtt":8.091},{"annotation":null,"asn":null,"ip":"2607:f8b0:4020:806::2004","name":null,"rtt":8.436}]}]}
|
||||
|
||||
113
tests/fixtures/generic/traceroute-n-q1-ipv4-streaming.json
vendored
Normal file
113
tests/fixtures/generic/traceroute-n-q1-ipv4-streaming.json
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
[
|
||||
{
|
||||
"type": "header",
|
||||
"destination_ip": "199.58.80.40",
|
||||
"destination_name": "www.koumbit.org",
|
||||
"max_hops": 30,
|
||||
"data_bytes": 60
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 1,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "192.168.2.1",
|
||||
"name": null,
|
||||
"rtt": 3.425
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 2,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "24.212.242.17",
|
||||
"name": null,
|
||||
"rtt": 16.153
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 3,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "10.170.192.58",
|
||||
"name": null,
|
||||
"rtt": 17.231
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 4,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "192.171.61.161",
|
||||
"name": null,
|
||||
"rtt": 25.393
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 5,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "206.248.189.97",
|
||||
"name": null,
|
||||
"rtt": 25.322
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 6,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "198.179.18.41",
|
||||
"name": null,
|
||||
"rtt": 23.755
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 7,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "64.15.69.54",
|
||||
"name": null,
|
||||
"rtt": 25.091
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 8,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "199.58.80.40",
|
||||
"name": null,
|
||||
"rtt": 25.196
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -1 +1 @@
|
||||
{"destination_ip":"199.58.80.40","destination_name":"www.koumbit.org","hops":[{"hop":1,"probes":[{"annotation":null,"asn":null,"ip":"192.168.2.1","name":null,"rtt":3.425}]},{"hop":2,"probes":[{"annotation":null,"asn":null,"ip":"24.212.242.17","name":null,"rtt":16.153}]},{"hop":3,"probes":[{"annotation":null,"asn":null,"ip":"10.170.192.58","name":null,"rtt":17.231}]},{"hop":4,"probes":[{"annotation":null,"asn":null,"ip":"192.171.61.161","name":null,"rtt":25.393}]},{"hop":5,"probes":[{"annotation":null,"asn":null,"ip":"206.248.189.97","name":null,"rtt":25.322}]},{"hop":6,"probes":[{"annotation":null,"asn":null,"ip":"198.179.18.41","name":null,"rtt":23.755}]},{"hop":7,"probes":[{"annotation":null,"asn":null,"ip":"64.15.69.54","name":null,"rtt":25.091}]},{"hop":8,"probes":[{"annotation":null,"asn":null,"ip":"199.58.80.40","name":null,"rtt":25.196}]}]}
|
||||
{"destination_ip":"199.58.80.40","destination_name":"www.koumbit.org","max_hops":30,"data_bytes":60,"hops":[{"hop":1,"probes":[{"annotation":null,"asn":null,"ip":"192.168.2.1","name":null,"rtt":3.425}]},{"hop":2,"probes":[{"annotation":null,"asn":null,"ip":"24.212.242.17","name":null,"rtt":16.153}]},{"hop":3,"probes":[{"annotation":null,"asn":null,"ip":"10.170.192.58","name":null,"rtt":17.231}]},{"hop":4,"probes":[{"annotation":null,"asn":null,"ip":"192.171.61.161","name":null,"rtt":25.393}]},{"hop":5,"probes":[{"annotation":null,"asn":null,"ip":"206.248.189.97","name":null,"rtt":25.322}]},{"hop":6,"probes":[{"annotation":null,"asn":null,"ip":"198.179.18.41","name":null,"rtt":23.755}]},{"hop":7,"probes":[{"annotation":null,"asn":null,"ip":"64.15.69.54","name":null,"rtt":25.091}]},{"hop":8,"probes":[{"annotation":null,"asn":null,"ip":"199.58.80.40","name":null,"rtt":25.196}]}]}
|
||||
|
||||
414
tests/fixtures/generic/traceroute1-streaming.json
vendored
Normal file
414
tests/fixtures/generic/traceroute1-streaming.json
vendored
Normal file
@@ -0,0 +1,414 @@
|
||||
[
|
||||
{
|
||||
"type": "header",
|
||||
"destination_ip": "173.207.22.152",
|
||||
"destination_name": "http://google.es",
|
||||
"max_hops": 30,
|
||||
"data_bytes": 60
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 1,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": "!P",
|
||||
"asn": 1739,
|
||||
"ip": "131.240.100.12",
|
||||
"name": "131.240.100.12",
|
||||
"rtt": 0.676
|
||||
},
|
||||
{
|
||||
"annotation": "!",
|
||||
"asn": 1739,
|
||||
"ip": "131.240.100.12",
|
||||
"name": "131.240.100.12",
|
||||
"rtt": 0.763
|
||||
},
|
||||
{
|
||||
"annotation": "!<500>",
|
||||
"asn": 1739,
|
||||
"ip": "131.240.100.12",
|
||||
"name": "131.240.100.12",
|
||||
"rtt": 0.91
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 2,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 1739,
|
||||
"ip": "131.232.1.26",
|
||||
"name": "http://tut1-fw-vlan558.av.tut.fi",
|
||||
"rtt": 0.266
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 1739,
|
||||
"ip": "131.232.1.26",
|
||||
"name": "http://tut1-fw-vlan558.av.tut.fi",
|
||||
"rtt": 0.404
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 1739,
|
||||
"ip": "131.232.1.26",
|
||||
"name": "http://tut1-fw-vlan558.av.tut.fi",
|
||||
"rtt": 0.493
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 3,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 1739,
|
||||
"ip": "131.232.1.20",
|
||||
"name": "http://surf-gw-vlan557.av.tut.fi",
|
||||
"rtt": 0.967
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 1739,
|
||||
"ip": "131.232.1.20",
|
||||
"name": "http://surf-gw-vlan557.av.tut.fi",
|
||||
"rtt": 0.961
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 1739,
|
||||
"ip": "131.232.1.20",
|
||||
"name": "http://surf-gw-vlan557.av.tut.fi",
|
||||
"rtt": 1.085
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 4,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 1739,
|
||||
"ip": "130.230.1.237",
|
||||
"name": "http://funet-tut6-rtr-xe-0-0-0.cc.tut.fi",
|
||||
"rtt": 1.096
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 1739,
|
||||
"ip": "130.230.1.237",
|
||||
"name": "http://funet-tut6-rtr-xe-0-0-0.cc.tut.fi",
|
||||
"rtt": 1.086
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 1739,
|
||||
"ip": "130.230.1.237",
|
||||
"name": "http://funet-tut6-rtr-xe-0-0-0.cc.tut.fi",
|
||||
"rtt": 1.049
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 5,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 1741,
|
||||
"ip": "86.50.255.220",
|
||||
"name": "http://hameenlinna2-et-0-0-0-1.ip.funet.fi",
|
||||
"rtt": 3.81
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 1741,
|
||||
"ip": "86.50.255.220",
|
||||
"name": "http://hameenlinna2-et-0-0-0-1.ip.funet.fi",
|
||||
"rtt": 3.845
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 1741,
|
||||
"ip": "86.50.255.220",
|
||||
"name": "http://hameenlinna2-et-0-0-0-1.ip.funet.fi",
|
||||
"rtt": 3.82
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 6,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 1741,
|
||||
"ip": "86.50.255.224",
|
||||
"name": "http://hameenlinna1-et-0-0-1-1.ip.funet.fi",
|
||||
"rtt": 29.055
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 1741,
|
||||
"ip": "86.50.255.224",
|
||||
"name": "http://hameenlinna1-et-0-0-1-1.ip.funet.fi",
|
||||
"rtt": 29.013
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 1741,
|
||||
"ip": "86.50.255.224",
|
||||
"name": "http://hameenlinna1-et-0-0-1-1.ip.funet.fi",
|
||||
"rtt": 28.977
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 7,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 1741,
|
||||
"ip": "86.50.255.223",
|
||||
"name": "http://espoo2-et-0-1-2-1.ip.funet.fi",
|
||||
"rtt": 3.468
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 1741,
|
||||
"ip": "86.50.255.223",
|
||||
"name": "http://espoo2-et-0-1-2-1.ip.funet.fi",
|
||||
"rtt": 8.007
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 1741,
|
||||
"ip": "86.50.255.223",
|
||||
"name": "http://espoo2-et-0-1-2-1.ip.funet.fi",
|
||||
"rtt": 7.89
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 8,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 1741,
|
||||
"ip": "86.50.255.232",
|
||||
"name": "http://espoo1-et-0-1-7-1.ip.funet.fi",
|
||||
"rtt": 13.498
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 1741,
|
||||
"ip": "86.50.255.232",
|
||||
"name": "http://espoo1-et-0-1-7-1.ip.funet.fi",
|
||||
"rtt": 13.307
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 1741,
|
||||
"ip": "86.50.255.232",
|
||||
"name": "http://espoo1-et-0-1-7-1.ip.funet.fi",
|
||||
"rtt": 13.399
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 9,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 2603,
|
||||
"ip": "109.105.102.168",
|
||||
"name": "http://fi-csc2.nordu.net",
|
||||
"rtt": 3.25
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 2603,
|
||||
"ip": "109.105.102.168",
|
||||
"name": "http://fi-csc2.nordu.net",
|
||||
"rtt": 3.268
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 2603,
|
||||
"ip": "109.105.102.168",
|
||||
"name": "http://fi-csc2.nordu.net",
|
||||
"rtt": 3.236
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 10,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 2603,
|
||||
"ip": "109.105.97.93",
|
||||
"name": "http://se-fre.nordu.net",
|
||||
"rtt": 9.418
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 2603,
|
||||
"ip": "109.105.97.93",
|
||||
"name": "http://se-fre.nordu.net",
|
||||
"rtt": 9.41
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 2603,
|
||||
"ip": "109.105.97.93",
|
||||
"name": "http://se-fre.nordu.net",
|
||||
"rtt": 9.369
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 11,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 2603,
|
||||
"ip": "109.105.97.27",
|
||||
"name": "http://se-kst2.nordu.net",
|
||||
"rtt": 9.617
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 2603,
|
||||
"ip": "109.105.97.27",
|
||||
"name": "http://se-kst2.nordu.net",
|
||||
"rtt": 9.594
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 2603,
|
||||
"ip": "109.105.97.27",
|
||||
"name": "http://se-kst2.nordu.net",
|
||||
"rtt": 9.603
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 12,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "192.121.80.47",
|
||||
"name": "http://as15169-10g-sk1.sthix.net",
|
||||
"rtt": 10.01
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 15169,
|
||||
"ip": "72.14.196.42",
|
||||
"name": "72.14.196.42",
|
||||
"rtt": 9.182
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 15169,
|
||||
"ip": "72.14.196.42",
|
||||
"name": "72.14.196.42",
|
||||
"rtt": 44.983
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 13,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 15169,
|
||||
"ip": "108.170.254.49",
|
||||
"name": "108.170.254.49",
|
||||
"rtt": 10.852
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 15169,
|
||||
"ip": "108.170.254.33",
|
||||
"name": "108.170.254.33",
|
||||
"rtt": 11.185
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 15169,
|
||||
"ip": "108.170.254.49",
|
||||
"name": "108.170.254.49",
|
||||
"rtt": 10.876
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 14,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 15169,
|
||||
"ip": "209.85.242.11",
|
||||
"name": "209.85.242.11",
|
||||
"rtt": 10.192
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 15169,
|
||||
"ip": "209.85.242.11",
|
||||
"name": "209.85.242.11",
|
||||
"rtt": 10.471
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 15169,
|
||||
"ip": "209.85.242.11",
|
||||
"name": "209.85.242.11",
|
||||
"rtt": 10.502
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 15,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 15169,
|
||||
"ip": "172.217.21.163",
|
||||
"name": "http://arn11s03-in-f3.1e100.net",
|
||||
"rtt": 9.652
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 15169,
|
||||
"ip": "172.217.21.163",
|
||||
"name": "http://arn11s03-in-f3.1e100.net",
|
||||
"rtt": 9.664
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": 15169,
|
||||
"ip": "172.217.21.163",
|
||||
"name": "http://arn11s03-in-f3.1e100.net",
|
||||
"rtt": 9.777
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
2
tests/fixtures/generic/traceroute1.json
vendored
2
tests/fixtures/generic/traceroute1.json
vendored
File diff suppressed because one or more lines are too long
260
tests/fixtures/generic/traceroute2-streaming.json
vendored
Normal file
260
tests/fixtures/generic/traceroute2-streaming.json
vendored
Normal file
@@ -0,0 +1,260 @@
|
||||
[
|
||||
{
|
||||
"type": "header",
|
||||
"destination_ip": "216.58.194.46",
|
||||
"destination_name": "google.com",
|
||||
"max_hops": 30,
|
||||
"data_bytes": 40
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 1,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "216.230.231.141",
|
||||
"name": "216-230-231-141.static.houston.tx.oplink.net",
|
||||
"rtt": 198.574
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "216.230.231.141",
|
||||
"name": "216-230-231-141.static.houston.tx.oplink.net",
|
||||
"rtt": 198.65
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 2,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 3,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 4,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "72.14.242.34",
|
||||
"name": "72.14.242.34",
|
||||
"rtt": 4.932
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "72.14.242.34",
|
||||
"name": "72.14.242.34",
|
||||
"rtt": 4.945
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "72.14.242.34",
|
||||
"name": "72.14.242.34",
|
||||
"rtt": 4.951
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 5,
|
||||
"probes": []
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 6,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "108.170.230.116",
|
||||
"name": "108.170.230.116",
|
||||
"rtt": 4.687
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "108.170.230.116",
|
||||
"name": "108.170.230.116",
|
||||
"rtt": 4.798
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "108.170.230.116",
|
||||
"name": "108.170.230.116",
|
||||
"rtt": 4.688
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 7,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "108.170.252.130",
|
||||
"name": "108.170.252.130",
|
||||
"rtt": 4.825
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "108.170.252.130",
|
||||
"name": "108.170.252.130",
|
||||
"rtt": 4.844
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "108.170.252.130",
|
||||
"name": "108.170.252.130",
|
||||
"rtt": 4.797
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 8,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "108.170.233.117",
|
||||
"name": "108.170.233.117",
|
||||
"rtt": 5.386
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "108.170.233.117",
|
||||
"name": "108.170.233.117",
|
||||
"rtt": 5.288
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "108.170.233.117",
|
||||
"name": "108.170.233.117",
|
||||
"rtt": 5.324
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 9,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "216.239.63.250",
|
||||
"name": "216.239.63.250",
|
||||
"rtt": 5.305
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "216.239.63.250",
|
||||
"name": "216.239.63.250",
|
||||
"rtt": 5.369
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "216.239.63.250",
|
||||
"name": "216.239.63.250",
|
||||
"rtt": 5.406
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 10,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "108.170.240.129",
|
||||
"name": "108.170.240.129",
|
||||
"rtt": 6.005
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "108.170.240.129",
|
||||
"name": "108.170.240.129",
|
||||
"rtt": 5.93
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "108.170.240.129",
|
||||
"name": "108.170.240.129",
|
||||
"rtt": 5.983
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 11,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "209.85.242.53",
|
||||
"name": "209.85.242.53",
|
||||
"rtt": 4.973
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "209.85.242.53",
|
||||
"name": "209.85.242.53",
|
||||
"rtt": 4.973
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "209.85.242.53",
|
||||
"name": "209.85.242.53",
|
||||
"rtt": 4.979
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "hop",
|
||||
"hop": 12,
|
||||
"probes": [
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "216.58.194.46",
|
||||
"name": "dfw25s12-in-f46.1e100.net",
|
||||
"rtt": 4.871
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "216.58.194.46",
|
||||
"name": "dfw25s12-in-f46.1e100.net",
|
||||
"rtt": 4.884
|
||||
},
|
||||
{
|
||||
"annotation": null,
|
||||
"asn": null,
|
||||
"ip": "216.58.194.46",
|
||||
"name": "dfw25s12-in-f46.1e100.net",
|
||||
"rtt": 4.863
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
2
tests/fixtures/generic/traceroute2.json
vendored
2
tests/fixtures/generic/traceroute2.json
vendored
@@ -1 +1 @@
|
||||
{"destination_ip": "216.58.194.46", "destination_name": "google.com", "hops": [{"hop": 1, "probes": [{"annotation": null, "asn": null, "ip": "216.230.231.141", "name": "216-230-231-141.static.houston.tx.oplink.net", "rtt": 198.574}, {"annotation": null, "asn": null, "ip": "216.230.231.141", "name": "216-230-231-141.static.houston.tx.oplink.net", "rtt": 198.65}]}, {"hop": 2, "probes": []}, {"hop": 3, "probes": []}, {"hop": 4, "probes": [{"annotation": null, "asn": null, "ip": "72.14.242.34", "name": "72.14.242.34", "rtt": 4.932}, {"annotation": null, "asn": null, "ip": "72.14.242.34", "name": "72.14.242.34", "rtt": 4.945}, {"annotation": null, "asn": null, "ip": "72.14.242.34", "name": "72.14.242.34", "rtt": 4.951}]}, {"hop": 5, "probes": []}, {"hop": 6, "probes": [{"annotation": null, "asn": null, "ip": "108.170.230.116", "name": "108.170.230.116", "rtt": 4.687}, {"annotation": null, "asn": null, "ip": "108.170.230.116", "name": "108.170.230.116", "rtt": 4.798}, {"annotation": null, "asn": null, "ip": "108.170.230.116", "name": "108.170.230.116", "rtt": 4.688}]}, {"hop": 7, "probes": [{"annotation": null, "asn": null, "ip": "108.170.252.130", "name": "108.170.252.130", "rtt": 4.825}, {"annotation": null, "asn": null, "ip": "108.170.252.130", "name": "108.170.252.130", "rtt": 4.844}, {"annotation": null, "asn": null, "ip": "108.170.252.130", "name": "108.170.252.130", "rtt": 4.797}]}, {"hop": 8, "probes": [{"annotation": null, "asn": null, "ip": "108.170.233.117", "name": "108.170.233.117", "rtt": 5.386}, {"annotation": null, "asn": null, "ip": "108.170.233.117", "name": "108.170.233.117", "rtt": 5.288}, {"annotation": null, "asn": null, "ip": "108.170.233.117", "name": "108.170.233.117", "rtt": 5.324}]}, {"hop": 9, "probes": [{"annotation": null, "asn": null, "ip": "216.239.63.250", "name": "216.239.63.250", "rtt": 5.305}, {"annotation": null, "asn": null, "ip": "216.239.63.250", "name": "216.239.63.250", "rtt": 5.369}, {"annotation": null, "asn": null, "ip": "216.239.63.250", "name": "216.239.63.250", "rtt": 5.406}]}, {"hop": 10, "probes": [{"annotation": null, "asn": null, "ip": "108.170.240.129", "name": "108.170.240.129", "rtt": 6.005}, {"annotation": null, "asn": null, "ip": "108.170.240.129", "name": "108.170.240.129", "rtt": 5.93}, {"annotation": null, "asn": null, "ip": "108.170.240.129", "name": "108.170.240.129", "rtt": 5.983}]}, {"hop": 11, "probes": [{"annotation": null, "asn": null, "ip": "209.85.242.53", "name": "209.85.242.53", "rtt": 4.973}, {"annotation": null, "asn": null, "ip": "209.85.242.53", "name": "209.85.242.53", "rtt": 4.973}, {"annotation": null, "asn": null, "ip": "209.85.242.53", "name": "209.85.242.53", "rtt": 4.979}]}, {"hop": 12, "probes": [{"annotation": null, "asn": null, "ip": "216.58.194.46", "name": "dfw25s12-in-f46.1e100.net", "rtt": 4.871}, {"annotation": null, "asn": null, "ip": "216.58.194.46", "name": "dfw25s12-in-f46.1e100.net", "rtt": 4.884}, {"annotation": null, "asn": null, "ip": "216.58.194.46", "name": "dfw25s12-in-f46.1e100.net", "rtt": 4.863}]}]}
|
||||
{"destination_ip":"216.58.194.46","destination_name":"google.com","max_hops":30,"data_bytes":40,"hops":[{"hop":1,"probes":[{"annotation":null,"asn":null,"ip":"216.230.231.141","name":"216-230-231-141.static.houston.tx.oplink.net","rtt":198.574},{"annotation":null,"asn":null,"ip":"216.230.231.141","name":"216-230-231-141.static.houston.tx.oplink.net","rtt":198.65}]},{"hop":2,"probes":[]},{"hop":3,"probes":[]},{"hop":4,"probes":[{"annotation":null,"asn":null,"ip":"72.14.242.34","name":"72.14.242.34","rtt":4.932},{"annotation":null,"asn":null,"ip":"72.14.242.34","name":"72.14.242.34","rtt":4.945},{"annotation":null,"asn":null,"ip":"72.14.242.34","name":"72.14.242.34","rtt":4.951}]},{"hop":5,"probes":[]},{"hop":6,"probes":[{"annotation":null,"asn":null,"ip":"108.170.230.116","name":"108.170.230.116","rtt":4.687},{"annotation":null,"asn":null,"ip":"108.170.230.116","name":"108.170.230.116","rtt":4.798},{"annotation":null,"asn":null,"ip":"108.170.230.116","name":"108.170.230.116","rtt":4.688}]},{"hop":7,"probes":[{"annotation":null,"asn":null,"ip":"108.170.252.130","name":"108.170.252.130","rtt":4.825},{"annotation":null,"asn":null,"ip":"108.170.252.130","name":"108.170.252.130","rtt":4.844},{"annotation":null,"asn":null,"ip":"108.170.252.130","name":"108.170.252.130","rtt":4.797}]},{"hop":8,"probes":[{"annotation":null,"asn":null,"ip":"108.170.233.117","name":"108.170.233.117","rtt":5.386},{"annotation":null,"asn":null,"ip":"108.170.233.117","name":"108.170.233.117","rtt":5.288},{"annotation":null,"asn":null,"ip":"108.170.233.117","name":"108.170.233.117","rtt":5.324}]},{"hop":9,"probes":[{"annotation":null,"asn":null,"ip":"216.239.63.250","name":"216.239.63.250","rtt":5.305},{"annotation":null,"asn":null,"ip":"216.239.63.250","name":"216.239.63.250","rtt":5.369},{"annotation":null,"asn":null,"ip":"216.239.63.250","name":"216.239.63.250","rtt":5.406}]},{"hop":10,"probes":[{"annotation":null,"asn":null,"ip":"108.170.240.129","name":"108.170.240.129","rtt":6.005},{"annotation":null,"asn":null,"ip":"108.170.240.129","name":"108.170.240.129","rtt":5.93},{"annotation":null,"asn":null,"ip":"108.170.240.129","name":"108.170.240.129","rtt":5.983}]},{"hop":11,"probes":[{"annotation":null,"asn":null,"ip":"209.85.242.53","name":"209.85.242.53","rtt":4.973},{"annotation":null,"asn":null,"ip":"209.85.242.53","name":"209.85.242.53","rtt":4.973},{"annotation":null,"asn":null,"ip":"209.85.242.53","name":"209.85.242.53","rtt":4.979}]},{"hop":12,"probes":[{"annotation":null,"asn":null,"ip":"216.58.194.46","name":"dfw25s12-in-f46.1e100.net","rtt":4.871},{"annotation":null,"asn":null,"ip":"216.58.194.46","name":"dfw25s12-in-f46.1e100.net","rtt":4.884},{"annotation":null,"asn":null,"ip":"216.58.194.46","name":"dfw25s12-in-f46.1e100.net","rtt":4.863}]}]}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user