ansible roles galaxy

Core Idea

Imports are resolved statically at parse time while includes are resolved dynamically at run time; roles package tasks into redistributable units, and Galaxy is where you share them.

  • import_tasks and import_role: everything expands up front, in listed order.
  • Includes: dynamic includes and role includes that decide what runs at execution time.
  • Roles: directory structure, pre-tasks and post-tasks, and Ansible Galaxy.

Imports & Includes

The import_* feature allows you to include tasks, or even whole roles, in the tasks section of a play through the use of the keywords import_tasks and import_role.
When importing files in other playbooks statically, Ansible runs the plays and tasks in each imported playbook in the order they are listed, just as if they had been defined directly in the main playbook.

The include_* features allow you to dynamically include tasks, vars, or even whole roles by the use of the keywords include_tasks, include_vars, and include_role.
This is often used in roles to separate or even group tasks and task arguments to each task in the included file.
Included roles and tasks mayβ€”or may notβ€”run, depending on the results of other tasks in the playbook. When a loop is used with include_tasks or include_role, the included tasks or role will be executed once for each item in the loop.

Imports

Import variable files

vars_files:
	- vars.yml

Tasks can easily be included in a similar way. In the tasks: section of your playbook, you can add import_tasks directives like so:

tasks:
	- import_tasks: imported-tasks.yml

Example

# user.yml
---
- name: Add profile info for user
  ansible.builtin.copy:
    src: example_profile
    dest: "/home/{{ username }}/.profile"
    owner: "{{ username }}"
    group: "{{ username }}"
    mode: 0744
 
- name: Add private keys for user
  ansible.builtin.copy:
    src: "{{ item.src }}"
    dest: "/home/{{ username }}/.ssh/{{ item.dest }}"
    owner: "{{ username }}"
    group: "{{ username }}"
    mode: 0600
  with_items: "{{ ssh_private_keys }}"
 
- name: Restart example service
  ansible.builtin.service:
    name: example
    state: restarted
# main.yml
- name: Configure users
  hosts: all
  vars:
    username: johndoe
    ssh_private_keys:
      - { src: /path/to/johndoe/key1, dest: id_rsa }
      - { src: /path/to/johndoe/key2, dest: id_rsa_2 }
  tasks:
    - import_tasks: user.yml
      vars:
        username: johndoe
        ssh_private_keys:
          - { src: /path/to/johndoe/key1, dest: id_rsa }
          - { src: /path/to/johndoe/key2, dest: id_rsa_2 }
 
    - import_tasks: user.yml
      vars:
        username: janedoe
        ssh_private_keys:
          - { src: /path/to/janedoe/key1, dest: id_rsa }
          - { src: /path/to/janedoe/key2, dest: id_rsa_2 }

Includes

---
- name: Setup Web Server
  hosts: webservers
  become: true
  vars_files:
    - vars/main.yml
 
  tasks:
    - name: Load environment-specific variables
      include_vars: "vars/{{ env }}.yml"
 
    - name: Install required packages
      include_tasks: tasks/install-packages.yml
 
    - name: Configure web server
      include_tasks: tasks/configure-webserver.yml
 
    - name: Start and enable web server
      include_tasks: tasks/start-service.yml

Dynamic Includes

Depending on the number of operating systems supported by the role, this can lead to a lot of boilerplate for the include_tasks:

- include_tasks: Redhat.yml
  when: ansible_os_family == 'Redhat'
 
- include_tasks: Debian.yml
  when: ansible_os_family == 'Debian'

Ansible has allowed users to include a file dynamically by using variable substitution. This is called a dynamic include:

- name: Play platform specific actions 
  include_tasks: "{{ ansible_os_family }}.yml"

However, there is a drawback to using dynamic includes. If Ansible does not have enough information to populate the variables that determine which file will be included, ansible-playbook --list-tasks might not list the tasks.

Role Includes

The include_role clause differs from the import_role clause, which statically imports all parts of the role. By contrast, include_role allows us to select what parts of a role to include and use, as well as where in the play:

- name: Install nginx 
  yum: 
	  pkg: nginx 
- name: Install php 
  include_role: 
	  name: php 
- name: Configure nginx 
  template: 
	  src: nginx.conf.j2 
	  dest: /etc/nginx/nginx.conf

Roles

Ansible roles are a structured way to organize and reuse configuration, code, and tasks in Ansible projects.

Directory Structure

my_role/
β”œβ”€β”€ tasks/         # Main tasks of the role (defined in main.yml).
β”œβ”€β”€ handlers/      # Handlers to trigger upon task completion.
β”œβ”€β”€ files/         # Static files to copy to managed hosts.
β”œβ”€β”€ templates/     # Jinja2 templates for dynamic configuration files.
β”œβ”€β”€ vars/          # Variables with high priority (defined in main.yml).
β”œβ”€β”€ defaults/      # Default variables with low priority (defined in main.yml).
β”œβ”€β”€ meta/          # Metadata about the role, e.g., dependencies.
└── tests/         # Test playbooks to verify the role.

There are only two directories required to make a working Ansible role:

role_name/
β”œβ”€β”€ meta/
β”œβ”€β”€ tasks/

Pre-Tasks & Post-Tasks

Ansible allows you to define the order in your playbooks:

  • A list of tasks that execute before the roles with a pre_tasks section
  • A list of roles to execute
  • A list of tasks that execute after the roles with a post_tasks section
- name: Deploy
  hosts: web
  vars_files: 
	  - secrets.yml
pre-tasks:
	# Pre Task Here
roles:
	# Role
post-tasks:
	# Post tasks here..

Ansible Galaxy

Collection of pre-made ansible roles.

ansible-galaxy role install geerlingguy.apache \ 
	geerlingguy.mysql geerlingguy.php
  • ansible-galaxy role list displays a list of installed roles, with version numbers
  • ansible-galaxy role remove [role] removes an installed role
  • ansible-galaxy role init can be used to create a role template suitable for submission to Ansible Galaxy