Published: December 28, 2018
Updated: March 30, 2019
Tags: Ansible, Infrared
6 min read

CLIze your Ansible playbooks using Infrared

CLI - Command-Line Interface
Serialize - arrange (something) in a series

Infrared

Infrared [1] is a tool which aims to provide a CLI to Ansible based projects that can be used by anyone without prior Ansible knowledge.

Infrared consumes Ansible projects in the form of plugins.
Each plugin has it's own properties and represents a different Ansible project(playbook).

Documentation can be found on Infrared's Read The Docs [2].

Who uses infrared

Infrared originated from Red Hat OpenStack infrastructure team which aimed to provide a solution which allowed to deploy various topologies of OpenStack cloud using an easy-to-use CLI tool.
Since then, Infrared grew to support any Ansible projects.

At Red Hat, various OpenStack teams use Infrared to automate OpenStack deployments and testing in various complex topologies.

The following blog posts describe how Red Hat OpenStack members use this tool as part as their workflow:

  • Arie Bregman's blog post on deploying and testing OpenStack using Infrared [3]
  • Gonéri Le Bouder's blog post on RDO + Infrared and Distributed-CI [4]
  • Pablo Iranzo Gómez's blog post on deploying OpenStack using Infrared [5]

Installing Infrared

There are 3 ways to install Infrared:

GIT

Infrared's code is hosted on GitHub and has 3 important branches:

  • Master - The most updated branch.
  • Nightly - Once a master build deemed as safe for rollout (Most CI jobs pass), it is tagged as nightly.
  • Stable - The most stable build, updates rollout ares slower but guaranteed to not break.
git clone https://github.com/redhat-openstack/infrared/
cd infrared
pip install .

Binaries

Infrared binaries can be found on the project's release page on GitHub [6].

PIP

Infrared is a python tool which is hosted on PyPi.

pip install infrared

Infrared key components

Infrared has two key components necessary to it's operation:

Plugins

Infrared comes with 14 pre-defined plugins which most of them perform actions related to OpenStack deployment and testing.

In this blog post we'll discuss how to migrate and develop an Infrared plugin for your project.

Each plugin represents a unique Ansible project with it's own parameters and tasks.

Every plugin is defined by a plugin.spec file which declares a 'subparser' (the expression after infrared) and plugin parameters.
Example of plugin.spec from my personal demo virt-customize plugin:

config:
    plugin_type: other
subparsers:
    virt-customize:
        description: Customize virtual disk images
        include_groups: ["Ansible options", "Inventory", "Common options", "Answers file"]
        groups:
            - title: Host arguments
              options:
                  host-address:
                      type: Value
                      help: 'Address/FQDN of the executor host'
                      required: false
                      default: 'undercloud'
                  host-user:
                      type: Value
                      help: 'User to SSH to the remote executor host with'
                      default: root
                  host-key:
                      type: Value
                      help: |
                            User's SSH key used to connect to remote executor host
                            Example: '/root/.ssh/id_rsa.pub'.
                      required: false

(text is omitted, for full reference refer to the file in infrared-virt-customize demo repo [7])

Plugins can be listed using infrared plugin list:

+-----------+--------------------+
| Type      | Name               |
+-----------+--------------------+
| provision | beaker             |
|           | foreman            |
|           | virsh              |
|           | openstack          |
+-----------+--------------------+
| install   | tripleo-undercloud |
|           | tripleo-overcloud  |
|           | cloud-config       |
|           | tripleo-standalone |
|           | packstack          |
|           | tripleo-upgrade    |
+-----------+--------------------+
| test      | gabbi              |
|           | octario            |
|           | pytest-runner      |
|           | rally              |
|           | tempest            |
|           | ospdui             |
+-----------+--------------------+
| other     | virt-customize     |
|           | reportportal       |
|           | list-builds        |
|           | collect-logs       |
|           | tripleo-inventory  |
+-----------+--------------------+

Plugins can be added from remote git repositories or local repositories using infrared plugin add.

Installing plugin from git repo:

infrared plugin add https://github.com/VKhitrin/infrared-virt-customize

Installing plugin from local path:

infrared plugin add /path/to/plugin/infrared-virt-customize

Plugins can be removed using infrared plugin remove.

Plugins can be updated using infrared plugin update.

For the full list of commands and more, refer to plugins documentation [8].

Workspace

