1
0
mirror of https://github.com/kellyjonbrazil/jc.git synced 2026-04-03 17:44:07 +02:00

Compare commits

..

58 Commits

Author SHA1 Message Date
Kelly Brazil
77d334f7f3 Merge pull request #19 from kellyjonbrazil/dev-1.7.1
Dev v1.7.1
2020-02-05 16:59:52 -08:00
Kelly Brazil
53cdf863ac changelog update 2020-02-05 16:53:17 -08:00
Kelly Brazil
7b7e7fe0fe changelog update 2020-02-05 16:50:55 -08:00
Kelly Brazil
0c03132847 fix error codes using sys.exit() 2020-02-05 16:18:58 -08:00
Kelly Brazil
3b81f7e2a1 exit code on ctrl-c exit 2020-02-05 16:12:09 -08:00
Kelly Brazil
3d76437b43 doc fix 2020-02-05 16:00:23 -08:00
Kelly Brazil
4bc54c78ce fix compatibility list 2020-02-05 16:00:10 -08:00
Kelly Brazil
3d303a96b9 crontab bug fix and tests 2020-02-05 15:52:39 -08:00
Kelly Brazil
33c99d031d fix line clobbering bug 2020-02-05 15:12:59 -08:00
Kelly Brazil
caf7e9f69a fix line clobbering bug and add user field to shortcuts 2020-02-05 15:11:51 -08:00
Kelly Brazil
9449f1f5d5 crontab bugfix: inserting header row was clobbering the first data row 2020-02-05 14:44:49 -08:00
Kelly Brazil
6bad164b5e simplify by removing unnecessary getattr calls 2020-02-05 14:10:22 -08:00
Kelly Brazil
bb5ba7ddb1 add indent variable to helptext 2020-02-05 13:57:34 -08:00
Kelly Brazil
8b2e01d540 doc update 2020-02-05 13:50:12 -08:00
Kelly Brazil
ff1159b1de exit codes on error 2020-02-05 11:45:17 -08:00
Kelly Brazil
a2fd3202a0 description formatting change 2020-02-05 11:34:33 -08:00
Kelly Brazil
7b53715b91 change description 2020-02-05 11:08:58 -08:00
Kelly Brazil
e05fc0a510 change padding of helptext 2020-02-05 11:08:47 -08:00
Kelly Brazil
43604c33f6 doc update 2020-02-05 10:59:51 -08:00
Kelly Brazil
eb67c484ff add crontab-u to parsers list 2020-02-05 10:58:26 -08:00
Kelly Brazil
a7b7bdd467 load parser modules 'just in time' so we don't need to load all modules at startup 2020-02-05 10:55:08 -08:00
Kelly Brazil
ab06989a18 description updates 2020-02-04 21:46:52 -08:00
Kelly Brazil
657b722f94 ini to INI 2020-02-04 21:44:10 -08:00
Kelly Brazil
dd2aecad27 description update 2020-02-04 21:37:07 -08:00
Kelly Brazil
c82c5c5c64 changelog update 2020-02-04 21:34:57 -08:00
Kelly Brazil
a1761cd68f id tests 2020-02-04 21:25:33 -08:00
Kelly Brazil
d618a7f583 doc update 2020-02-04 21:17:03 -08:00
Kelly Brazil
831a42f660 id formatting 2020-02-04 21:12:32 -08:00
Kelly Brazil
3b36022e5a add id parser 2020-02-04 21:09:42 -08:00
Kelly Brazil
d01dfa25f1 changelog updates 2020-02-04 15:22:36 -08:00
Kelly Brazil
395a99037b crontab-u and history doc updates 2020-02-04 14:36:03 -08:00
Kelly Brazil
025986c51d change history 'line' to integer 2020-02-04 14:31:28 -08:00
Kelly Brazil
c56b83093f doc update 2020-02-04 14:19:33 -08:00
Kelly Brazil
7c712a4133 doc update 2020-02-04 14:18:14 -08:00
Kelly Brazil
9a0cfe6dfa minor formatting 2020-02-04 14:18:01 -08:00
Kelly Brazil
a116cdbcec tests for crontab-u 2020-02-04 14:11:34 -08:00
Kelly Brazil
f2d616c98e add crontab with user parser 2020-02-04 14:02:27 -08:00
Kelly Brazil
42cbd1777d add xml and yaml tests 2020-02-04 13:53:45 -08:00
Kelly Brazil
ebf375aac0 add ini tests 2020-02-04 12:18:31 -08:00
Kelly Brazil
1f9050267e add ini, xml, and yaml test files 2020-02-04 12:02:18 -08:00
Kelly Brazil
d7f9707a15 minor formatting 2020-02-04 11:18:32 -08:00
Kelly Brazil
ab589ee3ed add __version__ variable 2020-02-04 11:18:15 -08:00
Kelly Brazil
c84ec0361f xml example update 2020-02-03 22:25:30 -08:00
Kelly Brazil
47d2f8968a doc update 2020-02-03 22:21:40 -08:00
Kelly Brazil
019c480bcc update acknowledgments 2020-02-03 22:17:13 -08:00
Kelly Brazil
547c6d3d59 add xml parser 2020-02-03 22:13:06 -08:00
Kelly Brazil
b5ebf8b76a add ruamel.yaml ack 2020-02-03 21:41:53 -08:00
Kelly Brazil
c690e328f2 add examples 2020-02-03 21:38:21 -08:00
Kelly Brazil
cbb92c1a95 add ini and yaml 2020-02-03 21:38:08 -08:00
Kelly Brazil
beb41997c9 doc update 2020-02-03 21:28:11 -08:00
Kelly Brazil
755a6faf11 clean up multi-document support 2020-02-03 21:22:30 -08:00
Kelly Brazil
021f8350a3 update doc 2020-02-03 19:11:36 -08:00
Kelly Brazil
76583dcd2f add ini file parser 2020-02-03 19:07:31 -08:00
Kelly Brazil
bf033239a7 doc update 2020-02-03 16:20:38 -08:00
Kelly Brazil
eb37fccd37 doc update 2020-02-03 16:17:29 -08:00
Kelly Brazil
d04ad45331 setup for 1.7.1 2020-02-03 16:12:45 -08:00
Kelly Brazil
db157b8ca7 add yaml file parser 2020-02-03 16:12:32 -08:00
Kelly Brazil
68f277bb20 add __version__ 2020-02-03 16:11:58 -08:00
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()