Error tags must be specified as a list

By default all the tasks from the ansible playbook gets executed which can be controller using ansible tags by assigning one or more tags to individual tasks

Ansible tags are another great feature which can help you execute respective tasks from the playbook. By default all the tasks from the playbook are executed but with tags we can control this behaviour and execute only the tasks with the matching tags.

Understanding Tags

  • Tags are used at resource level to give a name to a specific resource
  • The --tags option is used with ansible-playbook to run only resources with a specific tag
  • When a task file is included in a playbook, it can be tagged in the include statement
  • When ansible-playbook --tags "tagname" is used, only resources marked with those tags will run. That would mean that if a resource at the same level doesn’t have a tag then it won’t run
  • Use --skip-tags 'tagname' to exclude resources with a specific tag
  • The special tag can be used to make sure a resource is always executed, unless specifically excluded with --skip-tags
  • The --tags option can take 3 specific tags as argument
    • tagged runs any tagged resource
    • untagged excludes all tagged resources
    • all runs all tasks (which is also the default behaviour when no tags have been specified)

NOTE:

You should take care of the indentation, tags should take the same amount of whitespace as used by the module definition i.e. module name or name under the tasks section (but without the hyphen).

ALSO READ: How to provision AWS EC2 Instances using Ansible

Example-1: Add tags to all the tasks

In this example I will prepare my sample playbook ansible-tags-1.yml with four tasks which will just print a message on the console. I will add a different tag with each task so we can use these individual tags to execute the mapping task

---
 - name: Ansible Tags
   hosts: localhost
   gather_facts: false
   tasks:
     - debug:
         msg: "This is first task"
       tags: first
     - debug:
         msg: "This is second task"
       tags: second
     - debug:
         msg: "This is third task"
       tags: third
     - debug:
         msg: "This is fourth task"
       tags: fourth

Now if I execute this playbook without any additional command line argument then all the tasks will be executed by default:

[ansible@controller ~]$ ansible-playbook ansible-tags-1.yml

PLAY [Ansible Tags] ************************************************************************************************

TASK [debug] *******************************************************************************************************
ok: [localhost] => {
    "msg": "This is first task"
}

TASK [debug] *******************************************************************************************************
ok: [localhost] => {
    "msg": "This is second task"
}

TASK [debug] *******************************************************************************************************
ok: [localhost] => {
    "msg": "This is third task"
}

TASK [debug] *******************************************************************************************************
ok: [localhost] => {
    "msg": "This is fourth task"
}

PLAY RECAP *********************************************************************************************************
localhost                  : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

But we can control this behaviour by using tags, assuming we only wish to execute the first task so we can use «--tags first» with the same command:

[ansible@controller ~]$ ansible-playbook ansible-tags-1.yml --tags first

PLAY [Ansible Tags] ************************************************************************************************

TASK [debug] *******************************************************************************************************
ok: [localhost] => {
    "msg": "This is first task"
}

PLAY RECAP *********************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

So all other tasks are excluded from the play. We can add more tags to the list, for example to call task1 and task3 we will use:

[ansible@controller ~]$ ansible-playbook ansible-tags-1.yml --tags first,third

PLAY [Ansible Tags] ************************************************************************************************

TASK [debug] *******************************************************************************************************
ok: [localhost] => {
    "msg": "This is first task"
}

TASK [debug] *******************************************************************************************************
ok: [localhost] => {
    "msg": "This is third task"
}

PLAY RECAP *********************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

So we just need to give the mapping tag name to execute the respective task

ALSO READ: Working with Ansible Handlers

Example-2: Exclude tasks using tags

Now in the above example we were executing the tasks by using the mapping tag name. But if you have 100s of tags and you only wish to exclude few of the tasks then it is not a good practice to provide all those tags through the command line.

In such case we can use --skip-tags to call all the other tags except the provided tags with --skip-tags. For example here I am executing all the tags except for the task mapped with tag fourth

[ansible@controller ~]$ ansible-playbook ansible-tags-1.yml --skip-tags fourth

PLAY [Ansible Tags] ************************************************************************************************

TASK [debug] *******************************************************************************************************
ok: [localhost] => {
    "msg": "This is first task"
}

TASK [debug] *******************************************************************************************************
ok: [localhost] => {
    "msg": "This is second task"
}

TASK [debug] *******************************************************************************************************
ok: [localhost] => {
    "msg": "This is third task"
}

PLAY RECAP *********************************************************************************************************
localhost                  : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Example-3: Using same tag for multiple tasks

