If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
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!
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:
... 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.
Hey Dmitriy,
Sure, you should avoid uncommitted changes in your repo before running playbooks that have Git module. Or you need to improve your playbook to skip Git checkout if there's uncommitted changes, but this I'd not recommend because you would need to double check if Git was checked or no manually. So, I think better to commit changes first and then run the playbook. And I think it makes sense, you probably want to deploy only when all the changes you made are committed into the repo to deliver it to host.
Cheers!
Ansible fails constantly on this command:
$ ansible-playbook ansible/playbook.yml -i ansible/hosts.ini -t permissions
PLAY [vb] ***********************************************************************************************
TASK [Gathering Facts] **********************************************************************************
ok: [192.168.33.10]
TASK [Fix var directory permissions] ********************************************************************
fatal: [192.168.33.10]: FAILED! => {"changed": false, "module_stderr": "Shared connection to 192.168.33.10 closed.\r\n", "module_stdout": "Traceback (most recent call last):\r\n File \"/home/vagrant/.ansible/tmp/ansible-tmp-1539374113.5349424-162400146138678/AnsiballZ_file.py\", line 113, in <module>\r\n _ansiballz_main()\r\n File \"/home/vagrant/.ansible/tmp/ansible-tmp-1539374113.5349424-162400146138678/AnsiballZ_file.py\", line 105, in _ansiballz_main\r\n invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\r\n File \"/home/vagrant/.ansible/tmp/ansible-tmp-1539374113.5349424-162400146138678/AnsiballZ_file.py\", line 48, in invoke_module\r\n imp.load_module('__main__', mod, module, MOD_DESC)\r\n File \"/tmp/ansible_file_payload_rBkmeP/__main__.py\", line 863, in <module>\r\n File \"/tmp/ansible_file_payload_rBkmeP/__main__.py\", line 849, in main\r\n File \"/tmp/ansible_file_payload_rBkmeP/__main__.py\", line 571, in ensure_directory\r\n File \"/tmp/ansible_file_payload_rBkmeP/__main__.py\", line 289, in recursive_set_attributes\r\n File \"/tmp/ansible_file_payload_rBkmeP/ansible_file_payload.zip/ansible/module_utils/basic.py\", line 1546, in set_fs_attributes_if_different\r\n File \"/tmp/ansible_file_payload_rBkmeP/ansible_file_payload.zip/ansible/module_utils/basic.py\", line 1313, in set_mode_if_different\r\nOSError: [Errno 1] Operation not permitted: '/var/www/project/var/sessions/prod'\r\n", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1}
to retry, use: --limit @/home/ivan/learn/SymfonyCasts/mootube/ansible/playbook.retry
PLAY RECAP **********************************************************************************************
192.168.33.10 : ok=1 changed=0 unreachable=0 failed=1```
But it does look like the permissions were partially changed back:
vagrant@vagrant-ubuntu-trusty-64:/var/www/project$ ls -ld var
drwxrwxrwx 5 vagrant vagrant 4096 Oct 12 19:51 var
vagrant@vagrant-ubuntu-trusty-64:/var/www/project$ ls -lR var
var:
total 104
-rwxrwxrwx 1 vagrant vagrant 55029 Oct 12 19:51 bootstrap.php.cache
drwxrwxrwx 2 vagrant vagrant 4096 Oct 12 19:53 cache
drwxrwxrwx 2 vagrant vagrant 4096 Oct 12 19:51 logs
drwxrwxrwx 4 vagrant vagrant 4096 Oct 12 19:51 sessions
-rwxrwxrwx 1 vagrant vagrant 34155 Oct 12 19:51 SymfonyRequirements.php
var/cache:
total 0
var/logs:
total 12
-r-xr-xr-x 1 vagrant vagrant 9772 Oct 12 19:51 dev.log
var/sessions:
total 8
drwxrwxrwx 2 vagrant vagrant 4096 Oct 12 19:51 dev
dr-xr-xr-x 2 www-data www-data 4096 Oct 12 19:51 prod
var/sessions/dev:
total 0
var/sessions/prod:
total 0`
Edit: nevermind, I see the problem: var/cache/prod was somewhen generated by the web server...
Hey Ivan,
Yes, files generated with web server will have different permissions. Btw, how did you fix the problem?
Cheers!
Hi guys: why would you tags deploy for Move Compose globally when you just want to deploy your new code to server? Is this a one time thing when you install composer? I think most of time u just need to run composer install when you deploy ur new code to server.
Hey Jian,
Good question :) Actually, as Ryan said, this is debatable: you might consider Composer as a "Server setup" task, not deployment. It's up to you. But yeah, there's no a good reason to do it, especially if you're installing Composer globally. But it makes more sense if you do not want to install composer globally, i.e. just download composer.phar, use it and then remove it from the server at all. So fell free to remove deploy tag from tasks which install Composer and move it globally.
Cheers!
// 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
"composer/package-versions-deprecated": "^1.11" // 1.11.99
},
"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
}
}
Hi guys, I've modified 'app/Resources/views/default/index.html.twig' in VM, then I run `ansible-playbook ansible/playbook.yml -i ansible/hosts.ini -t deploy` and my changes have gone (file 'app/Resources/views/default/index.html.twig' does not contain changes). What am I doing wrong? Looks like ansible deploy task ('Checkout Git repository') returns it to its original state
Suppose, in theory, I should commit and push changes in repo before run this task?