Ansible: Checking and Controlling Task Execution, Orchestration and Scope

Ansible is a powerful tool that gives you great control over your infrastructure. When I developed the Ansible code to install and maintain my infrastructure at home, I wrote most scripts first as single files. This was good for some time — until you realized that the structure is getting complex and you find yourself looking for the script you needed for a considerable amount of time. Then I refactored my code base to a proper layout: A central playbook site.yml that contains all plays and roles. But now I was struggling how to run only specific tasks on specific nodes.

In this article, I will show you how to use the Ansible command line to control which tasks to execute, which hosts to target, and even custom orchestration of tasks. If you need a refresher on Ansible concepts, read the footnote1.

This article originally appeared at my blog.

Directory Layout of my Infrastructure at Home Project

At the top level, I have the following directories and files:

├── group_vars
├── host_vars
├── roles
├── scripts
├── site.yml

The roles define the basic software that gets installed on each node.

├── roles
│ ├── consul
│ └── nomad
│ └── dns
│ ├── docker-arch
│ ├── docker-arm
│ ├── nfs-client
│ ├── nfs-server
├── site.yml

And scripts include smaller tasks that I execute on a selected number of hosts, for example deploying nomad jobs or system maintenance tasks on the nodes:

├── scripts
│ ├── consul
│ ├── nomad
│ ├── tutorial
│ └── uninstall
│ ├── system
│ │ ├── clean_docker.yml
│ │ ├── connection_test.yml
│ │ ├── install_package_on_arch.yml
│ │ ├── install_package_on_debian.yml
│ │ ├── reboot.yml
│ │ ├── rotate_ssh_key.yaml
│ │ ├── shutdown.yml
│ │ └── update_packages.yml

All roles, and some scripts, are defined site.yml. This is the idempotent playbook that sets up all nodes with Docker, Nomad, Consul, DNS and NFS services.

So, how can I execute just a small set of tasks from the site.yml playbook, without running it completely? Read on...

Check Playbooks before Execution

Syntax Check

>> ansible-playbook site.yml --syntax-checkOK playbook: site.yml

If you would have any error, for example in a role, you will get helpful information.

>> ansible-playbook site.yml --syntax-check
ERROR! Syntax Error while loading YAML.
mapping values are not allowed in this context
The error appears to be in '[...]/roles/dns/tasks/main.yml': line 7, column 15, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be: - name: Configure dnsmasq
^ here

List Affected Hosts

>> ansible-playbook site.yml --list-hostsplaybook: site.yml  play #1 (all): Install consul TAGS: [consul]
pattern: ['all']
hosts (6):

List all Tasks

>> ansible-playbook site.yml --list-tasksplaybook: site.yml  play #1 (all): Install consul TAGS: [consul]
command TAGS: [consul]
consul : Check if current consul version is installed TAGS: [consul]
consul : Set vars when architecture is armv7l TAGS: [consul]
consul : Set vars when architecture is armv6l TAGS: [consul]
consul : Set vars when architecture is x86_64 TAGS: [consul]
consul : Create consul group TAGS: [consul]
consul : Create consul user TAGS: [consul]
consul : Create consul dir TAGS: [consul]
consul : Get consul binary TAGS: [consul]
consul : Unzip consul binary TAGS: [consul]
consul : Create symlink TAGS: [consul]

Dry Run to Detail all Changes

>> ansible-playbook site.yml --check --diff
TASK [nfs-server : Install software] ****************************************
The following NEW packages will be installed:
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
changed: [minas]
TASK [nfs-server : Create mount dir] ****************************************
--- before
+++ after
@@ -1,4 +1,4 @@
"path": "/mnt/nfs",
- "state": "absent"
+ "state": "directory"
changed: [minas]TASK [nfs-server : Create fstab entry] ****************************************
--- before: /etc/fstab (content)
+++ after: /etc/fstab (content)
@@ -8,3 +8,4 @@
UUID=BB43-B9B6 /boot/efi vfat defaults,noatime 0 2
UUID=1ece07a6-5072-4f25-aed0-27e01b0ded17 / ext4 defaults,noatime 0 1 /mnt/nfs nfs defaults,soft,bg,noauto,rsize=32768,wsize=32768,noatime 0 0
+/dev/sda1 /mnt/nfs ext3 defaults,user 0 1
changed: [minas]TASK [nfs-server : Configure nfs access] ****************************************
--- before: /etc/exports (content)
+++ after: /etc/exports (content)
@@ -0,0 +1 @@
changed: [minas]

Ok! At this point, you have a good understanding of what your playbook will change. Lets continue.

Controlling Task Execution

- name: Configure DNS
- all
- dns
become: true
- dns

However, this play is placed in the middle of the file. How can I just execute this specific play?

Executing Specific Plays

Now, if I only want to run the DNS play, I execute ansible-playbook site.yml --tags consul. Another option is to use its name, like ansible-playbook site.yml --start-at-task="Install consul", but tags are preferred.

Executing Specific Tasks inside a Play

ansible-playbook -i hosts site.yml --tags "dns" --stepPLAY [Install consul]
PLAY [Install nomad]
PLAY [Configure DNS]
Perform task: TASK: dns : Install dnsmasq on raspi-3-1 (N)o/(y)es/(c)ontinue:

Executing Tasks only on specific Hosts

>> ansible-playbook -i hosts site.yml --tags "dns" --limit minasTASK [dns : Install dnsmasq]
ok: [minas]TASK [dns : Configure dnsmasq]
ok: [minas]

Now you have learned all about picking a set of tasks from a central playbook. There is only one thing remaining.

Orchestrating Tasks



  • Playbook: A collection of plays
  • Plays: A set of tasks that run on a set of hosts
  • Tasks: Concrete actions that are applied to a host
  • Role: A set of tasks that provision a host to perform a self-defined responsibility

IT Project Manager & Developer