Infrared workspace represents an Ansible inventory, ssh configuration and Ansible configuration.
Multiple Workspaces allow the user to alternate between various environments.

Workspaces contain all the relevant files and are sym linked during activation of required workspace.

To create a workspace, use infrared workspace create.

To list Infrared workspaces, use infrared workspace list:

+-------------------------------+--------+
| Name                          | Active |
+-------------------------------+--------+
| Example                       |        |
+-------------------------------+--------+
| Lab                           |    *   |
+-------------------------------+--------+

To switch between workspaces, use infrared workspace checkout.

Workspaces can be exported/imported by using infrared workspace export and infrared workspace import.

Since a workspace contains an Ansible inventory, all Ansible hosts and groups can be viewed using infrared workspace node-list and infrared workspace group-list:

infrared workspace node-list
+--------------+-------------+-------------------------------------------------------+
| Name         | Address     | Groups                                                |
+--------------+-------------+-------------------------------------------------------+
| controller-0 | 192.0.60.11 | overcloud_nodes, network, controller, openstack_nodes |
+--------------+-------------+-------------------------------------------------------+
| controller-1 | 192.0.60.17 | overcloud_nodes, network, controller, openstack_nodes |
+--------------+-------------+-------------------------------------------------------+
| controller-2 | 192.0.60.6  | overcloud_nodes, network, controller, openstack_nodes |
+--------------+-------------+-------------------------------------------------------+
| undercloud-0 | 172.16.0.81 | tester, undercloud, openstack_nodes                   |
+--------------+-------------+-------------------------------------------------------+
| hypervisor   | 10.35.74.2  | hypervisor, shade                                     |
+--------------+-------------+-------------------------------------------------------+
| compute-0    | 192.0.60.13 | overcloud_nodes, compute, openstack_nodes             |
+--------------+-------------+-------------------------------------------------------+
infrared workspace group-list
+-----------------+-------------------------------------------------------------------+
| Name            | Nodes                                                             |
+-----------------+-------------------------------------------------------------------+
| compute         | compute-0                                                         |
+-----------------+-------------------------------------------------------------------+
| controller      | controller-2, controller-1, controller-0                          |
+-----------------+-------------------------------------------------------------------+
| hypervisor      | hypervisor                                                        |
+-----------------+-------------------------------------------------------------------+
| network         | controller-2, controller-1, controller-0                          |
+-----------------+-------------------------------------------------------------------+
| openstack_nodes | controller-2, controller-1, controller-0, undercloud-0, compute-0 |
+-----------------+-------------------------------------------------------------------+
| overcloud_nodes | controller-2, controller-1, controller-0, compute-0               |
+-----------------+-------------------------------------------------------------------+
| shade           | hypervisor                                                        |
+-----------------+-------------------------------------------------------------------+
| tester          | undercloud-0                                                      |
+-----------------+-------------------------------------------------------------------+
| undercloud      | undercloud-0                                                      |
+-----------------+-------------------------------------------------------------------+

For the full list of commands and more, refer to workspaces documentation [9].

Migrating your project/Developing your own plugin

Your Ansible playbook is probably structured this way:

├── defaults
│  └── main.yml
├── files
├── handlers
│  └── main.yml
├── meta
│  └── main.yml
├── README.md
├── main.yml
├── tasks
│  └── main.yml
├── templates
└── vars
   └── main.yml

main.yml is acting as an entrypoint of the Ansible playbook.

For the sake of demonstration, all of our tasks are in main.yml:

- hosts: localhost
  tasks:
  - debug:
      var: foo

foo is a variable which is populated using -e flag when invoking ansible-playbook.

Invocation of this demo playbook:

ansible-playbook main.yml -e foo='bar'
PLAY [localhost] **************************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************************************************************************************************
ok: [localhost]

TASK [debug] ******************************************************************************************************************************************************************************************************************************
ok: [localhost] => {
    "foo": "bar"
}

Imagine if it were a complex playbook with tens of variables with dependencies on each other,
a user not knoweledgeble in Ansible will have a hard time knowing how to use all variables in CLI or passing a file containing all variables.

Infrared helps to streamline a playbook into an easy to consume CLI command, for example how this playbook will look like:

infrared foo-plugin --foo "bar"

To transform this playbook into a plugin, we must perform two actions:

Creating plugin.spec

Create and define a plugin.spec file describing your project.

