How to set an Ansible tier-specific inventory variable?

109 views
Skip to first unread message

Robert F

unread,
Apr 29, 2016, 12:51:32 PM4/29/16
to Ansible Project
Is it possible to create an Ansible inventory variable that isn't associated with an inventory host or group but the server tier the playbook is run on?  I have an Ansible role that installs the libffi-dev package using APT, but I may want to install a different version of that package on each server tier.  I've created a variable "libffi-dev_ver" for that purpose.  I also have the inventory files "development", "staging", and "production" that correspond to each of my tiers.

My role's main task, which is called from my main site.yml playbook, checks that version variable exists prior to running the role:

    # roles/misc_libs/tasks/main.yml
    - include: check_vars.yml tags=misc_libs
    - include: misc_libs.yml tags=misc_libs

check_vars.yml checks to ensure that the package version variable exists:

    # roles/misc_libs_tasks/check_vars.yml
    - name: check that required role variables are set
      fail: msg="{{ item }} is not defined"
      when: not {{ item }}
      with_items:
        - libffi-dev_ver

The misc_libs role actually uses that variable to install the package:

    # roles/misc_libs/tasks/misc_libs.yml
    - name: install libffi-dev
      apt: >
        pkg=libffi-dev={{ libffi-dev_ver }}
        update_cache=yes
        cache_valid_time=3600
      become: True

My development inventory file looks like this:

    # development
    [webservers]
    web01.example.com ansible_ssh_host=<ip_address>

    [dev:children]
    webservers
    
    [webservers:vars]
    libffi-dev_ver="3.1-2+b2"

When I run this command:

    ansible-playbook -i development site.yml -l webservers

I get this Ansible error:

    fatal: [web01.example.com] => error while evaluating conditional: not libffi-dev_ver

What is the correct way to declare a package versioning variable like this in Ansible?  The variable's value depends on the server tier which indicates to me that it goes in an inventory file since inventory files are server tier-specific.  But all inventory variables seem to have to be associated with a host or group.  I've done that but the role still doesn't see the variable.  I could add a task to the role that detects the server tier and uses a "when" conditional to set the variable accordingly but that solution seems ugly because if you're installing multiple packages in a role, you'd need three conditionals for each package version variable.  I've looked through the Ansible documentation and read numerous blog posts on setting up multi-tier playbooks but I don't see this particular situation addressed.  What's the right way to declare a tier-specific variable like this?

Thanks!

Brian Coca

unread,
Apr 29, 2016, 1:06:45 PM4/29/16
to ansible...@googlegroups.com
There are several ways.

Make all machines in the development inventory part  of the development group, same with other 'tier's, then you can have 'tier vars'.

make each var a composite:

libffi:
  dev: 3.1-2+b2
  qa:  3.0-1
  prod:  3.0-1

Then have the 'tier' var defined by inventory file (under all:vars), then always acceiss this way: libffi[tier]


That should be enough to give you an idea.

----------
Brian Coca

Robert F

unread,
Apr 29, 2016, 1:23:27 PM4/29/16
to Ansible Project
Thanks.  Initially, I did have all machines in my dev inventory a part of a "dev" group but I was getting the same error using that approach.  I thought it should work too but it didn't for some reason.  But your idea on making each var a composite is interesting so I'm going to give it a try.

Brian Coca

unread,
Apr 29, 2016, 1:30:20 PM4/29/16
to ansible...@googlegroups.com
just thought, you dont even need a variable, just the built in for inventory:

tier: '{{inventory_path|basename}}' 


----------
Brian Coca

Robert F

unread,
Apr 29, 2016, 5:59:03 PM4/29/16
to Ansible Project
Brian, I found another way to do this and I'll post my solution shortly.  I think your solution will work too but my solution allows me to keep tier-specific variables in their own separate files.  While one could argue that it would be simpler to maintain them if they were all in one file, I kind of like keeping them in separate files.  Thanks for your help.

Robert F

unread,
Apr 29, 2016, 5:59:29 PM4/29/16
to Ansible Project
The problem was that the variable 'libffi-dev_ver' I declared is actually a Jinja2 [identifier](http://jinja.pocoo.org/docs/dev/api/#notes-on-identifiers) that must adhere to Python 2.x naming rules.  The '-' (dash) is an invalid character according to these rules.  Once I changed it to an '_' (underscore), I no longer got the error.

Also, the check_vars.yml playbook is actually unnecessary.  There is an Ansible configuration variable [error_on_undefined_vars](http://docs.ansible.com/ansible/intro_configuration.html#error-on-undefined-vars) which will cause steps containing an undefined variable to fail.  Since it's true by default, I don't need to run check_vars.yml as all variables are already being checked.

One place to declare server tier-specific variables seems to be in a file in the group_vars directory that has the same name as the group which is named after that tier in your inventory file.  So in my case my 'development' inventory file contains a 'dev' child group.  Therefore, I created a file 'group_vars/dev' and declared a variable in that file called 'libffi_dev_ver' which I can reference in my misc_libs.yml playbook.
Reply all
Reply to author
Forward
0 new messages