Cheat Sheet - Ansible

Iteration

Loops

- name: add several users
  user:
    name: "{{ item }}"
    state: present
    groups: "wheel"
  loop:
     - testuser1
     - testuser2

If you have defined a YAML list in a variables file, or the ‘vars’ section, you can also do:

loop: "{{ somelist }}"

Packages

Some plugins like, the yum and apt modules can take lists directly to their options, this is more optimal than looping over the task. See each action’s documentation for details, for now here is an example:

- name: optimal yum
  yum:
    name: "{{ list_of_packages }}"
    state: present

- name: non optimal yum, not only slower but might cause issues with interdependencies
  yum:
    name: "{{item}}"
    state: present
  loop: "{{ list_of_packages }}"

Note that the types of items you iterate over do not have to be simple lists of strings. If you have a list of hashes, you can reference subkeys using things like:

- name: add several users
  user:
    name: "{{ item.name }}"
    state: present
    groups: "{{ item.groups }}"
  loop:
    - { name: 'testuser1', groups: 'wheel' }
    - { name: 'testuser2', groups: 'root' }

Also be aware that when combining Conditionals with a loop, the when: statement is processed separately for each item. See The When Statement for an example.

To loop over a dict, use the dict2items Dict Filter:

- name: create a tag dictionary of non-empty tags
  set_fact:
    tags_dict: "{{ (tags_dict | default({})) | combine({item.key: item.value}) }}"
  loop: "{{ tags | dict2items }}"
  vars:
    tags:
      Environment: dev
      Application: payment
      Another: "{{ doesnotexist | default() }}"
  when: item.value != ""

Pick host from group:

docker_host: "{{ groups['dockerhosts'][0] }}"

Pass variables to playbook

# short
ansible-playbook release.yml -e "version=1.23.45 other_variable=foo"

# long
ansible-playbook release.yml --extra-vars "version=1.23.45 other_variable=foo"

# as json
ansible-playbook release.yml --extra-vars '{"pacman":"mrs","ghosts":["inky","pinky","clyde","sue"]}'

# from file and from cli
ansible-playbook release.yml --extra-vars "@some_file.json" --extra-vars "other_variable=foo"

Join a list

- name: Concatenate the public keys
  set_fact:
    my_joined_list: "{{ my_list | join('\n') }}"

List ansible facts

ansible -m setup -i srv-dev-app1b, all

Only gather subset of facts

ansible all -m setup -a 'gather_subset=network,virtual' -i environments/aws-eu-dev/hosts --limit=srv-dev-app1b

List hosts in inventory

ansible-inventory --list --yaml --playbook-dir=environments/development

Reliably get remote user name

ansible_user is used when we want to specifiy default SSH user in ansible hosts file whereas remote_user is used in playbook context: https://github.com/ansible/ansible/blob/c600ab81ee/lib/ansible/playbook/play_context.py#L46-L55

# the magic variable mapping dictionary below is used to translate
# host/inventory variables to fields in the PlayContext
# object. The dictionary values are tuples, to account for aliases
# in variable names.

MAGIC_VARIABLE_MAPPING = dict(
    connection       = ('ansible_connection',),
    remote_addr      = ('ansible_ssh_host', 'ansible_host'),
    remote_user      = ('ansible_ssh_user', 'ansible_user'),
    port             = ('ansible_ssh_port', 'ansible_port'),

Here is an example of using ansible_user in ansible hosts file:

[targets]

localhost              ansible_connection=local
other1.example.com     ansible_connection=ssh        ansible_user=mpdehaan
other2.example.com     ansible_connection=ssh        ansible_user=mdehaan

Use {{ ansible_user_id }} to detect the user name on the remote machine that Ansible operates under even if you set become: true. For the become user, use {{ ansible_become_user }} instead (default=root)

Become when default sudo is unavailable

# DC privilege workaround:
# executing commands as admin via sudo is not possible, the only way to
# use admin privileges is to become the root user with "sudo su"
ansible_become_method: "su"
ansible_become_exe: "sudo su -"

List all Ansible hostvars

Playbook: hostvars.yml

---

- hosts: all
  tasks:
    - name: Print all variables for each remote device
      debug:
        var: hostvars[inventory_hostname]

Run it with:

# Run against all hosts in the inventory
ansible-playbook -i "environments/aws-eu-dev/hosts" hostvars.yml

# Limit to specific hosts (requires "hosts: all" in the play)
ansible-playbook -i "environments/aws-eu-dev/hosts" hostvars.yml --limit=host1,host2

# Specify one or more hosts without an inventory
# Note the comma (,) at the end; this signals that it's a list, not a file.
ansible-playbook -i "host1,host2," hostvars.yml