Automation controller workflow deployment as code

November 15, 2021 by Sean Sullivan

Background: The Automation Controller Collection

The Automation Controller Collection allows Ansible Playbooks to automate the interaction with automation controller. For example, manually interacting via the Web-based UI or the API can now be automated just as the targets it manages.

This Collection provides a programmatic way to create, update or delete automation controller objects as well as perform tasks such as run jobs, change configurations and much more. This article discusses new updates to this Collection, as well as an example playbook and details on how to run it successfully.

The ansible.controller Ansible Collection is the downstream supported distribution available on Ansible automation hub, made to work with Red Hat Ansible Automation Platform 2.  The awx.awx Collection is the upstream community distribution available on Ansible Galaxy.  For more details on the difference between Ansible Galaxy and Ansible automation hub, please refer to Ajay Chenampara’s blog post.

In this post, we are use the ansible.controller Collection, but this can be replaced with the legacy ansible.tower or the awx.awx Collection depending on the user’s needs.

 

Using the Collection with Workflows

One of the goals of the Automation Controller Collection is to allow users to easily create objects in Ansible Automation Platform 2. In service of that, we will explore how to codify workflows and deploy them on the automation controller. 

First, let’s take a look at the following workflow:

Each node represents an action, such as an inventory update, project update or the running of a job template. Other options can also be specified (see the docs for detail), and each node is linked to one or many other nodes. The common practice is to create the workflows inside of the automation controller GUI, but with the Collections, it is possible to manage these workflows through Ansible Playbooks. In this article we will cover how to export the workflow as well as how to create and edit a new workflow.

Using this example playbook, we are able to extract the information from the server about a specific workflow. The ansible.controller.export module can also be used to extract other objects from the server as well. In this example, we will use environment variables to authenticate, while the later example will use Ansible vars; both are valid methods to use.

---
- name: Export Workflow
  hosts: localhost
  connection: local
  gather_facts: false
  collections:
    - ansible.controller
  environment:
     CONTROLLER_HOST: https://localhost
     CONTROLLER_USERNAME: admin
     CONTROLLER_PASSWORD: password
     CONTROLLER_VERIFY_SSL: False

  tasks:
    - name: Export workflow job template
      ansible.controller.export:
        workflow_job_templates: Complicated workflow schema
      register: export_results

    - debug:
        var: export_results

    - name: Export workflow job template to file
      copy:
        content: "{{ export_results | to_nice_yaml( width=50, explicit_start=True, explicit_end=True) }}"
        dest: workflow.yaml
...

This outputs the information from the API to a yaml formatted file.

Notes: 

  1. Currently the export does not export approval nodes due to a limitation in the underlying awxkit component, however, one has been added as an example. It is supported for pushing workflows using the workflow_job_template module.
  2. Many fields that are empty or irrelevant to this example have been removed from the below example to ease clarity; exporting by default populates every option. The variable file will work as-is, but there are many more options available that are described in the documentation.
---
workflow_job_templates:
-   name: Complicated workflow schema
    related:
      workflow_nodes:
      -   identifier: node101
          related:
              success_nodes:
              -   identifier: node201
          unified_job_template:
              inventory:
                  organization:
                      name: Satellite
              name: RHVM-01
              type: inventory_source
      -   identifier: node102
          related:
              success_nodes:
              -   identifier: node201
          unified_job_template:
              name: Demo Project
              organization:
                 name: Default
              type: project
      -   identifier: node201
          related:
              success_nodes:
              -   identifier: node401
              failure_nodes:
              -   identifier: node301
          unified_job_template:
              name: test-template-1
              organization:
                  name: Satellite
              type: job_template
      -   identifier: node301
          related:
              success_nodes:
              -   identifier: node401
          unified_job_template:
              description: Approval node for example
              timeout: 900
              type: workflow_approval
              name: Approval to continue
      -   identifier: node401
          unified_job_template:
              name: Demo Job Template
              organization:
                  name: Satellite
              type: job_template

At the top level, our workflow has a named property (“Complicated workflow schema”) and may have other properties such as extra vars or surveys. In addition, we have a property called "related" which contains a list of workflow_nodes.  This contains all of the nodes, all the links, and how they interact.

Identifiers are required when describing a node in code. When using the GUI, a GUID like ‘51fcba23-7778-4e68-9aad-df8a1fc7c0dd‘ is generated for the user.  It is recommended to use Columns and Rows to describe where it is in the workflow. This helps to keep track of each node’s location for when you edit later on. It also helps to keep the nodes in order.

