| name | ansible-conventions |
| description | Ansible coding conventions including task structure, module usage, variable patterns, OpenWrt constraints, and network restart patterns. |
Ansible Coding Conventions
Use when writing Ansible tasks, configuring OpenWrt systems, managing Proxmox hosts, or following project coding standards.
Rules
- ALWAYS use fully qualified collection names (
ansible.builtin.command, not command)
- NEVER use
local_action - always use delegate_to: localhost
- ALWAYS include
changed_when or failed_when on command/shell tasks
- ALWAYS use
community.proxmox.proxmox_kvm (NOT community.general.proxmox_kvm)
- ALWAYS use OpenWrt commands with
ansible.builtin.raw ONLY (no Python)
- NEVER mix legacy directives with RainerScript in rsyslog configs
- ALWAYS capitalize first word in handler names and match
notify: exactly
- NEVER install packages in configure roles - bake into images instead
Patterns
Task structure:
- name: Configure service
ansible.builtin.command: systemctl enable service
changed_when: true
when: not vm_exists | bool
OpenWrt two-phase restart:
- name: Configure network interfaces
ansible.builtin.raw: uci set network.lan.ipaddr='192.168.1.1'
ansible.builtin.raw: uci commit network
- name: Install packages
ansible.builtin.raw: opkg install package-name
- name: Set final LAN IP
ansible.builtin.raw: uci set network.lan.ipaddr='10.10.10.1'
Detached restart pattern:
- name: Schedule restart via detached script
ansible.builtin.raw: >-
printf '#!/bin/sh\nsleep 3\n/etc/init.d/network restart\nsleep 5\n/etc/init.d/dropbear restart\nrm -f /tmp/_restart_net.sh\n'
> /tmp/_restart_net.sh &&
chmod +x /tmp/_restart_net.sh &&
start-stop-daemon -S -b -x /tmp/_restart_net.sh
ignore_unreachable: true
Container File Deployment Patterns
When writing files inside LXC containers via pct exec:
- name: Create config file in container
ansible.builtin.shell:
cmd: |
set -o pipefail
pct exec {{ ct_id }} -- bash -c 'cat > /path/config.yml << "EOF"
key: value
nested:
item: data
EOF
chmod 0644 /path/config.yml'
executable: /bin/bash
changed_when: true
NEVER use Ansible template/copy modules for files inside containers
when running from the host context — they write to the HOST filesystem.
For Docker-in-LXC services, the configure play runs on the HOST (e.g.,
service_nodes), not on the container dynamic group. Use pct exec
with the container ID from group_vars/all.yml.
Anti-patterns
NEVER explain what Ansible is in coding conventions
NEVER use heredocs in YAML | blocks for OpenWrt scripts (indentation breaks shebang)
NEVER install packages during configure roles
NEVER hardcode bridge names (vmbr0, vmbr1) - use auto-detection
NEVER use Ansible template/copy modules for files inside containers from host context
NEVER target container dynamic group when role uses pct exec - target the host group
NEVER use Docker --format "{{.X}}" in Ansible tasks without Jinja2 escaping