We can also use the same tag name for multiple tasks so that with a single tag name we can execute multiple tasks. I have updated my playbook to assign another tag name for my first and third task.

---
 - name: Ansible Tags
   hosts: localhost
   gather_facts: false
   tasks:
     - debug:
         msg: "This is first task"
       tags:
         - first
         - general
     - debug:
         msg: "This is second task"
       tags: second
     - debug:
         msg: "This is third task"
       tags:
         - third
         - general
     - debug:
         msg: "This is fourth task"
       tags: fourth

I have created an additional tag «general» for first and third task so now I can only use this tag if I want to execute first and third task instead of using two different tags all the time:

ALSO READ: Getting started with Ansible

Let us verify this configuration

[ansible@controller ~]$ ansible-playbook ansible-tags-1.yml --tags general

PLAY [Ansible Tags] ************************************************************************************************

TASK [debug] *******************************************************************************************************
ok: [localhost] => {
    "msg": "This is first task"
}

TASK [debug] *******************************************************************************************************
ok: [localhost] => {
    "msg": "This is third task"
}

PLAY RECAP *********************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Example-4: Disable one or more tasks using tags

We know that by default all the tasks from a play are executed but for some debugging purpose if you wish to disable a task then we can achieve this using tags. You can just assign the respective task «never» tag and that task will not be executed by default unless you specifically call the tag name of that task.

For example I have added never tag to my fourth task

---
 - name: Ansible Tags
   hosts: localhost
   gather_facts: false
   tasks:
     - debug:
         msg: "This is first task"
       tags:
         - first
         - general
     - debug:
         msg: "This is second task"
       tags: second
     - debug:
         msg: "This is third task"
       tags:
         - third
         - general
     - debug:
         msg: "This is fourth task"
       tags:
        - fourth
        - never

Let me execute the playbook without any command line arguments:

[ansible@controller ~]$ ansible-playbook ansible-tags-1.yml

PLAY [Ansible Tags] ************************************************************************************************

TASK [debug] *******************************************************************************************************
ok: [localhost] => {
    "msg": "This is first task"
}

TASK [debug] *******************************************************************************************************
ok: [localhost] => {
    "msg": "This is second task"
}

TASK [debug] *******************************************************************************************************
ok: [localhost] => {
    "msg": "This is third task"
}

PLAY RECAP *********************************************************************************************************
localhost                  : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

So the fourth task was not executed here. But we can execute the fourth task by using --tags fourth

[ansible@controller ~]$ ansible-playbook ansible-tags-1.yml --tags fourth

PLAY [Ansible Tags] ************************************************************************************************

TASK [debug] *******************************************************************************************************
ok: [localhost] => {
    "msg": "This is fourth task"
}

PLAY RECAP *********************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

In such case the never tag control is overwritten by the command line argument with a higher precedence.

ALSO READ: Ansible Installation Guide on RHEL/CentOS 8

What’s Next

Next in our Ansible Tutorial we will learn about ansible blocks and rescue which can be used for error and recovery situations in real time environments

Didn’t find what you were looking for? Perform a quick search across GoLinuxCloud

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:

  1. Add tags to your tasks, either individually or with tag inheritance from a block, play, role, or import.

  2. Select or skip tags when you run your playbook.

  • Adding tags with the tags keyword

    • Adding tags to individual tasks

    • Adding tags to includes

    • Tag inheritance: adding tags to multiple tasks

      • Adding tags to blocks

      • Adding tags to plays

      • Adding tags to roles

      • Adding tags to imports

      • Tag inheritance for includes: blocks and the apply keyword

  • Special tags: always and never

  • Selecting or skipping tags when you run a playbook

    • Previewing the results of using tags

    • Selectively running tagged tasks in re-usable files

    • Configuring tags globally

Adding tags with the tags keyword

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 Selecting or skipping tags when you run a playbook for more details.

Adding tags to individual tasks

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:

tasks:
- name: Install the servers
  ansible.builtin.yum:
    name:
    - httpd
    - memcached
    state: present
  tags:
  - packages
  - webservers

- name: Configure the service
  ansible.builtin.template:
    src: templates/src.j2
    dest: /etc/foo.conf
  tags:
  - configuration

You can apply the same tag to more than one individual task. This example tags several tasks with the same tag, “ntp”:

---
# file: roles/common/tasks/main.yml

- name: Install ntp
  ansible.builtin.yum:
    name: ntp
    state: present
  tags: ntp

