1
0
mirror of https://github.com/kellyjonbrazil/jc.git synced 2025-06-19 00:17:51 +02:00

Merge pull request #123 from kellyjonbrazil/dev

Dev v1.15.2
This commit is contained in:
Kelly Brazil
2021-04-18 17:28:27 -07:00
committed by GitHub
162 changed files with 2915 additions and 1490 deletions

View File

@ -1,5 +1,14 @@
jc changelog
20210418 v1.15.2
- Add systeminfo parser tested on Windows
- Update dig parser to fix an issue with IPv6 addresses in the server field
- Update dig parser to fix an issue when axfr entries contain a semicolon
- Update dig parser to add support for Additional Section and Opt Pseudosection
- Update dig parser to add query_size field
- Use dig parser as the main example in readme, documentation, and man page
- Standardize int, float, and boolean conversion rules with functions in jc.utils
20210413 v1.15.1
- New feature to show parser documentation interactively with -h --parser_name
for example: $ jc -h --arp

View File

@ -548,7 +548,7 @@ dig cnn.com www.cnn.com @205.251.194.64 | jc --dig -p # or: jc -p dig
```json
[
{
"id": 52172,
"id": 10267,
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
@ -560,6 +560,13 @@ dig cnn.com www.cnn.com @205.251.194.64 | jc --dig -p # or: jc -p dig
"answer_num": 4,
"authority_num": 0,
"additional_num": 1,
"opt_pseudosection": {
"edns": {
"version": 0,
"flags": [],
"udp": 4096
}
},
"question": {
"name": "cnn.com.",
"class": "IN",
@ -570,40 +577,40 @@ dig cnn.com www.cnn.com @205.251.194.64 | jc --dig -p # or: jc -p dig
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": 27,
"ttl": 17,
"data": "151.101.65.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": 27,
"ttl": 17,
"data": "151.101.129.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": 27,
"ttl": 17,
"data": "151.101.1.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": 27,
"ttl": 17,
"data": "151.101.193.67"
}
],
"query_time": 38,
"server": "2600",
"when": "Tue Mar 30 20:07:59 PDT 2021",
"query_time": 51,
"server": "2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)",
"when": "Fri Apr 16 16:24:32 PDT 2021",
"rcvd": 100,
"when_epoch": 1617160079,
"when_epoch": 1618615472,
"when_epoch_utc": null
},
{
"id": 36292,
"id": 56207,
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
@ -615,6 +622,13 @@ dig cnn.com www.cnn.com @205.251.194.64 | jc --dig -p # or: jc -p dig
"answer_num": 1,
"authority_num": 4,
"additional_num": 1,
"opt_pseudosection": {
"edns": {
"version": 0,
"flags": [],
"udp": 4096
}
},
"question": {
"name": "www.cnn.com.",
"class": "IN",
@ -659,11 +673,11 @@ dig cnn.com www.cnn.com @205.251.194.64 | jc --dig -p # or: jc -p dig
"data": "ns-576.awsdns-08.net."
}
],
"query_time": 27,
"query_time": 22,
"server": "205.251.194.64#53(205.251.194.64)",
"when": "Tue Mar 30 20:07:59 PDT 2021",
"when": "Fri Apr 16 16:24:32 PDT 2021",
"rcvd": 212,
"when_epoch": 1617160079,
"when_epoch": 1618615472,
"when_epoch_utc": null
}
]
@ -674,7 +688,7 @@ dig -x 1.1.1.1 | jc --dig -p # or: jc -p dig -x 1.1.1.1
```json
[
{
"id": 22191,
"id": 20785,
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
@ -686,6 +700,13 @@ dig -x 1.1.1.1 | jc --dig -p # or: jc -p dig -x 1.1.1.1
"answer_num": 1,
"authority_num": 0,
"additional_num": 1,
"opt_pseudosection": {
"edns": {
"version": 0,
"flags": [],
"udp": 4096
}
},
"question": {
"name": "1.1.1.1.in-addr.arpa.",
"class": "IN",
@ -700,11 +721,11 @@ dig -x 1.1.1.1 | jc --dig -p # or: jc -p dig -x 1.1.1.1
"data": "one.one.one.one."
}
],
"query_time": 44,
"server": "2600",
"when": "Tue Mar 30 20:10:34 PDT 2021",
"query_time": 40,
"server": "2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)",
"when": "Sat Apr 17 14:50:50 PDT 2021",
"rcvd": 78,
"when_epoch": 1617160234,
"when_epoch": 1618696250,
"when_epoch_utc": null
}
]
@ -2869,6 +2890,72 @@ systemctl list-unit-files | jc --systemctl-luf -p # or: jc -p systemct
}
]
```
### systeminfo
```bash
systeminfo | jc --systeminfo -p # or: jc -p systeminfo
```
```json
{
"host_name": "TESTLAPTOP",
"os_name": "Microsoft Windows 10 Enterprise",
"os_version": "10.0.17134 N/A Build 17134",
"os_manufacturer": "Microsoft Corporation",
"os_configuration": "Member Workstation",
"os_build_type": "Multiprocessor Free",
"registered_owner": "Test, Inc.",
"registered_organization": "Test, Inc.",
"product_id": "11111-11111-11111-AA111",
"original_install_date": "3/26/2019, 3:51:30 PM",
"system_boot_time": "3/30/2021, 6:13:59 AM",
"system_manufacturer": "Dell Inc.",
"system_model": "Precision 5530",
"system_type": "x64-based PC",
"processors": [
"Intel64 Family 6 Model 158 Stepping 10 GenuineIntel ~2592 Mhz"
],
"bios_version": "Dell Inc. 1.16.2, 4/21/2020",
"windows_directory": "C:\\WINDOWS",
"system_directory": "C:\\WINDOWS\\system32",
"boot_device": "\\Device\\HarddiskVolume2",
"system_locale": "en-us;English (United States)",
"input_locale": "en-us;English (United States)",
"time_zone": "(UTC+00:00) UTC",
"total_physical_memory_mb": 32503,
"available_physical_memory_mb": 19743,
"virtual_memory_max_size_mb": 37367,
"virtual_memory_available_mb": 22266,
"virtual_memory_in_use_mb": 15101,
"page_file_locations": "C:\\pagefile.sys",
"domain": "test.com",
"logon_server": "\\\\TESTDC01",
"hotfixs": [
"KB2693643",
"KB4601054"
],
"network_cards": [
{
"name": "Intel(R) Wireless-AC 9260 160MHz",
"connection_name": "Wi-Fi",
"status": null,
"dhcp_enabled": true,
"dhcp_server": "192.168.2.1",
"ip_addresses": [
"192.168.2.219"
]
}
],
"hyperv_requirements": {
"vm_monitor_mode_extensions": true,
"virtualization_enabled_in_firmware": true,
"second_level_address_translation": false,
"data_execution_prevention_available": true
},
"original_install_date_epoch": 1553640690,
"original_install_date_epoch_utc": 1553615490,
"system_boot_time_epoch": 1617110039,
"system_boot_time_epoch_utc": 1617084839
}
```
### /usr/bin/time
```bash
/usr/bin/time --verbose -o timefile.out sleep 2.5; cat timefile.out | jc --time -p

127
README.md
View File

@ -9,62 +9,56 @@
JSON CLI output utility
`jc` JSONifies the output of many CLI tools and file-types for easier parsing in scripts. See the [**Parsers**](#parsers) section for supported commands and file-types.
This allows further command-line processing of output with tools like `jq` by piping commands:
```bash
ls -l /usr/bin | jc --ls | jq '.[] | select(.size > 50000000)'
dig example.com | jc --dig
```
```json
{
"filename": "docker",
"flags": "-rwxr-xr-x",
"links": 1,
"owner": "root",
"group": "root",
"size": 68677120,
"date": "Aug 14 19:41"
}
[{"id":38052,"opcode":"QUERY","status":"NOERROR","flags":["qr","rd","ra"],"query_num":1,"answer_num":1,
"authority_num":0,"additional_num":1,"opt_pseudosection":{"edns":{"version":0,"flags":[],"udp":4096}},"question":
{"name":"example.com.","class":"IN","type":"A"},"answer":[{"name":"example.com.","class":"IN","type":"A","ttl":
39049,"data":"93.184.216.34"}],"query_time":49,"server":"2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)","when":
"Fri Apr 16 16:09:00 PDT 2021","rcvd":56,"when_epoch":1618614540,"when_epoch_utc":null}]
```
This allows further command-line processing of output with tools like `jq` by piping commands:
```bash
$ dig example.com | jc --dig | jq -r '.[].answer[].data'
93.184.216.34
```
or using the alternative "magic" syntax:
```bash
jc ls -l /usr/bin | jq '.[] | select(.size > 50000000)'
```
```json
{
"filename": "docker",
"flags": "-rwxr-xr-x",
"links": 1,
"owner": "root",
"group": "root",
"size": 68677120,
"date": "Aug 14 19:41"
}
$ jc dig example.com | jq -r '.[].answer[].data'
93.184.216.34
```
The `jc` parsers can also be used as python modules. In this case the output will be a python dictionary, or list of dictionaries, instead of JSON:
```python
>>> import jc.parsers.ls
>>> import jc.parsers.dig
>>>
>>> data='''-rwxr-xr-x 1 root wheel 23648 May 3 22:26 cat
... -rwxr-xr-x 1 root wheel 30016 May 3 22:26 chmod
... -rwxr-xr-x 1 root wheel 29024 May 3 22:26 cp
... -rwxr-xr-x 1 root wheel 375824 May 3 22:26 csh
... -rwxr-xr-x 1 root wheel 28608 May 3 22:26 date
... -rwxr-xr-x 1 root wheel 32000 May 3 22:26 dd
... -rwxr-xr-x 1 root wheel 23392 May 3 22:26 df
... -rwxr-xr-x 1 root wheel 18128 May 3 22:26 echo'''
>>> data = '''; <<>> DiG 9.10.6 <<>> example.com
... ;; global options: +cmd
... ;; Got answer:
... ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 64612
... ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
...
... ;; OPT PSEUDOSECTION:
... ; EDNS: version: 0, flags:; udp: 4096
... ;; QUESTION SECTION:
... ;example.com. IN A
...
... ;; ANSWER SECTION:
... example.com. 29658 IN A 93.184.216.34
...
... ;; Query time: 52 msec
... ;; SERVER: 2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)
... ;; WHEN: Fri Apr 16 16:13:00 PDT 2021
... ;; MSG SIZE rcvd: 56'''
>>>
>>> jc.parsers.ls.parse(data)
[{'filename': 'cat', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 23648,
'date': 'May 3 22:26'}, {'filename': 'chmod', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root',
'group': 'wheel', 'size': 30016, 'date': 'May 3 22:26'}, {'filename': 'cp', 'flags': '-rwxr-xr-x',
'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 29024, 'date': 'May 3 22:26'}, {'filename': 'csh',
'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 375824, 'date': 'May 3
22:26'}, {'filename': 'date', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel',
'size': 28608, 'date': 'May 3 22:26'}, {'filename': 'dd', 'flags': '-rwxr-xr-x', 'links': 1, 'owner':
'root', 'group': 'wheel', 'size': 32000, 'date': 'May 3 22:26'}, {'filename': 'df', 'flags':
'-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 23392, 'date': 'May 3 22:26'},
{'filename': 'echo', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 18128,
'date': 'May 3 22:26'}]
>>> jc.parsers.dig.parse(data)
[{'id': 64612, 'opcode': 'QUERY', 'status': 'NOERROR', 'flags': ['qr', 'rd', 'ra'], 'query_num': 1, 'answer_num':
1, 'authority_num': 0, 'additional_num': 1, 'opt_pseudosection': {'edns': {'version': 0, 'flags': [], 'udp':
4096}}, 'question': {'name': 'example.com.', 'class': 'IN', 'type': 'A'}, 'answer': [{'name': 'example.com.',
'class': 'IN', 'type': 'A', 'ttl': 29658, 'data': '93.184.216.34'}], 'query_time': 52, 'server':
'2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)', 'when': 'Fri Apr 16 16:13:00 PDT 2021', 'rcvd': 56,
'when_epoch': 1618614780, 'when_epoch_utc': None}]
```
Two representations of the data are possible. The default representation uses a strict schema per parser and converts known numbers to int/float JSON values. Certain known values of `None` are converted to JSON `null`, known boolean values are converted, and, in some cases, additional semantic context fields are added.
@ -183,6 +177,7 @@ The JSON output can be compact (default) or pretty formatted with the `-p` optio
- `--systemctl-lj` enables the `systemctl list-jobs` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/systemctl_lj))
- `--systemctl-ls` enables the `systemctl list-sockets` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/systemctl_ls))
- `--systemctl-luf` enables the `systemctl list-unit-files` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/systemctl_luf))
- `--systeminfo` enables the `systeminfo` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/systeminfo))
- `--time` enables the `/usr/bin/time` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/time))
- `--timedatectl` enables the `timedatectl status` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/timedatectl))
- `--tracepath` enables the `tracepath` and `tracepath6` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/tracepath))
@ -352,48 +347,6 @@ cat homes.csv | jc --csv -p
}
]
```
### dig
```bash
dig cnn.com @205.251.194.64 | jc --dig -p # or: jc -p dig cnn.com @205.251.194.64
```
```json
[
{
"id": 52172,
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
"qr",
"rd",
"ra"
],
"query_num": 1,
"answer_num": 1,
"authority_num": 0,
"additional_num": 1,
"question": {
"name": "cnn.com.",
"class": "IN",
"type": "A"
},
"answer": [
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": 27,
"data": "151.101.65.67"
}
],
"query_time": 38,
"server": "2600",
"when": "Tue Mar 30 20:07:59 PDT 2021",
"rcvd": 100,
"when_epoch": 1617160079,
"when_epoch_utc": null
}
]
```
### /etc/hosts file
```bash
cat /etc/hosts | jc --hosts -p

