Pure Storage Ansible Execution Environments – Part 2

‌‌Part 2: Containerised Ansible

A lot has changed in the Ansible world recently. The latest being the introduction of Execution Environments. In this series of posts, I try to decipher what they are and what Pure Storage is doing in this space.

In the previous post, I recently discussed the major changes in Ansible that have led to the development of Execution Environments (EE). In this post, I’ll discuss EEs and their associated toolsets.

Environment Challenges

One of the underlying challenges with Ansible has been the requirement to ensure that all the environments that need to run a playbook have the correct dependencies.

A developer may have many packages installed to get his playbook working and then these have to be correctly replicated in the multiple execution environment, whether that be other developers, AWX, Tower, etc…). This is very important due to the way Ansible executes the Python code on the managed node. I’ll not go into that but it’s called the Ansiballz framework if you want to look it up…

With the architectural changes mentioned in the first blog post, not only does Ansible have its own dependencies, but so do any of the roles or collections you are going to use in your environment. You also have to ensure the correct Python interpreter is being used. More details on this can be found here.

There can also be system level-specific dependencies as well to add into the mix.

All in all, this can make the deployment of playbooks across multiple systems a bit of a headache.

To solve this, Ansible has introduced Execution Environments (EE), which allow you to create a standardized runtime stack that can run anywhere, from a developers laptop, in the cloud, or anywhere else. EEs are like a virtualenv on steroids… An EE is a containerized image containing all the bits and pieces required for a playbook to run.

Let’s have a look at how to build and implement an EE. Any examples will be specifically for the Pure Storage EEs and therefore there may be other pieces that are required if you want to build your own customized execution environment.

Ansible-builder

ansible-builder is a tool to help create an EE from a requirements file and from the collections it needs to build a container image.

To start with let’s imagine we have an environment that has been used to create and test an Ansible playbook that uses all the Pure Storage Collections: FlashArray, FlashBlade and Pure1. To ensure that the playbook will work in any environment we need to create an EE for this, so let’s install ansible-builder:

pip install ansible-builder

and then we can examine the running environment to ensure we understand all the dependencies that the playbook potentially requires…

# ansible-builder introspect --sanitize ~/.ansible/collections
---
python:
- 'purestorage>=''1.19''  # from collection purestorage.flasharray'
- 'py-pure-client>=''1.16'',>=''1.13.0'',>=''1.14.1''  # from collection purestorage.flasharray,purestorage.flashblade,purestorage.pure1'
- 'netaddr  # from collection purestorage.flasharray,purestorage.flashblade'
- 'requests  # from collection purestorage.flasharray'
- 'pycountry  # from collection purestorage.flasharray'
- 'purity-fb>=''1.12.2''  # from collection purestorage.flashblade'
system: []

The command is looking for a directory called ansible_collections, which in this case happens to be under ~/.ansible/collections, and here there are the three Pure Collections installed.

Notice that there are no system dependencies required for these collections, only Python-related dependencies.

Collection dependencies are created in a file called requirements.yml that ansible-builder will use. In this case, the file would contain:

---
collections:
  - name: purestorage.flasharray
  - name: purestorage.flashblade
  - name: purestorage.pure1

If there were any system dependencies, they would need to be added to a file called bindep.txt.

All that is required is a file to explain to ansible-builder about how to create the EE – this is called execution-environment.yml. In its simplest form, this file contains:

---
version: 1
dependencies:
  python: requirements.txt
  galaxy: requirements.yml

We are now ready to create our EE containing the three Pure Storage Collections.

Before running ansible-builder we need a container runtime engine installed. In this example, I am using podman.

Create the EE:

# ansible-builder build --tag all_pure_ee_image
Running command:
  podman build -f context/Containerfile -t all_pure_ee_image context
Complete! The build context can be found at: /root/test_ee/context

To check the EE image exists…

# podman images
REPOSITORY                    TAG        IMAGE ID      CREATED         SIZE
localhost/all_pure_ee_image   latest     7ab665653d32  25 seconds ago  967 MB

Ansible-navigator

How can we validate that the EE just created actually contains the Collections we requested?

Ansible has created a tool called ansible-navigator to help do just that, so install it first…

pip install ansible-navigator

There needs to be a configuration file for this called ansible-navigator.yml. A simple version of this file that will allow ansible-navigator to use the newly created EE image is:

---
ansible-navigator:
  execution-environment:
    pull-policy: never
    image: localhost/all_pure_ee_image

We can now interrogate the EE image to check it did install the Pure Storage Collections:

ansible-navigator collections

The output should look something like this:

  NAME                                  VERSION      SHADOWED       TYPE             PATH
0│purestorage.flasharray                1.10.0          False       contained        /usr/share/ansible/collections/ansible_collections/purestorage/flasharray/
1│purestorage.flashblade                1.6.0           False       contained        /usr/share/ansible/collections/ansible_collections/purestorage/flashblade/
2│purestorage.pure1                     1.0.0           False       contained        /usr/share/ansible/collections/ansible_collections/purestorage/pure1/

Now you have your EE image and have validated it contains the Collections you want; you can run playbooks in containers using the EE image in the sure and certain knowledge that this image will work in all environments.

If you want this container to be useable by your colleagues or other developers then push it to a public registry, such as quay.io.

All that needs to be done is amend your ansible-navigator.yml file and change pull-policy to be Always and image to be the registry name of the EE image.

Running a simple playbook

Here is a simple playbook that interrogates a FlashArray to get its base configuration details:

- name: sample
  hosts: localhost
  gather_facts: no
  vars:
    - array_ip: 1.2.3.4
    - api: 89a9356f-c203-d263-8a89-c229486a13ba
  tasks:
    - name: Get array info
      purestorage.flasharray.purefa_info:
        fa_url: "{{ array_ip }}"
        api_token: "{{ api }}"
      register: array
    - debug:
        msg: "{{ array }}"

I’m going to use ansible-navigator again but with some switches that will ensure the output is in the traditional ansible-playbook CLI format:

# ansible-navigator run -m interactive sample.yaml -m stdout
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

PLAY [sample] ******************************************************************

TASK [Get array info] **********************************************************
ok: [localhost]

TASK [debug] *******************************************************************
ok: [localhost] => {
    "msg": {
        "changed": false,
        "failed": false,
        "purefa_info": {
            "default": {
                "admins": 8,
                "array_model": "FA-405",
                "array_name": "sn1-405-c07-27",
                "connected_arrays": 2,
                "connection_key": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
                "hostgroups": 4,
                "hosts": 10,
                "maintenance_window": [],
                "pods": 1,
                "protection_groups": 7,
                "purity_version": "5.3.12",
                "remote_assist": "disabled",
                "snapshots": 18,
                "volume_groups": 1,
                "volumes": 28
            }
        }
    }
}

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

Pure Storage Execution Environment Images

To save you a lot of time and effort, Pure Storage has already performed the tasks above and pre-created Execution Environments for the FlashArray, FlashBlade and Pure1 Collections.

These can all be accessed publicly from Red Hat’s quay.io and will be kept up to date with the latest releases of the Collections as they are released.

The Execution Environments are available here:

I hope you found this blog series useful.

If you have any questions please reach out to the Pure Storage Ansible Team.

Leave a Reply

Your email address will not be published. Required fields are marked *