There are also many jumping off points after you learn playbooks, so hop back to the documentation
index after you're done with this section.
Playbook Language Example
`````````````````````````
@ -130,58 +135,6 @@ Just `Control-C` to kill it and run it again with `-K`.
not come into play. Ansible also takes care to not log password
parameters.
Vars section
++++++++++++
The `vars` section contains a list of variables and values that can be used in the plays, like this::
---
- hosts: webservers
remote_user: root
vars:
http_port: 80
van_halen_port: 5150
other: 'magic'
..note::
You can also keep variables in separate files and include them alongside inline `vars` with a `vars_files` declaration
in the play. See the `Advanced Playbooks chapter <http://www.ansibleworks.com/docs/playbooks2.html#variable-file-separation>`_
for more info.
These variables can be used later in the playbook like this::
{{ varname }}
Variables are passed through the Jinja2 templating engine. Any valid Jinja2
expression can be used between the curly braces, including the use of filters
to modify the variable (for example, `{{ varname|int }}` ensures the variable is
interpreted as an integer).
Jinja2 expressions are very similar to Python and even if you are not working
with Python you should feel comfortable with them. See the `Jinja2 documentation
<http://jinja.pocoo.org/docs/templates/>`_ to learn more about the syntax.
Please note that Jinja2 loops and conditionals are only useful in Ansible
templates, not in playbooks. Use the 'when' and 'with' keywords for
conditionals and loops in Ansible playbooks.
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', which are documented under 'setup' in the module documentation. Additionally,
facts can be gathered by ohai and facter if they are installed. Facter variables are prefixed with ``facter_`` and Ohai variables are prefixed with ``ohai_``. These add extra dependencies and are only there for ease of users
porting over from those other configuration systems. Finally, it's possible to drop files
on to the remote systems that provide additional sources of fact data, see "Facts.d" as documented
in the Advanced Playbooks section.
How about an example. If I wanted to write the hostname into the /etc/motd file, I could say::
Includes can also be used to import one playbook file into another. This allows
you to define a top-level playbook that is composed of other playbooks.
There are also many jumping off points after you learn playbooks, so hop back to the documentation
index after you're done with this section.
For example::
Playbook Language Example
`````````````````````````
- name: this is a play at the top level of a file
hosts: all
remote_user: root
tasks:
- name: say hi
tags: foo
shell: echo "hi..."
Playbooks are expressed in YAML format and have a minimum of syntax.
Each playbook is composed of one or more 'plays' in a list.
- include: load_balancers.yml
- include: webservers.yml
- include: dbservers.yml
The goal of a play is to map a group of hosts to some well defined roles, represented by
things ansible calls tasks. At a basic level, a task is nothing more than a call
to an ansible module, which you should have learned about in earlier chapters.
Note that you cannot do variable substitution when including one playbook
inside another.
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
server group, then more commands back on the webservers group, etc.
..note::
You can not conditionally path the location to an include file,
like you can with 'vars_files'. If you find yourself needing to do
this, consider how you can restructure your playbook to be more
class/role oriented. This is to say you cannot use a 'fact' to
decide what include file to use. All hosts contained within the
play are going to get the same tasks. ('*when*' provides some
ability for hosts to conditionally skip tasks).
.._roles:
Roles
`````
..versionadded:: 1.2
Now that you have learned about vars_files, tasks, and handlers, what is the best way to organize your playbooks?
The short answer is to use roles! Roles are ways of automatically loading certain vars_files, tasks, and
handlers based on a known file structure. Grouping content by roles also allows easy sharing of roles with other users.
Roles are just automation around 'include' directives as redescribed above, and really don't contain much
additional magic beyond some improvements to search path handling for referenced files. However, that can be a big thing!
Example project structure::
site.yml
webservers.yml
fooservers.yml
roles/
common/
files/
templates/
tasks/
handlers/
vars/
meta/
webservers/
files/
templates/
tasks/
handlers/
vars/
meta/
In a playbook, it would look like this::
For starters, here's a playbook that contains just one play::
---
- hosts: webservers
roles:
- common
- webservers
vars:
http_port: 80
max_clients: 200
remote_user: root
tasks:
- name: ensure apache is at the latest version
yum: pkg=httpd state=latest
- name: write the apache config file
template: src=/srv/httpd.j2 dest=/etc/httpd.conf
notify:
- restart apache
- name: ensure apache is running
service: name=httpd state=started
handlers:
- name: restart apache
service: name=httpd state=restarted
This designates the following behaviors, for each role 'x':
Below, we'll break down what the various features of the playbook language are.
- If roles/x/tasks/main.yml exists, tasks listed therein will be added to the play
- If roles/x/handlers/main.yml exists, handlers listed therein will be added to the play
- If roles/x/vars/main.yml exists, variables listed therein will be added to the play
- If roles/x/meta/main.yml exists, any role dependencies listed therein will be added to the list of roles (1.3 and later)
- Any copy tasks can reference files in roles/x/files/ without having to path them relatively or absolutely
- Any script tasks can reference scripts in roles/x/files/ without having to path them relatively or absolutely
- Any template tasks can reference files in roles/x/templates/ without having to path them relatively or absolutely
Basics
``````
..note::
Role dependencies are discussed below.
Hosts and Users
+++++++++++++++
If any files are not present, they are just ignored. So it's ok to not have a 'vars/' subdirectory for the role,
for instance.
For each play in a playbook, you get to choose which machines in your infrastructure
to target and what remote user to complete the steps (called tasks) as.
Note, you are still allowed to list tasks, vars_files, and handlers "loose" in playbooks without using roles,
but roles are a good organizational feature and are highly recommended. if there are loose things in the playbook,
the roles are evaluated first.
The `hosts` line is a list of one or more groups or host patterns,
separated by colons, as described in the :ref:`patterns`
documentation. The `remote_user` is just the name of the user account::
Also, should you wish to parameterize roles, by adding variables, you can do so, like this::
---
- hosts: webservers
remote_user: root
..Note::
The `remote_user` parameter was formerly called just `user`. It was renamed in Ansible 1.4 to make it more distinguishable from the `user` module (used to create users on remote systems).
Support for running things from sudo is also available::
When you start to think about it -- tasks, handlers, variables, and so -- begin to form larger concepts. You start to think about modelling
what something is, rather than how to make something look like something. It's no longer "apply this handful of THINGS" to these hosts, you say "these hosts are a dbservers" or "these hosts are webservers". In programming, we might call that 'encapsulating' how things work. For instance,
you can drive a car without knowing how the engine works.
Playbook Language Example
`````````````````````````
Roles in Ansible build on the idea of include files and combine them to form clean, reusable abstractions -- they allow you to focus
more on the big picture and only dive down into the details when needed.
Playbooks are expressed in YAML format and have a minimum of syntax.
Each playbook is composed of one or more 'plays' in a list.
We'll start with understanding includes so roles make more sense, but our ultimate goal should be understanding roles -- roles
are great and you should use them every time you write playbooks.
The goal of a play is to map a group of hosts to some well defined roles, represented by
things ansible calls tasks. At a basic level, a task is nothing more than a call
to an ansible module, which you should have learned about in earlier chapters.
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
server group, then more commands back on the webservers group, etc.
For starters, here's a playbook that contains just one play::
---
- hosts: webservers
vars:
http_port: 80
max_clients: 200
remote_user: root
tasks:
- name: ensure apache is at the latest version
yum: pkg=httpd state=latest
- name: write the apache config file
template: src=/srv/httpd.j2 dest=/etc/httpd.conf
notify:
- restart apache
- name: ensure apache is running
service: name=httpd state=started
handlers:
- name: restart apache
service: name=httpd state=restarted
Below, we'll break down what the various features of the playbook language are.
Basics
``````
Hosts and Users
+++++++++++++++
For each play in a playbook, you get to choose which machines in your infrastructure
to target and what remote user to complete the steps (called tasks) as.
The `hosts` line is a list of one or more groups or host patterns,
separated by colons, as described in the :ref:`patterns`
documentation. The `remote_user` is just the name of the user account::
---
- hosts: webservers
remote_user: root
..Note::
The `remote_user` parameter was formerly called just `user`. It was renamed in Ansible 1.4 to make it more distinguishable from the `user` module (used to create users on remote systems).
Support for running things from sudo is also available::
---
- hosts: webservers
remote_user: yourname
sudo: yes
You can also use sudo on a particular task instead of the whole play::
---
- hosts: webservers
remote_user: yourname
tasks:
- service: name=nginx state=started
sudo: yes
You can also login as you, and then sudo to different users than root::
---
- hosts: webservers
remote_user: yourname
sudo: yes
sudo_user: postgres
If you need to specify a password to sudo, run `ansible-playbook` with ``--ask-sudo-pass`` (`-K`).
If you run a sudo playbook and the playbook seems to hang, it's probably stuck at the sudo prompt.
Just `Control-C` to kill it and run it again with `-K`.
..important::
When using `sudo_user` to a user other than root, the module
arguments are briefly written into a random tempfile in /tmp.
These are deleted immediately after the command is executed. This
only occurs when sudoing from a user like 'bob' to 'timmy', not
when going from 'bob' to 'root', or logging in directly as 'bob' or
'root'. If this concerns you that this data is briefly readable
(not writeable), avoid transferring uncrypted passwords with
`sudo_user` set. In other cases, '/tmp' is not used and this does
not come into play. Ansible also takes care to not log password
parameters.
Vars section
++++++++++++
The `vars` section contains a list of variables and values that can be used in the plays, like this::
---
- hosts: webservers
remote_user: root
vars:
http_port: 80
van_halen_port: 5150
other: 'magic'
..note::
You can also keep variables in separate files and include them alongside inline `vars` with a `vars_files` declaration
in the play. See the `Advanced Playbooks chapter <http://www.ansibleworks.com/docs/playbooks2.html#variable-file-separation>`_
for more info.
These variables can be used later in the playbook like this::
{{ varname }}
Variables are passed through the Jinja2 templating engine. Any valid Jinja2
expression can be used between the curly braces, including the use of filters
to modify the variable (for example, `{{ varname|int }}` ensures the variable is
interpreted as an integer).
Jinja2 expressions are very similar to Python and even if you are not working
with Python you should feel comfortable with them. See the `Jinja2 documentation
<http://jinja.pocoo.org/docs/templates/>`_ to learn more about the syntax.
Please note that Jinja2 loops and conditionals are only useful in Ansible
templates, not in playbooks. Use the 'when' and 'with' keywords for
conditionals and loops in Ansible playbooks.
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', which are documented under 'setup' in the module documentation. Additionally,
facts can be gathered by ohai and facter if they are installed. Facter variables are prefixed with ``facter_`` and Ohai variables are prefixed with ``ohai_``. These add extra dependencies and are only there for ease of users
porting over from those other configuration systems. Finally, it's possible to drop files
on to the remote systems that provide additional sources of fact data, see "Facts.d" as documented
in the Advanced Playbooks section.
How about an example. If I wanted to write the hostname into the /etc/motd file, I could say::