View File

@ -252,4 +252,4 @@ Returns:
## Parser Information
Compatibility: linux
Version 1.1 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -105,4 +105,4 @@ Returns:
## Parser Information
Compatibility: darwin
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -133,4 +133,4 @@ Returns:
## Parser Information
Compatibility: darwin
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -145,4 +145,4 @@ Returns:
## Parser Information
Compatibility: linux
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -79,4 +79,4 @@ Returns:
## Parser Information
Compatibility: linux, darwin, cygwin, aix, freebsd
Version 1.1 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -122,4 +122,4 @@ Returns:
## Parser Information
Compatibility: linux, darwin, freebsd
Version 1.6 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.7 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -43,6 +43,16 @@ Schema:
"data": string
}
],
"opt_pseudosection": {
"edns": {
"version": integer,
"flags": [
string
],
"udp": integer
},
"cookie": string
},
"question": {
"name": string,
"class": string,
@ -57,6 +67,15 @@ Schema:
"data": string
}
],
"additional": [
{
"name": string,
"class": string,
"type": string,
"ttl": integer,
"data": string
}
],
"authority": [
{
"name": string,
@ -66,6 +85,7 @@ Schema:
"data": string
}
],
"query_size": integer,
"query_time": integer, # in msec
"server": string,
"when": string,
@ -78,10 +98,10 @@ Schema:
Examples:
$ dig cnn.com www.cnn.com @205.251.194.64 | jc --dig -p
$ dig example.com | jc --dig -p
[
{
"id": 52172,
"id": 2951,
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
@ -90,113 +110,35 @@ Examples:
"ra"
],
"query_num": 1,
"answer_num": 4,
"answer_num": 1,
"authority_num": 0,
"additional_num": 1,
"opt_pseudosection": {
"edns": {
"version": 0,
"flags": [],
"udp": 4096
}
},
"question": {
"name": "cnn.com.",
"name": "example.com.",
"class": "IN",
"type": "A"
},
"answer": [
{
"name": "cnn.com.",
"name": "example.com.",
"class": "IN",
"type": "A",
"ttl": 27,
"data": "151.101.65.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": 27,
"data": "151.101.129.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": 27,
"data": "151.101.1.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": 27,
"data": "151.101.193.67"
"ttl": 39302,
"data": "93.184.216.34"
}
],
"query_time": 38,
"server": "2600",
"when": "Tue Mar 30 20:07:59 PDT 2021",
"rcvd": 100,
"when_epoch": 1617160079,
"when_epoch_utc": null
},
{
"id": 36292,
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
"qr",
"aa",
"rd"
],
"query_num": 1,
"answer_num": 1,
"authority_num": 4,
"additional_num": 1,
"question": {
"name": "www.cnn.com.",
"class": "IN",
"type": "A"
},
"answer": [
{
"name": "www.cnn.com.",
"class": "IN",
"type": "CNAME",
"ttl": 300,
"data": "turner-tls.map.fastly.net."
}
],
"authority": [
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": 3600,
"data": "ns-1086.awsdns-07.org."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": 3600,
"data": "ns-1630.awsdns-11.co.uk."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": 3600,
"data": "ns-47.awsdns-05.com."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": 3600,
"data": "ns-576.awsdns-08.net."
}
],
"query_time": 27,
"server": "205.251.194.64#53(205.251.194.64)",
"when": "Tue Mar 30 20:07:59 PDT 2021",
"rcvd": 212,
"when_epoch": 1617160079,
"query_time": 49,
"server": "2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)",
"when": "Fri Apr 16 16:05:10 PDT 2021",
"rcvd": 56,
"when_epoch": 1618614310,
"when_epoch_utc": null
}
]
@ -204,7 +146,7 @@ Examples:
$ dig cnn.com www.cnn.com @205.251.194.64 | jc --dig -p -r
[
{
"id": "23843",
"id": "46052",
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
@ -213,117 +155,41 @@ Examples:
"ra"
],
"query_num": "1",
"answer_num": "4",
"answer_num": "1",
"authority_num": "0",
"additional_num": "1",
"opt_pseudosection": {
"edns": {
"version": "0",
"flags": [],
"udp": "4096"
}
},
"question": {
"name": "cnn.com.",
"name": "example.com.",
"class": "IN",
"type": "A"
},
"answer": [
{
"name": "cnn.com.",
"name": "example.com.",
"class": "IN",
"type": "A",
"ttl": "30",
"data": "151.101.193.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": "30",
"data": "151.101.1.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": "30",
"data": "151.101.65.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": "30",
"data": "151.101.129.67"
"ttl": "40426",
"data": "93.184.216.34"
}
],
"query_time": "24 msec",
"server": "192.168.1.254#53(192.168.1.254)",
"when": "Tue Nov 12 07:16:19 PST 2019",
"rcvd": "100"
},
{
"id": "8266",
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
"qr",
"aa",
"rd"
],
"query_num": "1",
"answer_num": "1",
"authority_num": "4",
"additional_num": "1",
"question": {
"name": "www.cnn.com.",
"class": "IN",
"type": "A"
},
"answer": [
{
"name": "www.cnn.com.",
"class": "IN",
"type": "CNAME",
"ttl": "300",
"data": "turner-tls.map.fastly.net."
}
],
"authority": [
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": "3600",
"data": "ns-1086.awsdns-07.org."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": "3600",
"data": "ns-1630.awsdns-11.co.uk."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": "3600",
"data": "ns-47.awsdns-05.com."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": "3600",
"data": "ns-576.awsdns-08.net."
}
],
"query_time": "26 msec",
"server": "205.251.194.64#53(205.251.194.64)",
"when": "Tue Nov 12 07:16:19 PST 2019",
"rcvd": "212"
"query_time": "48 msec",
"server": "2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)",
"when": "Fri Apr 16 16:06:12 PDT 2021",
"rcvd": "56"
}
]
$ dig -x 1.1.1.1 | jc --dig -p
[
{
"id": 22191,
"id": 20785,
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
@ -335,6 +201,13 @@ Examples:
"answer_num": 1,
"authority_num": 0,
"additional_num": 1,
"opt_pseudosection": {
"edns": {
"version": 0,
"flags": [],
"udp": 4096
}
},
"question": {
"name": "1.1.1.1.in-addr.arpa.",
"class": "IN",
@ -349,11 +222,11 @@ Examples:
"data": "one.one.one.one."
}
],
"query_time": 44,
"server": "2600",
"when": "Tue Mar 30 20:10:34 PDT 2021",
"query_time": 40,
"server": "2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)",
"when": "Sat Apr 17 14:50:50 PDT 2021",
"rcvd": 78,
"when_epoch": 1617160234,
"when_epoch": 1618696250,
"when_epoch_utc": null
}
]
@ -361,7 +234,7 @@ Examples:
$ dig -x 1.1.1.1 | jc --dig -p -r
[
{
"id": "50986",
"id": "32644",
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
@ -373,6 +246,13 @@ Examples:
"answer_num": "1",
"authority_num": "0",
"additional_num": "1",
"opt_pseudosection": {
"edns": {
"version": "0",
"flags": [],
"udp": "4096"
}
},
"question": {
"name": "1.1.1.1.in-addr.arpa.",
"class": "IN",
@ -387,9 +267,9 @@ Examples:
"data": "one.one.one.one."
}
],
"query_time": "38 msec",
"server": "2600",
"when": "Tue Nov 12 07:17:19 PST 2019",
"query_time": "52 msec",
"server": "2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)",
"when": "Sat Apr 17 14:51:46 PDT 2021",
"rcvd": "78"
}
]
@ -421,4 +301,4 @@ Returns:
## Parser Information
Compatibility: linux, aix, freebsd, darwin
Version 1.7 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 2.0 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -145,4 +145,4 @@ Returns:
## Parser Information
Compatibility: win32
Version 1.1 by Rasheed Elsaleh (rasheed@rebelliondefense.com)
Version 1.2 by Rasheed Elsaleh (rasheed@rebelliondefense.com)

View File

@ -150,4 +150,4 @@ Returns:
## Parser Information
Compatibility: linux
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -112,4 +112,4 @@ Returns:
## Parser Information
Compatibility: linux, darwin, aix, freebsd
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -97,4 +97,4 @@ Returns:
## Parser Information
Compatibility: linux
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -110,4 +110,4 @@ Returns:
## Parser Information
Compatibility: linux, freebsd
Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.5 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -134,4 +134,4 @@ Returns:
## Parser Information
Compatibility: linux, darwin, aix, freebsd
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -62,4 +62,4 @@ Returns:
## Parser Information
Compatibility: linux, darwin, cygwin, aix, freebsd
Version 1.1 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -342,4 +342,4 @@ Returns:
## Parser Information
Compatibility: linux
Version 1.1 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -83,4 +83,4 @@ Returns:
## Parser Information
Compatibility: linux, darwin, cygwin, aix, freebsd
Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.5 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -130,4 +130,4 @@ Returns:
## Parser Information
Compatibility: linux, darwin, aix, freebsd
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -211,4 +211,4 @@ Returns:
## Parser Information
Compatibility: linux, aix, freebsd, darwin
Version 1.9 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.10 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -188,4 +188,4 @@ Returns:
## Parser Information
Compatibility: linux
Version 1.5 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.6 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -119,4 +119,4 @@ Returns:
## Parser Information
Compatibility: linux, darwin, cygwin, aix, freebsd
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -128,4 +128,4 @@ Returns:
## Parser Information
Compatibility: linux, darwin, aix, freebsd
Version 1.6 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.7 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -6,7 +6,6 @@ jc - JSON CLI output utility `ls` and `vdir` command output parser
Options supported:
- `lbaR1`
- `--time-style=full-iso`
- `-h`: File sizes will be available in text form with `-r` but larger file sizes with human readable suffixes will be converted to `Null` in the default view since the parser attempts to convert this field to an integer.
Note: The `-1`, `-l`, or `-b` option of `ls` should be used to correctly parse filenames that include newline characters. Since `ls` does not encode newlines in filenames when outputting to a pipe it will cause `jc` to see multiple files instead of a single file if `-1`, `-l`, or `-b` is not used. Alternatively, `vdir` can be used, which is the same as running `ls -lb`.
@ -132,4 +131,4 @@ Returns:
## Parser Information
Compatibility: linux, darwin, cygwin, aix, freebsd
Version 1.8 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.9 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -293,4 +293,4 @@ Returns:
## Parser Information
Compatibility: linux
Version 1.6 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.7 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -150,4 +150,4 @@ Returns:
## Parser Information
Compatibility: linux
Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.5 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -144,4 +144,4 @@ Returns:
## Parser Information
Compatibility: linux
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -379,4 +379,4 @@ Returns:
## Parser Information
Compatibility: linux, darwin, freebsd
Version 1.9 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.10 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -231,4 +231,4 @@ Returns:
## Parser Information
Compatibility: linux, freebsd
Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.5 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -119,4 +119,4 @@ Returns:
## Parser Information
Compatibility: linux, darwin, aix, freebsd
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -170,4 +170,4 @@ Returns:
## Parser Information
Compatibility: linux, darwin, freebsd
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -231,4 +231,4 @@ Returns:
## Parser Information
Compatibility: linux, darwin, cygwin, aix, freebsd
Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.5 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -135,4 +135,4 @@ Returns:
## Parser Information
Compatibility: linux
Version 1.5 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.6 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -181,4 +181,4 @@ Returns:
## Parser Information
Compatibility: linux
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -126,4 +126,4 @@ Returns:
## Parser Information
Compatibility: linux, darwin, aix, freebsd
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -303,4 +303,4 @@ Returns:
## Parser Information
Compatibility: linux
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -193,4 +193,4 @@ Returns:
## Parser Information
Compatibility: linux, darwin, freebsd
Version 1.7 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.8 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -100,4 +100,4 @@ Returns:
## Parser Information
Compatibility: linux
Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.5 by Kelly Brazil (kellyjonbrazil@gmail.com)

232
docs/parsers/systeminfo.md Normal file
View File

