Ansible playbooks for configuration management in push mode.
❌ - false
✔️ - true
Complete - role is implemented and conceptually in a finished state. May contain errors or bugs if dry-test and real test have not been performed.
Dry-test - role has been tested in a dry-run mode and did not error.
Real-Test - role has been tested in a real environment and did not error.
| Role | Complete | Dry-Test | Real-Test |
|---|---|---|---|
| mounts_exports | ✔️ | ✔️ | ❌ |
| nfs | ❌ | ❌ | ❌ |
Before all, set the Ansible Vault password in home: vim ~/.ansible-vault-pass
Then install collection requirements (not needed when using ansible-parallel which already does this):
ansible-galaxy collection install -r requirements.ymlThen use ansible-playbook or ansible-parallel bash script to run playbooks.
To use a jumphost (for example from your local machine over base):
- Go to
hostsfile - Uncomment the
ansible_ssh_common_argsvariable under [all:vars] - Uncomment later when you have finished testing locally or run
git checkout hosts
All playbooks set their default remote user used by the automatic scheduled system like so:
remote_user: ansibleIf you do not have access to this user directly then override the remote_user variable with the following flag: -e 'ansible_user=<YOUR USER HERE>'
Each host should belong to ONE group to preserve readability.
To create a new group:
- Add it to the
hostsinventory file:
[<HOST GROUP NAME>]
<HOSTNAME> ansible_host=<HOST IP>- Create a playbook directory under
playbooks/directory and define list of roles in the fileplaybooks/<PLAYBOOK NAME>/main.yml.
Disabled roles can still be defined in playbooks but will be skipped on runs. Useful for when the role is in a bad/incomplete state but it is desirable to define the order of execution or add it to list of roles for the future.
To disable a role, define it in playbooks/vars_disabled_roles.yml:
disabled_roles:
# rrr disabled reason - <your reason here>
rrr: trueFor info, add a comment with reasons why the role is disabled.
Ansible does apply variable precedence for the 22 different places you can configure variables. For this repository, we only need to know about 6, for which the order of precedence from least to greatest (the variables listed last override/replace all other variables) is as follows:
- Role defaults (defined in
roles/<ROLE NAME>/defaults/main.yml) - Inventory file variables
- Playbook group vars (defined in
playbooks/<PLAYBOOK NAME>/group_vars/all.yml) - Playbook host vars (defined in
playbooks/<PLAYBOOK NAME>/host_vars/<HOST NAME>.yml) - Playbook vars files (included in
playbooks/<PLAYBOOK NAME>/main.ymlusingvars_files:) - Extra vars (defined in command line using
-e EXTRA_VARS, --extra-vars EXTRA_VARSflags)
Common variables should be defined in files under playbooks/ and imported with vars_files list.
For example playbooks/vars_common_all.yml contains variables that every single host needs access to. Then the file is imported inside the playbook playbooks/group_ggg_example/main.yml as follows:
- name: PLAYBOOK FOR GROUP 'GGG_EXAMPLE'
hosts: ggg_example
vars_files:
- ../vars_common_all.yml
- ../vars_disabled_roles.ymlAfter the announcement of deprecating hash_behaviour=merge option in Ansible it is no longer possible to implicitly combine dictionaries with same names in role, group and host variables. Instead separate dictionaries should be defined and then combined as needed, this is more explicit and improves readability.
AVOID COMMITING PLAINTEXT SECRETS, USE ANSIBLE-VAULT!
Using ansible-vault it is possible to create encrypted variables and files that can be commited to the repository.
In ansible.cfg the vault_password_file variable defines in which file the ansible-vault password should be defined in.
Once the vault password file is set up you can use ansible-vault as follows:
Secret variables can be set by encrypting strings:
ansible-vault encrypt_string password123 And pasting the output in place of a variable:
my_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
66386439653236336347626566653063336164663966303231363934653561363964363833
3136626431626536303530376336343832656537303632313433360a626438346336353331View encrypted variable with:
ansible localhost \
-m debug \
-a "var=<VAR NAME>" \
-e "@<PATH TO VAR FILE>"Encrypt files with:
ansible-vault encrypt encrypt_me.txtView encrypted files with:
ansible-vault view encrypt_me.txtEdit encrypted files with:
ansible-vault edit encrypt_me.txtDecrypt encrypted files with:
ansible-vault decrypt encrypt_me.txtEach playbook in playbooks/:
- has a name starting with:
group_(if it is applied to a group of machines)host_(if it is applied to one host)function_(if it is applied to a functionality).
- has a file named
main.ymlto describe the playbook with tasks and roles. - may have a
group_vars/all.ymlto set the default values of variables for all hosts executing the playbook. - may have a
host_vars/hhh.ymlto overwrite some variable values for that hosthhhexecuting the playbook. - may have multiple vars files imported with
vars_filesto include variable files that are common to some groups or hosts. - does NOT have a role directory as it is outside of the playbook.
- does NOT have the
ansible.cfgconfiguration file since it is one level upper.
Template structure of the playbooks:
playbooks/
vars_common_all.yml
vars_disabled_roles.yml
group_ggg/
main.yml
group_vars/
all.yml
host_hhh/
main.yml
host_vars/
hhh.yml
function_fff/
main.ymlExample structure of playbook playbook/ppp/main.yml:
- name: PLAYBOOK FOR GROUP 'GGG'
hosts: ggg
vars_files:
- ../vars_common_all.yml
- ../vars_disabled_roles.yml
roles:
- { role: pre, tags: [ pre ], when: not (disabled_roles.pre | default(false)) }
- { role: rrr, tags: [ rrr ] }
- { role: post, tags: [ post ] }It is possible to disable a role for host hhh for example, by defining in playbooks/group_ggg/host_vars/hhh.yml:
disabled_roles:
rrr: trueUse vars_files to include variable files that are common to some groups or hosts.
Each role in roles/ can be used in any playbook in playbooks/ppp/main.yml.
Structure of a role:
roles/
<ROLE NAME>/
tasks/ # Tasks of role
defaults/ # Default variables are defined here
files/ # Files and templates
handlers/ # Handler tasks
README.md # Role usage info and explanationsBefore all, keep it simple. If you need something specific configured, create a role that simply does it without complicated logic or variable handling. Add complexity only as other hosts need more different configurations. For example, mounts and exports are usually unique to host groups, as such it requires a more complex generic logic to handle multiple different mounts and exports. But on the other hand when configuring a single bind DNS server, the logic can be much more simpler, if there is only one DNS server then the role can be made without complex variable handling.
All updates should be done in a separate branch, tested and then merged into the master branch.
Naming for branches should use the following convention: <topic>/<short description>. Example: role/firewalld or playbook/group_training.
When registering output of a command, use the register keyword and save the output variable name prefixed with r_. Example:
- name: Check for sudo
ansible.builtin.stat: path=/etc/sudoers
register: r_sudoers
- name: Install sudo block
when: not r_sudoers.stat.existsWhen using block of tasks, define when condition right under the name remove spaces from the tasks to make it more readable. Example:
- name: Install Zabbix for CentOS/RedHat
when: ansible_os_family in ['CentOS', 'RedHat']
block:
- name: Add Zabbix repo
ansible.builtin.yum:
name: https://repo.zabbix.com/zabbix/5.0/rhel/7/x86_64/zabbix-release-5.0-1.el7.noarch.rpm
state: present
- name: Install Zabbix agent
ansible.builtin.yum:
name: "{{ zabbix_agent_packages }}"
state: latestComment Ansible-managed files with # Managed by Ansible, do not edit manually - changes made here will be overwritten! at the top. Use the ansible_managed variable to render the comment using jinja. Do not suffix files with jinja if they do not include any other logic besides including the comment variable.
"Unhide" dot files with the prefix dot_. For example, .bashrc should be named dot_bashrc.
jinja templates which should be suffixed with .jinja and not .j2.
- In Git, names are merged with a dash ('-'), such as jamlab-ansible. This is for historical reasons.
- In Ansible, names are merged with an underscore ('_'), such as group_vars or host_vars.
- In Linux, names are merged with a dash ('-'), such as NetworkManager-wait-online.service or system-auth.