349 lines
7.8 KiB
Markdown
349 lines
7.8 KiB
Markdown
---
|
|
description: Develop Ansible roles and playbooks
|
|
argument-hint: Optional role or playbook requirements
|
|
---
|
|
|
|
# Ansible Development
|
|
|
|
You are developing Ansible automation (roles, playbooks, tasks, handlers) using the ansible-developer agent.
|
|
|
|
## Workflow
|
|
|
|
### 1. Identify Development Type
|
|
|
|
Determine what to develop:
|
|
- **New role**: Complete role with tasks, handlers, defaults
|
|
- **New playbook**: Standalone playbook or site playbook
|
|
- **Task enhancement**: Add/modify tasks in existing role
|
|
- **Handler creation**: Create service handlers
|
|
- **Variable management**: Define defaults and vars
|
|
- **Module development**: Custom Ansible modules
|
|
|
|
### 2. Gather Requirements
|
|
|
|
If not specified, ask for:
|
|
|
|
**For Roles**:
|
|
- Role name and purpose
|
|
- Target systems (OS, distributions)
|
|
- Dependencies (packages, services, other roles)
|
|
- Configuration files needed
|
|
- Variables and their defaults
|
|
- Handlers required (restarts, reloads)
|
|
- Tags for selective execution
|
|
|
|
**For Playbooks**:
|
|
- Playbook purpose (deploy, configure, maintain)
|
|
- Target host groups
|
|
- Roles to include
|
|
- Pre-tasks and post-tasks
|
|
- Variables needed
|
|
- Execution order
|
|
|
|
**For Tasks**:
|
|
- What the task should accomplish
|
|
- Modules to use (package, service, template, etc.)
|
|
- Idempotency requirements
|
|
- Error handling needs
|
|
- Conditionals (OS-specific, etc.)
|
|
|
|
### 3. Launch Development Agent
|
|
|
|
Launch **ansible-developer** with complete requirements:
|
|
|
|
```
|
|
"Create Ansible role named [role-name] that [purpose].
|
|
Target systems: [OS/distro]
|
|
Requirements:
|
|
- Install and configure [software]
|
|
- Manage [service] with handlers
|
|
- Template [config-files]
|
|
- Variables: [list with defaults]
|
|
- Support check mode
|
|
- Include example playbook"
|
|
```
|
|
|
|
### 4. Review Generated Code
|
|
|
|
Check the developed automation for:
|
|
- **Idempotency**: All tasks can run multiple times safely
|
|
- **Module usage**: Proper Ansible modules (not shell when module exists)
|
|
- **Task naming**: Descriptive names starting with verbs
|
|
- **Variables**: Proper namespacing (role_name_variable)
|
|
- **Handlers**: Appropriate handler usage
|
|
- **Error handling**: Block/rescue where needed
|
|
- **Check mode**: Support for `--check` flag
|
|
- **Tags**: Meaningful tags for selective execution
|
|
|
|
### 5. Test Development
|
|
|
|
Run validation commands:
|
|
|
|
```bash
|
|
# Syntax check
|
|
ansible-playbook playbooks/test.yml --syntax-check
|
|
|
|
# Lint check
|
|
ansible-lint roles/[role-name]/
|
|
|
|
# Check mode (dry run)
|
|
ansible-playbook playbooks/test.yml --check
|
|
|
|
# Run on test environment
|
|
ansible-playbook playbooks/test.yml -i inventory/development
|
|
|
|
# Run specific tags
|
|
ansible-playbook playbooks/test.yml --tags "install,config"
|
|
|
|
# Verbose output for debugging
|
|
ansible-playbook playbooks/test.yml -vv
|
|
```
|
|
|
|
### 6. Iterate if Needed
|
|
|
|
If issues found:
|
|
- Launch ansible-code-reviewer to identify problems
|
|
- Fix issues with ansible-developer
|
|
- Re-test until all checks pass
|
|
|
|
## Common Development Patterns
|
|
|
|
### Creating a Role
|
|
|
|
**Example: Web Server Role**
|
|
|
|
```yaml
|
|
# roles/nginx/tasks/main.yml
|
|
---
|
|
- name: Ensure Nginx is installed
|
|
ansible.builtin.package:
|
|
name: nginx
|
|
state: present
|
|
tags: install
|
|
|
|
- name: Ensure Nginx configuration directory exists
|
|
ansible.builtin.file:
|
|
path: /etc/nginx/sites-available
|
|
state: directory
|
|
owner: root
|
|
group: root
|
|
mode: '0755'
|
|
tags: config
|
|
|
|
- name: Template Nginx main configuration
|
|
ansible.builtin.template:
|
|
src: nginx.conf.j2
|
|
dest: /etc/nginx/nginx.conf
|
|
owner: root
|
|
group: root
|
|
mode: '0644'
|
|
validate: nginx -t -c %s
|
|
backup: yes
|
|
notify: Reload nginx
|
|
tags: config
|
|
|
|
- name: Ensure Nginx is started and enabled
|
|
ansible.builtin.service:
|
|
name: nginx
|
|
state: started
|
|
enabled: yes
|
|
tags: service
|
|
```
|
|
|
|
**Handlers**:
|
|
```yaml
|
|
# roles/nginx/handlers/main.yml
|
|
---
|
|
- name: Reload nginx
|
|
ansible.builtin.service:
|
|
name: nginx
|
|
state: reloaded
|
|
|
|
- name: Restart nginx
|
|
ansible.builtin.service:
|
|
name: nginx
|
|
state: restarted
|
|
```
|
|
|
|
**Defaults**:
|
|
```yaml
|
|
# roles/nginx/defaults/main.yml
|
|
---
|
|
nginx_worker_processes: auto
|
|
nginx_worker_connections: 1024
|
|
nginx_user: www-data
|
|
nginx_keepalive_timeout: 65
|
|
nginx_server_names_hash_bucket_size: 64
|
|
```
|
|
|
|
### Creating a Playbook
|
|
|
|
**Example: Site Deployment Playbook**
|
|
|
|
```yaml
|
|
---
|
|
- name: Deploy web application
|
|
hosts: webservers
|
|
become: yes
|
|
gather_facts: yes
|
|
|
|
vars:
|
|
app_version: "1.0.0"
|
|
deployment_user: deploy
|
|
|
|
pre_tasks:
|
|
- name: Update package cache
|
|
ansible.builtin.apt:
|
|
update_cache: yes
|
|
cache_valid_time: 3600
|
|
when: ansible_os_family == "Debian"
|
|
tags: always
|
|
|
|
- name: Verify deployment user exists
|
|
ansible.builtin.user:
|
|
name: "{{ deployment_user }}"
|
|
state: present
|
|
tags: always
|
|
|
|
roles:
|
|
- role: common
|
|
tags: common
|
|
- role: nginx
|
|
tags: nginx
|
|
- role: application
|
|
tags: app
|
|
|
|
tasks:
|
|
- name: Deploy application version {{ app_version }}
|
|
ansible.builtin.copy:
|
|
src: "app-{{ app_version }}.tar.gz"
|
|
dest: "/opt/app/"
|
|
owner: "{{ deployment_user }}"
|
|
group: "{{ deployment_user }}"
|
|
mode: '0644'
|
|
tags: deploy
|
|
|
|
- name: Extract application
|
|
ansible.builtin.unarchive:
|
|
src: "/opt/app/app-{{ app_version }}.tar.gz"
|
|
dest: "/opt/app/"
|
|
remote_src: yes
|
|
owner: "{{ deployment_user }}"
|
|
group: "{{ deployment_user }}"
|
|
tags: deploy
|
|
|
|
post_tasks:
|
|
- name: Verify application is accessible
|
|
ansible.builtin.uri:
|
|
url: "http://{{ ansible_default_ipv4.address }}/"
|
|
status_code: 200
|
|
tags: verify
|
|
|
|
- name: Log deployment
|
|
ansible.builtin.lineinfile:
|
|
path: /var/log/deployments.log
|
|
line: "{{ ansible_date_time.iso8601 }} - Deployed {{ app_version }}"
|
|
create: yes
|
|
tags: always
|
|
```
|
|
|
|
## Output Format
|
|
|
|
### Development Summary
|
|
|
|
**Created**: [role-name / playbook-name]
|
|
**Purpose**: [description]
|
|
**Files Generated**:
|
|
```
|
|
✓ tasks/main.yml - Main task list
|
|
✓ handlers/main.yml - Service handlers
|
|
✓ defaults/main.yml - Default variables
|
|
✓ templates/ - Configuration templates
|
|
✓ README.md - Role documentation
|
|
```
|
|
|
|
### Usage Instructions
|
|
|
|
**Install role**:
|
|
```bash
|
|
# If using Galaxy
|
|
ansible-galaxy install [role-name]
|
|
|
|
# Local role (no action needed)
|
|
```
|
|
|
|
**Run playbook**:
|
|
```bash
|
|
# Syntax check
|
|
ansible-playbook playbook.yml --syntax-check
|
|
|
|
# Dry run
|
|
ansible-playbook playbook.yml --check
|
|
|
|
# Execute
|
|
ansible-playbook playbook.yml -i inventory/production
|
|
|
|
# Specific tags
|
|
ansible-playbook playbook.yml --tags "install,config"
|
|
|
|
# Limit to hosts
|
|
ansible-playbook playbook.yml --limit "web01,web02"
|
|
```
|
|
|
|
### Testing Commands
|
|
|
|
```bash
|
|
# Lint check
|
|
ansible-lint roles/[role-name]/
|
|
|
|
# Test with Molecule
|
|
cd roles/[role-name]
|
|
molecule test
|
|
|
|
# Manual test
|
|
ansible-playbook tests/test.yml -i tests/inventory
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
**Idempotency**:
|
|
- Use proper Ansible modules (not shell/command when module exists)
|
|
- Always set `changed_when` for command/shell tasks
|
|
- Use state management (present/absent, started/stopped)
|
|
|
|
**Task Naming**:
|
|
- Start with verb (Ensure, Configure, Install, Copy, etc.)
|
|
- Be specific about what task does
|
|
- Use sentence case consistently
|
|
|
|
**Variables**:
|
|
- Namespace with role name: `nginx_port`, `app_user`
|
|
- Provide sensible defaults in `defaults/main.yml`
|
|
- Document all variables in README
|
|
|
|
**Error Handling**:
|
|
- Use `failed_when` to define failure conditions
|
|
- Use `block/rescue` for rollback capability
|
|
- Validate before destructive operations
|
|
|
|
**Templates**:
|
|
- Add `{{ ansible_managed }}` header
|
|
- Use validate parameter when possible
|
|
- Always backup with `backup: yes`
|
|
|
|
**Handlers**:
|
|
- One handler per service action
|
|
- Use notify instead of direct service restarts
|
|
- Name handlers clearly (Restart nginx, Reload postgresql)
|
|
|
|
**Tags**:
|
|
- Add meaningful tags to tasks
|
|
- Use common tags (install, config, service)
|
|
- Allow selective execution
|
|
|
|
**Testing**:
|
|
- Always support check mode
|
|
- Test on multiple OS if targeting multiple platforms
|
|
- Use Molecule for automated testing
|
|
- Include example playbook in role
|