@ -0,0 +1,232 @@
[Home](https://kellyjonbrazil.github.io/jc/)
# jc.parsers.systeminfo
jc - JSON CLI output utility `systeminfo` command output parser
Blank or missing elements are set to `null`.
The `original_install_date_epoch` and `system_boot_time_epoch` calculated timestamp fields are naive (i.e. based on the local time of the system the parser is run on)
The `original_install_date_epoch_utc` and `system_boot_time_epoch_utc` calculated timestamp fields are timezone-aware and are only available if the timezone field is UTC.
Usage (cli):
$ systeminfo | jc --systeminfo
Usage (module):
import jc.parsers.systeminfo
result = jc.parsers.systeminfo.parse(systeminfo_command_output)
Schema:
{
"host_name": string,
"os_name": string,
"os_version": string,
"os_manufacturer": string,
"os_configuration": string,
"os_build_type": string,
"registered_owner": string,
"registered_organization": string,
"product_id": string,
"original_install_date": string,
"original_install_date_epoch": integer, # naive timestamp
"original_install_date_epoch_utc": integer, # timezone-aware timestamp
"system_boot_time": string,
"system_boot_time_epoch": integer, # naive timestamp
"system_boot_time_epoch_utc": integer, # timezone-aware timestamp
"system_manufacturer": string,
"system_model": string,
"system_type": string,
"processors": [
string
],
"bios_version": string,
"windows_directory": string,
"system_directory": string,
"boot_device": string,
"system_locale": string,
"input_locale": string,
"time_zone": string,
"total_physical_memory_mb": string,
"available_physical_memory_mb": integer,
"virtual_memory_max_size_mb": integer,
"virtual_memory_available_mb": integer,
"virtual_memory_in_use_mb": integer,
"page_file_locations": string,
"domain": string,
"logon_server": string,
"hotfixs": [
string
],
"network_cards": [
{
"name": string,
"connection_name": string,
"status": string,
"dhcp_enabled": boolean,
"dhcp_server": string,
"ip_addresses": [
string
]
}
],
"hyperv_requirements": {
"vm_monitor_mode_extensions": boolean,
"virtualization_enabled_in_firmware": boolean,
"second_level_address_translation": boolean,
"data_execution_prevention_available": boolean
}
}
Examples:
$ systeminfo | jc --systeminfo -p
{
"host_name": "TESTLAPTOP",
"os_name": "Microsoft Windows 10 Enterprise",
"os_version": "10.0.17134 N/A Build 17134",
"os_manufacturer": "Microsoft Corporation",
"os_configuration": "Member Workstation",
"os_build_type": "Multiprocessor Free",
"registered_owner": "Test, Inc.",
"registered_organization": "Test, Inc.",
"product_id": "11111-11111-11111-AA111",
"original_install_date": "3/26/2019, 3:51:30 PM",
"system_boot_time": "3/30/2021, 6:13:59 AM",
"system_manufacturer": "Dell Inc.",
"system_model": "Precision 5530",
"system_type": "x64-based PC",
"processors": [
"Intel64 Family 6 Model 158 Stepping 10 GenuineIntel ~2592 Mhz"
],
"bios_version": "Dell Inc. 1.16.2, 4/21/2020",
"windows_directory": "C:\WINDOWS",
"system_directory": "C:\WINDOWS\system32",
"boot_device": "\Device\HarddiskVolume2",
"system_locale": "en-us;English (United States)",
"input_locale": "en-us;English (United States)",
"time_zone": "(UTC+00:00) UTC",
"total_physical_memory_mb": 32503,
"available_physical_memory_mb": 19743,
"virtual_memory_max_size_mb": 37367,
"virtual_memory_available_mb": 22266,
"virtual_memory_in_use_mb": 15101,
"page_file_locations": "C:\pagefile.sys",
"domain": "test.com",
"logon_server": "\\TESTDC01",
"hotfixs": [
"KB2693643",
"KB4601054"
],
"network_cards": [
{
"name": "Intel(R) Wireless-AC 9260 160MHz",
"connection_name": "Wi-Fi",
"status": null,
"dhcp_enabled": true,
"dhcp_server": "192.168.2.1",
"ip_addresses": [
"192.168.2.219"
]
}
],
"hyperv_requirements": {
"vm_monitor_mode_extensions": true,
"virtualization_enabled_in_firmware": true,
"second_level_address_translation": false,
"data_execution_prevention_available": true
},
"original_install_date_epoch": 1553640690,
"original_install_date_epoch_utc": 1553615490,
"system_boot_time_epoch": 1617110039,
"system_boot_time_epoch_utc": 1617084839
}
$ systeminfo | jc --systeminfo -p -r
{
"host_name": "TESTLAPTOP",
"os_name": "Microsoft Windows 10 Enterprise",
"os_version": "10.0.17134 N/A Build 17134",
"os_manufacturer": "Microsoft Corporation",
"os_configuration": "Member Workstation",
"os_build_type": "Multiprocessor Free",
"registered_owner": "Test, Inc.",
"registered_organization": "Test, Inc.",
"product_id": "11111-11111-11111-AA111",
"original_install_date": "3/26/2019, 3:51:30 PM",
"system_boot_time": "3/30/2021, 6:13:59 AM",
"system_manufacturer": "Dell Inc.",
"system_model": "Precision 5530",
"system_type": "x64-based PC",
"processors": [
"Intel64 Family 6 Model 158 Stepping 10 GenuineIntel ~2592 Mhz"
],
"bios_version": "Dell Inc. 1.16.2, 4/21/2020",
"windows_directory": "C:\WINDOWS",
"system_directory": "C:\WINDOWS\system32",
"boot_device": "\Device\HarddiskVolume2",
"system_locale": "en-us;English (United States)",
"input_locale": "en-us;English (United States)",
"time_zone": "(UTC+00:00) UTC",
"total_physical_memory_mb": "32,503 MB",
"available_physical_memory_mb": "19,743 MB",
"virtual_memory_max_size_mb": "37,367 MB",
"virtual_memory_available_mb": "22,266 MB",
"virtual_memory_in_use_mb": "15,101 MB",
"page_file_locations": "C:\pagefile.sys",
"domain": "test.com",
"logon_server": "\\TESTDC01",
"hotfixs": [
"KB2693643",
"KB4601054"
],
"network_cards": [
{
"name": "Intel(R) Wireless-AC 9260 160MHz",
"connection_name": "Wi-Fi",
"status": "",
"dhcp_enabled": "Yes",
"dhcp_server": "192.168.2.1",
"ip_addresses": [
"192.168.2.219"
]
}
],
"hyperv_requirements": {
"vm_monitor_mode_extensions": "Yes",
"virtualization_enabled_in_firmware": "Yes",
"second_level_address_translation": "No",
"data_execution_prevention_available": "Yes"
}
}
## info
```python
info()
```
Provides parser metadata (version, author, etc.)
## parse
```python
parse(data, raw=False, quiet=False)
```
Main text parsing function
Parameters:
data: (string) text data to parse
raw: (boolean) output preprocessed JSON if True
quiet: (boolean) suppress warning messages if True
Returns:
List of Dictionaries. Raw or processed structured data.
## Parser Information
Compatibility: win32
Version 1.0 by Jon Smith (jon@rebelliondefense.com)

View File

@ -148,4 +148,4 @@ Returns:
## Parser Information
Compatibility: linux, darwin, cygwin, aix, freebsd
Version 1.1 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -88,4 +88,4 @@ Returns:
## Parser Information
Compatibility: linux
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -156,4 +156,4 @@ Returns:
## Parser Information
Compatibility: linux
Version 1.1 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -142,4 +142,4 @@ Returns:
## Parser Information
Compatibility: linux, darwin, freebsd
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -219,4 +219,4 @@ Returns:
## Parser Information
Compatibility: linux
Version 1.1 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -90,4 +90,4 @@ Returns:
## Parser Information
Compatibility: linux, darwin, cygwin, aix, freebsd
Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.5 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -79,4 +79,4 @@ Returns:
## Parser Information
Compatibility: linux, darwin, cygwin, aix, freebsd
Version 1.1 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -157,4 +157,4 @@ Returns:
## Parser Information
Compatibility: linux, darwin, cygwin, aix, freebsd
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -10,62 +10,79 @@ For documentation on each parser, see the [documentation site](https://kellyjonb
CLI Example:
$ ls -l /usr/bin | jc --ls -p
$ dig example.com | jc --dig -p
[
{
"filename": "apropos",
"link_to": "whatis",
"flags": "lrwxrwxrwx.",
"links": 1,
"owner": "root",
"group": "root",
"size": 6,
"date": "Aug 15 10:53"
"id": 2951,
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
"qr",
"rd",
"ra"
],
"query_num": 1,
"answer_num": 1,
"authority_num": 0,
"additional_num": 1,
"opt_pseudosection": {
"edns": {
"version": 0,
"flags": [],
"udp": 4096
}
},
"question": {
"name": "example.com.",
"class": "IN",
"type": "A"
},
"answer": [
{
"filename": "ar",
"flags": "-rwxr-xr-x.",
"links": 1,
"owner": "root",
"group": "root",
"size": 62744,
"date": "Aug 8 16:14"
},
{
"filename": "arch",
"flags": "-rwxr-xr-x.",
"links": 1,
"owner": "root",
"group": "root",
"size": 33080,
"date": "Aug 19 23:25"
},
...
"name": "example.com.",
"class": "IN",
"type": "A",
"ttl": 39302,
"data": "93.184.216.34"
}
],
"query_time": 49,
"server": "2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)",
"when": "Fri Apr 16 16:05:10 PDT 2021",
"rcvd": 56,
"when_epoch": 1618614310,
"when_epoch_utc": null
}
]
Module Example:
>>> import jc.parsers.ls
>>> import jc.parsers.dig
>>>
>>> data='''-rwxr-xr-x 1 root wheel 23648 May 3 22:26 cat
... -rwxr-xr-x 1 root wheel 30016 May 3 22:26 chmod
... -rwxr-xr-x 1 root wheel 29024 May 3 22:26 cp
... -rwxr-xr-x 1 root wheel 375824 May 3 22:26 csh
... -rwxr-xr-x 1 root wheel 28608 May 3 22:26 date
... -rwxr-xr-x 1 root wheel 32000 May 3 22:26 dd
... -rwxr-xr-x 1 root wheel 23392 May 3 22:26 df
... -rwxr-xr-x 1 root wheel 18128 May 3 22:26 echo'''
>>> data = '''; <<>> DiG 9.10.6 <<>> example.com
... ;; global options: +cmd
... ;; Got answer:
... ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 64612
... ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
...
... ;; OPT PSEUDOSECTION:
... ; EDNS: version: 0, flags:; udp: 4096
... ;; QUESTION SECTION:
... ;example.com. IN A
...
... ;; ANSWER SECTION:
... example.com. 29658 IN A 93.184.216.34
...
... ;; Query time: 52 msec
... ;; SERVER: 2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)
... ;; WHEN: Fri Apr 16 16:13:00 PDT 2021
... ;; MSG SIZE rcvd: 56'''
>>>
>>> jc.parsers.ls.parse(data)
[{'filename': 'cat', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 23648,
'date': 'May 3 22:26'}, {'filename': 'chmod', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root',
'group': 'wheel', 'size': 30016, 'date': 'May 3 22:26'}, {'filename': 'cp', 'flags': '-rwxr-xr-x',
'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 29024, 'date': 'May 3 22:26'}, {'filename': 'csh',
'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 375824, 'date': 'May 3
22:26'}, {'filename': 'date', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel',
'size': 28608, 'date': 'May 3 22:26'}, {'filename': 'dd', 'flags': '-rwxr-xr-x', 'links': 1, 'owner':
'root', 'group': 'wheel', 'size': 32000, 'date': 'May 3 22:26'}, {'filename': 'df', 'flags':
'-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 23392, 'date': 'May 3 22:26'},
{'filename': 'echo', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 18128,
'date': 'May 3 22:26'}]
>>> jc.parsers.dig.parse(data)
[{'id': 64612, 'opcode': 'QUERY', 'status': 'NOERROR', 'flags': ['qr', 'rd', 'ra'], 'query_num': 1, 'answer_num':
1, 'authority_num': 0, 'additional_num': 1, 'opt_pseudosection': {'edns': {'version': 0, 'flags': [], 'udp':
4096}}, 'question': {'name': 'example.com.', 'class': 'IN', 'type': 'A'}, 'answer': [{'name': 'example.com.',
'class': 'IN', 'type': 'A', 'ttl': 29658, 'data': '93.184.216.34'}], 'query_time': 52, 'server':
'2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)', 'when': 'Fri Apr 16 16:13:00 PDT 2021', 'rcvd': 56,
'when_epoch': 1618614780, 'when_epoch_utc': None}]

View File

@ -69,6 +69,54 @@ Returns:
Boolean True if input string (data) contains non-whitespace characters, otherwise False
## convert_to_int
```python
convert_to_int(value)
```
Converts string input to integer by stripping all non-numeric characters
Parameters:
value: (string/integer/float) Input value
Returns:
integer/None Integer if successful conversion, otherwise None
## convert_to_float
```python
convert_to_float(value)
```
Converts string input to float by stripping all non-numeric characters
Parameters:
value: (string) Input value
Returns:
float/None Float if successful conversion, otherwise None
## convert_to_bool
```python
convert_to_bool(value)
```
Converts string, integer, or float input to boolean by checking for 'truthy' values
Parameters:
value: (string/integer/float) Input value
Returns:
True/False False unless a 'truthy' number or string is found ('y', 'yes', 'true', '1', 1, -1, etc.)
## timestamp
```python
timestamp(datetime_string)

View File

@ -8,65 +8,82 @@ For documentation on each parser, see the [documentation site](https://kellyjonb
CLI Example:
$ ls -l /usr/bin | jc --ls -p
$ dig example.com | jc --dig -p
[
{
"filename": "apropos",
"link_to": "whatis",
"flags": "lrwxrwxrwx.",
"links": 1,
"owner": "root",
"group": "root",
"size": 6,
"date": "Aug 15 10:53"
"id": 2951,
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
"qr",
"rd",
"ra"
],
"query_num": 1,
"answer_num": 1,
"authority_num": 0,
"additional_num": 1,
"opt_pseudosection": {
"edns": {
"version": 0,
"flags": [],
"udp": 4096
}
},
"question": {
"name": "example.com.",
"class": "IN",
"type": "A"
},
"answer": [
{
"filename": "ar",
"flags": "-rwxr-xr-x.",
"links": 1,
"owner": "root",
"group": "root",
"size": 62744,
"date": "Aug 8 16:14"
},
{
"filename": "arch",
"flags": "-rwxr-xr-x.",
"links": 1,
"owner": "root",
"group": "root",
"size": 33080,
"date": "Aug 19 23:25"
},
...
"name": "example.com.",
"class": "IN",
"type": "A",
"ttl": 39302,
"data": "93.184.216.34"
}
],
"query_time": 49,
"server": "2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)",
"when": "Fri Apr 16 16:05:10 PDT 2021",
"rcvd": 56,
"when_epoch": 1618614310,
"when_epoch_utc": null
}
]
Module Example:
>>> import jc.parsers.ls
>>> import jc.parsers.dig
>>>
>>> data='''-rwxr-xr-x 1 root wheel 23648 May 3 22:26 cat
... -rwxr-xr-x 1 root wheel 30016 May 3 22:26 chmod
... -rwxr-xr-x 1 root wheel 29024 May 3 22:26 cp
... -rwxr-xr-x 1 root wheel 375824 May 3 22:26 csh
... -rwxr-xr-x 1 root wheel 28608 May 3 22:26 date
... -rwxr-xr-x 1 root wheel 32000 May 3 22:26 dd
... -rwxr-xr-x 1 root wheel 23392 May 3 22:26 df
... -rwxr-xr-x 1 root wheel 18128 May 3 22:26 echo'''
>>> data = '''; <<>> DiG 9.10.6 <<>> example.com
... ;; global options: +cmd
... ;; Got answer:
... ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 64612
... ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
...
... ;; OPT PSEUDOSECTION:
... ; EDNS: version: 0, flags:; udp: 4096
... ;; QUESTION SECTION:
... ;example.com. IN A
...
... ;; ANSWER SECTION:
... example.com. 29658 IN A 93.184.216.34
...
... ;; Query time: 52 msec
... ;; SERVER: 2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)
... ;; WHEN: Fri Apr 16 16:13:00 PDT 2021
... ;; MSG SIZE rcvd: 56'''
>>>
>>> jc.parsers.ls.parse(data)
[{'filename': 'cat', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 23648,
'date': 'May 3 22:26'}, {'filename': 'chmod', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root',
'group': 'wheel', 'size': 30016, 'date': 'May 3 22:26'}, {'filename': 'cp', 'flags': '-rwxr-xr-x',
'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 29024, 'date': 'May 3 22:26'}, {'filename': 'csh',
'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 375824, 'date': 'May 3
22:26'}, {'filename': 'date', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel',
'size': 28608, 'date': 'May 3 22:26'}, {'filename': 'dd', 'flags': '-rwxr-xr-x', 'links': 1, 'owner':
'root', 'group': 'wheel', 'size': 32000, 'date': 'May 3 22:26'}, {'filename': 'df', 'flags':
'-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 23392, 'date': 'May 3 22:26'},
{'filename': 'echo', 'flags': '-rwxr-xr-x', 'links': 1, 'owner': 'root', 'group': 'wheel', 'size': 18128,
'date': 'May 3 22:26'}]
>>> jc.parsers.dig.parse(data)
[{'id': 64612, 'opcode': 'QUERY', 'status': 'NOERROR', 'flags': ['qr', 'rd', 'ra'], 'query_num': 1, 'answer_num':
1, 'authority_num': 0, 'additional_num': 1, 'opt_pseudosection': {'edns': {'version': 0, 'flags': [], 'udp':
4096}}, 'question': {'name': 'example.com.', 'class': 'IN', 'type': 'A'}, 'answer': [{'name': 'example.com.',
'class': 'IN', 'type': 'A', 'ttl': 29658, 'data': '93.184.216.34'}], 'query_time': 52, 'server':
'2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)', 'when': 'Fri Apr 16 16:13:00 PDT 2021', 'rcvd': 56,
'when_epoch': 1618614780, 'when_epoch_utc': None}]
"""
name = 'jc'
__version__ = '1.15.1'
__version__ = '1.15.2'

View File

@ -97,6 +97,7 @@ parsers = [
'systemctl-lj',
'systemctl-ls',
'systemctl-luf',
'systeminfo',
'time',
'timedatectl',
'tracepath',
@ -319,27 +320,27 @@ def helptext():
{parsers_string}
Options:
-a about jc
-d debug - show traceback (-dd for verbose traceback)
-h help (use -h --parser_name for parser documentation)
-d debug (-dd for verbose debug)
-h help (-h --parser_name for parser documentation)
-m monochrome output
-p pretty print output
-q quiet - suppress parser warnings
-r raw JSON output
-v version info
Example:
ls -al | jc --ls -p
Examples:
Standard Syntax:
$ dig www.google.com | jc --dig -p
or using the magic syntax:
Magic Syntax:
$ jc -p dig www.google.com
jc -p ls -al
For parser documentation:
jc -h --ls
Parser Documentation:
$ jc -h --dig
'''
return textwrap.dedent(helptext_string)
def help_doc(options):
"""
Returns the parser documentation if a parser is found in the arguments, otherwise
@ -362,6 +363,7 @@ Version {parser.info.version} by {parser.info.author} ({parser.info.author_email
return helptext()
def versiontext():
"""Return the version text"""
versiontext_string = f'''\

Binary file not shown.

View File

@ -227,7 +227,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.1'
version = '1.2'
description = '`acpi` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -256,38 +256,19 @@ def _process(proc_data):
float_list = ['temperature']
for entry in proc_data:
for key in int_list:
if key in entry:
try:
entry[key] = int(entry[key])
except (ValueError):
entry[key] = None
for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
if key in float_list:
entry[key] = jc.utils.convert_to_float(entry[key])
if 'trip_points' in entry:
for tp in entry['trip_points']:
for key in int_list:
if key in tp:
try:
tp[key] = int(tp[key])
except (ValueError):
tp[key] = None
for entry in proc_data:
for key in float_list:
if key in entry:
try:
entry[key] = float(entry[key])
except (ValueError):
entry[key] = None
if 'trip_points' in entry:
for tp in entry['trip_points']:
for key in float_list:
if key in tp:
try:
tp[key] = float(tp[key])
except (ValueError):
tp[key] = None
for key in tp:
if key in int_list:
tp[key] = jc.utils.convert_to_int(tp[key])
if key in float_list:
tp[key] = jc.utils.convert_to_float(tp[key])
for entry in proc_data:
if 'until_charged' in entry:

View File

@ -80,7 +80,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.2'
version = '1.3'
description = '`airport -I` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -111,10 +111,7 @@ def _process(proc_data):
'lasttxrate', 'maxrate', 'lastassocstatus', 'mcs']
for key in proc_data:
if key in int_list:
try:
proc_data[key] = int(proc_data[key])
except (ValueError):
proc_data[key] = None
proc_data[key] = jc.utils.convert_to_int(proc_data[key])
return proc_data

View File

@ -109,7 +109,7 @@ import jc.parsers.universal
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.3'
version = '1.4'
description = '`airport -s` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -137,23 +137,14 @@ def _process(proc_data):
"""
for entry in proc_data:
# integers
# convert integers and booleans
int_list = ['rssi']
for key in int_list:
if key in entry:
try:
entry[key] = int(entry[key])
except (ValueError):
entry[key] = None
# booleans
bool_list = ['ht']
for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
if key in bool_list:
try:
entry[key] = True if entry[key] == 'Y' else False
except (ValueError):
entry[key] = None
entry[key] = jc.utils.convert_to_bool(entry[key])
if 'security' in entry:
entry['security'] = entry['security'].split()

View File

@ -150,12 +150,9 @@ def _process(proc_data):
entry['name'] = None
int_list = ['expires']
for key in int_list:
if key in entry:
try:
entry[key] = int(entry[key])
except (ValueError):
entry[key] = None
for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
return proc_data

View File

@ -121,7 +121,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.3'
version = '1.4'
description = '`blkid` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -155,12 +155,9 @@ def _process(proc_data):
'id_part_entry_offset', 'id_part_entry_size', 'minimum_io_size', 'physical_sector_size',
'logical_sector_size', 'id_iolimit_minimum_io_size', 'id_iolimit_physical_sector_size',
'id_iolimit_logical_sector_size']
for key in int_list:
if key in entry:
try:
entry[key] = int(entry[key])
except (ValueError):
entry[key] = None
for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
return proc_data

View File

@ -54,7 +54,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.1'
version = '1.2'
description = '`cksum` and `sum` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -82,12 +82,10 @@ def _process(proc_data):
for entry in proc_data:
int_list = ['checksum', 'blocks']
for key in int_list:
if key in entry:
try:
entry[key] = int(entry[key])
except (ValueError):
entry[key] = None
for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
return proc_data

View File

@ -98,7 +98,7 @@ import jc.parsers.universal
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.6'
version = '1.7'
description = '`df` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -144,11 +144,7 @@ def _process(proc_data):
# change any entry for key with '_blocks' in the name to int
for k in entry:
if '_blocks' in str(k):
try:
blocks_int = int(entry[k])
entry[k] = blocks_int
except (ValueError):
entry[k] = None
entry[k] = jc.utils.convert_to_int(entry[k])
# remove percent sign from 'use_percent', 'capacity_percent', and 'iused_percent'
if 'use_percent' in entry:
@ -162,13 +158,9 @@ def _process(proc_data):
# change used, available, use_percent, capacity_percent, ifree, iused, iused_percent to int
int_list = ['used', 'available', 'use_percent', 'capacity_percent', 'ifree', 'iused', 'iused_percent']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
return proc_data

View File

@ -40,6 +40,16 @@ Schema:
"data": string
}
],
"opt_pseudosection": {
"edns": {
"version": integer,
"flags": [
string
],
"udp": integer
},
"cookie": string
},
"question": {
"name": string,
"class": string,
@ -54,6 +64,15 @@ Schema:
"data": string
}
],
"additional": [
{
"name": string,
"class": string,
"type": string,
"ttl": integer,
"data": string
}
],
"authority": [
{
"name": string,
@ -63,6 +82,7 @@ Schema:
"data": string
}
],
"query_size": integer,
"query_time": integer, # in msec
"server": string,
"when": string,
@ -75,10 +95,10 @@ Schema:
Examples:
$ dig cnn.com www.cnn.com @205.251.194.64 | jc --dig -p
$ dig example.com | jc --dig -p
[
{
"id": 52172,
"id": 2951,
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
@ -87,113 +107,35 @@ Examples:
"ra"
],
"query_num": 1,
"answer_num": 4,
"answer_num": 1,
"authority_num": 0,
"additional_num": 1,
"opt_pseudosection": {
"edns": {
"version": 0,
"flags": [],
"udp": 4096
}
},
"question": {
"name": "cnn.com.",
"name": "example.com.",
"class": "IN",
"type": "A"
},
"answer": [
{
"name": "cnn.com.",
"name": "example.com.",
"class": "IN",
"type": "A",
"ttl": 27,
"data": "151.101.65.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": 27,
"data": "151.101.129.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": 27,
"data": "151.101.1.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": 27,
"data": "151.101.193.67"
"ttl": 39302,
"data": "93.184.216.34"
}
],
"query_time": 38,
"server": "2600",
"when": "Tue Mar 30 20:07:59 PDT 2021",
"rcvd": 100,
"when_epoch": 1617160079,
"when_epoch_utc": null
},
{
"id": 36292,
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
"qr",
"aa",
"rd"
],
"query_num": 1,
"answer_num": 1,
"authority_num": 4,
"additional_num": 1,
"question": {
"name": "www.cnn.com.",
"class": "IN",
"type": "A"
},
"answer": [
{
"name": "www.cnn.com.",
"class": "IN",
"type": "CNAME",
"ttl": 300,
"data": "turner-tls.map.fastly.net."
}
],
"authority": [
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": 3600,
"data": "ns-1086.awsdns-07.org."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": 3600,
"data": "ns-1630.awsdns-11.co.uk."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": 3600,
"data": "ns-47.awsdns-05.com."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": 3600,
"data": "ns-576.awsdns-08.net."
}
],
"query_time": 27,
"server": "205.251.194.64#53(205.251.194.64)",
"when": "Tue Mar 30 20:07:59 PDT 2021",
"rcvd": 212,
"when_epoch": 1617160079,
"query_time": 49,
"server": "2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)",
"when": "Fri Apr 16 16:05:10 PDT 2021",
"rcvd": 56,
"when_epoch": 1618614310,
"when_epoch_utc": null
}
]
@ -201,7 +143,7 @@ Examples:
$ dig cnn.com www.cnn.com @205.251.194.64 | jc --dig -p -r
[
{
"id": "23843",
"id": "46052",
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
@ -210,117 +152,41 @@ Examples:
"ra"
],
"query_num": "1",
"answer_num": "4",
"answer_num": "1",
"authority_num": "0",
"additional_num": "1",
"opt_pseudosection": {
"edns": {
"version": "0",
"flags": [],
"udp": "4096"
}
},
"question": {
"name": "cnn.com.",
"name": "example.com.",
"class": "IN",
"type": "A"
},
"answer": [
{
"name": "cnn.com.",
"name": "example.com.",
"class": "IN",
"type": "A",
"ttl": "30",
"data": "151.101.193.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": "30",
"data": "151.101.1.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": "30",
"data": "151.101.65.67"
},
{
"name": "cnn.com.",
"class": "IN",
"type": "A",
"ttl": "30",
"data": "151.101.129.67"
"ttl": "40426",
"data": "93.184.216.34"
}
],
"query_time": "24 msec",
"server": "192.168.1.254#53(192.168.1.254)",
"when": "Tue Nov 12 07:16:19 PST 2019",
"rcvd": "100"
},
{
"id": "8266",
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
"qr",
"aa",
"rd"
],
"query_num": "1",
"answer_num": "1",
"authority_num": "4",
"additional_num": "1",
"question": {
"name": "www.cnn.com.",
"class": "IN",
"type": "A"
},
"answer": [
{
"name": "www.cnn.com.",
"class": "IN",
"type": "CNAME",
"ttl": "300",
"data": "turner-tls.map.fastly.net."
}
],
"authority": [
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": "3600",
"data": "ns-1086.awsdns-07.org."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": "3600",
"data": "ns-1630.awsdns-11.co.uk."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": "3600",
"data": "ns-47.awsdns-05.com."
},
{
"name": "cnn.com.",
"class": "IN",
"type": "NS",
"ttl": "3600",
"data": "ns-576.awsdns-08.net."
}
],
"query_time": "26 msec",
"server": "205.251.194.64#53(205.251.194.64)",
"when": "Tue Nov 12 07:16:19 PST 2019",
"rcvd": "212"
"query_time": "48 msec",
"server": "2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)",
"when": "Fri Apr 16 16:06:12 PDT 2021",
"rcvd": "56"
}
]
$ dig -x 1.1.1.1 | jc --dig -p
[
{
"id": 22191,
"id": 20785,
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
@ -332,6 +198,13 @@ Examples:
"answer_num": 1,
"authority_num": 0,
"additional_num": 1,
"opt_pseudosection": {
"edns": {
"version": 0,
"flags": [],
"udp": 4096
}
},
"question": {
"name": "1.1.1.1.in-addr.arpa.",
"class": "IN",
@ -346,11 +219,11 @@ Examples:
"data": "one.one.one.one."
}
],
"query_time": 44,
"server": "2600",
"when": "Tue Mar 30 20:10:34 PDT 2021",
"query_time": 40,
"server": "2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)",
"when": "Sat Apr 17 14:50:50 PDT 2021",
"rcvd": 78,
"when_epoch": 1617160234,
"when_epoch": 1618696250,
"when_epoch_utc": null
}
]
@ -358,7 +231,7 @@ Examples:
$ dig -x 1.1.1.1 | jc --dig -p -r
[
{
"id": "50986",
"id": "32644",
"opcode": "QUERY",
"status": "NOERROR",
"flags": [
@ -370,6 +243,13 @@ Examples:
"answer_num": "1",
"authority_num": "0",
"additional_num": "1",
"opt_pseudosection": {
"edns": {
"version": "0",
"flags": [],
"udp": "4096"
}
},
"question": {
"name": "1.1.1.1.in-addr.arpa.",
"class": "IN",
@ -384,9 +264,9 @@ Examples:
"data": "one.one.one.one."
}
],
"query_time": "38 msec",
"server": "2600",
"when": "Tue Nov 12 07:17:19 PST 2019",
"query_time": "52 msec",
"server": "2600:1700:bab0:d40::1#53(2600:1700:bab0:d40::1)",
"when": "Sat Apr 17 14:51:46 PDT 2021",
"rcvd": "78"
}
]
@ -396,7 +276,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.7'
version = '2.0'
description = '`dig` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -421,47 +301,36 @@ def _process(proc_data):
List of Dictionaries. Structured data to conform to the schema.
"""
for entry in proc_data:
int_list = ['id', 'query_num', 'answer_num', 'authority_num', 'additional_num', 'rcvd']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
int_list = ['id', 'query_num', 'answer_num', 'authority_num', 'additional_num', 'rcvd',
'query_size', 'query_time']
for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
if 'axfr' in entry:
for ax in entry['axfr']:
try:
ttl_int = int(ax['ttl'])
ax['ttl'] = ttl_int
except (ValueError):
ax['ttl'] = None
ax['ttl'] = jc.utils.convert_to_int(ax['ttl'])
if 'opt_pseudosection' in entry:
if 'edns' in entry['opt_pseudosection']:
if 'version' in entry['opt_pseudosection']['edns']:
entry['opt_pseudosection']['edns']['version'] = jc.utils.convert_to_int(entry['opt_pseudosection']['edns']['version'])
if 'udp' in entry['opt_pseudosection']['edns']:
entry['opt_pseudosection']['edns']['udp'] = jc.utils.convert_to_int(entry['opt_pseudosection']['edns']['udp'])
if 'answer' in entry:
for ans in entry['answer']:
try:
ttl_int = int(ans['ttl'])
ans['ttl'] = ttl_int
except (ValueError):
ans['ttl'] = None
ans['ttl'] = jc.utils.convert_to_int(ans['ttl'])
if 'additional' in entry:
for add in entry['additional']:
add['ttl'] = jc.utils.convert_to_int(add['ttl'])
if 'authority' in entry:
for auth in entry['authority']:
try:
ttl_int = int(auth['ttl'])
auth['ttl'] = ttl_int
except (ValueError):
auth['ttl'] = None
if 'query_time' in entry:
try:
qt_int = int(entry['query_time'].split()[0])
entry['query_time'] = qt_int
except (ValueError):
entry['query_time'] = None
auth['ttl'] = jc.utils.convert_to_int(auth['ttl'])
if 'when' in entry:
ts = jc.utils.timestamp(entry['when'])
@ -507,6 +376,31 @@ def _parse_flags_line(flagsline):
'additional_num': additional_num}
def _parse_opt_pseudosection(optline):
# ;; OPT PSEUDOSECTION:
# ; EDNS: version: 0, flags:; udp: 4096
# ; COOKIE: 1cbc06703eaef210
if optline.startswith('; EDNS:'):
optline_list = optline.replace(',', ' ').split(';')
optline_first = optline_list[1]
optline_rest = optline_list[2]
_, _, ver, _, *flags = optline_first.split()
udp = optline_rest.split()[-1]
return {
'edns': {
'version': ver,
'flags': flags,
'udp': udp
}
}
elif optline.startswith('; COOKIE:'):
return {
'cookie': optline.split()[2]
}
def _parse_question(question):
# ;www.cnn.com. IN A
question = question.split()
@ -519,22 +413,6 @@ def _parse_question(question):
'type': dns_type}
def _parse_authority(authority):
# cnn.com. 3600 IN NS ns-1086.awsdns-07.org.
authority = authority.split()
authority_name = authority[0]
authority_class = authority[2]
authority_type = authority[3]
authority_ttl = authority[1]
authority_data = authority[4]
return {'name': authority_name,
'class': authority_class,
'type': authority_type,
'ttl': authority_ttl,
'data': authority_data}
def _parse_answer(answer):
# www.cnn.com. 5 IN CNAME turner-tls.map.fastly.net.
answer = answer.split(maxsplit=4)
@ -574,6 +452,28 @@ def _parse_axfr(axfr):
'data': axfr_data}
def _parse_footer(footer):
# footer consists of 4 lines
# footer line 1
if footer.startswith(';; Query time:'):
return {'query_time': footer.split(':')[1].lstrip()}
# footer line 2
if footer.startswith(';; SERVER:'):
return {'server': footer.split(':', maxsplit=1)[1].lstrip()}
# footer line 3
if footer.startswith(';; WHEN:'):
return {'when': footer.split(':', maxsplit=1)[1].lstrip()}
# footer line 4 (last line)
if footer.startswith(';; MSG SIZE rcvd:'):
return {'rcvd': footer.split(':')[1].lstrip()}
elif footer.startswith(';; XFR size:'):
return {'size': footer.split(':')[1].lstrip()}
def parse(data, raw=False, quiet=False):
"""
Main text parsing function
@ -597,104 +497,104 @@ def parse(data, raw=False, quiet=False):
# remove blank lines
cleandata = list(filter(None, cleandata))
question = False
authority = False
answer = False
axfr = False
# section can be: header, flags, question, authority, answer, axfr, additional, opt_pseudosection, footer
section = ''
output_entry = {}
if jc.utils.has_data(data):
for line in cleandata:
# identify sections
if line.startswith(';; Got answer:'):
section = ''
continue
if line.startswith('; <<>> ') and ' axfr ' in line.lower():
question = False
authority = False
answer = False
axfr = True
section = 'axfr'
axfr_list = []
continue
if ';' not in line and axfr:
axfr_list.append(_parse_axfr(line))
output_entry.update({'axfr': axfr_list})
continue
if line.startswith(';; ->>HEADER<<-'):
section = 'header'
if output_entry:
raw_output.append(output_entry)
output_entry = {}
output_entry.update(_parse_header(line))
continue
if line.startswith(';; flags:'):
section = 'flags'
output_entry.update(_parse_flags_line(line))
continue
if line.startswith(';; QUESTION SECTION:'):
question = True
authority = False
answer = False
axfr = False
if line.startswith(';; OPT PSEUDOSECTION:'):
section = 'opt_pseudosection'
continue
if question:
output_entry['question'] = _parse_question(line)
question = False
authority = False
answer = False
axfr = False
if line.startswith(';; QUESTION SECTION:'):
section = 'question'
continue
if line.startswith(';; AUTHORITY SECTION:'):
question = False
authority = True
answer = False
axfr = False
section = 'authority'
authority_list = []
continue
if ';' not in line and authority:
authority_list.append(_parse_authority(line))
output_entry.update({'authority': authority_list})
continue
if line.startswith(';; ANSWER SECTION:'):
question = False
authority = False
answer = True
axfr = False
section = 'answer'
answer_list = []
continue
if ';' not in line and answer:
if line.startswith(';; ADDITIONAL SECTION:'):
section = 'additional'
additional_list = []
continue
if line.startswith(';; Query time:'):
section = 'footer'
output_entry.update(_parse_footer(line))
continue
# parse sections
if line.startswith(';; QUERY SIZE:'):
output_entry.update({'query_size': line.split(': ', maxsplit=1)[1]})
continue
if not line.startswith(';') and section == 'axfr':
axfr_list.append(_parse_axfr(line))
output_entry.update({'axfr': axfr_list})
continue
if section == 'opt_pseudosection':
if 'opt_pseudosection' not in output_entry:
output_entry['opt_pseudosection'] = {}
output_entry['opt_pseudosection'].update(_parse_opt_pseudosection(line))
continue
if section == 'question':
output_entry['question'] = _parse_question(line)
continue
if not line.startswith(';') and section == 'authority':
authority_list.append(_parse_answer(line))
output_entry.update({'authority': authority_list})
continue
if not line.startswith(';') and section == 'answer':
answer_list.append(_parse_answer(line))
output_entry.update({'answer': answer_list})
continue
# footer consists of 4 lines
# footer line 1
if line.startswith(';; Query time:'):
output_entry.update({'query_time': line.split(':')[1].lstrip()})
if not line.startswith(';') and section == 'additional':
additional_list.append(_parse_answer(line))
output_entry.update({'additional': additional_list})
continue
# footer line 2
if line.startswith(';; SERVER:'):
output_entry.update({'server': line.split(':')[1].lstrip()})
if section == 'footer':
output_entry.update(_parse_footer(line))
continue
# footer line 3
if line.startswith(';; WHEN:'):
output_entry.update({'when': line.split(':', maxsplit=1)[1].lstrip()})
continue
# footer line 4 (last line)
if line.startswith(';; MSG SIZE rcvd:'):
output_entry.update({'rcvd': line.split(':')[1].lstrip()})
if output_entry:
raw_output.append(output_entry)
elif line.startswith(';; XFR size:'):
output_entry.update({'size': line.split(':')[1].lstrip()})
if output_entry:
raw_output.append(output_entry)

View File

@ -121,7 +121,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.1'
version = '1.2'
description = '`dir` command parser'
author = 'Rasheed Elsaleh'
author_email = 'rasheed@rebelliondefense.com'
@ -155,14 +155,9 @@ def _process(proc_data):
# add ints
int_list = ["size"]
for key in int_list:
if entry.get(key):
try:
key_int = int(entry[key].replace(",", ""))
except ValueError:
entry[key] = None
else:
entry[key] = key_int
for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
return proc_data

View File

@ -125,7 +125,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.2'
version = '1.3'
description = '`dmidecode` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -153,13 +153,9 @@ def _process(proc_data):
"""
for entry in proc_data:
int_list = ['type', 'bytes']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
if not entry['values']:
entry['values'] = None

View File

@ -88,7 +88,7 @@ import jc.parsers.universal
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.3'
version = '1.4'
description = '`du` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -116,13 +116,9 @@ def _process(proc_data):
"""
int_list = ['size']
for entry in proc_data:
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
return proc_data

View File

@ -66,6 +66,8 @@ def _process(proc_data):
"""
# rebuild output for added semantic information
# use helper functions in jc.utils for int, float, bool conversions and timestamps
return proc_data

View File

@ -73,7 +73,7 @@ import jc.parsers.universal
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.3'
version = '1.4'
description = '`free` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -101,13 +101,9 @@ def _process(proc_data):
for entry in proc_data:
int_list = ['total', 'used', 'free', 'shared', 'buff_cache', 'available']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
return proc_data

View File

@ -85,7 +85,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.4'
version = '1.5'
description = '`/etc/fstab` file parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -111,13 +111,9 @@ def _process(proc_data):
"""
for entry in proc_data:
int_list = ['fs_freq', 'fs_passno']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
return proc_data

View File

@ -109,7 +109,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.2'
version = '1.3'
description = '`/etc/group` file parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -136,13 +136,9 @@ def _process(proc_data):
"""
for entry in proc_data:
int_list = ['gid']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
if entry['members'] == ['']:
entry['members'] = []

View File

@ -38,7 +38,7 @@ import jc.parsers.universal
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.1'
version = '1.2'
description = '`hash` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -63,15 +63,10 @@ def _process(proc_data):
List of Dictionaries. Structured data to conform to the schema.
"""
for entry in proc_data:
# change to int
int_list = ['hits']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
return proc_data

View File

@ -317,7 +317,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.1'
version = '1.2'
description = '`hciconfig` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -346,15 +346,11 @@ def _process(proc_data):
for entry in proc_data:
# integers
int_list = ['acl_mtu', 'acl_mtu_packets', 'sco_mtu', 'sco_mtu_packets', 'rx_bytes', 'rx_acl', 'rx_sco',
'rx_events', 'rx_errors', 'tx_bytes', 'tx_acl', 'tx_sco', 'tx_commands', 'tx_errors']
for key in int_list:
if key in entry:
try:
entry[key] = int(entry[key])
except (ValueError):
entry[key] = None
for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
if 'service_classes' in entry and len(entry['service_classes']) == 1 and 'Unspecified' in entry['service_classes']:
entry['service_classes'] = None

View File

@ -57,7 +57,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.4'
version = '1.5'
description = '`history` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -82,12 +82,10 @@ def _process(proc_data):
List of Dictionaries. Structured data to conform to the schema.
"""
# rebuild output for added semantic information
processed = []
for k, v in proc_data.items():
proc_line = {
'line': int(k) if k.isdigit() else None,
'line': jc.utils.convert_to_int(k),
'command': v,
}
processed.append(proc_line)

View File

@ -105,7 +105,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.2'
version = '1.3'
description = '`id` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -133,25 +133,16 @@ def _process(proc_data):
"""
if 'uid' in proc_data:
if 'id' in proc_data['uid']:
try:
proc_data['uid']['id'] = int(proc_data['uid']['id'])
except (ValueError):
proc_data['uid']['id'] = None
proc_data['uid']['id'] = jc.utils.convert_to_int(proc_data['uid']['id'])
if 'gid' in proc_data:
if 'id' in proc_data['gid']:
try:
proc_data['gid']['id'] = int(proc_data['gid']['id'])
except (ValueError):
proc_data['gid']['id'] = None
proc_data['gid']['id'] = jc.utils.convert_to_int(proc_data['gid']['id'])
if 'groups' in proc_data:
for group in proc_data['groups']:
if 'id' in group:
try:
group['id'] = int(group['id'])
except (ValueError):
group['id'] = None
group['id'] = jc.utils.convert_to_int(group['id'])
return proc_data

View File

@ -188,7 +188,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.9'
version = '1.10'
description = '`ifconfig` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -264,7 +264,7 @@ class _IfconfigParser(object):
:return:
"""
for attr in kwargs.keys():
if attr not in IfconfigParser.attributes:
if attr not in _IfconfigParser.attributes:
raise ValueError("Attribute [{}] not supported.".format(attr))
filtered_interfaces = []
@ -398,7 +398,8 @@ class _IfconfigParser(object):
if match:
details = match.groupdict()
for k, v in details.items():
if isinstance(v, str): details[k] = v.strip()
if isinstance(v, str):
details[k] = v.strip()
_interface.update(details)
if _interface is not None:
available_interfaces[_interface['name']] = self.update_interface_details(_interface)
@ -433,13 +434,9 @@ def _process(proc_data):
int_list = ['flags', 'mtu', 'ipv6_mask', 'rx_packets', 'rx_bytes', 'rx_errors', 'rx_dropped', 'rx_overruns',
'rx_frame', 'tx_packets', 'tx_bytes', 'tx_errors', 'tx_dropped', 'tx_overruns', 'tx_carrier',
'tx_collisions', 'metric']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError, TypeError):
entry[key] = None
for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
# convert OSX-style subnet mask to dotted quad
if 'ipv4_mask' in entry:

View File

@ -163,7 +163,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.5'
version = '1.6'
description = '`iptables` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -191,13 +191,9 @@ def _process(proc_data):
for entry in proc_data:
for rule in entry['rules']:
int_list = ['num', 'pkts']
for key in int_list:
if key in rule:
try:
key_int = int(rule[key])
rule[key] = key_int
except (ValueError):
rule[key] = None
for key in rule:
if key in int_list:
rule[key] = jc.utils.convert_to_int(rule[key])
if 'bytes' in rule:
multiplier = 1
@ -218,7 +214,7 @@ def _process(proc_data):
rule['bytes'] = rule['bytes'].rstrip('P')
try:
bytes_int = int(rule['bytes'])
bytes_int = jc.utils.convert_to_int(rule['bytes'])
rule['bytes'] = bytes_int * multiplier
except (ValueError):
rule['bytes'] = None

View File

@ -95,7 +95,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.3'
version = '1.4'
description = '`jobs` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -122,13 +122,9 @@ def _process(proc_data):
"""
for entry in proc_data:
int_list = ['job_number', 'pid']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
return proc_data

View File

@ -104,7 +104,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.6'
version = '1.7'
description = '`last` and `lastb` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -161,7 +161,7 @@ def _process(proc_data):
entry['logout_epoch'] = timestamp.naive
if 'login_epoch' in entry and 'logout_epoch' in entry:
entry['duration_seconds'] = int(entry['logout_epoch']) - int(entry['login_epoch'])
entry['duration_seconds'] = entry['logout_epoch'] - entry['login_epoch']
if 'duration' in entry and re.match(r'^\d+\+', entry['duration']):
m = re.match(r'^(?P<days>\d+)\+(?P<hours>\d\d):(?P<minutes>\d\d)', entry['duration'])

View File

@ -3,7 +3,6 @@
Options supported:
- `lbaR1`
- `--time-style=full-iso`
- `-h`: File sizes will be available in text form with `-r` but larger file sizes with human readable suffixes will be converted to `Null` in the default view since the parser attempts to convert this field to an integer.
Note: The `-1`, `-l`, or `-b` option of `ls` should be used to correctly parse filenames that include newline characters. Since `ls` does not encode newlines in filenames when outputting to a pipe it will cause `jc` to see multiple files instead of a single file if `-1`, `-l`, or `-b` is not used. Alternatively, `vdir` can be used, which is the same as running `ls -lb`.
@ -108,7 +107,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.8'
version = '1.9'
description = '`ls` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -135,13 +134,9 @@ def _process(proc_data):
"""
for entry in proc_data:
int_list = ['links', 'size']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
if 'date' in entry:
# to speed up processing only try to convert the date if it's not the default format

View File

@ -269,7 +269,7 @@ import jc.parsers.universal
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.6'
version = '1.7'
description = '`lsblk` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -295,25 +295,14 @@ def _process(proc_data):
List of Dictionaries. Structured data to conform to the schema.
"""
for entry in proc_data:
# boolean changes
# boolean and integer changes
bool_list = ['rm', 'ro', 'rota', 'disc_zero', 'rand']
for key in bool_list:
if key in entry:
try:
key_bool = bool(int(entry[key]))
entry[key] = key_bool
except (ValueError):
entry[key] = None
# integer changes
int_list = ['ra', 'alignment', 'min_io', 'opt_io', 'phy_sec', 'log_sec', 'rq_size', 'disc_aln']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
for key in entry:
if key in bool_list:
entry[key] = jc.utils.convert_to_bool(entry[key])
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
return proc_data

View File

@ -126,7 +126,7 @@ import jc.parsers.universal
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.4'
version = '1.5'
description = '`lsmod` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -152,15 +152,10 @@ def _process(proc_data):
List of Dictionaries. Structured data to conform to the schema.
"""
for entry in proc_data:
# integer changes
int_list = ['size', 'used']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
return proc_data

View File

@ -120,7 +120,7 @@ import jc.parsers.universal
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.3'
version = '1.4'
description = '`lsof` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -146,15 +146,11 @@ def _process(proc_data):
List of Dictionaries. Structured data to conform to the schema.
"""
for entry in proc_data:
# integer changes
int_list = ['pid', 'tid', 'size_off', 'node']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError, TypeError):
entry[key] = None
for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
return proc_data

View File

@ -349,11 +349,12 @@ Examples:
}
]
"""
import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.9'
version = '1.10'
description = '`netstat` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -379,7 +380,7 @@ def _process(proc_data):
List of Dictionaries. Structured data to conform to the schema.
"""
for entry in proc_data:
# integer changes
# integer and float conversions
int_list = ['recv_q', 'send_q', 'pid', 'refcnt', 'inode', 'unit', 'vendor', 'class',
'osx_flags', 'subcla', 'pcbcount', 'rcvbuf', 'sndbuf', 'rxbytes', 'txbytes',
'route_refs', 'use', 'mtu', 'mss', 'window', 'irtt', 'metric', 'ipkts',
@ -387,35 +388,23 @@ def _process(proc_data):
'tx_ok', 'tx_err', 'tx_drp', 'tx_ovr', 'idrop', 'ibytes', 'obytes', 'r_mbuf',
's_mbuf', 'r_clus', 's_clus', 'r_hiwa', 's_hiwa', 'r_lowa', 's_lowa', 'r_bcnt',
's_bcnt', 'r_bmax', 's_bmax', 'rexmit', 'ooorcv', '0_win']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
# float changes
float_list = ['rexmt', 'persist', 'keep', '2msl', 'delack', 'rcvtime']
for key in float_list:
if key in entry:
try:
key_float = float(entry[key])
entry[key] = key_float
except (ValueError):
entry[key] = None
for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
if key in float_list:
entry[key] = jc.utils.convert_to_float(entry[key])
# add number keys
if 'local_port' in entry:
try:
entry['local_port_num'] = int(entry['local_port'])
except (ValueError):
pass
local_num = jc.utils.convert_to_int(entry['local_port'])
if local_num:
entry['local_port_num'] = local_num
if 'foreign_port' in entry:
try:
entry['foreign_port_num'] = int(entry['foreign_port'])
except (ValueError):
pass
foreign_num = jc.utils.convert_to_int(entry['foreign_port'])
if foreign_num:
entry['foreign_port_num'] = foreign_num
return proc_data

View File

@ -207,7 +207,7 @@ import jc.parsers.universal
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.4'
version = '1.5'
description = '`ntpq -p` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -240,20 +240,12 @@ def _process(proc_data):
entry['state'] = entry.pop('s')
int_list = ['st', 'when', 'poll', 'reach']
for key in int_list:
if key in entry:
try:
entry[key] = int(entry[key])
except (ValueError):
entry[key] = None
float_list = ['delay', 'offset', 'jitter']
for key in float_list:
if key in entry:
try:
entry[key] = float(entry[key])
except (ValueError):
entry[key] = None
for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
if key in float_list:
entry[key] = jc.utils.convert_to_float(entry[key])
return proc_data

View File

@ -94,7 +94,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.2'
version = '1.3'
description = '`/etc/passwd` file parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -121,13 +121,9 @@ def _process(proc_data):
"""
for entry in proc_data:
int_list = ['uid', 'gid']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
return proc_data

View File

@ -146,7 +146,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.3'
version = '1.4'
description = '`ping` and `ping6` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -175,34 +175,20 @@ def _process(proc_data):
float_list = ['packet_loss_percent', 'round_trip_ms_min', 'round_trip_ms_avg', 'round_trip_ms_max',
'round_trip_ms_stddev', 'timestamp', 'time_ms']
for key in proc_data.keys():
for item in int_list:
if item == key:
try:
proc_data[key] = int(proc_data[key])
except (ValueError, TypeError):
proc_data[key] = None
for key in proc_data:
if key in int_list:
proc_data[key] = jc.utils.convert_to_int(proc_data[key])
for item in float_list:
if item == key:
try:
proc_data[key] = float(proc_data[key])
except (ValueError, TypeError):
proc_data[key] = None
if key in float_list:
proc_data[key] = jc.utils.convert_to_float(proc_data[key])
if key == 'responses':
for entry in proc_data['responses']:
for k in entry.keys():
for k in entry:
if k in int_list:
try:
entry[k] = int(entry[k])
except (ValueError, TypeError):
entry[k] = None
entry[k] = jc.utils.convert_to_int(entry[k])
if k in float_list:
try:
entry[k] = float(entry[k])
except (ValueError, TypeError):
entry[k] = None
entry[k] = jc.utils.convert_to_float(entry[k])
return proc_data

View File

@ -207,7 +207,7 @@ import jc.parsers.universal
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.4'
version = '1.5'
description = '`ps` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -241,26 +241,16 @@ def _process(proc_data):
if '%mem' in entry:
entry['mem_percent'] = entry.pop('%mem')
# change to int
# convert ints and floats
int_list = ['pid', 'ppid', 'c', 'vsz', 'rss']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
# change to float
float_list = ['cpu_percent', 'mem_percent']
for key in float_list:
if key in entry:
try:
key_float = float(entry[key])
entry[key] = key_float
except (ValueError):
entry[key] = None
for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
if key in float_list:
entry[key] = jc.utils.convert_to_float(entry[key])
# clean up other fields
if 'tty' in entry:
if entry['tty'] == '?' or entry['tty'] == '??':
entry['tty'] = None

View File

@ -111,7 +111,7 @@ import jc.parsers.universal
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.5'
version = '1.6'
description = '`route` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -138,13 +138,9 @@ def _process(proc_data):
"""
for entry in proc_data:
int_list = ['metric', 'ref', 'use', 'mss', 'window', 'irtt']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
# add flags_pretty
# Flag mapping from https://www.man7.org/linux/man-pages/man8/route.8.html

View File

@ -156,7 +156,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.2'
version = '1.3'
description = '`rpm -qi` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -185,12 +185,9 @@ def _process(proc_data):
for entry in proc_data:
int_list = ['epoch', 'size']
for key in int_list:
if key in entry:
try:
entry[key] = int(entry[key])
except (ValueError):
entry[key] = None
for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
if 'build_date' in entry:
timestamp = jc.utils.timestamp(entry['build_date'])

View File

@ -101,7 +101,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.2'
version = '1.3'
description = '`/etc/shadow` file parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -128,13 +128,9 @@ def _process(proc_data):
"""
for entry in proc_data:
int_list = ['last_changed', 'minimum', 'maximum', 'warn', 'inactive', 'expire']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
return proc_data

View File

@ -279,7 +279,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.3'
version = '1.4'
description = '`ss` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -306,25 +306,19 @@ def _process(proc_data):
"""
for entry in proc_data:
int_list = ['recv_q', 'send_q', 'pid']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
if 'local_port' in entry:
try:
entry['local_port_num'] = int(entry['local_port'])
except (ValueError):
pass
local_num = jc.utils.convert_to_int(entry['local_port'])
if local_num is not None and local_num >= 0:
entry['local_port_num'] = local_num
if 'peer_port' in entry:
try:
entry['peer_port_num'] = int(entry['peer_port'])
except (ValueError):
pass
peer_num = jc.utils.convert_to_int(entry['peer_port'])
if peer_num is not None and peer_num >= 0:
entry['peer_port_num'] = peer_num
return proc_data

View File

@ -169,7 +169,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.7'
version = '1.8'
description = '`stat` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -195,14 +195,11 @@ def _process(proc_data):
List of Dictionaries. Structured data to conform to the schema.
"""
for entry in proc_data:
int_list = ['size', 'blocks', 'io_blocks', 'inode', 'links', 'uid', 'gid', 'unix_device', 'rdev', 'block_size']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
int_list = ['size', 'blocks', 'io_blocks', 'inode', 'links', 'uid', 'gid', 'unix_device',
'rdev', 'block_size']
for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
# turn - into null for time fields and add calculated timestamp fields
for entry in proc_data:

View File

@ -75,7 +75,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.4'
version = '1.5'
description = '`systemctl list-jobs` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -102,13 +102,10 @@ def _process(proc_data):
"""
for entry in proc_data:
int_list = ['job']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
return proc_data

528
jc/parsers/systeminfo.py Normal file
View File

@ -0,0 +1,528 @@
"""jc - JSON CLI output utility `systeminfo` command output parser
Blank or missing elements are set to `null`.
The `original_install_date_epoch` and `system_boot_time_epoch` calculated timestamp fields are naive (i.e. based on the local time of the system the parser is run on)
The `original_install_date_epoch_utc` and `system_boot_time_epoch_utc` calculated timestamp fields are timezone-aware and are only available if the timezone field is UTC.
Usage (cli):
$ systeminfo | jc --systeminfo
Usage (module):
import jc.parsers.systeminfo
result = jc.parsers.systeminfo.parse(systeminfo_command_output)
Schema:
{
"host_name": string,
"os_name": string,
"os_version": string,
"os_manufacturer": string,
"os_configuration": string,
"os_build_type": string,
"registered_owner": string,
"registered_organization": string,
"product_id": string,
"original_install_date": string,
"original_install_date_epoch": integer, # naive timestamp
"original_install_date_epoch_utc": integer, # timezone-aware timestamp
"system_boot_time": string,
"system_boot_time_epoch": integer, # naive timestamp
"system_boot_time_epoch_utc": integer, # timezone-aware timestamp
"system_manufacturer": string,
"system_model": string,
"system_type": string,
"processors": [
string
],
"bios_version": string,
"windows_directory": string,
"system_directory": string,
"boot_device": string,
"system_locale": string,
"input_locale": string,
"time_zone": string,
"total_physical_memory_mb": string,
"available_physical_memory_mb": integer,
"virtual_memory_max_size_mb": integer,
"virtual_memory_available_mb": integer,
"virtual_memory_in_use_mb": integer,
"page_file_locations": string,
"domain": string,
"logon_server": string,
"hotfixs": [
string
],
"network_cards": [
{
"name": string,
"connection_name": string,
"status": string,
"dhcp_enabled": boolean,
"dhcp_server": string,
"ip_addresses": [
string
]
}
],
"hyperv_requirements": {
"vm_monitor_mode_extensions": boolean,
"virtualization_enabled_in_firmware": boolean,
"second_level_address_translation": boolean,
"data_execution_prevention_available": boolean
}
}
Examples:
$ systeminfo | jc --systeminfo -p
{
"host_name": "TESTLAPTOP",
"os_name": "Microsoft Windows 10 Enterprise",
"os_version": "10.0.17134 N/A Build 17134",
"os_manufacturer": "Microsoft Corporation",
"os_configuration": "Member Workstation",
"os_build_type": "Multiprocessor Free",
"registered_owner": "Test, Inc.",
"registered_organization": "Test, Inc.",
"product_id": "11111-11111-11111-AA111",
"original_install_date": "3/26/2019, 3:51:30 PM",
"system_boot_time": "3/30/2021, 6:13:59 AM",
"system_manufacturer": "Dell Inc.",
"system_model": "Precision 5530",
"system_type": "x64-based PC",
"processors": [
"Intel64 Family 6 Model 158 Stepping 10 GenuineIntel ~2592 Mhz"
],
"bios_version": "Dell Inc. 1.16.2, 4/21/2020",
"windows_directory": "C:\\WINDOWS",
"system_directory": "C:\\WINDOWS\\system32",
"boot_device": "\\Device\\HarddiskVolume2",
"system_locale": "en-us;English (United States)",
"input_locale": "en-us;English (United States)",
"time_zone": "(UTC+00:00) UTC",
"total_physical_memory_mb": 32503,
"available_physical_memory_mb": 19743,
"virtual_memory_max_size_mb": 37367,
"virtual_memory_available_mb": 22266,
"virtual_memory_in_use_mb": 15101,
"page_file_locations": "C:\\pagefile.sys",
"domain": "test.com",
"logon_server": "\\\\TESTDC01",
"hotfixs": [
"KB2693643",
"KB4601054"
],
"network_cards": [
{
"name": "Intel(R) Wireless-AC 9260 160MHz",
"connection_name": "Wi-Fi",
"status": null,
"dhcp_enabled": true,
"dhcp_server": "192.168.2.1",
"ip_addresses": [
"192.168.2.219"
]
}
],
"hyperv_requirements": {
"vm_monitor_mode_extensions": true,
"virtualization_enabled_in_firmware": true,
"second_level_address_translation": false,
"data_execution_prevention_available": true
},
"original_install_date_epoch": 1553640690,
"original_install_date_epoch_utc": 1553615490,
"system_boot_time_epoch": 1617110039,
"system_boot_time_epoch_utc": 1617084839
}
$ systeminfo | jc --systeminfo -p -r
{
"host_name": "TESTLAPTOP",
"os_name": "Microsoft Windows 10 Enterprise",
"os_version": "10.0.17134 N/A Build 17134",
"os_manufacturer": "Microsoft Corporation",
"os_configuration": "Member Workstation",
"os_build_type": "Multiprocessor Free",
"registered_owner": "Test, Inc.",
"registered_organization": "Test, Inc.",
"product_id": "11111-11111-11111-AA111",
"original_install_date": "3/26/2019, 3:51:30 PM",
"system_boot_time": "3/30/2021, 6:13:59 AM",
"system_manufacturer": "Dell Inc.",
"system_model": "Precision 5530",
"system_type": "x64-based PC",
"processors": [
"Intel64 Family 6 Model 158 Stepping 10 GenuineIntel ~2592 Mhz"
],
"bios_version": "Dell Inc. 1.16.2, 4/21/2020",
"windows_directory": "C:\\WINDOWS",
"system_directory": "C:\\WINDOWS\\system32",
"boot_device": "\\Device\\HarddiskVolume2",
"system_locale": "en-us;English (United States)",
"input_locale": "en-us;English (United States)",
"time_zone": "(UTC+00:00) UTC",
"total_physical_memory_mb": "32,503 MB",
"available_physical_memory_mb": "19,743 MB",
"virtual_memory_max_size_mb": "37,367 MB",
"virtual_memory_available_mb": "22,266 MB",
"virtual_memory_in_use_mb": "15,101 MB",
"page_file_locations": "C:\\pagefile.sys",
"domain": "test.com",
"logon_server": "\\\\TESTDC01",
"hotfixs": [
"KB2693643",
"KB4601054"
],
"network_cards": [
{
"name": "Intel(R) Wireless-AC 9260 160MHz",
"connection_name": "Wi-Fi",
"status": "",
"dhcp_enabled": "Yes",
"dhcp_server": "192.168.2.1",
"ip_addresses": [
"192.168.2.219"
]
}
],
"hyperv_requirements": {
"vm_monitor_mode_extensions": "Yes",
"virtualization_enabled_in_firmware": "Yes",
"second_level_address_translation": "No",
"data_execution_prevention_available": "Yes"
}
}
"""
import re
import jc.utils
class info:
"""Provides parser metadata (version, author, etc.)"""
version = "1.0"
description = "`systeminfo` command parser"
author = "Jon Smith"
author_email = "jon@rebelliondefense.com"
# details = 'enter any other details here'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ["win32"]
magic_commands = ["systeminfo"]
__version__ = info.version
def _process(proc_data):
"""
Final processing to conform to the schema.
Parameters:
proc_data: (Dictionary) raw structured data to process
Returns:
Dictionary. Some keys are optional. Example: a system without hyper-v capabilities
will not have a 'hyperv_requirements' key, and a system already running hyper-v
will have an empty "hyperv_requirements" object.
Structured data to conform to the schema.
"""
# convert empty strings to None/null
for item in proc_data:
if isinstance(proc_data[item], str) and not proc_data[item]:
proc_data[item] = None
for i, nic in enumerate(proc_data["network_cards"]):
proc_data["network_cards"][i]["dhcp_enabled"] = jc.utils.convert_to_bool(
nic["dhcp_enabled"]
)
# convert empty strings to None/null
for item in nic:
if isinstance(nic[item], str) and not nic[item]:
proc_data["network_cards"][i][item] = None
int_list = [
"total_physical_memory_mb",
"available_physical_memory_mb",
"virtual_memory_max_size_mb",
"virtual_memory_available_mb",
"virtual_memory_in_use_mb",
]
for key in int_list:
proc_data[key] = jc.utils.convert_to_int(proc_data[key])
dt_list = ["original_install_date", "system_boot_time"]
for key in dt_list:
tz = proc_data.get("time_zone", "")
if tz:
# convert
# from: (UTC-08:00) Pacific Time (US & Canada)
# to: (UTC-0800)
tz_fields = tz.split()
tz = " " + tz_fields[0].replace(":", "")
proc_data[key + '_epoch'] = jc.utils.timestamp(f"{proc_data.get(key)}{tz}").naive
proc_data[key + '_epoch_utc'] = jc.utils.timestamp(f"{proc_data.get(key)}{tz}").utc
hyperv_key = "hyperv_requirements"
hyperv_subkey_list = [
"vm_monitor_mode_extensions",
"virtualization_enabled_in_firmware",
"second_level_address_translation",
"data_execution_prevention_available",
]
if hyperv_key in proc_data:
for key in hyperv_subkey_list:
if key in proc_data[hyperv_key]:
proc_data[hyperv_key][key] = jc.utils.convert_to_bool(
proc_data[hyperv_key][key]
)
return proc_data
def parse(data, raw=False, quiet=False):
"""
Main text parsing function
Parameters:
data: (string) text data to parse
raw: (boolean) output preprocessed JSON if True
quiet: (boolean) suppress warning messages if True
Returns:
List of Dictionaries. Raw or processed structured data.
"""
if not quiet:
jc.utils.compatibility(__name__, info.compatible)
delim = ":" # k/v delimiter
raw_data = {} # intermediary output
if jc.utils.has_data(data):
# keepends = True, so that multiline data retains return chars
lines = [line for line in data.splitlines(keepends=True) if line.strip() != ""]
# find the character position of the value in the k/v pair of the first line
# all subsequent lines of data use the same character position
start_value_pos = _get_value_pos(lines[0], delim)
last_key = None
for line in lines:
key = line[0:start_value_pos]
value = line[start_value_pos:]
# possible multiline data
if last_key:
# the value data doesn't start where it should
# so this is multiline data
if delim not in key:
raw_data[last_key] += line
continue
raw_data[key] = value
last_key = key
# clean up keys; strip values
raw_output = {}
for k, v in raw_data.items():
k = _transform_key(k)
# since we split on start_value_pos, the delimiter
# is still in the key field. Remove it.
k = k.rstrip(delim)
if k in ["hotfixs", "processors"]:
raw_output[k] = _parse_hotfixs_or_processors(v)
elif k in ["network_cards"]:
raw_output[k] = _parse_network_cards(v)
elif k in ["hyperv_requirements"]:
raw_output[k] = _parse_hyperv_requirements(v)
elif k in [
"total_physical_memory",
"available_physical_memory",
"virtual_memory_max_size",
"virtual_memory_available",
"virtual_memory_in_use"
]:
raw_output[k + "_mb"] = v.strip()
else:
raw_output[k] = v.strip()
if raw:
return raw_output
else:
return _process(raw_output)
def _parse_hotfixs_or_processors(data):
"""
Turns a list of return-delimited hotfixes or processors
with [x] as a prefix into an array of hotfixes
Note that if a high number of items exist, the list may cutoff
and this list may not contain all items installed on the system
IRL, this likely applies to hotfixes more than processors
Parameters:
data: (string) Input string
"""
arr_output = []
for i, l in enumerate(data.splitlines()):
# skip line that says how many are installed
if i == 0:
continue
# we have to make sure this is a complete line
# as data could cutoff. Make sure the delimiter
# exists. Otherwise, skip it.
if ":" in l:
k, v = l.split(":")
# discard the number sequence
arr_output.append(v.strip())
return arr_output
def _parse_hyperv_requirements(data):
"""
Turns a list of key/value settings for hyperv
into an object
Parameters:
data: (string) Input string
"""
output = {}
for i, l in enumerate(data.splitlines()):
if ":" in l:
k, v = l.split(":")
# discard the number sequence
output[_transform_key(k)] = v.strip()
return output
def _parse_network_cards(data):
"""
Turns a list of network_cards into an array of objects
Parameters:
data: (string) Input string
"""
delim = ":"
arr_output = []
cur_nic = None
is_ip = False
nic_value_pos = 0
for i, line in enumerate(data.splitlines()):
# skip first line
if i == 0:
continue
if "IP address(es)" in line:
is_ip = True
continue
cur_value_pos = len(line) - len(line.lstrip())
line = line.strip()
m = re.match(r"\[(\d+)\]" + delim + "(.+)", line)
if m and is_ip and cur_value_pos > nic_value_pos:
cur_nic["ip_addresses"].append(m.group(2).strip())
elif m:
if cur_nic:
arr_output.append(cur_nic)
cur_nic = _default_nic()
cur_nic["name"] = m.group(2).strip()
nic_value_pos = cur_value_pos
is_ip = False
elif delim in line:
k, v = line.split(delim)
k = _transform_key(k)
cur_nic[k] = v.strip()
if cur_nic:
arr_output.append(cur_nic)
return arr_output
def _convert_to_boolean(value):
"""
Converts string input to boolean assuming "Yes/No" inputs
Parameters:
value: (string) Input value
"""
return value == "Yes"
def _convert_to_int(value):
"""
Converts string input to integer by stripping all non-numeric characters
Parameters:
value: (string) Input value
"""
try:
value = int(re.sub("[^0-9]", "", value))
except ValueError:
pass
return value
def _default_nic():
"""
Returns a default network card object
"""
return {
"name": "",
"connection_name": "",
"status": "",
"dhcp_enabled": "No",
"dhcp_server": "",
"ip_addresses": [],
}
def _get_value_pos(line, delim):
"""
Finds the first non-whitespace character after the delimiter
Parameters:
line: (string) Input string
delim: (string) The data delimiter
"""
fields = line.split(delim, 1)
if not len(fields) == 2:
raise Exception(f"Expected a '{delim}' delimited field. Actual: {line}")
return len(line) - len(fields[1].lstrip())
def _transform_key(key):
"""
Converts a given key to a valid json key that plays nice with jq
Parameters:
key: (string) Input value
"""
# lowercase and replace spaces with underscores
key = key.strip().lower().replace(" ", "_")
# remove invalid key characters
for c in ";:!@#$%^&*()-":
key = key.replace(c, "")
return key

View File

@ -123,7 +123,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.1'
version = '1.2'
description = '`/usr/bin/time` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -156,38 +156,30 @@ def _process(proc_data):
*hours, minutes, seconds, centiseconds = proc_data['elapsed_time'].split(':')
proc_data['elapsed_time'] = proc_data['elapsed_time'][::-1].replace(':', '.', 1)[::-1]
if hours:
proc_data['elapsed_time_hours'] = int(hours[0])
proc_data['elapsed_time_hours'] = jc.utils.convert_to_int(hours[0])
else:
proc_data['elapsed_time_hours'] = 0
proc_data['elapsed_time_minutes'] = int(minutes)
proc_data['elapsed_time_seconds'] = int(seconds)
proc_data['elapsed_time_centiseconds'] = int(centiseconds)
proc_data['elapsed_time_minutes'] = jc.utils.convert_to_int(minutes)
proc_data['elapsed_time_seconds'] = jc.utils.convert_to_int(seconds)
proc_data['elapsed_time_centiseconds'] = jc.utils.convert_to_int(centiseconds)
proc_data['elapsed_time_total_seconds'] = (proc_data['elapsed_time_hours'] * 3600) + \
(proc_data['elapsed_time_minutes'] * 60) + \
(proc_data['elapsed_time_seconds']) + \
(proc_data['elapsed_time_centiseconds'] / 100)
int_list = ['elapsed_time_hours', 'elapsed_time_minutes', 'elapsed_time_seconds', 'elapsed_time_microseconds',
'cpu_percent', 'average_shared_text_size', 'average_unshared_data_size', 'average_unshared_stack_size',
# convert ints and floats
int_list = ['cpu_percent', 'average_shared_text_size', 'average_unshared_data_size', 'average_unshared_stack_size',
'average_shared_memory_size', 'maximum_resident_set_size', 'block_input_operations',
'block_output_operations', 'major_pagefaults', 'minor_pagefaults', 'swaps', 'page_reclaims',
'page_faults', 'messages_sent', 'messages_received', 'signals_received', 'voluntary_context_switches',
'involuntary_context_switches', 'average_stack_size', 'average_total_size', 'average_resident_set_size',
'signals_delivered', 'page_size', 'exit_status']
for key in int_list:
if key in proc_data:
try:
proc_data[key] = int(proc_data[key])
except (ValueError, TypeError):
proc_data[key] = None
float_list = ['real_time', 'user_time', 'system_time']
for key in float_list:
if key in proc_data:
try:
proc_data[key] = float(proc_data[key])
except (ValueError):
proc_data[key] = None
for key in proc_data:
if key in int_list:
proc_data[key] = jc.utils.convert_to_int(proc_data[key])
if key in float_list:
proc_data[key] = jc.utils.convert_to_float(proc_data[key])
return proc_data

View File

@ -63,7 +63,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.3'
version = '1.4'
description = '`timedatectl status` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -89,15 +89,11 @@ def _process(proc_data):
Dictionary. Structured data to conform to the schema.
"""
# boolean changes
bool_list = ['ntp_enabled', 'ntp_synchronized', 'rtc_in_local_tz', 'dst_active',
'system_clock_synchronized', 'systemd-timesyncd.service_active']
for key in proc_data:
if key in bool_list:
try:
proc_data[key] = True if proc_data[key] == 'yes' else False
except (ValueError):
proc_data[key] = None
proc_data[key] = jc.utils.convert_to_bool(proc_data[key])
if 'universal_time' in proc_data:
ts = jc.utils.timestamp(proc_data['universal_time'])

View File

@ -132,7 +132,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.1'
version = '1.2'
description = '`tracepath` and `tracepath6` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -157,39 +157,23 @@ def _process(proc_data):
Dictionary. Structured data to conform to the schema.
"""
# convert ints and floats
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:
for key in proc_data:
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:
proc_data[key] = jc.utils.convert_to_int(proc_data[key])
if key in float_list:
try:
proc_data[key] = float(proc_data[key])
except (ValueError, TypeError):
proc_data[key] = None
proc_data[key] = jc.utils.convert_to_float(proc_data[key])
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 entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
for key in float_list:
if key in entry:
try:
entry[key] = float(entry[key])
except (ValueError, TypeError):
entry[key] = None
if key in float_list:
entry[key] = jc.utils.convert_to_float(entry[key])
return proc_data

View File

@ -119,7 +119,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.2'
version = '1.3'
description = '`traceroute` and `traceroute6` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -335,35 +335,21 @@ def _process(proc_data):
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 entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
for key in float_list:
if key in entry:
try:
entry[key] = float(entry[key])
except (ValueError, TypeError):
entry[key] = None
if key in float_list:
entry[key] = jc.utils.convert_to_float(entry[key])
if 'probes' in entry:
for item in entry['probes']:
for key in int_list:
if key in item:
try:
item[key] = int(item[key])
except (ValueError, TypeError):
item[key] = None
for key in item:
if key in int_list:
item[key] = jc.utils.convert_to_int(item[key])
for key in float_list:
if key in item:
try:
item[key] = float(item[key])
except (ValueError, TypeError):
item[key] = None
if key in float_list:
item[key] = jc.utils.convert_to_float(item[key])
return proc_data

View File

@ -194,7 +194,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.1'
version = '1.2'
description = '`upower` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -225,7 +225,7 @@ def _process(proc_data):
if 'updated' in entry:
updated_list = entry['updated'].replace('(', '').replace(')', '').split()
entry['updated'] = ' '.join(updated_list[:-3])
entry['updated_seconds_ago'] = int(updated_list[-3])
entry['updated_seconds_ago'] = jc.utils.convert_to_int(updated_list[-3])
if entry['updated']:
ts = jc.utils.timestamp(entry['updated'])
@ -236,20 +236,14 @@ def _process(proc_data):
bool_list = ['power_supply', 'has_history', 'has_statistics', 'on_battery', 'lid_is_closed', 'lid_is_present']
for key in entry:
if key in bool_list:
if entry[key].lower() == 'yes':
entry[key] = True
else:
entry[key] = False
entry[key] = jc.utils.convert_to_bool(entry[key])
# detail level boolean conversions
bool_list = ['online', 'present', 'rechargeable']
if 'detail' in entry:
for key in entry['detail']:
if key in bool_list:
if entry['detail'][key].lower() == 'yes':
entry['detail'][key] = True
else:
entry['detail'][key] = False
entry['detail'][key] = jc.utils.convert_to_bool(entry['detail'][key])
# detail level convert warning to null if value is none
if 'detail' in entry:
@ -262,8 +256,8 @@ def _process(proc_data):
add_items = []
for key, value in entry['detail'].items():
if value and isinstance(value, str):
if len(value.split()) == 2 and value.split()[0].replace('.', '').isnumeric():
entry['detail'][key] = float(value.split()[0])
if len(value.split()) == 2:
entry['detail'][key] = jc.utils.convert_to_float(value.split()[0])
add_items.append({
key + '_unit': value.split()[1]
})
@ -278,7 +272,7 @@ def _process(proc_data):
for key, value in entry['detail'].items():
if value and isinstance(value, str):
if value[-1] == '%':
entry['detail'][key] = float(value[:-1])
entry['detail'][key] = jc.utils.convert_to_float(value)
# detail level fix quoted values
if 'detail' in entry:
@ -302,9 +296,9 @@ def _process(proc_data):
new_history_obj = {}
for key, value in history_obj.items():
if key == 'time':
new_history_obj[key] = int(value)
new_history_obj[key] = jc.utils.convert_to_int(value)
elif key == 'percent_charged':
new_history_obj[key] = float(value)
new_history_obj[key] = jc.utils.convert_to_float(value)
else:
new_history_obj[key] = value

View File

@ -65,7 +65,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.4'
version = '1.5'
description = '`uptime` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -92,10 +92,10 @@ def _process(proc_data):
"""
if 'time' in proc_data:
time_list = proc_data['time'].split(':')
proc_data['time_hour'] = int(time_list[0])
proc_data['time_minute'] = int(time_list[1])
proc_data['time_hour'] = jc.utils.convert_to_int(time_list[0])
proc_data['time_minute'] = jc.utils.convert_to_int(time_list[1])
if len(time_list) == 3:
proc_data['time_second'] = int(time_list[2])
proc_data['time_second'] = jc.utils.convert_to_int(time_list[2])
else:
proc_data['time_second'] = None
@ -113,14 +113,14 @@ def _process(proc_data):
uptime_total_seconds = 0
if 'min' in proc_data['uptime']:
uptime_minutes = int(proc_data['uptime'].split()[-2])
uptime_minutes = jc.utils.convert_to_int(proc_data['uptime'].split()[-2])
if ':' in proc_data['uptime']:
uptime_hours = int(proc_data['uptime'].split()[-1].split(':')[-2])
uptime_minutes = int(proc_data['uptime'].split(':')[-1])
uptime_hours = jc.utils.convert_to_int(proc_data['uptime'].split()[-1].split(':')[-2])
uptime_minutes = jc.utils.convert_to_int(proc_data['uptime'].split(':')[-1])
if 'day' in proc_data['uptime']:
uptime_days = int(proc_data['uptime'].split()[0])
uptime_days = jc.utils.convert_to_int(proc_data['uptime'].split()[0])
proc_data['uptime_days'] = uptime_days
proc_data['uptime_hours'] = uptime_hours
@ -129,25 +129,14 @@ def _process(proc_data):
uptime_total_seconds = (uptime_days * 86400) + (uptime_hours * 3600) + (uptime_minutes * 60)
proc_data['uptime_total_seconds'] = uptime_total_seconds
# integer conversions
# integer and float conversions
int_list = ['users']
for key in int_list:
if key in proc_data:
try:
key_int = int(proc_data[key])
proc_data[key] = key_int
except (ValueError):
proc_data[key] = None
# float conversions
float_list = ['load_1m', 'load_5m', 'load_15m']
for key in float_list:
if key in proc_data:
try:
key_float = float(proc_data[key])
proc_data[key] = key_float
except (ValueError):
proc_data[key] = None
for key in proc_data:
if key in int_list:
proc_data[key] = jc.utils.convert_to_int(proc_data[key])
if key in float_list:
proc_data[key] = jc.utils.convert_to_float(proc_data[key])
return proc_data

View File

@ -131,8 +131,8 @@ def _process(proc_data):
"""
for entry in proc_data:
null_list = ['user', 'tty', 'from', 'login_at', 'idle', 'what']
for key in null_list:
if key in entry:
for key in entry:
if key in null_list:
if entry[key] == '-':
entry[key] = None

View File

@ -54,7 +54,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.1'
version = '1.2'
description = '`wc` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -82,12 +82,10 @@ def _process(proc_data):
for entry in proc_data:
int_list = ['lines', 'words', 'characters']
for key in int_list:
if key in entry:
try:
entry[key] = int(entry[key])
except (ValueError):
entry[key] = None
for key in entry:
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
return proc_data

Some files were not shown because too many files have changed in this diff Show More