Ansible: Tags are a code smell

I have referred to this article by Michel Blanc a number of times, primarily because of one thing he says:

Do not overdo tags: most of the time, this is YAGNI (You Ain’t Gonna Need It)

What he says is absolutely the truth. Using Ansible tags creates all sorts of uncertainty in your playbooks and roles at run-time.

Let’s look at an example. In this very simple playbook, we have four tasks: one with no tags, one with a non-special tag, one with the never special tag, and one with the always special tag:

We can try various invocations of ansible-playbook and observe what happens with each:

That’s quite a truth table, even with just four tags! Using tags to control the flow of your Ansible playbooks gets confusing quickly. It’s easy to make our example even more confusing by creating additional tasks with never and always tags:

- name: demo another always-tagged task
msg: I am another always-tagged task
- always
- another-always

What happens to that truth table, now? Tags in your own code are confusing enough, but let’s consider what happens when you inject dependencies into your playbooks.

Suppose you import someone else’s Ansible role through Galaxy or by other means, like this one. In my base playbook (we’ll just use the example, above) I never accounted for the other role author’s ‘security,’ ‘install,’ nor ‘configure’ tags when faithfully importing his (or her) role. If I run my own Ansible playbook and specify any of the tags I’m using, then the other author’s tasks simply won’t run.

You can’t use tags to *include* tasks without potentially skipping other tasks, and using special tags like ‘never’ and ‘always’ just makes running playbooks worse. Ansible’s command-line tools provide way too many ways to include or skip tags, leading to a difficult-to-diagnose mess.

It would be great to see Ansible Galaxy evolve to the point where its community just disallows tags in contributed content.

There are other ways to work around using tags:

  • Use when conditionals and consider passing extra variables for conditional evaluation during ansible-playbook invocations using the ‘-e’ flag.
  • Write separate playbooks and invoke those, instead of your main playbook, when doing something simple with Ansible like reloading a service. Note that you can include specific tasks when importing an Ansible using the tasks_from argument to an include_role task.
  • Other ideas? Feel free to hit me up!



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store