1
0
mirror of https://github.com/kellyjonbrazil/jc.git synced 2025-07-15 01:24:29 +02:00

Merge pull request #19 from kellyjonbrazil/dev-1.7.1

Dev v1.7.1
This commit is contained in:
Kelly Brazil
2020-02-05 16:59:52 -08:00
committed by GitHub
81 changed files with 2812 additions and 144 deletions

266
README.md
View File

@ -1,7 +1,7 @@
# JC
JSON CLI output utility
`jc` is used to JSONify the output of many standard linux cli tools for easier parsing in scripts. See the **Parsers** section for supported commands.
`jc` is used to JSONify the output of many standard linux cli tools and file types for easier parsing in scripts. See the **Parsers** section for supported commands.
This allows further command line processing of output with tools like `jq` simply by piping commands:
@ -66,6 +66,7 @@ jc PARSER [OPTIONS]
### Parsers
- `--arp` enables the `arp` parser
- `--crontab` enables the `crontab` file parser
- `--crontab-u` enables the `crontab` file parser with user support
- `--df` enables the `df` parser
- `--dig` enables the `dig` parser
- `--du` enables the `du` parser
@ -74,7 +75,9 @@ jc PARSER [OPTIONS]
- `--fstab` enables the `/etc/fstab` file parser
- `--history` enables the `history` parser
- `--hosts` enables the `/etc/hosts` file parser
- `--id` enables the `id` parser
- `--ifconfig` enables the `ifconfig` parser
- `--ini` enables the `INI` file parser
- `--iptables` enables the `iptables` parser
- `--jobs` enables the `jobs` parser
- `--ls` enables the `ls` parser
@ -96,6 +99,8 @@ jc PARSER [OPTIONS]
- `--uname` enables the `uname -a` parser
- `--uptime` enables the `uptime` parser
- `--w` enables the `w` parser
- `--xml` enables the `XML` file parser
- `--yaml` enables the `YAML` file parser
### Options
- `-a` about `jc`. Prints information about `jc` and the parsers (in JSON, of course!)
@ -229,6 +234,82 @@ $ cat /etc/crontab | jc --crontab -p
]
}
```
### crontab-u (with user support)
```
$ cat /etc/crontab | jc --crontab-u -p
{
"variables": [
{
"name": "MAILTO",
"value": "root"
},
{
"name": "PATH",
"value": "/sbin:/bin:/usr/sbin:/usr/bin"
},
{
"name": "SHELL",
"value": "/bin/bash"
}
],
"schedule": [
{
"minute": [
"5"
],
"hour": [
"10-11",
"22"
],
"day_of_month": [
"*"
],
"month": [
"*"
],
"day_of_week": [
"*"
],
"user": "root",
"command": "/var/www/devdaily.com/bin/mk-new-links.php"
},
{
"minute": [
"30"
],
"hour": [
"4/2"
],
"day_of_month": [
"*"
],
"month": [
"*"
],
"day_of_week": [
"*"
],
"user": "root",
"command": "/var/www/devdaily.com/bin/create-all-backups.sh"
},
{
"occurrence": "yearly",
"user": "root",
"command": "/home/maverick/bin/annual-maintenance"
},
{
"occurrence": "reboot",
"user": "root",
"command": "/home/cleanup"
},
{
"occurrence": "monthly",
"user": "root",
"command": "/home/maverick/bin/tape-backup"
}
]
}
```
### df
```
$ df | jc --df -p
@ -489,7 +570,7 @@ $ free | jc --free -p
}
]
```
### /etc/fstab
### /etc/fstab file
```
$ cat /etc/fstab | jc --fstab -p
[
@ -524,25 +605,25 @@ $ cat /etc/fstab | jc --fstab -p
$ history | jc --history -p
[
{
"line": "118",
"line": 118,
"command": "sleep 100"
},
{
"line": "119",
"line": 119,
"command": "ls /bin"
},
{
"line": "120",
"line": 120,
"command": "echo \"hello\""
},
{
"line": "121",
"line": 121,
"command": "docker images"
},
...
]
```
### /etc/hosts
### /etc/hosts file
```
$ cat /etc/hosts | jc --hosts -p
[
@ -591,6 +672,36 @@ $ cat /etc/hosts | jc --hosts -p
}
]
```
### id
```
$ id | jc --id -p
{
"uid": {
"id": 1000,
"name": "joeuser"
},
"gid": {
"id": 1000,
"name": "joeuser"
},
"groups": [
{
"id": 1000,
"name": "joeuser"
},
{
"id": 10,
"name": "wheel"
}
],
"context": {
"user": "unconfined_u",
"role": "unconfined_r",
"type": "unconfined_t",
"level": "s0-s0:c0.c1023"
}
}
```
### ifconfig
```
$ ifconfig | jc --ifconfig -p
@ -662,6 +773,40 @@ $ ifconfig | jc --ifconfig -p
}
]
```
### INI files
```
$ cat example.ini
[DEFAULT]
ServerAliveInterval = 45
Compression = yes
CompressionLevel = 9
ForwardX11 = yes
[bitbucket.org]
User = hg
[topsecret.server.com]
Port = 50022
ForwardX11 = no
$ cat example.ini | jc --ini -p
{
"bitbucket.org": {
"serveraliveinterval": "45",
"compression": "yes",
"compressionlevel": "9",
"forwardx11": "yes",
"user": "hg"
},
"topsecret.server.com": {
"serveraliveinterval": "45",
"compression": "yes",
"compressionlevel": "9",
"forwardx11": "no",
"port": "50022"
}
}
```
### iptables
```
$ sudo iptables --line-numbers -v -L -t nat | jc --iptables -p
@ -1599,6 +1744,110 @@ $ w | jc --w -p
}
]
```
### XML files
```
$ cat cd_catalog.xml
<?xml version="1.0" encoding="UTF-8"?>
<CATALOG>
<CD>
<TITLE>Empire Burlesque</TITLE>
<ARTIST>Bob Dylan</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>Columbia</COMPANY>
<PRICE>10.90</PRICE>
<YEAR>1985</YEAR>
</CD>
<CD>
<TITLE>Hide your heart</TITLE>
<ARTIST>Bonnie Tyler</ARTIST>
<COUNTRY>UK</COUNTRY>
<COMPANY>CBS Records</COMPANY>
<PRICE>9.90</PRICE>
<YEAR>1988</YEAR>
</CD>
...
$ cat cd_catalog.xml | jc --xml -p
{
"CATALOG": {
"CD": [
{
"TITLE": "Empire Burlesque",
"ARTIST": "Bob Dylan",
"COUNTRY": "USA",
"COMPANY": "Columbia",
"PRICE": "10.90",
"YEAR": "1985"
},
{
"TITLE": "Hide your heart",
"ARTIST": "Bonnie Tyler",
"COUNTRY": "UK",
"COMPANY": "CBS Records",
"PRICE": "9.90",
"YEAR": "1988"
},
...
}
```
### YAML files
```
$ cat istio-mtls-permissive.yaml
apiVersion: "authentication.istio.io/v1alpha1"
kind: "Policy"
metadata:
name: "default"
namespace: "default"
spec:
peers:
- mtls: {}
---
apiVersion: "networking.istio.io/v1alpha3"
kind: "DestinationRule"
metadata:
name: "default"
namespace: "default"
spec:
host: "*.default.svc.cluster.local"
trafficPolicy:
tls:
mode: ISTIO_MUTUAL
$ cat istio-mtls-permissive.yaml | jc --yaml -p
[
{
"apiVersion": "authentication.istio.io/v1alpha1",
"kind": "Policy",
"metadata": {
"name": "default",
"namespace": "default"
},
"spec": {
"peers": [
{
"mtls": {}
}
]
}
},
{
"apiVersion": "networking.istio.io/v1alpha3",
"kind": "DestinationRule",
"metadata": {
"name": "default",
"namespace": "default"
},
"spec": {
"host": "*.default.svc.cluster.local",
"trafficPolicy": {
"tls": {
"mode": "ISTIO_MUTUAL"
}
}
}
}
]
```
## TODO
Future parsers:
- /proc files
@ -1625,4 +1874,7 @@ Tested on:
## Acknowledgments
- `ifconfig-parser` module from https://github.com/KnightWhoSayNi/ifconfig-parser
- `xmltodict` module from https://github.com/martinblech/xmltodict by Martín Blech
- `ruamel.yaml` library from https://pypi.org/project/ruamel.yaml by Anthon van der Neut
- Parsing code from Conor Heine at https://gist.github.com/cahna/43a1a3ff4d075bcd71f9d7120037a501 adapted for some parsers
- Excellent constructive feedback from Ilya Sher (https://github.com/ilyash-b)

View File

@ -1,5 +1,18 @@
jc changelog
20200205 v1.7.1
- Add YAML file parser
- Add INI file parser
- Add XML file parser
- Add id parser (tested on linux and OSX)
- Add crontab file parser with user support (tested on linux)
- Add __version__ variable to parser modules
- Add exit code on error
- Updated history parser to output "line" as an integer
- Updated compatibility list for some parsers
- Bugfix in crontab file parser: header insertion was clobbering first row
- Just-in-time loading of parser modules instead of loading all at start
20191217 v1.6.1
- Add du parser (tested on linux and OSX)
- Add crontab parser (tested on linux and OSX)

View File

@ -6,6 +6,7 @@ pydocmd simple jc+ > ../docs/readme.md
pydocmd simple utils+ > ../docs/utils.md
pydocmd simple jc.parsers.arp+ > ../docs/parsers/arp.md
pydocmd simple jc.parsers.crontab+ > ../docs/parsers/crontab.md
pydocmd simple jc.parsers.crontab_u+ > ../docs/parsers/crontab_u.md
pydocmd simple jc.parsers.df+ > ../docs/parsers/df.md
pydocmd simple jc.parsers.dig+ > ../docs/parsers/dig.md
pydocmd simple jc.parsers.du+ > ../docs/parsers/du.md
@ -14,7 +15,9 @@ pydocmd simple jc.parsers.free+ > ../docs/parsers/free.md
pydocmd simple jc.parsers.fstab+ > ../docs/parsers/fstab.md
pydocmd simple jc.parsers.history+ > ../docs/parsers/history.md
pydocmd simple jc.parsers.hosts+ > ../docs/parsers/hosts.md
pydocmd simple jc.parsers.id+ > ../docs/parsers/id.md
pydocmd simple jc.parsers.ifconfig+ > ../docs/parsers/ifconfig.md
pydocmd simple jc.parsers.ini+ > ../docs/parsers/ini.md
pydocmd simple jc.parsers.iptables+ > ../docs/parsers/iptables.md
pydocmd simple jc.parsers.jobs+ > ../docs/parsers/jobs.md
pydocmd simple jc.parsers.ls+ > ../docs/parsers/ls.md
@ -36,3 +39,5 @@ pydocmd simple jc.parsers.systemctl_luf+ > ../docs/parsers/systemctl_luf.md
pydocmd simple jc.parsers.uname+ > ../docs/parsers/uname.md
pydocmd simple jc.parsers.uptime+ > ../docs/parsers/uptime.md
pydocmd simple jc.parsers.w+ > ../docs/parsers/w.md
pydocmd simple jc.parsers.xml+ > ../docs/parsers/xml.md
pydocmd simple jc.parsers.yaml+ > ../docs/parsers/yaml.md

View File

@ -150,8 +150,8 @@ Returns:
{
"variables": [
"name": string,
"value": string
"name": string,
"value": string
],
"schedule": [
{

199
docs/parsers/crontab_u.md Normal file
View File

@ -0,0 +1,199 @@
# jc.parsers.crontab_u
jc - JSON CLI output utility crontab file Parser
Usage:
specify --crontab-u as the first argument if the piped input is coming from a crontab file with User specified
Compatibility:
'linux', 'darwin', 'aix', 'freebsd'
Examples:
$ cat /etc/crontab | jc --crontab -p
{
"variables": [
{
"name": "PATH",
"value": "/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin"
},
{
"name": "SHELL",
"value": "/bin/sh"
}
],
"schedule": [
{
"minute": [
"25"
],
"hour": [
"6"
],
"day_of_month": [
"*"
],
"month": [
"*"
],
"day_of_week": [
"*"
],
"user": "root",
"command": "test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )"
},
{
"minute": [
"47"
],
"hour": [
"6"
],
"day_of_month": [
"*"
],
"month": [
"*"
],
"day_of_week": [
"7"
],
"user": "root",
"command": "test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )"
},
{
"minute": [
"52"
],
"hour": [
"6"
],
"day_of_month": [
"1"
],
"month": [
"*"
],
"day_of_week": [
"*"
],
"user": "root",
"command": "test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )"
}
]
}
$ cat /etc/crontab | jc --crontab-u -p -r
{
"variables": [
{
"name": "PATH",
"value": "/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin"
},
{
"name": "SHELL",
"value": "/bin/sh"
}
],
"schedule": [
{
"minute": "25",
"hour": "6",
"day_of_month": "*",
"month": "*",
"day_of_week": "*",
"user": "root",
"command": "test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )"
},
{
"minute": "47",
"hour": "6",
"day_of_month": "*",
"month": "*",
"day_of_week": "7",
"user": "root",
"command": "test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )"
},
{
"minute": "52",
"hour": "6",
"day_of_month": "1",
"month": "*",
"day_of_week": "*",
"user": "root",
"command": "test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )"
}
]
}
## info
```python
info(self, /, *args, **kwargs)
```
## process
```python
process(proc_data)
```
Final processing to conform to the schema.
Parameters:
proc_data: (dictionary) raw structured data to process
Returns:
Dictionary. Structured data with the following schema:
{
"variables": [
"name": string,
"value": string
],
"schedule": [
{
"occurrence" string,
"minute": [
string
],
"hour": [
string
],
"day_of_month": [
string
],
"month": [
string
],
"day_of_week": [
string
],
"occurrence": string,
"user": string,
"command": string
}
]
}
## 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:
Dictionary. Raw or processed structured data.

View File

@ -7,7 +7,7 @@ Usage:
Compatibility:
'linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'
'linux', 'darwin', 'aix', 'freebsd'
Examples:

View File

@ -7,26 +7,26 @@ Usage:
Compatibility:
'linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'
'linux', 'darwin', 'cygwin', 'aix', 'freebsd'
Examples:
$ history | jc --history -p
[
{
"line": "118",
"line": 118,
"command": "sleep 100"
},
{
"line": "119",
"line": 119,
"command": "ls /bin"
},
{
"line": "120",
"line": 120,
"command": "echo "hello""
},
{
"line": "121",
"line": 121,
"command": "docker images"
},
...
@ -63,7 +63,7 @@ Returns:
[
{
"line": string,
"line": integer,
"command": string
}
]

133
docs/parsers/id.md Normal file
View File

@ -0,0 +1,133 @@
# jc.parsers.id
jc - JSON CLI output utility id Parser
Usage:
specify --id as the first argument if the piped input is coming from id
Compatibility:
'linux', 'darwin', 'aix', 'freebsd'
Examples:
$ id | jc --id -p
{
"uid": {
"id": 1000,
"name": "joeuser"
},
"gid": {
"id": 1000,
"name": "joeuser"
},
"groups": [
{
"id": 1000,
"name": "joeuser"
},
{
"id": 10,
"name": "wheel"
}
],
"context": {
"user": "unconfined_u",
"role": "unconfined_r",
"type": "unconfined_t",
"level": "s0-s0:c0.c1023"
}
}
$ id | jc --id -p -r
{
"uid": {
"id": "1000",
"name": "joeuser"
},
"gid": {
"id": "1000",
"name": "joeuser"
},
"groups": [
{
"id": "1000",
"name": "joeuser"
},
{
"id": "10",
"name": "wheel"
}
],
"context": {
"user": "unconfined_u",
"role": "unconfined_r",
"type": "unconfined_t",
"level": "s0-s0:c0.c1023"
}
}
## info
```python
info(self, /, *args, **kwargs)
```
## process
```python
process(proc_data)
```
Final processing to conform to the schema.
Parameters:
proc_data: (dictionary) raw structured data to process
Returns:
Dictionary. Structured data with the following schema:
{
"uid": {
"id": integer,
"name": string
},
"gid": {
"id": integer,
"name": string
},
"groups": [
{
"id": integer,
"name": string
},
{
"id": integer,
"name": string
}
],
"context": {
"user": string,
"role": string,
"type": string,
"level": string
}
}
## 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.

87
docs/parsers/ini.md Normal file
View File

@ -0,0 +1,87 @@
# jc.parsers.ini
jc - JSON CLI output utility INI Parser
Usage:
specify --ini as the first argument if the piped input is coming from an INI file
Compatibility:
'linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'
Examples:
$ cat example.ini
[DEFAULT]
ServerAliveInterval = 45
Compression = yes
CompressionLevel = 9
ForwardX11 = yes
[bitbucket.org]
User = hg
[topsecret.server.com]
Port = 50022
ForwardX11 = no
$ cat example.ini | jc --ini -p
{
"bitbucket.org": {
"serveraliveinterval": "45",
"compression": "yes",
"compressionlevel": "9",
"forwardx11": "yes",
"user": "hg"
},
"topsecret.server.com": {
"serveraliveinterval": "45",
"compression": "yes",
"compressionlevel": "9",
"forwardx11": "no",
"port": "50022"
}
}
## info
```python
info(self, /, *args, **kwargs)
```
## process
```python
process(proc_data)
```
Final processing to conform to the schema.
Parameters:
proc_data: (dictionary) raw structured data to process
Returns:
Dictionary representing an ini document:
{
ini document converted to a dictionary
see configparser standard library documentation for more details
}
## 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:
Dictionary representing the ini file

99
docs/parsers/xml.md Normal file
View File

@ -0,0 +1,99 @@
# jc.parsers.xml
jc - JSON CLI output utility XML Parser
Usage:
specify --xml as the first argument if the piped input is coming from an XML file
Compatibility:
'linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'
Examples:
$ cat cd_catalog.xml
<?xml version="1.0" encoding="UTF-8"?>
<CATALOG>
<CD>
<TITLE>Empire Burlesque</TITLE>
<ARTIST>Bob Dylan</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>Columbia</COMPANY>
<PRICE>10.90</PRICE>
<YEAR>1985</YEAR>
</CD>
<CD>
<TITLE>Hide your heart</TITLE>
<ARTIST>Bonnie Tyler</ARTIST>
<COUNTRY>UK</COUNTRY>
<COMPANY>CBS Records</COMPANY>
<PRICE>9.90</PRICE>
<YEAR>1988</YEAR>
</CD>
...
$ cat cd_catalog.xml | jc --xml -p
{
"CATALOG": {
"CD": [
{
"TITLE": "Empire Burlesque",
"ARTIST": "Bob Dylan",
"COUNTRY": "USA",
"COMPANY": "Columbia",
"PRICE": "10.90",
"YEAR": "1985"
},
{
"TITLE": "Hide your heart",
"ARTIST": "Bonnie Tyler",
"COUNTRY": "UK",
"COMPANY": "CBS Records",
"PRICE": "9.90",
"YEAR": "1988"
},
...
}
## info
```python
info(self, /, *args, **kwargs)
```
## process
```python
process(proc_data)
```
Final processing to conform to the schema.
Parameters:
proc_data: (dictionary) raw structured data to process
Returns:
Dictionary representing an XML document:
{
XML Document converted to a Dictionary
See https://github.com/martinblech/xmltodict for details
}
## 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:
Dictionary. Raw or processed structured data.

113
docs/parsers/yaml.md Normal file
View File

@ -0,0 +1,113 @@
# jc.parsers.yaml
jc - JSON CLI output utility YAML Parser
Usage:
specify --yaml as the first argument if the piped input is coming from a YAML file
Compatibility:
'linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'
Examples:
$ cat istio-mtls-permissive.yaml
apiVersion: "authentication.istio.io/v1alpha1"
kind: "Policy"
metadata:
name: "default"
namespace: "default"
spec:
peers:
- mtls: {}
---
apiVersion: "networking.istio.io/v1alpha3"
kind: "DestinationRule"
metadata:
name: "default"
namespace: "default"
spec:
host: "*.default.svc.cluster.local"
trafficPolicy:
tls:
mode: ISTIO_MUTUAL
$ cat istio-mtls-permissive.yaml | jc --yaml -p
[
{
"apiVersion": "authentication.istio.io/v1alpha1",
"kind": "Policy",
"metadata": {
"name": "default",
"namespace": "default"
},
"spec": {
"peers": [
{
"mtls": {}
}
]
}
},
{
"apiVersion": "networking.istio.io/v1alpha3",
"kind": "DestinationRule",
"metadata": {
"name": "default",
"namespace": "default"
},
"spec": {
"host": "*.default.svc.cluster.local",
"trafficPolicy": {
"tls": {
"mode": "ISTIO_MUTUAL"
}
}
}
}
]
## info
```python
info(self, /, *args, **kwargs)
```
## process
```python
process(proc_data)
```
Final processing to conform to the schema.
Parameters:
proc_data: (dictionary) raw structured data to process
Returns:
List of dictionaries. Each dictionary represents a YAML document:
[
{
YAML Document converted to a Dictionary
See https://pypi.org/project/ruamel.yaml for details
}
]
## 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.

199
jc/cli.py
View File

@ -3,113 +3,121 @@
JC cli module
"""
import sys
import importlib
import textwrap
import signal
import json
import jc.utils
import jc.parsers.arp
import jc.parsers.crontab
import jc.parsers.df
import jc.parsers.dig
import jc.parsers.du
import jc.parsers.env
import jc.parsers.free
import jc.parsers.fstab
import jc.parsers.history
import jc.parsers.hosts
import jc.parsers.ifconfig
import jc.parsers.iptables
import jc.parsers.jobs
import jc.parsers.ls
import jc.parsers.lsblk
import jc.parsers.lsmod
import jc.parsers.lsof
import jc.parsers.mount
import jc.parsers.netstat
import jc.parsers.pip_list
import jc.parsers.pip_show
import jc.parsers.ps
import jc.parsers.route
import jc.parsers.ss
import jc.parsers.stat
import jc.parsers.systemctl
import jc.parsers.systemctl_lj
import jc.parsers.systemctl_ls
import jc.parsers.systemctl_luf
import jc.parsers.uname
import jc.parsers.uptime
import jc.parsers.w
parser_map = {
'--arp': jc.parsers.arp,
'--crontab': jc.parsers.crontab,
'--df': jc.parsers.df,
'--dig': jc.parsers.dig,
'--du': jc.parsers.du,
'--env': jc.parsers.env,
'--free': jc.parsers.free,
'--fstab': jc.parsers.fstab,
'--history': jc.parsers.history,
'--hosts': jc.parsers.hosts,
'--ifconfig': jc.parsers.ifconfig,
'--iptables': jc.parsers.iptables,
'--jobs': jc.parsers.jobs,
'--ls': jc.parsers.ls,
'--lsblk': jc.parsers.lsblk,
'--lsmod': jc.parsers.lsmod,
'--lsof': jc.parsers.lsof,
'--mount': jc.parsers.mount,
'--netstat': jc.parsers.netstat,
'--pip-list': jc.parsers.pip_list,
'--pip-show': jc.parsers.pip_show,
'--ps': jc.parsers.ps,
'--route': jc.parsers.route,
'--ss': jc.parsers.ss,
'--stat': jc.parsers.stat,
'--systemctl': jc.parsers.systemctl,
'--systemctl-lj': jc.parsers.systemctl_lj,
'--systemctl-ls': jc.parsers.systemctl_ls,
'--systemctl-luf': jc.parsers.systemctl_luf,
'--uname': jc.parsers.uname,
'--uptime': jc.parsers.uptime,
'--w': jc.parsers.w
}
parsers = [
'arp',
'crontab',
'crontab-u',
'df',
'dig',
'du',
'env',
'free',
'fstab',
'history',
'hosts',
'id',
'ifconfig',
'ini',
'iptables',
'jobs',
'ls',
'lsblk',
'lsmod',
'lsof',
'mount',
'netstat',
'pip-list',
'pip-show',
'ps',
'route',
'ss',
'stat',
'systemctl',
'systemctl-lj',
'systemctl-ls',
'systemctl-luf',
'uname',
'uptime',
'w',
'xml',
'yaml'
]
def parser_shortname(parser_argument):
"""short name of the parser with dashes and no -- prefix"""
return parser_argument[2:]
def parser_argument(parser):
"""short name of the parser with dashes and with -- prefix"""
return f'--{parser}'
def parser_mod_shortname(parser):
"""short name of the parser's module name (no -- prefix and dashes converted to underscores)"""
return parser.replace('--', '').replace('-', '_')
def parser_module(parser):
"""import the module just in time and present the module object"""
importlib.import_module('jc.parsers.' + parser_mod_shortname(parser))
return getattr(jc.parsers, parser_mod_shortname(parser))
class info():
version = '1.6.1'
version = '1.7.1'
description = 'jc cli output JSON conversion tool'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
__version__ = info.version
def ctrlc(signum, frame):
exit()
sys.exit(1)
def parsers_text():
def parsers_text(indent=0, pad=0):
ptext = ''
for parser in parser_map:
if hasattr(parser_map[parser], 'info'):
padding = 16 - len(parser)
for parser in parsers:
parser_arg = parser_argument(parser)
parser_mod = parser_module(parser)
if hasattr(parser_mod, 'info'):
parser_desc = parser_mod.info.description
padding = pad - len(parser_arg)
padding_char = ' '
indent_text = padding_char * indent
padding_text = padding_char * padding
ptext += ' ' + parser + padding_text + parser_map[parser].info.description + '\n'
ptext += indent_text + parser_arg + padding_text + parser_desc + '\n'
return ptext
def about_jc():
parser_list = []
for parser in parser_map:
if hasattr(parser_map[parser], 'info'):
for parser in parsers:
parser_mod = parser_module(parser)
if hasattr(parser_mod, 'info'):
info_dict = {}
info_dict['name'] = parser_map[parser].__name__.split('.')[-1]
info_dict['argument'] = parser
parser_entry = vars(parser_map[parser].info)
info_dict['name'] = parser_mod.__name__.split('.')[-1]
info_dict['argument'] = parser_argument(parser)
parser_entry = vars(parser_mod.info)
for k, v in parser_entry.items():
if not k.startswith('__'):
info_dict[k] = v
parser_list.append(info_dict)
return {
@ -124,7 +132,7 @@ def about_jc():
def helptext(message):
parsers_string = parsers_text()
parsers_string = parsers_text(indent=12, pad=17)
helptext_string = f'''
jc: {message}
@ -134,11 +142,11 @@ def helptext(message):
Parsers:
{parsers_string}
Options:
-a about jc
-d debug - show trace messages
-p pretty print output
-q quiet - suppress warnings
-r raw JSON output
-a about jc
-d debug - show trace messages
-p pretty print output
-q quiet - suppress warnings
-r raw JSON output
Example:
ls -al | jc --ls -p
@ -180,7 +188,7 @@ def main():
if sys.stdin.isatty():
helptext('missing piped data')
exit()
sys.exit(1)
data = sys.stdin.read()
@ -188,25 +196,32 @@ def main():
if debug:
for arg in sys.argv:
if arg in parser_map:
result = parser_map[arg].parse(data, raw=raw, quiet=quiet)
parser_name = parser_shortname(arg)
if parser_name in parsers:
# load parser module just in time so we don't need to load all modules
parser = parser_module(arg)
result = parser.parse(data, raw=raw, quiet=quiet)
found = True
break
else:
for arg in sys.argv:
if arg in parser_map:
parser_name = parser_shortname(arg)
if parser_name in parsers:
# load parser module just in time so we don't need to load all modules
parser = parser_module(arg)
try:
result = parser_map[arg].parse(data, raw=raw, quiet=quiet)
result = parser.parse(data, raw=raw, quiet=quiet)
found = True
break
except:
parser_name = parser_map[arg].__name__.split('.')[-1]
jc.utils.error_message(f'{parser_name} parser could not parse the input data. Did you use the correct parser?\n For details use the -d option.')
exit(1)
sys.exit(1)
if not found:
helptext('missing or incorrect arguments')
exit()
sys.exit(1)
json_out(result, pretty=pretty)

View File

@ -100,6 +100,9 @@ class info():
compatible = ['linux', 'aix', 'freebsd', 'darwin']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.

View File

@ -132,7 +132,7 @@ import jc.parsers.universal
class info():
version = '1.0'
version = '1.1'
description = 'crontab file parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -142,6 +142,9 @@ class info():
compatible = ['linux', 'darwin', 'aix', 'freebsd']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.
@ -156,8 +159,8 @@ def process(proc_data):
{
"variables": [
"name": string,
"value": string
"name": string,
"value": string
],
"schedule": [
{
@ -249,12 +252,12 @@ def parse(data, raw=False, quiet=False):
'command': cmd})
# Add header row for parsing
cleandata[0] = 'minute hour day_of_month month day_of_week command'
cleandata[:0] = ['minute hour day_of_month month day_of_week command']
if len(cleandata) > 1:
cron_list = jc.parsers.universal.simple_table_parse(cleandata)
raw_output['schedule'] = cron_list
raw_output['schedule'] = cron_list
# Add shortcut entries back in
for item in shortcut_list:

273
jc/parsers/crontab_u.py Normal file
View File

@ -0,0 +1,273 @@
"""jc - JSON CLI output utility crontab file Parser
Usage:
specify --crontab-u as the first argument if the piped input is coming from a crontab file with User specified
Compatibility:
'linux', 'darwin', 'aix', 'freebsd'
Examples:
$ cat /etc/crontab | jc --crontab -p
{
"variables": [
{
"name": "PATH",
"value": "/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin"
},
{
"name": "SHELL",
"value": "/bin/sh"
}
],
"schedule": [
{
"minute": [
"25"
],
"hour": [
"6"
],
"day_of_month": [
"*"
],
"month": [
"*"
],
"day_of_week": [
"*"
],
"user": "root",
"command": "test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )"
},
{
"minute": [
"47"
],
"hour": [
"6"
],
"day_of_month": [
"*"
],
"month": [
"*"
],
"day_of_week": [
"7"
],
"user": "root",
"command": "test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )"
},
{
"minute": [
"52"
],
"hour": [
"6"
],
"day_of_month": [
"1"
],
"month": [
"*"
],
"day_of_week": [
"*"
],
"user": "root",
"command": "test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )"
}
]
}
$ cat /etc/crontab | jc --crontab-u -p -r
{
"variables": [
{
"name": "PATH",
"value": "/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin"
},
{
"name": "SHELL",
"value": "/bin/sh"
}
],
"schedule": [
{
"minute": "25",
"hour": "6",
"day_of_month": "*",
"month": "*",
"day_of_week": "*",
"user": "root",
"command": "test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )"
},
{
"minute": "47",
"hour": "6",
"day_of_month": "*",
"month": "*",
"day_of_week": "7",
"user": "root",
"command": "test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )"
},
{
"minute": "52",
"hour": "6",
"day_of_month": "1",
"month": "*",
"day_of_week": "*",
"user": "root",
"command": "test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )"
}
]
}
"""
import jc.utils
import jc.parsers.universal
class info():
version = '1.0'
description = 'crontab file parser with user support'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# details = 'enter any other details here'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'darwin', 'aix', 'freebsd']
__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. Structured data with the following schema:
{
"variables": [
"name": string,
"value": string
],
"schedule": [
{
"occurrence" string,
"minute": [
string
],
"hour": [
string
],
"day_of_month": [
string
],
"month": [
string
],
"day_of_week": [
string
],
"occurrence": string,
"user": string,
"command": string
}
]
}
"""
# put itmes in lists
try:
for entry in proc_data['schedule']:
entry['minute'] = entry['minute'].split(',')
entry['hour'] = entry['hour'].split(',')
entry['day_of_month'] = entry['day_of_month'].split(',')
entry['month'] = entry['month'].split(',')
entry['day_of_week'] = entry['day_of_week'].split(',')
except (KeyError):
pass
return proc_data
def parse(data, raw=False, quiet=False):
"""
Main text parsing function
Parameters:
data: (string) text data to parse
raw: (boolean) output preprocessed JSON if True
quiet: (boolean) suppress warning messages if True
Returns:
Dictionary. Raw or processed structured data.
"""
if not quiet:
jc.utils.compatibility(__name__, info.compatible)
raw_output = {}
cleandata = data.splitlines()
# Clear any blank lines
cleandata = list(filter(None, cleandata))
# Clear any commented lines
for i, line in reversed(list(enumerate(cleandata))):
if line.strip().find('#') == 0:
cleandata.pop(i)
# Pop any variable assignment lines
cron_var = []
for i, line in reversed(list(enumerate(cleandata))):
if line.find('=') != -1:
var_line = cleandata.pop(i)
var_name = var_line.split('=', maxsplit=1)[0].strip()
var_value = var_line.split('=', maxsplit=1)[1].strip()
cron_var.append({'name': var_name,
'value': var_value})
raw_output['variables'] = cron_var
# Pop any shortcut lines
shortcut_list = []
for i, line in reversed(list(enumerate(cleandata))):
if line.strip().startswith('@'):
shortcut_line = cleandata.pop(i)
occurrence = shortcut_line.split(maxsplit=1)[0].strip().lstrip('@')
usr = shortcut_line.split(maxsplit=2)[1].strip()
cmd = shortcut_line.split(maxsplit=2)[2].strip()
shortcut_list.append({'occurrence': occurrence,
'user': usr,
'command': cmd})
# Add header row for parsing
cleandata[:0] = ['minute hour day_of_month month day_of_week user command']
if len(cleandata) > 1:
cron_list = jc.parsers.universal.simple_table_parse(cleandata)
raw_output['schedule'] = cron_list
# Add shortcut entries back in
for item in shortcut_list:
raw_output['schedule'].append(item)
if raw:
return raw_output
else:
return process(raw_output)

View File

@ -82,6 +82,9 @@ class info():
compatible = ['linux', 'darwin']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.

View File

@ -333,6 +333,9 @@ class info():
compatible = ['linux', 'aix', 'freebsd', 'darwin']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.

View File

@ -6,7 +6,7 @@ Usage:
Compatibility:
'linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'
'linux', 'darwin', 'aix', 'freebsd'
Examples:
@ -73,14 +73,17 @@ import jc.parsers.universal
class info():
version = '1.0'
version = '1.1'
description = 'du parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# details = 'enter any other details here'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
compatible = ['linux', 'darwin', 'aix', 'freebsd']
__version__ = info.version
def process(proc_data):

View File

@ -61,6 +61,9 @@ class info():
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.

View File

@ -30,6 +30,9 @@ class info():
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.

View File

@ -62,6 +62,9 @@ class info():
compatible = ['linux']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.

View File

@ -79,6 +79,9 @@ class info():
compatible = ['linux']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.

View File

@ -6,26 +6,26 @@ Usage:
Compatibility:
'linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'
'linux', 'darwin', 'cygwin', 'aix', 'freebsd'
Examples:
$ history | jc --history -p
[
{
"line": "118",
"line": 118,
"command": "sleep 100"
},
{
"line": "119",
"line": 119,
"command": "ls /bin"
},
{
"line": "120",
"line": 120,
"command": "echo \"hello\""
},
{
"line": "121",
"line": 121,
"command": "docker images"
},
...
@ -50,7 +50,10 @@ class info():
author_email = 'kellyjonbrazil@gmail.com'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
compatible = ['linux', 'darwin', 'cygwin', 'aix', 'freebsd']
__version__ = info.version
def process(proc_data):
@ -67,7 +70,7 @@ def process(proc_data):
[
{
"line": string,
"line": integer,
"command": string
}
]
@ -81,6 +84,16 @@ def process(proc_data):
proc_line['command'] = v
processed.append(proc_line)
for entry in processed:
int_list = ['line']
for key in int_list:
if key in entry:
try:
key_int = int(entry[key])
entry[key] = key_int
except (ValueError):
entry[key] = None
return processed

View File

@ -70,6 +70,9 @@ class info():
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.

214
jc/parsers/id.py Normal file
View File

@ -0,0 +1,214 @@
"""jc - JSON CLI output utility id Parser
Usage:
specify --id as the first argument if the piped input is coming from id
Compatibility:
'linux', 'darwin', 'aix', 'freebsd'
Examples:
$ id | jc --id -p
{
"uid": {
"id": 1000,
"name": "joeuser"
},
"gid": {
"id": 1000,
"name": "joeuser"
},
"groups": [
{
"id": 1000,
"name": "joeuser"
},
{
"id": 10,
"name": "wheel"
}
],
"context": {
"user": "unconfined_u",
"role": "unconfined_r",
"type": "unconfined_t",
"level": "s0-s0:c0.c1023"
}
}
$ id | jc --id -p -r
{
"uid": {
"id": "1000",
"name": "joeuser"
},
"gid": {
"id": "1000",
"name": "joeuser"
},
"groups": [
{
"id": "1000",
"name": "joeuser"
},
{
"id": "10",
"name": "wheel"
}
],
"context": {
"user": "unconfined_u",
"role": "unconfined_r",
"type": "unconfined_t",
"level": "s0-s0:c0.c1023"
}
}
"""
import jc.utils
class info():
version = '1.0'
description = 'id parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
# details = 'enter any other details here'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'darwin', 'aix', 'freebsd']
__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. Structured data with the following schema:
{
"uid": {
"id": integer,
"name": string
},
"gid": {
"id": integer,
"name": string
},
"groups": [
{
"id": integer,
"name": string
},
{
"id": integer,
"name": string
}
],
"context": {
"user": string,
"role": string,
"type": string,
"level": string
}
}
"""
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
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
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
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)
raw_output = {}
cleandata = data.split()
# Clear any blank lines
cleandata = list(filter(None, cleandata))
if cleandata:
for section in cleandata:
if section.startswith('uid'):
uid_parsed = section.replace('(', '=').replace(')', '=')
uid_parsed = uid_parsed.split('=')
raw_output['uid'] = {}
raw_output['uid']['id'] = uid_parsed[1]
raw_output['uid']['name'] = uid_parsed[2]
if section.startswith('gid'):
gid_parsed = section.replace('(', '=').replace(')', '=')
gid_parsed = gid_parsed.split('=')
raw_output['gid'] = {}
raw_output['gid']['id'] = gid_parsed[1]
raw_output['gid']['name'] = gid_parsed[2]
if section.startswith('groups'):
groups_parsed = section.replace('(', '=').replace(')', '=')
groups_parsed = groups_parsed.replace('groups=', '')
groups_parsed = groups_parsed.split(',')
raw_output['groups'] = []
for group in groups_parsed:
group_dict = {}
grp_parsed = group.split('=')
group_dict['id'] = grp_parsed[0]
group_dict['name'] = grp_parsed[1]
raw_output['groups'].append(group_dict)
if section.startswith('context'):
context_parsed = section.replace('context=', '')
context_parsed = context_parsed.split(':', maxsplit=3)
raw_output['context'] = {}
raw_output['context']['user'] = context_parsed[0]
raw_output['context']['role'] = context_parsed[1]
raw_output['context']['type'] = context_parsed[2]
raw_output['context']['level'] = context_parsed[3]
if raw:
return raw_output
else:
return process(raw_output)

View File

@ -156,6 +156,9 @@ class info():
compatible = ['linux', 'aix', 'freebsd', 'darwin']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.

112
jc/parsers/ini.py Normal file
View File

@ -0,0 +1,112 @@
"""jc - JSON CLI output utility INI Parser
Usage:
specify --ini as the first argument if the piped input is coming from an INI file
Compatibility:
'linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'
Examples:
$ cat example.ini
[DEFAULT]
ServerAliveInterval = 45
Compression = yes
CompressionLevel = 9
ForwardX11 = yes
[bitbucket.org]
User = hg
[topsecret.server.com]
Port = 50022
ForwardX11 = no
$ cat example.ini | jc --ini -p
{
"bitbucket.org": {
"serveraliveinterval": "45",
"compression": "yes",
"compressionlevel": "9",
"forwardx11": "yes",
"user": "hg"
},
"topsecret.server.com": {
"serveraliveinterval": "45",
"compression": "yes",
"compressionlevel": "9",
"forwardx11": "no",
"port": "50022"
}
}
"""
import jc.utils
import configparser
class info():
version = '1.0'
description = 'INI file parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
details = 'Using configparser from the standard library'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
__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 representing an ini document:
{
ini document converted to a dictionary
see configparser standard library documentation for more details
}
"""
# No further processing
return proc_data
def parse(data, raw=False, quiet=False):
"""
Main text parsing function
Parameters:
data: (string) text data to parse
raw: (boolean) output preprocessed JSON if True
quiet: (boolean) suppress warning messages if True
Returns:
Dictionary representing the ini file
"""
if not quiet:
jc.utils.compatibility(__name__, info.compatible)
raw_output = {}
if data:
ini = configparser.ConfigParser()
ini.read_string(data)
raw_output = {s: dict(ini.items(s)) for s in ini.sections()}
if raw:
return raw_output
else:
return process(raw_output)

View File

@ -143,6 +143,9 @@ class info():
compatible = ['linux']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.

View File

@ -86,6 +86,9 @@ class info():
compatible = ['linux', 'darwin', 'cygwin', 'aix', 'freebsd']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.

View File

@ -153,6 +153,9 @@ class info():
compatible = ['linux', 'darwin', 'cygwin', 'aix', 'freebsd']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.

View File

@ -225,6 +225,9 @@ class info():
compatible = ['linux']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.

View File

@ -116,6 +116,9 @@ class info():
compatible = ['linux']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.

View File

@ -106,6 +106,9 @@ class info():
compatible = ['linux']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.

View File

@ -65,6 +65,9 @@ class info():
compatible = ['linux', 'darwin']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.

View File

@ -322,6 +322,9 @@ class info():
compatible = ['linux']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.

View File

@ -33,7 +33,7 @@ import jc.parsers.universal
class info():
version = '1.0'
description = 'pip-list parser'
description = 'pip list parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -41,6 +41,9 @@ class info():
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.

View File

@ -43,7 +43,7 @@ import jc.utils
class info():
version = '1.0'
description = 'pip-show parser'
description = 'pip show parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -51,6 +51,9 @@ class info():
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.

View File

@ -186,6 +186,9 @@ class info():
compatible = ['linux', 'darwin', 'cygwin', 'aix', 'freebsd']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.

View File

@ -110,6 +110,9 @@ class info():
compatible = ['linux']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.

View File

@ -260,6 +260,9 @@ class info():
compatible = ['linux']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.

View File

@ -113,6 +113,9 @@ class info():
compatible = ['linux']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.

View File

@ -49,6 +49,9 @@ class info():
compatible = ['linux']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.

View File

@ -68,6 +68,9 @@ class info():
compatible = ['linux']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.

View File

@ -43,6 +43,9 @@ class info():
compatible = ['linux']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.

View File

@ -40,6 +40,9 @@ class info():
compatible = ['linux']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.

View File

@ -39,6 +39,9 @@ class info():
compatible = ['linux', 'darwin']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.

View File

@ -43,6 +43,9 @@ class info():
compatible = ['linux', 'darwin', 'cygwin', 'aix', 'freebsd']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.

View File

@ -92,6 +92,9 @@ class info():
compatible = ['linux', 'darwin', 'cygwin', 'aix', 'freebsd']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.

120
jc/parsers/xml.py Normal file
View File

@ -0,0 +1,120 @@
"""jc - JSON CLI output utility XML Parser
Usage:
specify --xml as the first argument if the piped input is coming from an XML file
Compatibility:
'linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'
Examples:
$ cat cd_catalog.xml
<?xml version="1.0" encoding="UTF-8"?>
<CATALOG>
<CD>
<TITLE>Empire Burlesque</TITLE>
<ARTIST>Bob Dylan</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>Columbia</COMPANY>
<PRICE>10.90</PRICE>
<YEAR>1985</YEAR>
</CD>
<CD>
<TITLE>Hide your heart</TITLE>
<ARTIST>Bonnie Tyler</ARTIST>
<COUNTRY>UK</COUNTRY>
<COMPANY>CBS Records</COMPANY>
<PRICE>9.90</PRICE>
<YEAR>1988</YEAR>
</CD>
...
$ cat cd_catalog.xml | jc --xml -p
{
"CATALOG": {
"CD": [
{
"TITLE": "Empire Burlesque",
"ARTIST": "Bob Dylan",
"COUNTRY": "USA",
"COMPANY": "Columbia",
"PRICE": "10.90",
"YEAR": "1985"
},
{
"TITLE": "Hide your heart",
"ARTIST": "Bonnie Tyler",
"COUNTRY": "UK",
"COMPANY": "CBS Records",
"PRICE": "9.90",
"YEAR": "1988"
},
...
}
"""
import jc.utils
import xmltodict
class info():
version = '1.0'
description = 'XML file parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
details = 'Using the xmltodict library at https://github.com/martinblech/xmltodict'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
__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 representing an XML document:
{
XML Document converted to a Dictionary
See https://github.com/martinblech/xmltodict for details
}
"""
# No further processing
return proc_data
def parse(data, raw=False, quiet=False):
"""
Main text parsing function
Parameters:
data: (string) text data to parse
raw: (boolean) output preprocessed JSON if True
quiet: (boolean) suppress warning messages if True
Returns:
Dictionary. Raw or processed structured data.
"""
if not quiet:
jc.utils.compatibility(__name__, info.compatible)
if data:
raw_output = xmltodict.parse(data)
if raw:
return raw_output
else:
return process(raw_output)

137
jc/parsers/yaml.py Normal file
View File

@ -0,0 +1,137 @@
"""jc - JSON CLI output utility YAML Parser
Usage:
specify --yaml as the first argument if the piped input is coming from a YAML file
Compatibility:
'linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'
Examples:
$ cat istio-mtls-permissive.yaml
apiVersion: "authentication.istio.io/v1alpha1"
kind: "Policy"
metadata:
name: "default"
namespace: "default"
spec:
peers:
- mtls: {}
---
apiVersion: "networking.istio.io/v1alpha3"
kind: "DestinationRule"
metadata:
name: "default"
namespace: "default"
spec:
host: "*.default.svc.cluster.local"
trafficPolicy:
tls:
mode: ISTIO_MUTUAL
$ cat istio-mtls-permissive.yaml | jc --yaml -p
[
{
"apiVersion": "authentication.istio.io/v1alpha1",
"kind": "Policy",
"metadata": {
"name": "default",
"namespace": "default"
},
"spec": {
"peers": [
{
"mtls": {}
}
]
}
},
{
"apiVersion": "networking.istio.io/v1alpha3",
"kind": "DestinationRule",
"metadata": {
"name": "default",
"namespace": "default"
},
"spec": {
"host": "*.default.svc.cluster.local",
"trafficPolicy": {
"tls": {
"mode": "ISTIO_MUTUAL"
}
}
}
}
]
"""
import jc.utils
from ruamel.yaml import YAML
class info():
version = '1.0'
description = 'YAML file parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
details = 'Using the ruamel.yaml library at https://pypi.org/project/ruamel.yaml'
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
__version__ = info.version
def process(proc_data):
"""
Final processing to conform to the schema.
Parameters:
proc_data: (dictionary) raw structured data to process
Returns:
List of dictionaries. Each dictionary represents a YAML document:
[
{
YAML Document converted to a Dictionary
See https://pypi.org/project/ruamel.yaml for details
}
]
"""
# No further processing
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)
raw_output = []
yaml = YAML(typ='safe')
for document in yaml.load_all(data):
raw_output.append(document)
if raw:
return raw_output
else:
return process(raw_output)

View File

@ -5,12 +5,14 @@ with open('README.md', 'r') as f:
setuptools.setup(
name='jc',
version='1.6.1',
version='1.7.1',
author='Kelly Brazil',
author_email='kellyjonbrazil@gmail.com',
description='This tool serializes the output of popular command line tools to structured JSON output.',
description='This tool serializes the output of popular command line tools and filetypes to structured JSON output.',
install_requires=[
'ifconfig-parser>=0.0.5'
'ifconfig-parser>=0.0.5',
'ruamel.yaml>=0.15.0',
'xmltodict>=0.12.0'
],
license='MIT',
long_description=long_description,

View File

@ -0,0 +1 @@
{"variables": [{"name": "MAILTO", "value": "root"}, {"name": "PATH", "value": "/sbin:/bin:/usr/sbin:/usr/bin"}, {"name": "SHELL", "value": "/bin/bash"}], "schedule": [{"minute": ["01"], "hour": ["*"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "user": "root", "command": "run-parts /etc/cron.hourly"}, {"occurrence": "hourly", "user": "root", "command": "/usr/local/bin/backup"}]}

View File

@ -0,0 +1,6 @@
# Run the hourly jobs
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
@hourly root /usr/local/bin/backup
01 * * * * root run-parts /etc/cron.hourly

View File

@ -1 +1 @@
{"variables": [{"name": "MAILTO", "value": "root"}, {"name": "PATH", "value": "/sbin:/bin:/usr/sbin:/usr/bin"}, {"name": "SHELL", "value": "/bin/bash"}], "schedule": [{"minute": ["*"], "hour": ["*"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "command": "/var/www/devdaily.com/bin/check-apache.sh"}, {"minute": ["5"], "hour": ["10-11", "22"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "command": "/var/www/devdaily.com/bin/mk-new-links.php"}, {"minute": ["30"], "hour": ["4/2"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "command": "/var/www/devdaily.com/bin/create-all-backups.sh"}, {"minute": ["5"], "hour": ["0", "4", "10", "16"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "command": "/var/www/devdaily.com/bin/create-cat-list.sh"}, {"minute": ["5"], "hour": ["0"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "command": "/var/www/devdaily.com/bin/resetContactForm.sh"}, {"minute": ["0", "20", "40"], "hour": ["*"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "command": "/var/www/bin/ads/freshMint.sh"}, {"minute": ["5", "25", "45"], "hour": ["*"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "command": "/var/www/bin/ads/greenTaffy.sh"}, {"minute": ["10", "30", "50"], "hour": ["*"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "command": "/var/www/bin/ads/raspberry.sh"}, {"minute": ["15", "35", "55"], "hour": ["*"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "command": "/var/www/bin/ads/robinsEgg.sh"}, {"occurrence": "yearly", "command": "/home/maverick/bin/annual-maintenance"}, {"occurrence": "reboot", "command": "/home/cleanup"}, {"occurrence": "monthly", "command": "/home/maverick/bin/tape-backup"}]}
{"variables": [{"name": "MAILTO", "value": "root"}, {"name": "PATH", "value": "/sbin:/bin:/usr/sbin:/usr/bin"}, {"name": "SHELL", "value": "/bin/bash"}], "schedule": [{"minute": ["0"], "hour": ["*"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "command": "/usr/bin/wget -O - -q -t 1 http://localhost/cron.php"}, {"minute": ["*"], "hour": ["*"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "command": "/var/www/devdaily.com/bin/check-apache.sh"}, {"minute": ["5"], "hour": ["10-11", "22"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "command": "/var/www/devdaily.com/bin/mk-new-links.php"}, {"minute": ["30"], "hour": ["4/2"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "command": "/var/www/devdaily.com/bin/create-all-backups.sh"}, {"minute": ["5"], "hour": ["0", "4", "10", "16"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "command": "/var/www/devdaily.com/bin/create-cat-list.sh"}, {"minute": ["5"], "hour": ["0"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "command": "/var/www/devdaily.com/bin/resetContactForm.sh"}, {"minute": ["0", "20", "40"], "hour": ["*"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "command": "/var/www/bin/ads/freshMint.sh"}, {"minute": ["5", "25", "45"], "hour": ["*"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "command": "/var/www/bin/ads/greenTaffy.sh"}, {"minute": ["10", "30", "50"], "hour": ["*"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "command": "/var/www/bin/ads/raspberry.sh"}, {"minute": ["15", "35", "55"], "hour": ["*"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "command": "/var/www/bin/ads/robinsEgg.sh"}, {"occurrence": "yearly", "command": "/home/maverick/bin/annual-maintenance"}, {"occurrence": "reboot", "command": "/home/cleanup"}, {"occurrence": "monthly", "command": "/home/maverick/bin/tape-backup"}]}

File diff suppressed because one or more lines are too long

1
tests/fixtures/centos-7.7/id.json vendored Normal file
View File

@ -0,0 +1 @@
{"uid": {"id": 1000, "name": "kbrazil"}, "gid": {"id": 1000, "name": "kbrazil"}, "groups": [{"id": 1000, "name": "kbrazil"}, {"id": 10, "name": "wheel"}], "context": {"user": "unconfined_u", "role": "unconfined_r", "type": "unconfined_t", "level": "s0-s0:c0.c1023"}}

1
tests/fixtures/centos-7.7/id.out vendored Normal file
View File

@ -0,0 +1 @@
uid=1000(kbrazil) gid=1000(kbrazil) groups=1000(kbrazil),10(wheel) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

View File

@ -0,0 +1,133 @@
[Settings]
#======================================================================
# Set detailed log for additional debugging info
DetailedLog=1
RunStatus=1
StatusPort=6090
StatusRefresh=10
Archive=1
# Sets the location of the MV_FTP log file
LogFile=/opt/ecs/mvuser/MV_IPTel/log/MV_IPTel.log
#======================================================================
Version=0.9 Build 4 Created July 11 2004 14:00
ServerName=Unknown
[FTP]
#======================================================================
# set the FTP server active
RunFTP=1
# defines the FTP control port
FTPPort=21
# defines the FTP data port
FTPDataPort=20
# Sets the location of the FTP data directory to catch terminal backups
FTPDir=/opt/ecs/mvuser/MV_IPTel/data/FTPdata
# FTP Timeout (secs)
FTP_TimeOut=5
# Enable SuperUser
EnableSU=1
# set the SuperUser Name
SUUserName=mvuser
# set the SuperUser Password
SUPassword=Avaya
#
#======================================================================
[FTPS]
#======================================================================
# set the FTPS server active
RunFTPS=0
# defines the FTP control port
FTPPort=990
# defines the FTP data port
FTPDataPort=889
#======================================================================
[TFTP]
#======================================================================
# set the Trivial FTP server active
RunTrivialFTP=1
# defines the Trivial FTP port
TrivialFTPPort=69
# Sets the location of the TFTP data directory for terminal downloads
TFTPDir=/opt/ecs/mvuser/MV_IPTel/data/TFTPdata
#======================================================================
[HTTP]
#======================================================================
# set the HTTP download server active
RunHTTP=1
# defines the HTTP download port
HTTPPort=81
# Sets the location of the HTTP data directory for downloads
HTTPDir=/opt/ecs/mvuser/MV_IPTel/data/HTTPdata
#======================================================================
[HTTPS]
#======================================================================
# set the HTTPS download server active
RunHTTPS=0
# defines the HTTPS download port
HTTPSPort=411
# Sets the location of the HTTPS data directory for downloads
HTTPSDir=/opt/ecs/mvuser/MV_IPTel/data/HTTPSdata
# Sets the location of the CertFile
CertFile=/opt/ecs/mvuser/MV_IPTel/certs/IPTelcert.pem
# Sets the location of the KeyFile
KeyFile=/opt/ecs/mvuser/MV_IPTel/certs/IPTelkey.pem
# Use Client Authorization
ClientAuth=0
# narrow config for Avaya IPTel (TLSV1 using RSA_NULL_SHA)
IPTel=0
# sets the SSL variants if not Avaya IPtel (IPTel=0)
SSLV2=0
SSLV3=0
TLSV1=1
UseProxy=0
ProxyAddr=simon.avaya.com
ProxyPort=9000
#======================================================================
[BACKUP_SERVERS]
#======================================================================
# Run as FileServer for Backup & Update requests - Note this process uses HTTPS
FileServer=0
# sets whether to download Firmware updates from the primary/secondary file servers
RequestUpdates=0
# sets whether to upload FTP files to the primary/secondary file servers
RequestBackup=0
# Enable use of the Primary file server
UsePrimarySvr=0
# Primary file server IP address ( or resolvable DNS)
PrimaryIP=192.168.0.13
# Enable use of the Secondary file server
UseSecondarySvr=0
# Secondary file server IP address ( or resolvable DNS)
SecondaryIP=192.168.0.10
# Sets the update interval for Backups & updates ; 1 = min; 2 =hour, 3=day, 4 =month
UpdateInterval=2
#Send FTP backup to the customer sever
CustomFTP=1
# FTP backup directory customer sever
CustomFTPDir=home/mvuser/backup
# FTP backup directory user login name
CustomFTPUName=tom
# FTP backup directory user password
CustomFTPPwd=jerry
# Enable CDR Backup - enable=1 on both File Server & Client
CDRBackup=0
# Enable BCMS Backup - enable=1 on both File Server & Client
BCMSBackup=0
# Retain CDR / BCMS copy data for x days ( Receiver always + 1 week)
RetainDays=7.0
#======================================================================
[SNMP]
#================================================================
#
# Validate FTP store with SNMP check
UseSNMP=1
# In case the SNMPGET syntax changes you can redefine the commands
# Uncomment the relevant line to override the internal command
#the syntax is "Command + IPADDR + ExtObj + Awk
# the IPADRR is derived from the connection
# Note there are relavant spaces at the start/end of the component - omit and it will fail
#Command=/usr/bin/snmpget
#Params= -v2c -cpublic
#ExtObject=.1.3.6.1.4.1.6889.2.69.1.4.9.0
#TypeObject=.1.3.6.1.4.1.6889.2.69.1.1.2.0
#Awk=| awk -F \" '' {print $2 } ''
#================================================================

View File

@ -0,0 +1 @@
{"Settings": {"detailedlog": "1", "runstatus": "1", "statusport": "6090", "statusrefresh": "10", "archive": "1", "logfile": "/opt/ecs/mvuser/MV_IPTel/log/MV_IPTel.log", "version": "0.9 Build 4 Created July 11 2004 14:00", "servername": "Unknown"}, "FTP": {"runftp": "1", "ftpport": "21", "ftpdataport": "20", "ftpdir": "/opt/ecs/mvuser/MV_IPTel/data/FTPdata", "ftp_timeout": "5", "enablesu": "1", "suusername": "mvuser", "supassword": "Avaya"}, "FTPS": {"runftps": "0", "ftpport": "990", "ftpdataport": "889"}, "TFTP": {"runtrivialftp": "1", "trivialftpport": "69", "tftpdir": "/opt/ecs/mvuser/MV_IPTel/data/TFTPdata"}, "HTTP": {"runhttp": "1", "httpport": "81", "httpdir": "/opt/ecs/mvuser/MV_IPTel/data/HTTPdata"}, "HTTPS": {"runhttps": "0", "httpsport": "411", "httpsdir": "/opt/ecs/mvuser/MV_IPTel/data/HTTPSdata", "certfile": "/opt/ecs/mvuser/MV_IPTel/certs/IPTelcert.pem", "keyfile": "/opt/ecs/mvuser/MV_IPTel/certs/IPTelkey.pem", "clientauth": "0", "iptel": "0", "sslv2": "0", "sslv3": "0", "tlsv1": "1", "useproxy": "0", "proxyaddr": "simon.avaya.com", "proxyport": "9000"}, "BACKUP_SERVERS": {"fileserver": "0", "requestupdates": "0", "requestbackup": "0", "useprimarysvr": "0", "primaryip": "192.168.0.13", "usesecondarysvr": "0", "secondaryip": "192.168.0.10", "updateinterval": "2", "customftp": "1", "customftpdir": "home/mvuser/backup", "customftpuname": "tom", "customftppwd": "jerry", "cdrbackup": "0", "bcmsbackup": "0", "retaindays": "7.0"}, "SNMP": {"usesnmp": "1"}}

12
tests/fixtures/generic/ini-test.ini vendored Normal file
View File

@ -0,0 +1,12 @@
[DEFAULT]
ServerAliveInterval = 45
Compression = yes
CompressionLevel = 9
ForwardX11 = yes
[bitbucket.org]
User = hg
[topsecret.server.com]
Port = 50022
ForwardX11 = no

1
tests/fixtures/generic/ini-test.json vendored Normal file
View File

@ -0,0 +1 @@
{"bitbucket.org": {"serveraliveinterval": "45", "compression": "yes", "compressionlevel": "9", "forwardx11": "yes", "user": "hg"}, "topsecret.server.com": {"serveraliveinterval": "45", "compression": "yes", "compressionlevel": "9", "forwardx11": "no", "port": "50022"}}

View File

@ -0,0 +1 @@
{"CATALOG": {"CD": [{"TITLE": "Empire Burlesque", "ARTIST": "Bob Dylan", "COUNTRY": "USA", "COMPANY": "Columbia", "PRICE": "10.90", "YEAR": "1985"}, {"TITLE": "Hide your heart", "ARTIST": "Bonnie Tyler", "COUNTRY": "UK", "COMPANY": "CBS Records", "PRICE": "9.90", "YEAR": "1988"}, {"TITLE": "Greatest Hits", "ARTIST": "Dolly Parton", "COUNTRY": "USA", "COMPANY": "RCA", "PRICE": "9.90", "YEAR": "1982"}, {"TITLE": "Still got the blues", "ARTIST": "Gary Moore", "COUNTRY": "UK", "COMPANY": "Virgin records", "PRICE": "10.20", "YEAR": "1990"}, {"TITLE": "Eros", "ARTIST": "Eros Ramazzotti", "COUNTRY": "EU", "COMPANY": "BMG", "PRICE": "9.90", "YEAR": "1997"}, {"TITLE": "One night only", "ARTIST": "Bee Gees", "COUNTRY": "UK", "COMPANY": "Polydor", "PRICE": "10.90", "YEAR": "1998"}, {"TITLE": "Sylvias Mother", "ARTIST": "Dr.Hook", "COUNTRY": "UK", "COMPANY": "CBS", "PRICE": "8.10", "YEAR": "1973"}, {"TITLE": "Maggie May", "ARTIST": "Rod Stewart", "COUNTRY": "UK", "COMPANY": "Pickwick", "PRICE": "8.50", "YEAR": "1990"}, {"TITLE": "Romanza", "ARTIST": "Andrea Bocelli", "COUNTRY": "EU", "COMPANY": "Polydor", "PRICE": "10.80", "YEAR": "1996"}, {"TITLE": "When a man loves a woman", "ARTIST": "Percy Sledge", "COUNTRY": "USA", "COMPANY": "Atlantic", "PRICE": "8.70", "YEAR": "1987"}, {"TITLE": "Black angel", "ARTIST": "Savage Rose", "COUNTRY": "EU", "COMPANY": "Mega", "PRICE": "10.90", "YEAR": "1995"}, {"TITLE": "1999 Grammy Nominees", "ARTIST": "Many", "COUNTRY": "USA", "COMPANY": "Grammy", "PRICE": "10.20", "YEAR": "1999"}, {"TITLE": "For the good times", "ARTIST": "Kenny Rogers", "COUNTRY": "UK", "COMPANY": "Mucik Master", "PRICE": "8.70", "YEAR": "1995"}, {"TITLE": "Big Willie style", "ARTIST": "Will Smith", "COUNTRY": "USA", "COMPANY": "Columbia", "PRICE": "9.90", "YEAR": "1997"}, {"TITLE": "Tupelo Honey", "ARTIST": "Van Morrison", "COUNTRY": "UK", "COMPANY": "Polydor", "PRICE": "8.20", "YEAR": "1971"}, {"TITLE": "Soulsville", "ARTIST": "Jorn Hoel", "COUNTRY": "Norway", "COMPANY": "WEA", "PRICE": "7.90", "YEAR": "1996"}, {"TITLE": "The very best of", "ARTIST": "Cat Stevens", "COUNTRY": "UK", "COMPANY": "Island", "PRICE": "8.90", "YEAR": "1990"}, {"TITLE": "Stop", "ARTIST": "Sam Brown", "COUNTRY": "UK", "COMPANY": "A and M", "PRICE": "8.90", "YEAR": "1988"}, {"TITLE": "Bridge of Spies", "ARTIST": "T'Pau", "COUNTRY": "UK", "COMPANY": "Siren", "PRICE": "7.90", "YEAR": "1987"}, {"TITLE": "Private Dancer", "ARTIST": "Tina Turner", "COUNTRY": "UK", "COMPANY": "Capitol", "PRICE": "8.90", "YEAR": "1983"}, {"TITLE": "Midt om natten", "ARTIST": "Kim Larsen", "COUNTRY": "EU", "COMPANY": "Medley", "PRICE": "7.80", "YEAR": "1983"}, {"TITLE": "Pavarotti Gala Concert", "ARTIST": "Luciano Pavarotti", "COUNTRY": "UK", "COMPANY": "DECCA", "PRICE": "9.90", "YEAR": "1991"}, {"TITLE": "The dock of the bay", "ARTIST": "Otis Redding", "COUNTRY": "USA", "COMPANY": "Stax Records", "PRICE": "7.90", "YEAR": "1968"}, {"TITLE": "Picture book", "ARTIST": "Simply Red", "COUNTRY": "EU", "COMPANY": "Elektra", "PRICE": "7.20", "YEAR": "1985"}, {"TITLE": "Red", "ARTIST": "The Communards", "COUNTRY": "UK", "COMPANY": "London", "PRICE": "7.80", "YEAR": "1987"}, {"TITLE": "Unchain my heart", "ARTIST": "Joe Cocker", "COUNTRY": "USA", "COMPANY": "EMI", "PRICE": "8.20", "YEAR": "1987"}]}}

View File

@ -0,0 +1,211 @@
<?xml version="1.0" encoding="UTF-8"?>
<CATALOG>
<CD>
<TITLE>Empire Burlesque</TITLE>
<ARTIST>Bob Dylan</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>Columbia</COMPANY>
<PRICE>10.90</PRICE>
<YEAR>1985</YEAR>
</CD>
<CD>
<TITLE>Hide your heart</TITLE>
<ARTIST>Bonnie Tyler</ARTIST>
<COUNTRY>UK</COUNTRY>
<COMPANY>CBS Records</COMPANY>
<PRICE>9.90</PRICE>
<YEAR>1988</YEAR>
</CD>
<CD>
<TITLE>Greatest Hits</TITLE>
<ARTIST>Dolly Parton</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>RCA</COMPANY>
<PRICE>9.90</PRICE>
<YEAR>1982</YEAR>
</CD>
<CD>
<TITLE>Still got the blues</TITLE>
<ARTIST>Gary Moore</ARTIST>
<COUNTRY>UK</COUNTRY>
<COMPANY>Virgin records</COMPANY>
<PRICE>10.20</PRICE>
<YEAR>1990</YEAR>
</CD>
<CD>
<TITLE>Eros</TITLE>
<ARTIST>Eros Ramazzotti</ARTIST>
<COUNTRY>EU</COUNTRY>
<COMPANY>BMG</COMPANY>
<PRICE>9.90</PRICE>
<YEAR>1997</YEAR>
</CD>
<CD>
<TITLE>One night only</TITLE>
<ARTIST>Bee Gees</ARTIST>
<COUNTRY>UK</COUNTRY>
<COMPANY>Polydor</COMPANY>
<PRICE>10.90</PRICE>
<YEAR>1998</YEAR>
</CD>
<CD>
<TITLE>Sylvias Mother</TITLE>
<ARTIST>Dr.Hook</ARTIST>
<COUNTRY>UK</COUNTRY>
<COMPANY>CBS</COMPANY>
<PRICE>8.10</PRICE>
<YEAR>1973</YEAR>
</CD>
<CD>
<TITLE>Maggie May</TITLE>
<ARTIST>Rod Stewart</ARTIST>
<COUNTRY>UK</COUNTRY>
<COMPANY>Pickwick</COMPANY>
<PRICE>8.50</PRICE>
<YEAR>1990</YEAR>
</CD>
<CD>
<TITLE>Romanza</TITLE>
<ARTIST>Andrea Bocelli</ARTIST>
<COUNTRY>EU</COUNTRY>
<COMPANY>Polydor</COMPANY>
<PRICE>10.80</PRICE>
<YEAR>1996</YEAR>
</CD>
<CD>
<TITLE>When a man loves a woman</TITLE>
<ARTIST>Percy Sledge</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>Atlantic</COMPANY>
<PRICE>8.70</PRICE>
<YEAR>1987</YEAR>
</CD>
<CD>
<TITLE>Black angel</TITLE>
<ARTIST>Savage Rose</ARTIST>
<COUNTRY>EU</COUNTRY>
<COMPANY>Mega</COMPANY>
<PRICE>10.90</PRICE>
<YEAR>1995</YEAR>
</CD>
<CD>
<TITLE>1999 Grammy Nominees</TITLE>
<ARTIST>Many</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>Grammy</COMPANY>
<PRICE>10.20</PRICE>
<YEAR>1999</YEAR>
</CD>
<CD>
<TITLE>For the good times</TITLE>
<ARTIST>Kenny Rogers</ARTIST>
<COUNTRY>UK</COUNTRY>
<COMPANY>Mucik Master</COMPANY>
<PRICE>8.70</PRICE>
<YEAR>1995</YEAR>
</CD>
<CD>
<TITLE>Big Willie style</TITLE>
<ARTIST>Will Smith</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>Columbia</COMPANY>
<PRICE>9.90</PRICE>
<YEAR>1997</YEAR>
</CD>
<CD>
<TITLE>Tupelo Honey</TITLE>
<ARTIST>Van Morrison</ARTIST>
<COUNTRY>UK</COUNTRY>
<COMPANY>Polydor</COMPANY>
<PRICE>8.20</PRICE>
<YEAR>1971</YEAR>
</CD>
<CD>
<TITLE>Soulsville</TITLE>
<ARTIST>Jorn Hoel</ARTIST>
<COUNTRY>Norway</COUNTRY>
<COMPANY>WEA</COMPANY>
<PRICE>7.90</PRICE>
<YEAR>1996</YEAR>
</CD>
<CD>
<TITLE>The very best of</TITLE>
<ARTIST>Cat Stevens</ARTIST>
<COUNTRY>UK</COUNTRY>
<COMPANY>Island</COMPANY>
<PRICE>8.90</PRICE>
<YEAR>1990</YEAR>
</CD>
<CD>
<TITLE>Stop</TITLE>
<ARTIST>Sam Brown</ARTIST>
<COUNTRY>UK</COUNTRY>
<COMPANY>A and M</COMPANY>
<PRICE>8.90</PRICE>
<YEAR>1988</YEAR>
</CD>
<CD>
<TITLE>Bridge of Spies</TITLE>
<ARTIST>T'Pau</ARTIST>
<COUNTRY>UK</COUNTRY>
<COMPANY>Siren</COMPANY>
<PRICE>7.90</PRICE>
<YEAR>1987</YEAR>
</CD>
<CD>
<TITLE>Private Dancer</TITLE>
<ARTIST>Tina Turner</ARTIST>
<COUNTRY>UK</COUNTRY>
<COMPANY>Capitol</COMPANY>
<PRICE>8.90</PRICE>
<YEAR>1983</YEAR>
</CD>
<CD>
<TITLE>Midt om natten</TITLE>
<ARTIST>Kim Larsen</ARTIST>
<COUNTRY>EU</COUNTRY>
<COMPANY>Medley</COMPANY>
<PRICE>7.80</PRICE>
<YEAR>1983</YEAR>
</CD>
<CD>
<TITLE>Pavarotti Gala Concert</TITLE>
<ARTIST>Luciano Pavarotti</ARTIST>
<COUNTRY>UK</COUNTRY>
<COMPANY>DECCA</COMPANY>
<PRICE>9.90</PRICE>
<YEAR>1991</YEAR>
</CD>
<CD>
<TITLE>The dock of the bay</TITLE>
<ARTIST>Otis Redding</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>Stax Records</COMPANY>
<PRICE>7.90</PRICE>
<YEAR>1968</YEAR>
</CD>
<CD>
<TITLE>Picture book</TITLE>
<ARTIST>Simply Red</ARTIST>
<COUNTRY>EU</COUNTRY>
<COMPANY>Elektra</COMPANY>
<PRICE>7.20</PRICE>
<YEAR>1985</YEAR>
</CD>
<CD>
<TITLE>Red</TITLE>
<ARTIST>The Communards</ARTIST>
<COUNTRY>UK</COUNTRY>
<COMPANY>London</COMPANY>
<PRICE>7.80</PRICE>
<YEAR>1987</YEAR>
</CD>
<CD>
<TITLE>Unchain my heart</TITLE>
<ARTIST>Joe Cocker</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>EMI</COMPANY>
<PRICE>8.20</PRICE>
<YEAR>1987</YEAR>
</CD>
</CATALOG>

View File

@ -0,0 +1 @@
{"breakfast_menu": {"food": [{"name": "Belgian Waffles", "price": "$5.95", "description": "Two of our famous Belgian Waffles with plenty of real maple syrup", "calories": "650"}, {"name": "Strawberry Belgian Waffles", "price": "$7.95", "description": "Light Belgian waffles covered with strawberries and whipped cream", "calories": "900"}, {"name": "Berry-Berry Belgian Waffles", "price": "$8.95", "description": "Light Belgian waffles covered with an assortment of fresh berries and whipped cream", "calories": "900"}, {"name": "French Toast", "price": "$4.50", "description": "Thick slices made from our homemade sourdough bread", "calories": "600"}, {"name": "Homestyle Breakfast", "price": "$6.95", "description": "Two eggs, bacon or sausage, toast, and our ever-popular hash browns", "calories": "950"}]}}

33
tests/fixtures/generic/xml-foodmenu.xml vendored Normal file
View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<breakfast_menu>
<food>
<name>Belgian Waffles</name>
<price>$5.95</price>
<description>Two of our famous Belgian Waffles with plenty of real maple syrup</description>
<calories>650</calories>
</food>
<food>
<name>Strawberry Belgian Waffles</name>
<price>$7.95</price>
<description>Light Belgian waffles covered with strawberries and whipped cream</description>
<calories>900</calories>
</food>
<food>
<name>Berry-Berry Belgian Waffles</name>
<price>$8.95</price>
<description>Light Belgian waffles covered with an assortment of fresh berries and whipped cream</description>
<calories>900</calories>
</food>
<food>
<name>French Toast</name>
<price>$4.50</price>
<description>Thick slices made from our homemade sourdough bread</description>
<calories>600</calories>
</food>
<food>
<name>Homestyle Breakfast</name>
<price>$6.95</price>
<description>Two eggs, bacon or sausage, toast, and our ever-popular hash browns</description>
<calories>950</calories>
</food>
</breakfast_menu>

View File

@ -0,0 +1 @@
[{"apiVersion": "networking.istio.io/v1alpha3", "kind": "Sidecar", "metadata": {"name": "sidecar-config", "namespace": "default", "testboolean": true}, "spec": {"ingress": [{"port": {"number": 8080, "protocol": "HTTP", "name": "waf"}, "defaultEndpoint": "127.0.0.1:80", "captureMode": "IPTABLES"}], "egress": [{"hosts": ["*/*"]}]}}]

View File

@ -0,0 +1,17 @@
apiVersion: networking.istio.io/v1alpha3
kind: Sidecar
metadata:
name: sidecar-config
namespace: default
testboolean: true
spec:
ingress:
- port:
number: 8080
protocol: HTTP
name: waf
defaultEndpoint: 127.0.0.1:80
captureMode: IPTABLES
egress:
- hosts:
- "*/*"

View File

@ -0,0 +1 @@
[{"apiVersion": "v1", "kind": "ServiceAccount", "metadata": {"name": "www", "testboolean": true}}, {"apiVersion": "v1", "kind": "ServiceAccount", "metadata": {"name": "db", "testboolean": false}}, {"apiVersion": "v1", "kind": "ServiceAccount", "metadata": {"name": "auth"}}, {"apiVersion": "apps/v1", "kind": "Deployment", "metadata": {"name": "www"}, "spec": {"replicas": 3, "selector": {"matchLabels": {"app": "www"}}, "template": {"metadata": {"labels": {"app": "www", "version": "v1.0"}}, "spec": {"serviceAccountName": "www", "containers": [{"name": "modsecurity", "image": "owasp/modsecurity-crs:v3.2-modsec2-apache", "ports": [{"containerPort": 80}], "env": [{"name": "SETPROXY", "value": "True"}, {"name": "PROXYLOCATION", "value": "http://127.0.0.1:8080/"}]}, {"name": "microsimserver", "image": "kellybrazil/microsimserver", "ports": [{"containerPort": 8080}], "env": [{"name": "STATS_PORT", "value": "5000"}]}, {"name": "microsimclient", "image": "kellybrazil/microsimclient", "env": [{"name": "STATS_PORT", "value": "5001"}, {"name": "REQUEST_URLS", "value": "http://auth.default.svc.cluster.local:8080/,http://db.default.svc.cluster.local:8080/"}, {"name": "SEND_SQLI", "value": "True"}]}]}}}}, {"apiVersion": "apps/v1", "kind": "Deployment", "metadata": {"name": "auth"}, "spec": {"replicas": 3, "selector": {"matchLabels": {"app": "auth"}}, "template": {"metadata": {"labels": {"app": "auth", "version": "v1.0"}}, "spec": {"serviceAccountName": "auth", "containers": [{"name": "modsecurity", "image": "owasp/modsecurity-crs:v3.2-modsec2-apache", "ports": [{"containerPort": 80}], "env": [{"name": "SETPROXY", "value": "True"}, {"name": "PROXYLOCATION", "value": "http://127.0.0.1:8080/"}]}, {"name": "microsimserver", "image": "kellybrazil/microsimserver", "ports": [{"containerPort": 8080}], "env": [{"name": "STATS_PORT", "value": "5000"}]}]}}}}, {"apiVersion": "apps/v1", "kind": "Deployment", "metadata": {"name": "db"}, "spec": {"replicas": 3, "selector": {"matchLabels": {"app": "db"}}, "template": {"metadata": {"labels": {"app": "db", "version": "v1.0"}}, "spec": {"serviceAccountName": "db", "containers": [{"name": "modsecurity", "image": "owasp/modsecurity-crs:v3.2-modsec2-apache", "ports": [{"containerPort": 80}], "env": [{"name": "SETPROXY", "value": "True"}, {"name": "PROXYLOCATION", "value": "http://127.0.0.1:8080/"}]}, {"name": "microsimserver", "image": "kellybrazil/microsimserver", "ports": [{"containerPort": 8080}], "env": [{"name": "STATS_PORT", "value": "5000"}]}]}}}}, {"apiVersion": "v1", "kind": "Service", "metadata": {"labels": {"app": "www"}, "name": "www"}, "spec": {"ports": [{"port": 8080, "targetPort": 80, "name": "http"}], "selector": {"app": "www"}, "sessionAffinity": "None"}}, {"apiVersion": "v1", "kind": "Service", "metadata": {"labels": {"app": "auth"}, "name": "auth"}, "spec": {"ports": [{"port": 8080, "targetPort": 80, "name": "http"}], "selector": {"app": "auth"}, "sessionAffinity": "None"}}, {"apiVersion": "v1", "kind": "Service", "metadata": {"labels": {"app": "db"}, "name": "db"}, "spec": {"ports": [{"port": 8080, "targetPort": 80, "name": "http"}], "selector": {"app": "db"}, "sessionAffinity": "None"}}]

View File

@ -0,0 +1,174 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: www
testboolean: true
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: db
testboolean: false
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: auth
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: www
spec:
replicas: 3
selector:
matchLabels:
app: www
template:
metadata:
labels:
app: www
version: v1.0 # add version
spec:
serviceAccountName: www # add serviceAccountName
containers:
- name: modsecurity
image: owasp/modsecurity-crs:v3.2-modsec2-apache
ports:
- containerPort: 80
env:
- name: SETPROXY
value: "True"
- name: PROXYLOCATION
value: "http://127.0.0.1:8080/"
- name: microsimserver
image: kellybrazil/microsimserver
ports:
- containerPort: 8080 # add microsimserver port
env:
- name: STATS_PORT
value: "5000"
- name: microsimclient
image: kellybrazil/microsimclient
env:
- name: STATS_PORT
value: "5001"
- name: REQUEST_URLS
value: "http://auth.default.svc.cluster.local:8080/,http://db.default.svc.cluster.local:8080/"
- name: SEND_SQLI
value: "True"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: auth
spec:
replicas: 3
selector:
matchLabels:
app: auth
template:
metadata:
labels:
app: auth
version: v1.0 # add version
spec:
serviceAccountName: auth # add serviceAccountName
containers:
- name: modsecurity
image: owasp/modsecurity-crs:v3.2-modsec2-apache
ports:
- containerPort: 80
env:
- name: SETPROXY
value: "True"
- name: PROXYLOCATION
value: "http://127.0.0.1:8080/"
- name: microsimserver
image: kellybrazil/microsimserver
ports:
- containerPort: 8080 # add microsimserver port
env:
- name: STATS_PORT
value: "5000"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: db
spec:
replicas: 3
selector:
matchLabels:
app: db
template:
metadata:
labels:
app: db
version: v1.0 # add version
spec:
serviceAccountName: db # add serviceAccountName
containers:
- name: modsecurity
image: owasp/modsecurity-crs:v3.2-modsec2-apache
ports:
- containerPort: 80
env:
- name: SETPROXY
value: "True"
- name: PROXYLOCATION
value: "http://127.0.0.1:8080/"
- name: microsimserver
image: kellybrazil/microsimserver
ports:
- containerPort: 8080 # add microsimserver port
env:
- name: STATS_PORT
value: "5000"
---
apiVersion: v1
kind: Service
metadata:
labels:
app: www
name: www
spec:
# externalTrafficPolicy: Local # remove externalTrafficPolicy
ports:
- port: 8080
targetPort: 80
name: http # add port name
selector:
app: www
sessionAffinity: None
# type: LoadBalancer # remove LoadBalancer type
---
apiVersion: v1
kind: Service
metadata:
labels:
app: auth
name: auth
spec:
ports:
- port: 8080
targetPort: 80
name: http # add port name
selector:
app: auth
sessionAffinity: None
---
apiVersion: v1
kind: Service
metadata:
labels:
app: db
name: db
spec:
ports:
- port: 8080
targetPort: 80
name: http # add port name
selector:
app: db
sessionAffinity: None

1
tests/fixtures/osx-10.14.6/id.json vendored Normal file
View File

@ -0,0 +1 @@
{"uid": {"id": 501, "name": "kbrazil"}, "gid": {"id": 20, "name": "staff"}, "groups": [{"id": 20, "name": "staff"}, {"id": 501, "name": "access_bpf"}, {"id": 12, "name": "everyone"}, {"id": 61, "name": "localaccounts"}, {"id": 79, "name": "_appserverusr"}, {"id": 80, "name": "admin"}, {"id": 81, "name": "_appserveradm"}, {"id": 98, "name": "_lpadmin"}, {"id": 703, "name": "com.apple.sharepoint.group.3"}, {"id": 701, "name": "com.apple.sharepoint.group.1"}, {"id": 702, "name": "com.apple.sharepoint.group.2"}, {"id": 33, "name": "_appstore"}, {"id": 100, "name": "_lpoperator"}, {"id": 204, "name": "_developer"}, {"id": 250, "name": "_analyticsusers"}, {"id": 395, "name": "com.apple.access_ftp"}, {"id": 398, "name": "com.apple.access_screensharing"}]}

1
tests/fixtures/osx-10.14.6/id.out vendored Normal file
View File

@ -0,0 +1 @@
uid=501(kbrazil) gid=20(staff) groups=20(staff),501(access_bpf),12(everyone),61(localaccounts),79(_appserverusr),80(admin),81(_appserveradm),98(_lpadmin),703(com.apple.sharepoint.group.3),701(com.apple.sharepoint.group.1),702(com.apple.sharepoint.group.2),33(_appstore),100(_lpoperator),204(_developer),250(_analyticsusers),395(com.apple.access_ftp),398(com.apple.access_screensharing)

View File

@ -0,0 +1 @@
{"variables": [{"name": "PATH", "value": "/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin"}, {"name": "SHELL", "value": "/bin/sh"}], "schedule": [{"minute": ["17"], "hour": ["*"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "user": "root", "command": "cd / && run-parts --report /etc/cron.hourly"}, {"minute": ["25"], "hour": ["6"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "user": "root", "command": "test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )"}, {"minute": ["47"], "hour": ["6"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["7"], "user": "root", "command": "test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )"}, {"minute": ["52"], "hour": ["6"], "day_of_month": ["1"], "month": ["*"], "day_of_week": ["*"], "user": "root", "command": "test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )"}]}

View File

@ -1 +0,0 @@
{"variables": [{"name": "PATH", "value": "/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin"}, {"name": "SHELL", "value": "/bin/sh"}], "schedule": [{"minute": ["25"], "hour": ["6"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["*"], "command": "root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )"}, {"minute": ["47"], "hour": ["6"], "day_of_month": ["*"], "month": ["*"], "day_of_week": ["7"], "command": "root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )"}, {"minute": ["52"], "hour": ["6"], "day_of_month": ["1"], "month": ["*"], "day_of_week": ["*"], "command": "root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )"}]}

File diff suppressed because one or more lines are too long

View File

@ -13,28 +13,16 @@ class MyTests(unittest.TestCase):
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/centos-7.7/crontab.out'), 'r') as f:
self.centos_7_7_crontab = f.read()
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/ubuntu-18.04/crontab.out'), 'r') as f:
self.ubuntu_18_4_crontab = f.read()
# output
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/centos-7.7/crontab.json'), 'r') as f:
self.centos_7_7_crontab_json = json.loads(f.read())
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/ubuntu-18.04/crontab.json'), 'r') as f:
self.ubuntu_18_4_crontab_json = json.loads(f.read())
def test_crontab_centos_7_7(self):
"""
Test 'crontab' on Centos 7.7
"""
self.assertEqual(jc.parsers.crontab.parse(self.centos_7_7_crontab, quiet=True), self.centos_7_7_crontab_json)
def test_crontab_ubuntu_18_4(self):
"""
Test 'crontab' on Ubuntu 18.4
"""
self.assertEqual(jc.parsers.crontab.parse(self.ubuntu_18_4_crontab, quiet=True), self.ubuntu_18_4_crontab_json)
if __name__ == '__main__':
unittest.main()

40
tests/test_crontab_u.py Normal file
View File

@ -0,0 +1,40 @@
import os
import json
import unittest
import jc.parsers.crontab_u
THIS_DIR = os.path.dirname(os.path.abspath(__file__))
class MyTests(unittest.TestCase):
def setUp(self):
# input
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/ubuntu-18.04/crontab-u.out'), 'r') as f:
self.ubuntu_18_4_crontab_u = f.read()
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/centos-7.7/crontab-u.out'), 'r') as f:
self.centos_7_7_crontab_u = f.read()
# output
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/ubuntu-18.04/crontab-u.json'), 'r') as f:
self.ubuntu_18_4_crontab_u_json = json.loads(f.read())
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/centos-7.7/crontab-u.json'), 'r') as f:
self.centos_7_7_crontab_u_json = json.loads(f.read())
def test_crontab_u_ubuntu_18_4(self):
"""
Test 'crontab' on Ubuntu 18.4 (has a user field)
"""
self.assertEqual(jc.parsers.crontab_u.parse(self.ubuntu_18_4_crontab_u, quiet=True), self.ubuntu_18_4_crontab_u_json)
def test_crontab_u_centos_7_7(self):
"""
Test 'crontab' on Centos 7.7 (has a user field)
"""
self.assertEqual(jc.parsers.crontab_u.parse(self.centos_7_7_crontab_u, quiet=True), self.centos_7_7_crontab_u_json)
if __name__ == '__main__':
unittest.main()

40
tests/test_id.py Normal file
View File

@ -0,0 +1,40 @@
import os
import json
import unittest
import jc.parsers.id
THIS_DIR = os.path.dirname(os.path.abspath(__file__))
class MyTests(unittest.TestCase):
def setUp(self):
# input
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/centos-7.7/id.out'), 'r') as f:
self.centos_7_7_id = f.read()
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/osx-10.14.6/id.out'), 'r') as f:
self.osx_10_14_6_id = f.read()
# output
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/centos-7.7/id.json'), 'r') as f:
self.centos_7_7_id_json = json.loads(f.read())
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/osx-10.14.6/id.json'), 'r') as f:
self.osx_10_14_6_id_json = json.loads(f.read())
def test_id_centos_7_7(self):
"""
Test 'id' on Centos 7.7
"""
self.assertEqual(jc.parsers.id.parse(self.centos_7_7_id, quiet=True), self.centos_7_7_id_json)
def test_id_osx_10_14_6(self):
"""
Test 'id' on OSX 10.14.6
"""
self.assertEqual(jc.parsers.id.parse(self.osx_10_14_6_id, quiet=True), self.osx_10_14_6_id_json)
if __name__ == '__main__':
unittest.main()

40
tests/test_ini.py Normal file
View File

@ -0,0 +1,40 @@
import os
import unittest
import json
import jc.parsers.ini
THIS_DIR = os.path.dirname(os.path.abspath(__file__))
class MyTests(unittest.TestCase):
def setUp(self):
# input
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/ini-test.ini'), 'r') as f:
self.generic_ini_test = f.read()
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/ini-iptelserver.ini'), 'r') as f:
self.generic_ini_iptelserver = f.read()
# output
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/ini-test.json'), 'r') as f:
self.generic_ini_test_json = json.loads(f.read())
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/ini-iptelserver.json'), 'r') as f:
self.generic_ini_iptelserver_json = json.loads(f.read())
def test_ini_test(self):
"""
Test the test ini file
"""
self.assertEqual(jc.parsers.ini.parse(self.generic_ini_test, quiet=True), self.generic_ini_test_json)
def test_ini_iptelserver(self):
"""
Test the iptelserver ini file
"""
self.assertEqual(jc.parsers.ini.parse(self.generic_ini_iptelserver, quiet=True), self.generic_ini_iptelserver_json)
if __name__ == '__main__':
unittest.main()

40
tests/test_xml.py Normal file
View File

@ -0,0 +1,40 @@
import os
import unittest
import json
import jc.parsers.xml
THIS_DIR = os.path.dirname(os.path.abspath(__file__))
class MyTests(unittest.TestCase):
def setUp(self):
# input
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/xml-cd_catalog.xml'), 'r') as f:
self.generic_xml_cd_catalog = f.read()
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/xml-foodmenu.xml'), 'r') as f:
self.generic_xml_foodmenu = f.read()
# output
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/xml-cd_catalog.json'), 'r') as f:
self.generic_xml_cd_catalog_json = json.loads(f.read())
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/xml-foodmenu.json'), 'r') as f:
self.generic_xml_foodmenu_json = json.loads(f.read())
def test_xml_cd_catalog(self):
"""
Test the cd catalog xml file
"""
self.assertEqual(jc.parsers.xml.parse(self.generic_xml_cd_catalog, quiet=True), self.generic_xml_cd_catalog_json)
def test_xml_foodmenu(self):
"""
Test the food menu xml file
"""
self.assertEqual(jc.parsers.xml.parse(self.generic_xml_foodmenu, quiet=True), self.generic_xml_foodmenu_json)
if __name__ == '__main__':
unittest.main()

40
tests/test_yaml.py Normal file
View File

@ -0,0 +1,40 @@
import os
import unittest
import json
import jc.parsers.yaml
THIS_DIR = os.path.dirname(os.path.abspath(__file__))
class MyTests(unittest.TestCase):
def setUp(self):
# input
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/yaml-istio-sc.yaml'), 'r') as f:
self.generic_yaml_istio_sc = f.read()
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/yaml-istio-sidecar.yaml'), 'r') as f:
self.generic_yaml_istio_sidecar = f.read()
# output
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/yaml-istio-sc.json'), 'r') as f:
self.generic_yaml_istio_sc_json = json.loads(f.read())
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/yaml-istio-sidecar.json'), 'r') as f:
self.generic_yaml_istio_sidecar_json = json.loads(f.read())
def test_yaml_istio_sc(self):
"""
Test the Istio SC yaml file
"""
self.assertEqual(jc.parsers.yaml.parse(self.generic_yaml_istio_sc, quiet=True), self.generic_yaml_istio_sc_json)
def test_yaml_istio_sidecar(self):
"""
Test the Istio Sidecar yaml file
"""
self.assertEqual(jc.parsers.yaml.parse(self.generic_yaml_istio_sidecar, quiet=True), self.generic_yaml_istio_sidecar_json)
if __name__ == '__main__':
unittest.main()