- name: Configure ntp
  ansible.builtin.template:
    src: ntp.conf.j2
    dest: /etc/ntp.conf
  notify:
  - restart ntpd
  tags: ntp

- name: Enable and run ntpd
  ansible.builtin.service:
    name: ntpd
    state: started
    enabled: true
  tags: ntp

- name: Install NFS utils
  ansible.builtin.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.

Adding tags to includes

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 Selectively running tagged tasks in re-usable files for more details.

You add tags to includes the same way you add tags to any other task:

---
# 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:

---
- hosts: webservers
  tasks:
    - name: Include the bar role
      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 Tag inheritance for includes: blocks and the apply keyword for ways to work around this behavior.

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 block and define the tags at that level. For example, we could edit the NTP example shown above to use a block:

# myrole/tasks/main.yml
- name: ntp tasks
  tags: ntp
  block:
  - name: Install ntp
    ansible.builtin.yum:
      name: ntp
      state: present

  - name: Configure ntp
    ansible.builtin.template:
      src: ntp.conf.j2
      dest: /etc/ntp.conf
    notify:
    - restart ntpd

  - name: Enable and run ntpd
    ansible.builtin.service:
      name: ntpd
      state: started
      enabled: true

- name: Install NFS utils
  ansible.builtin.yum:
    name:
    - nfs-utils
    - nfs-util-lib
    state: present
  tags: filesharing

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:

- hosts: all
  tags: ntp
  tasks:
  - name: Install ntp
    ansible.builtin.yum:
      name: ntp
      state: present

  - name: Configure ntp
    ansible.builtin.template:
      src: ntp.conf.j2
      dest: /etc/ntp.conf
    notify:
    - restart ntpd

  - name: Enable and run ntpd
    ansible.builtin.service:
      name: ntpd
      state: started
      enabled: true

- hosts: fileservers
  tags: filesharing
  tasks:
  ...

Adding tags to roles

There are three ways to add tags to roles:

  1. Add the same tag or tags to all tasks in the role by setting tags under roles. See examples in this section.

  2. 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 Adding tags to imports.

  3. Add a tag or tags 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 Adding tags to includes for details.

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:

roles:
  - role: webserver
    vars:
      port: 5000
    tags: [ web, foo ]

or:

---
- hosts: webservers
  roles:
    - role: foo
      tags:
        - bar
        - baz
    # using YAML shorthand, this is equivalent to:
    # - { role: foo, tags: ["bar", "baz"] }

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:

---
- hosts: webservers
  tasks:
    - name: Import the foo role
      import_role:
        name: foo
      tags:
        - bar
        - baz

    - name: Import tasks from foo.yml
      import_tasks: foo.yml
      tags: [ web, foo ]

Tag inheritance for includes: blocks and the apply keyword

By default, Ansible does not apply 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 Selectively running tagged tasks in re-usable files 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:

- name: Apply 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:

- block:
   - name: Include tasks from db.yml
     include_tasks: db.yml
  tags: db

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).

For example:

tasks:
- name: Print a message
  ansible.builtin.debug:
    msg: "Always runs"
  tags:
  - always

- name: Print a message
  ansible.builtin.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.

Warning

  • The role argument specification validation task is tagged with ‘always’ by default. This validation
    will be skipped if you use --skip-tags always.

New in version 2.5.

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:

tasks:
  - name: Run the rarely-used debug task
    ansible.builtin.debug:
     msg: '{{ showmevar }}'
    tags: [ never, debug ]

The rarely-used debug task in the example above only runs when you specifically request the debug or never 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 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 use it with dynamic includes, or split the role into multiple roles.

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 either the tag tag1 or the tag tag2

  • --skip-tags [tag3, tag4] — run all tasks except those with either the tag tag3 or the tag 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:

ansible-playbook example.yml --tags "configuration,packages"

To run all tasks except those tagged packages:

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 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:

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.

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 Comparing includes and imports: dynamic and static re-use for more information on differences between static imports and dynamic includes.

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:

# mixed.yml
tasks:
- name: Run the task with no tags
  ansible.builtin.debug:
    msg: this task has no tags

- name: Run the tagged task
  ansible.builtin.debug:
    msg: this task is tagged with mytag
  tags: mytag

- block:
  - name: Run the first block task with mytag
    ...
  - name: Run the second block task with mytag
    ...
  tags:
  - mytag

And you might include the tasks file above in a playbook:

# myplaybook.yml
- hosts: all
  tasks:
  - name: Run tasks from mixed.yml
    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.

