However in ansible until recently all we had is the include directive. However ansible have recently added include_* and import_* (added in 2.4) directives for playbooks, tasks and vars.

include_* type directives are processed at compile time, and import_* at runtime. So conditional and tags applied to those directives are treated differently. A tag on an include_tasks directive is applied that that specific module, and is not inherited by the tasks in the included file.

The consquence of this, is that if you invoked a playbook like so;

$ ansible-playbook ~/ansible/elasticsearc-build.yml --tags elasticsearch

and your playbook contained the following exerpt;

  tasks:
    - name: install elastic search
      include_role:
        name: elasticsearch
      tags:
        - elasticsearch

and you have a role named elasticsearch containing the following

- name: install tools for working with elasticsearch
  action: >
     name= state=present
  with_items:
    - elasticsearch
    - logstash
    - filebeat

you might well expect ansible to include the role, and run the tasks in it. However you would be mistaken.

Because ansible treats the include_tasks as a static directive, and processes it at compile time, what in fact happens is that the tasks included are seen as separate, and not run because they are not tagged with elasticsearch

So to get those tasks to run, they need to be tagged as well, so you end up with tags on everything in order to get the tag to perculate down as expected.

- yum: apt
  tags:
  - elasticsearch

- file: /etc/resolv.conf
  tags:
  - elasticsearch

Import Tasks

The other option is to use import_tasks. According to the docs

“the parent task options will be copied to all child tasks contained within the import.”

This seems to work better. Setting a tag on the import causes all child tasks to run as expected.

and your playbook contained the following exerpt;

    - name: install elastic search
      import_tasks:
        name: elasticsearch.yml
      tags:
        - elasticsearch

will include and run all the task in that file.

However the statement “the parent task options will be copied to all child tasks” has an unfortunate consequence. The effect of the tag is that rather than to decide whether to procede with importing the contents of the file, it imports the tasks and tags them into the task list.

The downside of this becomes apparent when you try to run just some small section of the tasks by providing a tag. The output is dominated by a massive list of skipped tasks. and is make all the worse by the fact that you only are interested in a few of the output lines.

Blocks to the rescue

In version 2.0 ansible introduced blocks which allow the grouping of tasks, and setting properties at a group level.

So you can do something like this

- name: debian-9 annoyances block
  become: yes
  tags: [ annoyances ]
  block:
  - name: use vim.tiny for vi
    alternatives:
      name: vi
      path: /usr/bin/vim.tiny

which will allow you to use an include_tasks statement to prevent the spamming of the skipped tasks messages, but also not have to individually tag tasks that are included.

Blocks are pretty powerful and support setting a number of useful options

I think I will be making more use of blocks in my ansible roles and playbooks