diff --git a/.ansible-lint b/.ansible-lint index 61c20cec..a5189732 100644 --- a/.ansible-lint +++ b/.ansible-lint @@ -2,3 +2,24 @@ skip_list: - run_once[play] - no-changed-when + - yaml # Don't enforce line length + - no-handler # Don't require handlers for service restarts + - role-name # Don't enforce role naming conventions + - command-instead-of-module # Sometimes shell commands are necessary + +# Exclude paths from linting +exclude_paths: + - .github/ + - .git/ + - .venv/ + - ansible/roles/*/molecule/ + +# Determine whether to fail on warnings +warn_list: + - experimental # tasks using experimental features + +# Be quiet about skipped rules +quiet: false + +# Make output parsable +parseable: true diff --git a/.github/workflows/ansible-tests.yml b/.github/workflows/ansible-tests.yml new file mode 100644 index 00000000..37d10749 --- /dev/null +++ b/.github/workflows/ansible-tests.yml @@ -0,0 +1,68 @@ +name: Ansible Role Tests + +on: + push: + branches: [ main, master ] + paths: + - 'ansible/**' + pull_request: + branches: [ main, master ] + paths: + - 'ansible/**' + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.10' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install ansible ansible-lint yamllint + + - name: Run ansible-lint + run: | + ansible-lint ansible/ + + molecule: + needs: lint + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + role: + - common + # Add other roles as they are configured with molecule + scenario: + - default + - oracle + + steps: + - uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.10' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install molecule molecule-docker docker ansible-core ansible-lint + + - name: Set up Docker + uses: docker/setup-buildx-action@v2 + + - name: Run Molecule tests + run: | + cd ansible/roles/${{ matrix.role }} + molecule test -s ${{ matrix.scenario }} + env: + PY_COLORS: '1' + ANSIBLE_FORCE_COLOR: '1' diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..55f224ef --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,23 @@ +repos: + - repo: https://github.com/ansible/ansible-lint + rev: v6.17.0 # Use latest version + hooks: + - id: ansible-lint + files: \.(yaml|yml)$ + types: [file, yaml] + entry: ansible-lint + + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files + + - repo: https://github.com/adrienverge/yamllint + rev: v1.31.0 + hooks: + - id: yamllint + files: \.(yaml|yml)$ + types: [file, yaml] diff --git a/ansible/README_TESTING.md b/ansible/README_TESTING.md new file mode 100644 index 00000000..758e6049 --- /dev/null +++ b/ansible/README_TESTING.md @@ -0,0 +1,134 @@ +# Ansible Role Testing + +This document outlines the testing framework and approach for the Ansible roles in this repository. + +## Overview + +The testing framework uses [Molecule](https://molecule.readthedocs.io/) to test Ansible roles across different scenarios and platforms. The framework ensures that: + +1. Roles have correct syntax +2. Roles can be applied successfully +3. Roles are idempotent (can be run multiple times without changing the result) +4. Roles produce the expected system state + +## Prerequisites + +To run the tests locally, you'll need: + +```bash +# Install dependencies +pip install molecule molecule-docker ansible-lint pytest-testinfra + +# For Docker driver +brew install docker-compose +``` + +## Test Structure + +Each role may have multiple test scenarios, typically: + +- `default`: Tests the role with standard parameters +- `oracle`: Tests the role with Oracle Cloud specific parameters +- Other platform-specific scenarios as needed + +### Directory Structure + +``` +roles/ + common/ + molecule/ + default/ + molecule.yml # Test configuration + converge.yml # Playbook to apply the role + verify.yml # Tests to validate the role worked correctly + oracle/ + molecule.yml # Oracle-specific test configuration + converge.yml # Oracle-specific apply playbook + verify.yml # Oracle-specific validation tests +``` + +## Running Tests + +You can run tests using the provided script: + +```bash +# Run all tests for all roles +./scripts/run-ansible-tests.sh + +# Run tests for a specific role +./scripts/run-ansible-tests.sh common + +# Run a specific scenario for a role +./scripts/run-ansible-tests.sh -s oracle common + +# Just run the linting +./scripts/run-ansible-tests.sh --lint common + +# List roles with tests +./scripts/run-ansible-tests.sh --list +``` + +## Test Phases + +The Molecule tests run through the following phases: + +1. **Lint**: Check code quality using ansible-lint +2. **Syntax**: Verify playbook syntax +3. **Create**: Create test containers +4. **Prepare**: Prepare the container for testing +5. **Converge**: Run the role against the container +6. **Idempotence**: Run the role again to verify no changes +7. **Verify**: Run tests to validate the container state +8. **Destroy**: Clean up test containers + +## Writing Tests + +### Verification Tests + +Verification tests check that the role produces the expected state. They should verify: + +1. Required packages are installed +2. Configuration files have the correct content +3. Services are running (if applicable) +4. The system behaves as expected + +Example verification test in `verify.yml`: + +```yaml +--- +- name: Verify + hosts: all + become: true + tasks: + - name: Check if packages are installed + ansible.builtin.package: + name: "{{ item }}" + state: present + check_mode: true + register: pkg_status + failed_when: pkg_status.changed + loop: + - package1 + - package2 + + - name: Check if configuration file exists + ansible.builtin.stat: + path: "/etc/myconfig.conf" + register: config_file + + - name: Verify configuration file + ansible.builtin.assert: + that: config_file.stat.exists +``` + +## Continuous Integration + +These tests are designed to run in a CI/CD pipeline. They validate that roles work properly across different scenarios before changes are merged. + +## Best Practices + +1. Write tests for all roles +2. Keep tests focused and concise +3. Test for both presence (things that should exist) and absence (things that shouldn't) +4. Use assertion messages to make test failures clear +5. Test roles across multiple platforms when possible diff --git a/ansible/build-jvb.yml b/ansible/build-jvb.yml index fc529252..a077c873 100644 --- a/ansible/build-jvb.yml +++ b/ansible/build-jvb.yml @@ -10,7 +10,7 @@ tasks: - name: "Provision ec2 security group" delegate_to: localhost - amazon.aws.ec2_group: + amazon.aws.ec2_security_group: name: "{{ ec2_security_group_name }}-amibuilder" description: "VaaS Load test security group for temporary ec2 instance" vpc_id: "{{ ec2_vpc_id }}" @@ -27,7 +27,7 @@ cidr_ip: 0.0.0.0/0 - name: "Provision ec2 instance" delegate_to: localhost - amazon.aws.ec2: + amazon.aws.ec2_instance: key_name: "{{ ec2_keypair }}" vpc_subnet_id: "{{ ec2_vpc_subnet_id }}" instance_type: "{{ ec2_instance_type }}" @@ -182,8 +182,7 @@ - name: "Terminate temporary instance" delegate_to: localhost - amazon.aws.ec2: - module: ec2 + amazon.aws.ec2_instance: state: absent wait: true wait_timeout: 500 @@ -192,8 +191,7 @@ - name: "Drop ec2 security group" delegate_to: localhost - amazon.aws.ec2_group: - module: ec2_group + amazon.aws.ec2_security_group: name: "{{ ec2_security_group_name }}-amibuilder" description: "VaaS Load test security group for temporary ec2 instance" state: 'absent' diff --git a/ansible/configure-wavefront-proxy.yml b/ansible/configure-wavefront-proxy.yml deleted file mode 100644 index 96c945e1..00000000 --- a/ansible/configure-wavefront-proxy.yml +++ /dev/null @@ -1,29 +0,0 @@ ---- -- name: Main - hosts: all - gather_facts: true - become_user: root - become: yes - vars_files: - - secrets/wavefront.yml - - secrets/carbon-black.yml - - config/vars.yml - - sites/{{ hcv_environment }}/vars.yml - vars: - shard_role: wf-proxy - java_use_11: true - roles: - - { role: "openjdk-java", tags: "openjdk-java", when: cloud_provider=="oracle", java_install_flag: false } - - { role: "iptables-wf-proxy", when: cloud_provider=="oracle"} - - role: "wavefront" - tags: "wavefront-proxy" - wavefront_install_proxy: true - wavefront_proxy_address: localhost - telegraf_tags: - role: "wf-proxy" - cloud_name: "{{cloud_name}}" - region: "{{ region }}" - cloud: "{{ cloud_provider }}" - environment: "{{ hcv_environment }}" - - { role: "unattended-upgrades", tags: "unattended-upgrades"} - - { role: "carbon-black", tags: "carbon-black", when: carbon_black_install_flag} \ No newline at end of file diff --git a/ansible/roles/common/molecule/default/converge.yml b/ansible/roles/common/molecule/default/converge.yml new file mode 100644 index 00000000..bfb802b5 --- /dev/null +++ b/ansible/roles/common/molecule/default/converge.yml @@ -0,0 +1,9 @@ +--- +- name: Converge + hosts: all + become: true + become_user: root + tasks: + - name: "Include common role" + ansible.builtin.include_role: + name: "common" \ No newline at end of file diff --git a/ansible/roles/common/molecule/default/molecule.yml b/ansible/roles/common/molecule/default/molecule.yml new file mode 100644 index 00000000..880c9940 --- /dev/null +++ b/ansible/roles/common/molecule/default/molecule.yml @@ -0,0 +1,64 @@ +--- +dependency: + name: galaxy +driver: + name: docker +platforms: + - name: ubuntu-focal + image: dokken/ubuntu-20.04 + command: /lib/systemd/systemd + capabilities: + - SYS_ADMIN + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + privileged: true + - name: ubuntu-jammy + image: dokken/ubuntu-22.04 + command: /lib/systemd/systemd + capabilities: + - SYS_ADMIN + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + privileged: true +provisioner: + name: ansible + playbooks: + converge: converge.yml + verify: verify.yml + inventory: + host_vars: + ubuntu-focal: + ansible_user: root + locale: "en_US.UTF-8" + common_install_pip_flag: true + common_install_pip3_flag: true + ansible_distribution_major_version: "20" + common_cloud_provider: "aws" + ubuntu-jammy: + ansible_user: root + locale: "en_US.UTF-8" + common_install_pip_flag: false + common_install_pip3_flag: true + ansible_distribution_major_version: "22" + common_cloud_provider: "aws" + lint: + name: ansible-lint + options: + x: + - 204 # [204] Lines should be no longer than 160 chars +verifier: + name: ansible +scenario: + test_sequence: + - lint + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy \ No newline at end of file diff --git a/ansible/roles/common/molecule/default/verify.yml b/ansible/roles/common/molecule/default/verify.yml new file mode 100644 index 00000000..04f4ce88 --- /dev/null +++ b/ansible/roles/common/molecule/default/verify.yml @@ -0,0 +1,88 @@ +--- +- name: Verify + hosts: all + become: true + tasks: + # Verify that packages were installed + - name: Check if basic tools are installed + ansible.builtin.package: + name: "{{ item }}" + state: present + check_mode: true + register: pkg_status + failed_when: pkg_status.changed + loop: + - atop + - mc + - htop + - tmux + - unzip + - jq + - libffi-dev + - libssl-dev + - acl + - net-tools + - sysstat + - at + + # Check if locale was set properly + - name: Check locale configuration + ansible.builtin.command: "locale" + register: locale_output + changed_when: false + + - name: Verify locale is properly set + ansible.builtin.assert: + that: locale in locale_output.stdout + + # Verify python pip packages installation based on Ubuntu version + - name: Check if setuptools is installed (Ubuntu Focal) + ansible.builtin.command: "pip3 list | grep setuptools" + register: setuptools_output + changed_when: false + when: ansible_distribution_major_version | int == 20 + + - name: Check AWS related libraries + ansible.builtin.package: + name: "{{ item }}" + state: present + check_mode: true + register: aws_pkg_status + failed_when: aws_pkg_status.changed + loop: + - python3-boto3 + - python3-botocore + - python3-yaml + - python3-urllib3 + - python3-requests + + # Verify helper scripts were installed + - name: Check if helper scripts exist + ansible.builtin.stat: + path: "/usr/local/bin/{{ item }}" + register: scripts_stat + failed_when: not scripts_stat.stat.exists + loop: + - download.sh + - aws_cache.sh + + # Verify file permissions are correct + - name: Check file permissions + ansible.builtin.stat: + path: "/usr/local/bin/download.sh" + register: script_perms + + - name: Verify script permissions + ansible.builtin.assert: + that: + - script_perms.stat.mode == "0755" + + # Verify getaddrinfo configuration + - name: Check if gai.conf exists + ansible.builtin.stat: + path: "/etc/gai.conf" + register: gai_conf + + - name: Verify gai.conf exists + ansible.builtin.assert: + that: gai_conf.stat.exists \ No newline at end of file diff --git a/ansible/roles/common/molecule/oracle/converge.yml b/ansible/roles/common/molecule/oracle/converge.yml new file mode 100644 index 00000000..9cef24d8 --- /dev/null +++ b/ansible/roles/common/molecule/oracle/converge.yml @@ -0,0 +1,9 @@ +--- +- name: Converge + hosts: all + become: true + become_user: root + tasks: + - name: "Include common role" + include_role: + name: "common" diff --git a/ansible/roles/common/molecule/oracle/molecule.yml b/ansible/roles/common/molecule/oracle/molecule.yml new file mode 100644 index 00000000..458dd8fa --- /dev/null +++ b/ansible/roles/common/molecule/oracle/molecule.yml @@ -0,0 +1,62 @@ +--- +dependency: + name: galaxy +driver: + name: docker +platforms: + - name: ubuntu-focal + image: dokken/ubuntu-20.04 + command: /lib/systemd/systemd + capabilities: + - SYS_ADMIN + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + privileged: true + - name: ubuntu-jammy + image: dokken/ubuntu-22.04 + command: /lib/systemd/systemd + capabilities: + - SYS_ADMIN + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + privileged: true +provisioner: + name: ansible + playbooks: + converge: converge.yml + verify: verify.yml + inventory: + host_vars: + ubuntu-focal: + ansible_user: root + locale: "en_US.UTF-8" + common_install_pip_flag: true + common_install_pip3_flag: true + ansible_distribution_major_version: "20" + common_cloud_provider: "oracle" + ubuntu-jammy: + ansible_user: root + locale: "en_US.UTF-8" + common_install_pip_flag: false + common_install_pip3_flag: true + ansible_distribution_major_version: "22" + common_cloud_provider: "oracle" + lint: + name: ansible-lint +verifier: + name: ansible +scenario: + name: oracle + test_sequence: + - lint + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy \ No newline at end of file diff --git a/ansible/roles/common/molecule/oracle/verify.yml b/ansible/roles/common/molecule/oracle/verify.yml new file mode 100644 index 00000000..f1450f9c --- /dev/null +++ b/ansible/roles/common/molecule/oracle/verify.yml @@ -0,0 +1,74 @@ +--- +- name: Verify + hosts: all + become: true + tasks: + # Verify common baseline tests + - name: Check if basic tools are installed + ansible.builtin.package: + name: "{{ item }}" + state: present + check_mode: true + register: pkg_status + failed_when: pkg_status.changed + loop: + - atop + - mc + - htop + - tmux + - unzip + - jq + - libffi-dev + - libssl-dev + - acl + - net-tools + - sysstat + - at + + # Verify Oracle-specific tools + - name: Check for Oracle-specific scripts + ansible.builtin.stat: + path: "/usr/local/bin/{{ item }}" + register: oracle_scripts_stat + failed_when: not oracle_scripts_stat.stat.exists + loop: + - oracle_cache.sh + - postinstall.sh + - oci-testcert.py + - secondary_vnic_all_configure_oracle.sh + + # Check oci-cli installation + - name: Check for OCI CLI + ansible.builtin.stat: + path: "/usr/local/bin/oci" + register: oci_stat + + - name: Verify OCI CLI installation + ansible.builtin.assert: + that: + - oci_stat.stat.exists + - oci_stat.stat.mode == "0755" + + # Check for python3 tools + - name: Check if python3 tools are installed + ansible.builtin.package: + name: "{{ item }}" + state: present + check_mode: true + register: py3_pkg_status + failed_when: py3_pkg_status.changed + loop: + - python3-pip + - python3-setuptools + + # Check correct python-dev package based on distribution and flags + - name: Check python-dev-is-python3 on newer Ubuntu + ansible.builtin.package: + name: python-dev-is-python3 + state: present + check_mode: true + register: py_dev_pkg_status + failed_when: py_dev_pkg_status.changed + when: + - common_install_pip3_flag + - ansible_distribution_major_version | int >= 20 diff --git a/ansible/roles/jitsi-torture/files/auth0-authenticate/package-lock.json b/ansible/roles/jitsi-torture/files/auth0-authenticate/package-lock.json new file mode 100644 index 00000000..4feae337 --- /dev/null +++ b/ansible/roles/jitsi-torture/files/auth0-authenticate/package-lock.json @@ -0,0 +1,22 @@ +{ + "name": "auth0-authenticate", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "auth0-authenticate", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "set-cookie-parser": "^2.4.7" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "license": "MIT" + } + } +} diff --git a/ansible/test-all-roles.yml b/ansible/test-all-roles.yml new file mode 100644 index 00000000..c91d70e4 --- /dev/null +++ b/ansible/test-all-roles.yml @@ -0,0 +1,23 @@ +--- +# test-all-roles.yml - Playbook to test all roles together +- name: Test all roles + hosts: all + become: true + roles: + - role: common + tags: common + vars: + locale: "en_US.UTF-8" + common_install_pip_flag: true + common_install_pip3_flag: true + common_cloud_provider: "{{ cloud_provider | default('aws') }}" + + # Add additional roles as needed + # - role: another_role + # tags: another_role + # vars: + # role_specific_var: value + + vars: + # Default variables that apply to all hosts + ansible_distribution_major_version: "{{ ansible_distribution_major_version }}" diff --git a/scripts/check-ansible-syntax.sh b/scripts/check-ansible-syntax.sh new file mode 100755 index 00000000..cac06112 --- /dev/null +++ b/scripts/check-ansible-syntax.sh @@ -0,0 +1,70 @@ +#!/bin/bash +# check-ansible-syntax.sh +# Quick script to validate the syntax of all Ansible playbooks in the repo + +set -e + +# Colors for output +GREEN='\033[0;32m' +RED='\033[0;31m' +YELLOW='\033[0;33m' +NC='\033[0m' # No Color + +REPO_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) +ANSIBLE_DIR="${REPO_ROOT}/ansible" + +# Find all YAML files that are likely playbooks +find_playbooks() { + find "${ANSIBLE_DIR}" -name "*.yml" -type f | grep -v "/roles/" | grep -v "/molecule/" +} + +# Check syntax on a single playbook +check_playbook() { + local playbook=$1 + + echo -e "${YELLOW}Checking syntax for ${playbook}${NC}" + + if ansible-playbook --syntax-check "${playbook}"; then + echo -e "${GREEN}✓ ${playbook} - Syntax OK${NC}" + return 0 + else + echo -e "${RED}✗ ${playbook} - Syntax Error${NC}" + return 1 + fi +} + +# Main function +main() { + local playbooks=$(find_playbooks) + local failed_playbooks=() + local success_count=0 + local total_count=0 + + echo "Found $(echo "${playbooks}" | wc -l | tr -d ' ') playbooks to check" + + for playbook in ${playbooks}; do + ((total_count++)) + if check_playbook "${playbook}"; then + ((success_count++)) + else + failed_playbooks+=("${playbook}") + fi + done + + echo "" + echo "====== Summary ======" + echo -e "Total playbooks: ${total_count}" + echo -e "Passed: ${GREEN}${success_count}${NC}" + + if [ ${#failed_playbooks[@]} -eq 0 ]; then + echo -e "${GREEN}All playbooks passed syntax check!${NC}" + exit 0 + else + echo -e "Failed: ${RED}${#failed_playbooks[@]}${NC}" + echo -e "${RED}The following playbooks failed syntax check:${NC}" + printf " %s\n" "${failed_playbooks[@]}" + exit 1 + fi +} + +main "$@" diff --git a/scripts/run-ansible-tests.sh b/scripts/run-ansible-tests.sh new file mode 100755 index 00000000..d6e2cb65 --- /dev/null +++ b/scripts/run-ansible-tests.sh @@ -0,0 +1,191 @@ +#!/bin/bash +# run-ansible-tests.sh +# Simple script to run Molecule tests on all roles or a specific role + +set -e + +# Colors for output +GREEN='\033[0;32m' +RED='\033[0;31m' +YELLOW='\033[0;33m' +NC='\033[0m' # No Color + +# Function to run molecule test on a role +run_test() { + local role=$1 + local scenario=${2:-default} + + echo -e "${YELLOW}Testing role: ${role} (scenario: ${scenario})${NC}" + + cd "${ANSIBLE_ROLES_PATH}/${role}" + + if [ ! -d "molecule/${scenario}" ]; then + echo -e "${RED}No molecule/${scenario} directory found in ${role} role${NC}" + return 1 + fi + + echo "Running molecule test for ${role}..." + if molecule test -s "${scenario}"; then + echo -e "${GREEN}✓ Role ${role} passed all tests (scenario: ${scenario})${NC}" + return 0 + else + echo -e "${RED}✗ Role ${role} failed tests (scenario: ${scenario})${NC}" + return 1 + fi +} + +# Function to run ansible-lint on a role +run_lint() { + local role=$1 + + echo -e "${YELLOW}Linting role: ${role}${NC}" + + cd "${ANSIBLE_ROLES_PATH}/${role}" + + if ansible-lint; then + echo -e "${GREEN}✓ Role ${role} passed linting${NC}" + return 0 + else + echo -e "${RED}✗ Role ${role} failed linting${NC}" + return 1 + fi +} + +# Function to list all roles with molecule tests +list_testable_roles() { + find "${ANSIBLE_ROLES_PATH}" -name "molecule" -type d | sed 's|/molecule$||' | sort +} + +# Function to list all scenarios for a role +list_scenarios() { + local role=$1 + find "${ANSIBLE_ROLES_PATH}/${role}/molecule" -maxdepth 1 -mindepth 1 -type d | grep -v '_shared' | xargs -n1 basename +} + +# Function to run syntax check +run_syntax_check() { + local playbook=$1 + + echo -e "${YELLOW}Syntax checking playbook: ${playbook}${NC}" + + if ansible-playbook --syntax-check "${playbook}"; then + echo -e "${GREEN}✓ Playbook ${playbook} passed syntax check${NC}" + return 0 + else + echo -e "${RED}✗ Playbook ${playbook} failed syntax check${NC}" + return 1 + fi +} + +# Path to ansible roles +ANSIBLE_ROLES_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/../ansible/roles" + +# Help message +show_help() { + echo "Usage: $0 [options] [role_name]" + echo "" + echo "Options:" + echo " -h, --help Show this help message" + echo " -l, --list List all roles with molecule tests" + echo " -s, --scenario Specify a molecule scenario (default: default)" + echo " --lint Run only ansible-lint on the role" + echo " --syntax Run syntax check on all playbooks" + echo "" + echo "Examples:" + echo " $0 Run all molecule tests for all roles" + echo " $0 common Run molecule tests for the common role" + echo " $0 -s oracle common Run oracle scenario tests for the common role" + echo " $0 --lint common Run only ansible-lint on the common role" +} + +# Parse command-line arguments +SCENARIO="default" +LINT_ONLY=false +SYNTAX_CHECK=false + +while [[ $# -gt 0 ]]; do + case "$1" in + -h|--help) + show_help + exit 0 + ;; + -l|--list) + echo "Roles with molecule tests:" + list_testable_roles | xargs -n1 basename + exit 0 + ;; + -s|--scenario) + SCENARIO="$2" + shift 2 + ;; + --lint) + LINT_ONLY=true + shift + ;; + --syntax) + SYNTAX_CHECK=true + shift + ;; + *) + ROLE="$1" + shift + ;; + esac +done + +# If --syntax flag is set, run syntax check on all playbooks +if [ "$SYNTAX_CHECK" = true ]; then + PLAYBOOKS=$(find "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/ansible" -name "*.yml" -type f | grep -v "roles/") + + for playbook in $PLAYBOOKS; do + run_syntax_check "$playbook" + done + + exit 0 +fi + +# If a specific role is given +if [ -n "$ROLE" ]; then + # If --lint flag is set, only run ansible-lint + if [ "$LINT_ONLY" = true ]; then + run_lint "$ROLE" + else + # List available scenarios if the role exists + if [ -d "${ANSIBLE_ROLES_PATH}/${ROLE}/molecule" ]; then + echo "Available scenarios for ${ROLE}:" + list_scenarios "$ROLE" + + run_test "$ROLE" "$SCENARIO" + else + echo -e "${RED}Error: Role ${ROLE} not found or no molecule tests available${NC}" + exit 1 + fi + fi +else + # Run all tests for all roles + FAILED_ROLES=() + + for role_path in $(list_testable_roles); do + role=$(basename "$role_path") + + if [ "$LINT_ONLY" = true ]; then + if ! run_lint "$role"; then + FAILED_ROLES+=("$role") + fi + else + for scenario in $(list_scenarios "$role"); do + if ! run_test "$role" "$scenario"; then + FAILED_ROLES+=("$role ($scenario)") + fi + done + fi + done + + if [ ${#FAILED_ROLES[@]} -eq 0 ]; then + echo -e "${GREEN}All roles passed all tests!${NC}" + else + echo -e "${RED}The following roles failed tests:${NC}" + printf " %s\n" "${FAILED_ROLES[@]}" + exit 1 + fi +fi