English version
RefCard for Ansible usage.
Written by Germain LEFEBVRE on December 2018 for Ansible v2.7 usage.
Table of Contents
- Context
- Upgrade your Ansible version
- Ansible Definitions
- Ansible Configuration
- Ansible AdHoc Commands
- Ansible Inventories
- Ansible Tasks
- Ansible Playbooks
- Ansible Variables
- Ansible Plays
- Ansible Roles
- Ansible Modules
- Ansible Vault
This is the list of the packages version used to make this RefCard.
Operating System distribution and version:
cat /etc/redhat-release
CentOS Linux release 7.5.1804 (Core)
Python version:
python --version
Python 2.7.5
Ansible version:
ansible --version
ansible 2.7.1
config file = /etc/ansible/ansible.cfg
configured module search path = [u'/home/ansible/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python2.7/site-packages/ansible
executable location = /bin/ansible
python version = 2.7.5 (default, Apr 11 2018, 07:36:10) [GCC 4.8.5 20150623 (Red Hat 4.8.5-28)]
Ansible give their Roadmap for v2.7 : https://docs.ansible.com/ansible/2.7/roadmap/ROADMAP_2_7.html
Ansible provides porting guides to help you keeping up-to-date:
- Ansible 2.0 Porting Guide
- Ansible 2.3 Porting Guide
- Ansible 2.4 Porting Guide
- Ansible 2.5 Porting Guide
- Ansible 2.6 Porting Guide
- Ansible 2.7 Porting Guide
The Facts are variables used by Ansible to persist data through hosts and executions. There are native facts are stored on local server (disk or in-memory) and user facts defined by Human actions. It is important to get that facts are stored by group of actions OR by host.
The Hosts are just servers that the Ansible Server can reach trhough its preferred protocol.
The Inventories are list of Hosts defined by FQDN and tidied in groups. Groups can be composed with hosts or group of hosts. Hosts can be aliased to make the list customisable.
The Tasks are the actions launched on remote Hosts. Tasks are written in YAML langage in a descriptive structure way making the read and write uniform through any tasks in the world.
The Variables are the way for Ansible to pass custom values in tasks (and more over).
The Playbooks are the gathering of tasks and hosts. So a Playbook defines a list of tasks to perform on remote servers.
The Roles are the tidy way to write playbooks. It permits to store a group of actions with the same purpose and to call them in playbooks in a single line.
Ansible Handlers are action triggers called from tasks and run at the end of a play. A Handler is a tasks defined by its name and called with its name.
Modules are scripts written in Python and making uniform actions possible in giving common inputs for users and generating outputs regarding the command played in the module.
Configuration can be made and used in a file which will be searched for in the following order:
- ansible.cfg (in the current directory)
- ~/.ansible.cfg (in the home directory)
- /etc/ansible/ansible.cfg
AdHoc commands are commands launched on the fly with writting any complex structured files.
ansible localhost -m ping
ansible localhost -m setup
ansible localhost -m debug -a 'myVar'
ansible localhost -m shell -a 'uptime'
ansible all -i inventories/servers -m ping
Ansible Inventories make possible to gather servers in a single file to run commands on all these hosts. Inventories are usually organized by environments (a file by env) to let the group_vars operate on tasks and roles.
Inventory definition:
server.domain.fr
server[01-09].domain.fr
rhel01 rhel01.domain.fr
deb01 deb01.domain.fr
arch01 arch01.domain.fr
win01 win01.domain.fr
[redhat]
rhel01
[debian]
deb01
[linux:children]
redhat
debian
[linux]
arch01
[windows]
win01
A task is a YAML structure able to perform actions through Ansible.
Task definition :
- name: The task name to make things clearly
become: yes
become_method: sudo
become_user: root
check_mode: yes
diff: no
remote_user: ansible
ignore_errors: True
import_tasks: more_handlers
include_tasks: other-tasks.yml
notify: restart apache
register: my_register
changed_when: False
failed_when: False
vars:
- myvar: toto
myfiles:
- default.conf
loop:
- item1
- ["item2", "item3"]
- { name: "item4", description: "Desc Item 4" }
when:
- my_register is defined
- ansible_distribution == "CentOS"
- ansible_distribution_major_version == "7"
block:
- name: Task to run in block
...
rescue:
- name: Task when block failed
always:
- name: Task always run before/after block
A playbook is the gathering between hosts where will be applied tasks.
Install package on RHEL servers
- hosts: [redhat]
become: true
tasks
- yum:
name: httpd
state: installed
Run roles on Docker servers but Master
- hosts: docker,!docker-master
become: true
roles:
- docker
- kubernetes
A Ansible variable is defined in group_vars, host_vars, role vars, CLI vars and is called in Jinja Templating way : {{ my_variable }}
. You can call variables everywhere in Ansible (tasks, variables, template, ...)
You can have 3 types of variables:
- String
- List
- Dictionary
A variable is defined by a couple Key/Value where Key doesn't have any space and Value is a structure as defined above.
my_string: "value"
my_list: ["bob", "alice"]
my_dict:
item1: value1
item2: value2
You can set Ansible variables in multiple places like group_vars
, playbooks
, roles
, etc... but they are evaluated according to a precedence. Here is the order of precedence from least to greatest:
command line values
role defaults
inventory file or script group vars
inventory group_vars/all
playbook group_vars/all
inventory group_vars/*
playbook group_vars/*
inventory file or script host vars
inventory host_vars/*
playbook host_vars/*
host facts / cached set_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)
include_vars
set_facts / registered vars
role (and include_role) params
include params
extra vars (always win precedence)
A sufficient list of attributes for Ansible Play when running a playbook:
- hosts: webservers
accelerate: no
accelerate_port: 5099
ansible_connection: local
any_errors_fatal: True
become: yes
become_method: su
become_user: postgress
become_flags: True
debugger: on_failed
gather_facts: no
max_fail_percentage: 30
order: sorted
remote_user: root
serial: 5
strategy: debug
vars:
http_port: 80
vars_files:
- "vars.yml"
vars_prompt:
- name: "my_password2"
prompt: "Enter password2"
default: "secret"
private: yes
encrypt: "md5_crypt"
confirm: yes
salt: 1234
salt_size: 8
tags:
- stuff
pre_tasks:
- <task>
roles:
- common
- common
vars:
port: 5000
when: "bar == 'Baz'"
tags : [one, two]
- common
- { role: common, port: 5000, when: "bar == 'Baz'", tags :[one, two] }
tasks:
- include: tasks.yaml
- include: tasks.yaml
when: day == 'Thursday'
vars:
foo: aaa
baz:
- z
- y
- { include: tasks.yaml, foo: zzz, baz: [a,b]}
- <task>
post_tasks:
- <task>
Role directories strucutre:
roles/
└── my-role
├── defaults
│ └── main.yml
├── files
| └── file
├── handlers
│ └── main.yml
├── tasks
│ └── main.yml
├── templates
| └── template.j2
└── vars
└── main.yml
These are what files refer to:
my-role/defaults/main.yml
defines default variables for the role,my-role/files/file
file (without vars) to be copied,my-role/handlers/main.yml
defnies the handlers tasks,my-role/tasks/main.yml
is the main taskfile run thorugh the role,my-role/templates/template.yml.j2
template (with vars) to be copied,my-role/vars/main.yml
defines the vars to override,
- command: cat /etc/hosts
File at roles/example/files/my-file.sh
and task at roles/example/tasks/main.yml
.
- copy:
src: my-file.sh
dest: /tmp/my-file.sh
Template at roles/example/templates/my-template.sh.j2
#!/bin/bash
echo "{{ timezone }}"
Task at roles/example/tasks/main.yml
- template:
src: my-template.sh.j2
dest: /tmp/my-template.sh
Handler at roles/example/handlers/main.yml
.
- name: Restart Apache
systemd:
name: httpd
state: restart
Task at roles/example/tasks/main.yml
.
- copy:
src: httpd.conf
dest: /etc/httpd/conf/httpd.conf
notify: Restart Apache
Will run the handler Restart Apache
if task copy
state has changed.
Default variables at roles/example/defaults/main.yml
apache_version: '2.4.2'
Task at roles/example/tasks/main.yml
- yum:
name: httpd-{{ apache_version }}
state: present
Both import_task
and include_task
work.
- hosts: [redhat]
tasks:
- import_tasks: roles/example/tasks/main.yml
- include_tasks: roles/example/tasks/main.yml
Only import_tasks
works and evaluates tags from tasks.
Only import_playbook
works for including a whole playbook in another one.
- import_playbook: install_apache.yml
Both import_role
and include_role
can be used to call tasks from a role. This will include the whole role example
.
- hosts: [redhat]
tasks:
- import_role:
name: example
Permit to load all variables inherant to the role. This will include the task install.yml
from the role example
.
- hosts: [redhat]
tasks:
- include_role:
name: example
tasks_from: install
Only import_role
works for including a whole role in a playbook using tags on commands.
- hosts: [redhat]
tasks:
- import_role:
name: example
Ansible offre des possibilités plus avancées qui aident à la vérification, au débuggage et poussent sur le plan non destructif des exécutions.
Option --limit
or -l
filters playbook runtime by server (host or alias), inventory groups and understand the exclusions.
ansible-playbook -i hosts.yml playbook.yml --limit 'linux,!debian'
Option --tag
or -t
filters playbook tasks on tags set through attribut tags:
on Plays and Tasks. Exclusion is possible on Tag filter.
ansible-playbook -i host.yml playbook.yml --tags 'config,service,!reload'
Option --check
runs playbook without applying any modification on server and reveals the state for every Task (ok, changed, failed). Dry-Run mode make verifications easy.
ansible-playbook -i host.yml playbook.yml --check
Dry-Run mode is not plenty compatible with shell module because no state is returned on running shell scripts or commands.
Option --diff
show differences between Ansible and Server sides and is closely linked to files (copy, template modules). Differences mode is a good way to see changes on servers.
ansible-playbook -i host.yml playbook.yml --diff
Store your modules on :
- Local side (current dir) : Create your Ansibel Module directly in your ansible rundir in a directory
library
, - Server side (all users) : Define the path with the attribute
library
in/etc/ansible/ansible.cfg
.
library = /usr/share/my_modules/
class MyAnsibleModule(AnsibleModule):
def __init__(self, *args, **kwargs):
self._output = []
self._facts = dict()
super(MyAnsibleModule, self).__init__(*args, **kwargs)
def process(self):
[...]
if __name__ == '__main__':
MyAnsibleModule().process()
Define your module arguments.
MyAnsibleModule(
argument_spec=dict(
url=dict(type='str',
required=True),
type=dict(type='str',
required=True,
choices=['indice', 'document']),
state=dict(type='str',
choices=['present','absent'],
default='present')
)
).process()
Call your module argument on processing.
def process(self):
try:
changed = False
# Retrieve value for attribute 'url'
param_url = self.params['url']
self.exit_json(changed=changed, ansible_facts={}, output=self._output)
except Exception as e:
self.fail_json(msg=(e.message, self._output))
Enable the check mode.
def main():
MyAnsibleModule(
supports_check_mode=True,
[...]
).process()
Use the check mode in processing. Process to your action after checking check_mode statement.
def process(self):
# Stop if check_mode is true before doing any action
if self.check_mode:
return True
# Keep doing actions if check_mode is false
Ansible Vault Password configuration can be done in several ways:
- Attribute
vault_password_file
in fileansible.cfg
, - Env variable
ANSIBLE_VAULT_PASSWORD_FILE
, - Option
--vault-password-file
or--vault-id
with password file in ansible command, - Option
--ask-vault-pass
with prompt in ansible command.
You can secure whole files with vault in encrypting them.
ansible-vault create foo.yml
ansible-vault encrypt foo.yml
View and decrypt to clear file.
ansible-vault view foo.yml
ansible-vault encrypt foo.yml
You can also only encrypt value in variables files.
ansible-vault encrypt_string --name 'mykey' 'mysecret'
If you have provided a vault password in configuration file then you will keep using ansible as usual.
If not you will need to provide vault options to your ansible commands.
ansible-playbook site.yml --ask-vault-pass
ansible-playbook site.yml --vault-password-file ~/.vault_pass
ansible-playbook --vault-id dev@dfile-dev-password site.yml
ansible-playbook --vault-id prod@prompt site.yml
You can also provide multiple vault resolvers to roll on multiple environments. Example for Dev with password file and Prod with prompt.
ansible-playbook --vault-id dev@dev-password --vault-id prod@prompt site.yml