From e4611f55ae3d365029d982f9e04bb1eb34791a5d Mon Sep 17 00:00:00 2001 From: Branden Pleines <13591727+bpleines@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:20:42 -0800 Subject: [PATCH 01/11] feat: static code analysis --- .github/workflows/static-code-analysis.yaml | 33 +++++++++++++++++++++ README.md | 13 ++++---- ansibleLogParser.py | 8 ++--- requirements.txt | 1 + 4 files changed, 44 insertions(+), 11 deletions(-) create mode 100644 .github/workflows/static-code-analysis.yaml create mode 100644 requirements.txt diff --git a/.github/workflows/static-code-analysis.yaml b/.github/workflows/static-code-analysis.yaml new file mode 100644 index 0000000..3137765 --- /dev/null +++ b/.github/workflows/static-code-analysis.yaml @@ -0,0 +1,33 @@ +--- +name: static-code-analysis +on: + pull_request: + push: + branches: main +jobs: + python: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: + - "2.7" + - "3.6" + - "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 diff --git a/README.md b/README.md index 4c6a0c1..350ab83 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ # 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. @@ -7,7 +6,7 @@ _tested on Tower v3.0.3 & v3.2.3_ ## Usage: `ansibleLogParser.py -h` - + ``` usage: ansibleLogParser.py [-h] -l LOGFILE [-c CRITERIA] [-o OUTPUT] @@ -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` +`ansibleLogParser.py -l ansibleDiskmapLogTest.txt` ``` Successes: 6 @@ -49,7 +48,7 @@ rhtubtib66.prod.redhat.com ``` ### Show only success output -`ansibleLogParser.py -l ansibleDiskmapLogTest.txt -c success` +`ansibleLogParser.py -l ansibleDiskmapLogTest.txt -c success` ``` Successes: 6 rhtudhtltapp.prod.redhat.com @@ -61,7 +60,7 @@ rhtudhuatweb.prod.redhat.com ``` ### Show only failure output -`ansibleLogParser.py -l ansibleDiskmapLogTest.txt -c failure` +`ansibleLogParser.py -l ansibleDiskmapLogTest.txt -c failure` ``` Failures: 4 rhtubtib23.prod.redhat.com @@ -71,7 +70,7 @@ rhtudeip2.prod.redhat.com ``` ### Show only unreachable output -`ansibleLogParser.py -l ansibleDiskmapLogTest.txt -c unreachable` +`ansibleLogParser.py -l ansibleDiskmapLogTest.txt -c unreachable` ``` Unreachable: 1 rhtubtib66.prod.redhat.com diff --git a/ansibleLogParser.py b/ansibleLogParser.py index 5472771..6600b3d 100644 --- a/ansibleLogParser.py +++ b/ansibleLogParser.py @@ -10,8 +10,8 @@ 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") - exit(1) + print("The --criteria or -c option must be one of: all, success, failure, or unreachable") + exit(1) def printSummary(): hitRecap = False @@ -39,12 +39,12 @@ def printSummary(): else: #This should theortically never run pass - + #+= syntax chosen for readability - could use join() with a list instead outputFileString = '' if 'all' in args.criteria: outputFileString += "Successes: " + str(len(successes)) + "\n" - for success in successes: + for success in successes: outputFileString += success + "\n" outputFileString += "\nFailures: " + str(len(failures)) + "\n" for failure in failures: diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..c034708 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +pylint==3.0.2 From a71e1f8f036d05dd2f7e5159fca1cda1115fd6e1 Mon Sep 17 00:00:00 2001 From: Branden Pleines <13591727+bpleines@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:24:27 -0800 Subject: [PATCH 02/11] feat: static code analysis --- .github/workflows/static-code-analysis.yaml | 6 ++++-- .pylintrc | 6 ++++++ 2 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 .pylintrc diff --git a/.github/workflows/static-code-analysis.yaml b/.github/workflows/static-code-analysis.yaml index 3137765..d840efc 100644 --- a/.github/workflows/static-code-analysis.yaml +++ b/.github/workflows/static-code-analysis.yaml @@ -11,8 +11,10 @@ jobs: fail-fast: false matrix: python-version: - - "2.7" - - "3.6" + # :( https://github.com/actions/setup-python/issues/672 + # - "2.7" + - "3.7" + - "3.8" - "3.9" - "3.10" - "3.11" diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 0000000..609f2d0 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,6 @@ +[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 From 12f10856c82e74bc2e0b51ad77aef14353067580 Mon Sep 17 00:00:00 2001 From: Branden Pleines <13591727+bpleines@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:25:23 -0800 Subject: [PATCH 03/11] feat: static code analysis --- ansibleLogParser.py | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/ansibleLogParser.py b/ansibleLogParser.py index 6600b3d..990042b 100644 --- a/ansibleLogParser.py +++ b/ansibleLogParser.py @@ -41,45 +41,45 @@ def printSummary(): pass #+= syntax chosen for readability - could use join() with a list instead - outputFileString = '' + output_file_string = '' if 'all' in args.criteria: - outputFileString += "Successes: " + str(len(successes)) + "\n" + output_file_string += "Successes: " + str(len(successes)) + "\n" for success in successes: - outputFileString += success + "\n" - outputFileString += "\nFailures: " + str(len(failures)) + "\n" + output_file_string += success + "\n" + output_file_string += "\nFailures: " + str(len(failures)) + "\n" for failure in failures: - outputFileString += failure + "\n" - outputFileString += "\nUnreachables: " + str(len(unreachables)) + "\n" + output_file_string += failure + "\n" + output_file_string += "\nUnreachables: " + str(len(unreachables)) + "\n" for unreachable in unreachables: - outputFileString += unreachable + "\n" - finalize(outputFileString) + output_file_string += unreachable + "\n" + finalize(output_file_string) allHostnames = [successes, failures, unreachables] return allHostnames elif 'success' in args.criteria: - outputFileString += "Successes: " + str(len(successes)) + "\n" + output_file_string += "Successes: " + str(len(successes)) + "\n" for success in successes: - outputFileString += success + "\n" - finalize(outputFileString) + output_file_string += success + "\n" + finalize(output_file_string) return successes elif 'failure' in args.criteria: - outputFileString += "Failures: " + str(len(failures)) + "\n" + output_file_string += "Failures: " + str(len(failures)) + "\n" for failure in failures: - outputFileString += failure + "\n" - finalize(outputFileString) + output_file_string += failure + "\n" + finalize(output_file_string) return failures elif 'unreachable' in args.criteria: - outputFileString += "Unreachables: " + str(len(unreachables)) + "\n" + output_file_string += "Unreachables: " + str(len(unreachables)) + "\n" for unreachable in unreachables: - outputFileString += unreachable + "\n" - finalize(outputFileString) + output_file_string += unreachable + "\n" + finalize(output_file_string) return unreachables else: pass -def finalize(outputFileString): - print(outputFileString) +def finalize(output_file_string): + print(output_file_string) if args.output: with open(args.output, 'w') as outputFile: - outputFile.write(outputFileString) + outputFile.write(output_file_string) result = printSummary() From e050e36829b26b1dde8fa5bbfeaafb28fc759da2 Mon Sep 17 00:00:00 2001 From: Branden Pleines <13591727+bpleines@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:27:04 -0800 Subject: [PATCH 04/11] feat: static code analysis --- ansibleLogParser.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ansibleLogParser.py b/ansibleLogParser.py index 990042b..aa8937e 100644 --- a/ansibleLogParser.py +++ b/ansibleLogParser.py @@ -14,19 +14,19 @@ exit(1) def printSummary(): - hitRecap = False + hit_recap = False successes = [] failures = [] unreachables = [] with open(args.logfile, 'r') as log: for line in log: - if 'PLAY RECAP' in line and not hitRecap: - hitRecap = True - elif hitRecap: + 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: - nextLine = line[6:] - hostname, tasks = nextLine.split('[0m', 1) + next_line = line[6:] + hostname, tasks = next_line.split('[0m', 1) #Tower 3.2.3 log compatible else: hostname, tasks = line.split(' : ',1) From 72ed94e2bcc7736cea56c1a745f8288a9bfd5e84 Mon Sep 17 00:00:00 2001 From: Branden Pleines <13591727+bpleines@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:32:30 -0800 Subject: [PATCH 05/11] feat: static code analysis --- ansibleLogParser.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/ansibleLogParser.py b/ansibleLogParser.py index aa8937e..719be9a 100644 --- a/ansibleLogParser.py +++ b/ansibleLogParser.py @@ -2,6 +2,7 @@ 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') @@ -10,10 +11,10 @@ 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") - exit(1) + print("The --criteria or -c option must be one of: all, success, failure, or unreachable") + exit(1) -def printSummary(): +def print_summary(): hit_recap = False successes = [] failures = [] @@ -53,8 +54,8 @@ def printSummary(): for unreachable in unreachables: output_file_string += unreachable + "\n" finalize(output_file_string) - allHostnames = [successes, failures, unreachables] - return allHostnames + 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: @@ -79,7 +80,7 @@ def printSummary(): def finalize(output_file_string): print(output_file_string) if args.output: - with open(args.output, 'w') as outputFile: - outputFile.write(output_file_string) + with open(args.output, 'w') as output_file: + output_file.write(output_file_string) -result = printSummary() +result = print_summary() From a5244552ac86b517710302335fb0675b5bbb88ce Mon Sep 17 00:00:00 2001 From: Branden Pleines <13591727+bpleines@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:34:04 -0800 Subject: [PATCH 06/11] feat: static code analysis --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index c034708..7fb0ea1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -pylint==3.0.2 +pylint From e1640fa4c7c986067f0cc7951cb82c0dbded1562 Mon Sep 17 00:00:00 2001 From: Branden Pleines <13591727+bpleines@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:36:22 -0800 Subject: [PATCH 07/11] feat: static code analysis --- ansibleLogParser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ansibleLogParser.py b/ansibleLogParser.py index 719be9a..ba17dba 100644 --- a/ansibleLogParser.py +++ b/ansibleLogParser.py @@ -12,14 +12,14 @@ if args.criteria not in ['all','success','failure','unreachable']: print("The --criteria or -c option must be one of: all, success, failure, or unreachable") - exit(1) + sys.exit(1) def print_summary(): hit_recap = False successes = [] failures = [] unreachables = [] - with open(args.logfile, 'r') as log: + 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 From 606dac96b367116dfe29d835d0ff7aa93d56952a Mon Sep 17 00:00:00 2001 From: Branden Pleines <13591727+bpleines@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:37:49 -0800 Subject: [PATCH 08/11] feat: static code analysis --- ansibleLogParser.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/ansibleLogParser.py b/ansibleLogParser.py index ba17dba..8cabca1 100644 --- a/ansibleLogParser.py +++ b/ansibleLogParser.py @@ -5,8 +5,18 @@ 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( + '-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() From 4079a64d0aae732a32afafb244862721c45d286f Mon Sep 17 00:00:00 2001 From: Branden Pleines <13591727+bpleines@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:39:59 -0800 Subject: [PATCH 09/11] feat: static code analysis --- README.md | 12 ++++++------ ansibleLogParser.py => ansible_log_parser.py | 0 2 files changed, 6 insertions(+), 6 deletions(-) rename ansibleLogParser.py => ansible_log_parser.py (100%) diff --git a/README.md b/README.md index 350ab83..5a75359 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,10 @@ The following script uses python to parse an Ansible Tower log file into success _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 @@ -26,7 +26,7 @@ optional arguments: ### Show all output -`ansibleLogParser.py -l ansibleDiskmapLogTest.txt` +`python ansible_log_parser.py -l ansibleDiskmapLogTest.txt` ``` Successes: 6 @@ -48,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 @@ -60,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 @@ -70,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 diff --git a/ansibleLogParser.py b/ansible_log_parser.py similarity index 100% rename from ansibleLogParser.py rename to ansible_log_parser.py From 62b6c03a8350fae8e318e196048dc9319567aed8 Mon Sep 17 00:00:00 2001 From: Branden Pleines <13591727+bpleines@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:40:47 -0800 Subject: [PATCH 10/11] feat: static code analysis --- ansible_log_parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ansible_log_parser.py b/ansible_log_parser.py index 8cabca1..a3743c0 100644 --- a/ansible_log_parser.py +++ b/ansible_log_parser.py @@ -90,7 +90,7 @@ def print_summary(): def finalize(output_file_string): print(output_file_string) if args.output: - with open(args.output, 'w') as output_file: + with open(args.output, 'w', encoding="utf-8") as output_file: output_file.write(output_file_string) result = print_summary() From 668716e92c210aaefd0c49e3baf86ab2bc32447d Mon Sep 17 00:00:00 2001 From: Branden Pleines <13591727+bpleines@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:44:08 -0800 Subject: [PATCH 11/11] feat: static code analysis --- .pylintrc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.pylintrc b/.pylintrc index 609f2d0..859c0c6 100644 --- a/.pylintrc +++ b/.pylintrc @@ -4,3 +4,6 @@ # 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