Ansible has rapidly become one of the most popular open source automation tools with over 6 million downloads and 6x user growth year-over-year. This tremendous adoption is driven by IT teams needing to embrace automation and configuration management for complex infrastructure and deployment environments.
Ansible enables robust automation through playbooks which declaratively define ordered sets of tasks to execute against configured hosts. Playbooks provide tremendous capability but can become large, tedious to maintain, and difficult to reuse code across.
Ansible roles emerged to ease playbook authoring by enabling reusable abstractions through Role interfaces. Roles allow playbook authors to break functionality into separate self-contained content blocks with designated directories for tasks, variables, dependencies and more.
However, roles with all contained tasks statically import functionality which may not always be needed or customizable enough per usage. Ansible include_role overcomes these reuse limitations by dynamically executing roles or components at runtime based on inclusion parameters versus fixed imports.
In this comprehensive guide, we will cover how Ansible experts leverage include_role for streamlined flexible playbook authoring utilizing some key patterns:
- Conditionally including role execution
- Overriding variables and defaults
- Filtering tasks to execute
- Permitting duplicate role execution
- Iterating over multiple role inclusions
- Embedding role assembly via includes
- Integrating with role dependencies
These techniques simplify playbook code, encapsulate role functionality cleanly for reuse, and avoid fixed dependencies. Using include_role effectively lets roles become truly dynamic modular abstractions.
Let‘s explore include_role in depth including advanced usage.
Why Dynamic Roles?
Traditionally engineers directly used Ansible modules and wrote extensive playbooks containing all automation logic end-to-end. This leads to challenges:
- Verbose playbooks with intermingled steps become difficult to maintain
- Hard to reuse common procedures across playbooks without copy-pasting
- Hard to test in modular fashion
Ansible roles emerged as abstractions by encapsulating functionality into separate directories containing logical components:
roles/
webserver/
files/
templates/
tasks/
handlers/
vars/
defaults/
meta/
Roles provide interfaces making playbooks much cleaner:
- hosts: webservers
roles:
- webserver
However, roles have limitations around flexibility and reuse:
- All role tasks execute regardless of necessity
- Role variables are fixed unless changed in defaults
- No variations in role execution without editing role definition
Ansible include_role addresses these limitations by enabling playbook authors to dynamically execute roles on-demand with overrides and filters rather than via static imports.
Core Capabilities of Include_Role
The include_role module provides a rich interface enabling dynamic role usage within playbook tasks themselves. Basic syntax:
- name: Include role dynamically
include_role:
name: myrole
This runs all tasks defined within myrole exactly as if the role is imported but doesn‘t require a fixed import. include_role supports parameters:
| Parameter | Description |
|---|---|
| name | Name of role to include |
| tasks_from | File with alternate role tasks to run |
| defaults_from | File with alternate default variables |
| vars | Set role variables at runtime |
| apply | Filter role tasks by tags |
| allow_duplicates | Permit including role multiple times |
These parameters enable extensive customization directly embedding role execution dynamically within playbook tasks themselves.
Let‘s analyze some common usage patterns taking advantage of include_role flexibility.
Conditionally Including Roles
Ansible roles aim to encapsulate reusable functionality, but that doesn‘t mean all tasks possibly defined by a role always warrant execution.
Using include_role, playbook authors can choose to include roles on demand conditionally versus fixed static imports upfront.
- name: Conditionally install web server
include_role:
name: webserver
when: installd_web|bool == true
Here if the inventory installd_web variable evaluates true, the web server role executes for those hosts, otherwise it will be skipped. Avoid assumptions of fixed role execution order!
Conditionals can also leverage Ansible facts like the operating system family:
- name: Configure RHEL web servers
include_role:
name: webserver
when: ansible_os_family == "RedHat"
This allows flexible OS specific tuning by variable definitions within the role execution limited to RHEL hosts only.
Inclusion based on registered facts from previous playbook steps is also very powerful for precision role execution based on discovered details.
Overriding Role Variables
A key benefit of roles is variability through input variables customized per environment. However, managed default values are fixed in roles/rolename/defaults/main.yml limiting runtime flexibility.
The vars parameter for include_role allows defining or overriding variables explicitly at role include time without changing role defaults:
- name: Install apache
include_role:
name: webserver
vars:
pkgname: httpd
port: 7080
Here the role likely defines configurable pkgname and port, but runtime values are overridden for this particular webserver instance vs. updating role defaults.
Filtering Role Tasks
Roles should encapsulate all related functionality which may be vast covering many potential use cases. However, playbook authors may intend to only execute a subset of role tasks for particular inclusions.
include_role provides an apply parameter to filter role tasks brought in based on tags or named task includes.
For example:
- name: Run web install procedures only
include_role:
name: webserver
apply:
tags:
- install
This includes only tasks tagged install from the extensive webserver role. Avoid assumptions around fixed order!
The same applies for filtering via named task include files with tasks_from rather than assuming everything under tasks/main.yml. Playbook authors choose components.
Permitting Duplicate Inclusions
By default, Ansible protects against the same role included twice to avoid accidental side effects from duplicate module executions. However, for some advanced usages playbook authors intentionally want duplicates permitted.
The allow_duplicates flag overrides protections enabling duplicate includes:
- name: Allow repeat web server config
include_role:
name: webserver
allow_duplicates: yes
For example configuring multiple distinct web server instances deployed to same hosts. Use carefully! as deduplication often provides safety.
Iterating Over Dynamic Includes
By combining Ansible looping with include_role, playbook authors can iterate role execution to configure multiple similar instances.
For example, setting up multiple distinct database servers:
- name: Configure DB servers
include_role:
name: database
loop:
- db1
- db2
vars:
dbname: "{{ item }}"
Here the single database role is included twice, each iteration assigning the loop item to customized dbname var. Avoid duplication with role revisions!
The same applies for multi-tier deployments configuring integrated app+db tiers together via iteration.
Embedding Include_Role Within Roles
While designed for dynamic role usage within playbooks, include_role also enables role authors to break role internal logic across multiple task files while dynamically compiling the full role execution at runtime based on inclusion directives.
For example:
roles/
webapp/
tasks/
main.yml
install.yml
configure.yml
Where main.yml dynamically assemblies role tasks:
- name: Compile webapp role
import_role:
name: webapp
tasks_from: install
import_role:
name: webapp
tasks_from: configure
When another playbook then includes this webapp role, it executes the modular install and configure task subsets as part of the named role based on inclusion directives.
Integrating Role Dependencies
As roles grow more complex encapsulating application logic, they have dependencies on common functionality separate roles provide. Role dependencies map required roles rather than requiring playbook authors explicitly load all transitive dependencies.
These dependent roles automatically execute prior to the target role inclusion via include_role.
For example in webapp role meta/main.yml:
dependencies:
- base
- database
- messaging
Including just the webapp role will first run setup from those other roles it requires. However, be aware include_role parameters like variables apply only to the named role itself.
Comparison to Static Import Modules
Modules like import_tasks, import_playbook and import_role provide static imports of playbook code, while include_role dynamic injects role content.
Static imports have limitations around flexibility:
- All imported tasks always run regardless of condition
- Imports can‘t handle runtime overrides of role variables
- No filtering of imported tasks
include_role addresses these through conditional logic, parameterized includes, and task filtering – enabling more modular role usage.
Think include_role for most role usage, import_role only for strict dependencies to enforce fixed execution order.
Integrating with Ansible Galaxy
Ansible Galaxy provides access to thousands of reusable community roles. This ecosystem is enhanced by leveraging include_role for dynamic consumption of shared roles.
Galaxy roles can utilize include_role capabilities within their role definitions enabling more flexible reuse.
Likewise playbook authors can conditionally consume Galaxy roles on-demand with overrides rather than assume fixed standalone usage.
Modular role usage enabled by include_role amplifies the advantages of tapping into the Galaxy role ecosystem!
Best Practices For Dynamic Role Development
Proper encapsulation of automation functionality into reusable roles and leveraging capabilities like include_role takes practice and planning. Keep these guidelines in mind:
Loose coupling
-Roles should encapsulate cohesive functionality but remain independently consumable
Limited side effects
-Strive for idempotent task definitions that work when re-run such as using "state: present"
Atomic transactions
-Structure role task flows with retry mechanisms to handle transient infrastructure issues
Parameterization not customization
-Pass inputs to roles via variables rather than tweaking role internals
Adhering to these practices will result in role abstractions reliable and resilient for streamlined dynamic usage via include_role in diverse playbooks.
Wrap Up
This guide provided a comprehensive tour of Ansible include_role and how it enables dynamic modular execution of roles within playbooks. The techniques covered such as conditionally including roles, overriding variables, filtering tasks subsets at runtime, and permitting duplicate execution simplify playbook authoring and make roles truly reusable abstractions.
Ansible automation experts should have these include_role patterns in their playbook authoring toolbox to elegantly handle complexity and change without requiring role internal modifications.
As Ansible continues exponential growth, include_role mastery is a key enabler for scaling automation code abstraction and modularization needs of modern infrastructure teams.


