Ansible Cheatsheet
Ansible Cheatsheet
###############################################################################
## Run the playbook(s):
$ ansible -i localhost, <playbook>.yaml
!When using the '-i' parameter, if the value is a 'list' (it contains at least
one comma) it will be used as the inventory LIST
!It can be either FQDN or IP address
$ ansible -i /etc/ansible/hosts <playbook>.yaml
!While the variable is a string, it will be used as the inventory PATH
## Ansible verbosity:
$ ansible-playbook -v -i <HOST> <playbook>.yaml <-displays output data
$ ansible-playbook -vv -i <HOST> <playbook>.yaml <-displays output & input data
$ ansible-playbook -vvv -i <HOST> <playbook>.yaml <-information about
connections
$ ansible-playbook -vvvv -i <HOST> <playbook>.yaml <-information about plugins
###############################################################################
## Inventory file examples:
[webserver] <-both hosts can be reduced to ws[01:02].lmaly.io using
regexp
ws01.lmaly.io
ws02.lmaly.io:1234 <-configured to listen on port 1234
[database]
db01.lmaly.io
192.168.[1:5].[0:255] <-includes 192.168.1.0/24 through 192.168.5.0/24
[nsw_cities:children] <-nested groups use the keyword :children
webserver
database
others
[others]
localhost ansible_connection=local <-it will use local
connection, without SSH
192.168.3.7 ansible_connection=ssh ansible_user=ftaylor <-use different
settings example
!Multiple inventory files in one dir = All the files in the directory are merged
and treated as one inventory
###############################################################################
## Which hosts will the playbook run against?
$ ansible-playbook <playbook>.yaml --list-hosts
## Print all the tasks in short form that playbook would perform:
$ ansible-playbook <playbook>.yaml --list-tasks
###############################################################################
## See the metadata obtained during Ansible setup (module setup):
$ ansible all -i <HOST>, -m setup
$ ansible <group> -m setup
$ ansible <group> -m setup --tree facts
# Show the specific metadata:
$ ansible <group> -m setup -a 'filter=*ipv4*'
# Examples:
{{ ansible_hostname }}
{{ ansible_default_ipv4.address }}
{{ ansible_devices.vda.partitions.vda1.size }}
{{ ansible_dns.nameservers }}
{{ ansible_kernel }}
# To disable facts:
gather_facts: no
# Custom facts are saved under ansible_local:
$ cat /etc/ansible/facts.d/new.fact <-ini or json file
$ ansible demo1.example.com -m setup -a 'filter=ansible_local'
# Accessing facts of another node:
{{ hostvars['demo2.example.com']['ansible_os_family'] }}
###############################################################################
# Run arbitrary command on all hosts as sudo:
$ ansible all -s -a "cat /var/log/messages"
# Run ad hoc command that generates one line input for each operation:
$ ansible myhosts -m command -a /usr/bin/hostname -o
###############################################################################
## Playbook(s) basics:
--- <-indicates YAML, optional document
marker
- hosts: all <-host or host group against we will run
the task (example - hosts: webserver)
remote_user: lmaly <-as what user will Ansible log in to the
machine(s)
tasks: <-list of actions
- name: Whatever you want to name it <-name of the first task
yum:
name: httpd
state: present <-same as single line 'yum: name=httpd
state=present become=True'
become: True <-task will be executed with sudo
... <-optional document marker indicating end
of YAML
Notes:
!Space characters used for indentation
!Pipe (|) preservers line returns within string
!Arrow (>) converts line returns to spaces, removes leading space in lines
!Indentation rules:
Elements at same level in hierarchy must have same indentation
Child elements must be indented further than parents
No rules about exact number of spaces to use
!Optional: Insert blank lines for readability
!Use YAML Lint http://yamllint.com to check the syntax correctness
!Use 'ansible-playbook --syntax-check <MYAML.YML>'
!Use 'ansible-playbook -C <MYAML.YML>' for dry run (what changes would occur if
playbook is executed?)
!Use 'always_run: true' to execute only some tasks in check mode (or 'always_run:
false' for the opposite)
!Use 'ansible-playbook --step <MYAML.YML>' to prompt each task (y=yes/n=no/c=exit
and execute remaining without asking)
!Use 'ansible-playbook <MYAML.YML> --start-at-task="start httpd service" to start
execution from given task
!For complex playbooks, use 'include' to include separate files in main playbook
(include: tasks/env.yml)
###############################################################################
## Variables:
--- # Usually comment field describing what it does
- hosts: all
remote_user: lmaly
tasks:
- name: Set variable 'name'
set_fact:
name: Test machine
- name: Print variable 'name'
debug:
msg: '{{ name }}'
a/ In vars block:
vars:
set_fact: 'Test machine'
b/ Passed as arguments:
include_vars: vars/extra_args.yml
b/
[webserver:vars] <- ! Host variables will override group variables in case
tge same variable is used in both
https_enabled=True
b/ group_vars:
$ cat group_vars/webserver
https_enabled=True
!Variable must start with letter; valid characters are: letters, numbers,
underscores
# Array definition example:
users:
bjones:
first_name: Bob
last_name: Jones
acook:
first_name: Anne
last_name: Cook
# Array accessing/reading example:
users.bjones.first_name # Returns 'Bob'
users['bjones']['first_name'] # Returns 'Bob' <-preferable method
!Variables passed to the CLI have priority over any other variable.
!You can override the following parameters from an inventory file:
ansible_user, ansible_port, ansible_host, ansible_connection,
ansible_private_key_file, ansible_shell_type
###############################################################################
## Iterates (http://docs.ansible.com/ansible/playbooks_loops.html)
(1) Standard - 'with_items' example:
a/ Simple loop
firewall
firewalld:
service: '{{ item }}'
state: enabled
permanent: True
immediate: True
become: True
with_items:
- http
- https
b/ List of hashes
- user:
name: {{ item.name }}
state: present
groups: {{ item.groups }}
with_items:
- { name: 'jane', groups: 'wheel' }
- { name: 'joe', groups: 'root' }
(2) Nested loops (iterate all elements of a list with all items from other
lists) - 'with_nested' example:
user:
name: '{{ item }}'
become: True
with_items:
- '{{ users }}'
file:
path: '/home/{{ item.0 }}/{{ item.1 }}'
state: directory
become: True
with_nested:
- '{{ users }}'
- '{{ folders }}'
(4) Integer loop (iterate over the integer numbers) - 'with_sequence' example:
file:
dest: '/tmp/dir{{ item }}'
state: directory
with_sequence: start=1 end=10
become: True
Notes:
with_file - Takes list of file names; 'item' set to content of each file in
sequence
with_fileglob - Takes file name globbing pattern; 'item' set to each file in
directory that matches pattern; in sequence, nonrecursively
with_sequence - Generates sequence of items in increasing numerical order; Can
take 'start' and 'end' arguments
- Supports decimal, octal, hexadecimal integer values
with_random_choices - Takes list; 'item' set to one list item at random
Note - Conditionals:
Equal "{{ max_memory }} == 512"
Less than "{{ min_memory }} < 128"
Greater than "{{ min_memory }} > 256"
Less than or equal "{{ min_memory }} <= 256"
Greater than or equal "{{ min_memory }} >= 512"
Not equal "{{ min_memory }} != 512"
Variable exists "{{ min_memory }} is defined"
Variable does not exist "{{ min_memory }} is not defined"
Variable set to 1, True, or yes "{{ available_memory }}"
Variable set to 0, False, or no "not {{ available_memory }}"
Value present in variable or array "{{ users }} in users["db_admins"]"
AND ansible_kernel == 3.10.el7.x86_64 and
inventory_hostname in groups['staging']
OR ansible_distribution == "RedHat" or
ansible_distribution == "Fedora"
(6) When combining 'when' with 'with_items', the when statement is processed
for each item:
with_items: "{ ansible_mounts }"
when: item.mount == "/" and item.size_available > 300000000
###############################################################################
## Register - To capture output of module that uses array
- shell: echo "{{ item }}"
with_items:
- one
- two
register: echo
###############################################################################
## Handlers - Task that responds to notification triggered by other tasks:
notify:
- restart_apache
handlers:
-name: restart_apache
service:
name: httpd:
state: restarted
!Task may call more than one handler in notify
!Ansible treats notify as an array and iterates over handler names
!Handlers run in order they are written in play, not in order listed by notify
task
!If two handlers have same name, only one runs
!Handler runs only once, even if notified by more than one task
!Handlers defined inside 'include' cannot be notified
!--force-handlers
###############################################################################
## Resource tagging
a/ Tasks
tags:
- packages
b/ Roles - all tasks they define also tagged
roles:
- { role: user, tags: [production] }
c/ Include - all tasks they define also tagged
- include: common.yml
tags: [testing]
$ ansible-playbook --tags "production"
$ ansible-playbook --skip-tags "development"
Special tags: always, tagged, untagged, all (default)
###############################################################################
## Ignore and task errors
Default: If task fails, play is aborted immediatelly, same with handlers
To skip failed tasks, use 'ignore_errors: yes'
To force handler to be called even if task fails, use 'force_handlers: yes'
To mark task as failed even when it succeeds, use 'failed_when:
cmd: /usr/local/bin/create_user.show
register: command_result
failed_when: "'Password missing' in command_result.stdout"
Default: Task acquires 'changed' state after updating managed host, which
causes handlers skipped if task does not make changed
changed_when: "'Success' in command_result.stdout"
###############################################################################
## Environmental variables
a/ Set env:
environment:
http_proxy: http://demo.lab.example.com:8080
###############################################################################
## Blocks - logical grouping of tasks, controls how are they executed
a/ block: <-main tasks to run
b/ rescue: <-tasks to run if block tasks fail
c/ always: <-tasks to always run, independent on a/ or b/
tasks:
- block:
- shell:
cmd: /usr/local/lib/upgrade-database
rescue:
- shell:
cmd: /usr/local/lib/create-user
always:
- service:
name: mariadb
state: restarted
###############################################################################
## Delegation using 'delegate_to' and 'local_action'
c/ Host outside play in inventory - example of removing managed hosts from ELB,
upgrading and the adding them back:
- hosts: webservers
tasks:
- name: Remove server from load balancer
command: remove-from-lb {{ inventory_hostname }}
delegate_to: localhost
- name: Deploy the latest version of Webstack
git:repo=git://git.example.com/path/repo.git dest=/srv/www
- name: Add server back to ELB pool
command: add-to-lb {{ inventory_hostname }}
delegate_to: localhost
Inventory data used when creating connection to target:
ansible_connection
ansible_host
ansible_port
ansible_user
e/ 'run_once: True'
!Facts gathered by delegated tasks assigned to 'delegate_to' host, not host that
produced facts
!To gather facts from delegated host, set 'delegate_facts: True' in the play
###############################################################################
## Jinja2 Template(s) - no need for file extension:
---
- hosts: all
remote_user: lmaly
tasks:
- name: Ensure the website is present and updated
template:
src: index.html.j2 <-the J2 template source
dest: /var/www/html/index.html <-destination
owner: root
group: root
mode: 0644
become: True
# Variables in J2 template(s):
'{{ VARIABLE_NAME }}'
'{{ ARRAY_NAME['KEY'] }}'
'{{ OBJECT_NAME.PROPERTY_NAME }}'
# Comments:
{# ... #}
# Conditionals:
{ % ... % }
a/ Equal to example A
{% if ansible_eth0.active == True %}
<p>eth0 address {{ ansible_eth0.ipv4.address }}.</p>
{% endif %}
b/ Equal to example B
{% if ansible_eth0.active is equalto True %}
<p>eth0 address {{ ansible_eth0.ipv4.address }}.</p>
{% endif %}
# Cycles/loops:
{% for address in ansible_all_ipv4_addresses %}
<li>{{ address }}</li>
{% endfor %}
# Issues
a/ When value after : starts with { you need to " the whole object
app_path: "{{ base_path }}/bin"
b/ When you have nested {{...}} elements, remove the inner set:
msg: Host {{ params[{{ host_ip }}] }} <-wrong
msg: Host {{ params[ host_ip] }} <-fine
More information:
http://jinja.pocoo.org/docs/dev/templates/#builtin-filters
http://jinja.pocoo.org/docs/dev/templates/#builtin-tests
###############################################################################
## Roles
# Structure:
It looks for different roles at 'roles' subdirectory or 'roles_path' dir in
ansible.cfg (default /etc/ansible/roles)
Top-level = specifically named role name
Subdirs = main.yml
files = contains objects referenced by main.yml
templates = contains objects referenced by main.yml
!Role tasks execute before tasks of play in which they appear
!To override default, use 'pre_tasks' (performed before any roles applied) and
'post_tasks' (performed after all roles completed)
# Role sources
$ cat roles2install.yml
# From Galaxy:
- src: author.rolename
###############################################################################
## Optimizations
(1) Default 'smart' settings (transport=smart in ansible.cfg):
a/ check if locally installed SSH supports 'ControlPersist', if not, 'paramiko'
is used
b/ ControlPersist=60s (listed as comment in /etc/ansible/ansible.cfg)
(2) Other settings include:
a/ paramiko (Python implementation of SSHv2, does not have ControlPersist)
b/ local (runs locally and not over SSH)
c/ ssh (uses OpenSSH)
d/ docker (uses docker exec)
e/ plug-ins (not based on SSH, e.g. chroot, libvirt_lxc...)
(3) Change on-the-fly settings with
a/ $ ansible-playbook <PLAYBOOK> -c <TRANSPORT_NAME>
b/ $ ansible <PLAYBOOK> -c <TRANSPORT_NAME>
(4) SSH settings are under [ssh_connection]
(5) Paramiko settings are under [paramiko_connection]
(6) To specify connection type in the inventory file, use 'ansible_connection':
[targets]
localgost ansible_connection=local
demo.lab.example.com ansible_connection=ssh
(7) To specify connection type in play:
---
- name: Connection type
hosts: 127.0.0.01
connection: local
(8) To limit concurrent connection, use SSH server's 'MaxStartups' option
(9) Parallelism - by default 5 different machines at once:
a/ setting 'forks' in 'ansible.cfg'
b/ $ ansible-playbook --forks
c/ 'serial' in the play overrides 'ansible.cfg' - either number or %
d/ 'async' & 'async_status' - value is time that Ansible waits for command to
complete [default 3600s, long tasks 0]
e/ 'pool' - sets how often Ansible checks if command has completed [default
10s, long tasks 0]
f/ 'wait_for'
g/ pause module
###############################################################################
## Ansible vault
(1a) Create encrypted file:
$ ansible-vault create <FILENAME>
$ ansible-vault create --vault-password-file=.secret_file <FILENAME>
(2a) Enter and confirm new vault password
###############################################################################
## Troubleshooting
By default no log, but you can enable it:
a/ 'log_path' parameter under [default] in 'ansible.cfg'
b/ ANSIBLE_LOG_PATH environment variable
###############################################################################
## Ansible Tower
Web-based interface
Enterprise solution for IT automation
Dashboard for managing deployments and monitoring resources
Adds automation, visual management, monitoring capabilities to Ansible
Gives administrators control over user access
Uses SSH credentials
Blocks access to or transfer of credentials
Implements continuous delivery and configuration management
Integrates management in single tool
# SSL certificate:
/etc/tower/awx.cert
/etc/tower/awx.key
# User types:
normal
organization admin
superuser
# User permissions:
read
write
admin
execute commands
check
run
create
# Projects:
/var/lib/awx/projects
$ sudo mkdir /var/lib/awx/projects/demoproject
$ sudo cp demo.yml /var/lib/awx/projects/demoproject
$ sudo chown -R awx /var/lib/awx/projects/demoproject
###############################################################################
## CLI:
(1) Run a command somewhere else using Ansible
$ ansible
Usage: ansible <host-pattern> [options]
Options:
-a MODULE_ARGS, --args=MODULE_ARGS
module arguments
--ask-vault-pass ask for vault password
-B SECONDS, --background=SECONDS
run asynchronously, failing after X seconds
(default=N/A)
-C, --check don't make any changes; instead, try to predict some
of the changes that may occur
-D, --diff when changing (small) files and templates, show the
differences in those files; works great with --check
-e EXTRA_VARS, --extra-vars=EXTRA_VARS
set additional variables as key=value or YAML/JSON
-f FORKS, --forks=FORKS
specify number of parallel processes to use
(default=5)
-h, --help show this help message and exit
-i INVENTORY, --inventory-file=INVENTORY
specify inventory host path
(default=/etc/ansible/hosts) or comma separated host
list.
-l SUBSET, --limit=SUBSET
further limit selected hosts to an additional pattern
--list-hosts outputs a list of matching hosts; does not execute
anything else
-m MODULE_NAME, --module-name=MODULE_NAME
module name to execute (default=command)
-M MODULE_PATH, --module-path=MODULE_PATH
specify path(s) to module library (default=None)
--new-vault-password-file=NEW_VAULT_PASSWORD_FILE
new vault password file for rekey
-o, --one-line condense output
--output=OUTPUT_FILE output file name for encrypt or decrypt; use - for
stdout
-P POLL_INTERVAL, --poll=POLL_INTERVAL
set the poll interval if using -B (default=15)
--syntax-check perform a syntax check on the playbook, but do not
execute it
-t TREE, --tree=TREE log output to this directory
--vault-password-file=VAULT_PASSWORD_FILE
vault password file
-v, --verbose verbose mode (-vvv for more, -vvvv to enable
connection debugging)
--version show program's version number and exit
Connection Options:
control as whom and how to connect to hosts
###############################################################################
(2) Run Ansible playbook
$ ansible-playbook
Usage: ansible-playbook playbook.yml
Options:
--ask-vault-pass ask for vault password
-C, --check don't make any changes; instead, try to predict some
of the changes that may occur
-D, --diff when changing (small) files and templates, show the
differences in those files; works great with --check
-e EXTRA_VARS, --extra-vars=EXTRA_VARS
set additional variables as key=value or YAML/JSON
--flush-cache clear the fact cache
--force-handlers run handlers even if a task fails
-f FORKS, --forks=FORKS
specify number of parallel processes to use
(default=5)
-h, --help show this help message and exit
-i INVENTORY, --inventory-file=INVENTORY
specify inventory host path
(default=/etc/ansible/hosts) or comma separated host
list.
-l SUBSET, --limit=SUBSET
further limit selected hosts to an additional pattern
--list-hosts outputs a list of matching hosts; does not execute
anything else
--list-tags list all available tags
--list-tasks list all tasks that would be executed
-M MODULE_PATH, --module-path=MODULE_PATH
specify path(s) to module library (default=None)
--new-vault-password-file=NEW_VAULT_PASSWORD_FILE
new vault password file for rekey
--output=OUTPUT_FILE output file name for encrypt or decrypt; use - for
stdout
--skip-tags=SKIP_TAGS
only run plays and tasks whose tags do not match these
values
--start-at-task=START_AT_TASK
start the playbook at the task matching this name
--step one-step-at-a-time: confirm each task before running
--syntax-check perform a syntax check on the playbook, but do not
execute it
-t TAGS, --tags=TAGS only run plays and tasks tagged with these values
--vault-password-file=VAULT_PASSWORD_FILE
vault password file
-v, --verbose verbose mode (-vvv for more, -vvvv to enable
connection debugging)
--version show program's version number and exit
Connection Options:
control as whom and how to connect to hosts
###############################################################################
(3) Set up a remote copy of ansible on each managed node (clone Ansible
configuration files from Git repository)
$ ansible-pull
Usage: ansible-pull -U <repository> [options]
Options:
--accept-host-key adds the hostkey for the repo url if not already added
--ask-vault-pass ask for vault password
-C CHECKOUT, --checkout=CHECKOUT
branch/tag/commit to checkout. Defaults to behavior
of repository module.
-d DEST, --directory=DEST
directory to checkout repository to
-e EXTRA_VARS, --extra-vars=EXTRA_VARS
set additional variables as key=value or YAML/JSON
-f, --force run the playbook even if the repository could not be
updated
--full Do a full clone, instead of a shallow one.
-h, --help show this help message and exit
-i INVENTORY, --inventory-file=INVENTORY
specify inventory host path
(default=/etc/ansible/hosts) or comma separated host
list.
-l SUBSET, --limit=SUBSET
further limit selected hosts to an additional pattern
--list-hosts outputs a list of matching hosts; does not execute
anything else
-m MODULE_NAME, --module-name=MODULE_NAME
Repository module name, which ansible will use to
check out the repo. Default is git.
-M MODULE_PATH, --module-path=MODULE_PATH
specify path(s) to module library (default=None)
--new-vault-password-file=NEW_VAULT_PASSWORD_FILE
new vault password file for rekey
-o, --only-if-changed
only run the playbook if the repository has been
updated
--output=OUTPUT_FILE output file name for encrypt or decrypt; use - for
stdout
--purge purge checkout after playbook run
--skip-tags=SKIP_TAGS
only run plays and tasks whose tags do not match these
values
-s SLEEP, --sleep=SLEEP
sleep for random interval (between 0 and n number of
seconds) before starting. This is a useful way to
disperse git requests
-t TAGS, --tags=TAGS only run plays and tasks tagged with these values
-U URL, --url=URL URL of the playbook repository
--vault-password-file=VAULT_PASSWORD_FILE
vault password file
-v, --verbose verbose mode (-vvv for more, -vvvv to enable
connection debugging)
--verify-commit verify GPG signature of checked out commit, if it
fails abort running the playbook. This needs the
corresponding VCS module to support such an operation
--version show program's version number and exit
Connection Options:
control as whom and how to connect to hosts
###############################################################################
(4) Accessing documentation locally
$ ansible-doc
Usage: ansible-doc [options] [module...]
Options:
-h, --help show this help message and exit
-l, --list List available modules
-M MODULE_PATH, --module-path=MODULE_PATH
specify path(s) to module library (default=None)
-s, --snippet Show playbook snippet for specified module(s)
-v, --verbose verbose mode (-vvv for more, -vvvv to enable
connection debugging)
--version show program's version number and exit
###############################################################################
(5) Ansible Galaxy tool
$ ansible-galaxy
Options:
-h, --help show this help message and exit
-v, --verbose verbose mode (-vvv for more, -vvvv to enable connection
debugging)
--version show program's version number and exit
Examples:
ansible-galaxy search --author <AUTHOR>
ansible-galaxy search --platforms <PLATFORM>
ansible-galaxy search --galaxy-tags <TAG>
ansible-galaxy info <ROLE>
ansible-galaxy install <ROLE> -p <ROLE_DIRECTORY>
ansible-galaxy install -r <ROLE1> <ROLE2> <ROLE3> ...
ansible-galaxy list
ansible-galaxy remove <ROLE>
ansible-galaxy init <ROLE>
ansible-galaxy init --offline <ROLE>
###############################################################################
(6) Hiding secrets
$ ansible-vault
Options:
--ask-vault-pass ask for vault password
-h, --help show this help message and exit
--new-vault-password-file=NEW_VAULT_PASSWORD_FILE
new vault password file for rekey
--output=OUTPUT_FILE output file name for encrypt or decrypt; use - for
stdout
--vault-password-file=VAULT_PASSWORD_FILE
vault password file
-v, --verbose verbose mode (-vvv for more, -vvvv to enable
connection debugging)
--version show program's version number and exit
###############################################################################
(7) Windows
$ pip install pywinrm <-- on the control machine
Authentication:
a/ Certificate: authentication similar to SSH
b/ Kerberos: python-kerberos
c/ CredSSP: for local and domain accounts
On the client(s):
a/ PowerShell 3.0 or higher
b/ Enable PowerShell
c/ Set up WinRM:
https://github.com/ansible/ansible/blob/devel/examples/scripts/ConfigureRemotingFor
Ansible.ps1
'ansible.cfg' example:
ansible_connection=winrm
ansible_user=Administrator