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.

Similar Posts