Ansible 2
=========
.. contents:: Table of Contents
Introduction
------------
Ansible is a simple utility for automating configuration management and system administration tasks via SSH for UNIX-like operating systems. The only requirements are a SSH connection from a control node to a managed node and Python on both nodes. Ansible uses YAML syntax and does not require any knowledge of programming. [1]
There is also support for Windows modules. Ansible is executed on a control node that runs on Linux, using Python. A remote connection to WinRM (via HTTPS, by default) is made and then modules are executed remotely using PowerShell commands. [31]
Starting with Ansible 2.4, it has a 1 year life cycle. The first 4 months of the release get general bug and security updates. The next 4 months get major bug and security updates. Finally, the last 4 months only get security updates. [63]
Official documentation:
- `Stable `__
- `Development `__
- `2.10 `__
- `2.9 `__
- `2.8 `__
Editions
~~~~~~~~
There are two editions of Ansible available. There is the upstream Ansible community project which receives no support. For enterprise users, there is Red Hat Ansible Engine which provides support that covers Core modules, priority bug and feature updates, documentation, and more. Both use the same binary code with the only difference being support. [40]
Deprecations
~~~~~~~~~~~~
If a component in Ansible release ``N`` becomes deprecated then it is normally left unmaintained up until ``N + 4`` when it is fully removed. For example, a module deprecated in 2.2 would have been removed in 2.6. Ansible aims to be as highly backwards compatible as possible with each minor release.
Installation
------------
Ansible requires Python 2.7 or >= 3.5 on both the control and managed nodes. [18] Python 3 support is stable and has been fully supported since the Ansible 2.5 release. [43]
Ansible RPMs for Fedora based operating systems are available from:
- The "extras" repository (Fedora)
- The upstream Ansible repository http://releases.ansible.com/ansible/rpm/release/ (Enterprise Linux and Fedora)
- The Ansible Engine repository (RHEL): ``sudo subscription-manager repos --enable=``
- RHEL 7: rhel-7-server-ansible-2-rpms OR rhel-7-server-ansible-2.9-rpms + rhel-7-server-extras-rpms
- RHEL 8: ansible-2-for-rhel-8-x86_64-rpms OR ansible-2.9-for-rhel-8-x86_64-rpms
Fedora:
.. code-block:: sh
$ sudo dnf install ansible-python3
Debian:
.. code-block:: sh
$ sudo apt-get install software-properties-common
$ sudo apt-add-repository ppa:ansible/ansible
$ sudo apt-get update
$ sudo apt-get install ansible
Source code:
.. code-block:: sh
$ git clone https://github.com/ansible/ansible.git
$ cd ./ansible/
$ git branch -a | grep stable
$ git checkout remotes/origin/stable-2.10
$ git submodule update --init --recursive
$ source ./hacking/env-setup
Updating source code installations:
.. code-block:: sh
$ git pull --rebase
$ git submodule update --init --recursive
Pre-release branch or tag directly from GitHub using pip:
.. code-block:: sh
$ pip install --user git+https://github.com/ansible/ansible.git@
[18]
For managing Windows servers, the "winrm" Python library is required on the Ansible control node. The remote Windows servers need PowerShell >= 3.0 installed and WinRM enabled. [31]
Configuration
-------------
Main
~~~~
All of the possible configuration files are listed below in the order
that they are read. The last file overrides any previous settings.
Configuration files:
- ``$ANSIBLE_CONFIG`` = A command line variable containing the Ansible
configuration settings.
- ``ansible.cfg`` = If it is in the current directory, it will be used.
- ``~/.ansible.cfg`` = The configuration file in a user's home
directory.
- ``/etc/ansible/ansible.cfg`` = The global configuration file.
Common settings:
- [defaults]
- ansible\_managed = String. The phrase that will be assigned to the
``{{ ansible_managed }}`` variable. This should generally reside
at the top of a template file to indicate that the file is managed
by Ansible.
- ask\_pass = Boolean. Default: False. Prompt the user for the SSH
password.
- ask\_sudo\_pass = Boolean. Default: False. Prompt the user for the
sudo password.
- ask\_vault\_pass = Boolean. Default: False. Prompt the user for
the Ansible vault password.
- command\_warnings = Boolean. Default: True. Inform the user an
Ansible module can be used instead of running certain commands.
- deprecation\_warnings = Boolean. Default: True. Show deprecated
messages about features that will be removed in a future release
of Ansible.
- display\_skipped\_hosts = Boolean. Default: True. Show tasks that
a skipped host would have run.
- executable = String. Default: /bin/bash. The shell executable to
use.
- forks = Integer. Default: 5. The number of parallel processes used
to run tasks on remote hosts. This is not how many hosts a
Playbook or module can run on, that is handled by the "serial"
module. This helps to increase the performance of many operations
across a large number of remote hosts.
- host\_key\_checking = Boolean. Default: True. Do not automatically
accept warnings about leaving SSH fingerprints on a connection to
a new host.
- internal\_poll\_interval = Float. Default: 0.001. The number of
seconds to wait before checking on the status of a module that is
being executed.
- inventory = String. Default: /etc/ansible/hosts. The default
inventory file to find hosts from.
- log\_path = String. Default: none. The file to log Ansible's
operations.
- nocolor. Boolean. Default: 0. Do not format Ansible output with
color.
- nocows = Boolean. Default: 0. If the ``cowsay`` binary is present,
a Playbook will output information using a cow.
- hosts = String. Default: \*. The hosts to run a Playbook on if no
host is specified. The default is to run on all hosts.
- private\_key\_file = String. The private SSH key file to use.
- remote\_port = Integer. Default: 22. The SSH port used for remote
connections.
- remote\_tmp = String. Default: ~/.ansible/tmp. The temporary
directory on the remote server to save information to.
- remote\_user = String. Default: root. The default ``ansible_user``
to use for SSH access.
- roles\_path = String. The path to the location of installed roles.
- sudo\_exe = String. Default: sudo. The binary to run to execute
commands as a non-privileged user.
- sudo\_user = String. Default: root. The user that sudo should run
as.
- timeout = Integer. Default: 10. The amount of time, in seconds, to
wait for a SSH connection to a remote host.
- vault\_password\_file = String. The default file to use for the
Vault password.
- [privilege\_escalation]
- become = Boolean. Default: False. This specifies if root level
commands should be run by a privileged user.
- become\_method = String. Default: sudo. The method to run root
tasks.
- become\_user = String. Default: root. The user to change to to run
root tasks.
- become\_ask\_pass = Boolean. Default: False. Ask the end-user for
a password for the become method.
- [ssh\_connection]
- ssh\_args = String. Additional SSH arguments.
- retries = Integer. Default: 0 (keep retrying). How many times
should an SSH connection attempt to reconnect after a failure.
- pipelining = Boolean. Default: False. Ansible modules can be
combined and sent to the remote host via SSH to help save time and
improve performance. This is disabled by default because ``sudo``
accounts usually have the "requiretty" option enabled that is not
compatible with pipelining.
- ansible\_ssh\_executable = String. Default: ssh (found in the
$PATH environment variable). The path to the ``ssh`` binary.
[27]
Python 3
~~~~~~~~
Python 3 is supported on the control node and managed nodes. For using
Python 3 on the managed nodes, the ``ansible_python_interpreter``
variable needs to be set to reference the path to the managed nodes'
Python 3.
Example:
.. code-block:: sh
$ /usr/bin/python3 /usr/bin/ansible -e "ansible_python_interpreter=/usr/bin/python3" -m setup localhost
Documentation on how to create Ansible modules for Python 3 with
backwards compatibility with Python 2 can be found `here `__.
[43]
Commands Usage
--------------
See: `Linux Commands - Configuration Management - Ansible <../commands/configuration_management.html#ansible>`__.
Playbooks
---------
Playbooks organize tasks into one or more YAML files. It can be a
self-contained file or a large project organized in a directory.
Official examples can he found here at
https://github.com/ansible/ansible-examples.
Tasks
~~~~~
Tasks and roles defined in a playbook are executed in this specific order:
- pre_tasks
- roles
- tasks
- post_tasks
Example:
.. code-block:: yaml
---
- name: Example of running tasks.
hosts: all
pre_tasks:
- debug:
msg: "Hello world from the pre task (before installing NGINX)."
roles:
- nginx
tasks:
- debug:
msg: "Hello world from the second task (after installing NGINX)."
post_tasks:
- debug:
msg: "Hello world from the third task (after the normal tasks)."
[78]
Directory Structure
~~~~~~~~~~~~~~~~~~~
A Playbook can be self-contained entirely into one file. However,
especially for large projects, each segment of the Playbook should be
split into separate files and directories.
Layout:
::
├── production/
│ ├── group_vars/
│ ├── host_vars/
│ └── inventory
├── staging/
│ ├── group_vars/
│ ├── host_vars/
│ └── inventory
├── roles/
│ └── general/
│ ├── defaults/
│ │ └── main.yml
│ ├── files/
│ ├── handlers/
│ │ └── main.yml
│ ├── meta/
│ │ └── main.yml
│ ├── tasks/
│ │ └── main.yml
│ ├── templates/
│ └── vars/
│ └── main.yml
└── site.yml
Layout Explained:
- production/ = A directory that contains information about the
Ansible-controlled hosts and inventory variables. This should be used
for deploying to live production environments. Alternatively, simple
Playbooks can use a "production" file to list all of the inventory
servers there.
- group\_vars/ = Group specific variables. A file named "all" can be
used to define global variables for all hosts.
- host\_vars/ = Host specific variables.
- inventory = The main "production" inventory file.
- staging/ = The same as the "production/" directory except this is
designed for running Playbooks in testing environments.
- roles/ = This directory should contain all of the different roles.
- general/ = A role name. This can be anything.
- defaults/ = Define default variables. If any variables are
defined elsewhere, these will be overridden.
- main.yml = Each main.yml file is executed as the first file.
Additional separation of operations can be split into
different files that can be accessed via "include:"
statements.
- files/ = Store static files that are not modified.
- handlers/ = Specify alias commands that can be called using the
"notify:" method.
- main.yml
- meta/ = Specify role dependencies and Playbook information such
as author, version, etc. These can be other roles and/or
Playbooks.
- main.yml
- tasks/
- main.yml = The tasks' main file is executed first for the
entire role.
- templates/ = Store dynamic files that will be generated based
on variables.
- vars/ = Define role-specific variables.
- main.yml
- site.yml = This is typically the default Playbook file to execute.
Any name and any number of Playbook files can be used here to include
different roles.
Examples:
- site.yml = This is generally the main Playbook file. It should
include all other Playbook files required if more than one is used.
[5]
.. code-block:: yaml
---
# File: site.yaml
include: nginx.yml
include: php-fpm.yml
.. code-block:: yaml
---
# File: nginx.yml
- hosts: webnodes
roles:
- common
- nginx
- roles/\ ````/vars/main.yml = Global variables for a role.
.. code-block:: yaml
---
# File: vars/main.yaml
memcache_hosts:
- 192.168.1.11
- 192.168.1.12
- 192.168.1.13
ldap_ip: 192.168.10.1
- group\_vars/ and host\_vars/ = These files define variables for hosts
and/or groups. Details about this can be found in the
`Variables <#configuration---inventory---variables>`__ section.
- templates/ = Template configuration files for services. The files in
here end with a ".j2" suffix to signify that it uses the Jinja2
template engine. [1]
.. code-block:: html
My domain name is {{ domain }}
Performance Tuning
~~~~~~~~~~~~~~~~~~
A few configuration changes can help to speed up the runtime of Ansible
modules and Playbooks.
- ansible.cfg
- [defaults]
- forks = The number of parallel processes that are spun up for remote connections. Each fork connects to one host. The default is 5. This should be increased to a larger number to handle . The recommended number is between ``processor_cores x 10`` and ``100 per 4GB RAM`` depending on whether the Ansible tasks are CPU- or RAM-bound. Ansible is normally CPU-bound.
- pipelining = Enable pipelining to bundle commands together that
do not require a file transfer. This is disabled by default
because most sudo users are enforced to use the ``requiretty``
sudo option that pipelining is incompatible with. [26]
- gathering = Set this to "explicit" to only gather the necessary
facts when/if they are required by the Playbook. [27]
Fact caching will temporarily save information gathered about hosts. By only gathering the setup/host fact once, this helps to speed up execution time if playbooks will need to be ran multiple times. The supported types of fact caching are currently memory (none), jsonfile, memcached, mongodb, pickle, redis, and yaml. [19]
All:
- ansible.cfg
- [defaults]
- gathering = smart
- fact\_caching = 86400 \# This will set the cache time to 1 day.
JSON File:
- ansible.cfg
- [defaults]
- fact\_caching = jsonfile
- fact\_caching\_connection =
````
Redis:
- ansible.cfg
- [defaults]
- fact\_caching = redis
- fact\_caching\_connection = ``:``
[4]
If tasks between hosts can run independently of each other, then tasks can be allowed to move onto the next one immediately when a host is done (even if other hosts are not).
- ansible.cfg
- [defaults]
- strategy = free
[36]
Inventory
---------
Default file: /etc/ansible/hosts
The hosts file is referred to as the "inventory" for Ansible. Here
servers and groups of servers are defined. Ansible can then be used to
execute commands and/or Playbooks on these hosts. There are two groups
that are automatically created by Ansible. The "all" group is every
defined host and "ungrouped" is a group of hosts that do not belong to
any groups. User defined groups are created by using brackets "[" and
"]" to specify the name.
Syntax:
.. code-block:: ini
ansible_host=
[]
Example:
.. code-block:: ini
[dns-us]
dns-us01
dns-us02
dns-us03
A sequence of letters "[a:z]" or numbers "[0:9]" can be used to
dynamically define a large number of hosts.
Example:
.. code-block:: ini
[dns-us]
dns-us[01:03]
A group can also be created from other groups by using the ":children"
tag.
Example:
.. code-block:: ini
[dns-global:children]
dns-us
dns-ca
dns-mx
Variables are created for a host and/or group using the tag ":vars".
Then any custom variable can be defined and associated with a string. A
host specifically can also have it's variables defined on the same line
as it's Ansible inventory variables. [3] A few examples are listed
below. These can also be defined in separate files as explained in the "Variables" chapter.
Example:
.. code-block:: ini
examplehost ansible_user=toor ansible_host=192.168.0.1 custom_var_here=True
.. code-block:: ini
[examplegroup:vars]
domain_name=examplehost.tld
domain_ip=192.168.7.7
There are a large number of customizations that can be used to suit most
server's access requirements.
Common inventory options:
- ansible\_host = The IP address or hostname of the server.
- ansible\_port = A custom SSH port (i.e., if not using the standard
port 22).
- ansible\_connection = These options specify how to log in to execute
tasks.
- chroot = Run commands in a directory using chroot.
- local = Run on the local system.
- ssh = Run commands over a remote SSH connection (default).
- winrm = Use the Windows Remote Management (WinRM) protocols to
connect to Windows servers.
- ansible\_winrm\_server\_cert\_validation
- ignore = Ignore self-signed certificates for SSL/HTTPS connections
via WinRM.
- ansible\_user = The SSH user.
- ansible\_pass = The SSH user's password. This is very insecure to
keep passwords in plain text files so it is recommended to use SSH
keys or pass the "--ask-pass" option to ansible when running tasks.
- ansible\_ssh\_private\_key\_file = Specify the private SSH key to use
for accessing the server(s).
- ansible\_ssh\_common\_args = Append additional SSH command-line
arguments for sftp, scp, and ssh.
- ansible\_{sftp\|scp\|ssh}\_extra\_args = Append arguments for the
specified utility.
- ansible\_python\_interpreter = This will force Ansible to run on
remote systems using a different Python binary. Ansible only supports
Python 2 so on server's where only Python 3 is available a custom
install of Python 2 can be used instead. [3]
- ansible\_vault\_password\_file = Specify the file to read the Vault
password from. [21]
- ansible\_become = Set to "True" or "yes" to become a different user
than the ansible\_user once logged in.
- ansible\_become\_method = Pick a method for switching users. Valid
options are: sudo, su, pbrun, pfexec, doas, or dzdo.
- ansible\_become\_user = Specify the user to become.
- ansible\_become\_pass = Optionally use a password to change users.
[13]
Examples:
.. code-block:: ini
localhost ansible_connection=local
dns1 ansible_host=192.168.1.53 ansible_port=2222 ansible_become=True ansible_become_user=root ansible_become_method=sudo
dns2 ansible_host=192.168.1.54
/home/user/ubuntu1604 ansible_connection=chroot
[4]
Production and Staging
~~~~~~~~~~~~~~~~~~~~~~
Ansible best practices suggest having a separation between a production
and staging inventory. Changes should be tested in the staging
environment and then eventually ran on the production server(s).
Scenario #1 - Use the Same Variables
A different inventory file can be created if all of the variables are
the exact same in the production and staging environments. This will run
the same Playbook roles on a different server.
Syntax:
::
├── production
├── staging
├── group_vars
│ └──
├── host_vars
│ └──
.. code-block:: sh
$ ansible-playbook -i production .yml
.. code-block:: sh
$ ansible-playbook -i staging .yml
Example:
::
├── production
├── staging
├── group_vars
│ ├── web
│ ├── db
│ └── all
├── host_vars
│ ├── web1
│ ├── web2
│ ├── db1
│ ├── db2
│ └── db3
Scenario #2 - Use Different Variables
In more complex scenarios, the inventory and variables will be different
in production and staging. This requires further separation. Instead of
using a "production" or "staging" inventory file, they can be split into
directories. These directories contain their own group and host
variables. The production example also shows how to separate plain-text and Vault encrypted variables.
Syntax:
::
├── production
│ ├── group_vars
│ │ └──
│ │ ├── vars
│ │ └── vault
│ ├── host_vars
│ │ └──
│ │ ├── vars
│ │ └── vault
│ └── inventory
::
├── staging
│ ├── group_vars
│ │ └──
│ ├── host_vars
│ │ └──
│ └── inventory
.. code-block:: sh
$ ansible-playbook -i production .yml
.. code-block:: sh
$ ansible-playbook -i staging .yml
Example:
::
├── production
│ ├── group_vars
│ │ ├── web
│ │ ├── db
│ │ └── all
│ ├── host_vars
│ │ ├── web1
│ │ ├── web2
│ │ ├── db1
│ │ ├── db2
│ │ └── db3
│ └── inventory
::
├── staging
│ ├── group_vars
│ │ ├── web
│ │ ├── db
│ │ └── all
│ ├── host_vars
│ │ ├── web1
│ │ ├── web2
│ │ ├── db1
│ │ ├── db2
│ │ └── db3
│ └── inventory
[5][22]
Vault Encryption
~~~~~~~~~~~~~~~~
Any file in a Playbook can be encrypted. This is useful for storing
sensitive username and passwords securely. A password is used to open
these files after encryption. All encrypted files in a Playbook should
use the same password.
Vault Usage:
- Create a new encrypted file.
.. code-block:: sh
$ ansible-vault create .yml
- Encrypt an existing plaintext file.
.. code-block:: sh
$ ansible-vault encrypt .yml
- Viewing the contents of the file.
.. code-block:: sh
$ ansible-vault view .yml
- Edit the encrypted file.
.. code-block:: sh
$ ansible-vault edit .yml
- Change the password.
.. code-block:: sh
$ ansible-vault rekey .yml
- Decrypt to plaintext.
.. code-block:: sh
$ ansible-vault decrypt .yml
Playbook Usage:
- Run a Playbook, prompting the user for the Vault password.
.. code-block:: sh
$ ansible-playbook --ask-vault-pass .yml
- Run the Playbook, reading the file for the vault password.
.. code-block:: sh
$ ansible-playbook --vault-password-file .yml
[21]
Dynamic
~~~~~~~
Dynamic inventory can be used to automatically obtain information about
hosts from various infrastructure platforms and tools. Community
provided scripts be be found here:
https://github.com/ansible/ansible/tree/devel/contrib/inventory.
Variables
---------
Variables that Playbooks will use can be defined for specific hosts
and/or groups. The file that stores the variables should reflect the
name of the host and/or group. Global variables can be found in the
``/etc/ansible/`` directory. [3]
Inventory variable directories and files:
- host\_vars/
- ```` = Variables for a host defined in the inventory file.
- group\_vars/
- ````/
- vars = Variables for this group.
- vault = Encrypted Ansible Vault variables. [5]
- all = This file contains variables for all hosts.
- ungrouped = This file contains variables for all hosts that are not defined in any groups.
It is assumed that the inventory variable files are in YAML format. Here
is an example for a host variable file.
Example:
.. code-block:: yaml
---
domain_name: examplehost.tld
domain_ip: 192.168.10.1
hello_string: Hello World!
In the Playbook and/or template files, these variables can then be
referenced when enclosed by double braces "{{" and "}}". [4]
Example:
::
Hello world from {{ domain_name }}!
Variables from other hosts or groups can also be referenced.
Syntax:
::
{{ groupvars[''][''] }}
{{ hostvars[''][''] }}
::
{{ groupvars..}}
{{ hostvars.. }}
Example:
::
- command: echo {{ hostvars.db3.hostname }}
The order that variables take precedence in is listed below. The bottom
locations get overridden by anything above them.
- extra vars
- task vars
- block vars
- role and include vars
- set\_facts
- registered vars
- play vars\_files
- play vars\_prompt
- play vars
- host facts
- playbook host\_vars
- playbook group\_vars
- inventory host\_vars
- inventory group\_vars
- inventory vars
- role defaults
[5]
Magic Variables
~~~~~~~~~~~~~~~
Magic variables are variables that Ansible creates and manages outside of user-defined variables. Most of these exist with every playbook run.
- ansible_check_mode = If the playbook is ran with ``--check`` mode to see if tasks will make any modifications.
- ansible_dependent_role_names = A list of all of the roles imported as dependencies by playbooks that are referenced in the main playbook.
- ansible_diff_mode = If the playbook is ran with ``--diff`` mode to see what modifications were made.
- ansible_forks = The number of forks that are set.
- ansible_inventory_sources = A list of all of the inventory files that are loaded.
- ansible_limit = The string of hosts defined by ``--limit`` that the playbook is currently limited to.
- ansible_play_batch = The current hosts that are running, limited to only the hosts running from the ``serial`` size.
- ansible_play_hosts = The list of all of the (non-failed) hosts that the playbook ``hosts`` is set to use.
- ansible_play_name = The name of the playbook that is running.
- ansible_play_role_names = A list of the roles that are defined in the playbook file.
- ansible_playbook_python = The Python executable used to run Ansible on the control node.
- ansible_run_tags = A list of tags that are defined by ``--tags`` that the playbook is running.
- ansible_skip_tags = A list of tags that are defined by ``--skip-tags`` that the playbook is skipping.
- ansible_user_dir = The $HOME directory for the user that is being accessed on the managed node.
- ansible_verbosity = The level of verbosity set for the playbook execution.
- ansible_version = The Ansible version running.
- hostvars = Access variables from another host. Example: ``hostvars['web01']['ansible_hostname']``.
- inventory_dir = The directory that contains the inventory file(s).
- inventory_file = The full path to the primary "inventory" file that is loaded.
- inventory_hostname = The hostname of the current host that is being used.
- inventory_hostname_short = The subdomain of the current host's domain that is being used.
- groups = A list of all hosts and groups from the inventories that are loaded.
- group_names = A list of all of the groups that the current host is a part of.
- playbook_dir = The full path to the directory where the current playbook is located.
- omit = Used to skip the passing of an argument to a task. This is commonly used via the use of the Jinja filter ``default(omit)``.
- role_name = The name of the current role in use.
- role_path = The full path to the current role in use.
[82]
Modules
-------
A list of all of the latest Ansible modules is provided `here `__.
Main Modules
~~~~~~~~~~~~
Root Pages refers to generic Playbook-related modules as the "main
modules." This is not to be confused with official naming of "core
modules" which is a mixture of both the main and regular modules
mentioned in this guide.
Assert
^^^^^^
Assert is used to check if one or more statements is True. The module
will fail if any statement returns False. Optionally, a message can be
displayed if any operator comparisons return False.
Syntax:
.. code-block:: yaml
- assert:
that:
- " "
msg: ""
Example:
.. code-block:: yaml
- cmd: /usr/bin/date
register: date_command
ignore_errors: True
- assert:
that:
- "date_command.rc == 0"
- "'2017' in date_command.stdout"
msg: "Date either failed or did not return the correct year."
[45]
Async
^^^^^
The ``async`` function is used to start a detached task on a managed
system. Ansible will then poll that system periodically to see if the
task is complete. By default, it checks every 10 seconds and will only
move onto the next task if all of the processes are complete.
Tasks with loops will execute the module in parallel for each item.
By using ``poll: 0``, the task will be ran in the background and Ansible
will continue onto the next task. Do not set ``async: 0`` as that will disable async.
Syntax:
.. code-block:: yaml
async:
poll:
This example will run a command, check every 5 seconds to see if it is complete, until 15 seconds has elapsed. If it is still not complete, Ansible will end that async process and mark the task as being failed.
.. code-block:: yaml
- command: bash /usr/local/bin/example.sh
async: 15
poll: 5
[15]
Block
^^^^^
A ``block`` is used to handle logic for executing tasks. A set of tasks
can be run, for example, if a condition is met. This also handles errors
in a ``try/except`` fashion. If the code from the ``block`` fails then
it proceeds to run the tasks in the ``rescue`` section. There is also a
final ``always`` section that will execute whether the block failed or
not.
Syntax (minimal):
.. code-block:: yaml
block:
Syntax (full):
.. code-block:: yaml
block:
rescue:
always:
Example:
.. code-block:: yaml
- name: Installing docker
block:
- package:
name: docker
state: latest
rescue:
- debug:
msg: "Unable to properly install docker. Cleaning up now."
- file:
dest: /path/to/custom/docker/files
state: absent
always:
- debug:
msg: "Continuing onto the next set of tasks..."
[53]
Check Mode
^^^^^^^^^^
A Playbook can run in a test mode with ``--check``. No changes will be
made. Optionally, the ``--diff`` argument can also be added to show
exactly what would be changed.
Syntax:
.. code-block:: sh
$ ansible-playbook --check site.yml
.. code-block:: sh
$ ansible-playbook --check --diff site.yml
In Ansible 2.1, the ``ansible_check_mode`` variable was added to verify
if check mode is on or off. This can be used to forcefully run tasks
even if check mode is on.
Examples:
.. code-block:: yaml
- command: echo "Hello world"
when: not ansible_check_mode
.. code-block:: yaml
- name: Continue if this fails when check_mode is enabled
stat:
path: /etc/neutron/neutron.conf
register: neutron_conf
ignore_errors: "{{ ansible_check_mode }}"
In Ansible 2.2, the ``check_mode`` module can be forced to run during a
check mode. [29]
Syntax:
.. code-block:: yaml
check_mode: no
Examples:
.. code-block:: yaml
- name: Updating the operating system
yum:
name: "*"
state: latest
check_mode: no
- name: Installing the EPEL repository
yum:
name: epel-release
state: latest
check_mode: no
Debug
^^^^^
The debug module is used for helping facilitate troubleshooting. It prints out specified information to standard output.
Syntax:
.. code-block:: yaml
debug:
Common options:
- msg = Display a message. Default: ``Hello world!``.
- var = Display a variable.
- verbosity = Only display the debug output when a certain verbosity level is set for Ansible. Default: ``0``. [45]
Example:
- Print Ansible's hostname of the current server that the script is being run on.
.. code-block:: yaml
debug:
msg: The inventory host name is {{ inventory_hostname }}
verbosity: 1
Gather Facts
^^^^^^^^^^^^
By default, Ansible will connect to all hosts related to a Playbook and
cache information about them. This includes hostnames, IP addresses, the
operating system version, etc.
Syntax:
.. code-block:: yaml
gather_facts:
If these variables are not required then gather\_facts and be set to
"False" to speed up a Playbook's run time. [23]
Example:
.. code-block:: yaml
gather_facts: False
In other situations, information about other hosts may be required that
are not being used in the Playbook. Facts can be gather about them
before the roles in a Playbook are executed.
Example:
.. code-block:: yaml
---
- hosts: squidproxy1,squidproxy2,squidproxy3
gather_facts: True
- hosts: monitor1,monitor2
roles:
- common
- haproxy
Common facts:
- ansible\_os\_family = The main distribution that the operating system is forked from. A full list of the mappings can be found in the ``OS_FAMILY_MAP`` variable `here `__.
- Archlinux = Archlinux, Antergos, Manjaro
- Darwin = macOS
- Debian = Debian, Ubuntu, Linux Mint, etc.
- RedHat = RHEL, CentOS, Fedora, etc.
- Windows = Windows, Windows Server, etc.
Handlers and Notify
^^^^^^^^^^^^^^^^^^^
The ``notify`` function will run a handler which is typically defined in the ``handlers/main.yml`` file within a role. It will only run if the the state of the module it's tied to changes. By default the handler will listen on a "name" if it is specified. Otherwise, a explicit "listen" directive can be given to multiple handlers. This will allow them all to be executed at once (in the order that they were defined). Handlers cannot have the same name, only the same listen name. This is useful for checking if a configuration file changed and, if it did, then restart the service.
Handlers only execute when a Playbook successfully completes. For executing handlers sooner, refer to the "meta" main module's documentation.
Syntax #1 (Playbook handler):
.. code-block:: yaml
handlers:
- name:
:
listen:
Syntax #2 (Role handler file = handlers/main.yml):
.. code-block:: yaml
- name:
:
listen:
Syntax (Tasks):
.. code-block:: yaml
- :
notify:
-
Example #1 (Playbook handler):
.. code-block:: yaml
handlers:
- name: restart nginx
service:
name: nginx
state: restarted
listen: "restart stack"
- name: restart php-fpm
service:
name: php-fpm
state: restarted
listen: "restart stack"
- name: restart mariadb
service:
name: mariadb
state: restarted
listen: "restart stack"
Example #2 (Role handler file):
.. code-block:: yaml
- name: restart nginx
service:
name: nginx
state: restarted
listen: "restart stack"
- name: restart php-fpm
service:
name: php-fpm
state: restarted
listen: "restart stack"
- name: restart mariadb
service:
name: mariadb
state: restarted
listen: "restart stack"
Example (Tasks):
.. code-block:: yaml
- template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: restart stack
[2]
Meta
^^^^
The meta module handles some aspects of the Ansible Playbooks execution.
All options (free form):
- clear\_facts = Removes all of the gathered facts about the Playbook
hosts.
- clear\_host\_errors = Removes hosts from being in a failed state to
continue running the Playbook.
- end\_play = End the Playbook instantly and mark it as successfully
unless there were any failures.
- flush\_handlers = Any handlers that have been notified will be run.
- noop = Do no operations. This is mainly for Ansible developers and
debugging purposes.
- refresh\_inventory = Reload the inventory files. This is useful when
using dynamic inventory scripts.
- reset\_connection = Closes the current connections to the hosts and
start a new connection.
Syntax:
.. code-block:: yaml
meta:
Example:
.. code-block:: yaml
meta: flush_handlers
[45]
No Log
^^^^^^
The ``no_log`` module can be used to disable logging for a single task or an entire Playbook. This is helpful for not logging sensitive information that may be exposed by one or more tasks. [64]
Task syntax:
.. code-block:: yaml
- :
no_log: True
Playbook syntax:
.. code-block:: yaml
- hosts:
nog_log: True
Example:
.. code-block:: yaml
- name: Authenticating against the API
uri:
method: POST
url: http://example.org/v1/auth
body: "{{ auth_body }}"
register: auth_response
no_log: True
- name: Running a task with the API
uri:
method: POST
url: http://example.org/v1/ip/create
headers:
Token: "{{ auth_response.ansible_facts.token }}"
body: "{{ ip_create_body }}"
no_log: True
Pause
^^^^^
The ``pause`` module is used to temporarily pause an entire Playbook. If
no time argument is specified, the end-user will need to hit ``CTRL+c``
then ``c`` to continue or hit ``CTRL+c`` and then ``a`` to abort the
Playbook.
All options:
- minutes
- prompt = An optional text to display to the end-user.
- seconds
Syntax:
.. code-block:: yaml
pause:
Example:
.. code-block:: yaml
- pause:
minutes: 3
prompt: "The new program needs to finish initializing."
[45]
Roles
^^^^^
A Playbook consists of roles. Each role that needs to be run needs to be
specified in a list. Additional roles can be added within a role
dynamically or statically using "include\_role" or "import\_role." [49]
Syntax:
.. code-block:: yaml
roles:
-
-
Example:
.. code-block:: yaml
roles:
- common
- httpd
- sql
Run Once
^^^^^^^^
In some situations a command should only need to be run on one node. An
example is when using a MariaDB Galera cluster where database changes
will get synced to all nodes.
Syntax:
.. code-block:: yaml
run_once: True
This can also be assigned to a specific host.
Syntax:
.. code-block:: yaml
run_once: True
delegate_to:
[14]
Serial
^^^^^^
By default, Ansible will run all tasks in parallels on all hosts. By setting a number or percentage of hosts, a user can restrict how many hosts must fully complete in a playbook before moving onto the next set of hosts. [14] The ``serial`` keyword can only be used at the playbook level. [83]
Syntax:
.. code-block:: yaml
serial:
Example:
.. code-block:: yaml
- hosts: web
serial: 50%
tasks:
- name: Installing Nginx
package:
name: nginx
state: present
Strategy
^^^^^^^^
By default, a Playbook strategy is set to "linear" meaning that it will
only move onto the next task once it completes on all hosts. This can be
changed to "free" so that once a task completes on a host, that host
will instantly move onto the next available task.
Syntax:
.. code-block:: yaml
strategy: free
Example (site.yml):
.. code-block:: yaml
- hosts: all
strategy: free
roles:
- gitlab
[36]
Tags
^^^^
Each task in a tasks file can have a tag associated to it. This should
be appended to the end of the task. This is useful for debugging and
separating tasks into specific groups. Here is the syntax:
Syntax:
.. code-block:: yaml
tags:
-
-
-
Run only tasks that include specific tags.
.. code-block:: sh
$ ansible-playbook --tags ",,"
Alternatively, skip specific tags.
.. code-block:: sh
$ ansible-playbook --skip-tags ",,"
Example:
.. code-block:: yaml
---
# File: webserver.yaml
- package:
name: nginx
state: latest
tags:
- yum
- rpm
- nginx
.. code-block:: sh
$ ansible-playbook --tags "yum" site.yml webnode1
[8]
Tasks
^^^^^
Playbooks can include specific task files or define and run tasks in the
Playbook file itself. In Ansible 2.0, loops, variables, and other
dynamic elements now work correctly.
Syntax:
.. code-block:: yaml
- hosts:
tasks:
- :
Example:
.. code-block:: yaml
- hosts: jenkins
tasks:
- debug:
msg: "Warning: This will modify ALL Jenkins servers."
roles:
- common
- docker
[45]
Wait For
^^^^^^^^
A condition can be searched for before continuing on to the next task.
Syntax:
.. code-block:: yaml
wait_for:
Example:
.. code-block:: yaml
wait_for:
timeout: 60
delegate_to: localhost
Common options:
- delay = How long to wait (in seconds) before running the wait\_for
check.
- path = A file to check.
- host = A host to check a connection to.
- port = A port to check on the specified host.
- connect\_timeout = How long to wait (in seconds) before retrying the
connection.
- search\_regex = A regular expression string to match from either a
port or file.
- state
- started = Check for a open port.
- stopped = Check for a closed port.
- drained = Check for active connections to the port.
- present = Check for a file.
- absent = Verify a file does not exist.
- timeout = How long to wait (in seconds) before continuing on.
[45]
When
^^^^
The "when" function can be used to specify that a sub-task should only
run if the condition returns turn. This is similar to an "if" statement
in programming languages. It is usually the last line to a sub-task. [11]
"When" Example:
.. code-block:: yaml
- package:
name: httpd
state: latest
when: ansible_os_family == "CentOS"
"Or" example:
.. code-block:: yaml
when: (ansible_os_family == "CentOS") or (ansible_os_family == "Debian")
"And" example:
.. code-block:: yaml
when: (ansible_os_family == "Fedora") and
(ansible_distribution_major_version == "26")
Errors
^^^^^^
These modules handle Playbook errors.
Any Errors Fatal
''''''''''''''''
By default, a Playbook will continue to run on all of the hosts that do
not have any failures reported by modules. It is possible to stop the
Playbook from running on all hosts once an error has occurred. [12]
Syntax:
.. code-block:: yaml
any_errors_fatal: True
Example:
.. code-block:: yaml
- hosts: nfs_servers
any_errors_fatal: True
roles:
- nfs
Fail
''''
The simple ``fail`` module will make a Playbook fail. This is useful
when checking if a certain condition has to exist to continue on.
All options:
- msg = An optional message to provide the end-user.
Syntax:
.. code-block:: yaml
fail:
Example:
.. code-block:: yaml
- fail:
msg: "Unexpected return code."
when: (command_variable.rc != 0) or (command_variable.rc != 900)
[45]
Failed When
'''''''''''
In some situations, a error from a command or module may not be reported
properly. This module can be used to force a failure based on a certain
condition. [12]
Syntax:
.. code-block:: yaml
failed_when:
Example:
.. code-block:: yaml
- command: echo "Testing a failure. 123."
register: cmd
failed_when: "'123' in cmd.stdout"
Ignore Errors
'''''''''''''
Playbooks, by default, will stop running on a host if it fails to run a
module. Sometimes a module will report a false-positive or an error will
be expected. This will allow the Playbook to continue onto the next
step. [12]
Syntax:
.. code-block:: yaml
ignore_errors: yes
Example:
.. code-block:: sh
- name: Even though this will fail, the Playbook will keep running.
package:
name: does-not-exist
state: present
ignore_errors: yes
Includes
^^^^^^^^
Include and import modules allow other elements of a Playbook to be
called and executed.
Import Playbook
'''''''''''''''
The proper way to use other Playbooks in a Playbook is to use the
``import_playbook``. Before Ansible 2.4 this was handled via the
``include`` module. There is also no ``include_playbook`` module, only
``import_playbook``.
Syntax:
.. code-block:: yaml
---
- import_playbook:
Example:
.. code-block:: yaml
---
- import_playbook: nginx.yml
- import_playbook: phpfpm.yml
- import_playbook: mariadb.yml
[49][58]
Import and Include Role
'''''''''''''''''''''''
The ``import_role`` is a static inclusion of a role that cannot be used
in loops. This is loaded on runtime of the Playbook
The ``include_role`` is a dynamic inclusion of a role that can be used
in loops. Tags will not automatically be shown with the ``--list-tags``
Ansible Playbook argument. This can be loaded dynamically based on
conditions. [49][58]
All options:
- allow\_duplicates = Allow a role to be used more than once. Default:
True.
- defaults\_from = A default variable file to load from the role's
"default" directory.
- **name** = The name of the role to import.
- private = All of the "default" an "vars" variables in the role are
private and not accessible via the rest of the Playbook.
- tasks\_from = A task file to load from the role's "tasks" directory.
- vars\_from = A variables file to load from the role's "vars"
directory.
Syntax:
.. code-block:: yaml
- import_role:
.. code-block:: yaml
- include_role:
Examples:
.. code-block:: yaml
- name: Run only the install.yml task from the openshift role
import_role:
name: openshift
tasks_from: install
.. code-block:: yaml
- name: Run the Nagios role
include_role:
name: nagios
vars:
listen_port: 8080
[45]
In Ansible 2.7, the ``apply`` argument was added to both the ``include_role`` and ``include_tasks`` modules. This allows the end-user to apply the same type of keyword attributes that a normal ``role`` can accept. These include become arguments, delegation, ignore_errors, tags, and more. The full list of allowed keywords for roles can be found `here `__.
Example:
.. code-block:: yaml
- name: Install Nova
include_role:
name: nova
apply:
delegate_to: "{{ compute_nodes }}"
tags:
- compute
[79]
Import and Include Tasks
''''''''''''''''''''''''
Use the ``import_tasks`` to statically include tasks at a Playbook's
runtime or ``include_tasks`` to dynamically run tasks once the Playbook
gets to it.
Syntax:
.. code-block:: yaml
- import_tasks: .yml
.. code-block:: yaml
- include_tasks: .yml
vars:
:
:
:
.. code-block:: yaml
- include_tasks:
file: .yml
vars:
:
:
:
apply:
[49]
Include
'''''''
**Deprecated in: 2.4 Replaced by: include\_tasks, import\_plays,
import\_tasks**
Other task files and Playbooks can be included. The functions in them
will immediately run. Variables can be defined for the inclusion as
well. [49]
Syntax:
.. code-block:: yaml
include:
.. code-block:: yaml
include: .yml = =
Example:
.. code-block:: yaml
include: wine.yml wine_version=1.8.0 compression_format=xz download_util=wget
[45]
Include Variables
'''''''''''''''''
Additional variables can be defined within a Playbook file. These can be
openly added to the ``include_vars`` module via YAML syntax.
Common options:
- file = Specify a filename to source variables from.
- name = Store variables from a file into a specified variable.
Syntax:
.. code-block:: yaml
include_vars:
Examples:
.. code-block:: yaml
- hosts: all
include_vars:
- gateway: "192.168.0.1"
- netmask: "255.255.255.0"
roles:
- addressing
.. code-block:: yaml
- hosts: all
include_vars:
file: monitor_vars.yml
roles:
- nagios
[45]
Loops
^^^^^
Loops can be used to iterate through lists and/or dictionaries. All ``with_`` loops from Ansible <= 2.4 have been replaced by the ``loop`` keyword in Ansible 2.5. The older loops are currently planned to be removed in the Ansible 2.9 release. Jinja filters are now required to explicitly be defined for creating a customized list of data to loop through. Use `this migration guide `__ for examples on how to use the logic of old ``with_`` loops using the new syntax. Package modules in Ansible >= 2.7 support passing a list variable as an argument value.
Ansible >= 2.5 loops:
- `Loop `__
- `Until `__
Loop
''''
Ansible 2.5 introduced a simpler keyword for loops called ``loop`` instead of the more complex name ``with_items``. This new loop directly replaces ``with_list`` and is used in substitution of all of the older ``with_`` prefixed loops. This change was to put emphasis on the end-user to do the parsing of variables with Jinja filters and lookups such as how Ansible <= 2.4 handles it in the back-end. This helps to make the code more understandable.
Syntax:
.. code-block:: yaml
loop: "{{ LIST_VARIABLE }}"
.. code-block:: yaml
loop:
- "{{ }}"
- "{{ }}"
View the available Ansible Jinja lookups [62]:
.. code-block:: sh
$ ansible-doc -t lookup -l
$ ansible-doc -t lookup
Ansible provides a special Jinja ``lookup`` wrapper called ``query`` that will return lists instead of a comma separated string.
Query syntax:
::
{{ query('', '') }}
::
{{ query('', ['', '']) }}
Loop Control
''''''''''''
Loops can be configured to behave differently for more control over how it is used.
Options:
- index_var = The variable name for the current index that the loop is iterating on.
- label = Only use a specific key from a dictionary when the entire dictionary is not required to be processed.
- loop_var = The variable name for the current item in the loop. This is useful for nested loops. Default: ``item``.
- pause = The number of seconds to pause before moving onto the next item.
Example:
.. code-block:: yaml
- name: Debug the API messages and loop index
debug:
msg: "{{ current.message }}. Current index: {{ index }}"
verbosity: 1
loop:
- message: Hello world
settings:
api: v3
url: https://example.tld/
- message: Goodbye world
settings:
api: v2.1
url: https://example.tld/
loop_control:
index_var: index
label: "{{ current.message }}"
loop_var: current
pause: 5
[10]
Until Loops
'''''''''''
Do-Until loops can be used to continually run a check and verify it's completion.
- **until** = The logic of the ``until`` loop. The typical use case is to check the output of a registered variable or do a Jinja lookup. When the condition is not met, the module runs again. When the condition is met, the module finishes and moves onto the next task.
- retries = The number of times to retry the loop until marking the task as failed. Default: 3.
- delay = The delay, in seconds, before starting the next retry. Default: 5.
Example:
.. code-block:: yaml
- name: Generate random numbers until 5 is found
shell: echo $(($RANDOM % 10 + 1))
register: random_number
until: '"5" in random_number.stdout'
retries: 30
delay: 1
The registered variable will have a special "attempts" key that will contain the number of retries that the ``until`` loop went through.
[10]
Variables
^^^^^^^^^
These are modules relating to defining new variables.
Vars Prompt
'''''''''''
A prompt can be used to assign a user's standard input as a variable. [9] Note
that this module is not compatible with Ansible Tower and that a Survey
should be created within Tower instead. [38]
Common options:
- confirm = Prompt the user twice and then verify that the input is the
same.
- encrypt = Encrypt the text.
- md5\_crypt
- sha256\_crypt
- sha512\_crypt
- salt = Specify a string to use as a salt for encrypting.
- salt\_size = Specify the length to use for a randomly generated salt.
The default is 8.
Syntax:
.. code-block:: yaml
vars_prompt:
- name: ""
prompt: ""
Examples:
.. code-block:: yaml
vars_prompt:
- name: "zipcode"
prompt: "Enter your zipcode."
.. code-block:: yaml
vars_prompt:
- name: "pw"
prompt: "Password:"
encrypt: "sha512_crypt"
salt_size: 12
[9]
Register
''''''''
The output of modules and commands can be saved to a variable.
Variable return values [30]:
- backup\_file = String. If a module creates a backup file, this is
that file's name.
- changed = Boolean. If something was changed after the module runs,
this would be set to "True."
- failed = Boolean. Shows if the module failed.
- invocation = Dictionary. This describes the module used to run the
operation as well as all of the arguments.
- msg = String. A message that is optionally given to the end-user.
- rc = Integer. The return code of a command, shell, or similar module.
- stderr = String. The standard error of the command.
- stderr\_lines = List. The standard output of the command is separated
by the newline characters into a list.
- stdout = String. The standard output of the command.
- stdout\_lines = List.
- results = List of dictionaries. If a loop was used, the results for
each loop are stored as a new list item.
- skipped = Boolean. If this module was skipped or not.
Syntax:
.. code-block:: yaml
register:
Examples:
.. code-block:: yaml
- command: echo Hello World
register: hello
- debug:
msg: "We heard you"
when: "'Hello World' in hello.stdout"
.. code-block:: yaml
- copy:
src: example.conf
dest: /etc/example.conf
register: copy_example
- debug:
msg: "Copying example.conf failed."
when: copy_example|failed
[12]
Set Fact
''''''''
New variables can be defined set the "set\_fact" module. These are added
to the available variables/facts tied to a inventory host. [45]
Syntax:
.. code-block:: yaml
set_fact:
:
:
Example:
.. code-block:: yaml
- set_fact:
is_installed: True
sql_server: mariadb
UNIX Modules
~~~~~~~~~~~~
Authorized Key
^^^^^^^^^^^^^^
The ``authorized_key`` module will add a public SSH key to the specified user's ``~/.ssh/authorized_keys`` file. [55]
.. code-block:: yaml
- name: Configure SSH key access
authorized_key:
user: foo
key: "{{ ssh_public_key }}"
Command and Shell
^^^^^^^^^^^^^^^^^
Both the command and shell modules provide the ability to run command
line programs. The big difference is that shell provides a full shell
environment where operand redirection and pipping works, along with
loading up all of the shell variables. Conversely, command will not load
a full shell environment so it will lack in features and functionality
but it makes up for that by being faster and more efficient. [6]
Syntax:
.. code-block:: yaml
command:
.. code-block:: yaml
shell:
Common options:
- executable = Set the executable shell binary.
- chdir = Change directories before running the command.
Example:
.. code-block:: yaml
- shell: echo "Hello world" >> /tmp/hello_world.txt
args:
executable: /bin/bash
Copy, File, Synchronize, and Template
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The ``copy``, ``file``, ``synchronize``, and ``template`` modules provide ways for creating and modifying various files. The ``file`` module is used to handle file creation/modification on the remote host. ``template``\ s are to be used when a file contains variables that will be rendered out by Jinja2. ``copy`` is used for copying files from the Ansible control node or on the managed host. ``synchronize`` is used as a wrapper around rsync to provide a more robust copy functionality. This module is the only module that can recursive copy a directory and all of it's contents on a remote host to another folder on that same host. Most of the options and usage are the same between these four modules.
Syntax:
.. code-block:: yaml
copy:
.. code-block:: yaml
file:
.. code-block:: yaml
synchronize:
.. code-block:: yaml
template:
Common options:
- src = Define the source file or template. If a full path is not
given, Ansible will check in the roles/\ ````/files/
directory for a file or roles/\ ````/templates/ for a
template. If the src path ends with a "/" then only the files within
that directory will be copied (not the directory itself).
- dest (or path) = This is the full path to where the file should be
copied to on the destination server.
- owner = Set the user owner.
- group = Set the group owner.
- setype = Set SELinux file permissions.
Copy, file, and template options:
- mode = Set the octal or symbolic permissions. If using octal, it has
to be four digits. The first digit is generally the flag "0" to
indicate no special permissions.
Copy options:
- content = Instead of providing a ``src`` file to copy, write the ``contents`` string to the file.
- remote\_src = If set to ``True``, the source file will be found on the server Ansible is running tasks on (not the local machine). The default is ``false``.
File options:
- state = Specify the state the file should be created in.
- file = Copy the file.
- link = Create a soft link shortcut.
- hard = Create a hard link reference.
- touch = Create an empty file.
- directory = Create all subdirectories in the destination folder.
- absent = Delete destination folders.
Synchronize options:
- archive = Preserve all of the original file permissions. The default
is ``yes``.
- delete = Remove files in the destination directory that do not exist
in the source directory.
- mode
- push = Default. Copy files from the source to the destination
directory.
- pull = Copy files from the destination to the source directory.
- recursive = Recursively copy contents of all sub-directories. The
default is ``no``.
- rsync\_opts = Provide additional ``rsync`` command line arguments.
Synchronize example:
.. code-block:: yaml
- name: Copying the contents from one directory to another on the managed host only
synchronize:
src: /path/to/src/
dest: /path/to/dest/
delegate_to: "{{ inventory_hostname }}"
Template example:
.. code-block:: yaml
- name: Copying a template from the role's "templates" directory to the managed hosts
template:
src: example.conf.j2
dest: /etc/example/example.conf
mode: 0644
owner: root
group: nobody
[46]
Cron
^^^^
The cron module is used to manage crontab entries. Crons are
scheduled/automated tasks that run on Unix-like systems.
Syntax:
.. code-block:: yaml
cron:
Common options:
- user = Modify the specified user's crontab.
- job = Provide a command to run when the cron reaches the correct
- minute
- hour
- weekday = Specify the weekday as a number 0 through 6 where 0 is
Sunday and 6 is Saturday.
- month
- day = Specify the day number in the 30 day month.
- backup = Backup the existing crontab. The "backup\_file" variable
provides the backed up file name.
- yes
- no
- state
- present = add the crontab
- absent = remove an existing entry
- special\_time
- reboot
- yearly or annually
- monthly
- weekly
- daily
- hourly
Example #1:
.. code-block:: yaml
cron:
job: "/usr/bin/wall This actually works"
minute: "*/1"
user: redhat
Example #2:
.. code-block:: yaml
cron:
job: "/usr/bin/yum -y update"
weekday: 0
hour: 6
backup: yes
[55]
Expect
^^^^^^
The ``expect`` module executes a command, searches for a regular
expression pattern and, if found, it will provide standard input back to
the command.
All options:
- chdir = Change into a different directory before running the command.
- **command** = The command to execute.
- creates = A path to a file which should be created after the command
executes properly.
- echo = Show the response strings that were used.
- removes = A path to a file which should not exist after the command
executes properly.
- **responses** = A dictionary of patterns to search for and responses
that they should provide back.
- timeout = The time, in seconds, to wait for finding the pattern.
Syntax:
.. code-block:: yaml
expect:
command:
responses:
:
Example:
.. code-block:: yaml
- name: Find all of the available fruit
expect:
command: mysql -u dave -p -e 'SELECT fruit_name FROM food.fruits;'
responses:
password: "{{ mysql_pass_dave }}"
[6]
Get URL
^^^^^^^
The ``get_url`` module is used to download files from online.
Common options:
- backup = Backup the destination file if it already exists. Default:
no.
- checksum = Specify a checksum method to use and the hash that is
expected.
- **dest** = Where the downloaded file should be saved to
- timeout = The time, in seconds, to wait for a connection to the URL
before failing. Default: 10.
- {group\|mode\|owner} = Specify the permissions for the downloaded
file.
- **url** = The URL to download.
-
- use\_proxy = Use the proxy settings from the environment
variables. Default: yes.
- validate\_certs = Validate SSL certificates. Default: yes.
Syntax:
.. code-block:: yaml
get_url:
Example:
.. code-block:: yaml
- name: Downloading a configuration file
get_url:
url: https://internal.domain.tld/configs/nginx/nginx.conf
dest: /etc/nginx/nginx.conf
owner: nginx
group: nginx
mode: 0644
validate_certs: no
[54]
Git
^^^
Git is a utility used for provisioning and versioning software. Ansible
has built-in support for handling most Git-related tasks.
Syntax:
.. code-block:: yaml
git:
Common options:
- repo = The full path of the repository.
- dest = The path to place/use the repository
- update = Pull the latest version from the Git server. The default is
"yes."
- version = Switch to a different branch or tag.
- ssh\_opts = If using SSH, specify custom SSH options.
- force = Override local changes. The default is "yes."
[7]
Service
^^^^^^^
The service module is used to handle system services.
Syntax:
.. code-block:: yaml
service:
Common options:
- name = Specify the service name.
- enabled = Enable the service to start on boot or not. Valid options
are "yes" or "no."
- sleep = When restarted a service, specify the amount of time (in
seconds) to wait before starting a service after stopping it.
- state = Specify what state the service should be in.
- started = Start the service.
- stopped = Stop the service.
- restarted = Stop and then start the service.
- reloaded = If supported by the service, it will reload it's
configuration file without restarting it's main thread. [55]
Example:
- Restart the Apache service "httpd."
.. code-block:: yaml
- name: Restarting the Apache service and waiting 3 seconds for it to fully start
service:
name: httpd
state: restarted
sleep: 3
MySQL Database and User
^^^^^^^^^^^^^^^^^^^^^^^
MySQL databases and users can be managed via Ansible. It requires the
"MySQLdb" Python library and the "mysql" and "mysqldump" binaries.
MySQL database syntax:
.. code-block:: yaml
mysql_db:
MySQL user syntax:
.. code-block:: yaml
mysql_user:
Options:
- name = Specify the database name. The word "all" can be used to
control all databases.
- state
- present = Create the database.
- absent = Delete the database.
- dump = Backup the database.
- import = Import a database.
- target = Specify a dump or import location.
- config\_file = Specify the user configuration file. Default:
"~/.my.cnf." Alternatively, login credentials can be manually
specified.
- login\_host = The MySQL server's IP or hostname. Default:
"localhost."
- login\_user = The MySQL username to login as.
- login\_password = The MySQL user's password.
- login\_port = The MySQL port to connect to. Default: "3306."
- login\_unix\_socket = On Unix, a socket file can be used to connect
to MySQL instead of a host and port.
- connection\_timeout = How long to wait (in seconds) before closing
the MySQL connection. The default is "30." [16]
- priv (mysql\_user) = The privileges for the MySQL user. [17]
Example #1:
.. code-block:: yaml
mysql_db:
name: toorsdb
state: present
config_file: /secrets/.my.cnf
Example #2:
.. code-block:: yaml
mysql_user:
name: toor
login_user: root
login_password: "{{ vault_encrypted_password }}"
priv: "somedb.*:ALL"
state: present
Example #3:
.. code-block:: yaml
mysql_user:
name: maxscale
host: "10.0.0.%"
priv: "*.*:REPLICATION CLIENT,SELECT"
password: "{{ maxscale_vault_encrypted_password }}"
state: present
Raw
^^^
The ``raw`` module runs commands directly through SSH. Unlike the ``shell`` module, Ansible does not have any Python wrappers around this. This makes it possible to run commands on remote systems that do not have Python installed. [6]
Options:
- executable = The absolute path to an executable shell.
Syntax:
.. code-block:: yaml
raw:
Example:
.. code-block:: yaml
raw: echo "Hello world!"
Stat
^^^^
This module provides detailed information about a file, directory, or
link. It was designed to be similar to the Unix command ``stat``. All
the information from this module can be saved to a variable and accessed
as a from new ``.stat`` dictionary.
Syntax:
.. code-block:: yaml
stat:
path:
register:
Example:
.. code-block:: yaml
- stat:
path: /root/.ssh/id_rsa
register: id_rsa
- file:
path: /root/.ssh/id_rsa
mode: 0600
owner: root
group: root
when: id_rsa.stat.mode is not "0600"
Common options:
- checksum\_algorithm = The algorithm to use for finding the checksum.
- sha1 (Default)
- sha224
- sha256
- sha384
- sha512
- follow = Follow symbolic links.
- get\_checksum = If the SHA checksum should be generated.
- get\_md5 = Boolean. If the MD5 checksum should be generated.
- path = Required. String. The full path to the file.
``stat`` dictionary values:
- {a\|c\|m}time = Float. The last time the file was either accessed,
the metadata was created, or modified.
- attributes = List. All of the file attributes.
- charset = String. The text file encoding format.
- checksum = String. The has of the path.
- dev = Integer. The device the inode exists on.
- {executable\|readable\|writable} = Boolean. If the file is
executable, readable, or writable by the remote user that Ansible is
running as.
- exists = Boolean. If the file exists or not.
- {gr\|pw}\_name = String. The name of the group or user owner.
- isblk = Boolean. If the file is a block device.
- ischr = Boolean. If the file is a character device for standard input
or output.
- isdir = Boolean. If the file is a directory.
- isfifo = Boolean. If the file is a named pipe.
- islink = Boolean. If the file is a symbolic link.
- inode = Integer. The Unix inode number of the file.
- isreg = Boolean. If the file is a regular file.
- issock. Boolean. If the file is a Unix socket.
- is{uid\|gid} = Boolean. If the file is owned by the user or group
that the remote Ansible user is running as.
- lnk\_source = String. The original path of the symbolic link.
- md5 = String. The MD5 hash of the file.
- mime\_type = The "magic data" that specifies the file type.
- mode = Octal Unix file permissions.
- nlink. Integer. The number of links that are used to redirect to the
original inode.
- path = String. The full path to the file.
- {r\|w\|x}usr = Boolean. If the user owner has readable, writable, or
executable permissions.
- {r\|w\|x}grp = Boolean. If the group owner has readable, writable,
or executable permissions.
- {r\|w\|x}oth = Boolean. If other users have readable, writable, or
executable permissions.
- size = Integer. The size, in bytes, of the file.
- {uid\|gid} = Integer. The ID of user or group owner of the file.
[46]
URI
^^^
The ``uri`` module is used for handling HTTP requests.
Common options:
- HEADER\_\* = Modify different types of header content.
- body = The body of the request to send.
- body\_format = The format to uses for the body. Default: raw.
- json
- raw
- dest = A path to where a file should be downloaded to.
- follow\_redirects = Default: safe.
- all = Follow all redirects.
- none = Do not follow any redirects.
- safe = Follow the first redirect only.
- method = The HTTP method type to use. Default: GET.
- CONNECT
- DELETE
- GET
- HEAD
- OPTIONS
- PATCH
- POST
- PUT
- REFRESH
- TRACE
- password = The password to use for basic HTTP authentication.
- status\_code = The expected status code from the request. Default:
200.
- timeout = When a connection to a URL should time out if it's
unreachable.
- **url** = The HTTP URL to connect to.
- user = The username to use for basic HTTP authentication.
Syntax:
.. code-block:: yaml
uri:
Example:
.. code-block:: yaml
- name: Authenticate with OpenStack's Keystone v3 service
uri:
HEADER_Content-Type="application/json"
body_format: json
body: >
{
"auth": {
"identity": {
"methods": [
"password"
],
"password": {
"user": {
"domain": {
"name": "Default"
},
"name": "admin",
"password": "{{ admin_pass }}"
}
}
},
"scope": {
"project": {
"domain": {
"name": "Default"
},
"name": "demo"
}
}
}
}
method: POST
url: https://openstack.tld:5000/v3/auth/tokens
register: os_token_request
[54]
Package Managers
^^^^^^^^^^^^^^^^
Ansible has the ability to add, remove, or update software packages.
Almost every popular package manager is supported. This can
generically be handled by the "package" module or the specific module
for the operating system's package manager.
In Ansible >= 2.7, package modules can accept a list for the "name" argument. This avoids the need to use a loop. [73]
Syntax:
.. code-block:: yaml
package:
Common options:
- name = Specify the package name.
- state = Specify how to change the package state.
- present = Install the package.
- latest = Update the package (or install, if necessary).
- absent = Uninstall the package.
- use = Specify the package manager to use.
- auto = Automatically detect the package manager to use. This is the
default.
- apt = Use Debian's Apt package manager.
- yum = Use Red Hat's yum package manager.
Example:
.. code-block:: yaml
- name: Updating MariaDB
package:
name: mariadb
state: latest
[47]
Apt
'''
Apt is used to install and manage packages on Debian based operating
systems.
Common options:
- name = The package name.
- state
- present = Install the package.
- latest = Update the package.
- absent = Uninstall the package.
- build-dep = Install the build dependencies for the source code.
- update\_cache = Update the Apt cache (apt-get update). Default: no.
- deb = Install a specified \*.deb file.
- autoremove = Remove all dependencies that are no longer required.
- purge = Delete configuration files.
- install\_recommends = Install recommended packages.
- upgrade
- no = Do not upgrade any system packages (default).
- yes = Update all of the system packages (apt-get upgrade).
- full = Update all of the system packages and uninstall older,
conflicting packages (apt-get full-upgrade).
- dist = Upgrade the operating system (apt-get dist-upgrade).
[47]
Yum
'''
There are two commands to primarily handle Red Hat's Yum package
manager: "yum" and "yum\_repository."
Syntax:
.. code-block:: yaml
yum:
Common options:
- name = Specify the package name.
- state = Specify the package state.
- {present\|installed\|latest} = Any of these will install the package.
- {absent\|removed} = Any of these will uninstall the package.
- enablerepo = Temporarily enable a repository.
- disablerepo = Temporarily disable a repository.
- disable\_gpg\_check = Disable the GPG check. The default is "no".
- conf\_file = Specify a Yum configuration file to use.
Example:
.. code-block:: yaml
- name: Installing Ansible from EPEL and disabling GPG check as an example
yum:
name: ansible
state: installed
enablerepo: epel
disable_gpg_check: yes
Yum repository syntax:
.. code-block:: yaml
yum_repository:
Common options:
- baseurl = Provide the URL of the repository.
- **description** = Required if ``state=present``. Provide a
description of the repository.
- enabled = Enable the repository permanently to be active. The default
is "yes."
- exclude = List packages that should be excluded from being accessed
from this repository.
- gpgcheck = Validate the RPMs with a GPG check. The default is "no."
- gpgkey = Specify a URL to the GPG key.
- includepkgs = A space separated list of packages that can be used
from this repository. This is an explicit allow list.
- mirrorlist = Provide a URL to a mirrorlist repository instead of the
baseurl.
- **name** = Required. Specify a name for the repository. This is only
required if the file is being created (state=present) or deleted
(state=absent).
- reposdir = The directory to store the Yum configuration files.
Default: ``/etc/yum.repos.d/``.
- state = Specify a state for the repository file.
- present = Install the Yum repository file. This is the default.
- absent = Delete the repository file.
Example:
.. code-block:: yaml
- name: Adding the RepoForge repository to /etc/yum.repos.d/
yum_repository:
name: repoforge
baseurl: http://apt.sw.be/redhat/el7/en/x86_64/rpmforge/
enabled: no
description: "Third-party RepoForge packages (previously RPMForge)"
[47]
Windows Modules
~~~~~~~~~~~~~~~
These modules are specific to managing Windows servers and are not
related to the normal modules designed for UNIX-like operating systems.
These module names start with the "win\_" prefix.
Command and Shell
^^^^^^^^^^^^^^^^^
Windows commands can be executed via a console. The ``command`` module
uses the DOS "cmd" binary and shell, by default, uses PowerShell.
All similar ``command`` and ``shell`` options:
- chdir = Change the current working directory on the remote server
before executing a command.
- creates = A path (optionally with a regular expression pattern) to a
file. If this file already exists, this module will be marked as
"skipped."
- removes = If a path does not exist then this module will be marked as
"skipped."
``shell`` options:
- executable = The binary to use for executing commands. By default
this is PowerShell. Use "cmd" for running DOS commands.
Syntax:
.. code-block:: yaml
win_command:
.. code-block:: yaml
win_shell
Example:
::
win_shell: "echo Hello World > c:\hello.txt"
chdir: "c:\"
creates: "c:\hello.txt"
[48]
File Management
^^^^^^^^^^^^^^^
Copy
''''
Copy files from the Playbook to the remote server.
All options:
- content = Instead of using ``src``, specify the text that should
exist in the destination file.
- **dest** = The destination to copy the file to.
- force = Replace files in the destination path if there is a conflict.
Default: True.
- remote\_src = Copy a file from one location on the remote server to
another on the same server.
- **src** = The source file to copy.
Syntax:
.. code-block:: yaml
win_copy:
Example:
.. code-block:: yaml
- name: Copying a configuration file
win_copy:
src: C:\Windows\example.conf
dest: C:\temp\
remote_src: True
[48]
File
''''
All options:
- **path** = The full path to the file on the remote server that should
be created, removed, and/or checked.
- state
- absent = Delete the file.
- directory = Create a directory.
- file = Check to see if a file exists. Do not create a file if it
does not exist.
- touch = Create a file if it does not exist.
Syntax:
.. code-block:: yaml
win_file:
Example:
.. code-block:: yaml
- win_file:
path: C:\Users\admin\runtime_files
state: directory
[48]
Robocopy
''''''''
Robocopy is a CLI utility, available on the latest versions of Windows,
for synchronizing directories.
All options:
- **dest** = The destination directory.
- flags = Provide additional arguments to the robocopy command.
- purge = Delete files in the destination that do not exist in the
source directory.
- recurse = Recursively copy subdirectories.
- **src** = The source directory to copy from.
Syntax:
.. code-block:: yaml
win_robocopy:
Example:
.. code-block:: yaml
win_robocopy:
src: C:\tmp\
dest: C:\tmp_old\
recurse: True
[48]
Shortcut
''''''''
Manage Windows shortcuts.
All options:
- args = Arguments to provide to the source executable.
- description = A description about the shortcut.
- **dest** = The path and file name of the shortcut. For executables
use the extension ``.lnk`` and for URLs use ``.url``.
- directory = The work directory for the executable.
- hotkey = The combination of keys to virtually press when the shortcut
is executed.
- icon = A ``.ico`` icon file to use as the shortcut image.
- src = The executable or URL that the shortcut should open.
- state
- absent = Delete the shortcut.
- present = Create the shortcut.
- windowstyle = How the program's window is sized during launch.
- default
- maximized
- minimized
Syntax:
.. code-block:: yaml
win_shortcut:
Example:
.. code-block:: yaml
win_shortcut:
src: C:\Program Files (x86)\game\game.exe
dest: C:\Users\Ben\Desktop\game.lnk
[48]
Template
''''''''
The Windows Jinja2 template module uses the same options as the normal
``template`` module.
Syntax:
.. code-block:: yaml
win_template:
[48]
Installations
^^^^^^^^^^^^^
Chocolatey
''''''''''
Chocolatey is an unofficial package manager for Windows. Packages can be
installed from a public or private Chocolatey repository.
Common options:
- force = Reinstall an existing package.
- install\_args = Arguments to pass to Chocolatey during installation.
- ignore\_dependencies = Ignore dependencies of a package. Default: no.
- **name** = The name of a package to manage.
- source = The Chocolatey repository to use.
- state = Default: present.
- absent = Uninstall the package.
- present = Install the package.
- latest = Update the package.
- timeout = The number of seconds to wait for Chocolatey to complete
it's action. Default: 2700.
- version = The exact version of a package that should be installed.
Syntax:
.. code-block:: yaml
win_chocolatey:
Example:
.. code-block:: yaml
win_chocolatey:
name: "libreoffice-fresh"
state: "upgrade"
version: "6.0.3"
[48]
Feature
'''''''
Manage official features and roles in Windows.
All options:
- include\_management\_tools = Install related management tools. This
only works in Windows Server >= 2012.
- include\_sub\_features = Install all subfeatures related to the main
feature.
- **name** = The name of the feature or role.
- restart = Restart the server after installation.
- source = The path to the local package of the feature. This only
works in Windows Server >= 2012.
- state
- absent = Uninstall the feature.
- present = Install the feature.
Syntax:
.. code-block:: yaml
win_feature:
Example:
.. code-block:: yaml
- name: Install the IIS HTTP web server
win_feature:
name: Web-Server
state: present
[48]
On Windows, all of the available features can be found via PowerShell.
.. code-block:: sh
> Get-WindowsFeature
If part of the name is known, a PowerShell wildcard can be used to
narrow it down.
.. code-block:: sh
> Get-WindowsFeature -Name *
[37]
MSI
'''
**Deprecated in: 2.3 Replaced by: ``win_package``**
The MSI module is used to install executable packages. [48]
Package
'''''''
Manage official Microsoft packages for Windows. Examples of these
include the .NET Framework, Remote Desktop Connection Manager, Visual
C++ Redistributable, and more.
All options:
- arguments = Arguments will be passed to the package during
installation.
- expected\_return\_code = The return code number that is expected
after the installation is complete. Default: 0.
- name = Optionally provide a friendly name for the package for Ansible
logging purposes.
- **path** = The file path or HTTP URL to a package.
- **product\_id** = For verifying installation, the product ID is
required to lookup in the registry if it is installed already.
- Note: This can be found at:
- 64-bit:
``HKLM:Software\Microsoft\Windows\CurrentVersion\Uninstall``
- 32-bit:
``HKLM:Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall``
- state
- absent = Uninstall the package.
- present = Install the package.
- user\_{name\|password} = Specify the username and password to access
a SMB/CIFS share that contains the package.
Syntax:
.. code-block:: yaml
win_package:
Example:
.. code-block:: yaml
- name: 'Microsoft .NET Framework 4.5.1'
win_package:
path: https://download.microsoft.com/download/1/6/7/167F0D79-9317-48AE-AEDB-17120579F8E2/NDP451-KB2858728-x86-x64-AllOS-ENU.exe
productid: '{7DEBE4EB-6B40-3766-BB35-5CBBC385DA37}'
arguments: '/q /norestart'
ensure: present
# Return code "3010" means that Windows requires a reboot
expected_return_code: 3010
[48]
Updates
'''''''
Windows Updates can be managed by Ansible.
All options:
- category\_names = A list of categories to manage updates for. Valid
categories are:
- Application
- Connectors
- CriticalUpdates (default)
- DefinitionUpdates
- DeveloperKits
- FeaturePacks
- Guidance
- SecurityUpdates (default)
- ServicePacks
- Tools
- UpdateRollups (default)
- Updates
- log\_path = The path to a custom log file.
- state
- installed = Search for and install updates.
- searched = Only search for updates.
Syntax:
.. code-block:: yaml
win_updates:
Example:
::
- name: Installing only the critical Windows updates
win_updates:
category_names:
- CriticalUpdates
state: searched
log_path: "c:\tmp\win_updates_log.txt"
[48]
Registry
^^^^^^^^
The registry can be viewed and edited using the
`win\_regedit `__
and
`win\_reg\_stat `__
modules.
Scheduled Task
^^^^^^^^^^^^^^
Manage scheduled tasks in Windows.
All options:
- arguments = Arguments that should be supplied to the executable.
- days\_of\_week = A list of weekdays to run the task.
- description = A useful description for the purpose of the task.
- enabled = Set the task to be enabled or not.
- executable = The command the task should run.
- frequency = The frequency to run the command.
- once
- daily
- weekly
- **name** = The name of the task.
- path = The folder to store the task in.
- **state**
- absent = Delete the task.
- present = Create the task.
- time = The time to run the task.
- user = The user to run the task as.
Syntax:
.. code-block:: yaml
win_scheduled_task:
Example:
.. code-block:: yaml
win_scheduled_task:
name: RestartIIS
executable: iisreset
arguments: /restart
days_of_week: saturday
time: 2am
[48]
Service
^^^^^^^
Manage services on Windows.
All options:
- dependencies = A list of other services that are dependencies for
this service.
- dependency\_action
- add = Append these dependencies to the existing dependencies.
- set = Set this list of dependencies as the only dependencies.
- remove = Remove these dependencies from the service.
- description = A useful description of the service.
- desktop\_interact = Allow the LocalSystem user to interact with the
Windows desktop.
- display\_name = A user-friendly name for the service.
- force\_dependent\_services = Changing the state of this service will
change the state of all of the dependencies.
- **name** = The actual name of the service.
- password = The password to authenticate with. For the LocalService,
LocalSystem, and NetworkService users, the password has to be an
empty string and not undefined.
- path = The path to the executable for the service.
- start\_mode
- auto = Automatically start on boot.
- delayed = Automatically start on boot after all of the "auto"
services have started.
- disabled = Do not allow this service to be run.
- manual = The administrator has to manually start this task.
- state
- absent = Delete the service.
- restarted = Restart the service.
- started = Start the service.
- stopped = Stop the service.
- username = The user to run the service as.
Syntax:
.. code-block:: yaml
win_service:
Example:
.. code-block:: yaml
win_service:
name: CustomService
path: C:\Program Files (x86)\myapp\myapp.exe
start_mode: auto
username: .\Administrator
password: {{ admin_pass }}
[48]
User
^^^^
Create, read, update, or delete (CRUD) a Windows user account.
All options:
- account\_disabled = Disable the account. The user can no longer be
used.
- account\_locked = Lock the account. The user will no longer have
access to log into their account.
- description = A description of the user's purpose.
- fullname = The full name of the user.
- groups = A list of groups that the user should be added to or removed
from.
- groups\_actions
- replace = Add the user to each of the ``groups`` and remove them
from all others.
- add = Add the user to each of the ``groups``.
- remove = Remove the user from all of the ``groups``.
- **name** = The name of the user to modify.
- password = The the user's password.
- password\_expired = Force the user's password to be expired/changed.
- password\_never\_expires = Determine if the user's password should
ever expire.
- state
- absent = Delete the user.
- present = Create the user. This is the default option.
- query = Look up information about the user account.
- update\_password
- always = Change the password for a user.
- on\_create = Only change a password for a user that was just
created.
- user\_cannot\_change\_password = Allow or disallow a user from
modifying their password.
Syntax:
.. code-block:: yaml
win_user:
Example:
.. code-block:: yaml
win_user: name="default" password="abc123xyz890" user_cannot_change_password="yes" groups=['privileged', 'shares'] state="present"
[48]
Module Development
~~~~~~~~~~~~~~~~~~
Official Ansible module development documentation can be found `here `__.
All of the helper libraries for Ansible can be found in
`lib/ansible/modules\_utils/ `__.
At the bare minimum, the `AnsibleModule
class `__
should be used to create a new module object.
.. code-block:: python
from ansible.module_utils.basic import AnsibleModule
That basic syntax and layout of creating a module object looks like
this.
.. code-block:: python
module = AnsibleModule(
argument_spec=dict(
=dict()
),
)
These are all of the various settings that can be defined and used
AnsibleModule object.
- ``AnsibleModule`` **initialization:**
- argument\_spec = A dictionary of arguments that can be provided by a user using this module. Each argument can have it's own settings.
- ```` = A unique argument name should be given. This
will contain a dictionary of additional settings for this
argument.
- aliases = A list of other names that can be used to reference
this same argument.
- choices = A list of explicit valid choices for this argument.
This is primarily used for documentation.
- required = True or False. If this argument is required for the
module to work.
- default = A default value to provide if the user does not
specify one.
- type = The type of value that should be provided. This can be
any valid Python variable type. Common types include:
- bool = Boolean.
- float = Float, a decimal number.
- int = Integer, a whole number.
- list
- path = A path to a file or directory.
- string
- required\_one\_of = A list of arguments where at least one is required for the module to work.
- mutually\_exclusive = A list of arguments that cannot be used together.
- supports\_check\_mode = Specify if this module supports Ansible's "check mode" where it can check to see if this module will change anything without modifying the system. This sets the ``module.check_mode`` boolean.
- ``module`` **common object methods:**
- \_deprecation = A dictionary of information for a deprecation message.
- msg = The deprecation string.
- version = The version this was / will be deprecated in.
- \_warnings = A list of warnings to provide the end user.
- append\_to\_file = Append text to a file.
- atomic\_move = Copy a source file to a destination. The new destination file will use the same file attributes as the original destination file.
- debug = Debug a variable's value.
- digest\_from\_file = Return a checksum of a file.
- exit\_json = A dictionary of return data when the module finishes successfully.
- *kwargs* = Any variables can be passed to this method and will be returned in the error message. Common variable names and values to pass include:
- changed = A boolean stating if anything has changed.
- changes = A dictionary of items that were changed.
- results = A dictionary of results that should be returned to the end user.
- fail\_json = A dictionary for when the module fails.
- msg = A string of a failure message.
- *kwargs* = Any other variables can be passed to this method and will be returned in the error message.
- from\_json = Convert JSON data into a dictionary.
- get\_bin\_path = Find the path of a binary on the managed system.
- jsonify = Convert a variable into JSON format.
- run\_command = Run a command on the managed system. This method will return the return code, the standard output, and the standard error from the process. Example:
.. code-block:: python
cmd = "echo Hello world"
rc, out, err = module.run_command(cmd)
- ``module`` **common object variables:**
- check\_mode = Boolean. Determines if check\_mode is supported based on what ``module.supports_check_mode`` value is set to.
- params = Dictionary. All of the module argument variables.
[44]
Roles
-----
Roles are a collection of related tasks. Playbooks use one or more roles to configure remote hosts. Ansible searches in these locations for roles:
- /etc/ansible/roles/ (set by ``roles_path`` in the ansible.cfg)
- /usr/share/ansible/roles/
- ~/.ansible/roles/
- roles/
Galaxy
~~~~~~
Ansible Galaxy is used to manage playbook and role dependencies. Roles can be downloaded from the `Ansible Galaxy community `__ or from source control management (SCM) systems such as GitHub. [25] The latest beta version of Galaxy can be found `here `__. The ``ansible-galaxy`` command is installed by default with Ansible.
.. code-block:: sh
$ ansible-galaxy install .
.. code-block:: sh
$ ansible-galaxy install .,
.. code-block:: sh
$ ansible-galaxy install --roles-path .
For a role to work with Ansible Galaxy, it is required to have the
``meta/main.yml`` file. This will define supported Ansible versions and
systems, dependencies on other roles, the license, and other useful
information. [58]
.. code-block:: yaml
---
galaxy_info:
author:
description:
company:
license:
min_ansible_version:
platforms:
- name:
versions:
-
- name:
versions:
- all
galaxy_tags:
-
- :
dependencies:
- .
At least one tag should be one of the popular Ansible Galaxy categories [71]:
- cloud
- database
- development
- monitoring
- networking
- packaging
- security
- system
- web
Below is an example of defining support for all Linux operating systems that are listed in Galaxy:
.. code-block:: yaml
---
platforms:
- name: Alpine
versions:
- all
- name: ArchLinux
versions:
- all
- name: Debian
versions:
- all
- name: Devuan
versions:
- all
# "CentOS" and "RHEL" are not valid names. Use "EL" instead.
# https://github.com/ansible/galaxy/issues/2072
- name: EL
versions:
- all
- name: Fedora
versions:
- all
- name: GenericLinux
versions:
- all
- name: opensuse
versions:
- all
- name: SLES
versions:
- all
- name: Ubuntu
versions:
- all
- name: Void Linux
versions:
- all
Dependencies
^^^^^^^^^^^^
Roles can define dependencies to other roles hosted remotely. By
default, the Ansible Galaxy repository is used to pull roles from.
Ansible Galaxy in itself uses GitHub.com as it's back-end. Dependencies
can be defined in ``requirements.yml`` or inside the role at
``meta/main.yml``.
Install the dependencies by running:
.. code-block:: sh
$ ansible-galaxy install -r requirements.yml
- Dependency options:
- src = The role to use. Valid formats are:
- ``.`` = The user and project name
to use from GitHub.
- ``https://github.com//``
- ``git+https://github.com//.git`` =
Explicitly use HTTPS for accessing GitHub.
- ``git+ssh://git@//.git`` = Use
SSH for accessing GitHub.
- version = The branch, tag, or commit to use. Default: master.
- name = Provide the role a new custom name.
- scm = The supply chain management (SCM) tool to use. Currently
only Git (git) and Mercurial (hg) are supported. This is useful
for using projects that are not hosted on GitHub.com. Default:
git.
Dependency syntax:
.. code-block:: yaml
dependencies:
- src: .
version:
name:
scm:
- src: .
Dependency example:
.. code-block:: yaml
- src: https://github.com/hux/starkiller
version: 3101u9e243r90adf0a98avn4bmz
name: new_deathstar
- src: https://example.tld/project
scm: hg
name: project
Git with SSH example (useful for GitLab):
.. code-block:: yaml
- src: git+ssh://git@//.git
version: 1.2.0
scm: git
[25]
Community Roles
^^^^^^^^^^^^^^^
Unofficial community roles can be used within Playbooks. Most of these
can be found on `Ansible Galaxy `__ or
`GitHub `__. This section covers some useful roles for system administrators.
Network Interface
'''''''''''''''''
URL: https://github.com/MartinVerges/ansible.network\_interface
The ``network_interface`` role was created to help automate the
management of network interfaces on Debian and RHEL based systems. The
most up-to-date and currently maintained fork of the original project is
owned by the `GitHub user
MartinVerges `__.
The role can be passed any of these dictionaries to configure the
network devices.
- network\_ether\_interfaces = Configure Ethernet devices.
- network\_bridge\_interfaces = Configure bridge devices.
- network\_bond\_interfaces = Configure bond devices.
- network\_vlan\_interfaces = Configure VLAN devices.
Valid dictionary values:
- device = Required. This should define the device name to modify or
create.
- bootproto = Required. ``static`` or ``dhcp``.
- address = Required for ``static``. IP address.
- netmask = Required for ``static``. Subnet mask.
- cidr = For ``static``. Optionally use CIDR notation to specify the IP
address and subnet mask.
- gateway = The default gateway for the IP address.
- hwaddress = Use a custom MAC address.
- mtu = Specify the MTU packet size.
- vlan = Set to ``True`` for creating the VLAN devices.
- bond\_ports = Required for bond interfaces. Specify the Ethernet
devices to use for the unified bond.
- bond\_mode = For bond interfaces. Define the type of Linux bonding
method.
- bridge\_ports = Required for bridge interfaces. Specify the Ethernet
device(s) to use for the bridge.
- dns-nameserver = A Python list of DNS nameservers to use.
Example:
- ``eth0`` is configured to use DHCP and has it's MTU set to 9000.
- ``eth1`` is added to the new bridge ``br0`` with the IP address
``10.0.0.1`` and the subnet mask of ``255.255.255.0``.
- ``eth2`` and ``eth3`` are configured to be in a bond, operating in
mode "6" (adaptive load balancing).
- ``bond0.10`` and ``bond0.20`` are created as VLAN tagged devices off
of the newly created bond.
.. code-block:: yaml
- hosts: gluster01
roles:
- ansible.network_interfaces
network_ether_interfaces:
- device: eth0
bootproto: dhcp
mtu: 9000
network_bridge_interfaces:
- device: br0
cidr: 10.0.0.1/24
bridge_ports: [ "eth1" ]
network_bond_interfaces:
- device: bond0
bootproto: static
bond_mode: 6
bond_ports: [ "eth2", "eth3" ]
network_vlan_interfaces:
- device: bond0.10
vlan: True
bootproto: static
- device: bond0.20
vlan: True
bootproto: static
[28]
Jinja2
------
Jinja2 is the Python library used for variable manipulation and
substitution in Ansible. This is also commonly used when creating files
for the "``template``" module.
Variables
~~~~~~~~~
Variables defined in Ansible can be single variables, lists, and
dictionaries. This can be referenced from the template.
- Syntax:
::
{{ }}
::
{{ . }}
{{ [''] }}
- Example:
::
{{ certification.name }}
Variables can be defined as a list or nested lists.
Syntax:
.. code-block:: yaml
:
-
-
-
.. code-block:: yaml
:
- ['', '']
- ['', '']
Examples:
.. code-block:: yaml
colors:
- blue
- red
- green
.. code-block:: yaml
cars:
- ['sports', 'sedan']
- ['suv', 'pickup']
Lists can be called by their array position, starting at "0." Alternatively they can be called by the subvariable name.
Syntax:
::
{{ item.0 }}
::
{{ item.0. }}
Example:
.. code-block:: yaml
members:
- name: Frank
contact:
- address: "111 Puppet Drive"
- phone: "1111111111"
.. code-block:: yaml
- debug:
msg: "Contact {{ item.name }} at {{ item.contact.phone }}"
with_items:
- {{ members }}
[3]
Using a variable for a variable name is not possible with Jinja
templates. Only substitution for dictionary keys can be done with format
substitution.
Works:
.. code-block:: yaml
- name: find interface facts
debug:
msg: "{{ hostvars[inventory_hostname]['ansible_%s' | format(item)] }}"
with_items: "{{ ansible_interfaces }}"
Does not work:
.. code-block:: yaml
- name: find interface facts
debug:
msg: "{{ ansible_%s | format(item)] }}"
with_items: "{{ ansible_interfaces }}"
Variables can be updated and manipulated using Python attributes by using Jinja's no-print ``do`` method.
::
{% do example_list.append('new item') %}
[20]
Filters
~~~~~~~
In certain situations it is desired to apply filters to alert a variable
or expression. The syntax for running Jinja filters is
``|()``. Below are some of the
more common functions.
- Convert to a different variable type.
::
{{ |string }}
::
{{ |list }}
::
{{ |int }}
::
{{ |float }}
::
{{ |bool }}
- Convert a list into a string and optionally separate each item by a
specified character.
::
{{ |join("") }}
- Create a default variable if the variable is undefined.
::
{{ |default("")
- Convert all characters in a string to lower or upper case.
::
{{ |lower }}
::
{{ |upper }}
- Round numbers.
::
{{ |round }}
- Escape HTML characters.
::
{{ |escape }}
::
{% autoescape true %}
These HTML tags will be
escaped and visible via a HTML browser.
{% endautoescape %}
- String substitution.
::
{{ "%s %d"|format("I am this old:", 99) }}
- Find the first or last value in a list.
::
{{ |first }}
::
{{ |last }}
- Find the number of items in a variable.
::
{{ |length }}
[20]
Comments
~~~~~~~~
Comments are template comments that will be removed when once a template
has been generated.
Syntax:
::
{# #}
Example:
::
{# this is a...
{% if ip is '127.0.0.1' %}
Welcome to localhost
{% endif %}
...example comment #}
Sometimes it is necessary to escape blocks of code, especially when
dealing with JSON or other similar formats. Jinja will not render
anything that is escaped.
Syntax:
::
{{ '' }}
::
{% raw %}
{% endraw %}
Examples:
::
{{ 'hello world' }}
::
{% raw %}
{{ jinja.wont.replace.this }}
{% endraw %}
[20]
Blocks
~~~~~~
Templates can extend other templates by replacing "block" elements. At
least two files are required. The first file creates a place holder
block. The second file contains the content that will fill in that place
holder.
Syntax (file 1):
::
{% block %}{% endblock %}
Syntax (file 2):
::
{% extends "" %}
{% block %}
{% endblock %}
Example (file 1):
.. code-block:: html
{% block header %}{% endblock %}
{% block body %}{% endblock %}
Example (file 2):
::
{% extends "index.html" %}
{% block header %}
Hello World
{% endblock %}
{% block body %}
Welcome to the Hello World page!
{% endblock %}
[20]
Loops
~~~~~
Loops can use standard comparison and/or logic operators.
Comparison Operators:
- ``==``
- ``!=``
- ``>``
- ``>=``
- ``<``
- ``=<``
Logic Operators:
- ``and``
- ``or``
- ``not``
"For" loops can be used to loop through a list or dictionary.
Syntax:
::
{% for in {{ }} %}
{% endfor %}
::
{% for , in {{ }} %}
{% endfor %}
Examples:
::
# /etc/hosts
{% for host in groups['ceph'] %}
hostvars[host]['private_ip'] hostvars[host]['ansible_hostname']
{% endfor %}
::
{% for count in range(1,4) %}
[{{ groups['db'][{{ count }}] }}]
type=server
priority={{ count }}
{% endfor %}
"For" loops have special variables that can be referenced relating to
the index that the loop is on.
- loop.index = The current index of the loop, starting at 1.
- loop.index0 = The current index of the loop, starting at 0.
- loop.revindex = The same as "loop.index" but in reverse order.
- loop.revindex = The same as "loop.index0" but in reverse order.
- loop.first = This will be True if it is the first index.
- loop.last = This will be True if is it the last index.
"If" statements can be run if a certain condition is met.
Syntax:
::
{% if %}
{% endif %}
::
{% if %}
{% elif %}
{% else %}
{% endif %}
Example:
::
{% if {{ taco_day }} == "Tuesday" %}
Taco day is on Tuesday.
{% else %}
Taco day is not on a Tuesday.
{% endif %}
[20]
Plugins
-------
Ansible supports a variety of custom plugins that can be used.
- Action = Ran before a module is executed.
- Cache = Temporarily store facts in a specific location.
- Callback = Run custom functions based on the current events of a playbook.
- Connection = Manage connections to remote hosts and are used for every task.
- Filter = Data manipulation for Jinja content.
- Lookup = Specify how to lookup specific information using a custom Jinja function.
- Shell = The format that commands should use for different remote shells.
- Strategy = Handle how tasks are executed on remote hosts and in what order.
- Vars = Add in new hosts and variables. In most cases, dynamic inventory scripts are preferred over plugins.
[41]
Containers
----------
Containers can be manually built by using special container connections provided by Ansible.
This example creates a container with Buildah, adds it to the inventory, and then runs another play to execute roles on it.
.. code-block:: yaml
---
- hosts: localhost
tasks:
- name: Create the container
command: "buildah from --name {{ container_name }} {{ container_os }}:{{ container_version_tag }}"
- name: Add the container to the inventory
add_host:
hostname: "{{ container_name }}"
ansible_connection: buildah
- hosts: "{{ container_name }}"
roles:
- "{{ role_name }}"
This example for Ansible >= 2.7 shows how the new "apply" keyword can be used to delegate roles to specific hosts.
.. code-block:: yaml
---
- hosts: localhost
tasks:
- name: Create the container
command: "buildah from --name {{ container_name }} {{ container_os }}:{{ container_version_tag }}"
- name: Add the container to the inventory
add_host:
hostname: "{{ container_name }}"
ansible_connection: buildah
- name: Run a role in the container
include_role:
name: "{{ role_name }}"
apply:
delegate_to: "{{ container_name }}"
There is also a community project called `ansible-bender `__ that seeks to be a spiritual successor to the now deprecated Ansible-Container project. It is used to build containers using Ansible playbooks. [77]
Best Practices
--------------
- Store Ansible content in a source control manager (SCM) such as git. It is important to keep a history of changes for infrastructure-as-code content.
- Formatting:
- Use YAML formatting. Do not use single-line tasks.
- Indent YAML dictionaries/lists by two spaces under the key.
- Leave one newline between each task.
- Inventory:
- Hosts and groups in an inventory should have a descriptive name.
- Tasks:
- Every task should have a ``name:`` to declaratively describe what it does.
- Define the expected ``state:`` of a task (if applicable).
- Avoid ``command``, ``raw``, and ``shell`` modules. If that is not possible, add additional tasks to do idempotency checks.
- Use ``handlers`` to restart system services.
- Set a ``tag:`` for tasks to showcase it has certain attributes such as ``become:`` set.
.. code-block:: yaml
- name: Check the Apache configuration syntax
command: httpd -t
changed_when: False
tags:
- become
become: True
become_user: apache
- Roles:
- Roles should be designed to be re-usable and re-distributable for other projects.
- Fill out the details in the ``requirements.yml`` file for every role.
- Add Molecule tests for each scenario supported by a role.
- Variables:
- Define variables that can be overridden in the ``defaults`` folder in a role. Define variables that should never be changed in the ``vars`` folder instead.
- Prefix role-specific variable names with the role name.
- Files:
- Place static files in the ``files`` directory in a role. Only Jinja templates should exist in the ``templates`` directory.
- Jinja templates should have the ``.j2`` file extension name.
- Jinja templates should contain ``{{ ansible_managed | comment }}`` at the top of the file.
[5][74]
Python API
----------
Ansible is written in Python so it can be used programmatically to run Playbooks. Using the Ansible Python library directly is not recommended. It does not provide a thread-safe interface and is subject to change depending on the needs of the actual Ansible utilities. Instead, consider using `ansible-runner `__ or a RESTful API from a dashboard such as the official AWX project. [32]
Testing
-------
Ansible Lint
~~~~~~~~~~~~
The ``ansible-lint`` utility is used to check for best practices in Ansible playbooks and roles. If a certain rule was triggered and is deemed to be a false-positive then the affected line can have the comment ``# noqa `` appended to it to skip checking that rule. Alternatively, add the tag ``skip_ansible_lint`` to the task to skip all lint checks on that particular task.
.. code-block:: yaml
tags:
- skip_ansible_lint
[69]
Molecule
~~~~~~~~
Molecule is a testing framework designed specifically for Ansible roles. It assists with running validations such as lint and syntax checks. Users can optionally configure custom tests via an Ansible playbook and/or Python with the ``testinfra`` library. It was originally created by Cisco employees and, as of October 2018, it is now maintained by Red Hat. Molecule 2.20 was the first release of Molecule by Red Hat. [81]
Checks done by ``molecule test`` (in order of execution):
- lint = Run ``ansible-lint`` and ``yamllint`` on the role.
- destroy = Destroy any existing virtual machines using the ``destroy.yml`` playbook.
- dependency = Install any necessary role dependencies from Ansible Galaxy.
- syntax = Check the YAML syntax.
- create = Create the virtual machine using the ``create.yml`` playbook.
- prepare = Run post-provisioning tasks to setup the virtual machine before testing the role using the ``prepare.yml`` playbook.
- converge = Test the role by running the ``molecule/default/playbook.yml`` playbook.
- idempotence = Verify that tasks are only changed when they need to be.
- side_effect = Run an optional side_effect playbook to test out more complex scenarios relating to this role (example, cluster recovery).
- verify = Run the verify test scripts from the ``molecule/default/tests/`` directory.
- destroy = Destroy the virtual machine.
Supported virtualization drivers and their provisioners:
- azure
- delegated = Use a custom driver. The default for this is to run ``create.yaml`` and ``destroy.yaml`` for provisioning the test environment unless ``[driver][options]managed=False`` is configured.
- docker
- ec2
- gce
- lxc
- lxd
- openstack
- vagrant
- libvirt
- parallels (macOS only)
- virtualbox (default)
- vmware
Create a new role with Molecule and a specific virtualization driver. This will create the directory ``/molecule/default/`` that will store all of the Molecule settings and playbooks used for testing.
.. code-block:: sh
$ molecule init role --role-name --driver-name
Molecule can be configured by the ``molecule.yml`` file. By default, it will use the Vagrant driver with VirtualBox as the hypervisor software for testing.
.. code-block:: yaml
---
driver:
name:
provider:
name:
Specific tests handled by the ``molecule test`` command can be turned off in the ``molecule.yml`` file.
.. code-block:: yaml
---
dependency:
name: galaxy
enabled: False
lint:
name: yamllint
enabled: False
provisioner:
name: ansible
enabled: False
verifier:
name: testinfra
enabled: False
The order of tests can be changed using the ``scenario._sequence`` lists. Parts of the sequence can also be disabled by being commented out.
.. code-block:: yaml
---
scenario:
name: default
create_sequence:
- create
- prepare
check_sequence:
- destroy
- dependency
- create
- prepare
- converge
- check
- destroy
converge_sequence:
- dependency
- create
- prepare
- converge
destroy_sequence:
- destroy
test_sequence:
- lint
- destroy
- dependency
- syntax
- create
- prepare
- converge
- idempotence
- side_effect
- verify
- destroy
docker containers will require a "command" is provided to start and keep it running. By default, an infinite while loop with a sleep command is executed using Bash for maximum portability. [72]
Example command:
.. code-block:: yaml
platforms:
- name: centos_7
image: centos:7
command: bash -c 'while true; do sleep 1; done'
- name: ubuntu_1804
image: ubuntu:18.04
command: sleep infinity
The main playbook test is executed with the ``molecule converge`` command. It will run through these steps in order:
- dependency
- create
- prepare
- converge
Additional playbook arguments can be provided by stopping the current arguments for Molecule with ``--``.
Example:
.. code-block:: sh
$ molecule converge -- -vvv --become --become-user=root
Specific tasks in a role can be disabled by setting the "molecule-notest" or "notest" tag.
During the creation and deletion of the infrastructure to test with, Molecule configures the Ansible playbook to disable logging to hide sensitive information about the environment. If any issues are encounteredin the provisioning stage, use one of these methods to re-enable logging. Any of these methods will essentially set the parameter `no_log: False` for all create and destroy tasks.
- Use the ``molecule --debug`` argument.
- Export the environment variable ``MOLECULE_DEBUG=True``.
- Configure the provisioner in ``molecule.yml`` to have debugging enabled.
.. code-block:: yaml
provisioner:
name: ansible
debug: True
Additional Ansible arguments can be defined in the configuration or via the command line.
.. code-block:: yaml
provisioner:
name: ansible
ansible_args:
- --skip-tags molecule_skip
.. code-block:: sh
$ molecule converge -- --skip-tags molecule_skip
The virtual environment instance can be accessed with ``molecule login``. If more than one environment is created, use the ``--host`` argument to specify which one to enter.
Example:
.. code-block:: sh
$ molecule login --host
Delete instances with ``molecule destroy``.
[70]
Dashboards
----------
Various dashboards are available that provide a graphical user interface
(GUI) and usually an API to help automate Ansible deployments. These can
be used for user access control lists (ACLs), scheduling automated
tasks, and having a visual representation of Ansible's deployment
statistics.
Ansible Tower 3
~~~~~~~~~~~~~~~
Ansible Tower is the official dashboard maintained by Red Hat. The program is built using Python and uses RabbitMQ for clustering and PostgreSQL for storing it's data. PostgreSQL is used for the database back-end because it is one of the few relational databases that support storing and accessing JSON formatted data. [52] Tower 3.3.0 was the first release to support installing services as docker containers on OpenShift. [75]
**Requirements and Support**
- 3.6
- EL 8 or EL >= 7.4
- PostgreSQL 10
- Ansible >= 2.2 (EL 7)
- Ansible >= 2.8 (EL 8)
- Release date: 2019-11-14
- EOL: 2021-05-14
- 3.5
- EL 8, EL >= 7.4, or Ubuntu 16.04 (Ubuntu is now deprecated)
- PostgreSQL 9.6
- Ansible >= 2.2 (EL 7 or Ubuntu)
- Ansible >= 2.8 (EL 8)
- Release date: 2019-05-29
- EOL: 2020-11-29
- 3.4
- EL >= 7.4 or Ubuntu 16.04
- PostgreSQL 9.6
- Ansible >= 2.2
- Release date: 2019-01-09
- EOL: 2020-07-09
- 3.3
- EL >= 7.4 or Ubuntu 16.04
- PostgreSQL 9.6
- Ansible >= 2.2
- Release date: 2018-09-12
- EOL: 2020-03-12
- 3.2
- EL >= 7.2, Ubuntu 16.04, or Ubuntu 14.04
- Ansible >= 2.2
- Access to some inventory sources, including Azure, requires >= 2.4
- PostgreSQL 9.6
- Release date: 2017-10-02
- EOL: 2019-04-02
**Support Changes**
- 3.6.0 dropped support for Ubuntu.
- 3.1.0 dropped support for EL 6.
[35][66]
Tower can be downloaded from http://releases.ansible.com/ansible-tower/. The "setup" package only contains Ansible Tower. The "setup-bundle" has all of the dependencies for an offline installation on RHEL servers. At least a free trial of Tower can be used to manage up to 10 servers for testing purposes only. A license can be bought from Red Hat to use Tower for managing more servers and to provide customer support. A license can be obtained from the `Ansible Tower license page `__.
.. code-block:: sh
$ curl -O http://releases.ansible.com/ansible-tower/setup/ansible-tower-setup-latest.tar.gz
$ tar -x -z -v -f ansible-tower-setup-latest.tar.gz
$ cd ./ansible-tower-setup-3.*/
At a bare minimum for 1 node Ansible Tower installation, the passwords to use for the various services need to be defined in the ``inventory`` file or a separate variables file that is encrypted using Ansible Vault.
- admin\_password
- pg\_password
- rabbitmq\_password
Ansible Tower supports clustering. This requires that the PostgreSQL service is configured on a dedicated server that is not running Ansible Tower. The Playbook that installs Tower can install PostgreSQL or use credentials to an existing server. The PostgreSQL user for Ansible Tower also requires ``CREATEDB`` access during the initial installation to setup the necessary database and tables.
- Installing PostgreSQL:
.. code-block:: ini
[tower]
[database]
[all:vars]
# PostgreSQL
pg_database="awx"
pg_username="awx"
pg_password=""
# RabbitMQ
rabbitmq_port=5672
rabbitmq_vhost="tower"
rabbitmq_username="tower"
rabbitmq_password=""
rabbitmq_cookie=""
## Set to "True" if fully qualified domain names (FQDNs)
## are used in the inventory file. Otherwise this should
## be "False"
rabbitmq_use_long_name="True"
- Using an existing PostgreSQL server:
.. code-block:: ini
[tower]
[all:vars]
# PostgreSQL
pg_host=""
pg_port=5432
pg_database="awx"
pg_username="awx"
pg_password=""
# RabbitMQ
rabbitmq_port=5672
rabbitmq_vhost="tower"
rabbitmq_username="tower"
rabbitmq_password=""
rabbitmq_cookie=""
## Set to "True" if fully qualified domain names (FQDNs)
## are used in the inventory file. Otherwise this should
## be "False"
rabbitmq_use_long_name="True"
Then install Ansible Tower using the setup shell script. This will run an Ansible Playbook to install Tower.
.. code-block:: sh
$ ./setup.sh
When the installation is complete, Ansible Tower can be accessed by a web browser. If no SSL certificate was defined, then a self-signed SSL certificate will be used to encrypt the connection. The default username is "admin" and the password is defined in the ``inventory`` file.
::
https:///
For updating Ansible Tower, download the latest tarball release and
re-run the ``setup.sh`` script with the original inventory and
variables. Adding new nodes to the cluster should also have that script
run again so that all of the existing and new nodes will be configured
to know about each other. Automatically scaling and/or replicating
PostgreSQL is currently not supported by the Tower setup Playbook. Only
1 database node can be configured by this Playbook.
Logs are stored in ``/var/log/tower/``. The main log file is
``/var/log/tower/tower.log``.
Ports:
- 80/tcp = Unencrypted Ansible Tower dashboard web traffic.
- 443/tcp = SSL encrypted Ansible Tower dashboard web traffic.
- 5432/tcp = PostgreSQL relational database server.
Cluster ports:
- 4369/tcp = Discovering other Ansible Tower nodes (Erlang service: epmd).
- 5672/tcp = Local RabbitMQ port.
- 15672/tcp = RabbitMQ dashboard.
- 25672/tcp = External RabbitMQ port (Erlang communication between clustered nodes).
[33][35]
GUI
^^^
There is a navigation bar that contains links to the most important
parts of Ansible Tower.
- Projects = Playbooks and, if applicable, credentials to access them
from different types of source code management (SCM) systems.
- Manual = Use the a Playbook from the local file system on the
Ansible Tower server.
- Git = A SCM.
- Mercurial (hg) = A SCM.
- Subversion (svn) = A SCM.
- Red Hat Insights = Use a Playbook from the Red Hat Insights
program to do validation checks.
- Inventories = Static and dynamic inventories can be defined here.
- Supported sources:
- Custom Script = Provide a custom script that outputs a valid
JSON or YAML inventory.
- Sourced from a Project = Import inventory from an existing
Project (Playbook).
- Amazon EC2
- Google Compute Engine
- Microsoft Azure Resource Manager
- VMware vCenter
- Red Hat Satellite 6
- OpenStack
- Templates = Used for defining a Playbook to run, the hosts to run on,
any additional variables to use, and optionally a time interval to
automatically run the template.
- Workflow Template = Defines a workflow for determining when to run
a Playbook and what runs after depending on if the Playbook failed
or succeeded.
- Jobs = Templates that have been run (or are running) and their logs
and statistics.
- (The gear/cog image) = Settings for configuring new users, teams,
dynamic inventory scripts, notifications, the license, and other
settings relating to the Ansible Tower installation.
- (The book image) = A shortcut to Ansible Tower's official
documentation.
[50][51]
The default timeout for an authorization token is 30 minutes. After this
time, the token will expire and the end-user will need to re-login into
their account. This setting can be modified in the ``settings.py`` file.
[52]
.. code-block:: sh
$ sudo vim /etc/tower/conf.d/settings.py
AUTH_TOKEN_EXPIRATION =
Security
^^^^^^^^
Authentication
''''''''''''''
User authentication, by default, will store encrypted user information into the PostgreSQL database. Instead of using this, Tower can be configured to use an external authentication service by going into ``Settings > CONFIGURE TOWER``. The enterprise authentication back-ends are not supported on trial or self-supported licenses.
- Social
- GitHub OAuth2
- GitHub [Users]
- GitHub Org[anization]
- GitHub Team
- Google OAuth2
- Enterprise
- Azure AD
- LDAP
- RADIUS
- SAML
- TACACS+
[52]
RBAC
''''
A key part of Ansible Tower is the role-based access control (RBAC) that is provides. Every user in Tower is associated with at least one organization. The level of access the user has to that organizations resources is defined by one of the different access control lists (ACLs).
Hierarchy [1]:
- Organizations = A combination of Users, Teams, Projects, and
Inventories.
- Teams = Teams are a collection of users. Teams are not required.
Multiple users' access can be modified easily and quickly via a
Team instead of individually modifying each user's access.
- Users = Users are optionally associated with a Team and are
always associated with an Organization. An ACL is set for what
resources the user is allowed to use.
Organizational User types:
- System Administrator = Has full access to all organizations and the Tower installation.
- System Auditor = Has read-only access to an organization.
- Normal User = Has read and write access to an organization.
[51]
SSL
'''
By default, Tower creates a self-signed SSL certificate to secure web
traffic. [35] Most web browsers will mark this as an untrusted
connection. For using a different SSL that is trusted, the contents of
these two files need to be replaced on each Tower node:
- ``/etc/tower/tower.cert``
- ``/etc/tower/tower.key``
API
^^^
Ansible Tower has a strong focus on automating Ansible even more by
providing an API interface. Programs can interact with this by making
HTTP GET and PUT requests. All of the available endpoints can be viewed
by going to: ``https:///api/v2/``.
Version 2 of the API provides these endpoints:
.. code-block:: json
{
"authtoken": "/api/v2/authtoken/",
"ping": "/api/v2/ping/",
"instances": "/api/v2/instances/",
"instance_groups": "/api/v2/instance_groups/",
"config": "/api/v2/config/",
"settings": "/api/v2/settings/",
"me": "/api/v2/me/",
"dashboard": "/api/v2/dashboard/",
"organizations": "/api/v2/organizations/",
"users": "/api/v2/users/",
"projects": "/api/v2/projects/",
"project_updates": "/api/v2/project_updates/",
"teams": "/api/v2/teams/",
"credentials": "/api/v2/credentials/",
"credential_types": "/api/v2/credential_types/",
"inventory": "/api/v2/inventories/",
"inventory_scripts": "/api/v2/inventory_scripts/",
"inventory_sources": "/api/v2/inventory_sources/",
"inventory_updates": "/api/v2/inventory_updates/",
"groups": "/api/v2/groups/",
"hosts": "/api/v2/hosts/",
"job_templates": "/api/v2/job_templates/",
"jobs": "/api/v2/jobs/",
"job_events": "/api/v2/job_events/",
"ad_hoc_commands": "/api/v2/ad_hoc_commands/",
"system_job_templates": "/api/v2/system_job_templates/",
"system_jobs": "/api/v2/system_jobs/",
"schedules": "/api/v2/schedules/",
"roles": "/api/v2/roles/",
"notification_templates": "/api/v2/notification_templates/",
"notifications": "/api/v2/notifications/",
"labels": "/api/v2/labels/",
"unified_job_templates": "/api/v2/unified_job_templates/",
"unified_jobs": "/api/v2/unified_jobs/",
"activity_stream": "/api/v2/activity_stream/",
"workflow_job_templates": "/api/v2/workflow_job_templates/",
"workflow_jobs": "/api/v2/workflow_jobs/",
"workflow_job_template_nodes": "/api/v2/workflow_job_template_nodes/",
"workflow_job_nodes": "/api/v2/workflow_job_nodes/"
}
[34]
Recovery
^^^^^^^^
Ansible Tower provides an official automated solution to backups and restorations of existing Tower clusters.
Backup:
.. code-block:: sh
./setup.sh -b
A backup creates a tar archive that is gzip compressed. A symlink is created from the latest backup to the link named "``tower-backup-latest.tar.gz``."
Syntax - Restore:
.. code-block:: sh
./setup.sh -r
Syntax - Restore a specific backup file:
.. code-block:: sh
./setup.sh -r -e "restore_backup_file="
Example - Restore with a specific backup file:
.. code-block:: sh
./setup.sh -r -e "restore_backup_file=/backups/tower/tower-backup-2018-01-15-12:43:21.tar.gz"
[67]
The PostgreSQL database service can natively be configured for streaming replication feature. This is not supported by Red Hat. This replicates all data from the master node to a slave node. If the master node fails, a system administrator can manually set the slave node to be the new master. [68] `A community supported Ansible role `__ can be used to help automate the setup and usage of this.
Individual Ansible Tower nodes can also be safely removed from the cluster by using the ``awx-manage`` CLI utility. [42]
.. code-block:: sh
$ sudo ansible-tower-service stop
$ sudo awx-manage deprovision_instance -—hostname=
$ sudo awx-manage unregister_queue --queuename=
Updates
^^^^^^^
Before updating, it is recommended to take a full backup.
.. code-block:: sh
$ ./setup.sh -b
Minor updates (for example, from 3.2.0 to 3.2.5) for Ansible Tower require using the `latest setup archive