Add error detection
This commit is contained in:
@@ -1,51 +1,87 @@
|
|||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
def parse_file(file_path):
|
def parse_file(file_path):
|
||||||
results = []
|
recap_results = []
|
||||||
|
failed_tasks = defaultdict(list)
|
||||||
|
|
||||||
with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
|
with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
|
||||||
for line in f:
|
lines = f.readlines()
|
||||||
|
|
||||||
# Look for lines containing recap info
|
current_task = None
|
||||||
if "ok=" in line and "failed=" in line and "unreachable=" in line:
|
|
||||||
|
|
||||||
# Extract host (first non-time token before :)
|
for i, line in enumerate(lines):
|
||||||
host_match = re.search(r"(?:\d{2}:\d{2}:\d{2}\s+)?(\S+)\s+:", line)
|
|
||||||
if not host_match:
|
|
||||||
continue
|
|
||||||
|
|
||||||
host = host_match.group(1)
|
# -------------------------
|
||||||
|
# 1. Detect TASK name
|
||||||
|
# -------------------------
|
||||||
|
task_match = re.search(r"TASK \[(.*?)\]", line)
|
||||||
|
if task_match:
|
||||||
|
current_task = task_match.group(1)
|
||||||
|
|
||||||
# Extract values individually (order-independent)
|
# -------------------------
|
||||||
def get_value(field):
|
# 2. Detect FAILED lines
|
||||||
match = re.search(rf"{field}=(\d+)", line)
|
# -------------------------
|
||||||
return int(match.group(1)) if match else 0
|
fail_match = re.search(r"fatal: \[(.*?)\]: FAILED!", line)
|
||||||
|
if fail_match:
|
||||||
|
host = fail_match.group(1)
|
||||||
|
|
||||||
ok = get_value("ok")
|
# Try to grab error message from same or next lines
|
||||||
changed = get_value("changed")
|
error_msg = ""
|
||||||
unreachable = get_value("unreachable")
|
|
||||||
failed = get_value("failed")
|
|
||||||
|
|
||||||
status = (
|
# Look ahead a few lines to capture reason
|
||||||
"UNREACHABLE" if unreachable > 0
|
for j in range(i, min(i + 5, len(lines))):
|
||||||
else "FAILED" if failed > 0
|
if "msg" in lines[j] or "stderr" in lines[j]:
|
||||||
else "OK"
|
error_msg += lines[j].strip() + " "
|
||||||
)
|
|
||||||
|
|
||||||
results.append({
|
if not error_msg:
|
||||||
"host": host,
|
error_msg = "Unknown error"
|
||||||
"ok": ok,
|
|
||||||
"changed": changed,
|
|
||||||
"unreachable": unreachable,
|
|
||||||
"failed": failed,
|
|
||||||
"status": status
|
|
||||||
})
|
|
||||||
|
|
||||||
return results
|
failed_tasks[host].append({
|
||||||
|
"task": current_task,
|
||||||
|
"error": error_msg.strip()
|
||||||
|
})
|
||||||
|
|
||||||
|
# -------------------------
|
||||||
|
# 3. Parse PLAY RECAP lines
|
||||||
|
# -------------------------
|
||||||
|
if "ok=" in line and "failed=" in line and "unreachable=" in line:
|
||||||
|
|
||||||
|
host_match = re.search(r"(?:\d{2}:\d{2}:\d{2}\s+)?(\S+)\s+:", line)
|
||||||
|
if not host_match:
|
||||||
|
continue
|
||||||
|
|
||||||
|
host = host_match.group(1)
|
||||||
|
|
||||||
|
def get_value(field):
|
||||||
|
match = re.search(rf"{field}=(\d+)", line)
|
||||||
|
return int(match.group(1)) if match else 0
|
||||||
|
|
||||||
|
ok = get_value("ok")
|
||||||
|
changed = get_value("changed")
|
||||||
|
unreachable = get_value("unreachable")
|
||||||
|
failed = get_value("failed")
|
||||||
|
|
||||||
|
status = (
|
||||||
|
"UNREACHABLE" if unreachable > 0
|
||||||
|
else "FAILED" if failed > 0
|
||||||
|
else "OK"
|
||||||
|
)
|
||||||
|
|
||||||
|
recap_results.append({
|
||||||
|
"host": host,
|
||||||
|
"ok": ok,
|
||||||
|
"changed": changed,
|
||||||
|
"unreachable": unreachable,
|
||||||
|
"failed": failed,
|
||||||
|
"status": status
|
||||||
|
})
|
||||||
|
|
||||||
|
return recap_results, failed_tasks
|
||||||
|
|
||||||
|
|
||||||
def print_report(results):
|
def print_report(results, failed_tasks):
|
||||||
unreachable_hosts = []
|
unreachable_hosts = []
|
||||||
failed_hosts = []
|
failed_hosts = []
|
||||||
|
|
||||||
@@ -68,7 +104,22 @@ def print_report(results):
|
|||||||
print("\nFAILED HOSTS:")
|
print("\nFAILED HOSTS:")
|
||||||
print("\n".join(failed_hosts) if failed_hosts else " None")
|
print("\n".join(failed_hosts) if failed_hosts else " None")
|
||||||
|
|
||||||
|
# -------------------------
|
||||||
|
# NEW SECTION
|
||||||
|
# -------------------------
|
||||||
|
print("\n=== FAILED TASK DETAILS ===")
|
||||||
|
|
||||||
|
if not failed_tasks:
|
||||||
|
print(" No failed tasks detected")
|
||||||
|
return
|
||||||
|
|
||||||
|
for host, tasks in failed_tasks.items():
|
||||||
|
print(f"\n{host}")
|
||||||
|
for t in tasks:
|
||||||
|
print(f" Task: {t['task']}")
|
||||||
|
print(f" Error: {t['error']}")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
results = parse_file(sys.argv[1])
|
results, failed_tasks = parse_file(sys.argv[1])
|
||||||
print_report(results)
|
print_report(results, failed_tasks)
|
||||||
Reference in New Issue
Block a user