Copy your Ansible project to a new directory and create a plugin.spec file:

config:
   plugin_type: other
   entry_point: main.yml
subparsers:
    foo-plugin:
        description: Example foo plugin
        include_groups: ["Ansible options", "Inventory", "Common options", "Answers file"]
        groups:
           - title: Group Foo
             options:
                 foo:
                     type: Value
                     help: "foo variable"
                     required: True

plugin_type - describes the type of your plugin, can be: provision, install, test or other.
entry_point - the main file of your playbook, by default it main.yml.
subparser foo-plugin - populates the infrared command with arguments, in this case foo-plugin will contain the defined arguments and can be invoked via infrared foo-plugin.
include_groups - contains a list of argument groups that consumed by the parser, this way we can add ansible command line arguments to infrared foo-plugin command.
groups - our own defined groups containing arguments exposed to infrared foo-plugin command.
foo - argument that represents an Ansible variable, is required and is a string.

One of Infrared strength's is to perform argument validation before invoking Ansible playbooks.
Infrared can make sure the user is supplying the correct values, can create dependencies between arguments, handles the type assignment of the variable and more.

For full documentation regarding plugin.spec, refer to plugin specification [10]

Refactor your variables to be consumed by infrared

Infrared implemented a capability to map it's variable to an ansible variable, refer to 'ansible_variable' section in documentation

It's possible not to refactor your Ansible variables and use a task which translates Infrared variables into your Ansible variables, refer to tripleo-inventory plugin in the Example of complex plugins section

The previous foo variable can not be used by Infrared since Infrared doesn't know how to refer to it.

Infrared plugin variables are structured in the following way plugin_type.var_dict.
Using the playbook above, we have one variable foo that we must refactor. Our new variable must look like other['foo'] or other.foo (Jinja wise it's the same variable).

- hosts: localhost
  tasks:
  - debug:
      var: other['foo']

Now we can add our new plugin using infrared plugin add /path/to/foo-plugin and verify it's added:

infrared plugin list
+-----------+--------------------+
| Type      | Name               |
+-----------+--------------------+
| provision | beaker             |
|           | foreman            |
|           | virsh              |
|           | openstack          |
+-----------+--------------------+
| install   | tripleo-undercloud |
|           | tripleo-overcloud  |
|           | cloud-config       |
|           | tripleo-standalone |
|           | packstack          |
|           | tripleo-upgrade    |
+-----------+--------------------+
| test      | gabbi              |
|           | octario            |
|           | pytest-runner      |
|           | rally              |
|           | tempest            |
|           | ospdui             |
+-----------+--------------------+
| other     | foo-plugin         |
|           | reportportal       |
|           | tripleo-inventory  |
|           | collect-logs       |
|           | list-builds        |
+-----------+--------------------+

Our Ansible project now should be consumable via CLI - infrared foo-plugin --foo 'bar'.

other:
  foo: bar


PLAY [localhost] **************************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************************************************************************************************
ok: [localhost]

TASK [debug] ******************************************************************************************************************************************************************************************************************************
ok: [localhost] => {
    "other['foo']": "bar"
}

PLAY RECAP ********************************************************************************************************************************************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0

Examples of complex plugins

The Ansible playbook we used in this blog post is basic.
There are some complex plugins created under the rhos-infra GitHub project [11] project and my personal demo virt-customize plugin [12].

As mentioned above, there is an option to keep using your old defined variables and do a "translation" of Infrared variables intro already defined variables. Please refer to tripleo-inventory plugin [13].

Summary

Migrating your Ansible projects to infrared is not a complex task. The return of investment will be high since it'll allow non experienced
users to consume your playbooks and it'll provide additional logic regarding your variables definitions.


  1. Infrared GitHub repo ↩︎

  2. Infrared's documentation ↩︎

  3. InfraRed: Deploying and Testing Openstack just made easier! ↩︎

  4. Distributed-CI and InfraRed ↩︎

  5. InfraRed for deploying OpenStack ↩︎

  6. Infrared release page on GitHub ↩︎

  7. infrared-virt-customize demo plugin.spec ↩︎

  8. Infrared plugins documentation ↩︎

  9. Infrared workspaces documentation ↩︎

  10. Infrared's plugin specification ↩︎

  11. rhos-infra ↩︎

  12. infrared-virt-customize demo ↩︎

  13. tripleo-inventory plugin ↩︎