Configuring tags globally

If you run or skip certain tags by default, you can use the TAGS_RUN and TAGS_SKIP options in Ansible configuration to set those defaults.

Sometimes, you might want to run specific tasks instead of running an entire playbook file.  This helps to reduce the total playbook execution time, especially when dealing with a large playbook file.

So, what are tags?

Tags in playbooks are pieces of metadata that are attached to tasks in a playbook file. They are referred to when running playbooks and allow you to selectively target certain tasks at runtime. Basically, the instruct Ansible to execute (or not to execute) specific tasks within the playbook file.

Usually, tasks that are skipped have been carried out and hence there is no need to carry them out once again. This way, tags avoid repetition and optimize playbook execution time. They are handy when you want to run certain tasks on demand.

In this guide, we will delve into Ansible Tags and demonstrate how you can attach tags to tasks to determine playbook execution.

Execute a specific task in a playbook

Let us take an example of a playbook file that executes three tasks as shown. The tags are specified using the tags label at the end of each task.

---
- name: Ansible Tags example
  hosts: localhost
  gather_facts: False
  tasks:
    - name: Hello World tag example
      debug:
        msg: "Hello World!"
      tags:
        - hello

    - name: Welcome to Ansible Tags tag example
      debug:
        msg: "How are you?"
      tags:
        - welcome

    - name: Enjoy tag example
      debug:
        msg: "Enjoy!"
      tags:
        - enjoy

In this playbook, we have three tags: hello, welcome, and enjoy.

$ sudo ansible-playbook /etc/ansible/ansible-01-tags.yml --list-tags

List-Tags-From-Ansible-Playbook

As mentioned earlier, you can use tags to control the execution of Ansible playbooks.  To specify which task to execute use the -t or –tags flag.

In the command below, we are instructing Ansible to execute the first task only which has been tagged as hello.

$ sudo ansible-playbook /etc/ansible/ansible-01-tags.yml --tags hello

Run-Specific-Task-with-Tag-Ansible

Skip specific tags in a Playbook

You can also instruct Ansible to skip specific tags using the –skip-tags flag. In doing so, Ansible will run the rest of the tasks in the Playbook file with the exception of the task provided.

In this example, Ansible ignores the last task which is tagged enjoy and executes the rest of the tasks defined in the playbook.

$ sudo ansible-playbook /etc/ansible/ansible-01-tags.yml --skip-tags enjoy

Skip-Tags-While-Running-Ansible-Playbook

Ensure that a task always (or never) runs

Even as you use tags to determine which tasks to be executed in a playbook file, sometimes, you find that there are tasks that you need to execute.  Take, for example, a playbook that installs Apache on the remote webserver.

The playbook has 3 tasks. It first updates the package lists on the remote host, installs Apache, and restarts it.  However, before installing Apache, it is required to update the package lists or refresh the repositories.

Since refreshing the repositories is a prerequisite, We will tag this task with the always tag.

---
- name: install Apache webserver
  hosts: webserver
  tasks:
    - name: Update and upgrade apt packages
      apt:
        update_cache: yes
      tags:
        - always

    - name: install Apache on Ubuntu
      apt:
        name: apache2
        state: latest
      tags:
        - install_apache

    - name: Restart Apache Webserver
      service:
        name: apache2
        state: restarted
      tags:
        - restart_apache

Without any tags, the playbook runs as expected.

$ sudo ansible-playbook /etc/ansible/ansible-02-tags.yml

Ansible-Playbook-with-Always-Tag

If we specify to run a specific task other than the one that is mandatory (which in this case is the first task) Ansible will also execute the task that bears the ‘always’ tag.

In this example, we have instructed Ansible to restart Apache which bears the ‘restart_apache’  tag. However, the ‘update apt repository’ task still runs since it has the ‘always’ tag.

$ sudo ansible-playbook /etc/ansible/ansible-02-tags.yml --tags restart_apache

Tasks-runs-always-tag-ansible

In the same vein, you can tell Ansible never to run a task, and for this, we use the ‘never‘ tag. This is the exact opposite of the ‘always’ tag.

Back to our playbook. Suppose you don’t want to restart Apache after installing. To achieve this, simply pass the never tag as shown.

- name: Restart Apache Webserver
  service:
    name: apache2
    state: restarted
  tags:
    - restart_apache
    - never

This can also be tagged as follows using the double square brackets:

  tags: [ restart_apache, never ]

When the playbook is executed without any tags, the task will be omitted.

