Docs: User Guide overhaul, part 3 (#66371)

pull/66674/head
Alicia Cozine 4 years ago committed by Sandra McCann
parent 20eb1dca99
commit 0b503f6057

@ -9,8 +9,7 @@ If Ansible modules are the tools in your workshop, playbooks are your instructio
At a basic level, playbooks can be used to manage configurations of and deployments to remote machines. At a more advanced level, they can sequence multi-tier rollouts involving rolling updates, and can delegate actions to other hosts, interacting with monitoring servers and load balancers along the way.
While there's a lot of information here, there's no need to learn everything at once. You can start small and pick up more features
over time as you need them.
While there's a lot of information here, there's no need to learn everything at once. You can start small and pick up more features over time as you need them.
Playbooks are designed to be human-readable and are developed in a basic text language. There are multiple
ways to organize playbooks and the files they include, and we'll offer up some suggestions on that and making the most out of Ansible.
@ -21,7 +20,9 @@ You should look at `Example Playbooks <https://github.com/ansible/ansible-exampl
:maxdepth: 2
playbooks_intro
playbooks_best_practices
playbooks_reuse
playbooks_reuse_roles
playbooks_variables
playbooks_templating
playbooks_conditionals
@ -29,5 +30,4 @@ You should look at `Example Playbooks <https://github.com/ansible/ansible-exampl
playbooks_blocks
playbooks_special_topics
playbooks_strategies
playbooks_best_practices
guide_rolling_upgrade

@ -1,29 +1,26 @@
.. _pb-py-compat:
Python Version and Templating
=============================
********************
Python3 in templates
********************
Jinja2 templates leverage Python data types and standard functions. This
makes for a rich set of operations that can be performed on data. However,
this also means that certain specifics of the underlying Python becomes
visible to template authors. Since Ansible playbooks use Jinja2 for templates
and variables, this means that playbook authors need to be aware of these
specifics as well.
Ansible uses Jinja2 to leverage Python data types and standard functions in templates and variables.
You can use these data types and standard functions to perform a rich set of operations on your data. However,
if you use templates, you must be aware of differences between Python versions.
Unless otherwise noted, these differences are only of interest when running
Ansible in Python2 versus Python3. Changes within Python2 and Python3 are
generally small enough that they are not visible at the jinja2 level.
These topics help you design templates that work on both Python2 and Python3. They might also help if you are upgrading from Python2 to Python3. Upgrading within Python2 or Python3 does not usually introduce changes that affect Jinja2 templates.
.. _pb-py-compat-dict-views:
Dictionary Views
----------------
Dictionary views
================
In Python2, the :meth:`dict.keys`, :meth:`dict.values`, and :meth:`dict.items`
methods returns a list. Jinja2 returns that to Ansible via a string
representation that Ansible can turn back into a list. In Python3, those
methods return a :ref:`dictionary view <python3:dict-views>` object. The
string representation that Jinja2 returns for dictionary views cannot be parsed back
methods return a list. Jinja2 returns that to Ansible via a string
representation that Ansible can turn back into a list.
In Python3, those methods return a :ref:`dictionary view <python3:dict-views>` object. The
string representation that Jinja2 returns for dictionary views cannot be parsed back
into a list by Ansible. It is, however, easy to make this portable by
using the :func:`list <jinja2:list>` filter whenever using :meth:`dict.keys`,
:meth:`dict.values`, or :meth:`dict.items`::
@ -43,13 +40,11 @@ using the :func:`list <jinja2:list>` filter whenever using :meth:`dict.keys`,
.. _pb-py-compat-iteritems:
dict.iteritems()
----------------
================
Python2 dictionaries have :meth:`~dict.iterkeys`, :meth:`~dict.itervalues`, and :meth:`~dict.iteritems` methods.
In Python2, dictionaries have :meth:`~dict.iterkeys`,
:meth:`~dict.itervalues`, and :meth:`~dict.iteritems` methods. These methods
have been removed in Python3. Playbooks and Jinja2 templates should use
:meth:`dict.keys`, :meth:`dict.values`, and :meth:`dict.items` in order to be
compatible with both Python2 and Python3::
Python3 dictionaries do not have these methods. Use :meth:`dict.keys`, :meth:`dict.values`, and :meth:`dict.items` to make your playbooks and templates compatible with both Python2 and Python3::
vars:
hosts:

@ -1,72 +1,179 @@
.. _playbooks_reuse:
Creating Reusable Playbooks
===========================
**************************
Re-using Ansible artifacts
**************************
.. toctree::
:maxdepth: 1
You can write a simple playbook in one very large file, and most users learn the one-file approach first. However, breaking tasks up into different files is an excellent way to organize complex sets of tasks and reuse them. Smaller, more distributed artifacts let you re-use the same variables, tasks, and plays in multiple playbooks to address different use cases. You can use distributed artifacts across multiple parent playbooks or even multiple times within one playbook. For example, you might want to update your customer database as part of several different playbooks. If you put all the tasks related to updating your database in a tasks file, you can re-use them in many playbooks while only maintaining them in one place.
playbooks_reuse_includes
playbooks_reuse_roles
.. contents::
:local:
While it is possible to write a playbook in one very large file (and you might start out learning playbooks this way), eventually you'll want to reuse files and start to organize things. In Ansible, there are three ways to do this: includes, imports, and roles.
Creating re-usable files and roles
==================================
Includes and imports (added in Ansible version 2.4) allow users to break up large playbooks into smaller files, which can be used across multiple parent playbooks or even multiple times within the same Playbook.
Ansible offers four distributed, re-usable artifacts: variables files, task files, playbooks, and roles.
Roles allow more than just tasks to be packaged together and can include variables, handlers, or even modules and other plugins. Unlike includes and imports, roles can also be uploaded and shared via Ansible Galaxy.
- A variables file contains only variables.
- A task file contains only tasks.
- A playbook contains at least one play, and may contain variables, tasks, and other content. You can re-use tightly focused playbooks, but you can only re-use them statically, not dynamically.
- A role contains a set of related tasks, variables, defaults, handlers, and even modules or other plugins in a defined file-tree. Unlike variables files, task files, or playbooks, roles can be easily uploaded and shared via Ansible Galaxy. See :ref:`playbooks_reuse_roles` for details about creating and using roles.
.. versionadded:: 2.4
Re-using playbooks
==================
You can incorporate multiple playbooks into a master playbook. However, you can only use imports to re-use playbooks. For example:
.. code-block:: yaml
- import_playbook: webservers.yml
- import_playbook: databases.yml
Importing incorporates playbooks in other playbooks statically. Ansible runs the plays and tasks in each imported playbook in the order they are listed, just as if they had been defined directly in the master playbook.
Re-using files and roles
========================
Ansible offers two ways to re-use files and roles in a playbook: dynamic and static.
- For dynamic re-use, add an ``include_*`` task in the tasks section of a play:
- :ref:`include_role <include_role_module>`
- :ref:`include_tasks <include_tasks_module>`
- :ref:`include_vars <include_vars_module>`
- For static re-use, add an ``import_*`` task in the tasks section of a play:
- :ref:`import_role <import_role_module>`
- :ref:`import_tasks <import_tasks_module>`
Task include and import statements can be used at arbitrary depth.
You can still use the bare :ref:`roles <roles_keyword>` keyword at the play level to incorporate a role in a playbook statically. However, the bare :ref:`include <include_module>` keyword, once used for both task files and playbook-level includes, is now deprecated.
Includes: dynamic re-use
------------------------
Including roles, tasks, or variables adds them to a playbook dynamically. Ansible processes included files and roles as they come up in a playbook, so included tasks can be affected by the results of earlier tasks within the top-level playbook. Included roles and tasks are similar to handlers - they may or may not run, depending on the results of other tasks in the top-level playbook. The primary advantage of using ``include_*`` statements is looping. When a loop is used with an include, the included tasks or role will be executed once for each item in the loop.
You can pass variables into includes. See :ref:`ansible_variable_precedence` for more details on variable inheritance and precedence.
Imports: static re-use
----------------------
Importing roles, tasks, or playbooks adds them to a playbook statically. Ansible pre-processes imported files and roles before it runs any tasks in a playbook, so imported content is never affected by other tasks within the top-level playbook.
You can pass variables to imports. You must pass variables if you want to run an imported file more than once in a playbook. For example:
.. code-block:: yaml
tasks:
- import_tasks: wordpress.yml
vars:
wp_user: timmy
- import_tasks: wordpress.yml
vars:
wp_user: alice
- import_tasks: wordpress.yml
vars:
wp_user: bob
See :ref:`ansible_variable_precedence` for more details on variable inheritance and precedence.
.. _dynamic_vs_static:
Dynamic vs. Static
``````````````````
Comparing includes and imports: dynamic vs. static
--------------------------------------------------
Each approach to re-using distributed Ansible artifacts has advantages and limitations. You may choose dynamic re-use for some playbooks and static re-use for others. Although you can use both dynamic and static re-use in a single playbook, it is best to select one approach per playbook. Mixing static and dynamic re-use can introduce difficult-to-diagnose bugs into your playbooks. This table summarizes the main differences so you can choose the best approach for each playbook you create.
.. table::
:class: documentation-table
========================= ======================================== ========================================
.. Include_* Import_*
========================= ======================================== ========================================
Type of re-use Dynamic Static
When processed At runtime, when encountered Pre-processed during playbook parsing
Task or play All includes are tasks ``import_playbook`` cannot be a task
Task options Apply only to include task itself Apply to all child tasks in import
Calling from loops Executed once for each loop item Cannot be used in a loop
Using ``--list-tags`` Tags within includes not listed All tags appear with ``--list-tags``
Using ``--list-tasks`` Tasks within includes not listed All tasks appear with ``--list-tasks``
Notifying handlers Cannot trigger handlers within includes Can trigger individual imported handlers
Using ``--start-at-task`` Cannot start at tasks within includes Can start at imported tasks
Ansible has two modes of operation for reusable content: dynamic and static.
Using inventory variables Can ``include_*: {{ inventory_var }}`` Cannot ``import_*: {{ inventory_var }}``
In Ansible 2.0, the concept of *dynamic* includes was introduced. Due to some limitations with making all includes dynamic in this way, the ability to force includes to be *static* was introduced in Ansible 2.1. Because the *include* task became overloaded to encompass both static and dynamic syntaxes, and because the default behavior of an include could change based on other options set on the Task, Ansible 2.4 introduces the concept of ``include`` vs. ``import``.
With playbooks No ``include_playbook`` Can import full playbooks
If you use any ``include*`` Task (``include_tasks``, ``include_role``, etc.), it will be *dynamic*.
If you use any ``import*`` Task (``import_playbook``, ``import_tasks``, etc.), it will be *static*.
With variables files Can include variables files Use ``vars_files:`` to import variables
The bare ``include`` task (which was used for both Task files and Playbook-level includes) is still available, however it is now considered *deprecated*.
========================= ======================================== ========================================
Differences Between Dynamic and Static
``````````````````````````````````````
Re-using tasks as handlers
==========================
The two modes of operation are pretty simple:
You can also use includes and imports in the :ref:`handlers` section of a playbook. For instance, if you want to define how to restart Apache, you only have to do that once for all of your playbooks. You might make a ``restarts.yml`` file that looks like:
* Dynamic includes are processed during runtime at the point in which that task is encountered.
* Ansible pre-processes all static imports during Playbook parsing time.
.. code-block:: yaml
When it comes to Ansible task options like ``tags`` and conditional statements (``when:``):
# restarts.yml
- name: restart apache
service:
name: apache
state: restarted
* For dynamic includes, the task options will *only* apply to the dynamic task as it is evaluated, and will not be copied to child tasks.
* For static imports, the parent task options will be copied to all child tasks contained within the import.
- name: restart mysql
service:
name: mysql
state:restarted
.. note::
Roles are a somewhat special case. Prior to Ansible 2.3, roles were always statically included via the special ``roles:`` option for a given play and were always executed first before any other play tasks (unless ``pre_tasks`` were used). Roles can still be used this way, however, Ansible 2.3 introduced the ``include_role`` option to allow roles to be executed inline with other tasks.
You can trigger handlers from either an import or an include, but the procedure is different for each method of re-use. If you include the file, you must notify the include itself, which triggers all the tasks in ``restarts.yml``. If you import the file, you must notify the individual task(s) within ``restarts.yml``. You can mix direct tasks and handlers with included or imported tasks and handlers.
Tradeoffs and Pitfalls Between Includes and Imports
```````````````````````````````````````````````````
Triggering included (dynamic) handlers
--------------------------------------
Using ``include*`` vs. ``import*`` has some advantages as well as some tradeoffs which users should consider when choosing to use each:
Includes are executed at run-time, so the name of the include exists during play execution, but the included tasks do not exist until the include itself is triggered. To use the ``restart apache`` task with dynamic re-use, refer to the name of the include itself. This approach triggers all tasks in the included file as handlers. For example, with the task file shown above:
The primary advantage of using ``include*`` statements is the support of looping. When a loop is used with an include, the included tasks or role will be executed once for each item in the loop.
.. code-block:: yaml
Using ``include*`` does have some limitations when compared to ``import*`` statements:
- trigger an included (dynamic) handler
hosts: localhost
handlers:
- name: restart services
include_tasks: restarts.yml
tasks:
- command: "true"
notify: restart services
* Tags which only exist inside a dynamic include will not show up in ``--list-tags`` output.
* Tasks which only exist inside a dynamic include will not show up in ``--list-tasks`` output.
* You cannot use ``notify`` to trigger a handler name which comes from inside a dynamic include (see note below).
* You cannot use ``--start-at-task`` to begin execution at a task inside a dynamic include.
Triggering imported (static) handlers
-------------------------------------
Using ``import*`` can also have some limitations when compared to dynamic includes:
Imports are processed before the play begins, so the name of the import no longer exists during play execution, but the names of the individual imported tasks do exist. To use the ``restart apache`` task with static re-use, refer to the name of each task or tasks within the imported file. For example, with the task file shown above:
* As noted above, loops cannot be used with imports at all.
* When using variables for the target file or role name, variables from inventory sources (host/group vars, etc.) cannot be used.
* Handlers using ``import*`` will not be triggered when notified by their name, as importing overwrites the handler's named task with the imported task list.
.. code-block:: yaml
.. note::
Regarding the use of ``notify`` for dynamic tasks: it is still possible to trigger the dynamic include itself, which would result in all tasks within the include being run.
- trigger an imported (static) handler
hosts: localhost
handlers:
- name: restart services
import_tasks: restarts.yml
tasks:
- command: "true"
notify: restart apache
- command: "true"
notify: restart mysql
.. seealso::

@ -1,102 +1,12 @@
:orphan:
.. _playbooks_reuse_includes:
Including and Importing
Including and importing
=======================
.. contents:: Topics
Includes vs. Imports
````````````````````
As noted in :ref:`playbooks_reuse`, include and import statements are very similar, however the Ansible executor engine treats them very differently.
- All ``import*`` statements are pre-processed at the time playbooks are parsed.
- All ``include*`` statements are processed as they are encountered during the execution of the playbook.
Please refer to :ref:`playbooks_reuse` for documentation concerning the trade-offs one may encounter when using each type.
Also be aware that this behaviour changed in 2.4. Prior to Ansible 2.4, only ``include`` was available and it behaved differently depending on context.
.. versionadded:: 2.4
Importing Playbooks
```````````````````
It is possible to include playbooks inside a master playbook. For example::
- import_playbook: webservers.yml
- import_playbook: databases.yml
The plays and tasks in each playbook listed will be run in the order they are listed, just as if they had been defined here directly.
Prior to 2.4 only ``include`` was available and worked for both playbooks and tasks as both import and include.
.. versionadded:: 2.4
Including and Importing Task Files
``````````````````````````````````
Breaking tasks up into different files is an excellent way to organize complex sets of tasks or reuse them. A task file simply contains a flat list of tasks::
# common_tasks.yml
- name: placeholder foo
command: /bin/foo
- name: placeholder bar
command: /bin/bar
You can then use ``import_tasks`` or ``include_tasks`` to execute the tasks in a file in the main task list::
tasks:
- import_tasks: common_tasks.yml
# or
- include_tasks: common_tasks.yml
You can also pass variables into imports and includes::
tasks:
- import_tasks: wordpress.yml
vars:
wp_user: timmy
- import_tasks: wordpress.yml
vars:
wp_user: alice
- import_tasks: wordpress.yml
vars:
wp_user: bob
See :ref:`ansible_variable_precedence` for more details on variable inheritance and precedence.
Task include and import statements can be used at arbitrary depth.
.. note::
- Static and dynamic can be mixed, however this is not recommended as it may lead to difficult-to-diagnose bugs in your playbooks.
- The ``key=value`` syntax for passing variables to import and include is deprecated. Use YAML ``vars:`` instead.
Includes and imports can also be used in the ``handlers:`` section. For instance, if you want to define how to restart Apache, you only have to do that once for all of your playbooks. You might make a ``handlers.yml`` that looks like::
# more_handlers.yml
- name: restart apache
service:
name: apache
state: restarted
And in your main playbook file::
handlers:
- include_tasks: more_handlers.yml
# or
- import_tasks: more_handlers.yml
.. note::
Be sure to refer to the limitations/trade-offs for handlers noted in :ref:`playbooks_reuse`.
You can mix in includes along with your regular non-included tasks and handlers.
Including and Importing Roles
`````````````````````````````
The content on this page has been moved to :ref:`playbooks_reuse`.
Please refer to :ref:`playbooks_reuse_roles` for details on including and importing roles.
.. seealso::

@ -1,19 +1,22 @@
.. _playbooks_reuse_roles:
*****
Roles
=====
*****
.. contents:: Topics
Roles let you automatically load related vars_files, tasks, handlers, and other Ansible artifacts based on a known file structure. Once you group your content in roles, you can easily re-use them and share them with other users.
.. versionadded:: 1.2
.. contents::
:local:
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.
Role directory structure
========================
Role Directory Structure
````````````````````````
An Ansible role has a defined directory structure with seven main standard directories. You must include at least one of these directories in each role. You can omit any directories the role does not use. For example:
Example project structure::
.. code-block:: text
# playbooks
site.yml
webservers.yml
fooservers.yml
@ -31,100 +34,112 @@ Example project structure::
defaults/
meta/
Roles expect files to be in certain directory names. Roles must include at least one of these directories, however it is perfectly fine to exclude any which are not being used. When in use, each directory must contain a ``main.yml`` file, which contains the relevant content:
Each directory within a role must contain a ``main.yml`` file with relevant content:
- ``tasks`` - contains the main list of tasks to be executed by the role.
- ``handlers`` - contains handlers, which may be used by this role or even anywhere outside this role.
- ``defaults`` - default variables for the role (see :ref:`playbooks_variables` for more information).
- ``vars`` - other variables for the role (see :ref:`playbooks_variables` for more information).
- ``files`` - contains files which can be deployed via this role.
- ``templates`` - contains templates which can be deployed via this role.
- ``meta`` - defines some meta data for this role. See below for more details.
- ``tasks/main.yml`` - the main list of tasks that the role executes.
- ``handlers/main.yml`` - handlers, which may be used within or outside this role.
- ``defaults/main.yml`` - default variables for the role (see :ref:`playbooks_variables` for more information). These variables have the lowest priority of any variables available, and can be easily overridden by any other variable, including inventory variables.
- ``vars/main.yml`` - other variables for the role (see :ref:`playbooks_variables` for more information).
- ``files/main.yml`` - files that the role deploys.
- ``templates/main.yml`` - templates that the role deploys.
- ``meta/main.yml`` - metadata for the role, including role dependencies.
Other YAML files may be included in certain directories. For example, it is common practice to have platform-specific tasks included from the ``tasks/main.yml`` file::
You can add other YAML files in some directories. For example, you can place platform-specific tasks in separate files and refer to them in the ``tasks/main.yml`` file:
.. code-block:: yaml
# roles/example/tasks/main.yml
- name: added in 2.4, previously you used 'include'
- name: install the correct web server for RHEL
import_tasks: redhat.yml
when: ansible_facts['os_family']|lower == 'redhat'
- import_tasks: debian.yml
- name: install the correct web server for debian
import_tasks: debian.yml
when: ansible_facts['os_family']|lower == 'debian'
# roles/example/tasks/redhat.yml
- yum:
- install web server
yum:
name: "httpd"
state: present
# roles/example/tasks/debian.yml
- apt:
- install web server
apt:
name: "apache2"
state: present
Roles may also include modules and other plugin types. For more information, please refer to the :ref:`embedding_modules_and_plugins_in_roles` section below.
Roles may also include modules and other plugin types in a directory called ``library``. For more information, please refer to :ref:`embedding_modules_and_plugins_in_roles` below.
.. _role_search_path:
Storing and finding roles
=========================
By default, Ansible looks for roles in two locations:
- in a directory called ``roles/``, relative to the playbook file
- in ``/etc/ansible/roles``
Using Roles
```````````
If you store your roles in a different location, set the :ref:`roles_path <DEFAULT_ROLES_PATH>` configuration option so Ansible can find your roles. Checking shared roles into a single location makes them easier to use in multiple playbooks. See :ref:`intro_configuration` for details about managing settings in ansible.cfg.
The classic (original) way to use roles is via the ``roles:`` option for a given play::
Alternatively, you can call a role with a fully qualified path:
.. code-block:: yaml
---
- hosts: webservers
roles:
- common
- webservers
- role: '/path/to/my/roles/common'
This designates the following behaviors, for each role 'x':
Using roles
===========
- 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/defaults/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, script, template or include tasks (in the role) can reference files in roles/x/{files,templates,tasks}/ (dir depends on task) without having to path them relatively or absolutely.
You can use roles in three ways:
When used in this manner, the order of execution for your playbook is as follows:
- at the play level with the ``roles`` option,
- at the tasks level with ``include_role``, or
- at the tasks level with ``import_role``
- Any ``pre_tasks`` defined in the play.
- Any handlers triggered so far will be run.
- Each role listed in ``roles`` will execute in turn. Any role dependencies defined in the roles ``meta/main.yml`` will be run first, subject to tag filtering and conditionals.
- Any ``tasks`` defined in the play.
- Any handlers triggered so far will be run.
- Any ``post_tasks`` defined in the play.
- Any handlers triggered so far will be run.
.. _roles_keyword:
.. note::
See below for more information regarding role dependencies.
Using roles at the play level
-----------------------------
.. note::
If using tags with tasks (described later as a means of only running part of a playbook), be sure to also tag your pre_tasks, post_tasks, and role dependencies and pass those along as well, especially if the pre/post tasks and role dependencies are used for monitoring outage window control or load balancing.
The classic (original) way to use roles is with the ``roles`` option for a given play:
As of Ansible 2.4, you can now use roles inline with any other tasks using ``import_role`` or ``include_role``::
.. code-block:: yaml
---
- hosts: webservers
tasks:
- debug:
msg: "before we run our role"
- import_role:
name: example
- include_role:
name: example
- debug:
msg: "after we ran our role"
roles:
- common
- webservers
When roles are defined in the classic manner, they are treated as static imports and processed during playbook parsing.
When you use the ``roles`` option at the play level, for each role 'x':
.. note::
The ``include_role`` option was introduced in Ansible 2.3. The usage has changed slightly as of Ansible 2.4 to match the include (dynamic) vs. import (static) usage. See :ref:`dynamic_vs_static` for more details.
- If roles/x/tasks/main.yml exists, Ansible adds the tasks in that file to the play.
- If roles/x/handlers/main.yml exists, Ansible adds the handlers in that file to the play.
- If roles/x/vars/main.yml exists, Ansible adds the variables in that file to the play.
- If roles/x/defaults/main.yml exists, Ansible adds the variables in that file to the play.
- If roles/x/meta/main.yml exists, Ansible adds any role dependencies in that file to the list of roles.
- Any copy, script, template or include tasks (in the role) can reference files in roles/x/{files,templates,tasks}/ (dir depends on task) without having to path them relatively or absolutely.
The name used for the role can be a simple name (see :ref:`role_search_path` below), or it can be a fully qualified path::
When you use the ``roles`` option at the play level, Ansible treats the roles as static imports and processes them during playbook parsing. Ansible executes your playbook in this order:
---
- hosts: webservers
roles:
- role: '/path/to/my/roles/common'
- Any ``pre_tasks`` defined in the play.
- Any handlers triggered by pre_tasks.
- Each role listed in ``roles:``, in the order listed. Any role dependencies defined in the roles ``meta/main.yml`` run first, subject to tag filtering and conditionals. See :ref:`role_dependencies` for more details.
- Any ``tasks`` defined in the play.
- Any handlers triggered by the roles or tasks.
- Any ``post_tasks`` defined in the play.
- Any handlers triggered by post_tasks.
.. note::
If using tags with tasks in a role, be sure to also tag your pre_tasks, post_tasks, and role dependencies and pass those along as well, especially if the pre/post tasks and role dependencies are used for monitoring outage window control or load balancing. See :ref:`tags` for details on adding and using tags.
Roles can accept other keywords::
You can pass other keywords to the ``roles`` option:
.. code-block:: yaml
---
- hosts: webservers
@ -134,12 +149,37 @@ Roles can accept other keywords::
vars:
dir: '/opt/a'
app_port: 5000
tags: typeA
- role: foo_app_instance
vars:
dir: '/opt/b'
app_port: 5001
tags: typeB
When you add a tag to the ``role`` option, Ansible applies the tag to ALL tasks within the role.
Including roles: dynamic re-use
-------------------------------
Or, using the newer syntax::
You can re-use roles dynamically anywhere in the ``tasks`` section of a play using ``include_role``. While roles added in a ``roles`` section run before any other tasks in a playbook, included roles run in the order they are defined. If there are other tasks before an ``include_role`` task, the other tasks will run first.
To include a role:
.. code-block:: yaml
---
- hosts: webservers
tasks:
- debug:
msg: "this task runs before the example role"
- include_role:
name: example
- debug:
msg: "this task runs after the example role"
You can pass other keywords, including variables and tags, when including roles:
.. code-block:: yaml
---
- hosts: webservers
@ -149,9 +189,14 @@ Or, using the newer syntax::
vars:
dir: '/opt/a'
app_port: 5000
tags: typeA
...
You can conditionally import a role and execute its tasks::
When you add a :ref:`tag <tags>` to an ``include_role`` task, Ansible applies the tag `only` to the include itself. This means you can pass ``--tags`` to run only selected tasks from the role, if those tasks themselves have the same tag as the include statement. See :ref:`selective_reuse` for details.
You can conditionally include a role:
.. code-block:: yaml
---
- hosts: webservers
@ -160,67 +205,61 @@ You can conditionally import a role and execute its tasks::
name: some_role
when: "ansible_facts['os_family'] == 'RedHat'"
Importing roles: static re-use
------------------------------
You can re-use roles statically anywhere in the ``tasks`` section of a play using ``import_role``. The behavior is the same as using the ``roles`` keyword. For example:
Finally, you may wish to assign tags to the tasks inside the roles you specify. You can do::
---
- hosts: webservers
roles:
- role: foo
tags:
- bar
- baz
# using YAML shorthand, this is equivalent to the above:
- { role: foo, tags: ["bar", "baz"] }
Or, again, using the newer syntax::
.. code-block:: yaml
---
- hosts: webservers
tasks:
- debug:
msg: "before we run our role"
- import_role:
name: foo
tags:
- bar
- baz
name: example
- debug:
msg: "after we ran our role"
.. note::
This *tags all of the tasks in that role with the tags specified*, appending to any tags that are specified inside the role.
You can pass other keywords, including variables and tags, when importing roles:
On the other hand you might just want to tag the import of the role itself::
.. code-block:: yaml
---
- hosts: webservers
tasks:
- include_role:
name: bar
tags:
- foo
- import_role:
name: foo_app_instance
vars:
dir: '/opt/a'
app_port: 5000
...
.. note:: The tags in this example will *not* be added to tasks inside an ``include_role``, you can use a surrounding ``block`` directive to do both.
When you add a tag to an ``import_role`` statement, Ansible applies the tag to `all` tasks within the role. See :ref:`tag_inheritance` for details.
.. note:: There is no facility to import a role while specifying a subset of tags to execute. If you find yourself building a role with lots of tags and you want to call subsets of the role at different times, you should consider just splitting that role into multiple roles.
Running a role multiple times in one playbook
=============================================
Role Duplication and Execution
``````````````````````````````
Ansible only executes each role once, even if you define it multiple times, unless the parameters defined on the role are different for each definition. For example, Ansible only runs the role ``foo`` once in a play like this:
Ansible will only allow a role to execute once, even if defined multiple times, if the parameters defined on the role are not different for each definition. For example::
.. code-block:: yaml
---
- hosts: webservers
roles:
- foo
- bar
- foo
Given the above, the role ``foo`` will only be run once.
You have two options to force Ansible to run a role more than once:
To make roles run more than once, there are two options:
#. Pass different parameters in each role definition.
#. Add ``allow_duplicates: true`` to the ``meta/main.yml`` file for the role.
1. Pass different parameters in each role definition.
2. Add ``allow_duplicates: true`` to the ``meta/main.yml`` file for the role.
Example 1 - passing different parameters:
Example 1 - passing different parameters::
.. code-block:: yaml
---
- hosts: webservers
@ -230,9 +269,11 @@ Example 1 - passing different parameters::
message: "first"
- { role: foo, vars: { message: "second" } }
In this example, because each role definition has different parameters, ``foo`` will run twice.
In this example, because each role definition has different parameters, Ansible runs ``foo`` twice.
Example 2 - using ``allow_duplicates: true``:
Example 2 - using ``allow_duplicates: true``::
.. code-block:: yaml
# playbook.yml
---
@ -245,24 +286,20 @@ Example 2 - using ``allow_duplicates: true``::
---
allow_duplicates: true
In this example, ``foo`` will run twice because we have explicitly enabled it to do so.
In this example, Ansible runs ``foo`` twice because we have explicitly enabled it to do so.
Role Default Variables
``````````````````````
.. _role_dependencies:
.. versionadded:: 1.3
Using role dependencies
=======================
Role default variables allow you to set default variables for included or dependent roles (see below). To create
defaults, simply add a ``defaults/main.yml`` file in your role directory. These variables will have the lowest priority
of any variables available, and can be easily overridden by any other variable, including inventory variables.
Role dependencies let you automatically pull in other roles when using a role. Ansible does not execute role dependencies when you include or import a role. You must use the ``roles`` keyword if you want Ansible to execute role dependencies.
Role Dependencies
`````````````````
Role dependencies are stored in the ``meta/main.yml`` file within the role directory. This file should contain a list of roles and parameters to insert before the specified role. For example:
.. versionadded:: 1.3
Role dependencies allow you to automatically pull in other roles when using a role. Role dependencies are stored in the ``meta/main.yml`` file contained within the role directory, as noted above. This file should contain a list of roles and parameters to insert before the specified role, such as the following in an example ``roles/myapp/meta/main.yml``::
.. code-block:: yaml
# roles/myapp/meta/main.yml
---
dependencies:
- role: common
@ -276,15 +313,16 @@ Role dependencies allow you to automatically pull in other roles when using a ro
dbname: blarg
other_parameter: 12
.. note::
Role dependencies must use the classic role definition style.
Ansible always executes role dependencies before the role that includes them. Ansible executes recursive role dependencies as well. If one role depends on a second role, and the second role depends on a third role, Ansible executes the third role, then the second role, then the first role.
Role dependencies are always executed before the role that includes them, and may be recursive. Dependencies also follow the duplication rules specified above. If another role also lists it as a dependency, it will not be run again based on the same rules given above. See :ref:`Galaxy role dependencies <galaxy_dependencies>` for more details.
Running role dependencies multiple times
----------------------------------------
.. note::
Always remember that when using ``allow_duplicates: true``, it needs to be in the dependent role's ``meta/main.yml``, not the parent.
Ansible treats duplicate role dependencies like duplicate roles listed under ``roles:``: Ansible only executes role dependencies once, even if defined multiple times, unless the parameters defined on the role are different for each definition. If two roles in a playbook both list a third role as a dependency, Ansible only runs that role dependency once, unless you pass different parameters or use ``allow_duplicates: true`` in the dependent (third) role. See :ref:`Galaxy role dependencies <galaxy_dependencies>` for more details.
For example, a role named ``car`` depends on a role named ``wheel`` as follows::
For example, a role named ``car`` depends on a role named ``wheel`` as follows:
.. code-block:: yaml
---
dependencies:
@ -301,20 +339,25 @@ For example, a role named ``car`` depends on a role named ``wheel`` as follows::
vars:
n: 4
And the ``wheel`` role depends on two roles: ``tire`` and ``brake``. The ``meta/main.yml`` for wheel would then contain the following::
And the ``wheel`` role depends on two roles: ``tire`` and ``brake``. The ``meta/main.yml`` for wheel would then contain the following:
.. code-block:: yaml
---
dependencies:
- role: tire
- role: brake
And the ``meta/main.yml`` for ``tire`` and ``brake`` would contain the following::
And the ``meta/main.yml`` for ``tire`` and ``brake`` would contain the following:
.. code-block:: yaml
---
allow_duplicates: true
The resulting order of execution would be as follows:
The resulting order of execution would be as follows::
.. code-block:: text
tire(n=1)
brake(n=1)
@ -325,27 +368,23 @@ The resulting order of execution would be as follows::
...
car
Note that we did not have to use ``allow_duplicates: true`` for ``wheel``, because each instance defined by ``car`` uses different parameter values.
To use ``allow_duplicates: true`` with role dependencies, you must specify it for the dependent role, not for the parent role. In the example above, ``allow_duplicates: true`` appears in the ``meta/main.yml`` of the ``tire`` and ``brake`` roles. The ``wheel`` role does not require ``allow_duplicates: true``, because each instance defined by ``car`` uses different parameter values.
.. note::
Variable inheritance and scope are detailed in the :ref:`playbooks_variables`.
See :ref:`playbooks_variables` for details on how Ansible chooses among variable values defined in different places (variable inheritance and scope).
.. _embedding_modules_and_plugins_in_roles:
Embedding Modules and Plugins In Roles
``````````````````````````````````````
Embedding modules and plugins in roles
======================================
This is an advanced topic that should not be relevant for most users.
If you write a custom module (see :ref:`developing_modules`) or a plugin (see :ref:`developing_plugins`), you may wish to distribute it as part of a role.
Generally speaking, Ansible as a project is very interested in taking high-quality modules into ansible core for inclusion, so this shouldn't be the norm, but it's quite easy to do.
A good example for this is if you worked at a company called AcmeWidgets, and wrote an internal module that helped configure your internal software, and you wanted other
people in your organization to easily use this module -- but you didn't want to tell everyone how to configure their Ansible library path.
If you write a custom module (see :ref:`developing_modules`) or a plugin (see :ref:`developing_plugins`), you might wish to distribute it as part of a role. For example, if you write a module that helps configure your company's internal software, and you want other people in your organization to use this module, but you do not want to tell everyone how to configure their Ansible library path, you can include the module in your internal_config role.
Alongside the 'tasks' and 'handlers' structure of a role, add a directory named 'library'. In this 'library' directory, then include the module directly inside of it.
Assuming you had this::
Assuming you had this:
.. code-block:: text
roles/
my_custom_modules/
@ -353,7 +392,9 @@ Assuming you had this::
module1
module2
The module will be usable in the role itself, as well as any roles that are called *after* this role, as follows::
The module will be usable in the role itself, as well as any roles that are called *after* this role, as follows:
.. code-block:: yaml
---
- hosts: webservers
@ -362,9 +403,11 @@ The module will be usable in the role itself, as well as any roles that are call
- some_other_role_using_my_custom_modules
- yet_another_role_using_my_custom_modules
This can also be used, with some limitations, to modify modules in Ansible's core distribution, such as to use development versions of modules before they are released in production releases. This is not always advisable as API signatures may change in core components, however, and is not always guaranteed to work. It can be a handy way of carrying a patch against a core module, however, should you have good reason for this. Naturally the project prefers that contributions be directed back to github whenever possible via a pull request.
If necessary, you can also embed a module in a role to modify a module in Ansible's core distribution. For example, you can use the development version of a particular module before it is released in production releases by copying the module and embedding the copy in a role. Use this approach with caution, as API signatures may change in core components, and this workaround is not guaranteed to work.
The same mechanism can be used to embed and distribute plugins in a role, using the same schema. For example, for a filter plugin:
The same mechanism can be used to embed and distribute plugins in a role, using the same schema. For example, for a filter plugin::
.. code-block:: text
roles/
my_custom_filter/
@ -372,26 +415,14 @@ The same mechanism can be used to embed and distribute plugins in a role, using
filter1
filter2
They can then be used in a template or a jinja template in any role called after 'my_custom_filter'
.. _role_search_path:
Role Search Path
````````````````
Ansible will search for roles in the following way:
- A ``roles/`` directory, relative to the playbook file.
- By default, in ``/etc/ansible/roles``
In Ansible 1.4 and later you can configure an additional roles_path to search for roles. Use this to check all of your common roles out to one location, and share them easily between multiple playbook projects. See :ref:`intro_configuration` for details about how to set this up in ansible.cfg.
These filters can then be used in a Jinja template in any role called after 'my_custom_filter'.
Ansible Galaxy
``````````````
Sharing roles: Ansible Galaxy
=============================
`Ansible Galaxy <https://galaxy.ansible.com>`_ is a free site for finding, downloading, rating, and reviewing all kinds of community developed Ansible roles and can be a great way to get a jumpstart on your automation projects.
`Ansible Galaxy <https://galaxy.ansible.com>`_ is a free site for finding, downloading, rating, and reviewing all kinds of community-developed Ansible roles and can be a great way to get a jumpstart on your automation projects.
The client ``ansible-galaxy`` is included in Ansible. The Galaxy client allows you to download roles from Ansible Galaxy, and also provides an excellent default framework for creating your own roles.
The client ``ansible-galaxy`` is included in Ansible. The Galaxy client allows you to download roles from Ansible Galaxy, and also provides an excellent default framework for creating your own roles.
Read the `Ansible Galaxy documentation <https://galaxy.ansible.com/docs/>`_ page for more information
@ -404,17 +435,19 @@ Read the `Ansible Galaxy documentation <https://galaxy.ansible.com/docs/>`_ page
:ref:`working_with_playbooks`
Review the basic Playbook language features
:ref:`playbooks_best_practices`
Various tips about managing playbooks in the real world
Tips for managing playbooks in the real world
:ref:`playbooks_variables`
All about variables in playbooks
Variables in playbooks
:ref:`playbooks_conditionals`
Conditionals in playbooks
:ref:`playbooks_loops`
Loops in playbooks
:ref:`tags`
Using tags to select or skip roles/tasks in long playbooks
:ref:`all_modules`
Learn about available modules
List of available modules
:ref:`developing_modules`
Learn how to extend Ansible by writing your own modules
Extending Ansible by writing your own modules
`GitHub Ansible examples <https://github.com/ansible/ansible-examples>`_
Complete playbook files from the GitHub project source
`Mailing List <https://groups.google.com/group/ansible-project>`_

@ -1,227 +1,410 @@
.. _tags:
****
Tags
====
****
If you have a large playbook, it may become useful to be able to run only
a specific part of it rather than running *everything* in the playbook.
Ansible supports a "tags:" attribute for this reason.
If you have a large playbook, it may be useful to run only specific parts of it instead of running the entire playbook. You can do this with Ansible tags. Using tags to execute or skip selected tasks is a two-step process:
Tags can be applied to *many* structures in Ansible (see "tag inheritance",
below), but its simplest use is with individual tasks. Here is an example
that tags two tasks with different tags::
#. Add tags to your tasks, either individually or with tag inheritance from a block, play, role, or import
#. Select or skip tags when you run your playbook
tasks:
- yum:
name:
- httpd
- memcached
state: present
tags:
- packages
.. contents::
:local:
- template:
src: templates/src.j2
dest: /etc/foo.conf
tags:
- configuration
Adding tags with the tags keyword
=================================
When you execute a playbook, you can filter tasks based on tags in two ways:
You can add tags to a single task or include. You can also add tags to multiple tasks by defining them at the level of a block, play, role, or import. The keyword ``tags`` addresses all these use cases. The ``tags`` keyword always defines tags and adds them to tasks; it does not select or skip tasks for execution. You can only select or skip tasks based on tags at the command line when you run a playbook. See :ref:`using_tags` for more details.
- On the command line, with the ``--tags`` or ``--skip-tags`` options
- In Ansible configuration settings, with the ``TAGS_RUN``
and ``TAGS_SKIP`` options
Adding tags to individual tasks
-------------------------------
For example, if you wanted to just run the "configuration" and "packages" part
of a very long playbook, you can use the ``--tags`` option on the command line::
At the simplest level, you can apply one or more tags to an individual task. You can add tags to tasks in playbooks, in task files, or within a role. Here is an example that tags two tasks with different tags:
ansible-playbook example.yml --tags "configuration,packages"
.. code-block:: yaml
On the other hand, if you want to run a playbook *without* certain tagged
tasks, you can use the ``--skip-tags`` command-line option::
tasks:
- install the servers
yum:
name:
- httpd
- memcached
state: present
tags:
- packages
- webservers
ansible-playbook example.yml --skip-tags "packages"
- configure the service
template:
src: templates/src.j2
dest: /etc/foo.conf
tags:
- configuration
You can see which tasks will be executed with ``--tags`` or ``--skip-tags`` by
combining it with ``--list-tasks``::
You can apply the same tag to more than one individual task. This example tags several tasks with the same tag, "ntp":
ansible-playbook example.yml --tags "configuration,packages" --list-tasks
.. code-block:: yaml
.. warning::
* Fact gathering is tagged with 'always' by default. It is ONLY skipped if
you apply a tag and then use a different tag in ``--tags`` or the same
tag in ``--skip-tags``.
.. _tag_reuse:
Tag Reuse
```````````````
You can apply the same tag to more than one task. When a play is run using
the ``--tags`` command-line option, all tasks with that tag name will be run.
This example tags several tasks with one tag, "ntp"::
---
# file: roles/common/tasks/main.yml
- name: be sure ntp is installed
yum:
name: ntp
state: present
tags: ntp
- name: be sure ntp is configured
template:
src: ntp.conf.j2
dest: /etc/ntp.conf
notify:
- restart ntpd
tags: ntp
- name: be sure ntpd is running and enabled
service:
name: ntpd
state: started
enabled: yes
tags: ntp
---
# file: roles/common/tasks/main.yml
.. _tag_inheritance:
- name: be sure ntp is installed
yum:
name: ntp
state: present
tags: ntp
- name: be sure ntp is configured
template:
src: ntp.conf.j2
dest: /etc/ntp.conf
notify:
- restart ntpd
tags: ntp
- name: be sure ntpd is running and enabled
service:
name: ntpd
state: started
enabled: yes
tags: ntp
- name: be sure file sharing is installed
yum:
name:
- nfs-utils
- nfs-util-lib
state: present
tags: filesharing
If you ran these four tasks in a playbook with ``--tags ntp``, Ansible would run the three tasks tagged ``ntp`` and skip the one task that does not have that tag.
Tag Inheritance
```````````````
.. _tags_on_includes:
Adding ``tags:`` to a play, or to statically imported tasks and roles, adds
those tags to all of the contained tasks. This is referred to as *tag
inheritance*. Tag inheritance is *not* applicable to dynamic inclusions
such as ``include_role`` and ``include_tasks``.
Adding tags to includes
-----------------------
When you apply ``tags:`` attributes to structures other than tasks,
Ansible processes the tag attribute to apply ONLY to the tasks they contain.
Applying tags anywhere other than tasks is just a convenience so you don't
have to tag tasks individually.
You can apply tags to dynamic includes in a playbook. As with tags on an individual task, tags on an ``include_*`` task apply only to the include itself, not to any tasks within the included file or role. If you add ``mytag`` to a dynamic include, then run that playbook with ``--tags mytag``, Ansible runs the include itself, runs any tasks within the included file or role tagged with ``mytag``, and skips any tasks within the included file or role without that tag. See :ref:`selective_reuse` for more details.
This example tags all tasks in the two plays. The first play has all its tasks
tagged with 'bar', and the second has all its tasks tagged with 'foo'::
You add tags to includes the same way you add tags to any other task:
- hosts: all
tags:
- bar
tasks:
...
.. code-block:: yaml
- hosts: all
tags: [ foo ]
tasks:
...
---
# file: roles/common/tasks/main.yml
- name: dynamic re-use of database tasks
include_tasks: db.yml
tags: db
You can add a tag only to the dynamic include of a role. In this example, the ``foo`` tag will `not` apply to tasks inside the ``bar`` role:
.. code-block:: yaml
---
- hosts: webservers
tasks:
- include_role:
name: bar
tags:
- foo
With plays, blocks, the ``role`` keyword, and static imports, Ansible applies tag inheritance, adding the tags you define to every task inside the play, block, role, or imported file. However, tag inheritance does *not* apply to dynamic re-use with ``include_role`` and ``include_tasks``. With dynamic re-use (includes), the tags you define apply only to the include itself. If you need tag inheritance, use a static import. If you cannot use an import because the rest of your playbook uses includes, see :ref:`apply_keyword` for ways to work around this behavior.
.. _tag_inheritance:
You may also apply tags to the tasks imported by ``roles``::
Tag inheritance: adding tags to multiple tasks
----------------------------------------------
If you want to apply the same tag or tags to multiple tasks without adding a ``tags`` line to every task, you can define the tags at the level of your play or block, or when you add a role or import a file. Ansible applies the tags down the dependency chain to all child tasks. With roles and imports, Ansible appends the tags set by the ``roles`` section or import to any tags set on individual tasks or blocks within the role or imported file. This is called tag inheritance. Tag inheritance is convenient, because you do not have to tag every task. However, the tags still apply to the tasks individually.
Adding tags to blocks
^^^^^^^^^^^^^^^^^^^^^
If you want to apply a tag to many, but not all, of the tasks in your play, use a :ref:`block <playbooks_blocks>` and define the tags at that level. For example, we could edit the NTP example shown above to use a block:
.. code-block:: yaml
# myrole/tasks/main.yml
tasks:
- block:
tags: ntp
- name: be sure ntp is installed
yum:
name: ntp
state: present
- name: be sure ntp is configured
template:
src: ntp.conf.j2
dest: /etc/ntp.conf
notify:
- restart ntpd
- name: be sure ntpd is running and enabled
service:
name: ntpd
state: started
enabled: yes
- name: be sure file sharing is installed
yum:
name:
- nfs-utils
- nfs-util-lib
state: present
tags: filesharing
roles:
- role: webserver
vars:
port: 5000
tags: [ web, foo ]
Adding tags to plays
^^^^^^^^^^^^^^^^^^^^
If all the tasks in a play should get the same tag, you can add the tag at the level of the play. For example, if you had a play with only the NTP tasks, you could tag the entire play:
.. code-block:: yaml
- hosts: all
tags: ntp
tasks:
- name: be sure ntp is installed
yum:
name: ntp
state: present
And to ``import_role:`` and ``import_tasks:`` statements::
- name: be sure ntp is configured
template:
src: ntp.conf.j2
dest: /etc/ntp.conf
notify:
- restart ntpd
- import_role:
name: myrole
tags: [ web, foo ]
- name: be sure ntpd is running and enabled
service:
name: ntpd
state: started
enabled: yes
- import_tasks: foo.yml
tags: [ web, foo ]
- hosts: fileservers
tags: filesharing
tasks:
...
Adding tags to roles
^^^^^^^^^^^^^^^^^^^^
All of these apply the specified tags to EACH task inside the play, imported
file, or role, so that these tasks can be selectively run when the playbook
is invoked with the corresponding tags.
There are three ways to add tags to roles:
Tags are applied *down* the dependency chain. In order for a tag to be
inherited to a dependent role's tasks, the tag should be applied to the
role declaration or static import, not to all the tasks within the role.
#. Add the same tag or tags to all tasks in the role by setting tags under ``roles``. See examples in this section.
#. Add the same tag or tags to all tasks in the role by setting tags on a static ``import_role`` in your playbook. See examples in :ref:`tags_on_imports`.
#. Add a tag or tags to to individual tasks or blocks within the role itself. This is the only approach that allows you to select or skip some tasks within the role. To select or skip tasks within the role, you must have tags set on individual tasks or blocks, use the dynamic ``include_role`` in your playbook, and add the same tag or tags to the include. When you use this approach, and then run your playbook with ``--tags foo``, Ansible runs the include itself plus any tasks in the role that also have the tag ``foo``. See :ref:`tags_on_includes` for details.
There is no way to 'import only these tags'; you probably want to split
into smaller roles/includes if you find yourself looking for such a feature.
When you incorporate a role in your playbook statically with the ``roles`` keyword, Ansible adds any tags you define to all the tasks in the role. For example:
The above information does not apply to `include_tasks` or other dynamic
includes, as the attributes applied to an include, only affect the include
itself.
.. code-block:: yaml
You can see which tags are applied to tasks, roles, and static imports
by running ``ansible-playbook`` with the ``--list-tasks`` option. You can
display all tags available with the ``--list-tags`` option.
roles:
- role: webserver
vars:
port: 5000
tags: [ web, foo ]
.. note::
The above information does not apply to `include_tasks`, `include_roles`,
or other dynamic includes. Tags applied to either of these only tag the
include itself.
or:
To use tags with tasks and roles intended for dynamic inclusions,
all needed tasks should be explicitly tagged at the task level; or
``block:`` may be used to tag more than one task at once. The include
itself should also be tagged.
.. code-block:: yaml
Here is an example of tagging role tasks with the tag ``mytag``, using a
``block`` statement, to then be used with a dynamic include:
---
- hosts: webservers
roles:
- role: foo
tags:
- bar
- baz
# using YAML shorthand, this is equivalent to:
# - { role: foo, tags: ["bar", "baz"] }
.. _tags_on_imports:
Adding tags to imports
^^^^^^^^^^^^^^^^^^^^^^
You can also apply a tag or tags to all the tasks imported by the static ``import_role`` and ``import_tasks`` statements:
.. code-block:: yaml
---
- hosts: webservers
tasks:
- import_role:
name: foo
tags:
- bar
- baz
Playbook file::
- import_tasks: foo.yml
tags: [ web, foo ]
- hosts: all
tasks:
- include_role:
name: myrole
tags: mytag
.. _apply_keyword:
Role tasks file::
Tag inheritance for includes: blocks and the ``apply`` keyword
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- block:
- name: First task to run
...
- name: Second task to run
...
tags:
- mytag
By default, Ansible does not apply :ref:`tag inheritance <tag_inheritance>` to dynamic re-use with ``include_role`` and ``include_tasks``. If you add tags to an include, they apply only to the include itself, not to any tasks in the included file or role. This allows you to execute selected tasks within a role or task file - see :ref:`selective_reuse` when you run your playbook.
If you want tag inheritance, you probably want to use imports. However, using both includes and imports in a single playbook can lead to difficult-to-diagnose bugs. For this reason, if your playbook uses ``include_*`` to re-use roles or tasks, and you need tag inheritance on one include, Ansible offers two workarounds. You can use the ``apply`` keyword:
.. code-block:: yaml
- name: applies the db tag to the include and to all tasks in db.yaml
include_tasks:
file: db.yml
# adds 'db' tag to tasks within db.yml
apply:
tags: db
# adds 'db' tag to this 'include_tasks' itself
tags: db
Or you can use a block:
.. code-block:: yaml
- block:
- include_tasks: db.yml
tags: db
.. _special_tags:
Special Tags
````````````
Special tags: always and never
==============================
Ansible reserves two tag names for special behavior: always and never. If you assign the ``always`` tag to a task or play, Ansible will always run that task or play, unless you specifically skip it (``--skip-tags always``).
There is a special ``always`` tag that will always run a task, unless
specifically skipped (``--skip-tags always``)
For example:
Example::
.. code-block:: yaml
tasks:
- debug:
msg: "Always runs"
tags:
- always
tasks:
- debug:
msg: "Always runs"
tags:
- always
- debug:
msg: "runs when you use tag1"
tags:
- tag1
- debug:
msg: "runs when you use tag1"
tags:
- tag1
.. warning::
* Fact gathering is tagged with 'always' by default. It is only skipped if
you apply a tag and then use a different tag in ``--tags`` or the same
tag in ``--skip-tags``.
.. versionadded:: 2.5
Another special tag is ``never``, which will prevent a task from running unless
a tag is specifically requested.
If you assign the ``never`` tag to a task or play, Ansible will skip that task or play unless you specifically request it (``--tags never``).
For example:
.. code-block:: yaml
tasks:
- Rarely-used debug task
debug: msg="{{ showmevar }}"
tags: [ never, debug ]
The rarely-used debug task in the example above only runs when you specifically request the the ``debug`` or ``never`` tags.
.. _using_tags:
Selecting or skipping tags when you run a playbook
==================================================
Once you have added tags to your tasks, includes, blocks, plays, roles, and imports, you can selectively execute or skip tasks based on their tags when you run :ref:`ansible-playbook`. Ansible runs or skips all tasks with tags that match the tags you pass at the command line. If you have added a tag at the block or play level, with ``roles``, or with an import, that tag applies to every task within the block, play, role, or imported role or file. If you have a role with lots of tags and you want to call subsets of the role at different times, either :ref:`use it with dynamic includes <selective_reuse>`, or split the role into multiple roles.
:ref:`ansible-playbook` offers five tag-related command-line options:
* ``--tags all`` - run all tasks, ignore tags (default behavior)
* ``--tags [tag1, tag2]`` - run only tasks with the tags ``tag1`` and ``tag2``
* ``--skip-tags [tag3, tag4]`` - run all tasks except those with the tags ``tag3`` and ``tag4``
* ``--tags tagged`` - run only tasks with at least one tag
* ``--tags untagged`` - run only tasks with no tags
For example, to run only tasks and blocks tagged ``configuration`` and ``packages`` in a very long playbook:
.. code-block:: bash
ansible-playbook example.yml --tags "configuration,packages"
To run all tasks except those tagged ``packages``:
.. code-block:: bash
ansible-playbook example.yml --skip-tags "packages"
Previewing the results of using tags
------------------------------------
When you run a role or playbook, you might not know or remember which tasks have which tags, or which tags exist at all. Ansible offers two command-line flags for :ref:`ansible-playbook` that help you manage tagged playbooks:
* ``--list-tags`` - generate a list of available tags
* ``--list-tasks`` - when used with ``--tags tagname`` or ``--skip-tags tagname``, generate a preview of tagged tasks
For example, if you do not know whether the tag for configuration tasks is ``config`` or ``conf`` in a playbook, role, or tasks file, you can display all available tags without running any tasks:
.. code-block:: bash
ansible-playbook example.yml --list-tags
If you do not know which tasks have the tags ``configuration`` and ``packages``, you can pass those tags and add ``--list-tasks``. Ansible lists the tasks but does not execute any of them.
.. code-block:: bash
ansible-playbook example.yml --tags "configuration,packages" --list-tasks
These command-line flags have one limitation: they cannot show tags or tasks within dynamically included files or roles. See :ref:`dynamic_vs_static` for more information on differences between static imports and dynamic includes.
.. _selective_reuse:
Selectively running tagged tasks in re-usable files
---------------------------------------------------
If you have a role or a tasks file with tags defined at the task or block level, you can selectively run or skip those tagged tasks in a playbook if you use a dynamic include instead of a static import. You must use the same tag on the included tasks and on the include statement itself. For example you might create a file with some tagged and some untagged tasks:
.. code-block:: yaml
# mixed.yml
tasks:
- name: task with no tags
debug:
msg: this task has no tags
- name: tagged task
debug:
msg: this task is tagged with mytag
tags: mytag
- block:
- name: First block task with mytag
...
- name: Second block task with mytag
...
tags:
- mytag
Example::
And you might include the tasks file above in a playbook:
tasks:
- debug: msg="{{ showmevar }}"
tags: [ never, debug ]
.. code-block:: yaml
In this example, the task will only run when the ``debug`` or ``never`` tag
is explicitly requested.
# myplaybook.yml
- hosts: all
tasks:
- include_tasks:
name: mixed.yml
tags: mytag
When you run the playbook with ``ansible-playbook -i hosts myplaybook.yml --tags "mytag"``, Ansible skips the task with no tags, runs the tagged individual task, and runs the two tasks in the block.
There are another 3 special keywords for tags: ``tagged``, ``untagged`` and
``all``, which run only tagged, only untagged
and all tasks respectively.
Configuring tags globally
-------------------------
By default, Ansible runs as if ``--tags all`` had been specified.
If you run or skip certain tags by default, you can use the :ref:`TAGS_RUN` and :ref:`TAGS_SKIP` options in Ansible configuration to set those defaults.
.. seealso::

Loading…
Cancel
Save