Ansible Reference Card
Contents
1 Overview
1.1 Inventory
1.1.1 Documentation
- show all inventory plugins
ansible-doc -t inventory -l
- show ini style inventory (default)
ansible-doc -t inventory ini
1.1.2 Examples
/etc/ansible/hosts
[apache] web[01:05] ansible_user=devops [nginx] web[10:12] web13 ansible_port=222 has_java = False 10.0.1.[250:253] [nginx:vars] http_port=8080 [webservers:children] nginx apache
1.1.3 Dynamic Inventory Example
cat inventory/dynamic-inventory.sh #!/bin/bash echo '{ "web": ["www1", "www2", "www3"], "db": ["db1", "db2", "oracle1"] }'
cat inventory/hosts [sudo] vm20 ansible_user=ansible
chmod 700 inventory/dynamic-inventory.sh ls -l inventory/
-rwxr-xr-x. 1 root root 94 Dec 14 15:01 dynamic-inventory.sh -rw-r--r--. 1 root root 34 Dec 14 15:03 hosts
</source>
<source lang="bash"> [root@ansible lab]# ansible -i inventory/ --list-hosts web
hosts (3): www1 www2 www3
[root@ansible lab]# ansible -i inventory/ --list-hosts sudo
hosts (1): vm20
</source>
1.1.4 Commands
- query inventory for specific hosts
ansible web01 --list-hosts ansible 'all:!kvm' -i /etc/ansible/hosts --list-hosts
- show host involved by playbook
ansible-playbook --list-hosts tests/qa.yml
- run module on specific host
ansible vm06 -m setup
2 Setup Ansible
yum list installed python yum -y install ansible #install public key on destination ssh-copy-id root@web1
2.1 Configure Ansible
- Order of config file sources
ANSIBLE_CONFIG=/opt/ansible.cfg -> ./ansible.cfg -> $HOME/.ansible.cfg -> /etc/ansible/ansible.cfg
- Config Sections
egrep '^\[' /etc/ansible/ansible.cfg [defaults] [privilege_escalation] [ssh_connection] [accelerate] [selinux] [colors]
2.1.1 defaults
forks = 5 # specify number of parallel processes to use host_key_checking = True vault_password_file = /path/to/vault_password_file ansible_managed = Ansible managed: {file} on {host} display_skipped_hosts = True display_args_to_stdout = True
2.1.2 privilege_escalation
become=True # to enable privilege escalation
2.1.2.1 Example
# define user in inventory on ansible host vm20 ansible_user=ansible # create and configure user on destination host useradd ansible su - ansible mkdir .ssh chmod 700 .ssh vi .ssh/authorized_keys # add ansible host pub key chmod 600 .ssh/authorized_keys echo 'ansible ALL=(ALL)NOPASSWD: ALL' > /etc/sudoers.d/ansible visudo -cf /etc/sudoers.d/ansible # verify configuration [root@ansible lab]# ansible vm20 -m command -a w vm20 | SUCCESS | rc=0 >> 14:24:49 up 48 min, 2 users, load average: 0.00, 0.01, 0.05 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT root pts/0 192.168.223.59 13:43 5:05 0.05s 0.00s tail -f /var/log/secure ansible pts/1 192.168.223.43 14:24 0.00s 0.10s 0.00s /bin/bash -c sudo -H -S -n -u root /bin/bash -c 'echo BECOME-SUCCESS-fwkpkpwhbtkkrxdktmuwvgjmi...
2.2 vim settings
- $HOME/.vimrc
autocmd Filetype yml setlocal ai sw=2 et
2.3 Configure Cisco IOS devices
ansible-galaxy collection install ansible.netcommon
- ios_playbook_example.yml
- hosts: switch-aa-325-06 gather_facts: no vars: #### ansible v5 #ansible_connection: ansible.netcommon.network_cli #ansible_network_os: cisco.ios.ios #### ansible v2.9 ansible_connection: network_cli ansible_network_os: ios ansible_user: admin ansible_password: xxx ansible_become: yes ansible_become_method: enable ansible_become_password: xxx pre_tasks: - name: Gather facts ios_facts: when: ansible_network_os == 'ios' tasks: - name: run ios cmd ios_command: commands: show version register: version - name: print cmd output debug: var: version - name: print all native facts debug: var: ansible_facts - name: backup config (ios) ios_config: backup_options: dir_path: /tmp/ios-backup backup: yes register: backup_ios_location when: ansible_network_os == 'ios' - name: print ios backup config debug: var: backup_ios_location
2.4 Configure Fortigate devices
Note that forti modules are not really well maintained.
some of them use https connection, some only ssh! <pre> - name: test connectivity hosts: fw01 collections: - fortinet.fortios vars: vdom: "root" ansible_httpapi_use_ssl: yes ansible_httpapi_validate_certs: no ansible_httpapi_port: 8443 # ansible_user: "ansible_forti" # ansible_password: "xxxxxxxxx" connection: httpapi gather_facts: no pre_tasks: - name: gather facts for forti devices fortios_facts: vdom: "{{ vdom }}" gather_subset: - fact: system_current-admins_select - fact: system_firmware_select - fact: system_fortimanager_status - fact: system_ha-checksums_select - fact: system_interface_select - fact: system_status_select - fact: system_time_select tasks: - name: print all facts debug: var: ansible_facts - name: print firmware debug: var: ansible_facts.network_resources.system_firmware_select.version
3 Working with Playbooks
3.1 Loop examples
--- - hosts: localhost vars: var1: this is one var array1: [aaa, bbb] array2: - ccc - ddd dictionary1: { key1: value1, key2: value2 } dictionary2: key3: value3 key4: value4 multi_array1: user1: name: bob nr: 123 user2: name: mike nr: 456 tasks: - name: show var1 debug: msg: "{{ var1 }}" - name: loop array1 debug: msg: "{{ item }}" with_items: "{{ array1 }}" - name: loop array2 debug: msg: "{{ item }}" with_items: "{{ array2 }}" - name: loop dictionary1 debug: msg: "{{ item.key }}: {{ item.value }}" with_dict: "{{ dictionary1 }}" - name: loop dictionary2 debug: msg: "{{ item.key }}: {{ item.value }}" with_dict: "{{ dictionary2 }}" - name: "multi_array1['user1']['name']" debug: msg: "multi_array1['user1']['name']: {{ multi_array1['user1']['name'] }}" - name: "multi_array1.user2'.name" debug: msg: "multi_array1.user2'.name: {{ multi_array1.user2.name }}" - name: multi_array1 loop with_dict debug: msg: "User {{ item.key }} is {{ item.value.name }} with nr {{ item.value.nr }}" with_dict: '{{ multi_array1 }}' - name: loop with with_fileglob debug: msg: "/etc/ansible/{{item}}" with_fileglob: "/etc/ansible/*" ...
3.1.1 Example Output
PLAY [localhost] ****************************************************************************************************** TASK [Gathering Facts] ************************************************************************************************ ok: [localhost] TASK [show var1] ****************************************************************************************************** ok: [localhost] => { "msg": "this is one var" } TASK [loop array1] **************************************************************************************************** ok: [localhost] => (item=aaa) => { "item": "aaa", "msg": "aaa" } ok: [localhost] => (item=bbb) => { "item": "bbb", "msg": "bbb" } TASK [loop array2] **************************************************************************************************** ok: [localhost] => (item=ccc) => { "item": "ccc", "msg": "ccc" } ok: [localhost] => (item=ddd) => { "item": "ddd", "msg": "ddd" } TASK [loop dictionary1] *********************************************************************************************** ok: [localhost] => (item={'key': u'key2', 'value': u'value2'}) => { "item": { "key": "key2", "value": "value2" }, "msg": "key2: value2" } ok: [localhost] => (item={'key': u'key1', 'value': u'value1'}) => { "item": { "key": "key1", "value": "value1" }, "msg": "key1: value1" } TASK [loop dictionary2] *********************************************************************************************** ok: [localhost] => (item={'key': u'key3', 'value': u'value3'}) => { "item": { "key": "key3", "value": "value3" }, "msg": "key3: value3" } ok: [localhost] => (item={'key': u'key4', 'value': u'value4'}) => { "item": { "key": "key4", "value": "value4" }, "msg": "key4: value4" } TASK [multi_array1['user1']['name']] ********************************************************************************** ok: [localhost] => { "msg": "multi_array1['user1']['name']: bob" } TASK [multi_array1.user2'.name] *************************************************************************************** ok: [localhost] => { "msg": "multi_array1.user2'.name: mike" } TASK [multi_array1 loop with_dict] ************************************************************************************ ok: [localhost] => (item={'key': u'user2', 'value': {u'nr': 456, u'name': u'mike'}}) => { "item": { "key": "user2", "value": { "name": "mike", "nr": 456 } }, "msg": "User user2 is mike with nr 456" } ok: [localhost] => (item={'key': u'user1', 'value': {u'nr': 123, u'name': u'bob'}}) => { "item": { "key": "user1", "value": { "name": "bob", "nr": 123 } }, "msg": "User user1 is bob with nr 123" } TASK [loop with with_fileglob] **************************************************************************************** ok: [localhost] => (item=/etc/ansible/hosts) => { "item": "/etc/ansible/hosts", "msg": "/etc/ansible//etc/ansible/hosts" } ok: [localhost] => (item=/etc/ansible/ansible.cfg) => { "item": "/etc/ansible/ansible.cfg", "msg": "/etc/ansible//etc/ansible/ansible.cfg" } ok: [localhost] => (item=/etc/ansible/ansible.cfg.rpmnew) => { "item": "/etc/ansible/ansible.cfg.rpmnew", "msg": "/etc/ansible//etc/ansible/ansible.cfg.rpmnew" } PLAY RECAP ************************************************************************************************************ localhost : ok=10 changed=0 unreachable=0 failed=0
3.2 Merging Dictionaries, dynamic Variables
- hosts: localhost vars: _default: name: chris name2: lompetier _custom1: name: calvin name2: hobbes _custom2: name: god tasks: - set_fact: {"{{ item.key }}":"{{ item.value }}"} with_dict: "{{_default|combine(_custom1)|combine(_custom2)}}"
3.2.1 Example Output
PLAY [localhost] ************************************************************************************************************************************************************************************************** TASK [Gathering Facts] ******************************************************************************************************************************************************************************************** ok: [localhost] TASK [set_fact] *************************************************************************************************************************************************************************************************** ok: [localhost] => (item={'key': 'name', 'value': 'god'}) ok: [localhost] => (item={'key': 'name2', 'value': 'hobbes'}) PLAY RECAP ******************************************************************************************************************************************************************************************************** localhost : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
4 Variables and Inclusions
4.1 Ansible variable precedence
Ansible variable overriding documentation
In 2.x, we have made the order of precedence more specific (with the last listed variables winning prioritization):
- role defaults [1]
- inventory file or script group vars [2]
- inventory group_vars/all
- playbook group_vars/all
- inventory group_vars/*
- playbook group_vars/*
- inventory file or script host vars [2]
- inventory host_vars/*
- playbook host_vars/*
- host facts
- play vars
- play vars_prompt
- play vars_files
- role vars (defined in role/vars/main.yml)
- block vars (only for tasks in block)
- task vars (only for the task)
- role (and include_role) params
- include params
- include_vars
- set_facts / registered vars
- extra vars (always win precedence)
Basically, anything that goes into “role defaults” (the defaults folder inside the role) is the most malleable and easily overridden. Anything in the vars directory of the role overrides previous versions of that variable in namespace. The idea here to follow is that the more explicit you get in scope, the more precedence it takes with command line -e extra vars always winning. Host and/or inventory variables can win over role defaults, but not explicit includes like the vars directory or an include_vars task.
5 Task Control
5.1 shell
- name: get list of services without Ansible warning shell: "service --status-all 2>&1 | awk {'print $4'}" args: warn: false # set warn=false to prevent warning register: services_list
5.2 error handling
- name: this will not be counted as a failure command: /bin/false ignore_errors: yes - name: Fail task when the command error output prints FAILED command: /usr/bin/example-command -x -y -z register: command_result failed_when: "'FAILED' in command_result.stderr" - name: Fail task when both files are identical raw: diff foo/file1 bar/file2 register: diff_cmd failed_when: diff_cmd.rc == 0 or diff_cmd.rc >= 2 - name: Check if a file exists in temp and fail task if it does command: ls /tmp/this_should_not_be_here register: result failed_when: - result.rc == 0 - '"No such" not in result.stdout' - name: example of many failed_when conditions with OR shell: "./myBinary" register: ret failed_when: > ("No such file or directory" in ret.stdout) or (ret.stderr != '') or (ret.rc == 10) - command: /bin/fake_command register: result ignore_errors: True changed_when: - '"ERROR" in result.stderr' - result.rc == 2