Ansible structure

Here would be my proposal with ansible structure:

try to avoid /vars folder, then it’s harder to manage that.

Each role should have owners file, so we know who wrote it, and later we use that for PR reviewer/approver selection.

Each role as first task should be check.yml which would do assert of variables provided if they match needed format.

Also as first CI tasks, there should be ansible-lint, from begining we need to ensure we have standarts.


This looks good to me and it is usually what I end up implementing at employers or for personal projects. Two things jump out at me:

  1. Consider swapping /$playbooks.yml to /playbooks/$playbooks.yml

Usually if I’m working with ansible I treat the repository as a python project, so I like to reserve the root folder for Pipfile, .python-version file, .gitignore, and similar.

Of course, it is easy to move the playbooks later if there end up being too many. :slight_smile:

  1. Where does ansible.cfg live with this configuration? I assume also in the repository root?
1 Like

At this point you’ve just created a Collection.

And I would strongly suggest we do so. All we need, at that point, is to drop β€œgalaxy.yml” in the root of the structure and fill it in. Then the roles structure, the library structure, etc are already present.

For $dayjob I do Ansible unit testing using Molecule and other related tools (I wrote and maintain tox-ansible, for instance, to streamline testing and linting of Ansible roles and playbooks). Happy to help all over the place in this effort.

1 Like

Yes Master Repo with the Playbooks in it to build the infrastructure and then the galaxy|requirements.yml in the root in order to install the roles, that is in general the expected install path and allows the further distribution of the Ansible roles to the relevant teams.

I personally think removing the vars directory is a bad idea as it means we would add static paths for each distribution but not something that matters at this point.

P.S. Yes i know we are only running CentOS/Rocky but major versions can change things and we will inevitably end up with a state of supporting both major versions for at least a small amount of time.

as migration to other major versions always is a long process, then you can use if’s in variables to determine what to use, and if those are in group_vars/ it makes sense how you search for variables you want to change. whatever version you choose group_vars or vars it will be needed to manage. I can see where are you going, but that makes it harder to follow which host has which variables. at least in my experience

I understand the desire to simplify the variable view the first time i saw the ansible variable inheritance stack… A fairly common standard to follow in the galaxy community though is to have each role manage that so that it can be contained at the role level rather than the playbook level is all i am referring to. Completely agree vars should be used minimally everything should in general live in defaults or up at the group_vars directory. probably only this line would use vars with one file.

- name: Include OS-specific variables .
  include_vars: "{{ ansible_os_family }}-{{ ansible_distribution_version.split('.')[0] }}.yml"

Not tied to doing this most of my roles don’t do it just bringing it up as a point of conversation.
Kicking my self because it stopped me from moving to Cent8 - Actually no… no i’m not…


Hi, I also use ansible all the time for my daily job.

since include_vars overrides almost all other vars, I avoid using it to save myself debug time looking for the reason why some variable refuses to accept a certain value in a play.

Setting these things in defaults or preferably group_vars and ensure that the system is a member of that group.

I have gotten into the habbit of creating playbooks that contain 2 or more plays
Relying on the ansible feature that in a playbook variables remain in cache untill all the plays are finished ( and with tower you could extend even beyond that by enabling cache)

The first play is used to set up al the group and host variables.
If needed I add new hosts and/or groups to the inventory in the first play
After which the second play does all the heavy lifting.
The second play can use the new hosts and new groups and all other dynamic variables that came out of the first play.


Isn’t it better to separate the roles from the playbooks?
I normally create separate GIT repositories per role and include them with β€œroles/requirements.yaml”. This really works nice with AWX. If you use ansible on the command line you have to make sure you update the roles before running the playbook (AWX is doing that for you).
This way it’s easier to maintain a specific role. You can also easily reuse roles in other projects so this makes it more flexible.

The best way to create a role is to use ansible-galaxy for it: ansible-galaxy init <role-name>
this way the layout of the role is conform the Ansible Galaxy standards


I like the structure as presented, except I am not sure what to expect under /library/ - external scripts etc?

Just putting my humble approach to this out there as this discussion seems to be far from concluded.

In my projects I have more or less the following structure:
β”œβ”€β”€ ansible.cfg
β”œβ”€β”€ inventory
β”‚ β”œβ”€β”€ group_vars
β”‚ β”œβ”€β”€ host_vars
β”‚ β”œβ”€β”€ development.ini
β”‚ └── prod.ini
β”œβ”€β”€ playbooks
β”‚ β”œβ”€β”€ development.yml
β”‚ └── prod.yml
β”œβ”€β”€ roles
β”‚ β”œβ”€β”€ thorian93.ansible_role_common
β”‚ β”‚ β”œβ”€β”€ defaults
β”‚ β”‚ β”‚ └── main.yml
β”‚ β”‚ β”œβ”€β”€ handlers
β”‚ β”‚ β”‚ └── main.yml
β”‚ β”‚ β”œβ”€β”€ LICENSE
β”‚ β”‚ β”œβ”€β”€ meta
β”‚ β”‚ β”‚ └── main.yml
β”‚ β”‚ β”œβ”€β”€
β”‚ β”‚ β”œβ”€β”€ tasks
β”‚ β”‚ β”‚ └── main.yml
β”‚ β”‚ β”œβ”€β”€ vars
β”‚ β”‚ β”‚ β”œβ”€β”€ Debian.yml
β”‚ β”‚ β”‚ β”œβ”€β”€ RedHat.yml
β”‚ β”‚ β”‚ └── Suse.yml

Regarding the roles, playbooks and role directories I think there is more or less consensus here. They should be separated. Roles should be installed from their own repositories.

Regarding the vars discussion: For me there is a simple rule: Configurable variables go into defaults. Static variables (e.g. distribution specific paths, package names, etc.) go into vars, as there is no need to change those for a specific run. Those would only be changed if the distribution changed something and that would be done creating a new version of the role.

I did not find the time to look into Ansible collections really, so I do not know whether my approach is viable for the future.