Ansible variable is undefined unless set as default

ansible

I am trying to add a new variable to an existing git repository full of Ansible files, that make heavy use of roles. So wherever foo is referenced, underneath

vars_files:
   - vars/aws.yml
   - vars/aws-credentials.yml

I've added the new line

   - vars/rpm-repo.yml

and I've created vars/rpm-repo.yml with contents:

---
yum_rpm_dir: https://example.com/repo/noarch

which is valid YAML according to the command given in this answer for checking whether a file is valid YAML.

And in roles/foo/tasks/main.yml I have changed a yum task to install this:

name: "{{ yum_rpm_dir }}/rest-api-{{ rest_api_version }}-1.noarch.rpm"

(the purpose of this explicit URL is to workaround a bug in our RPM repository.)

But I get:

fatal: [1.2.3.4]: FAILED! => {"failed": true, "msg": "'yum_rpm_dir' is undefined"}

So I thought, clearly I haven't understood the intricacies of how variables interact with roles in Ansible, so I'll add it as a default and that'll definitely work.

So I copied the file above to roles/foo/defaults/main.yml as well.

That works, but it's a hack. The whole point of making this a variable was that its value could be used by multiple roles without being copied and pasted.

tl;dr: How do I set a variable in Ansible properly so that it can be picked up by a role?

Best Answer

You don't specify which version of ansible is the one you are using, and there are important changes from 1.x to 2.x.

From the on-line documentation, the answer to

How do I set a variable in Ansible properly so that it can be picked up by a role?

would be:

In 1.x, the precedence is as follows (with the last listed variables winning prioritization):

  • “role defaults”, which lose in priority to everything and are the most easily overridden
  • variables defined in inventory
  • facts discovered about a system
  • “most everything else” (command line switches, vars in play, included vars, role vars, etc.)
  • connection variables (ansible_user, etc.)
  • extra vars (-e in the command line) always win

In 2.x, the order of precedence is more specific (with the last listed variables winning prioritization):

  • role defaults (Tasks in each role will see their own role’s defaults. Tasks defined outside of a role will see the last role’s defaults)
  • inventory vars (Variables defined in inventory file or provided by dynamic inventory)
  • inventory group_vars
  • inventory host_vars
  • playbook group_vars
  • playbook host_vars
  • host facts
  • play vars
  • play vars_prompt
  • play vars_files
  • registered vars
  • set_facts
  • role and include vars
  • block vars (only for tasks in block)
  • task vars (only for the task)
  • extra vars (always win precedence)

The answer to your specific use case requires that you provide the location of the var files (as it cannot be inferred from the data provided) in the directory structure. Depending on where those files where placed, they have a different precedence.

I personally prefer to group data under group_vars (check the best practices document for the preferred layout), so I can assign data to groups of hosts, mainly because this most commonly maps directly to roles.