Ansible’s immaturity compared to chef/puppet really shows when talking about the prioritized variable loading (facts).  In the chef world we had about 4 different places to store attributes with 3 different priorities.  This ordering is so important for organization and design that this page was one of two pages I had new people read and bookmark on their first day.  Up until Ansible 2 ( released Jan 2016), the loading of these variables was ill-defined.  Thankfully, we now have some good documentation on the intentions from Ansible with respect to this.

Once I have two different environments, my most basic organization requires that I have default variables in my role, but override some of them with environment specific values when in different environments.  The selling point of CM like Ansible is to use the same code to deploy to testing and production environments.  For this we most commonly externalize network locations, and authentication information.  Last year, when I wanted to have an organization where there were default variables for my roles, then overridden for my environment, I starting using a meta organization inspired by this blog post.  Here ( in Ansible 1 ) we cleverly dynamically load variable files based on a variables defined either on the command line or in the inventory.

For example we would have a playbook like this:

- hosts: myapp
  vars_files:
    - "{{ env }}/group_vars/env.yml"
    - "{{ env }}/group_vars/passwords.yml"
  roles: ...

An inventory like this:

[ my-app ]
127.0.0.1

[my-app:vars]
env=env1

[ my-db ]
127.0.0.2

[my-db:vars]
env=env1

 

My biggest annoyances with this design is that the include lines have to be in every playbook, and the path is relative to the playbook.  What I’d rather have is the include relative to the inventory no matter where it is.  Behold! I, and Ansible 2.0, have the solution [for your consideration].

If we make our inventory look like this:

[ my-app ]
127.0.0.1

[ my-db ]
127.0.0.2

[local-env:children]
my-app
my-db

We can define an arbitrary environment, then the group_vars will get autoloaded from directory tree [in alphabetical order]:

prod.ini
test.ini
local.ini
group_vars/
├── prod
│   ├── 1_environment.yml
│   └── 2_secret.yml
├── test
│   ├── 1_environment.yml
│   └── 2_secret.yml
└── local-env
├── 1_environment.yml
└── 2_secret.yml

Keep in mind I’m using git-crypt to encrypt all files matching *secret*.yml in that repository.

Finally Ansible has real organization and not just a meta-organization!  A quick playbook can be as simple as how we originally wanted it:

- hosts: myapp
  roles: ...

Until Tigger loses his bounce,
Jonathan Malachowski

Leave a comment

Your email address will not be published. Required fields are marked *

X