How to set an Ansible tier-specific inventory variable?

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!

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]

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.

just thought, you dont even need a variable, just the built in for inventory:

tier: ‘{{inventory_path|basename}}’

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.

The problem was that the variable ‘libffi-dev_ver’ I declared is actually a Jinja2 identifier 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 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.