guidelines structure - adeck/ansible-deployments GitHub Wiki

Repo Structure Guidelines Index

Notation Used in This Document

Whenever a directory tree is shown, it is shown in tree's output format, with a few notable exceptions.

  • All directories are suffixed with a / character, all symbolic links are suffixed with an @, and all regular files lack a suffix.
  • If and only if a directory has ... as a child it is permissible for that directory to have children not listed. Usually, it should be relatively obvious when this would be the case for a directory, but it is equally important to note when it would not be the case. If a directory should only contain symlinks, ... is suffixed with an @. If a directory should only contain directories, ... is suffixed with a /. Otherwise a directory may contain files, directories, or symlinks.

Goals

The goals underlying the structure of this repository are as follows:

  • Every role should be easily pluggable into any project which might wish to use that role, which means that:
    • All variables should be easy to locate.
    • All variables should be easy to override.
    • Variables of the same name are used consistently across roles.
    • Variables which depend upon project, or upon the specific details of a deployment (for example, the set of ports which should be open to the public in a given application), are documented in the wiki page for the role and left undefined (so that the play will fail without hardcoding an obscure default).
  • Each project should be easily usable and customizable by any end user, which means that:
    • A project is defined by a playbook, a set of project-agnostic roles, and a set of groups which together define all variables except those which the end-user would need to define (e.g. IP address, connection / authentication parameters, hostname, DDNS update auth token, etc.).
    • All the end user needs to do to get their project running is define the inventory file, fill in the host_vars for their setup as specified in the documentation for the role, and run the playbook.

Everything else in this document can be understood within that framework.

Overall Structure

.
├── README.md
├── lib.sh
├── projects/
|   └── ...
└── shared/
    ├── ansible.cfg
    └── roles/
        └── ...

The shared directory is for any resources that would be shared across projects. At the moment, that only includes roles and ansible.cfg but, as the repo matures, support for sharing further resources may be added to this specification. Apart from README.md, you'll notice all of the filenames are lowercase and contain no spaces. This is intentional. As with variables, all files / directories are named using lower_snake_case, and limited to lowercase alphanumerics ([a-z0-9]), underscores (_), and full stops (.).

The projects directory contains a single directory for each project, as defined below.

Project Structure

Within the context of this repo, a project is a collection of playbooks, roles, and groups intended to accomplish a given goal. Playbooks and groups are unique to projects. Roles, however, are shared between multiple projects. This is what a person would normally think of as an "ansible project", with the simple caveats that:

  • It shares its roles entirely with other projects.
  • It conforms to a relatively strict set of constraints, as outlined below.

Specifically, the directory structure is as follows (directories should be omitted if they would be empty):

.
├── ansible.cfg@
├── plays/
|   └── ...
├── inventory/
|   ├── template.ini
|   └── group_vars/
|       └── .../
|           └── ...
└── roles/
    └── ...@

As may be expected, ansible.cfg and the inventory and group_vars directories behave as they normally do in an ansible deployment, and should be used similarly; inventory files should go directly under inventory, beside group_vars and host_vars (although inventory files other than template.ini, and group_vars, should never be pushed to the repository). Directories should be used for each group's entry in group_vars, so that the vars files for each group are further separated by category, and are all suffixed with .yml (making it that much easier for text editors to automatically highlight).

NOTE: While placing the group_vars and host_vars directory beside inventory files in their own directory, rather than keeping them alongside the playbooks, is unusual, it is written into ansible. Which means that, once you've specified the inventory file to use via -i inventory/<FILE>, you don't need to pass any other options to account for the group_vars or host_vars locations.

The roles directory should contain only symlinks to directories in the shared/roles directory of this repo. The plays directory should contain playbooks, and the inventory directory should contain inventory files (which, pivotally, do not contain variable assignments, only group membership).

template.ini is the inventory file developers of the project are using, which contains only group definitions, and comments saying # insert hosts here where the hosts would be listed. The idea being that an end user could simply copy template.ini, replace the # insert hosts here comments with their list of hosts, define host_vars, and everything would work out of the box.

For more information on how the inventory and host_vars should be handled, see the document on How to Run a Deployment.

Role Structure

.
├── tasks/
|   ├── main.yml
|   └── ...
├── handlers/
|   └── ...
├── vars/
|   └── defaults/
|       └── ...
├── files/
|   └── ...
└── templates/
    └── ...

The omission of defaults and meta is intentional. defaults is omitted because it only loads defaults/main.yml, which means that it is impossible in the defaults directory to split variables into multiple files / organize by category. As such, the current solution is to include_vars (from within tasks/main.yml) all the files under vars/defaults/, and then do the same thing with all the files in vars/extern/ (which should not be defined in the repo, because it is only necessary if a user wants to override a default that should never need to be overridden. It is a convenience provided to the end-user which repo developers should never need to use).

For more information on how vars/extern is to be used, see the document on How to Run a Deployment.

Compliance Functions

To make compliance with these guidelines easier, the lib.sh file contains some useful functions which perform common tasks. The file is intended to be sourced.

The functions are as follows:

  • create <ROLE> when your CWD is the projects directory, create will generate an empty project skeleton.
⚠️ **GitHub.com Fallback** ⚠️