Skip to content
Back to skills

Ansible Testing

ASecurity

Testing strategies and ansible-lint configuration for validating Ansible automation quality, covering lint rules, syntax validation, and integration test setup.

  • 2 stars
  • 0 votes
  • 0 copies
  • 5 views
  • Added September 11, 2026
devopspythongoshellbashtestingdebugginggitci/cdsecurity

Works with

  • cli

Security analysis

A96/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 2 files and shows the line behind each finding

Scanned September 11, 2026

npx -y skills add jcasnellie69/homelab-config --skill ansible-testing --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Ansible Testing?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Ansible Testing
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/jcasnellie69-ansible-testing/badge)](https://www.skillsdirectory.com/skills/jcasnellie69-ansible-testing)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: ansible-testing
description: >
  Testing strategies and ansible-lint configuration for validating Ansible automation
  quality, covering lint rules, syntax validation, and integration test setup.
when_to_use: >
  Use when running ansible-lint, configuring linting rules, testing Ansible playbooks,
  validating playbook syntax, or setting up integration tests.
---

# Ansible Testing

Testing strategies and ansible-lint configuration for Ansible automation.

## ansible-lint

### Running Lint

```bash
# Via mise (recommended)
mise run ansible-lint

# Directly with uv
uv run ansible-lint ansible/playbooks/

# Specific file
uv run ansible-lint ansible/playbooks/my-playbook.yml

# With verbose output
uv run ansible-lint -v ansible/
```

### Configuration File

Located at `ansible/.ansible-lint`:

```yaml
---
# Profile: null, min, basic, moderate, safety, shared, production
profile: moderate

# Offline mode - don't download Galaxy requirements
offline: true

# Exclude paths
exclude_paths:
  - .cache/
  - .venv/
  - .git/
  - "*/templates/"
  - "*.j2"
  - .deprecated/

# Rules to skip completely
skip_list:
  - var-naming[no-role-prefix]  # We use descriptive names
  - run-once[task]              # Safe with our strategy
  - command-instead-of-module   # CLI tools require command
  - yaml[line-length]           # Long lines in infra configs

# Rules to warn but not fail
warn_list:
  - fqcn[action-core]
  - fqcn[action]
  - no-handler
  - name[play]
```

### Common Rule Categories

| Category | Description |
|----------|-------------|
| `fqcn` | Fully qualified collection names |
| `yaml` | YAML formatting (indentation, line length) |
| `name` | Task/play naming conventions |
| `command-instead-of-module` | Using command when module exists |
| `no-changed-when` | Missing changed_when on command |
| `risky-file-permissions` | Missing explicit file permissions |

### Fixing Common Issues

**Missing name on task:**

```yaml
# BAD
- ansible.builtin.apt:
    name: nginx

# GOOD
- name: Install nginx
  ansible.builtin.apt:
    name: nginx
```

**Short module name:**

```yaml
# BAD (triggers fqcn warning)
- name: Install package
  apt:
    name: nginx

# GOOD
- name: Install package
  ansible.builtin.apt:
    name: nginx
```

**Using shell instead of command:**

```yaml
# BAD (when no shell features needed)
- name: List files
  ansible.builtin.shell: ls -la /tmp

# GOOD
- name: List files
  ansible.builtin.command: ls -la /tmp
  changed_when: false
```

**Missing changed_when:**

```yaml
# BAD (always shows changed)
- name: Check status
  ansible.builtin.command: systemctl status app

# GOOD
- name: Check status
  ansible.builtin.command: systemctl status app
  register: status_check
  changed_when: false
  failed_when: false
```

## Syntax Checking

Validate playbook syntax before running:

```bash
# Check syntax only
uv run ansible-playbook --syntax-check playbooks/my-playbook.yml

# Check mode (dry run)
uv run ansible-playbook playbooks/my-playbook.yml --check

# Diff mode (show changes)
uv run ansible-playbook playbooks/my-playbook.yml --check --diff
```

## Idempotency Testing

Verify playbooks are idempotent by running twice:

```bash
# First run - may show changes
uv run ansible-playbook playbooks/setup.yml

# Second run - should show 0 changes
uv run ansible-playbook playbooks/setup.yml

# If second run shows changes, playbook is NOT idempotent
```

### Automated Idempotency Check

```bash
#!/bin/bash
set -euo pipefail

PLAYBOOK="$1"

echo "First run..."
uv run ansible-playbook "$PLAYBOOK"

echo "Second run (checking idempotency)..."
OUTPUT=$(uv run ansible-playbook "$PLAYBOOK" 2>&1)

if echo "$OUTPUT" | grep -q "changed=0"; then
    echo "✓ Playbook is idempotent"
    exit 0
else
    echo "✗ Playbook is NOT idempotent"
    echo "$OUTPUT" | grep -E "(changed|failed)="
    exit 1
fi
```

## Integration Testing

### Test Against Real Infrastructure

```bash
# Limit to test hosts
uv run ansible-playbook playbooks/deploy.yml --limit test_hosts

# With verbose output
uv run ansible-playbook playbooks/deploy.yml --limit test_hosts -vv
```

### Pre-flight Validation

Add validation tasks at playbook start:

```yaml
---
- name: Deploy with validation
  hosts: all
  become: true

  pre_tasks:
    - name: Validate target environment
      ansible.builtin.assert:
        that:
          - ansible_distribution == "Debian"
          - ansible_distribution_major_version | int >= 11
        fail_msg: "Requires Debian 11+"

    - name: Check connectivity
      ansible.builtin.ping:

    - name: Verify disk space
      ansible.builtin.assert:
        that:
          - ansible_mounts | selectattr('mount', 'equalto', '/') | map(attribute='size_available') | first > 1073741824
        fail_msg: "Insufficient disk space"
```

## Test Playbook Pattern

Create test playbooks for validation:

```yaml
# playbooks/test-role.yml
---
- name: Test role functionality
  hosts: test_hosts
  become: true

  vars:
    test_mode: true

  roles:
    - role: my_role

  tasks:
    - name: Verify service is running
      ansible.builtin.systemd:
        name: myservice
      register: service_status
      failed_when: service_status.status.ActiveState != "active"

    - name: Verify config file exists
      ansible.builtin.stat:
        path: /etc/myservice/config.yml
      register: config_stat
      failed_when: not config_stat.stat.exists

    - name: Verify port is listening
      ansible.builtin.wait_for:
        port: 8080
        timeout: 10
```

## CI/CD Integration

### GitHub Actions

```yaml
name: Ansible Lint

on: [push, pull_request]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.13'

      - name: Install uv
        run: pip install uv

      - name: Install dependencies
        run: uv sync

      - name: Run ansible-lint
        run: uv run ansible-lint ansible/
```

## Debugging Playbooks

### Verbose Output

```bash
# Increase verbosity
uv run ansible-playbook playbook.yml -v    # Basic
uv run ansible-playbook playbook.yml -vv   # More detail
uv run ansible-playbook playbook.yml -vvv  # Connection debugging
uv run ansible-playbook playbook.yml -vvvv # Maximum detail
```

### Debug Tasks

```yaml
- name: Debug variable value
  ansible.builtin.debug:
    var: my_variable

- name: Debug with message
  ansible.builtin.debug:
    msg: "The value is {{ my_variable }}"

- name: Debug registered result
  ansible.builtin.debug:
    var: command_result
  when: ansible_verbosity > 0
```

### Step Mode

```bash
# Pause after each task
uv run ansible-playbook playbook.yml --step
```

## Lint Profiles

Choose appropriate profile based on needs:

| Profile | Strictness | Use Case |
|---------|------------|----------|
| `min` | Lowest | Legacy code, quick fixes |
| `basic` | Low | Development |
| `moderate` | Medium | General infrastructure |
| `safety` | High | Security-sensitive |
| `production` | Highest | Production deployments |

## Additional Resources

For detailed testing patterns and techniques, consult:

- **`references/testing-comprehensive.md`** - ansible-lint configuration, integration testing strategies, CI/CD patterns

## Related Skills

- **ansible-fundamentals** - Core Ansible patterns
- **ansible-idempotency** - Ensuring tasks are idempotent

Files in this skill

  • SKILL.md7.2 KB
  • references/testing-comprehensive.md32.1 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.