Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

pre_tasks and set_fact

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

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

I want to guarantee that the symfony_env variable is always lowercased so that I can safely use. A cool way to do this is with a "pre task".

Add a new key called... well... pre_tasks and a new task called "Convert entered Symfony environment to lowercase":

---
- hosts: vb
... lines 3 - 19
pre_tasks:
- name: Convert entered Symfony environment to lowercase
... lines 22 - 26
tasks:
... lines 28 - 228

Pre-tasks are exactly like tasks... they just run first.

Wait... then what the heck is the difference between a "pre task" and just putting the task at the top of the task section?

Nothing! Well, nothing yet. But later, when we talk about roles - ooh roles are fancy - there will be a difference: pre tasks run before roles.

Anywho, in this pre task, we basically want to re-set the symfony_env variable to a lowercased version of itself. To do that, we'll use a new module: set_fact. We already know that we can set variables in 3 different ways: with vars, vars_prompt or by using the register key below a task. The set_fact module is yet another way.

Facts versus Variables

But wait... why set_fact and not set_variable? So... here's the deal: you'll hear the words "facts" and "variables" in Ansible... basically interchangeably. Both facts and variables can be set, and are referenced in exactly the same way. And while there do seem to be some subtle differences between the two, if you think of a fact and a variable as the same thing, it'll make your life easier. When you run the playbook, the first task is called "setup", and it prepares some facts about the host machine. That's usually where you hear the word facts: it's info about each host.

So, we're using set_fact... to set a fact... or a variable... Set symfony_env to {{ symfony_env|lower }}:

---
- hosts: vb
... lines 3 - 19
pre_tasks:
- name: Convert entered Symfony environment to lowercase
set_fact:
symfony_env: "{{ symfony_env|lower }}"
... lines 24 - 228

Love it! Oh, and just like with tasks, these can be tagged. We'll probably want this to run all the time... so let's use a special tag called always:

---
- hosts: vb
... lines 3 - 19
pre_tasks:
- name: Convert entered Symfony environment to lowercase
set_fact:
symfony_env: "{{ symfony_env|lower }}"
tags:
- always
... lines 26 - 228

Try the playbook!

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

Be difficult and use "PROD" in all capital letters again.

Ha, ha! This time, our playbook outsmarts us and lowercases the value.

Environment Variables and Pre Tasks

Remove the two debug tasks:

---
- hosts: vb
... lines 3 - 16
environment:
SYMFONY_ENV: "{{ symfony_env|lower }}"
... lines 19 - 26
tasks:
- ping: ~
... lines 29 - 222

Can we also remove the |lower from the environment variable? Actually... no! The environment section runs before tasks, even pre_tasks. And this has nothing to do with the order we have things in this file - environment always runs first. So, keep the |lower.

Using the symfony_env Variable

Ok, time to use our fancy symfony_env variable! First, when we install the composer dependencies, we currently have no_dev: no. But now, if the environment is prod, this can be yes. Let's use a fancy expression! {{ 'yes' if (prod == symfony_env) else 'no' }}:

---
- hosts: vb
... lines 3 - 26
tasks:
... lines 28 - 165
- name: Install Composer's dependencies
composer:
... line 168
no_dev: "{{ 'yes' if ('prod' == symfony_env) else 'no' }}"
... lines 170 - 224

Don't forget your curly braces. Weird, but cool! This is a special Jinja syntax.

Conditionally Running Tasks

Next, find the fixtures task. Hmm. If we're deploying in the prod environment... we might not want to load the data fixtures at all. But so far, we don't have any way to conditionally run a task: tasks always run.

Well guess what? We can tell a task to not run with the when key. In this case, say when: 'symfony_env != "prod":

---
- hosts: vb
... lines 3 - 26
tasks:
... lines 28 - 198
- name: Load data fixtures
... line 200
when: symfony_env != "prod"
... lines 202 - 224

