94

Ansible tags can be used to run only a subset of tasks/roles. This means that by default all tasks are executed and we can only prevent some tasks to execute.

Can we limit a task to be exectued only when "foo" tag is specified? Can we use current tags in when section of a task?

2
  • 2
    it sounds like what you need is some task setting like limit_to_tags: foo which does not exist and I don't think that is possible right now. A future implementation also needs to have a plan for whether to AND or OR those tags together.
    – dgh
    Jan 4, 2015 at 0:39
  • Take a look at my anwser in "Ansible - Default/Explicit Tags" stackoverflow.com/questions/28789912/…
    – sirkubax
    Mar 9, 2015 at 10:15

13 Answers 13

74

Ansible 2.5 comes with special tags never and always. Tag never can be used exactly for this purpose. E.g:

tasks:
  - debug: msg='{{ showmevar}}'
    tags: [ 'never', 'debug' ]

In this example, the task will only run when the debug (or never) tag is explicitly requested. [Reference on ansible docs]

1
  • This won't work with roles that have tags in the play definition. By calling a role by tag (for example "role_xy"), this tag will automagically be part of the task so ith will be executed even though "debug" was not set. serverfault.com/a/1003479/256436 provides a solution for that problem.
    – Marcus K.
    May 28 at 0:05
19

Although this is a roundabout solution, it works.

Inside the task list register a variable when normal execution runs. Then, add a when condition that checks that variable to the tagged task.

- shell: /bin/true
  register: normal_task_list

- name: Only run when tag is specified
  shell: /bin/echo "Only running because of specified tag"
  when: normal_task_list is not defined
  tags: specified
2
  • 1
    You can also use untagged to accomplish this: - set_fact: untagged_run=true tags: untagged
    – Pyzo
    Nov 28, 2017 at 19:56
  • 1
    Can you explain a little more about this? A real-world example? Jul 10, 2018 at 1:18
18

I don't have enough reputation to upvote or comment on the answer suggesting the use of command-line variables (--extra-vars), but I have this to add to it:

The caveat to this method is that the play will error and fail if you do not define that extra variable.

You can prevent play failure in the absence of an --extra-vars definition by defining a default value in the playbook itself:

---
- hosts: ...
# ↓↓↓
  vars:
    thorough: false
# ↑↑↑
  tasks:
  - name: apt - install nfs-common only when thorough is true
    when: thorough | bool
    apt:
      cache_valid_time: 86400
      force: yes
      pkg:
        - nfs-common

Overriding via --extra-vars will still work because variables defined on the command line take precedence over all other definitions.

The result is that the play runs without error when thorough is not changed to true on the command line.

3
  • 8
    The same can be achieved using thorough | default('no') | bool. Oct 10, 2015 at 17:09
  • 2
    Or when: thorough is defined and thorough if you prefer that syntax
    – KCD
    Apr 19, 2017 at 18:57
  • Thanks, love the is defined and syntax more. more than the multiple pipes which I don't feel are intuitive. Dec 22, 2017 at 22:49
11

You can use Conditionals to protect against accidentally running tasks that would otherwise be executed if you don't specify a tag. The caveat to this method is that the play will error and fail if you do not define that extra variable.

Using the extra-vars argument you can trigger your conditional to be executed.

From ansible-playbook --help:

 -e EXTRA_VARS, --extra-vars=EXTRA_VARS
    set additional variables as key=value or YAML/JSON

Example:

ansible-playbook test.yaml -e "thorough=true"

test.yaml:

...
- name: apt - install nfs-common only when thorough is true
  apt:
    cache_valid_time: 86400
    force: yes
    pkg:
    - nfs-common
  when: thorough | default(False)
...
1
  • 2
    To avoid an error if you do not define "thorough" just use thorough | default("false") | match("true"). Default does not have to be false, just anything not matching true, but it improves readability.
    – Tom Wilson
    Dec 22, 2016 at 14:37
8

A perhaps more idiomatic and elegant way is to add a when condition to the task, like such:

tasks:
  - debug: msg='{{ showmevar}}'
    tags: [ 'debug' ]
    when: "'debug' in ansible_run_tags"

This uses the magical variable ansible_run_tags which contains the list of tags supplied through the CLI argument --tags (or synonymously -t) and has the effect of running the above task if and only if the tag debug is given.

It seems this magic variable has been introduced in ansible 2.5

1
  • Best answer if you use tagged roles.
    – Marcus K.
    May 28 at 0:06
4

Yes. Running ansible-playbook with the --tags foo flag will ensure that only tasks that are tagged with foo are executed. For example, assume we have a playbook called example.yml:

tasks:

  - yum: name={{ item }} state=installed
    with_items:
       - httpd
       - memcached
    tags:
       - packages

  - name: some other task
    ..
    tags:
      - some other tag

running:

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

Will make sure only the yum task is executed.

So actually you don't really need to use tags in when section to conditionally execute a task. Notice that depending on the complexity of your playbooks/roles you might need to use a combination of --tags and --skip-tags to control which tasks are executed. For example, if an include tasks is tagged as 'foo' and some task inside the included playbook is tagged as 'bar' and you run

ansible-playbook --tags "foo"

The internal task (tagged only as 'bar') will be executed. To avoid the execution of all internal tasks tagged as 'bar' you will have to execute the following command

