Ansible tags provide a powerful way to selectively execute tasks and manage playbook runs, allowing for greater control and flexibility in your automation workflows.
In this post, we’ll look at how to use Ansible tags to control task executions in a playbook, how to assign tags to blocks and plays, how to use special tags (always and never), and how to obtain a list of all tags defined in a playbook.
Ansible tags serve as markers that can be added to individual tasks within an Ansible playbook, enabling the execution of specific or designated tasks based on these tags during playbook runs.
You’ll occasionally need to execute only a portion of a playbook rather than the whole thing. Ansible tags come in very handy in this situation.
With the aid of Ansible tags, you can also run or skip specified tasks in your Ansible playbook.
Here are some benefits of using Ansible tags.
Ansible tags offer a convenient way to control which parts of a playbook to run, allowing you to execute only specific tasks or roles without having to rerun the entire playbook, which improves efficiency and flexibility in automation workflows. With Ansible tags, you can choose to run only the necessary tasks within a playbook, reducing execution time and resource use, which is very helpful when testing, deploying updates, or isolating issues during troubleshooting.
For example, you can update settings on specific devices without having to re-run the entire playbook. This saves time and avoids mistakes. It is especially helpful when testing one change, e.g., a firewall update, without restarting other services you don’t need to touch.
Tags also make playbooks easier to manage and understand by labelling tasks and sections, which helps teams maintain and collaborate on large automation projects more effectively. Using clear and well-labelled tags, teams can quickly understand what each task does, making large playbooks easier to read, manage, and update.
This clarity can help streamline debugging and collaboration, especially when there are many engineers working on network automation projects integrating with a tool like NetBox.
Special tags like always
, which ensures a task runs no matter what, and never
, which prevents it from running unless explicitly called, make your automation more reliable and predictable.
For example, using an always
tag makes sure important tasks like logging always run, while a never
tag helps prevent risky actions, like resetting network devices, from running by mistake during regular operations. These special tags help keep things stable and predictable, especially in complex network automation setups that work with a tool like NetBox.
Now, let’s take a look at using Ansible and controlling the execution of our tasks within a playbook by using tags.
To create a playbook, you first need to create a YAML file in any directory with a name of your choice.
In our case, we’ll name the file play.yaml
. This will be the playbook file.
Next, we’ll edit this YAML file by adding some contents to it. Then, save it.
- name: play1
hosts: localhost
become: false
gather_facts: false
tasks:
- name: create user
debug:
msg: "The user {{ user }} will be created"
- name: delete user
debug:
msg: "The user {{ user }} will be deleted"
The playbook contains two tasks: create user
and delete user
. These tasks are defined under the tasks
section of the playbook and will be executed sequentially when the playbook is run against the specified host(s).
After saving your playbook file, head to your command line interface and make sure to use the directory where you saved your play.yml
file.
Now, we’ll run the playbook command.
ansible-playbook -e user=bill --list-tasks play.yml
playbook: play.yml
play #1 (localhost): localhost TAGS: []
tasks:
create user TAGS: []
delete user TAGS: []
Notice that the output is not particularly useful because we only displayed the list of tasks in the playbook.
We’re creating the user, and we’re also deleting a user. Obviously, there’s no control over the execution of our tasks.
To use the Ansible tags in a playbook, we specify them using the tags
keyword. The tags
keyword is then followed by a semicolon and the tag.
To use the Ansible tags in our playbook, we’ll go back to our play.yml
file and edit it. Let’s add the tags create
and delete
to users:
- name: play1
hosts: localhost
become: false
gather_facts: false
tasks:
- name: create user
debug:
msg: "The user {{ user }} will be created"
tags: create
- name: delete user
debug:
msg: "The user {{ user }} will be deleted"
tags: delete
In the playbook above, we created two tags, create
and delete
, which are contained in the tasks create user
and delete user
, respectively.
To run only certain tags in Ansible, we make use of the flag –tags
alongside the tag name in our command, Now, let’s run the play.yml
playbook by specifying a single tag.
We’ll typically expect this command to output the tasks that are tagged with the specified tag.
ansible-playbook -e user-bill –tags create –list-tasks play.yml
In this case, it’ll execute only the tasks that we’ve tagged with create
. Only tasks with the create
tag will be executed.
playbook: play.yml
play #1 (localhost): localhost TAGS: []
tasks:
create user TAGS: [create]
The code output reveals that running the playbook with the option –tags
create results in the return of only the tasks that are tagged with create
.
Now, we’ll run the playbook by specifying the other tag option, –tags delete
.
ansible-playbook -e user-bill –tags delete –list-tasks play.yml
Similar to the previous command, the only difference here is that we solely aim to run the tasks tagged with delete
.
playbook: play.yml
play #1 (localhost): localhost TAGS: []
tasks:
delete user TAGS: [delete]
To skip any tag in a given playbook, we make use of the –skip-tags
flag alongside the tag we intend to skip when executing the tasks in our playbook.
Let’s run a command that will skip the create
tag in our playbook by using the –skip-tags
flag.
ansible-playbook -e user=bill –skip-tags create play.yml
By introducing the –skip-tags
flag, we told Ansible to skip any task in our playbook with the create
tag.
PLAY [play1] ********************************************************************
TASK [delete user] ***************************************************************
ok: [localhost] => {
“msg”: “The user bill will be deleted”
}
PLAY RECAP ***********************************************************************
localhost: ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Here, it’s evident that we skip and don’t execute the create user
task, which has the tag create
.
To run the playbook without tags, execute the ansible-playbook
command without specifying any specific tags. Then, we’ll run the modified playbook without providing any tag.
ansible-playbook -e user=bill –list-tasks play.yml
playbook: play.yml
play #1 (localhost): localhost TAGS: []
tasks:
create user TAGS: [create]
delete user TAGS: [delete]
The code output shows that the playbook returns the two tasks together. This is because we didn’t specify any tags in the execution command of the playbook.
That’s a problem because without specifying or skipping a tag, the output still returns all the tasks in the playbook.
However, this leads us back to the initial problem of our playbook running all the tasks during its execution. Although we can have control over which task we specifically want to execute by running our command using the –tags
flag, it’s still very possible for us to run a specific task in our playbook by making use of special built-in tags that’ll tell Ansible to run a given task or not.
These special tags are the always
and never
tags.
The always
and never
tags are used to specify if a task should always—or never—run. This is irrespective of whether you used the –tags
or –skip—tags
flags in your run command.
In a real-life scenario, you actively fetch data from a server or the web during a data analysis process, ensuring that you always obtain new data for automation purposes. This is where the always
tag comes in when creating your tasks in a playbook.
The same can be said of the never
tag, which is just the opposite of the always
tag in that it ensures that a task is never executed unless you specifically call it.
Now, let’s modify our play.yaml
playbook to include the always
and never
tags.
- name: play1
hosts: localhost
become: false
gather_facts: false
tasks:
- name: create user
debug:
msg: "The user {{ user }} will be created"
tags:
- create
- never
- name: delete user
debug:
msg: "The user {{ user }} will be deleted"
tags:
- delete
- always
We added new tags, never
and always
, to the create user
and delete user
tasks, respectively. The never
tag in this case enables you to skip the create user
task, while the always
tag guarantees the execution of the delete user
task regardless of any other tags or conditions.
By using these tags, you can control the execution of specific tasks based on your requirements and easily skip or enforce their execution as needed.
Now that we’ve modified our playbook to include specific tags, we can execute the command to list all the tasks running during the execution of our playbook.
ansible-playbook -e user=bill --list-tasks play.yml
playbook: play.yml
play #1 (localhost): localhost TAGS: []
tasks:
delete user TAGS: [delete, always]
Bravo! We can now see that even without specifying any tag in our run command, we’re able to return only the tasks that should run (the task with the always
tag).
In this case, the delete user
task executed because we added the special tag always
to it in our playbook.
A block
in Ansible is a construct that gives you the flexibility to group multiple tasks together. It offers a method to sequentially arrange tasks and apply specific actions or circumstances to the entire group.
With a block, you can be very sure of handling task errors.
To define a block, we utilize the block
keyword followed by a block structure that contains a list of tasks. The block treats all tasks within it as a single unit, enabling the inclusion of multiple tasks that execute sequentially.
Now, let’s demonstrate how to add tags to blocks in our play.yml
playbook.
- name: play1
hosts: localhost
become: false
gather_facts: false
tasks:
- name: create user
block:
- name: Task 1 inside create block
debug:
msg: "This is Task 1 inside create block"
tags:
- create
- never
- name: delete user
block:
- name: Task 1 inside delete block
debug:
msg: "This is Task 1 inside delete block"
tags:
- delete
- never
By using blocks, you can group tasks together and apply tags, handlers, or other settings to the entire block instead of repeating them for each task individually. This helps improve the readability and maintainability of your playbook.
In Ansible, a play is a configuration unit with tasks executed on a specific group of hosts.
A play consists of a set of hosts, a set of tasks, and optional additional configuration settings.
Now, we’ll modify our playbook to include a tag (my_play_tag)
for the play.
Additionally, it’s important to note that the assigned tags of the play differ from the tags assigned to the individual tasks within the play.
- name: My Playbook
hosts: localhost
become: false
gather_facts: false
tags:
- my_play_tag
tasks:
- name: create user
block:
- name: Task 1 inside create block
debug:
msg: "This is Task 1 inside create block"
tags:
- create
- never
- name: delete user
block:
- name: Task 1 inside delete block
debug:
msg: "This is Task 1 inside delete block"
tags:
- delete
- never
To get all tags in your playbook, run the command below for a comprehensive list of available tags.
ansible-playbook –list-tags play.yml
In the command above, we use the –list-tags
flag to obtain a list of all tags in the Ansible playbook.
playbook: play.yml
play #1 (localhost): My Playbook TAGS: [my_play_tag]
TASK TAGS: [create, never, delete]
Ansible tags can also be used along with NetBox integration to automate against NetBox as the source of truth.
- name: NetBox Automation Playbook
hosts: localhost
gather_facts: false
tasks:
- name: Ensure NetBox is the source of truth
netbox_device:
netbox_url: http://netbox.example.com
api_token: YOUR_API_TOKEN
state: present
tags: [netbox]
- name: Render and deploy configuration templates
template:
src: template.j2
dest: /path/to/destination/file
tags: [template]
- name: Restart services
systemd:
name: myservice
state: restarted
tags: [service]
- name: Notify NetBox about changes
netbox_webhook:
netbox_url: http://netbox.example.com
api_token: YOUR_API_TOKEN
data:
message: Configuration changes applied
tags: [netbox, notification]
This playbook organizes tasks using tags. The first task, with the “netbox” tag ensures NetBox is considered the source of truth.
The second task, tagged as “template
,” renders and deploys configuration templates.
The third task, tagged as “service
,” restarts the specified service.
Finally, the fourth task, tagged as “netbox
” and “notification
,” notifies NetBox about the applied configuration changes.
In this post, we’ve covered how to use Ansible tags to control tasks, assign tags to blocks/plays, and get a list of defined tags.
Ansible tags label tasks, blocks, or plays in playbooks, enabling the selective execution or skipping of specific tasks. Tags like “never
” and “always
” control task execution, while the –tags
and –skip-tags
commands run or skip tasks.
Additionally, Ansible tags can be used along with NetBox integration to automate against NetBox as the source of truth.
Explore how Ansible tags can enhance network automation workflows and learn more about getting started with Ansible and NetBox for network automation in our webinar.
This post was written by Theophilus Onyejiaku. Theophilus has over 5 years of experience as data scientist and a machine learning engineer. He has garnered expertise in the field of Data Science, Machine Learning, Computer Vision, Deep learning, Object Detection, Model Development and Deployment. He has written well over 660+ articles in the aforementioned fields, python programming, data analytics and so much more.