Skip to content

Commit

Permalink
Merge pull request #7 from bpleines/static_code_analysis
Browse files Browse the repository at this point in the history
feat: static code analysis
  • Loading branch information
bpleines authored Nov 17, 2023
2 parents ad4eb1b + 668716e commit 019f046
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 94 deletions.
35 changes: 35 additions & 0 deletions .github/workflows/static-code-analysis.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
name: static-code-analysis
on:
pull_request:
push:
branches: main
jobs:
python:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version:
# :( https://github.com/actions/setup-python/issues/672
# - "2.7"
- "3.7"
- "3.8"
- "3.9"
- "3.10"
- "3.11"
steps:
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Analysing the code with pylint
run: pylint **.py
9 changes: 9 additions & 0 deletions .pylintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[MESSAGES CONTROL]
# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifier separated by comma (,) or put this option
# multiple time (only on the command line, not in the configuration file where
# it should appear only once).
disable=C0114,C0115,C0116,W1203,W0104,C0415

[MAIN]
fail-under=9.28
17 changes: 8 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
# Ansible Tower Log Parser
_tested on python2.7 & 3.6_

The following script uses python to parse an Ansible Tower log file into successes, failures, and unreachables by hostname. Ansible Tower jobs can run against large inventories and there are times that digging through the Play Recap can be a cumbersome task. This script is designed to remove human assessment and quickly return a summary of a job to the terminal or in an output file.

_tested on Tower v3.0.3 & v3.2.3_

## Usage:
`ansibleLogParser.py -h`
`python ansible_log_parser.py -h`

```
usage: ansibleLogParser.py [-h] -l LOGFILE [-c CRITERIA] [-o OUTPUT]
usage: python ansible_log_parser.py [-h] -l LOGFILE [-c CRITERIA] [-o OUTPUT]
optional arguments:
-h, --help show this help message and exit
Expand All @@ -22,12 +21,12 @@ optional arguments:
-o OUTPUT, --output OUTPUT
Additionally direct printed information to an output file
```

## Example Usage and Outputs:

### Show all output

`ansibleLogParser.py -l ansibleDiskmapLogTest.txt`
`python ansible_log_parser.py -l ansibleDiskmapLogTest.txt`

```
Successes: 6
Expand All @@ -49,7 +48,7 @@ rhtubtib66.prod.redhat.com
```
### Show only success output
`ansibleLogParser.py -l ansibleDiskmapLogTest.txt -c success`
`python ansible_log_parser.py -l ansibleDiskmapLogTest.txt -c success`
```
Successes: 6
rhtudhtltapp.prod.redhat.com
Expand All @@ -61,7 +60,7 @@ rhtudhuatweb.prod.redhat.com
```

### Show only failure output
`ansibleLogParser.py -l ansibleDiskmapLogTest.txt -c failure`
`python ansible_log_parser.py -l ansibleDiskmapLogTest.txt -c failure`
```
Failures: 4
rhtubtib23.prod.redhat.com
Expand All @@ -71,7 +70,7 @@ rhtudeip2.prod.redhat.com
```

### Show only unreachable output
`ansibleLogParser.py -l ansibleDiskmapLogTest.txt -c unreachable`
`python ansible_log_parser.py -l ansibleDiskmapLogTest.txt -c unreachable`
```
Unreachable: 1
rhtubtib66.prod.redhat.com
Expand Down
85 changes: 0 additions & 85 deletions ansibleLogParser.py

This file was deleted.

96 changes: 96 additions & 0 deletions ansible_log_parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#!/usr/bin/env python

import re
import argparse
import sys

parser = argparse.ArgumentParser()
parser.add_argument(
'-l',
'--logfile',
required=True,
help='The log file that you want to parse'
)
parser.add_argument(
'-c',
'--criteria',
default='all',
help='Whether you want to see "all" output parsed (default) or only the "success", "failure", or "unreachable" output'
)
parser.add_argument('-o', '--output', required=False, help='Specify an output file to store the output')
args = parser.parse_args()

if args.criteria not in ['all','success','failure','unreachable']:
print("The --criteria or -c option must be one of: all, success, failure, or unreachable")
sys.exit(1)

def print_summary():
hit_recap = False
successes = []
failures = []
unreachables = []
with open(args.logfile, 'r', encoding="utf-8") as log:
for line in log:
if 'PLAY RECAP' in line and not hit_recap:
hit_recap = True
elif hit_recap:
#Tower 3.0.3 log compatible
if '[0m' in line:
next_line = line[6:]
hostname, tasks = next_line.split('[0m', 1)
#Tower 3.2.3 log compatible
else:
hostname, tasks = line.split(' : ',1)
if 'unreachable=1' in tasks:
unreachables.append(hostname)
elif re.search('failed=[1-9+]', tasks):
failures.append(hostname)
else:
successes.append(hostname)
else:
#This should theortically never run
pass

#+= syntax chosen for readability - could use join() with a list instead
output_file_string = ''
if 'all' in args.criteria:
output_file_string += "Successes: " + str(len(successes)) + "\n"
for success in successes:
output_file_string += success + "\n"
output_file_string += "\nFailures: " + str(len(failures)) + "\n"
for failure in failures:
output_file_string += failure + "\n"
output_file_string += "\nUnreachables: " + str(len(unreachables)) + "\n"
for unreachable in unreachables:
output_file_string += unreachable + "\n"
finalize(output_file_string)
all_hostnames = [successes, failures, unreachables]
return all_hostnames
elif 'success' in args.criteria:
output_file_string += "Successes: " + str(len(successes)) + "\n"
for success in successes:
output_file_string += success + "\n"
finalize(output_file_string)
return successes
elif 'failure' in args.criteria:
output_file_string += "Failures: " + str(len(failures)) + "\n"
for failure in failures:
output_file_string += failure + "\n"
finalize(output_file_string)
return failures
elif 'unreachable' in args.criteria:
output_file_string += "Unreachables: " + str(len(unreachables)) + "\n"
for unreachable in unreachables:
output_file_string += unreachable + "\n"
finalize(output_file_string)
return unreachables
else:
pass

def finalize(output_file_string):
print(output_file_string)
if args.output:
with open(args.output, 'w', encoding="utf-8") as output_file:
output_file.write(output_file_string)

result = print_summary()
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pylint

0 comments on commit 019f046

Please sign in to comment.