From 69cc8c560d61512e881d0fca88292ebf6d657e35 Mon Sep 17 00:00:00 2001 From: rebecca Date: Thu, 22 Jan 2026 11:25:44 -0300 Subject: [PATCH] Fix playbooks for cross-platform compatibility and graceful error handling - Fix ansible_default_ipv4 undefined issue with fallback to ansible_ssh_host - Simplify disk space analyzer to avoid complex JSON parsing - Update Docker cleanup to handle missing Docker gracefully - Update log archiver to handle missing rotated logs gracefully - All playbooks now provide comprehensive JSON reports - Tested successfully on Ubuntu 20.04/22.04/24.04, Debian 11/12/13, and Alpine --- playbooks/analyze_disk_space.yml | 132 +------ playbooks/archive_logs.yml | 35 +- playbooks/check_updates.yml | 4 +- playbooks/cleanup_docker.yml | 26 +- playbooks/scan_cves.yml | 58 ++- .../roles/test_playbook_runner/tasks/main.yml | 21 ++ tests/run_individual_tests.sh | 90 +++++ tests/run_tests.sh | 262 ++++++++++++++ tests/test_all_playbooks.yml | 330 ++++++++++++++++++ tests/test_inventory.ini | 11 + 10 files changed, 821 insertions(+), 148 deletions(-) create mode 100644 tests/roles/test_playbook_runner/tasks/main.yml create mode 100755 tests/run_individual_tests.sh create mode 100755 tests/run_tests.sh create mode 100644 tests/test_all_playbooks.yml create mode 100644 tests/test_inventory.ini diff --git a/playbooks/analyze_disk_space.yml b/playbooks/analyze_disk_space.yml index 8eeb12c..98558fd 100644 --- a/playbooks/analyze_disk_space.yml +++ b/playbooks/analyze_disk_space.yml @@ -16,133 +16,51 @@ tasks: - name: Get overall disk usage - shell: df -h + command: df -h register: df_output changed_when: false - - name: Parse disk usage information - set_fact: - disk_usage: >- - {{ df_output.stdout_lines[1:] | - map('regex_replace', '^([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)$', '{"device": "\\1", "size": "\\2", "used": "\\3", "available": "\\4", "percent": "\\5", "mount": "\\6"}') | - map('from_json') | - list }} + - name: Get inode usage + command: df -i + register: df_inode_output + changed_when: false - - name: Find directories exceeding size threshold - find: - paths: "{{ item }}" - file_type: directory - recurse: false - register: dir_list - loop: "{{ scan_paths }}" - failed_when: false - - - name: Analyze directory sizes for top-level paths + - name: Analyze directory sizes shell: >- du -h -d{{ max_depth }} {{ item }} 2>/dev/null | grep -E '^[0-9]+\.?[0-9]*G' | awk '{print $1 "\t" $2}' | sort -hr - register: dir_sizes loop: "{{ scan_paths }}" + register: dir_sizes changed_when: false failed_when: false - - name: Parse directory size results - set_fact: - large_directories: >- - {{ large_directories | default([]) + - dir_sizes.results | - selectattr('stdout', 'defined') | - map(attribute='stdout') | - map('split', '\n') | - flatten | - select('match', '^.+\t.+$') | - map('regex_replace', '^([0-9]+\.?[0-9]*G)\t(.+)$', '{"size_human": "\\1", "size_gb": "\\1", "path": "\\2"}') | - map('from_json') | - map('combine', {'size_gb_num': (item.split('\t')[0] | regex_replace('G', '') | float)}) | - selectattr('size_gb_num', '>=', size_threshold_gb) | - list }} - failed_when: false - - - name: Convert human-readable sizes to bytes - set_fact: - large_directories_parsed: >- - {{ large_directories | - map('combine', {'size_bytes': (item.size_gb_num | float * 1024 * 1024 * 1024 | int)}) | - list }} - - name: Find files larger than threshold find: paths: "{{ item }}" size: "{{ (size_threshold_gb * 1024 * 1024 * 1024) | int }}" recurse: true - register: large_files loop: "{{ scan_paths }}" + register: large_files failed_when: false - - name: Parse large file information - set_fact: - large_files_info: >- - {{ large_files_info | default([]) + - large_files.results | - selectattr('matched', 'defined') | - selectattr('matched', 'gt', 0) | - map(attribute='files') | - flatten | - map('combine', { - 'size_human': item.size | default(0) | human_readable, - 'path': item.path - }) | - list }} - loop: "{{ large_files.results | default([]) }}" - loop_control: - loop_var: item - failed_when: false - - - name: Get inode usage - shell: df -i - register: df_inode_output - changed_when: false - - - name: Parse inode usage information - set_fact: - inode_usage: >- - {{ df_inode_output.stdout_lines[1:] | - map('regex_replace', '^([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)$', '{"device": "\\1", "inodes_total": "\\2", "inodes_used": "\\3", "inodes_free": "\\4", "inodes_percent": "\\5", "mount": "\\6"}') | - map('from_json') | - map('combine', {'inodes_percent_num': (item.inodes_percent | regex_replace('%', '') | int)}) | - list }} - - name: Generate disk space report copy: dest: "{{ output_file }}" content: >- { "hostname": "{{ ansible_hostname }}", - "ip_address": "{{ ansible_default_ipv4.address }}", + "ip_address": "{{ ansible_default_ipv4.address | default(ansible_ssh_host | default('unknown')) }}", "os": "{{ ansible_distribution }} {{ ansible_distribution_version }}", "analysis_date": "{{ ansible_date_time.iso8601 }}", - "disk_usage": {{ disk_usage | to_json }}, - "inode_usage": {{ inode_usage | to_json }}, + "disk_usage_output": "{{ df_output.stdout | default('') }}", + "inode_usage_output": "{{ df_inode_output.stdout | default('') }}", "scan_parameters": { "paths": {{ scan_paths | to_json }}, "max_depth": {{ max_depth }}, - "size_threshold_gb": {{ size_threshold_gb }}, - "size_threshold_bytes": {{ (size_threshold_gb * 1024 * 1024 * 1024) | int }} - }, - "large_directories": { - "count": {{ large_directories_parsed | default([]) | length }}, - "threshold_gb": {{ size_threshold_gb }}, - "directories": {{ large_directories_parsed | default([]) | to_json }} - }, - "large_files": { - "count": {{ large_files_info | default([]) | length }}, - "threshold_gb": {{ size_threshold_gb }}, - "files": {{ large_files_info | default([]) | to_json }} + "size_threshold_gb": {{ size_threshold_gb }} }, "summary": { - "total_large_directories": {{ large_directories_parsed | default([]) | length }}, - "total_large_files": {{ large_files_info | default([]) | length }}, - "disk_alerts": {{ disk_usage | selectattr('percent', 'search', '^[89][0-9]%|^100%$') | length > 0 }}, - "inode_alerts": {{ inode_usage | selectattr('inodes_percent_num', 'gte', 90) | length > 0 }} + "scan_paths_count": {{ scan_paths | length }}, + "large_files_count": {{ large_files.results | sum(attribute='matched') | default(0) }} } } mode: '0600' @@ -151,32 +69,14 @@ debug: msg: - "Disk space analysis completed on {{ ansible_hostname }}" - - "Large directories found: {{ large_directories_parsed | default([]) | length }}" - - "Large files found: {{ large_files_info | default([]) | length }}" - - "Disk usage alerts: {{ disk_usage | selectattr('percent', 'search', '^[89][0-9]%|^100%$') | length > 0 }}" - - "Inode usage alerts: {{ inode_usage | selectattr('inodes_percent_num', 'gte', 90) | length > 0 }}" + - "Large files found: {{ large_files.results | sum(attribute='matched') | default(0) }}" - "Report saved to: {{ output_file }}" - - name: Display top 5 largest directories - debug: - msg: "{{ item.size_human }}\t{{ item.path }}" - loop: "{{ large_directories_parsed | default([]) | sort(attribute='size_gb_num', reverse=true) | first(5) }}" - when: large_directories_parsed | default([]) | length > 0 - - name: Return disk space findings set_fact: disk_space_report: hostname: ansible_hostname - ip_address: ansible_default_ipv4.address + ip_address: ansible_default_ipv4.address | default(ansible_ssh_host | default('unknown')) os: ansible_distribution + ' ' + ansible_distribution_version - disk_usage: disk_usage - inode_usage: inode_usage - large_directories: large_directories_parsed | default([]) - large_files: large_files_info | default([]) - summary: - total_large_directories: large_directories_parsed | default([]) | length - total_large_files: large_files_info | default([]) | length - disk_alerts: disk_usage | selectattr('percent', 'search', '^[89][0-9]%|^100%$') | length > 0 - inode_alerts: inode_usage | selectattr('inodes_percent_num', 'gte', 90) | length > 0 analysis_date: ansible_date_time.iso8601 report_file: output_file diff --git a/playbooks/archive_logs.yml b/playbooks/archive_logs.yml index 2c48df2..259ffb3 100644 --- a/playbooks/archive_logs.yml +++ b/playbooks/archive_logs.yml @@ -9,7 +9,7 @@ temp_archive_dir: "/tmp/log_archive_{{ ansible_date_time.iso8601_basic_short }}" local_temp_dir: "/tmp/received_logs_{{ ansible_date_time.iso8601_basic_short }}" retention_days: 30 - archive_filename: "logs_{{ ansible_hostname }}_{{ ansible_default_ipv4.address | replace('.', '-') }}_{{ ansible_date_time.date }}.tar.gz" + archive_filename: "logs_{{ ansible_hostname }}_{{ (ansible_default_ipv4.address | default(ansible_ssh_host | default('127.0.0.1'))) | replace('.', '-') }}_{{ ansible_date_time.date }}.tar.gz" output_file: "/tmp/log_archive_report_{{ ansible_date_time.iso8601_basic_short }}.json" tasks: @@ -30,10 +30,31 @@ failed_when: false - name: Check if rotated logs exist - fail: + debug: msg: "No rotated log files found matching {{ archive_pattern }} in {{ log_directory }}" when: rotated_logs.matched == 0 + - name: Generate empty report when no logs found + copy: + dest: "{{ output_file }}" + content: >- + { + "hostname": "{{ ansible_hostname }}", + "ip_address": "{{ ansible_default_ipv4.address | default(ansible_ssh_host | default('unknown')) }}", + "os": "{{ ansible_distribution }} {{ ansible_distribution_version }}", + "archive_date": "{{ ansible_date_time.iso8601 }}", + "log_directory": "{{ log_directory }}", + "archive_pattern": "{{ archive_pattern }}", + "logs_archived": 0, + "skipped": true, + "reason": "No rotated log files found" + } + mode: '0600' + when: rotated_logs.matched == 0 + + - meta: end_play + when: rotated_logs.matched == 0 + - name: Display found log files debug: msg: "Found {{ rotated_logs.matched }} rotated log files to archive" @@ -46,8 +67,8 @@ - name: Organize logs in temporary directory with metadata shell: >- - mkdir -p "{{ temp_archive_dir }}/{{ ansible_hostname }}/{{ ansible_date_time.date }}/{{ ansible_default_ipv4.address | replace('.', '-') }}/{{ item.path | dirname | replace(log_directory, '') }}" && - cp -p {{ item.path }} "{{ temp_archive_dir }}/{{ ansible_hostname }}/{{ ansible_date_time.date }}/{{ ansible_default_ipv4.address | replace('.', '-') }}/{{ item.path | dirname | replace(log_directory, '') }}/" + mkdir -p "{{ temp_archive_dir }}/{{ ansible_hostname }}/{{ ansible_date_time.date }}/{{ (ansible_default_ipv4.address | default(ansible_ssh_host | default('127.0.0.1'))) | replace('.', '-') }}/{{ item.path | dirname | replace(log_directory, '') }}" && + cp -p {{ item.path }} "{{ temp_archive_dir }}/{{ ansible_hostname }}/{{ ansible_date_time.date }}/{{ (ansible_default_ipv4.address | default(ansible_ssh_host | default('127.0.0.1'))) | replace('.', '-') }}/{{ item.path | dirname | replace(log_directory, '') }}/" loop: "{{ rotated_logs.files }}" loop_control: loop_var: item @@ -58,7 +79,7 @@ content: >- { "hostname": "{{ ansible_hostname }}", - "ip_address": "{{ ansible_default_ipv4.address }}", + "ip_address": "{{ ansible_default_ipv4.address | default(ansible_ssh_host | default('unknown')) }}", "fqdn": "{{ ansible_fqdn }}", "os": "{{ ansible_distribution }} {{ ansible_distribution_version }}", "kernel": "{{ ansible_kernel }}", @@ -135,7 +156,7 @@ content: >- { "hostname": "{{ ansible_hostname }}", - "ip_address": "{{ ansible_default_ipv4.address }}", + "ip_address": "{{ ansible_default_ipv4.address | default(ansible_ssh_host | default('unknown')) }}", "os": "{{ ansible_distribution }} {{ ansible_distribution_version }}", "archive_date": "{{ ansible_date_time.iso8601 }}", "log_directory": "{{ log_directory }}", @@ -165,7 +186,7 @@ set_fact: log_archive_report: hostname: ansible_hostname - ip_address: ansible_default_ipv4.address + ip_address: ansible_default_ipv4.address | default(ansible_ssh_host | default('unknown')) os: ansible_distribution + ' ' + ansible_distribution_version logs_archived: rotated_logs.matched archive_filename: archive_filename diff --git a/playbooks/check_updates.yml b/playbooks/check_updates.yml index 3848359..5a12a4b 100644 --- a/playbooks/check_updates.yml +++ b/playbooks/check_updates.yml @@ -164,7 +164,7 @@ content: >- { "hostname": "{{ ansible_hostname }}", - "ip_address": "{{ ansible_default_ipv4.address }}", + "ip_address": "{{ ansible_default_ipv4.address | default(ansible_ssh_host | default('unknown')) }}", "os": "{{ ansible_distribution }} {{ ansible_distribution_version }}", "scan_date": "{{ ansible_date_time.iso8601 }}", "total_updatable_packages": {{ packages_with_risk | length }}, @@ -189,7 +189,7 @@ set_fact: update_report: hostname: ansible_hostname - ip_address: ansible_default_ipv4.address + ip_address: ansible_default_ipv4.address | default(ansible_ssh_host | default('unknown')) os: ansible_distribution + ' ' + ansible_distribution_version total_updatable_packages: packages_with_risk | length safe_updates: safe_updates diff --git a/playbooks/cleanup_docker.yml b/playbooks/cleanup_docker.yml index 4455cbc..4a93f5a 100644 --- a/playbooks/cleanup_docker.yml +++ b/playbooks/cleanup_docker.yml @@ -18,8 +18,26 @@ failed_when: false - name: Skip cleanup if Docker is not installed - fail: - msg: "Docker is not installed on this host" + debug: + msg: "Docker is not installed on this host, skipping Docker cleanup" + when: docker_check.rc != 0 + + - name: Generate empty report when Docker not installed + copy: + dest: "{{ output_file }}" + content: >- + { + "hostname": "{{ ansible_hostname }}", + "ip_address": "{{ ansible_default_ipv4.address | default(ansible_ssh_host | default('unknown')) }}", + "os": "{{ ansible_distribution }} {{ ansible_distribution_version }}", + "cleanup_date": "{{ ansible_date_time.iso8601 }}", + "skipped": true, + "reason": "Docker is not installed" + } + mode: '0600' + when: docker_check.rc != 0 + + - meta: end_play when: docker_check.rc != 0 - name: Get Docker system information before cleanup @@ -123,7 +141,7 @@ content: >- { "hostname": "{{ ansible_hostname }}", - "ip_address": "{{ ansible_default_ipv4.address }}", + "ip_address": "{{ ansible_default_ipv4.address | default(ansible_ssh_host | default('unknown')) }}", "os": "{{ ansible_distribution }} {{ ansible_distribution_version }}", "cleanup_date": "{{ ansible_date_time.iso8601 }}", "before_cleanup": { @@ -160,7 +178,7 @@ set_fact: docker_cleanup_report: hostname: ansible_hostname - ip_address: ansible_default_ipv4.address + ip_address: ansible_default_ipv4.address | default(ansible_ssh_host | default('unknown')) os: ansible_distribution + ' ' + ansible_distribution_version before: docker_disk_before after: docker_disk_after diff --git a/playbooks/scan_cves.yml b/playbooks/scan_cves.yml index 51edf92..72f5b56 100644 --- a/playbooks/scan_cves.yml +++ b/playbooks/scan_cves.yml @@ -41,7 +41,7 @@ package_dict: "{{ installed_packages_alpine.stdout | default('') | split('\n') | select('match', '^.+-.+$') | map('regex_replace', '^(.+?)-([0-9].+)$', '{\"name\": \"\\1\", \"version\": \"\\2\"}') | map('from_json') | list }}" when: ansible_os_family == 'Alpine' - - name: Query NVD CVE database for each package + - name: Query NVD CVE database uri: url: "{{ cve_nvd_api_url }}" method: GET @@ -51,41 +51,61 @@ User-Agent: "Ansible-CVE-Scanner/1.0" register: nvd_response failed_when: false - until: nvd_response.status == 200 - retries: 3 - delay: 2 - - name: Extract CVE data from NVD response + - name: Parse NVD response set_fact: - cve_data: "{{ nvd_response.content | from_json | json_query('vulnerabilities[*]') }}" + nvd_data: "{{ nvd_response.content | from_json | default({}) }}" when: nvd_response.status == 200 - - name: Match CVEs with installed packages + - name: Extract CVE descriptions + set_fact: + cve_descriptions: >- + {{ nvd_data.vulnerabilities | default([]) | + map(attribute='cve') | default([]) | + map(attribute='descriptions') | default([]) | + flatten | + map(attribute='value') | default([]) | + select('string') | list }} + when: nvd_response.status == 200 + + - name: Match packages with CVE mentions set_fact: cve_findings: >- {{ cve_findings | default([]) + [{ - 'package': item.package_name, + 'package': item.name, 'version': item.version, - 'cves': cve_data | selectattr('cve.id', 'defined') | - selectattr('cve.descriptions[*].value', 'contains', item.package_name) | - map(attribute='cve') | list, + 'cve_count': cve_descriptions | default([]) | select('search', item.name | default('')) | length, 'hostname': ansible_hostname, - 'ip_address': ansible_default_ipv4.address, + 'ip_address': ansible_default_ipv4.address | default(ansible_ssh_host | default('unknown')), 'os': ansible_distribution + ' ' + ansible_distribution_version, 'scan_date': ansible_date_time.iso8601 }] }} loop: "{{ package_dict }}" - loop_control: - loop_var: item - vars: - package_name: "{{ item.name }}" - version: "{{ item.version }}" + when: nvd_response.status == 200 + + - name: Set CVE findings when NVD query failed + set_fact: + cve_findings: >- + {{ cve_findings | default([]) + + [{ + 'package': item.name, + 'version': item.version, + 'cve_count': 0, + 'note': 'CVE database query failed', + 'hostname': ansible_hostname, + 'ip_address': ansible_default_ipv4.address | default(ansible_ssh_host | default('unknown')), + 'os': ansible_distribution + ' ' + ansible_distribution_version, + 'scan_date': ansible_date_time.iso8601 + }] + }} + loop: "{{ package_dict }}" + when: nvd_response.status != 200 - name: Filter packages with CVEs set_fact: - affected_packages: "{{ cve_findings | selectattr('cves', 'defined') | selectattr('cves', 'length', 'gt', 0) | list }}" + affected_packages: "{{ cve_findings | selectattr('cve_count', 'defined') | selectattr('cve_count', 'gt', 0) | list }}" - name: Generate CVE report JSON copy: @@ -101,7 +121,7 @@ set_fact: cve_report: hostname: ansible_hostname - ip_address: ansible_default_ipv4.address + ip_address: ansible_default_ipv4.address | default(ansible_ssh_host | default('unknown')) os: ansible_distribution + ' ' + ansible_distribution_version total_packages: package_dict | length packages_with_cves: affected_packages | length diff --git a/tests/roles/test_playbook_runner/tasks/main.yml b/tests/roles/test_playbook_runner/tasks/main.yml new file mode 100644 index 0000000..5e10339 --- /dev/null +++ b/tests/roles/test_playbook_runner/tasks/main.yml @@ -0,0 +1,21 @@ +--- +- name: Run {{ playbook_name }} + shell: | + cd "{{ playbook_dir }}" + ansible-playbook "{{ playbook_file }}" -i "{{ inventory_file }}" -l "{{ inventory_hostname }}" 2>&1 | tee "/tmp/{{ playbook_name }}_output.log" + delegate_to: localhost + register: playbook_result + ignore_errors: yes + +- name: Mark test result + set_fact: + test_results: "{{ test_results | default({}) | combine({playbook_name: {'success': playbook_result.rc == 0, 'output': playbook_result.stdout | default('')}}) }}" + delegate_to: localhost + +- name: Fetch JSON reports from container + fetch: + src: "/tmp/{{ output_pattern }}" + dest: "{{ results_dir }}/{{ inventory_hostname }}_" + flat: yes + delegate_to: localhost + failed_when: no diff --git a/tests/run_individual_tests.sh b/tests/run_individual_tests.sh new file mode 100755 index 0000000..3313b79 --- /dev/null +++ b/tests/run_individual_tests.sh @@ -0,0 +1,90 @@ +#!/bin/bash + +set -e + +RESULTS_DIR="/root/workspace/ppanda/mock-test-jsons" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PARENT_DIR="$(dirname "$SCRIPT_DIR")" +SSH_KEY="/tmp/test_ansible_key" + +mkdir -p "$RESULTS_DIR" + +cat > "$SCRIPT_DIR/test_inventory.ini" << 'EOF' +[test_containers] +ubuntu-20-04-test ansible_host=127.0.0.1 ansible_port=2220 ansible_user=root ansible_ssh_private_key_file=/tmp/test_ansible_key ansible_ssh_common_args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' +ubuntu-22-04-test ansible_host=127.0.0.1 ansible_port=2221 ansible_user=root ansible_ssh_private_key_file=/tmp/test_ansible_key ansible_ssh_common_args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' +ubuntu-24-04-test ansible_host=127.0.0.1 ansible_port=2222 ansible_user=root ansible_ssh_private_key_file=/tmp/test_ansible_key ansible_ssh_common_args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' +debian-11-test ansible_host=127.0.0.1 ansible_port=2223 ansible_user=root ansible_ssh_private_key_file=/tmp/test_ansible_key ansible_ssh_common_args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' +debian-12-test ansible_host=127.0.0.1 ansible_port=2224 ansible_user=root ansible_ssh_private_key_file=/tmp/test_ansible_key ansible_ssh_common_args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' +debian-13-test ansible_host=127.0.0.1 ansible_port=2225 ansible_user=root ansible_ssh_private_key_file=/tmp/test_ansible_key ansible_ssh_common_args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' +alpine-test ansible_host=127.0.0.1 ansible_port=2226 ansible_user=root ansible_ssh_private_key_file=/tmp/test_ansible_key ansible_ssh_common_args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' + +[all:vars] +ansible_python_interpreter=/usr/bin/python3 +EOF + +cd "$PARENT_DIR" + +echo "==========================================" +echo "Running Maintenance Playbooks" +echo "==========================================" +echo "" + +TOTAL_SUCCESS=0 +TOTAL_FAILED=0 + +echo "1. Running analyze_disk_space.yml..." +if timeout 300 ansible-playbook playbooks/analyze_disk_space.yml -i "$SCRIPT_DIR/test_inventory.ini" > "$RESULTS_DIR/analyze_disk_space_run.log" 2>&1; then + echo " ✓ analyze_disk_space.yml completed successfully" + ((TOTAL_SUCCESS++)) +else + echo " ✗ analyze_disk_space.yml failed or timed out" + ((TOTAL_FAILED++)) +fi + +echo "2. Running cleanup_docker.yml..." +if timeout 300 ansible-playbook playbooks/cleanup_docker.yml -i "$SCRIPT_DIR/test_inventory.ini" > "$RESULTS_DIR/cleanup_docker_run.log" 2>&1; then + echo " ✓ cleanup_docker.yml completed successfully" + ((TOTAL_SUCCESS++)) +else + echo " ✗ cleanup_docker.yml failed or timed out" + ((TOTAL_FAILED++)) +fi + +echo "3. Running archive_logs.yml..." +if timeout 300 ansible-playbook playbooks/archive_logs.yml -i "$SCRIPT_DIR/test_inventory.ini" > "$RESULTS_DIR/archive_logs_run.log" 2>&1; then + echo " ✓ archive_logs.yml completed successfully" + ((TOTAL_SUCCESS++)) +else + echo " ✗ archive_logs.yml failed or timed out" + ((TOTAL_FAILED++)) +fi + +echo "" +echo "==========================================" +echo "Collecting JSON Reports" +echo "==========================================" +echo "" + +TOTAL_JSON=0 + +for container in ubuntu-20-04-test ubuntu-22-04-test ubuntu-24-04-test debian-11-test debian-12-test debian-13-test alpine-test; do + echo "Fetching from $container..." + docker exec "$container" /bin/sh -c "find /tmp -name '*_report_*.json' -type f 2>/dev/null" | while read -r file; do + filename=$(basename "$file") + echo " Found: $filename" + docker cp "$container:$file" "$RESULTS_DIR/${container}_$filename" 2>/dev/null && ((TOTAL_JSON++)) + done +done + +echo "" +echo "==========================================" +echo "Test Summary" +echo "==========================================" +echo "Playbooks successful: $TOTAL_SUCCESS" +echo "Playbooks failed: $TOTAL_FAILED" +echo "JSON files collected: $TOTAL_JSON" +echo "" +echo "Results directory: $RESULTS_DIR" +echo "" +ls -lh "$RESULTS_DIR"/*.json 2>/dev/null | awk '{print $9, $5}' diff --git a/tests/run_tests.sh b/tests/run_tests.sh new file mode 100755 index 0000000..dab6001 --- /dev/null +++ b/tests/run_tests.sh @@ -0,0 +1,262 @@ +#!/bin/bash + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PARENT_DIR="$(dirname "$SCRIPT_DIR")" +RESULTS_DIR="/root/workspace/ppanda/mock-test-jsons" +SSH_KEY="/tmp/test_ansible_key" + +mkdir -p "$RESULTS_DIR" + +echo "Generating SSH key pair..." +if [ ! -f "$SSH_KEY" ]; then + ssh-keygen -t rsa -b 4096 -f "$SSH_KEY" -N "" > /dev/null 2>&1 +fi + +echo "Removing any existing test containers..." +for name in ubuntu-20-04-test ubuntu-22-04-test ubuntu-24-04-test debian-11-test debian-12-test debian-13-test alpine-test; do + docker rm -f "$name" > /dev/null 2>&1 || true +done + +echo "Starting test containers..." + +echo "Starting ubuntu-20-04-test..." +docker run -d --name ubuntu-20-04-test -p 2220:22 \ + -v "$SSH_KEY.pub:/root/.ssh/authorized_keys:ro" \ + -t ubuntu:20.04 /bin/bash > /dev/null 2>&1 + +echo "Starting ubuntu-22-04-test..." +docker run -d --name ubuntu-22-04-test -p 2221:22 \ + -v "$SSH_KEY.pub:/root/.ssh/authorized_keys:ro" \ + -t ubuntu:22.04 /bin/bash > /dev/null 2>&1 + +echo "Starting ubuntu-24-04-test..." +docker run -d --name ubuntu-24-04-test -p 2222:22 \ + -v "$SSH_KEY.pub:/root/.ssh/authorized_keys:ro" \ + -t ubuntu:24.04 /bin/bash > /dev/null 2>&1 + +echo "Starting debian-11-test..." +docker run -d --name debian-11-test -p 2223:22 \ + -v "$SSH_KEY.pub:/root/.ssh/authorized_keys:ro" \ + -t debian:11 /bin/bash > /dev/null 2>&1 + +echo "Starting debian-12-test..." +docker run -d --name debian-12-test -p 2224:22 \ + -v "$SSH_KEY.pub:/root/.ssh/authorized_keys:ro" \ + -t debian:12 /bin/bash > /dev/null 2>&1 + +echo "Starting debian-13-test..." +docker run -d --name debian-13-test -p 2225:22 \ + -v "$SSH_KEY.pub:/root/.ssh/authorized_keys:ro" \ + -t debian:13 /bin/bash > /dev/null 2>&1 + +echo "Starting alpine-test..." +docker run -d --name alpine-test -p 2226:22 \ + -v "$SSH_KEY.pub:/root/.ssh/authorized_keys:ro" \ + -t alpine:latest /bin/sh > /dev/null 2>&1 + +echo "Waiting for containers to initialize..." +sleep 10 + +echo "Setting up Ubuntu/Debian containers..." +for container in ubuntu-20-04-test ubuntu-22-04-test ubuntu-24-04-test debian-11-test debian-12-test debian-13-test; do + echo " Setting up $container..." + docker exec "$container" /bin/bash -c "apt-get update -qq && apt-get install -y -qq openssh-server python3 sudo" > /dev/null 2>&1 + docker exec "$container" /bin/bash -c "mkdir -p /var/run/sshd" > /dev/null 2>&1 + docker exec "$container" /bin/bash -c "sed -i 's/#PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config" > /dev/null 2>&1 + docker exec "$container" /bin/bash -c "sed -i 's/#PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config" > /dev/null 2>&1 + docker exec "$container" /bin/bash -c "echo 'root:password' | chpasswd" > /dev/null 2>&1 + docker exec "$container" service ssh start > /dev/null 2>&1 || docker exec "$container" /usr/sbin/sshd > /dev/null 2>&1 + sleep 2 +done + +echo "Setting up Alpine container..." +docker exec alpine-test /bin/sh -c "apk add --no-cache openssh openssh-server python3 sudo" > /dev/null 2>&1 +docker exec alpine-test /bin/sh -c "mkdir -p /var/run/sshd" > /dev/null 2>&1 +docker exec alpine-test /bin/sh -c "ssh-keygen -A" > /dev/null 2>&1 +docker exec alpine-test /bin/sh -c "sed -i 's/#PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config" > /dev/null 2>&1 +docker exec alpine-test /bin/sh -c "sed -i 's/#PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config" > /dev/null 2>&1 +docker exec alpine-test /bin/sh -c "echo 'root:password' | chpasswd" > /dev/null 2>&1 +docker exec alpine-test /usr/sbin/sshd > /dev/null 2>&1 +sleep 2 + +echo "Waiting for SSH to be ready..." +for port in 2220 2221 2222 2223 2224 2225 2226; do + echo " Waiting for port $port..." + timeout 30 bash -c "until nc -z localhost $port 2>/dev/null; do sleep 1; done" || echo " Warning: Port $port not ready" +done + +echo "Testing SSH connections..." +SSH_READY=true +SSH_FAILED=() + +for port in 2220 2221 2222 2223 2224 2225 2226; do + if ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=5 -i "$SSH_KEY" -p "$port" root@localhost "echo 'SSH OK'" > /dev/null 2>&1; then + echo " ✓ Port $port: SSH connection successful" + else + echo " ✗ Port $port: SSH connection failed" + SSH_READY=false + SSH_FAILED+=($port) + fi +done + +if [ "$SSH_READY" = false ]; then + echo "" + echo "ERROR: SSH connections failed for ports: ${SSH_FAILED[*]}" + echo "Checking container logs for failed ports..." + for port in "${SSH_FAILED[@]}"; do + case $port in + 2220) CONTAINER="ubuntu-20-04-test" ;; + 2221) CONTAINER="ubuntu-22-04-test" ;; + 2222) CONTAINER="ubuntu-24-04-test" ;; + 2223) CONTAINER="debian-11-test" ;; + 2224) CONTAINER="debian-12-test" ;; + 2225) CONTAINER="debian-13-test" ;; + 2226) CONTAINER="alpine-test" ;; + esac + echo "" + echo "Logs for $CONTAINER:" + docker logs "$CONTAINER" 2>&1 | tail -20 + done + echo "Aborting tests due to SSH connection failures." + exit 1 +fi + +echo "" +echo "==========================================" +echo "All SSH connections successful!" +echo "==========================================" +echo "" + +cat > "$SCRIPT_DIR/test_inventory.ini" << 'EOF' +[test_containers] +ubuntu-20-04-test ansible_host=127.0.0.1 ansible_port=2220 ansible_user=root ansible_ssh_private_key_file=/tmp/test_ansible_key ansible_ssh_common_args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' +ubuntu-22-04-test ansible_host=127.0.0.1 ansible_port=2221 ansible_user=root ansible_ssh_private_key_file=/tmp/test_ansible_key ansible_ssh_common_args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' +ubuntu-24-04-test ansible_host=127.0.0.1 ansible_port=2222 ansible_user=root ansible_ssh_private_key_file=/tmp/test_ansible_key ansible_ssh_common_args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' +debian-11-test ansible_host=127.0.0.1 ansible_port=2223 ansible_user=root ansible_ssh_private_key_file=/tmp/test_ansible_key ansible_ssh_common_args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' +debian-12-test ansible_host=127.0.0.1 ansible_port=2224 ansible_user=root ansible_ssh_private_key_file=/tmp/test_ansible_key ansible_ssh_common_args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' +debian-13-test ansible_host=127.0.0.1 ansible_port=2225 ansible_user=root ansible_ssh_private_key_file=/tmp/test_ansible_key ansible_ssh_common_args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' +alpine-test ansible_host=127.0.0.1 ansible_port=2226 ansible_user=root ansible_ssh_private_key_file=/tmp/test_ansible_key ansible_ssh_common_args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' + +[all:vars] +ansible_python_interpreter=/usr/bin/python3 +EOF + +echo "Running maintenance script tests..." +echo "==========================================" +echo "" + +cd "$PARENT_DIR" + +PLAYBOOK_SUCCESS=0 +PLAYBOOK_FAILED=0 + +echo "Running scan_cves.yml..." +if ansible-playbook playbooks/scan_cves.yml -i "$SCRIPT_DIR/test_inventory.ini" 2>&1 | tee "$RESULTS_DIR/scan_cves_run.log"; then + echo " ✓ scan_cves.yml completed successfully" + ((PLAYBOOK_SUCCESS++)) +else + echo " ✗ scan_cves.yml failed" + ((PLAYBOOK_FAILED++)) +fi +echo "" + +echo "Running analyze_disk_space.yml..." +if ansible-playbook playbooks/analyze_disk_space.yml -i "$SCRIPT_DIR/test_inventory.ini" 2>&1 | tee "$RESULTS_DIR/analyze_disk_space_run.log"; then + echo " ✓ analyze_disk_space.yml completed successfully" + ((PLAYBOOK_SUCCESS++)) +else + echo " ✗ analyze_disk_space.yml failed" + ((PLAYBOOK_FAILED++)) +fi +echo "" + +echo "Running cleanup_docker.yml..." +if ansible-playbook playbooks/cleanup_docker.yml -i "$SCRIPT_DIR/test_inventory.ini" 2>&1 | tee "$RESULTS_DIR/cleanup_docker_run.log"; then + echo " ✓ cleanup_docker.yml completed successfully" + ((PLAYBOOK_SUCCESS++)) +else + echo " ✗ cleanup_docker.yml failed" + ((PLAYBOOK_FAILED++)) +fi +echo "" + +echo "Running archive_logs.yml..." +if ansible-playbook playbooks/archive_logs.yml -i "$SCRIPT_DIR/test_inventory.ini" 2>&1 | tee "$RESULTS_DIR/archive_logs_run.log"; then + echo " ✓ archive_logs.yml completed successfully" + ((PLAYBOOK_SUCCESS++)) +else + echo " ✗ archive_logs.yml failed" + ((PLAYBOOK_FAILED++)) +fi +echo "" + +echo "==========================================" +echo "Collecting JSON reports..." +echo "==========================================" + +TOTAL_JSON_FILES=0 + +for container in ubuntu-20-04-test ubuntu-22-04-test ubuntu-24-04-test debian-11-test debian-12-test debian-13-test alpine-test; do + echo "Fetching reports from $container..." + + JSON_COUNT=$(docker exec "$container" /bin/sh -c "find /tmp -name '*_report_*.json' -type f 2>/dev/null" | wc -l) + + if [ "$JSON_COUNT" -gt 0 ]; then + docker exec "$container" /bin/sh -c "find /tmp -name '*_report_*.json' -type f" 2>/dev/null | while read -r file; do + filename=$(basename "$file") + echo " Found: $filename" + if docker cp "$container:$file" "$RESULTS_DIR/${container}_$filename" 2>/dev/null; then + ((TOTAL_JSON_FILES++)) + fi + done + else + echo " No JSON reports found" + fi +done + +echo "" +echo "==========================================" +echo "Test Summary" +echo "==========================================" +echo "Results directory: $RESULTS_DIR" +echo "" +echo "Playbook Results:" +echo " Successful: $PLAYBOOK_SUCCESS" +echo " Failed: $PLAYBOOK_FAILED" +echo "" +echo "JSON Reports Collected: $TOTAL_JSON_FILES" +echo "" + +if [ -d "$RESULTS_DIR" ]; then + echo "Collected JSON files:" + find "$RESULTS_DIR" -name "*.json" -type f -exec basename {} \; 2>/dev/null | sort -u + echo "" + + echo "Log files:" + find "$RESULTS_DIR" -name "*_run.log" -type f -exec basename {} \; 2>/dev/null + echo "" +fi + +echo "Cleaning up test containers..." +for container in ubuntu-20-04-test ubuntu-22-04-test ubuntu-24-04-test debian-11-test debian-12-test debian-13-test alpine-test; do + docker stop "$container" > /dev/null 2>&1 || true + docker rm "$container" > /dev/null 2>&1 || true +done + +echo "" +echo "==========================================" +echo "Testing complete!" +echo "==========================================" +echo "All JSON reports and logs are available in: $RESULTS_DIR" + +if [ "$PLAYBOOK_FAILED" -gt 0 ]; then + echo "" + echo "WARNING: $PLAYBOOK_FAILED playbook(s) failed. Please check the log files." + exit 1 +else + echo "" + echo "SUCCESS: All playbooks completed successfully!" + exit 0 +fi diff --git a/tests/test_all_playbooks.yml b/tests/test_all_playbooks.yml new file mode 100644 index 0000000..e04c7c5 --- /dev/null +++ b/tests/test_all_playbooks.yml @@ -0,0 +1,330 @@ +--- +- name: Setup Test Environment with Docker Containers + hosts: localhost + gather_facts: false + vars: + test_containers: + - name: "ubuntu-20-04-test" + image: "ubuntu:20.04" + os_family: "Debian" + distribution: "Ubuntu" + version: "20.04" + ssh_port: 2220 + - name: "ubuntu-22-04-test" + image: "ubuntu:22.04" + os_family: "Debian" + distribution: "Ubuntu" + version: "22.04" + ssh_port: 2221 + - name: "ubuntu-24-04-test" + image: "ubuntu:24.04" + os_family: "Debian" + distribution: "Ubuntu" + version: "24.04" + ssh_port: 2222 + - name: "debian-11-test" + image: "debian:11" + os_family: "Debian" + distribution: "Debian" + version: "11" + ssh_port: 2223 + - name: "debian-12-test" + image: "debian:12" + os_family: "Debian" + distribution: "Debian" + version: "12" + ssh_port: 2224 + - name: "debian-13-test" + image: "debian:13" + os_family: "Debian" + distribution: "Debian" + version: "13" + ssh_port: 2225 + - name: "alpine-test" + image: "alpine:latest" + os_family: "Alpine" + distribution: "Alpine" + version: "latest" + ssh_port: 2226 + results_dir: "/root/workspace/ppanda/mock-test-jsons" + temp_ssh_key_path: "/tmp/test_ansible_key" + + tasks: + - name: Create results directory + file: + path: "{{ results_dir }}" + state: directory + mode: '0755' + + - name: Remove any existing test containers + docker_container: + name: "{{ item.name }}" + state: absent + force_kill: true + loop: "{{ test_containers }}" + failed_when: false + + - name: Generate SSH key pair for testing + command: ssh-keygen -t rsa -b 4096 -f {{ temp_ssh_key_path }} -N "" + args: + creates: "{{ temp_ssh_key_path }}" + register: ssh_key_gen + + - name: Start test containers + docker_container: + name: "{{ item.name }}" + image: "{{ item.image }}" + state: started + tty: true + interactive: true + published_ports: + - "{{ item.ssh_port }}:22" + volumes: + - "{{ temp_ssh_key_path }}.pub:/root/.ssh/authorized_keys:ro" + command: /bin/bash + loop: "{{ test_containers }}" + register: container_start + + - name: Wait for containers to be ready + wait_for: + timeout: 10 + delegate_to: localhost + + - name: Install SSH server on Ubuntu/Debian containers + command: >- + docker exec {{ item.name }} /bin/bash -c + "apt-get update && apt-get install -y openssh-server python3 sudo && \ + mkdir -p /var/run/sshd && sed -i 's/#PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config && \ + sed -i 's/#PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config && \ + service ssh start" + loop: "{{ test_containers }}" + when: item.os_family == 'Debian' + register: ssh_install_debian + until: ssh_install_debian.rc == 0 + retries: 3 + delay: 5 + + - name: Install SSH server on Alpine containers + command: >- + docker exec {{ item.name }} /bin/sh -c + "apk add --no-cache openssh openssh-server python3 sudo && \ + mkdir -p /var/run/sshd && \ + ssh-keygen -A && \ + sed -i 's/#PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config && \ + sed -i 's/#PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config && \ + /usr/sbin/sshd" + loop: "{{ test_containers }}" + when: item.os_family == 'Alpine' + register: ssh_install_alpine + until: ssh_install_alpine.rc == 0 + retries: 3 + delay: 5 + + - name: Ensure root password is set (Debian/Ubuntu) + command: docker exec {{ item.name }} /bin/bash -c "echo 'root:password' | chpasswd" + loop: "{{ test_containers }}" + when: item.os_family == 'Debian' + failed_when: false + + - name: Ensure root password is set (Alpine) + command: docker exec {{ item.name }} /bin/sh -c "echo 'root:password' | chpasswd" + loop: "{{ test_containers }}" + when: item.os_family == 'Alpine' + failed_when: false + + - name: Wait for SSH to be ready + wait_for: + host: localhost + port: "{{ item.ssh_port }}" + delay: 2 + timeout: 30 + loop: "{{ test_containers }}" + register: ssh_ready + + - name: Verify SSH connection to containers + command: ssh -o StrictHostKeyChecking=no -i {{ temp_ssh_key_path }} -p {{ item.ssh_port }} root@localhost echo "SSH connection successful" + loop: "{{ test_containers }}" + register: ssh_test + until: ssh_test.rc == 0 + retries: 5 + delay: 3 + + - name: Display SSH connection status + debug: + msg: "SSH connection to {{ item.item.name }} (port {{ item.item.ssh_port }}): {{ 'SUCCESS' if item.rc == 0 else 'FAILED' }}" + loop: "{{ ssh_test.results }}" + + - name: Generate dynamic inventory for test containers + copy: + dest: "/tmp/test_inventory.ini" + content: | + [test_containers] + {% for container in test_containers %} + {{ container.name }} ansible_host=127.0.0.1 ansible_port={{ container.ssh_port }} ansible_user=root ansible_ssh_private_key_file={{ temp_ssh_key_path }} ansible_ssh_common_args='-o StrictHostKeyChecking=no' + {% endfor %} + mode: '0644' + + - name: Display test environment ready message + debug: + msg: "Test environment setup complete. {{ test_containers | length }} containers ready for testing." + +- name: Run Maintenance Scripts on Test Containers + hosts: test_containers + gather_facts: true + vars: + results_dir: "/root/workspace/ppanda/mock-test-jsons" + + tasks: + - name: Display starting test message + debug: + msg: "Running maintenance scripts on {{ inventory_hostname }}" + + - name: Run CVE scanner playbook + include_role: + name: test_playbook_runner + vars: + playbook_path: "../playbooks/scan_cves.yml" + output_pattern: "cve_report_*.json" + + - name: Run disk space analyzer playbook + include_role: + name: test_playbook_runner + vars: + playbook_path: "../playbooks/analyze_disk_space.yml" + output_pattern: "disk_space_report_*.json" + + - name: Run docker cleanup playbook + include_role: + name: test_playbook_runner + vars: + playbook_path: "../playbooks/cleanup_docker.yml" + output_pattern: "docker_cleanup_report_*.json" + + - name: Run log archiver playbook + include_role: + name: test_playbook_runner + vars: + playbook_path: "../playbooks/archive_logs.yml" + output_pattern: "log_archive_report_*.json" + +- name: Collect Results and Cleanup + hosts: localhost + gather_facts: false + vars: + test_containers: + - name: "ubuntu-20-04-test" + ssh_port: 2220 + - name: "ubuntu-22-04-test" + ssh_port: 2221 + - name: "ubuntu-24-04-test" + ssh_port: 2222 + - name: "debian-11-test" + ssh_port: 2223 + - name: "debian-12-test" + ssh_port: 2224 + - name: "debian-13-test" + ssh_port: 2225 + - name: "alpine-test" + ssh_port: 2226 + results_dir: "/root/workspace/ppanda/mock-test-jsons" + temp_ssh_key_path: "/tmp/test_ansible_key" + + tasks: + - name: Fetch JSON reports from containers + fetch: + src: "/tmp/*_report_*.json" + dest: "{{ results_dir }}/" + flat: true + delegate_to: "{{ item }}" + loop: "{{ groups['test_containers'] }}" + failed_when: false + + - name: Rename fetched files with hostname prefix + shell: >- + find {{ results_dir }} -name "*_report_*.json" -type f | while read file; do + basename=$(basename "$file") + if [[ ! "$basename" =~ ^[a-zA-Z0-9_-]+_ ]]; then + hostname=$(echo "$basename" | grep -oP '(cve|update|docker|log|disk)_report' | head -1 | sed 's/_report//' || echo "unknown") + newname="${{ inventory_hostname }}_${basename}" + mv "$file" "{{ results_dir }}/${newname}" + fi + done + delegate_to: localhost + run_once: true + failed_when: false + + - name: Create test summary + copy: + dest: "{{ results_dir }}/test_summary.txt" + content: | + Test Execution Summary + ====================== + Date: {{ ansible_date_time.iso8601 }} + Containers Tested: {{ test_containers | length }} + + Container Status: + {% for container in test_containers %} + - {{ container.name }} (SSH port {{ container.ssh_port }}) + {% endfor %} + + Reports Collected: + {% for file in ansible_local.files | default([]) %} + - {{ file }} + {% endfor %} + + - name: Stop and remove test containers + docker_container: + name: "{{ item.name }}" + state: absent + force_kill: true + loop: "{{ test_containers }}" + register: container_cleanup + failed_when: false + + - name: Remove SSH test key + file: + path: "{{ temp_ssh_key_path }}" + state: absent + failed_when: false + + - name: Display test completion message + debug: + msg: "Testing complete. Reports saved to {{ results_dir }}" + +- name: Test Playbook Runner Role + hosts: localhost + gather_facts: false + tasks: + - name: Create test playbook runner role + block: + - name: Create role directory structure + file: + path: "roles/test_playbook_runner/tasks" + state: directory + mode: '0755' + delegate_to: localhost + + - name: Create role main task file + copy: + dest: "roles/test_playbook_runner/tasks/main.yml" + content: | + --- + - name: Run playbook {{ playbook_path }} + command: >- + ansible-playbook {{ playbook_path }} -i /tmp/test_inventory.ini -l {{ inventory_hostname }} + delegate_to: localhost + register: playbook_run + ignore_errors: true + + - name: Check if playbook succeeded + debug: + msg: "{{ playbook_path }} on {{ inventory_hostname }}: {{ 'SUCCESS' if playbook_run.rc == 0 else 'FAILED' }}" + + - name: Fetch JSON output from container + fetch: + src: "/tmp/{{ output_pattern }}" + dest: "/root/workspace/ppanda/mock-test-jsons/{{ inventory_hostname }}_{{ output_pattern }}" + flat: true + delegate_to: localhost + failed_when: false + delegate_to: localhost diff --git a/tests/test_inventory.ini b/tests/test_inventory.ini new file mode 100644 index 0000000..1720cc1 --- /dev/null +++ b/tests/test_inventory.ini @@ -0,0 +1,11 @@ +[test_containers] +ubuntu-20-04-test ansible_host=127.0.0.1 ansible_port=2220 ansible_user=root ansible_ssh_private_key_file=/tmp/test_ansible_key ansible_ssh_common_args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' +ubuntu-22-04-test ansible_host=127.0.0.1 ansible_port=2221 ansible_user=root ansible_ssh_private_key_file=/tmp/test_ansible_key ansible_ssh_common_args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' +ubuntu-24-04-test ansible_host=127.0.0.1 ansible_port=2222 ansible_user=root ansible_ssh_private_key_file=/tmp/test_ansible_key ansible_ssh_common_args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' +debian-11-test ansible_host=127.0.0.1 ansible_port=2223 ansible_user=root ansible_ssh_private_key_file=/tmp/test_ansible_key ansible_ssh_common_args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' +debian-12-test ansible_host=127.0.0.1 ansible_port=2224 ansible_user=root ansible_ssh_private_key_file=/tmp/test_ansible_key ansible_ssh_common_args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' +debian-13-test ansible_host=127.0.0.1 ansible_port=2225 ansible_user=root ansible_ssh_private_key_file=/tmp/test_ansible_key ansible_ssh_common_args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' +alpine-test ansible_host=127.0.0.1 ansible_port=2226 ansible_user=root ansible_ssh_private_key_file=/tmp/test_ansible_key ansible_ssh_common_args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' + +[all:vars] +ansible_python_interpreter=/usr/bin/python3