I am trying to determine the best approach to define global default variables for my Ansible project. I have a project that consists of multiple playbooks, multiple roles. I also have some custom modules, etc…
Let’s say both my roles use git and require the git repository name to perform a job. So, my question is, where should I define the git repository name?
Based on Ansible best practices, role variables should use role name as a prefix (role1_git_repositoy_name). If I do this, I have to have the git repository defined in two places (defaults in each role).
On the other hand, I can define the Git repository name in the group_vars/all.yaml like this:
There is no right answer here. It’s a personal preference. If you had some additional criteria, maybe you could lean toward some definitive answer.
Looking at the provided examples, the first one is the most clean. Just a single var defined in group_vars or host_vars. You can also put a single assert task at the beginning of the role to test if git_repo_name is defined and has proper value.
The second one is just plain ugly.
The third one, my favorite, is a nice alternative but it unnecessarily grows the number of variables (more resources consumed), with essentially the same value, in case you want to globally force the value. On the other hand, this is a must have if you want to have the ability to override variable per role i.e. you don’t want to have it forced globally. Fallback to default value is also possible.
We have a “defaults” git project where we keep a few (very few) things global to all our projects. This includes an inventory, the ansible-lint configuration our ci/cd jobs use, and a group_vars/all/_ansible-defaults.yml file. That file contains variables that projects may need but are beyond the scope of any single project: load balancer SNAT pools, Jenkins user id/group names, proxy strings, etc.
Whenever any of those files changes, the “defaults” project’s Jenkins pipeline pushes changes to the appropriate places. In the case of group_vars/all/_ansible-defaults.yml, it goes through all our git projects looking for an existing group_vars/all/_ansible-defaults.yml file and updates/commits/pushes the new version of that file in the main branch.
By making group_vars/all a directory rather than a file, projects can still have their own group_vars/all/this.yml, group_vars/all/that.yml, group_vars/all/the_other_thing.yml, etc. files without fighting with the defaults project for the space in the all group_vars namespace.
I think neither 1 nor 3 is right, and for the same reason.
A role is a reusable unit, often authored by someone else. It has no business reading a bare, unnamespaced variable out of the project’s global namespace. git_repo_name is generic enough that any role may claim it — so the day role1 and role2 no longer share a repo, or the day you change git_repo_name assuming a single consumer, you cannot know what you just broke. The dependency lives inside the roles, where grepping your project finds nothing. Option 3 doesn’t fix this: it moves the same reference into defaults, keeps the coupling, and hides it one layer deeper — where lazy evaluation makes it fail late, far from the cause.
Prefer 2: each role consumes only its own prefixed interface (roleX_git_repo_name), and the project wires it up — group_vars/<group>/roleX.yml. Dependencies become visible and greppable, and splitting the two roles later is a one-line edit instead of a role rewrite. Sharing a value should be a choice the project makes at the call site or in a common group, not a constraint the role assumes — and never through role defaults, whose precedence is too low to hold that decision.
So yes: manage this dependency in the Ansible project, not inside the roles.