Cheat Sheet - Ansible



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

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

loop: "{{ somelist }}"


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
    name: "{{ list_of_packages }}"
    state: present

- name: non optimal yum, not only slower but might cause issues with interdependencies
    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
    name: "{{ }}"
    state: present
    groups: "{{ item.groups }}"
    - { 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
    tags_dict: "{{ (tags_dict | default({})) | combine({item.key: item.value}) }}"
  loop: "{{ tags | dict2items }}"
      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
    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:

# 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.

    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:


localhost              ansible_connection=local     ansible_connection=ssh        ansible_user=mpdehaan     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
    - name: Print all variables for each remote device
        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

Helper scripts

Multi vault edit

#/usr/bin/env bash


SCRIPT_DIR=$(dirname "$0")
cd "${SCRIPT_DIR}/../"

vault_files=$(find ./environments -name 'vault.yml' | sort)

# handle "Input is not from a terminal" error that can break the terminal
# Vim expects its stdin to be the same as its controlling terminal but xargs
# sets it to /dev/null
# see:

case "$(uname -s)" in
     echo "$vault_files" | fzf -e -m | xargs -o ansible-vault edit

     echo "$vault_files" | fzf -e -m | xargs bash -c '</dev/tty ansible-vault edit "$@"' ignoreme

Bad character finder



# U+00A0  non-breaking space (NBSP)
# U+02002 en space
# U+02003 em space
# U+02004 three-per-em space
# U+02005 four-per-em space
# U+02006 six-per-em space
# U+02007 figure space
# U+02008 punctuation space
# U+02009 thin space
# U+0200A hair space
# U+0202F narrow no-break space
# U+0205F medium mathematical space
# U+03000 ideographic space

case "$(uname -s)" in

    command -v ggrep >/dev/null 2>/dev/null || { echo 'Please run: brew install gnu-grep'; exit 1; }
    command -v gsed >/dev/null 2>/dev/null || { echo 'Please run: brew install gnu-sed'; exit 1; }
    ggrep --recursive --files-with-matches --binary-files=without-match --perl-regexp "\xa0" "${TARGET_PATH}" | xargs gsed -i 's/\xC2\xA0/ /g'

    grep --recursive --files-with-matches --binary-files=without-match --perl-regexp "\xa0" "${TARGET_PATH}" | xargs sed -i 's/\xC2\xA0/ /g'

    echo 'unsupported OS'; exit 1;

Last updated