vkhitrin.com

Technology And Ramblings

CLIze your Ansible playbooks using Infrared



Tags: #Ansible

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

Warning: Some parts of this post are outdated, infrarad was refactored.

infrared

infrared is a tool that aims to provide a CLI to Ansible-based projects that anyone can use without prior Ansible knowledge.

infrared consumes Ansible projects in the form of plugins.
Each plugin has its properties and represents a different Ansible project (playbooks, roles).

Documentation can be found on infrared’s Read The Docs.

Who Uses infrared

Infrared originated from the Red Hat OpenStack infrastructure team, which aimed to provide a solution that allowed deploying various topologies of OpenStack cloud using an easy-to-use CLI tool.
Since then, Infrared has grown to support any Ansible project.

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

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

Installing infrared

There are three ways to install Infrared:

git

Infrared’s code is hosted on GitHub and has three important branches:

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.

pip

Infrared is a Python tool that is hosted on PyPI.

pip install infrared

Infrared Key components

Infrared has two key components necessary for its operation:

Plugins

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

In this blog post, we’ll discuss migrating and developing an Infrared plugin for your project.

Each plugin represents a unique Ansible project with its 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)

Plugins can be listed using the infrared plugin list:

# Output
+-----------+--------------------+
| 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 or local repositories using infrared plugin add.

Installing a plugin from the git repo:

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

Installing a plugin from the 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 complete list of commands and more, refer to plugins documentation.

Workspace

The 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 symlinked during activation of the 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 using infrared workspace export and infrared workspace import.

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

# Show nodes ins workspace
infrared workspace node-list
# Output
+--------------+-------------+-------------------------------------------------------+
| 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             |
+--------------+-------------+-------------------------------------------------------+
# Show groups in workspace
infrared workspace group-list
# Output
+-----------------+-------------------------------------------------------------------+
| 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 complete list of commands and more, refer to workspace documentation.

Migrating Your Project/Developing Your 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 acts as an entry point 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 populated using the -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 knowledgeable in Ansible will have difficulty using 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, which can be: provision, install, test or other.
entry_point - the main file of your playbook. By default, it is 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 consumed by the parser, this way, we can add ansible command line arguments to the infrared foo-plugin command.
groups - our defined groups contain arguments exposed to the infrared foo-plugin command.
foo - an argument that represents an Ansible variable, is required, and is a string.

One of Infrared’s strengths is to validate arguments before invoking Ansible playbooks. Infrared can ensure the user supplies the correct values, create dependencies between arguments, handle the variable’s type assignment, and more.

For complete documentation regarding plugin.spec, refer to plugin specification.

Refactor Your Variables To Be Consumed By infrared

Note: infrared implemented a capability to map its variable to an ansible variable. Refer to 'ansible_variable' section in documentation.

Note: It's possible not to refactor your Ansible variables and use a task that 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
# Output
+-----------+--------------------+
| 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 and my demo virt-customize plugin.

As mentioned above, there is an option to keep using your old defined variables and do a “translation” of Infrared variables into already defined variables. Please refer to the tripleo-clouds-inventory plugin.

Summary

Migrating your Ansible projects to infrared is not a complex task. The return on investment will be high since it’ll allow nonexperienced users to consume your playbooks, and it’ll provide additional logic regarding your variable’s definitions.

Back To Top