Introducing the New Cloudify Ansible Plugin

Serving as a popular configuration management tool, Ansible is taking over other popular configuration management tools such as Chef and Puppet and has become a popular tool to manage the configuration of many network devices.
The motivation behind the Cloudify and Ansible integration follows the logic of an automation-first approach, allowing users to leverage existing Ansible playbooks to integrate into Cloudify rather than convert into a Cloudify format.
The integration between Cloudify and Ansible isn’t really new and a growing number of Cloudify users employ a combination of both solutions.
Our previous Cloudify integration was based on a generic script packaging a plugin intended for POCs- ‘the execution plugin’. This enabled users to create a work directory on the Cloudify Manager to run whatever they like. This had several drawbacks:

  • No DSL structural descriptors
  • Jinja2 templating in the Playbooks instead of Ansible
  • Security/Operations concerns over the execution directory
  • No Ansible Specific components

The previous Ansible integration version wasn’t tightly integrated and was mostly treated as yet another script. That made for a fairly cumbersome integration.
Growing demand led us to release a new Ansible plugin that exposes the native Ansible API and features through the Cloudify TOSCA template and, in this case, makes the integration more intuitive and simple for Ansible users.

Where does it fit within the Cloudify Stack?

Cloudify solves the problem of integrating multiple deployment vectors:

  • Infrastructure Management
  • Deployment Configuration
  • CI/CD Integration

Integrations are accomplished via plugins. Cloudify has the plugins for IaaS (Openstack, Azure, AWS, GCP, etc.) Cloudify also has plugins for configuration (Fabric, Script, REST, etc).
Ansible fits into one the configuration plugins as described in the diagram below:

Key features of the new Cloudify plugin

How does it work? Existing Ansible users can take existing Ansible playbooks and package them with Cloudify blueprints and have Cloudify ‘run’ them. This is accomplished by dropping the directory containing Ansible Playbook, Roles, Variables, Groups, etc, into the folder containing Cloudify blueprint (See diagram below). Then in the Cloudify blueprint, users can employ the Ansible plugin to map lifecycle operations to ansible-playbook runs. This is explained below. Existing Cloudify users who are using the Fabric or Script plugins can translate their Scripts to Ansible Playbooks. This ‘Ansible Plugin’ approach is very similar to the approach of the Fabric Plugin, also explained below.

Step by Step: Starting with a simple example, like Ansible’s “Writing Your First Playbook”, let’s take that playbook and put it into a Cloudify blueprint and deploy it.
The code from this example can be downloaded here.
## Preliminary: Create a work directory:
Note: A Cloudify Manager, as well as the IP, Username, and SSH key file to an existing VM is needed to run this example.
Create a work directory:

mkdir ansible-example
cd ansible-example

Next, create the Ansible Playbook.
Put the final code from the Ansible example in the playbook.yaml.

touch playbook.yaml
---
- name: Install nginx
  hosts: host.name.ip
  become: true
  tasks:
  - name: Add epel-release repo
    yum:
      name: epel-release
      state: present
  - name: Install nginx
    yum:
      name: nginx
      state: present
  - name: Insert Index Page
    template:
      src: index.html
      dest: /usr/share/nginx/html/index.html
  - name: Start NGiNX
    service:
      name: nginx
      state: started

Add the index.html file:

<html>
    <header>
        <title>Cloudify Hello World</title>
    </header>
<body>
    <h1>Hello, World!</h1>
</body>
</html>

Now, we want a blueprint in blueprint.yaml:

touch blueprint.yaml

Now insert this text:

tosca_definitions_version: cloudify_dsl_1_3
imports:
  - http://cloudify.co/spec/cloudify/4.5.5/types.yaml
  - http://www.getcloudify.org/spec/ansible-plugin/2.0.2/plugin.yaml
inputs:
  ip:
    type: string
    description: The VM IP.
  username:
    type: string
    description: The VM SSH user.
  private_key:
    type: string
    description: Full path to the VM's private key.
node_types:
  vm:
    derived_from: cloudify.nodes.Compute
    properties:
      agent_config:
        default:
          install_method: none
          key: { get_input: private_key }
          user: { get_input: username }
   interfaces:
      cloudify.interfaces.lifecycle:
        configure:
          implementation: ansible.cloudify_ansible.tasks.run
          inputs:
            site_yaml_path:
              default: playbook.yaml
 node_templates:

  vm:
    type: vm
    properties:
      ip: { get_input: ip }

Explaining the blueprint:
This specifies the DSL version. It’s not significant for beginners

    tosca_definitions_version: cloudify_dsl_1_3

The line ‘imports’ describes the base types, as well as the plugins that we need. For example, we import the Ansible plugin:

 - plugin:cloudify-ansible-plugin

Inputs allow us to define parameters that should be known at deployment creation time. For example, the VM brought to this example may have any IP, known only when provisioning a VM to use with this example. (This example does not include provisioning a VM at runtime because that is another topic.)

inputs:
  ip:
    type: string
    description: The VM IP.
  username:
    type: string
    description: The VM SSH user.
  private_key:
    type: string
    description: Full path to the VM's private key.

A Node Template is the static description of one or more runtime nodes that have identical configuration. This node template is a pre-provisioned VM. We define an interface for executing the Ansible playbook during configuration:

   interfaces:
      cloudify.interfaces.lifecycle:
        configure:
          implementation: ansible.cloudify_ansible.tasks.run
          inputs:
            site_yaml_path:
              default: playbook.yaml

The ansible.cloudify_ansible.tasks.run task contains all of the code that is needed to identify the inventory and configure the Ansible application. For each individual playbook run that you want to execute you need a different interface. For example, if you want to execute certain tags separately, you will need separate interfaces for each execution.
Install via Cloudify:

cfy install blueprint.yaml

That was a pretty basic example, however more can be found via:
Kubernetes Blueprint, based on Kubespray (Ansible Kubernetes Playbook).
DB-LB-App, a modular application utilizing Ansible Playbooks for MariaDB/Galera Cluster, HAProxy, and Drupal7.
Testing Examples with Vagrantfile (OpenVPN, Clearwater, LAMP, etc).
Explore the above examples, and submit questions on our User Group or Blueprint Examples Github Repo.
For more thorough documentation, head to our Ansible Plugin Docs.

comments

    Leave a Reply

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

    Back to top