1
0
mirror of https://github.com/kellyjonbrazil/jc.git synced 2025-08-06 22:32:54 +02:00

working tracepath parser

This commit is contained in:
Kelly Brazil
2020-07-27 13:48:46 -07:00
parent 12912521ec
commit 1e5d602cae
2 changed files with 286 additions and 30 deletions

View File

@ -11,11 +11,96 @@ Compatibility:
Examples: Examples:
$ tracepath | jc --tracepath -p $ tracepath6 3ffe:2400:0:109::2 | jc --tracepath -p
[] {
"pmtu": 1480,
"forward_hops": 2,
"return_hops": 2,
"hops": [
{
"ttl": 1,
"guess": true,
"host": "[LOCALHOST]",
"reply_ms": null,
"pmtu": 1500,
"asymmetric_difference": null,
"reached": false
},
{
"ttl": 1,
"guess": false,
"host": "dust.inr.ac.ru",
"reply_ms": 0.411,
"pmtu": null,
"asymmetric_difference": null,
"reached": false
},
{
"ttl": 2,
"guess": false,
"host": "dust.inr.ac.ru",
"reply_ms": 0.39,
"pmtu": 1480,
"asymmetric_difference": 1,
"reached": false
},
{
"ttl": 2,
"guess": false,
"host": "3ffe:2400:0:109::2",
"reply_ms": 463.514,
"pmtu": null,
"asymmetric_difference": null,
"reached": true
}
]
}
$ tracepath6 3ffe:2400:0:109::2 | jc --tracepath -p -r
{
"pmtu": "1480",
"forward_hops": "2",
"return_hops": "2",
"hops": [
{
"ttl": "1",
"guess": true,
"host": "[LOCALHOST]",
"reply_ms": null,
"pmtu": "1500",
"asymmetric_difference": null,
"reached": false
},
{
"ttl": "1",
"guess": false,
"host": "dust.inr.ac.ru",
"reply_ms": "0.411",
"pmtu": null,
"asymmetric_difference": null,
"reached": false
},
{
"ttl": "2",
"guess": false,
"host": "dust.inr.ac.ru",
"reply_ms": "0.390",
"pmtu": "1480",
"asymmetric_difference": "1",
"reached": false
},
{
"ttl": "2",
"guess": false,
"host": "3ffe:2400:0:109::2",
"reply_ms": "463.514",
"pmtu": null,
"asymmetric_difference": null,
"reached": true
}
]
}
$ tracepath | jc --tracepath -p -r
[]
## info ## info
```python ```python
@ -35,15 +120,24 @@ Parameters:
Returns: Returns:
List of dictionaries. Structured data with the following schema: Dictionary. Structured data with the following schema:
[ {
{ "pmtu": integer,
"tracepath": string, "forward_hops": integer,
"bar": boolean, "return_hops": integer,
"baz": integer "hops": [
} {
] "ttl": integer,
"guess": boolean,
"host": string,
"reply_ms": float,
"pmtu": integer,
"asymmetric_difference": integer,
"reached": boolean
}
]
}
## parse ## parse
```python ```python
@ -60,5 +154,5 @@ Parameters:
Returns: Returns:
List of dictionaries. Raw or processed structured data. Dictionary. Raw or processed structured data.

View File

