<h2>Playbook Language Example<aclass="headerlink"href="#playbook-language-example" title="Permalink to this headline">¶</a></h2>
<p>Playbooks are expressed in YAML format and have a minimum of syntax.
Each playbook is composed of one or more ‘plays’ in a list.</p>
<p>The goal of a play is map a group of hosts to some well defined roles, represented by
things ansible called tasks. At the basic level, a task is nothing more than a call
to an ansible module, which you should have learned about in earlier chapters.</p>
<p>By composing a playbook of multiple ‘plays’, it is possible to
orchestrate multi-machine deployments, running certain steps on all
machines in the webservers group, then certain steps on the database
@ -285,21 +287,18 @@ this does not come into play. Ansible also takes care to not log password parame
<p>These variables can be used later in the playbook like this:</p>
<divclass="highlight-python"><pre>$varname or ${varname}</pre>
</div>
<p>The later is useful in the event you need to do something like ${other}_concatenated_value.</p>
<p>The full power of the Jinja2 templating language is also available (note: in 0.4, this is only true inside of templates), which looks like this:</p>
<p>The later is useful in the event you need to do something like ${other}_some_string.</p>
<p>The full power of the <aclass="reference external"href="http://jinja.pocoo.org/docs/">Jinja2</a> templating language is also available, which looks like this:</p>
<p>The Jinja2 documentation provides information about how to construct loops and conditionals for those
who which to use more advanced templating. This is optional and the $varname format still works in template
files.</p>
<p>If there are discovered variables about the system (ansible provides some of these,
plus we include ones taken from facter or ohai if installed) these variables bubble up back into the
playbook, and can be used on each system just like explicitly set
variables.</p>
<p>Facter variables are prefixed with <ttclass="docutils literal"><spanclass="pre">facter_</span></tt> and Ohai
variables are prefixed with <ttclass="docutils literal"><spanclass="pre">ohai_</span></tt>. Ansible variables (0.3 and later)
are not surprisingly prefixed with <ttclass="docutils literal"><spanclass="pre">ansible_</span></tt> (See the <aclass="reference internal"href="modules.html#setup"><em>setup</em></a> module
documentation for a list of Ansible variables).</p>
<p>If there are discovered variables about the system, called ‘facts’, these variables bubble up back into the
playbook, and can be used on each system just like explicitly set variables. Ansible provides several
of these, prefixed with ‘ansible’, and are documented under <aclass="reference internal"href="modules.html#setup"><em>setup</em></a> in the module documentation. Additionally,
facts can be gathered by ohai and facter if they are installed. Facter variables are prefixed with <ttclass="docutils literal"><spanclass="pre">facter_</span></tt> and Ohai
variables are prefixed with <ttclass="docutils literal"><spanclass="pre">ohai_</span></tt>.</p>
<p>So for instance, if I wanted
to write the hostname into the /etc/motd file, I could say:</p>
<divclass="highlight-python"><pre>- name: write the motd
@ -314,19 +313,22 @@ to write the hostname into the /etc/motd file, I could say:</p>
<h3>Tasks list<aclass="headerlink"href="#tasks-list"title="Permalink to this headline">¶</a></h3>
<p>Each play contains a list of tasks. Tasks are executed in order, one
at a time, against all machines matched by the host pattern,
before moving on to the next task.</p>
<p>Hosts with failed tasks are taken out of the rotation for the entire
playbook. If things fail, simply correct the playbook file and rerun.</p>
before moving on to the next task. It is important to understand that, within a play,
all hosts are going to get the same task directives. It is the purpose of a play to map
a selection of hosts to tasks.</p>
<p>When running the playbook, which runs top to bottom, hosts with failed tasks are
taken out of the rotation for the entire playbook. If things fail, simply correct the playbook file and rerun.</p>
<p>The goal of each task is to execute a module, with very specific arguments.
Variables, as mentioned above, can be used in arguments to modules.</p>
<p>Modules other than <cite>command</cite> and <cite>shell</cite>are ‘idempotent’, meaning if you run them
<p>Modules are ‘idempotent’, meaning if you run them
again, they will make the changes they are told to make to bring the
system to the desired state. This makes it very safe to rerun
the same playbook multiple times. They won’t change things
unless they have to change things.</p>
<p>The <cite>command</cite> and <cite>shell</cite> modules will actually rerun the same command again,
<p>The <cite>command</cite> and <cite>shell</cite> modules will typically rerun the same command again,
which is totally ok if the command is something like
‘chmod’ or ‘setsebool’, etc.</p>
‘chmod’ or ‘setsebool’, etc. Though there is a ‘creates’ flag available which can
be used to make these modules also idempotent.</p>
<p>Every task should have a <cite>name</cite>, which is included in the output from
running the playbook. This is output for humans, so it is
nice to have reasonably good descriptions of each task step. If the name
@ -345,6 +347,18 @@ them work just like you would expect. Simple:</p>
- name: disable selinux
action: command /sbin/setenforce 0</pre>
</div>
<p>The command and shell module care about return codes, so if you have a command
who’s successful exit code is not zero, you may wish to do this:</p>
<blockquote>
<div><dlclass="docutils">
<dt>tasks:</dt>
<dd><ulclass="first last simple">
<li>name: run this command and ignore the result
action: shell /usr/bin/somecommand & /bin/true</li>
</ul>
</dd>
</dl>
</div></blockquote>
<p>Variables can be used in action lines. Suppose you defined
a variable called ‘vhost’ in the ‘vars’ section, you could do this:</p>
<divclass="highlight-python"><pre>tasks:
@ -352,11 +366,13 @@ a variable called ‘vhost’ in the ‘vars’ section, you cou
<h2>Accessing Information About Other Hosts<aclass="headerlink"href="#accessing-information-about-other-hosts"title="Permalink to this headline">¶</a></h2>
<h3>Accessing Information About Other Hosts<aclass="headerlink"href="#accessing-information-about-other-hosts"title="Permalink to this headline">¶</a></h3>
<p>If your database server wants to check the value of a ‘fact’ from another node, or an inventory variable
assigned to another node, it’s easy to do so within a template or even an action line (note: this uses syntax available in 0.4 and later):</p>
assigned to another node, it’s easy to do so within a template or even an action line:</p>
<p>NOTE: No database or other complex system is required to exchange data between hosts. The hosts that you
want to reference data from must be included in either the current play or any previous play.</p>
</div>
<divclass="section"id="magic-variables">
<h2>Magic Variables<aclass="headerlink"href="#magic-variables"title="Permalink to this headline">¶</a></h2>
<p>Some variables made available to hosts don’t come from definitions in a playbook, the inventory file, or discovery from the system. There are only two of these, and are used in special cases that many users won’t need.</p>
<p><em>group_names</em> 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:</p>
<p>Additionally, <em>group_names</em> 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:</p>
<divclass="highlight-python"><pre>{% if 'webserver' in group_names %}
# some part of a configuration file that only applies to webservers
{% endif %}</pre>
@ -238,10 +271,12 @@ For example:</p>
<p>Use cases include pointing a frontend proxy server to all of the app servers, setting up the correct firewall rules between servers, etc.</p>
<p><em>inventory_hostname</em> 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 <cite>ansible_hostname</cite> or for other mysterious
reasons. Don’t worry about it unless you think you need it.</p>
reasons. If you have a long FQDN, <em>inventory_hostname_short</em> (in Ansible 0.6) also contains the part up to the first
period.</p>
<p>Don’t worry about any of this unless you think you need it. You’ll know when you do.</p>
</div>
<divclass="section"id="variable-file-seperation">
<h2>Variable File Seperation<aclass="headerlink"href="#variable-file-seperation"title="Permalink to this headline">¶</a></h2>
<h3>Variable File Seperation<aclass="headerlink"href="#variable-file-seperation"title="Permalink to this headline">¶</a></h3>
<p>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
@ -267,9 +302,10 @@ sharing your playbook source with them.</p>
somevar: somevalue
password: magic</pre>
</div>
<p>NOTE: It’s also possible to keep per-host and per-group variables in very similar files, this is covered in <aclass="reference internal"href="patterns.html#patterns"><em>Inventory & Patterns</em></a>.</p>
<h2>Passing Variables On The Command Line<aclass="headerlink"href="#passing-variables-on-the-command-line"title="Permalink to this headline">¶</a></h2>
<h3>Passing Variables On The Command Line<aclass="headerlink"href="#passing-variables-on-the-command-line"title="Permalink to this headline">¶</a></h3>
<p>In addition to <cite>vars_prompt</cite> and <cite>vars_files</cite>, it is possible to send variables over
the ansible command line. This is particularly useful when writing a generic release playbook
where you may want to pass in the version of the application to deploy:</p>
<p>Variables from tools like <cite>facter</cite> and <cite>ohai</cite> can be used here, if installed, or you can
use variables that bubble up from ansible (0.3 and later). As a reminder,
use variables that bubble up from ansible, which many are provided by the <aclass="reference internal"href="modules.html#setup"><em>setup</em></a> module. As a reminder,
these variables are prefixed, so it’s <cite>$facter_operatingsystem</cite>, not <cite>$operatingsystem</cite>. Ansible’s
built in variables are prefixed with <cite>ansible_</cite>. The only_if
expression is actually a tiny small bit of Python, so be sure to quote variables and make something
built in variables are prefixed with <cite>ansible_</cite>.</p>
<p>The only_if expression is actually a tiny small bit of Python, so be sure to quote variables and make something
that evaluates to <cite>True</cite> or <cite>False</cite>. It is a good idea to use ‘vars_files’ instead of ‘vars’ to define
all of your conditional expressions in a way that makes them very easy to reuse between plays
and playbooks.</p>
<p>You cannot use live checks here, like ‘os.path.exists’, so don’t try.</p>
<p>It’s also easy to provide your own facts if you want, which is covered in <aclass="reference internal"href="moduledev.html"><em>Module Development</em></a>. To run them, just
make a call to your own custom fact gathering module at the top of your list of tasks, and variables returned
<h2>Selecting Files And Templates Based On Variables<aclass="headerlink"href="#selecting-files-and-templates-based-on-variables"title="Permalink to this headline">¶</a></h2>
<h3>Selecting Files And Templates Based On Variables<aclass="headerlink"href="#selecting-files-and-templates-based-on-variables"title="Permalink to this headline">¶</a></h3>
<p>Sometimes a configuration file you want to copy, or a template you will use may depend on a variable.
The following construct (new in 0.4) selects the first available file appropriate for the variables of a given host,
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.</p>
<p>The following example shows how to template out a configuration file that was very different between, say,
(New in 0.6) To further advance the concept of include files, playbook files can include other playbook
files. Suppose you define the behavior of all your webservers in "webservers.yml" and
all your database servers in "dbservers.yml". You can create a "site.yml" that would
reconfigure all of your systems like this::
----
- include: playbooks/webservers.yml
- include: playbooks/dbservers.yml
This concept works great with tags to rapidly select exactly what plays you want to run, and exactly
what parts of those plays.
Accessing Complex Variable Data
+++++++++++++++++++++++++++++++
Some provided facts, like networking information, are made available as nested data structures. To access
them a simple '$foo' is not sufficient, but it is still easy to do. Here's how we get an IP address using
Ansible 0.4 and later::
them a simple '$foo' is not sufficient, but it is still easy to do. Here's how we get an IP address::
${ansible_eth0.ipv4.address}
@ -30,26 +69,19 @@ Accessing Information About Other Hosts
+++++++++++++++++++++++++++++++++++++++
If your database server wants to check the value of a 'fact' from another node, or an inventory variable
assigned to another node, it's easy to do so within a template or even an action line (note: this uses syntax available in 0.4 and later)::
assigned to another node, it's easy to do so within a template or even an action line::
${hostvars.hostname.factname}
NOTE: No database or other complex system is required to exchange data between hosts. The hosts that you
want to reference data from must be included in either the current play or any previous play.
Magic Variables
+++++++++++++++
Some variables made available to hosts don't come from definitions in a playbook, the inventory file, or discovery from the system. There are only two of these, and are used in special cases that many users won't need.
*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::
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::
@ -57,12 +89,14 @@ For example::
# something that applies to all app servers.
{% endfor %}
Use cases include pointing a frontend proxy server to all of the app servers, setting up the correct firewall rules between servers, etc.
*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. Don't worry about it unless you think you need it.
reasons. If you have a long FQDN, *inventory_hostname_short* (in Ansible 0.6) also contains the part up to the first
period.
Don't worry about any of this unless you think you need it. You'll know when you do.
Variable File Seperation
++++++++++++++++++++++++
@ -96,6 +130,8 @@ The contents of each variables file is a simple YAML dictionary, like this::
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
++++++++++++++++++++++++++++
@ -117,6 +153,18 @@ in a push-script::
There are full examples of both of these items in the github examples/playbooks directory.
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: True
- name: "release_version"
prompt: "Product release version"
private: False
Passing Variables On The Command Line
+++++++++++++++++++++++++++++++++++++
@ -126,6 +174,18 @@ where you may want to pass in the version of the application to deploy::