$ sudo ansible-playbook /etc/ansible/ansible-02-tags.yml

Ansible-Playbook-never-tag

From the output, you can see that restart apache task has been skipped.

NOTE:

A task that is tagged ‘never‘ will still run when it is explicitly called in the ansible-playbook command. For example, the task that restarts Apache will still be executed since it has explicitly been defined in the command.

$ sudo ansible-playbook /etc/ansible/ansible-02-tags.yml --tags restart_apache

Run-Task-with-never-tags-ansible-playbook

Wrapping up

Ansible tags are handy and provide the flexibility needed in running Ansible playbooks. You can execute or skip executing specific tasks in a playbook. This provides better control of your playbooks during playbook runtime.

Read Also: How to Use Ansible Vault to Secure Sensitive Data

how do ansible tags workOne of the most confusing Ansible features is the tags, and in this blog, I will try to clarify how they work.

A tag is an attribute that you can set to an Ansible structure (plays, roles, tasks), and then when you run a playbook you can use –tags or –skip-tags to execute a subset of tasks.

Let’s look at this basic playbook example:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

hosts: localhost

  tasks:

     name: Install PMM2 client

      yum:

        name: pmm-client2

        state: present

      tags:

       install

     name: create pmm-admin flags source

      template:

        src: pmm-admin-flags.txt.j2

        dest: /etc/pmm/pmm-admin-flags.txt

      tags:

       configure

     name: setup pmm-agent

      command: «pmm-agent setup —force @/etc/pmm/pmm-agent-flags.txt»

      tags:

       configure

...

Looking at the play we can see two tags – install and configure. You can also list all tags in a play using –list-tags

% ansibleplaybook tags.yaml listtags

playbook: tags.yaml

play #1 (local): local TAGS: []

TASK TAGS: [configure, install]

You can list all tasks and tags with –list-tasks

% ansibleplaybook tags.yaml listtasks

playbook: tags.yaml

play #1 (local): local TAGS: []

tasks:

Install PMM2 client TAGS: [install]

create pmmadmin flags source TAGS: [configure]

setup pmmagent TAGS: [configure]

Now to see the effect of tags we can –list-tasks applying tags filters to know which tasks will run. 

% ansibleplaybook tags.yaml listtasks tags=install

playbook: tags.yaml

play #1 (local): local TAGS: []

tasks:

Install PMM2 client TAGS: [install]

% ansibleplaybook tags.yaml listtasks tags=configure

playbook: tags.yaml

play #1 (local): local TAGS: []

tasks:

create pmmadmin flags source TAGS: [configure]

setup pmmagent TAGS: [configure]

% ansibleplaybook tags.yaml listtasks skiptags=install

playbook: tags.yaml

play #1 (local): local TAGS: []

tasks:

create pmmadmin flags source TAGS: [configure]

setup pmmagent TAGS: [configure]

Ansible Tags Inheritance

So far, so good. Now let’s check how tags inheritance works. When you add a tag to a play or a static import (role or task), the included tasks inherit the tag. Let’s see an example:

hosts: local

  tags:

  — pmm

  tasks:

    — name: Install PMM2 client

This is the same play as before but I just added the pmm tag (Percona Monitoring and Management) to play structure. And we can see the inheritance: 

% ansibleplaybook tags.yaml listtasks

playbook: tags.yaml

play #1 (local): local TAGS: [pmm]

tasks:

Install PMM2 client TAGS: [install, pmm]

create pmmadmin flags source TAGS: [configure, pmm]

setup pmmagent TAGS: [configure, pmm]

All the tasks now have the pmm tag.

Also, with roles:

hosts: dbservers,!rds

  become: yes

  roles:

  — role: percona_repo

    tags:

    — percona_repo

    — toolkit

    — pmm

  — role: percona-toolkit

    tags:

    — toolkit

  — role: pmm

    tags:

    — pmm

When we set a tag on a role structure definition, all the tasks in those roles will inherit the tags. Which, in this case, means that all the tasks in the pmm role will have the pmm tag when we run this playbook.

As I mentioned before, inheritance only works with static imports (import_*). For dynamic includes (include_*), you would need to explicitly apply the tags.

name: Static import pmm role

  import_role: pmm

  tags

  — pmm

name: Dynamic include pmm role

  include_role: pmm

    apply:

      tags:

      — pmm

  tags

  — pmm

Be careful with this if you also have include_tasks inside your roles! Those dynamic included tasks won’t inherit the tag and then won’t run. A common example would be to include tasks based on the OS family.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

