🎁 Get the FREE AI Skills Starter Guide β€” Subscribe β†’
BytesAgainBytesAgain
πŸ¦€ ClawHub

EZ Ansible Skill

by @klima911

Generate, review, and optimize Ansible automation artifacts. Use this skill whenever the user mentions Ansible, playbooks, roles, inventory, tasks, handlers,...

TERMINAL
clawhub install klimatex911

πŸ“– About This Skill


name: ansible description: > Generate, review, and optimize Ansible automation artifacts. Use this skill whenever the user mentions Ansible, playbooks, roles, inventory, tasks, handlers, Jinja2 templates, ansible.cfg, Galaxy, AWX, or any infrastructure automation using YAML-based configuration management. Trigger even for vague requests like "automate server setup", "deploy my app with Ansible", "write a role for nginx", "create an inventory file", or "how do I configure hosts in Ansible". This skill covers the full lifecycle: generating playbooks, scaffolding roles, writing inventories, creating Jinja2 templates, designing variable structures, and producing CI/CD-ready Ansible project layouts.

Ansible Skill

A skill for generating production-grade Ansible automation: playbooks, roles, inventories, Jinja2 templates, variable files, and complete project structures following official best practices.


Workflow Overview

1. Clarify Intent        β†’ Understand target OS, task type, scale, idempotency needs
2. Choose Output Type    β†’ Playbook / Role / Inventory / Template / Full Project
3. Generate Artifacts    β†’ Produce YAML files with best practices embedded
4. Validate & Annotate  β†’ Add lint hints, --check commands, and idempotency notes
5. Deliver Structure     β†’ Present files with clear directory paths and run instructions


Step 1: Clarify Intent

Before generating, collect the following (infer from context when possible):

| Parameter | Description | Example | |-------------------|--------------------------------------------------|----------------------------| | target_os | OS family of managed hosts | Ubuntu 22.04, RHEL 9 | | task_type | What to automate | deploy app, manage users | | connection_type | How Ansible connects | SSH (default), WinRM | | privilege | Needs sudo/become? | yes / no | | scale | Number of hosts / groups | 3 webservers, 1 DB | | idempotency | Must be safe to re-run? | yes (always recommended) | | var_source | Where variables come from | group_vars, vault, extra |

If context is clear, skip the interview and generate directly.


Step 2: Output Types

A) Single Playbook

Use for: ad-hoc tasks, simple automation, one-off operations.

Template:

---

