75

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
    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 '15 at 0:39
  • Take a look at my anwser in "Ansible - Default/Explicit Tags" stackoverflow.com/questions/28789912/… – sirkubax Mar 9 '15 at 10:15

10 Answers 10

38

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]

20

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
  • You can also use untagged to accomplish this: - set_fact: untagged_run=true tags: untagged – Pyzo Nov 28 '17 at 19:56
  • Can you explain a little more about this? A real-world example? – Quintin Par Jul 10 '18 at 1:18
17

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.

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

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)
...
  • 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 '16 at 14:37
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

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
  • 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 '14 at 8:25
  • 1
    Seconded, statement is not true. – Chris Nov 20 '14 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 '15 at 0:41
  • 4
    Yeah, this is not answering the OP's question. – Allen Luce May 29 '15 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. – bbaassssiiee Sep 22 '16 at 5:59
1

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' ]
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.

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.