Skip to main content

ansible-operations

Ansible playbook/role conventions, Molecule testing patterns, and ansible-agent invocation for the infra-cd repository.

Ir a la instalación

Datos de origen

Repositorio
dark-vex/infra-cd
Última actividad en el origen
26 de julio de 2026 a las 12:40
Idioma detectado de SKILL.md
inglés
Estrellas
8
Forks
0

Opciones de instalación

De forma predeterminada está seleccionado el prompt que primero revisa el origen. Puedes cambiar a un comando directo o descargar una copia local.

Revisa los archivos de origen

Lee SKILL.md y los archivos complementarios que muestra SkillsMP antes de decidir si quieres instalarlo.

Mostrando SKILL.md

SKILL.md
Instrucciones de origen · Vista previa de solo lectura
name
ansible-operations
description
Ansible playbook/role conventions, Molecule testing patterns, and ansible-agent invocation for the infra-cd repository.
when_to_invoke
Any edit under ansible/ — new playbook, new role, task modifications, template changes, or adding a new playbook directory.
paths
ansible/**
# Ansible Operations ## Hard rule: Molecule is mandatory **Every** playbook or role directory under `ansible/` MUST ship a Molecule scenario before merging. No exceptions. Required structure for each playbook directory: ``` ansible/{playbook-name}/ ├── playbook.yml # thin wrapper: import_tasks + import handlers ├── tasks/main.yml # all tasks extracted here (reusable by Molecule) ├── handlers/main.yml # all handlers extracted here ├── group_vars/ # non-secret defaults ├── templates/ # Jinja2 templates ├── inventory.yml # production inventory └── molecule/ └── default/ ├── molecule.yml # docker driver + platform config ├── converge.yml # stub secrets + import_tasks ../../tasks/main.yml └── verify.yml # assertions (files, permissions, packages, service enabled) ``` PRs that add or modify tasks without a Molecule scenario should not be approved. --- ## Canonical examples | Playbook | Molecule location | Notes | |---|---|---| | `ansible/falco/` | `ansible/falco/molecule/default/` | Simple pattern, no systemd services started | | `ansible/pve-monitoring/` | `ansible/pve-monitoring/molecule/default/` | Full systemd pattern (pve-exporter + alloy) | | `ansible/iredmail/iredapd/` | `ansible/iredmail/iredapd/molecule/default/` | Service-specific scenario | --- ## Molecule scenario template ### `molecule/default/molecule.yml` ```yaml --- dependency: name: galaxy driver: name: docker platforms: - name: {playbook-name}-test image: geerlingguy/docker-debian12-ansible:latest pre_build_image: true privileged: true command: /lib/systemd/systemd cgroupns_mode: host volumes: - /sys/fs/cgroup:/sys/fs/cgroup:rw tmpfs: - /run - /tmp provisioner: name: ansible playbooks: converge: converge.yml inventory: host_vars: {playbook-name}-test: ansible_python_interpreter: /usr/bin/python3 # add any host_vars that normally live in inventory.yml verifier: name: ansible ``` **Always use** `geerlingguy/docker-debian12-ansible:latest` as the test image — it has systemd, Python, and common Ansible prerequisites pre-installed. Use `privileged: true` + `cgroupns_mode: host` + cgroup volume whenever the play manages `ansible.builtin.systemd`. ### `molecule/default/converge.yml` ```yaml --- - name: Converge hosts: all become: true gather_facts: true vars: # Template base dir — templates/ is at playbook root, two levels up from molecule/default/ pve_templates_dir: "{{ playbook_dir }}/../../templates" # Stub secrets — never use real values in Molecule secret_var: "test-stub-value" vars_files: - ../../group_vars/{group}.yml # load non-secret defaults tasks: - name: Run tasks ansible.builtin.import_tasks: ../../tasks/main.yml handlers: - import_tasks: ../../handlers/main.yml ``` Key rules: - **Never** reference real secrets — use clearly fake stubs. - **Always** load `group_vars/*.yml` via `vars_files` so defaults match production. - Use `import_tasks` (static, not `include_tasks`) for full idempotency checking. - **Template path resolution**: `ansible.builtin.template` resolves `src:` relative to the invoking playbook's directory, not the tasks file. Use a `{playbook}_templates_dir` variable in `tasks/main.yml` and set it to `{{ playbook_dir }}/templates` in `playbook.yml` and `{{ playbook_dir }}/../../templates` in `converge.yml`. ### `molecule/default/verify.yml` ```yaml --- - name: Verify {playbook-name} installation hosts: all become: true gather_facts: false tasks: - name: Check config file exists ansible.builtin.stat: path: /path/to/config register: config_file - name: Assert config file is present ansible.builtin.assert: that: config_file.stat.exists - name: Check package is installed ansible.builtin.package_facts: manager: apt - name: Assert package is installed ansible.builtin.assert: that: "'package-name' in ansible_facts.packages" - name: Check service is enabled ansible.builtin.systemd: name: service-name register: svc_info - name: Assert service is enabled ansible.builtin.assert: that: svc_info.status.UnitFileState == "enabled" ``` Verify **file existence + permissions**, **package installation**, and **service enabled state**. Do NOT assert `active` service state — services that depend on external infrastructure (PVE, Grafana, databases) will not actually connect in test containers. --- ## Running Molecule via ansible-agent Prefer dispatching to `ansible-agent` via the Agent tool (`subagent_type: ansible-agent`) over running these commands directly with Bash — it's the real Task-tool path the agent is defined for, not a manual fallback. The `ansible-agent` container has `molecule`, `molecule-plugins[docker]`, and Docker CLI pre-installed. The host Docker socket is mounted, so Molecule manages test containers from inside the agent. ```bash # Start the agent (once per session) cd /path/to/infra-cd/docker/agents docker compose up -d ansible-agent # Full test run (recommended before every PR) docker compose exec -w /workspace/ansible/{playbook-name} ansible-agent \ molecule test # Step-by-step (during development) docker compose exec -w /workspace/ansible/{playbook-name} ansible-agent molecule create docker compose exec -w /workspace/ansible/{playbook-name} ansible-agent molecule converge docker compose exec -w /workspace/ansible/{playbook-name} ansible-agent molecule verify docker compose exec -w /workspace/ansible/{playbook-name} ansible-agent molecule idempotence docker compose exec -w /workspace/ansible/{playbook-name} ansible-agent molecule destroy # Login to test container for debugging docker compose exec -w /workspace/ansible/{playbook-name} ansible-agent \ molecule login # Clean slate after a failed run docker compose exec -w /workspace/ansible/{playbook-name} ansible-agent molecule destroy ``` `molecule test` runs the full sequence: dependency → lint → cleanup → destroy → syntax → create → prepare → converge → **idempotence** → side_effect → verify → cleanup → destroy. The **idempotence** step re-runs converge and asserts zero changed tasks. This is often the hardest to pass — common causes: - `ansible.builtin.shell` without `creates:` or `changed_when: false` - `apt` with `state: latest` (use `state: present` + pinned version) - `lineinfile` with `create: true` (first run creates file → second run is idempotent, OK) --- ## Claude-driven iteration workflow When tests fail, the iteration pattern is: 1. Run `molecule test`, capture full output. 2. Identify the failing step (converge / idempotency / verify). 3. Edit the task file (`tasks/main.yml`) or scenario file (`molecule/default/{converge,verify}.yml`). 4. If the container state is dirty after a crash, run `molecule destroy` first. 5. Re-run `molecule test`. Cap at 8 iterations; surface root cause to user if still failing. --- ## Secrets in tests - Set stub values as plain vars inside `converge.yml` (`vars:` block). - Never import from 1Password, vault files, or external sources during Molecule runs. - If a template renders a URL/credential that gets validated at runtime (e.g., `curl` to Grafana), mock with a valid-format fake URL — the service won't connect, but the template renders. --- ## CI integration (future) Molecule is not yet wired into GitHub Actions. Until it is, scenarios **must** pass locally (via `ansible-agent`) before merge. Track this as follow-up work. --- ## Linting ```bash # Lint before Molecule (ansible-agent has ansible-lint installed) docker compose exec ansible-agent ansible-lint /workspace/ansible/{playbook-name}/playbook.yml ```
Ver en GitHub