@ -10,12 +10,98 @@ Compatibility:
Examples: Examples:
$ tracepath | jc --tracepath -p $ tracepath6 3ffe:2400:0:109::2 | jc --tracepath -p
[] {
"pmtu": 1480,
"forward_hops": 2,
"return_hops": 2,
"hops": [
{
"ttl": 1,
"guess": true,
"host": "[LOCALHOST]",
"reply_ms": null,
"pmtu": 1500,
"asymmetric_difference": null,
"reached": false
},
{
"ttl": 1,
"guess": false,
"host": "dust.inr.ac.ru",
"reply_ms": 0.411,
"pmtu": null,
"asymmetric_difference": null,
"reached": false
},
{
"ttl": 2,
"guess": false,
"host": "dust.inr.ac.ru",
"reply_ms": 0.39,
"pmtu": 1480,
"asymmetric_difference": 1,
"reached": false
},
{
"ttl": 2,
"guess": false,
"host": "3ffe:2400:0:109::2",
"reply_ms": 463.514,
"pmtu": null,
"asymmetric_difference": null,
"reached": true
}
]
}
$ tracepath6 3ffe:2400:0:109::2 | jc --tracepath -p -r
{
"pmtu": "1480",
"forward_hops": "2",
"return_hops": "2",
"hops": [
{
"ttl": "1",
"guess": true,
"host": "[LOCALHOST]",
"reply_ms": null,
"pmtu": "1500",
"asymmetric_difference": null,
"reached": false
},
{
"ttl": "1",
"guess": false,
"host": "dust.inr.ac.ru",
"reply_ms": "0.411",
"pmtu": null,
"asymmetric_difference": null,
"reached": false
},
{
"ttl": "2",
"guess": false,
"host": "dust.inr.ac.ru",
"reply_ms": "0.390",
"pmtu": "1480",
"asymmetric_difference": "1",
"reached": false
},
{
"ttl": "2",
"guess": false,
"host": "3ffe:2400:0:109::2",
"reply_ms": "463.514",
"pmtu": null,
"asymmetric_difference": null,
"reached": true
}
]
}
$ tracepath | jc --tracepath -p -r
[]
""" """
import re
import jc.utils import jc.utils
@ -43,18 +129,59 @@ def process(proc_data):
Returns: Returns:
List of dictionaries. Structured data with the following schema: Dictionary. Structured data with the following schema:
[ {
{ "pmtu": integer,
"tracepath": string, "forward_hops": integer,
"bar": boolean, "return_hops": integer,
"baz": integer "hops": [
} {
] "ttl": integer,
"guess": boolean,
"host": string,
"reply_ms": float,
"pmtu": integer,
"asymmetric_difference": integer,
"reached": boolean
}
]
}
""" """
int_list = ['pmtu', 'forward_hops', 'return_hops', 'ttl', 'asymmetric_difference']
float_list = ['reply_ms']
for key, value in proc_data.items():
for item in int_list:
if key in int_list:
try:
proc_data[key] = int(proc_data[key])
except (ValueError, TypeError):
proc_data[key] = None
for item in int_list:
if key in float_list:
try:
proc_data[key] = float(proc_data[key])
except (ValueError, TypeError):
proc_data[key] = None
if 'hops' in proc_data:
for entry in proc_data['hops']:
for key in int_list:
if key in entry:
try:
entry[key] = int(entry[key])
except (ValueError, TypeError):
entry[key] = None
for key in float_list:
if key in entry:
try:
entry[key] = float(entry[key])
except (ValueError, TypeError):
entry[key] = None
# rebuild output for added semantic information
return proc_data return proc_data
@ -70,18 +197,53 @@ def parse(data, raw=False, quiet=False):
Returns: Returns:
List of dictionaries. Raw or processed structured data. Dictionary. Raw or processed structured data.
""" """
if not quiet: if not quiet:
jc.utils.compatibility(__name__, info.compatible) jc.utils.compatibility(__name__, info.compatible)
raw_output = [] RE_TTL_HOST = re.compile(r'^\s?(?P<ttl>\d+)(?P<ttl_guess>\??):\s+(?P<host>(?:no reply|\S+))') # groups: ttl, ttl_guess, host
RE_PMTU = re.compile(r'\spmtu\s(?P<pmtu>[\d]+)') # group: pmtu
RE_REPLY_MS = re.compile(r'\s(?P<reply_ms>\d*\.\d*)ms') # group: reply_ms
RE_ASYMM = re.compile(r'\sasymm\s+(?P<asymm>[\d]+)') # group: asymm
RE_REACHED = re.compile(r'\sreached')
RE_SUMMARY = re.compile(r'\s+Resume:\s+pmtu\s+(?P<pmtu>\d+)(?:\s+hops\s+(?P<hops>\d+))?(?:\s+back\s+(?P<back>\d+))?') # groups: pmtu, hops, back
raw_output = {}
if jc.utils.has_data(data): if jc.utils.has_data(data):
hops = []
for line in filter(None, data.splitlines()): for line in filter(None, data.splitlines()):
# parse the content # grab hop information
pass ttl_host = re.search(RE_TTL_HOST, line)
pmtu = re.search(RE_PMTU, line)
reply_ms = re.search(RE_REPLY_MS, line)
asymm = re.search(RE_ASYMM, line)
reached = re.search(RE_REACHED, line)
summary = re.search(RE_SUMMARY, line)
if ttl_host:
hop = {
'ttl': ttl_host.group('ttl'),
'guess': bool(ttl_host.group('ttl_guess')),
'host': ttl_host.group('host') if ttl_host.group('host') != 'no reply' else None,
'reply_ms': reply_ms.group('reply_ms') if reply_ms else None,
'pmtu': pmtu.group('pmtu') if pmtu else None,
'asymmetric_difference': asymm.group('asymm') if asymm else None,
'reached': bool(reached)
}
hops.append(hop)
continue
elif summary:
raw_output = {
'pmtu': summary.group('pmtu') if summary.group('pmtu') else None,
'forward_hops': summary.group('hops') if summary.group('hops') else None,
'return_hops': summary.group('back') if summary.group('back') else None,
'hops': hops
}
if raw: if raw:
return raw_output return raw_output