Tagging Tasks

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $10.00

Sometimes - especially when debugging - you just want to run only some of your playbook. Because... our playbook is getting so awesome... that, honestly, it takes some serious time to run!

For example, in my VM, I'm going to change the permissions on the var/ directory:

sudo chmod -R 555 var/

Definitely use sudo. Then, I'll remove the cache files:

sudo rm -rf var/cache/*

If you try the page now, it explodes! Ok, I don't expect my permissions to suddenly change like this under normal conditions. But, suppose that we had just hit this permission error for the first time and then added the "Fix var permissions" task. In that case, we would know that re-running the entire playbook should fix things.

But... couldn't we run just this one task? Yep! And a great way to do that is via tags.

Below the task, add tags, and then permissions:

---
- hosts: vb
... lines 3 - 10
tasks:
... lines 12 - 144
- name: Fix var directory permissions
... lines 146 - 150
tags:
- permissions
... lines 153 - 176

Now, from the command line, tell Ansible to only execute tasks with this tag: -t permissions:

ansible-playbook ansible/playbook.yml -i ansible/hosts.ini -t permissions

It still goes through its setup but then... yep! Only one task! Refresh the page. Permissions fixed!

Tagging for Deployment

Here's another example. Right now, our playbook has tasks for two separate jobs. Some tasks setup the server - making sure PHP, Nginx and other stuff is installed and configured. But others are really more about code deployment: making sure the project directory exists, cloning the code, installing composer dependencies, and setting up the database.

In the future - when we make changes to the code - we might want to just deploy that code... without going through all the server setup tasks. Let's add a new tag - deploy - to every step involved in deployment. See the task that creates the project directory? Yep, give it the deploy tag. Add it to "Checkout Git Repository" and also to the three tasks that install Composer:

---
- hosts: vb
... lines 3 - 10
tasks:
... lines 12 - 111
- name: Create project directory and set its permissions
... lines 113 - 119
tags:
- deploy
- name: Checkout Git repository
... lines 124 - 127
tags:
- deploy
- name: Download Composer
... line 132
tags:
- deploy
- name: Move Composer globally
... lines 137 - 138
tags:
- deploy
- name: Set permissions on Composer
... lines 143 - 146
tags:
- deploy
- name: Install Composer's dependencies
... lines 151 - 153
tags:
- deploy
... lines 156 - 195

Actually, this is debatable: you might consider Composer as a "Server setup" task, not deployment. It's up to you.

Keep going! I'll add the task to everything that I want to run for each code update. It's not an exact science:

---
- hosts: vb
... lines 3 - 10
tasks:
... lines 12 - 111
- name: Create project directory and set its permissions
... lines 113 - 119
tags:
- deploy
- name: Checkout Git repository
... lines 124 - 127
tags:
- deploy
- name: Download Composer
... line 132
tags:
- deploy
- name: Move Composer globally
... lines 137 - 138
tags:
- deploy
- name: Set permissions on Composer
... lines 143 - 146
tags:
- deploy
- name: Install Composer's dependencies
... lines 151 - 153
tags:
- deploy
- name: Fix var directory permissions
... lines 158 - 162
tags:
- permissions
- deploy
# Symfony console commands
- name: Create DB if not exists
... line 169
tags:
- deploy
- name: Execute migrations
... line 174
tags:
- deploy
- name: Load data fixtures
... line 179
tags:
- deploy
... lines 182 - 195

Let's see if it works! In the virtual machine, I'm going to manually edit a file:

vim app/Resources/views/default/index.html.twig

Let's add a few exclamation points to be really excited. Then hit escape, :wq to save. In the browser, that won't show up immediately - because we're in Symfony's prod environment. But if you add app_dev.php to the URL... yep! "Filter by Tag!".

By the way, going to app_dev.php only works because I've already modified some security logic in that file to allow me to access it:

33 lines web/app_dev.php
... lines 1 - 10
// This check prevents access to debug front controllers that are deployed by accident to production servers.
// Feel free to remove this, extend it, or make something more sophisticated.
if (isset($_SERVER['HTTP_CLIENT_IP'])
|| isset($_SERVER['HTTP_X_FORWARDED_FOR'])
|| !(in_array(@$_SERVER['REMOTE_ADDR'], ['127.0.0.1', 'fe80::1', '::1', '192.168.33.1']) || php_sapi_name() === 'cli-server' || strpos($_SERVER['REMOTE_ADDR'], '192.168.') === 0)
) {
header('HTTP/1.0 403 Forbidden');
exit('You are not allowed to access this file. Check '.basename(__FILE__).' for more information.');
}
... lines 20 - 33

Ok, back in our local machine, run the playbook... this time with -t deploy:

ansible-playbook ansible/playbook.yml -i ansible/hosts.ini -t deploy

Oh, much, much faster! Try the browser! Code deployed! You can also use --skip-tags if you want to get crazy and do the opposite:

ansible-playbook ansible/playbook.yml -i ansible/hosts.ini --skip-tags deploy

Next, let's talk about how we can "fix" the fact that some tasks say "Changed" every time we run them. Eventually, this will help us speed up our playbook.

Leave a comment!

This tutorial is built using an older version of Symfony, but the core concepts of Ansible are still valid. New versions of Ansible may contain some features that we don't use here.

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=5.5.9",
        "symfony/symfony": "3.1.*", // v3.1.4
        "doctrine/orm": "^2.5", // v2.7.2
        "doctrine/doctrine-bundle": "^1.6", // 1.6.4
        "doctrine/doctrine-cache-bundle": "^1.2", // 1.3.0
        "symfony/swiftmailer-bundle": "^2.3", // v2.3.11
        "symfony/monolog-bundle": "^2.8", // 2.11.1
        "symfony/polyfill-apcu": "^1.0", // v1.2.0
        "sensio/distribution-bundle": "^5.0", // v5.0.12
        "sensio/framework-extra-bundle": "^3.0.2", // v3.0.16
        "incenteev/composer-parameter-handler": "^2.0", // v2.1.2
        "doctrine/doctrine-migrations-bundle": "^1.2", // v1.2.0
        "snc/redis-bundle": "^2.0", // 2.0.0
        "predis/predis": "^1.1" // v1.1.1
    },
    "require-dev": {
        "sensio/generator-bundle": "^3.0", // v3.0.8
        "symfony/phpunit-bridge": "^3.0", // v3.1.4
        "doctrine/data-fixtures": "^1.1", // 1.3.3
        "hautelook/alice-bundle": "^1.3" // v1.4.1
    }
}