ansible-playbook --tags foo --skip-tags bar
5
  • 7
    This is not true: "Specifying a tag on a task means that only when this tag is passed explicitly to the ansible-playbook command that task will be executed."
    – gimboland
    Oct 22, 2014 at 8:25
  • 1
    Seconded, statement is not true.
    – Chris
    Nov 20, 2014 at 19:26
  • 11
    yes, you can achieve the behavior by ensuring you always use the right ansible-playbook options, but I think the OP is asking for a way to annotate a task so that it isn't executed unless a specific tag is explicitly added in the ansible-playbook command.
    – dgh
    Jan 4, 2015 at 0:41
  • 4
    Yeah, this is not answering the OP's question.
    – Allen Luce
    May 29, 2015 at 17:23
  • all actions tagged/untagged run when you don't specify a tag. Tags cannot exclude an action to run, only include. There is no predicate logic except for an additive filter. Sep 22, 2016 at 5:59
4

Checking the 'tags' variable isn't working in Ansible 2.1.1.0. See below for the test. I have an other idea to execute task only when a tag is defined, working for both Ansible 1.9.X and 2.X.Y:

- set_fact: foo=true
  tags: bar
- set_fact: foo=false
- name: do something when 'bar' tag is defined
  debug: var=foo
  when: foo
  tags: bar

With that, when running the playbook without any tag, the 'foo' variable will be set to true then to false, so nothing is executed. If you add the 'bar' tag, only the first setting will be applied, so the 'foo' variable will be true, then your task will be executed. Enjoy!


And here's the test about the 'tags' variable in Ansible 2.1.1.0:

Here is the playbook:

- hosts: localhost
  connection: local
  tasks:
    - name: display tags variable
      debug: var=tags
      tags: foo

    - name: do something only when tag 'foo' is provided
      debug: var=tag
      when: tags is defined
      tags: foo

And here is the output:

$ ansible-playbook --version ; ansible-playbook ./test.yml -t foo
ansible-playbook 2.1.1.0
  config file = /home/nootal/projects/ivy/src/ansible/ansible.cfg
  configured module search path = Default w/o overrides

PLAY [localhost] ***************************************************************

TASK [display tags variable] ***************************************************
ok: [localhost] => {
    "tags": "VARIABLE IS NOT DEFINED!"
}

TASK [do something only when tag 'foo' is provided] ****************************

PLAY RECAP *********************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0   
1
4

There is a special tag - "never", which will prevent a task from running unless a tag is specifically requested.

tasks:
  - debug: msg='{{ showmevar}}'
    tags: [ 'never', 'debug' ]
1
1

The never tag is the correct solution in general, but it won't work in one instance: tags are not supported on meta tasks until Ansible 2.11. In this case we have to fake tag support with a when: conditional and the magic variable ansible_run_tags.

For example, here's a snippet that will list all hosts and end the play early when you say --tags list-hosts. It works with Ansible 2.8 and higher. This is useful if you generated hosts or groups at runtime with add_host or group_by, since that happens too late for --list-hosts.

- pre_tasks:
  - name: List hosts
    assert:
      that: true
      quiet: true
    tags:
      - never
      - list-hosts

  - meta: end_play
    when: "'list-hosts' in ansible_run_tags"
0

when clause can't evaluate the presence of tags. As a workaround, I use variables and tags together to run tasks specific to that tag/variable.

Ex: Imagine a playbook and inventory

# inventory
[dev]
192.168.1.1

# site.yml
- hosts: dev
  roles:
    - { role: common }

and in common/tasks/main.yml

# roles/common/tasks/main.yaml
- name: Install links
  apt: name=links state=present

- include: uninstall.yml
  when: uninstall_links is defined
  tags:
    - uninstall

# roles/common/tasks/uninstall.yml
- name: Uninstall links
  apt: name=links state=absent

With this approach, you use the tag to select only the tasks in uninstall.yml, but you also need to set 'uninstall_links' variable to something to enable it. So if you run the playbook without any parameters, it will, by default, run the install task. To uninstall, you can set the tag 'uninstall' to your playbook (or cmdline) and MUST set the variable. If you don't set the tag, it will run everything (install and uninstall) in that order, which is good to test the entire process.

How to run everything (it will install and uninstall):

$ ansible-playbook -i inventory site.yml -l dev -s -k -e "uninstall_links=true"

How to run only the 'uninstall' tag on dev group

$ ansible-playbook -i inventory site.yml -l dev -s -k -e "uninstall_links=true" -t uninstall

Therefore, variables and tags could also be in site.yml/inventory files, allowing you to commit into your SCM and record your intention.

0

nootal is right, my approach does not work - ignore it :( I now use "when: myvar is defined" and the command line switch "-e "myvar=X" to execute tasks only when explicitly requested.

Even easier (at least with ansible 2.1.1.0):

- name: do something only when tag 'foo' is provided
  when: tags is defined
  tags: foo

-> will only execute when tags have been provided AND tags includes "foo"

0

On Ansible 2.3.2.0 , here's my solution to the problem:

---
- hosts: localhost
  gather_facts: no
  vars:
    in_tag: yes
  tasks:
    - set_fact: in_tag=no
    - fail:
        msg: "recently_added is set and you're using blah tag"
      when: ( in_tag | bool )
      tags:
        - blah
    - debug:
        msg: "always remember"

It starts by setting in_tag to True then there is a set_fact that sets it back to False on when you don't specify any tags from ansible-playbook.

When you do specify tags, in_tag stays at True and the fail task runs.

PS: you can add the logic to any tasks you want

PS2: you can also extend the logic and hardcode all the tags you have and set_fact: in_tag_blah=True in combination with tags: ["blah"] of course.

0
tasks:
  - debug: msg='{{ showmevar}}'
    tags: [ 'never', 'debug' ]

This is the right answer, but what often confuses people is how to get Ansible to add this tag in, because if you put --tags debug on the command line then the only thing that runs is the debug tasks. The solution is --tags all,debug e.g.

ansible-playbook play.yaml --tags all,debug

The Ansible docs on tags has this line:

By default, Ansible runs as if --tags all had been specified.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.