Finally, down in the Clear cache task, instead of prod, use {{ symfony_env }}:

---
- hosts: vb
... lines 3 - 26
tasks:
... lines 28 - 205
- name: Clear cache
command: '{{ symfony_console_path }} cache:clear --env={{ symfony_env }}'
... lines 208 - 224

Let's try this thing! Re-run the playbook, but use -t deploy:

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

Use the prod environment. As we just saw, the vars_prompt runs always: it doesn't need a tag:

---
- hosts: vb
... lines 3 - 10
vars_prompt:
- name: symfony_env
... lines 13 - 224

Then, our "pre task" should run thanks to the always tag:

---
- hosts: vb
... lines 3 - 19
pre_tasks:
- name: Convert entered Symfony environment to lowercase
... lines 22 - 23
tags:
- always
... lines 26 - 224

By the time the "Composer Install" task executes, it should run with no_dev: yes, and then hopefully it'll skip data fixtures and change "Clear cache":

---
- hosts: vb
... lines 3 - 26
tasks:
... lines 28 - 165
- name: Install Composer's dependencies
composer:
... line 168
no_dev: "{{ 'yes' if ('prod' == symfony_env) else 'no' }}"
... lines 170 - 198
- name: Load data fixtures
... line 200
when: symfony_env != "prod"
... lines 202 - 205
- name: Clear cache
command: '{{ symfony_console_path }} cache:clear --env={{ symfony_env }}'
... lines 208 - 224

The "Install Composer's dependencies" does show as changed: that's a good sign: it should have installed less packages than before. And yea! It's skipping the fixtures!

In the VM, try to ls vendor/sensio. Ok cool! One of the require-dev dependencies is sensio/generator-bundle. That is not here, proving that the dev dependencies did NOT install this time. We are in business!

And before we continue, under the "Clear Cache" task, add changed_when: false:

---
- hosts: vb
... lines 3 - 26
tasks:
... lines 28 - 205
- name: Clear cache
... line 207
changed_when: false
... lines 209 - 224

That's not critical, it'll just prevent it from showing up as changed on every run.

Now, let's create a faster, smarter playbook by skipping some redundant tasks!

Leave a comment!

4
Login or Register to join the conversation
JuanLuisGarciaBorrego Avatar
JuanLuisGarciaBorrego Avatar JuanLuisGarciaBorrego | posted 5 years ago | edited

Hi!

When I run [composer install --no-dev] always there is a error in /AppKernel.php on line 29 because for the SensioGeneratorBundle is not installed. I'm using symfony 3.3.*

I have seen in http://symfony.com/doc/current/deployment.html
NOTE: If you get a "class not found" error during this step, you may need to run export SYMFONY_ENV=prod before running this command so that the post-install-cmd scripts run in the prod environment.

I don't know how to do this in Ansible


- name: Install Composer's dependencies
  composer:
    working_dir: "{{ symfony_root_dir }}"
    no_dev: "{{ 'yes' if ('prod' == symfony_env) else 'no' }}"
  tags:
    - deploy
  when: code_changed

Thanks!

Reply

Hey Juan,

Hm, you probably missed it, because we did export this env var in playbook.yml:


  vars_prompt:
    - name: symfony_env

  environment:
    SYMFONY_ENV: "{{ symfony_env|lower }}"

See chapter: https://knpuniversity.com/screencast/ansible/facts-variables-environment for more information. Or you can export env var on a specific task, see http://docs.ansible.com/ansible/latest/playbooks_environment.html - but in our case I think it's better to do globally as we did.

Good find about SYMFONY_ENV though ;)

Cheers!

Reply
JuanLuisGarciaBorrego Avatar
JuanLuisGarciaBorrego Avatar JuanLuisGarciaBorrego | Victor | posted 5 years ago | edited

Ooops!!!!!
I forgot that step .... =(

Thank you very much victor !!

Reply

You're welcome ;)

Cheers!

Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

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
        "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
    }
}
userVoice