Testing #
Playbook tanpa test adalah hutang teknis yang menunggu waktu untuk meledak. Perubahan kecil di role bisa membreak deployment di lingkungan yang tidak terduga. Template yang berubah bisa menghasilkan konfigurasi yang tidak valid. Dependency yang diupdate bisa membawa breaking change. Testing Ansible bukanlah kemewahan — ia adalah praktik yang membuat kamu percaya diri untuk mengubah kode dan mendeploy tanpa rasa takut.
ansible-lint: Static Analysis #
ansible-lint menganalisis playbook dan role untuk menemukan masalah tanpa perlu menjalankannya:
pip install ansible-lint
# Lint satu playbook
ansible-lint site.yml
# Lint seluruh project
ansible-lint
# Dengan output yang lebih detail
ansible-lint -v site.yml
Konfigurasi ansible-lint via file .ansible-lint di root project:
# .ansible-lint
profile: production # Level keketatan: min, basic, moderate, safety, shared, production
skip_list:
- yaml[line-length] # Skip rule panjang baris (sesuaikan dengan preferensi tim)
- name[template] # Skip rule template di nama task
warn_list:
- experimental # Warning, bukan error untuk rule experimental
exclude_paths:
- .cache/
- molecule/
- tests/
Molecule: Integration Testing untuk Role #
Molecule adalah framework testing khusus untuk Ansible role. Ia menyiapkan environment (container atau VM), menjalankan role, kemudian memverifikasi hasilnya:
pip install molecule molecule-plugins[docker]
Inisialisasi Molecule untuk role yang sudah ada:
cd roles/nginx
molecule init scenario --driver-name docker
Struktur yang dihasilkan:
roles/nginx/
└── molecule/
└── default/
├── molecule.yml # Konfigurasi scenario
├── converge.yml # Playbook yang menjalankan role
└── verify.yml # Playbook untuk verifikasi hasil
# roles/nginx/molecule/default/molecule.yml
---
dependency:
name: galaxy
driver:
name: docker
platforms:
- name: ubuntu-22
image: geerlingguy/docker-ubuntu2204-ansible:latest
pre_build_image: true
- name: ubuntu-20
image: geerlingguy/docker-ubuntu2004-ansible:latest
pre_build_image: true
provisioner:
name: ansible
verifier:
name: ansible
# roles/nginx/molecule/default/converge.yml
---
- name: Converge
hosts: all
become: true
vars:
nginx_port: 80
nginx_ssl_enabled: false
roles:
- role: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') | basename }}"
# roles/nginx/molecule/default/verify.yml
---
- name: Verify
hosts: all
gather_facts: false
tasks:
- name: Cek nginx terinstal
command: nginx -v
register: nginx_version
changed_when: false
- name: Cek nginx berjalan
systemd:
name: nginx
register: nginx_status
- name: Assert nginx aktif
assert:
that:
- nginx_status.status.ActiveState == "active"
fail_msg: "nginx tidak berjalan setelah role dieksekusi"
- name: Cek konfigurasi nginx valid
command: nginx -t
changed_when: false
- name: Verifikasi port 80 terbuka
wait_for:
port: 80
timeout: 10
state: started
Menjalankan Molecule test:
# Test penuh: create → converge → verify → destroy
molecule test
# Hanya converge (berguna saat develop)
molecule converge
# Hanya verify (setelah converge manual)
molecule verify
# Login ke container untuk debugging
molecule login --host ubuntu-22
testinfra: Verifikasi State Server #
testinfra adalah library Python untuk menulis test yang memverifikasi state server setelah playbook dieksekusi:
pip install pytest-testinfra
# tests/test_nginx.py
import pytest
def test_nginx_installed(host):
"""nginx harus terinstal"""
nginx = host.package("nginx")
assert nginx.is_installed
def test_nginx_running(host):
"""nginx service harus berjalan dan aktif"""
nginx_service = host.service("nginx")
assert nginx_service.is_running
assert nginx_service.is_enabled
def test_nginx_listening(host):
"""nginx harus mendengarkan di port 80"""
socket = host.socket("tcp://0.0.0.0:80")
assert socket.is_listening
def test_nginx_config_valid(host):
"""konfigurasi nginx harus valid"""
result = host.run("nginx -t")
assert result.rc == 0
def test_config_file_exists(host):
"""file konfigurasi harus ada dengan permission yang benar"""
config = host.file("/etc/nginx/nginx.conf")
assert config.exists
assert config.mode == 0o644
assert config.user == "root"
# Jalankan test terhadap host tertentu
pytest tests/test_nginx.py --hosts=ssh://[email protected]
Integrasikan Testing ke CI Pipeline #
# .github/workflows/test.yml
name: Test Ansible Role
on:
pull_request:
paths:
- 'roles/**'
- 'playbooks/**'
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: pip install ansible ansible-lint
- run: ansible-lint
molecule:
runs-on: ubuntu-latest
strategy:
matrix:
role: [nginx, postgresql, common]
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install test dependencies
run: pip install ansible molecule molecule-plugins[docker] pytest-testinfra
- name: Jalankan Molecule test
run: |
cd roles/${{ matrix.role }}
molecule test
env:
PY_COLORS: "1"
ANSIBLE_FORCE_COLOR: "1"
Ringkasan #
ansible-lintuntuk static analysis — temukan masalah syntax, best practice violation, dan potential bug sebelum playbook dijalankan.- Molecule untuk integration testing role — test role secara terisolasi di container, verifikasi bahwa role menghasilkan state yang diharapkan.
molecule testmenjalankan siklus penuh: create → converge → verify → destroy — gunakanmolecule convergesaat develop untuk loop yang lebih cepat.- testinfra untuk verifikasi state server dengan Python test — lebih ekspresif dari verify.yml Molecule untuk kasus kompleks.
- Integrasikan testing ke CI pipeline pada setiap pull request — pastikan tidak ada role yang bisa di-merge tanpa passing test.
- Mulai sederhana:
ansible-lintdulu, lalu tambahkan Molecule satu role sekaligus — jangan coba setup testing untuk semua role sekaligus.