Tasks & Modules
Task Structure
Basic Task Syntax
- name: Task description
module_name:
parameter1: value1
parameter2: value2
become: yes
when: condition
notify: handler_name
tags: tag_name
register: result_variable
Task with All Options
- name: Complete task example
package:
name: nginx
state: present
become: yes
become_user: root
become_method: sudo
delegate_to: localhost
delegate_facts: yes
run_once: true
environment:
PATH: /usr/local/bin:{{ ansible_env.PATH }}
async: 3600
poll: 0
retries: 3
delay: 10
timeout: 300
until: result.stdout.find("success") != -1
when: ansible_os_family == "Debian"
changed_when: false
failed_when: result.rc != 0
ignore_errors: yes
ignore_unreachable: yes
no_log: true
notify: restart nginx
tags: [installation, packages]
register: install_result
Core Modules
System Modules
package
- name: Install package (cross-platform)
package:
name: nginx
state: present
- name: Install multiple packages
package:
name:
- nginx
- mysql-server
- php
state: present
- name: Remove package
package:
name: apache2
state: absent
apt (Debian/Ubuntu)
- name: Update package cache
apt:
update_cache: yes
cache_valid_time: 3600
- name: Install package from specific repository
apt:
name: nginx
state: present
default_release: xenial-backports
- name: Install .deb package
apt:
deb: /path/to/package.deb
state: present
- name: Upgrade all packages
apt:
upgrade: dist
update_cache: yes
yum/dnf (RHEL/CentOS/Fedora)
- name: Install package with yum
yum:
name: nginx
state: present
- name: Install package with dnf
dnf:
name: nginx
state: present
- name: Install from URL
yum:
name: https://example.com/package.rpm
state: present
- name: Update all packages
yum:
name: '*'
state: latest
service
- name: Start and enable service
service:
name: nginx
state: started
enabled: yes
- name: Stop service
service:
name: nginx
state: stopped
- name: Restart service
service:
name: nginx
state: restarted
- name: Reload service
service:
name: nginx
state: reloaded
systemd
- name: Start systemd service
systemd:
name: nginx
state: started
enabled: yes
daemon_reload: yes
- name: Mask service
systemd:
name: nginx
masked: yes
- name: Check service status
systemd:
name: nginx
register: service_status
File System Modules
file
- name: Create directory
file:
path: /opt/app
state: directory
owner: app
group: app
mode: '0755'
- name: Create file
file:
path: /tmp/test.txt
state: touch
owner: root
group: root
mode: '0644'
- name: Create symlink
file:
src: /opt/app/current
dest: /opt/app/app-1.0
state: link
- name: Remove file
file:
path: /tmp/test.txt
state: absent
copy
- name: Copy file
copy:
src: /local/path/file.txt
dest: /remote/path/file.txt
owner: root
group: root
mode: '0644'
backup: yes
- name: Copy with content
copy:
content: |
This is the content
of the file
dest: /tmp/content.txt
owner: root
group: root
mode: '0644'
template
- name: Generate config file
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
backup: yes
notify: restart nginx
fetch
- name: Fetch file from remote
fetch:
src: /remote/path/file.txt
dest: /local/path/
flat: yes
fail_on_missing: no
synchronize
- name: Synchronize directories
synchronize:
src: /local/path/
dest: /remote/path/
delete: yes
recursive: yes
rsync_opts:
- '--exclude=*.log'
- '--exclude=.git'
User Management Modules
user
- name: Create user
user:
name: appuser
uid: 1001
group: app
groups: wheel,docker
home: /home/appuser
shell: /bin/bash
password: "{{ user_password | password_hash('sha512') }}"
create_home: yes
append: yes
- name: Remove user
user:
name: olduser
state: absent
remove: yes
group
- name: Create group
group:
name: app
gid: 1001
state: present
- name: Remove group
group:
name: oldgroup
state: absent
authorized_key
- name: Add SSH key
authorized_key:
user: appuser
key: "{{ lookup('file', '/home/ansible/.ssh/id_rsa.pub') }}"
state: present
- name: Add multiple SSH keys
authorized_key:
user: appuser
key: '{{ item }}'
state: present
loop:
- 'ssh-rsa AAAAB3NzaC1yc2E... user1@example.com'
- 'ssh-rsa AAAAB3NzaC1yc2E... user2@example.com'
Network Modules
uri
- name: Test web service
uri:
url: http://example.com/api/health
method: GET
status_code: 200
register: health_check
- name: POST data to API
uri:
url: http://example.com/api/data
method: POST
body_format: json
body:
key: value
data: '{{ variable }}'
headers:
Content-Type: application/json
Authorization: 'Bearer {{ api_token }}'
get_url
- name: Download file
get_url:
url: https://example.com/file.tar.gz
dest: /tmp/file.tar.gz
mode: '0644'
timeout: 30
validate_certs: yes
firewalld
- name: Configure firewall
firewalld:
service: http
permanent: yes
state: enabled
immediate: yes
- name: Open port
firewalld:
port: 8080/tcp
permanent: yes
state: enabled
immediate: yes
Database Modules
mysql_user
- name: Create MySQL user
mysql_user:
name: appuser
password: '{{ mysql_password }}'
priv: 'appdb.*:ALL'
host: '%'
state: present
login_user: root
login_password: '{{ mysql_root_password }}'
mysql_db
- name: Create MySQL database
mysql_db:
name: appdb
state: present
encoding: utf8
collation: utf8_general_ci
login_user: root
login_password: '{{ mysql_root_password }}'
postgresql_user
- name: Create PostgreSQL user
postgresql_user:
name: appuser
password: '{{ postgres_password }}'
role_attr_flags: CREATEDB,NOSUPERUSER
state: present
become_user: postgres
postgresql_db
- name: Create PostgreSQL database
postgresql_db:
name: appdb
owner: appuser
state: present
encoding: UTF-8
template: template0
become_user: postgres
Cloud Modules
ec2
- name: Launch EC2 instance
ec2:
key_name: mykey
instance_type: t2.micro
image: ami-12345678
wait: yes
group: webserver
count: 1
vpc_subnet_id: subnet-12345678
assign_public_ip: yes
region: us-east-1
instance_tags:
Name: webserver
Environment: production
register: ec2_instance
azure_rm_virtualmachine
- name: Create Azure VM
azure_rm_virtualmachine:
resource_group: myResourceGroup
name: myVM
vm_size: Standard_B2s
admin_username: azureuser
ssh_password_enabled: false
ssh_public_keys:
- path: /home/azureuser/.ssh/authorized_keys
key_data: '{{ ssh_public_key }}'
image:
offer: UbuntuServer
publisher: Canonical
sku: 18.04-LTS
version: latest
Command and Shell Modules
command
- name: Run command
command: ls -la /tmp
register: ls_result
- name: Run command with arguments
command:
cmd: /usr/bin/command
chdir: /tmp
creates: /tmp/output.txt
register: command_result
shell
- name: Run shell command
shell: |
echo "Starting backup"
tar -czf /backup/$(date +%Y%m%d).tar.gz /data/
echo "Backup completed"
args:
executable: /bin/bash
chdir: /tmp
register: backup_result
script
- name: Run local script on remote host
script: /local/path/script.sh
args:
creates: /tmp/script.done
register: script_result
raw
- name: Run raw command (no Python required)
raw: cat /etc/os-release
register: os_info
Error Handling in Tasks
Conditional Execution
- name: Task with conditions
package:
name: nginx
state: present
when:
- ansible_os_family == "Debian"
- ansible_distribution_version is version('18.04', '>=')
Custom Error Conditions
- name: Command with custom failure
shell: /path/to/command
register: result
failed_when:
- result.rc != 0
- "'ERROR' in result.stdout"
changed_when: "'CHANGED' in result.stdout"
Retry Logic
- name: Task with retry
uri:
url: http://example.com/api
method: GET
register: api_result
retries: 5
delay: 10
until: api_result.status == 200
Advanced Task Features
Async Tasks
- name: Long running task
shell: /path/to/long-running-script.sh
async: 3600
poll: 0
register: long_task
- name: Check async task status
async_status:
jid: '{{ long_task.ansible_job_id }}'
register: job_result
until: job_result.finished
retries: 30
delay: 60
Delegation
- name: Run task on different host
command: echo "Running on database server"
delegate_to: db1.example.com
delegate_facts: yes
- name: Run task locally
command: echo "Running on control machine"
delegate_to: localhost
Environment Variables
- name: Task with environment variables
shell: echo $CUSTOM_VAR
environment:
CUSTOM_VAR: custom_value
PATH: /usr/local/bin:{{ ansible_env.PATH }}
HOME: /home/appuser
Module Documentation
Getting Module Help
# List all modules
ansible-doc -l
# Get module documentation
ansible-doc copy
ansible-doc -s copy # Short format
# Search for modules
ansible-doc -l | grep mysql
# Module examples
ansible-doc copy | grep -A 20 "EXAMPLES:"
Module Testing
- name: Test module functionality
debug:
msg: 'Testing module'
check_mode: yes
- name: Verify module results
assert:
that:
- result.changed == true
- result.failed == false
fail_msg: 'Module did not work as expected'
Custom Modules
Simple Custom Module
#!/usr/bin/python
# library/hello.py
from ansible.module_utils.basic import AnsibleModule
def main():
module = AnsibleModule(
argument_spec=dict(
name=dict(type='str', required=True),
greeting=dict(type='str', default='Hello')
)
)
name = module.params['name']
greeting = module.params['greeting']
result = {
'changed': False,
'message': f'{greeting}, {name}!'
}
module.exit_json(**result)
if __name__ == '__main__':
main()
Using Custom Module
- name: Use custom module
hello:
name: World
greeting: Hi
register: hello_result
- name: Show custom module result
debug:
msg: '{{ hello_result.message }}'
Best Practices
Task Organization
- name: Well-organized tasks
block:
- name: Install packages
package:
name: '{{ item }}'
state: present
loop:
- nginx
- mysql-server
tags: installation
- name: Configure services
template:
src: '{{ item.src }}'
dest: '{{ item.dest }}'
loop:
- src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
- src: mysql.cnf.j2
dest: /etc/mysql/mysql.conf.d/custom.cnf
notify: restart services
tags: configuration
rescue:
- name: Handle installation errors
debug:
msg: 'Installation failed, rolling back'
always:
- name: Cleanup
file:
path: /tmp/install.lock
state: absent
Performance Optimization
- name: Optimized tasks
package:
name: '{{ packages }}' # Install multiple packages at once
state: present
vars:
packages:
- nginx
- mysql-server
- php
- name: Use appropriate modules
file:
path: /tmp/test
state: touch
# Better than: shell: touch /tmp/test
- name: Gather facts selectively
setup:
filter: ansible_distribution*
when: ansible_facts is undefined
Security Best Practices
- name: Secure task execution
user:
name: admin
password: "{{ admin_password | password_hash('sha512') }}"
no_log: true # Hide sensitive output
become: yes
become_user: root
- name: Secure file operations
file:
path: /etc/ssl/private/server.key
owner: root
group: root
mode: '0600'
- name: Use vault for sensitive data
template:
src: database.conf.j2
dest: /etc/app/database.conf
owner: app
group: app
mode: '0600'
vars:
db_password: '{{ vault_db_password }}'