6. Writing the verification play

Verification code is a regular playbook that asserts the elements configured by the converge play. The main tool is the ansible.builtin.assert module, which evaluates Jinja2 tests and filters against Ansible variables - including facts, registered results, and user-defined variables. Combine assertions with other modules such as package_facts, service_facts, or wait_for (for port checks), etc., to verify that the converge play produced the expected results.

Note

The verify play is not intended to check idempotency. That aspect is handled by running the converge step twice, which is performed automatically during the idempotency phase.

# verify.yml
---
- name: Verify
  hosts: webservers
  become: true
  tasks:
    - name: Check if Apache is installed
      ansible.builtin.package_facts:
        manager: auto

    - name: Verify Apache package is installed
      ansible.builtin.assert:
        that:
          - "'apache2' in ansible_facts.packages"
        fail_msg: "Apache (apache2) package is not installed"

    # === Service Block ===
    - name: Gather service facts
      ansible.builtin.service_facts:

    - name: Assert apache2 service is running on Debian
      ansible.builtin.assert:
        that:
          - "'apache2' in ansible_facts.services"
          - "ansible_facts.services['apache2'].state == 'running'"
        fail_msg: "Apache (apache2) service is not running on Debian system"
        success_msg: "Apache (apache2) service is running on Debian system"

    # === TCP Block ===
    - name: Check if port 80 is open (Apache)
      ansible.builtin.wait_for:
        port: 80
        host: "{{ ansible_default_ipv4.address | default('127.0.0.1') }}"
        state: started
        timeout: 5
      register: apache_port_check

    - name: Assert port 80 is accessible
      ansible.builtin.assert:
        that:
          - apache_port_check.state == "started"
        fail_msg: "Port 80 is not accessible"
        success_msg: "Port 80 is accessible"