% cat roles/pmm/tasks/main.yaml

name: include {{ ansible_os_family }} tasks

include_tasks: «{{ ansible_os_family }}.yaml»

apply:

tags:

      — pmm

% cat roles/pmm/tasks/Debian.yaml

name: Install pmmclient with apt

apt:

name: pmmclient2

state: present

% cat roles/pmm/tasks/RedHat.yaml

name: Install pmmclient with yum

yum:

name: pmmclient2

state: present

In this example, we had to re-apply tags for the dynamic included tasks. You could also be using static imports, but in that case, you would need to import two files and use when:  

name: import tasks for RedHat

  import_tasks: RedHat.yaml

  when: ansible_os_family == ‘RedHat’

name: import tasks for Debian

  import_tasks: Debian.yaml

  when: ansible_os_family == ‘Debian’

In this case, imported tasks will inherit tags from the top, but also all tasks on both files will be processed inheriting the when conditional from the import statement. This means that the when condition is not applied to the import_tasks itself, but to all the tasks imported from it. So for large roles, I don’t recommend this, as still all tasks would need to be processed and the output would become hard to analyze.

Special Ansible Tags

As you may see in the latest playbook example, the percona_repo role has three tags: one for itself (percona_repo) and one for each role that installs packages (toolkit, pmm). So what if I keep adding roles for other package management that would require the percona_repo to be present?  In that case, I will need to keep adding more tags to the percona_repo role, which is not efficient. Of course, you can use dependencies on the role’s meta, but for the context of this blog, I will just use tags. For these cases, Ansible has two special tags: always and never

always tagged tasks will run unless you skip it with –skip-tags=always.

never tagged tasks won’t run unless a tag on it is specified to run –tags=never.

Let’s extend the initial sample and add always and never tags.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

hosts: localhost

  tags:

  — pmm

  tasks:

  — name: Uninstall PMM2 client

      yum:

        name: pmm-client2

        state: absent

      tags:

      — never

      — uninstall

    — name: Install PMM2 client

      yum:

        name: pmm-client2

        state: present

      tags:

      — install

      — always 

    — name: create pmm-admin flags source

      template:

        src: pmm-admin-flags.txt.j2

        dest: /etc/pmm/pmm-admin-flags.txt

      tags:

      — configure

    — name: setup pmm-agent

      command: «pmm-agent setup —force @/etc/pmm/pmm-agent-flags.txt»

      tags:

      — configure

...

There is now a new task “Uninstall PMM2 client” with the never tag, and “Install PMM2 client” with always.

% ansibleplaybook tags.yaml listtasks

playbook: tags.yaml

play #1 (localhost): localhost TAGS: [pmm]

tasks:

Install PMM2 client TAGS: [always, install, pmm]

create pmmadmin flags source TAGS: [configure, pmm]

setup pmmagent TAGS: [configure, pmm]

We can see the never task was skipped as expected.

% ansibleplaybook tags.yaml listtasks tags=configure

playbook: tags.yaml

play #1 (localhost): localhost TAGS: [pmm]

tasks:

Install PMM2 client TAGS: [always, install, pmm]

create pmmadmin flags source TAGS: [configure, pmm]

setup pmmagent TAGS: [configure, pmm]

Running with configure tag, the install task is also executed as we added the always tag.

Be careful with the inheritance effect. As we said:

  • Never tagged tasks run only if one the tags are specified to run
  • Tags are inherited from parent blocks

In this play, we see that the pmm tag is inherited from the play to the tags, so what happens if we run with the pmm tag?

% ansibleplaybook tags.yaml listtasks tags=pmm

playbook: tags.yaml

play #1 (localhost): localhost TAGS: [pmm]

tasks:

Uninstall PMM2 client TAGS: [never, pmm, uninstall]

Install PMM2 client TAGS: [always, install, pmm]

create pmmadmin flags source TAGS: [configure, pmm]

setup pmmagent TAGS: [configure, pmm]

The task tagged as never is executed as-is, inheriting the pmm tag. So you will need to be careful when you use role tasks that are inheriting tags.

Conclusion

Tags are a powerful feature in Ansible, as it allows you to run a subset of tasks, and are very helpful for large plays. But it is really important to understand how inheritance works, and the difference between dynamic and static imports.

Понравилась статья? Поделить с друзьями:
  • Error t shirt
  • Error system was not declared in this scope
  • Error system service exception
  • Error system reflection targetinvocationexception рыбалка
  • Error system reflection targetinvocationexception как исправить