🧪 Skills

EZ Ansible Skill

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

v1.0.0
❤️ 0
⬇️ 117
👁 2
Share

Description


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/<name>.yml
- name: <Descriptive play name>
  hosts: <inventory_group>
  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: <role_name>
      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: <service>
        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/<role_name>/
├── 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/
│   └── <config>.conf.j2
├── files/
│   └── <static_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: <role_name>
# 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:

<project_name>/
├── ansible.cfg
├── requirements.yml          # Galaxy roles/collections
├── site.yml                  # Master playbook
├── playbooks/
│   ├── deploy.yml
│   ├── rollback.yml
│   └── maintenance.yml
├── roles/
│   └── <role_name>/          # 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

Reviews (0)

Sign in to write a review.

No reviews yet. Be the first to review!

Comments (0)

Sign in to join the discussion.

No comments yet. Be the first to share your thoughts!

Compatible Platforms

Pricing

Free

Related Configs