Additionally, *group_names* is a list (array) of all the groups the current host is in. This can be used in templates using Jinja2 syntax to make template source files that vary based on the group membership (or role) of the host::
{% if 'webserver' in group_names %}
# some part of a configuration file that only applies to webservers
{% endif %}
*groups* is a list of all the groups (and hosts) in the inventory. This can be used to enumerate all hosts within a group.
For example::
{% for host in groups['app_servers'] %}
# something that applies to all app servers.
{% endfor %}
A frequently used idiom is walking a group to find all IP addresses in that group::
An example of this could include pointing a frontend proxy server to all of the app servers, setting up the correct firewall rules between servers, etc.
Just a few other 'magic' variables are available... There aren't many.
Additionally, *inventory_hostname* is the name of the hostname as configured in Ansible's inventory host file. This can
be useful for when you don't want to rely on the discovered hostname `ansible_hostname` or for other mysterious
reasons. If you have a long FQDN, *inventory_hostname_short* also contains the part up to the first
period, without the rest of the domain.
Don't worry about any of this unless you think you need it. You'll know when you do.
Also available, *inventory_dir* is the pathname of the directory holding Ansible's inventory host file, *inventory_file* is the pathname and the filename pointing to the Ansible's inventory host file.
Variable File Separation
````````````````````````
It's a great idea to keep your playbooks under source control, but
you may wish to make the playbook source public while keeping certain
important variables private. Similarly, sometimes you may just
want to keep certain information in different files, away from
the main playbook.
You can do this by using an external variables file, or files, just like this::
---
- hosts: all
remote_user: root
vars:
favcolor: blue
vars_files:
- /vars/external_vars.yml
tasks:
- name: this is just a placeholder
command: /bin/echo foo
This removes the risk of sharing sensitive data with others when
sharing your playbook source with them.
The contents of each variables file is a simple YAML dictionary, like this::
---
# in the above example, this would be vars/external_vars.yml
somevar: somevalue
password: magic
.. note::
It's also possible to keep per-host and per-group variables in very
similar files, this is covered in :ref:`patterns`.
Prompting For Sensitive Data
````````````````````````````
You may wish to prompt the user for certain input, and can
do so with the similarly named 'vars_prompt' section. This has uses
beyond security, for instance, you may use the same playbook for all
software releases and would prompt for a particular release version
in a push-script::
---
- hosts: all
remote_user: root
vars:
from: "camelot"
vars_prompt:
name: "what is your name?"
quest: "what is your quest?"
favcolor: "what is your favorite color?"
There are full examples of both of these items in the github examples/playbooks directory.
If you have a variable that changes infrequently, it might make sense to
provide a default value that can be overridden. This can be accomplished using
the default argument::
vars_prompt:
- name: "release_version"
prompt: "Product release version"
default: "1.0"
An alternative form of vars_prompt allows for hiding input from the user, and may later support
some other options, but otherwise works equivalently::
vars_prompt:
- name: "some_password"
prompt: "Enter password"
private: yes
- name: "release_version"
prompt: "Product release version"
private: no
If `Passlib <http://pythonhosted.org/passlib/>`_ is installed, vars_prompt can also crypt the
entered value so you can use it, for instance, with the user module to define a password::
vars_prompt:
- name: "my_password2"
prompt: "Enter password2"
private: yes
encrypt: "md5_crypt"
confirm: yes
salt_size: 7
You can use any crypt scheme supported by 'Passlib':
As with the case of 'with_items' above, you can use previously defined variables. Just specify the variable's name without templating it with '{{ }}'::
- name: here, 'users' contains the above list of employees
``with_password`` and associated lookup macro generate a random plaintext password and store it in
a file at a given filepath. Support for crypted save modes (as with vars_prompt) is pending. If the
file exists previously, it will retrieve its contents, behaving just like with_file. Usage of variables like "{{ inventory_hostname }}" in the filepath can be used to set
up random passwords per host (what simplifies password management in 'host_vars' variables).
Generated passwords contain a random mix of upper and lowercase ASCII letters, the
numbers 0-9 and punctuation (". , : - _"). The default length of a generated password is 30 characters.
This length can be changed by passing an extra parameter::
It is quite possible that you may need to get package updates through a proxy, or even get some package
updates through a proxy and access other packages not through a proxy. Ansible makes it easy for you
to configure your environment by using the 'environment' keyword. Here is an example::
- hosts: all
remote_user: root
tasks:
- apt: name=cobbler state=installed
environment:
http_proxy: http://proxy.example.com:8080
The environment can also be stored in a variable, and accessed like so::
- hosts: all
remote_user: root
# here we make a variable named "env" that is a dictionary
vars:
proxy_env:
http_proxy: http://proxy.example.com:8080
tasks:
- apt: name=cobbler state=installed
environment: "{{ proxy_env }}"
While just proxy settings were shown above, any number of settings can be supplied. The most logical place
to define an environment hash might be a group_vars file, like so::
---
# file: group_vars/boston
ntp_server: ntp.bos.example.com
backup: bak.bos.example.com
proxy_env:
http_proxy: http://proxy.bos.example.com:8080
https_proxy: http://proxy.bos.example.com:8080
Getting values from files
`````````````````````````
.. versionadded:: 0.8
Sometimes you'll want to include the content of a file directly into a playbook. You can do so using a macro.
This syntax will remain in future versions, though we will also will provide ways to do this via lookup plugins (see "More Loops") as well. What follows
is an example using the authorized_key module, which requires the actual text of the SSH key as a parameter::
Sometimes a configuration file you want to copy, or a template you will use may depend on a variable.
The following construct selects the first available file appropriate for the variables of a given host, which is often much cleaner than putting a lot of if conditionals in a template.
The following example shows how to template out a configuration file that was very different between, say, CentOS and Debian::
first_available_file is only available to the copy and template modules.
Asynchronous Actions and Polling
````````````````````````````````
By default tasks in playbooks block, meaning the connections stay open
until the task is done on each node. If executing playbooks with
a small parallelism value (aka ``--forks``), you may wish that long
running operations can go faster. The easiest way to do this is
to kick them off all at once and then poll until they are done.
You will also want to use asynchronous mode on very long running
operations that might be subject to timeout.
To launch a task asynchronously, specify its maximum runtime
and how frequently you would like to poll for status. The default
poll value is 10 seconds if you do not specify a value for `poll`::
---
- hosts: all
remote_user: root
tasks:
- name: simulate long running op (15 sec), wait for up to 45, poll every 5
command: /bin/sleep 15
async: 45
poll: 5
.. note::
There is no default for the async time limit. If you leave off the
'async' keyword, the task runs synchronously, which is Ansible's
default.
Alternatively, if you do not need to wait on the task to complete, you may
"fire and forget" by specifying a poll value of 0::
---
- hosts: all
remote_user: root
tasks:
- name: simulate long running op, allow to run for 45, fire and forget
command: /bin/sleep 15
async: 45
poll: 0
.. note::
You shouldn't "fire and forget" with operations that require
exclusive locks, such as yum transactions, if you expect to run other
commands later in the playbook against those same resources.
.. note::
Using a higher value for ``--forks`` will result in kicking off asynchronous
tasks even faster. This also increases the efficiency of polling.
Local Playbooks
```````````````
It may be useful to use a playbook locally, rather than by connecting over SSH. This can be useful
for assuring the configuration of a system by putting a playbook on a crontab. This may also be used
to run a playbook inside a OS installer, such as an Anaconda kickstart.
To run an entire playbook locally, just set the "hosts:" line to "hosts:127.0.0.1" and then run the playbook like so::
ansible-playbook playbook.yml --connection=local
Alternatively, a local connection can be used in a single playbook play, even if other plays in the playbook
use the default remote connection type::
hosts: 127.0.0.1
connection: local
Turning Off Facts
`````````````````
If you know you don't need any fact data about your hosts, and know everything about your systems centrally, you
can turn off fact gathering. This has advantages in scaling Ansible in push mode with very large numbers of
systems, mainly, or if you are using Ansible on experimental platforms. In any play, just do this::
- hosts: whatever
gather_facts: no
Pull-Mode Playbooks
```````````````````
The use of playbooks in local mode (above) is made extremely powerful with the addition of `ansible-pull`.
A script for setting up ansible-pull is provided in the examples/playbooks directory of the source
checkout.
The basic idea is to use Ansible to set up a remote copy of Ansible on each managed node, each set to run via
cron and update playbook source via git. This inverts the default push architecture of Ansible into a pull
architecture, which has near-limitless scaling potential. The setup playbook can be tuned to change
the cron frequency, logging locations, and parameters to ansible-pull.
This is useful both for extreme scale-out as well as periodic remediation. Usage of the 'fetch' module to retrieve
logs from ansible-pull runs would be an excellent way to gather and analyze remote logs from ansible-pull.
Register Variables
``````````````````
.. versionadded:: 0.7
Often in a playbook it may be useful to store the result of a given command in a variable and access
it later. Use of the command module in this way can in many ways eliminate the need to write site specific facts, for
instance, you could test for the existence of a particular program.
The 'register' keyword decides what variable to save a result in. The resulting variables can be used in templates, action lines, or *when* statements. It looks like this (in an obviously trivial example)::
- name: test play
hosts: all
tasks:
- shell: cat /etc/motd
register: motd_contents
- shell: echo "motd contains the word hi"
when: motd_contents.stdout.find('hi') != -1
As shown previously, the registered variable's string contents are accessible with the 'stdout' value.
The registered result can be used in the "with_items" of a task if it is converted into
a list (or already is a list) as shown below. "stdout_lines" is already available on the object as
well though you could also call "home_dirs.stdout.split()" if you wanted, and could split by other
fields::
- name: registered variable usage as a with_items list
A common pattern is to use a local action to call 'rsync' to recursively copy files to the managed servers.
Here is an example::
---
# ...
tasks:
- name: recursively copy files from management server to target
local_action: command rsync -a /path/to/files {{ inventory_hostname }}:/path/to/target/
Note that you must have passphrase-less SSH keys or an ssh-agent configured for this to work, otherwise rsync
will need to ask for a passphrase.
Accelerated Mode
Accelerated Mode
````````````````
================
.. versionadded:: 1.3
.. versionadded:: 1.3
...
@@ -1112,219 +118,3 @@ Fedora and EPEL also have Ansible RPM subpackages available for fireball-depende
...
@@ -1112,219 +118,3 @@ Fedora and EPEL also have Ansible RPM subpackages available for fireball-depende
Also see the module documentation section.
Also see the module documentation section.
Understanding Variable Precedence
`````````````````````````````````
You have already learned about inventory variables, 'vars', and 'vars_files'. In the
event the same variable name occurs in more than one place, what happens? There are really three tiers
of precedence, and within those tiers, some minor ordering rules that you probably won't even need to remember.
We'll explain them anyway though.
Variables that are set during the execution of the play have highest priority. This includes registered
variables and facts, which are discovered pieces of information about remote hosts.
Descending in priority are variables defined in the playbook. 'vars_files' as defined in the playbook are next up,
followed by variables as passed to ansible-playbook via --extra-vars (-e), then variables defined in the 'vars' section. These
should all be taken to be basically the same thing -- good places to define constants about what the play does to all hosts
in the play.
Finally, inventory variables have the least priority. Variables about hosts override those about groups.
If a variable is defined in multiple groups and one group is a child of the other, the child group variable
will override the variable set in the parent.
This makes the 'group_vars/all' file the best place to define a default value you wish to override in another
group, or even in a playbook. For example, your organization might set a default ntp server in group_vars/all
and then override it based on a group based on a geographic region. However if you type 'ntpserver: asdf.example.com'
in a vars section of a playbook, you know from reading the playbook that THAT specific value is definitely the one
that is going to be used. You won't be fooled by some variable from inventory sneaking up on you.
So, in short, if you want something easy to remember: facts beat playbook definitions, and
playbook definitions beat inventory variables.
There's a little bit more if you are using roles -- roles fit in the "playbook definitions" category of scale. They are
trumped by facts, and still trump inventory variables. However, there's a bit of extra magic.
Variables passed as parameters to the role are accesible only within that role (and dependencies of that role). You can
almost think of them like programming functions or macros.
Variables loaded via the 'vars/' directory of a role are made available to all roles and tasks, which in older versions of Ansible
could be confusing in the case of a reused variable name. In Ansible 1.3 and later, however, vars/ directories are guaranteed to be scoped to the current role, just like roles parameters. They are still available globally though, so if you want to set a variable like "ntp_server" in a common role, other roles can still make use of it. Thus they are just like "vars_files" construct that they emulate, but they have a bit more of a "Do What I Mean" semantic to them. They are smarter.
If there are role dependencies involved, dependent roles can set variables visible to the roles that require them, but
the requiring role is allowed to override those variables. For instance if a role "myapp" requires "apache", and
the value of "apache_port" in "apache" is 80, "myapp" could choose to set it to 8080. Thus you may think of this somewhat
like an inheritance system if you're a developer -- though it's not exactly -- and we don't require folks to think in programming terms to know how things work.
If you want, you can choose to prefix variable names with the name of your role and be extra sure of where
data sources are coming from, but this is optional. However it can be a nice thing to do in your templates as you immediately
know where the variable was defined.
Ultimately, the variable system may seem complex -- but it's really not. It's mostly a "Do What I Mean" kind of system, though knowing the details may help you if you get stuck or are trying to do something advanced. Feel free to experiment!
Check Mode ("Dry Run") --check
```````````````````````````````
.. versionadded:: 1.1
When ansible-playbook is executed with --check it will not make any changes on remote systems. Instead, any module
instrumented to support 'check mode' (which contains the primary core modules, but it is not required that all modules do
this) will report what changes they would have made. Other modules that do not support check mode will also take no
action, but just will not report what changes they might have made.
Check mode is just a simulation, and if you have steps that use conditionals that depend on the results of prior commands,
it may be less useful for you. However it is great for one-node-at-time basic configuration management use cases.
Example::
ansible-playbook foo.yml --check
Running a task in check mode
````````````````````````````
.. versionadded:: 1.3
Sometimes you may want to have a task to be executed even in check
mode. To achieve this, use the `always_run` clause on the task. Its
value is a Jinja2 expression, just like the `when` clause. In simple
cases a boolean YAML value would be sufficient as a value.
Example::
tasks:
- name: this task is run even in check mode
command: /something/to/run --even-in-check-mode
always_run: yes
As a reminder, a task with a `when` clause evaluated to false, will
still be skipped even if it has a `always_run` clause evaluated to
true.
Showing Differences with --diff
```````````````````````````````
.. versionadded:: 1.1
The --diff option to ansible-playbook works great with --check (detailed above) but can also be used by itself. When this flag is supplied, if any templated files on the remote system are changed, and the ansible-playbook CLI will report back
the textual changes made to the file (or, if used with --check, the changes that would have been made). Since the diff
feature produces a large amount of output, it is best used when checking a single host at a time, like so::
As discussed in the playbooks chapter, Ansible facts are a way of getting data about remote systems for use in playbook variables.
Usually these are discovered automatically by the 'setup' module in Ansible. Users can also write custom facts modules, as described
in the API guide. However, what if you want to have a simple way to provide system or user
provided data for use in Ansible variables, without writing a fact module? For instance, what if you want users to be able to control some aspect about how their systems are managed? "Facts.d" is one such mechanism.
If a remotely managed system has an "/etc/ansible/facts.d" directory, any files in this directory
ending in ".fact", can be JSON, INI, or executable files returning JSON, and these can supply local facts in Ansible.
For instance assume a /etc/ansible/facts.d/preferences.fact::
[general]
asdf=1
bar=2
This will produce a hash variable fact named "general" with 'asdf' and 'bar' as members.
To validate this, run the following::
ansible <hostname> -m setup -a "filter=ansible_local"
And you will see the following fact added::
"ansible_local": {
"preferences": {
"general": {
"asdf" : "1",
"bar" : "2"
}
}
}
And this data can be accessed in a template/playbook as::
{{ ansible_local.preferences.general.asdf }}
The local namespace prevents any user supplied fact from overriding system facts
or variables defined elsewhere in the playbook.
Style Points
````````````
Ansible playbooks are colorized. If you do not like this, set the ANSIBLE_NOCOLOR=1 environment variable.
Ansible playbooks also look more impressive with cowsay installed, and we encourage installing this package.
.. seealso::
:doc:`YAMLSyntax`
Learn about YAML syntax
:doc:`playbooks`
Review the basic playbook features
:doc:`bestpractices`
Various tips about playbooks in the real world
:doc:`modules`
Learn about available modules
:doc:`moduledev`
Learn how to extend Ansible by writing your own modules