Each entity in the workflow_nodes list describes a single node. Here is a breakdown of what each of the fields in the node represent:

The Identifier is required to ID the node

 -   identifier: ← An identifier that is unique within its workflow.
           related:
               always_nodes: ← Dict List of nodes that always execute 
               -   identifier: X
               failure_nodes: ← Dict List of nodes that execute on failure
               success_nodes: ← Dict List of nodes that execute on success
           unified_job_template:
               name: ← Name of Job Template that will be run
               organization:
                   name: ← Name of Organization the Job template is in
               type: ← Type of node, this is required.

The type can be one of job_template, project, inventory_source, workflow_approval.

Unified Job template descriptions for inventory sources are slightly different to the others

 unified_job_template:
               inventory:
                   organization:
                       name: Satellite ← Organization that the inventory source is in
               name: RHVM-01 ← Name of inventory source
               type: inventory_source ← Type

Note that the organization is a sub variable of the inventory and is the organization that the inventory belongs to, not the workflow.

Approval nodes do not have organizations

unified_job_template:
              description: Approval node for example 
              timeout: 900  ← Timeout before the Approval fails
              type: workflow_approval ← Type
              name: Approval to continue ← Name that shows on node

Project updates and Job templates share the same model

unified_job_template:
              name: Demo Project ← Name of the Project or Job Template
              organization:
                 name: Default ← Organization the Project or Job Template are in
              type: project ← Type

Note that the type can be either project or job_template

By modifying the variable that represents the workflow, we can add additional nodes, remove or remap existing nodes, or even change the job template a node runs, amongst other things.

An example of removing a node:

-   identifier: node401
          unified_job_template:
              name: Demo Job Template
              organization:
                  name: Satellite
              type: job_template
          state: absent

It still requires a valid unified job template, but it will delete the node from the workflow.

If you have made drastic changes you can even wipe out the full schema and recreate it from scratch:

---
workflow_job_templates:
-   name: Complicated workflow schema
    destroy_current_schema: true
    related: …

In order to Restore the workflow to the automation controller, the workflow_job_template module is used to loop over the data structure we previously created. The example below uses variables in place of Environment variables in order to authenticate to the server:

---
- name: Push Workflow
  hosts: localhost
  connection: local
  gather_facts: false
  collections:
    - ansible.controller
  vars_files:
    - workflow.yaml
  tasks:
    - name: Push workflows to controller
      workflow_job_template:
        name: "{{ __workflow_loop_item.name }}"
        schema: "{{ __workflow_loop_item.related.workflow_nodes }}"
        controller_host: https://localhost
        controller_username: admin
        controller_password: password
        validate_certs: false
      loop: "{{ workflow_job_templates }}"
      loop_control:
        loop_var: __workflow_loop_item
...

And yet another method

Doing a single workflow is just the start. You can also take advantage of a community Collection redhat_cop.controller_configuration. This is a Collection of roles that wrap around the awx or ansible.controller modules that allow you to take advantage of exported objects in the automation controller, and manage all of your objects in automation controller or AWX as code. Please note that the redhat_cop.controller_configuration Collection is a community project and not officially supported by Red Hat.

 

Conclusion

While this may seem daunting, by following this guide it should be easy to get started with documenting your workflows in code and to get up and running with the AWX/automation controller Collection. Using these examples will help you keep your automation controller objects up-to-date. It will also allow you to deploy changes to the automation controller with playbooks and automation, rather than doing it by hand in the GUI. 

 

Further Reading

Introducing: The AWX and Ansible Tower Collections

Configuring Ansible Tower with the Tower Configuration Collection

The inspiration for the schemas addition to workflow job templates comes from akira6592
Do node definition and link definition well with tower_workflow_job_template_node module

There is also the AnsibleFest presentation that I participated in

Bell Canada: Managing Ansible as Code

 

Recommended links:

Ansible controller collection

Awx collection

Redhat_cop controller_configuration collection

Redhat_cop Tower_configuration collection

Redhat_cop automation hub Configuration collection

 

Self paced labs:

Experience self-paced interactive hands-on labs with Ansible Automation Platform

Share:

Topics:
Ansible content collections


 

Sean Sullivan

Sean is a Senior Consultant at Red Hat who focuses on the Ansible Automation Platform. He has contributed to the awx.awx Collection and is a co-maintainer of the redhat_cop.controller_configuration Collection.


rss-icon  RSS Feed

RH-ansible-automation-platform_trial-banner
rh-ansiblefest-blog-image-600x500