playbooks/.yml

  • name:
  • hosts: become: true gather_facts: true

    vars: app_port: 8080 app_user: deploy

    pre_tasks: - name: Ensure required packages are present ansible.builtin.package: name: "{{ item }}" state: present loop: - curl - git

    roles: - role: when: ansible_os_family == "Debian"

    tasks: - name: Task description (use verb + object) ansible.builtin.module: param: value notify: Restart service tags: - setup - deploy

    handlers: - name: Restart service ansible.builtin.service: name: state: restarted

    Rules:

  • Always use FQCN (Fully Qualified Collection Names): ansible.builtin.copy, not copy
  • Use state: present/absent for idempotency
  • Add tags for selective execution
  • Use notify + handlers for service restarts (never restart inline)
  • Prefer loop over with_items (deprecated)

  • B) Role Scaffold

    Use for: reusable, shareable, testable automation units.

    Directory structure:

    roles//
    β”œβ”€β”€ defaults/
    β”‚   └── main.yml          # Low-priority defaults (overridable)
    β”œβ”€β”€ vars/
    β”‚   └── main.yml          # High-priority role-internal vars
    β”œβ”€β”€ tasks/
    β”‚   β”œβ”€β”€ main.yml          # Entry point (import_tasks per OS/feature)
    β”‚   β”œβ”€β”€ install.yml
    β”‚   β”œβ”€β”€ configure.yml
    β”‚   └── service.yml
    β”œβ”€β”€ handlers/
    β”‚   └── main.yml
    β”œβ”€β”€ templates/
    β”‚   └── .conf.j2
    β”œβ”€β”€ files/
    β”‚   └── 
    β”œβ”€β”€ meta/
    β”‚   └── main.yml          # Galaxy metadata, dependencies
    └── README.md
    

    tasks/main.yml pattern:

    ---
    
  • name: Include OS-specific variables
  • ansible.builtin.include_vars: "{{ ansible_os_family }}.yml" failed_when: false

  • ansible.builtin.import_tasks: install.yml
  • tags: [install]

  • ansible.builtin.import_tasks: configure.yml
  • tags: [configure]

  • ansible.builtin.import_tasks: service.yml
  • tags: [service]

    defaults/main.yml pattern:

    ---
    

    Role:

    All variables with safe defaults

    role_package_name: nginx role_service_name: nginx role_config_path: /etc/nginx/nginx.conf role_user: www-data role_port: 80 role_enabled: true


    C) Inventory

    Static inventory (INI format):

    # inventory/hosts

    [webservers] web01.example.com ansible_host=10.0.1.10 web02.example.com ansible_host=10.0.1.11

    [databases] db01.example.com ansible_host=10.0.2.10

    [loadbalancers] lb01.example.com

    [production:children] webservers databases loadbalancers

    [all:vars] ansible_user=deploy ansible_ssh_private_key_file=~/.ssh/id_rsa ansible_python_interpreter=/usr/bin/python3

    Static inventory (YAML format β€” preferred):

    # inventory/hosts.yml
    all:
      vars:
        ansible_user: deploy
        ansible_python_interpreter: /usr/bin/python3

    children: webservers: hosts: web01: ansible_host: 10.0.1.10 http_port: 80 web02: ansible_host: 10.0.1.11 http_port: 80

    databases: hosts: db01: ansible_host: 10.0.2.10 db_port: 5432

    staging: children: webservers: databases:

    group_vars structure:

    inventory/
    β”œβ”€β”€ hosts.yml
    β”œβ”€β”€ group_vars/
    β”‚   β”œβ”€β”€ all.yml              # Applies to all hosts
    β”‚   β”œβ”€β”€ all/
    β”‚   β”‚   β”œβ”€β”€ vars.yml
    β”‚   β”‚   └── vault.yml        # ansible-vault encrypted secrets
    β”‚   β”œβ”€β”€ webservers.yml
    β”‚   └── databases.yml
    └── host_vars/
        └── web01.yml
    


    D) Jinja2 Templates

    Config file template pattern:

    {# templates/nginx.conf.j2 #}
    {# Managed by Ansible - Do not edit manually #}

    user {{ nginx_user | default('www-data') }}; worker_processes {{ nginx_worker_processes | default(ansible_processor_vcpus) }};

    events { worker_connections {{ nginx_worker_connections | default(1024) }}; }

    http { include mime.types; default_type application/octet-stream;

    {% if nginx_log_format is defined %} log_format main '{{ nginx_log_format }}'; {% endif %}

    {% for vhost in nginx_vhosts | default([]) %} server { listen {{ vhost.port | default(80) }}; server_name {{ vhost.name }}; root {{ vhost.root }};

    {% if vhost.ssl | default(false) %} listen 443 ssl; ssl_certificate {{ vhost.ssl_cert }}; ssl_certificate_key {{ vhost.ssl_key }}; {% endif %} } {% endfor %} }

    Key Jinja2 patterns:

    {# Default filter #}
    {{ variable | default('fallback_value') }}

    {# Conditional block #} {% if ansible_os_family == "Debian" %} apt_cache_valid_time: 3600 {% elif ansible_os_family == "RedHat" %} yum_releasever: latest {% endif %}

    {# Loop over dict #} {% for key, value in config_dict.items() %} {{ key }} = {{ value }} {% endfor %}

    {# Join list #} {{ my_list | join(', ') }}

    {# Uppercase / replace #} {{ service_name | upper | replace('-', '_') }}


    E) Variable Files

    Priority order (high β†’ low):

    extra vars (-e)           # Highest priority
    task vars
    block vars
    role and include vars
    play vars
    host facts
    host_vars
    group_vars/all
    role defaults            # Lowest priority
    

    vault.yml pattern (sensitive data):

    # group_vars/all/vault.yml
    

    Encrypt with: ansible-vault encrypt vault.yml

    vault_db_password: "super_secret_password" vault_api_key: "abc123xyz" vault_ssl_cert_content: | -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----

    vars.yml (reference vault vars):

    # group_vars/all/vars.yml
    db_password: "{{ vault_db_password }}"
    api_key: "{{ vault_api_key }}"
    


    F) ansible.cfg

    [defaults]
    inventory           = ./inventory/hosts.yml
    roles_path          = ./roles:~/.ansible/roles
    collections_paths   = ./collections:~/.ansible/collections
    remote_user         = deploy
    private_key_file    = ~/.ssh/id_rsa
    host_key_checking   = False
    retry_files_enabled = False
    stdout_callback     = yaml
    callbacks_enabled   = profile_tasks, timer
    interpreter_python  = auto_silent

    Performance tuning

    forks = 10 pipelining = True gathering = smart fact_caching = jsonfile fact_caching_connection = /tmp/ansible_facts fact_caching_timeout = 3600

    [privilege_escalation] become = True become_method = sudo become_user = root become_ask_pass = False

    [ssh_connection] ssh_args = -C -o ControlMaster=auto -o ControlPersist=60s control_path_dir = /tmp/.ansible/cp


    Step 3: Full Project Structure

    For complete projects, generate this layout:

    /
    β”œβ”€β”€ ansible.cfg
    β”œβ”€β”€ requirements.yml          # Galaxy roles/collections
    β”œβ”€β”€ site.yml                  # Master playbook
    β”œβ”€β”€ playbooks/
    β”‚   β”œβ”€β”€ deploy.yml
    β”‚   β”œβ”€β”€ rollback.yml
    β”‚   └── maintenance.yml
    β”œβ”€β”€ roles/
    β”‚   └── /          # See Role Scaffold above
    β”œβ”€β”€ inventory/
    β”‚   β”œβ”€β”€ production/
    β”‚   β”‚   β”œβ”€β”€ hosts.yml
    β”‚   β”‚   β”œβ”€β”€ group_vars/
    β”‚   β”‚   └── host_vars/
    β”‚   └── staging/
    β”‚       β”œβ”€β”€ hosts.yml
    β”‚       └── group_vars/
    β”œβ”€β”€ collections/
    β”‚   └── requirements.yml
    β”œβ”€β”€ filter_plugins/           # Custom Jinja2 filters
    β”œβ”€β”€ library/                  # Custom modules
    └── .github/
        └── workflows/
            └── ansible-lint.yml  # CI validation
    

    requirements.yml:

    ---
    collections:
      - name: community.general
        version: ">=7.0.0"
      - name: ansible.posix
      - name: community.docker
        version: "3.4.0"

    roles: - name: geerlingguy.nodejs version: "6.1.0" - src: https://github.com/org/role.git scm: git version: main name: custom_role


    Step 4: Validation & Run Instructions

    Always append these to generated output:

    Syntax check:

    ansible-playbook playbooks/deploy.yml --syntax-check
    

    Dry run (no changes):

    ansible-playbook playbooks/deploy.yml --check --diff
    

    Lint (requires ansible-lint):

    pip install ansible-lint
    ansible-lint playbooks/deploy.yml
    

    Run with vault:

    ansible-playbook playbooks/deploy.yml --ask-vault-pass
    

    or with vault password file:

    ansible-playbook playbooks/deploy.yml --vault-password-file ~/.vault_pass

    Limit to specific hosts/groups:

    ansible-playbook site.yml --limit webservers
    ansible-playbook site.yml --limit web01.example.com
    

    Run specific tags:

    ansible-playbook site.yml --tags deploy,configure
    ansible-playbook site.yml --skip-tags debug
    

    Ad-hoc commands:

    # Ping all hosts
    ansible all -m ping

    Gather facts

    ansible webservers -m ansible.builtin.setup

    Run shell command

    ansible databases -m ansible.builtin.shell -a "df -h"

    Copy file

    ansible all -m ansible.builtin.copy -a "src=file.conf dest=/etc/file.conf"


    Best Practices Checklist

    Always apply these principles:

  • βœ… FQCN: Use ansible.builtin.copy, not copy
  • βœ… Idempotency: Every task must be safe to re-run
  • βœ… State explicit: Always specify state: on resource modules
  • βœ… No shell when avoidable: Prefer native modules over shell/command
  • βœ… Handlers for restarts: Never restart services inline in tasks
  • βœ… Tags: Tag every task/block for selective execution
  • βœ… Vault for secrets: Never hardcode passwords or keys in plaintext
  • βœ… Defaults for all role vars: Every role var must have a default
  • βœ… changed_when / failed_when: Set on shell/command tasks
  • βœ… when conditions: Use Ansible facts, not shell conditionals
  • βœ… Header comment: First line of every file: # Managed by Ansible

  • Common Module Reference

    | Task | Module | |-------------------------|---------------------------------| | Install packages | ansible.builtin.package | | Copy files | ansible.builtin.copy | | Template files | ansible.builtin.template | | Manage services | ansible.builtin.service | | Manage users | ansible.builtin.user | | Run commands | ansible.builtin.command | | Run shell | ansible.builtin.shell | | Manage files/dirs | ansible.builtin.file | | Edit lines in files | ansible.builtin.lineinfile | | Download files | ansible.builtin.get_url | | Unarchive tarballs | ansible.builtin.unarchive | | Manage cron jobs | ansible.builtin.cron | | Manage firewall | ansible.posix.firewalld | | Docker containers | community.docker.docker_container | | Git clone | ansible.builtin.git | | Wait for condition | ansible.builtin.wait_for | | Set facts | ansible.builtin.set_fact | | Assert conditions | ansible.builtin.assert | | Include variables | ansible.builtin.include_vars | | Debug output | ansible.builtin.debug |


    Output Format Guidelines

    When delivering Ansible artifacts:

    1. Always show full file path as a comment at top of each file 2. Group related files together with clear separators 3. Explain non-obvious choices inline with # comment 4. Provide run command at the end of every response 5. Flag secrets β€” point out where vault encryption is needed 6. One file per code block β€” never mix multiple files in one block