Running an Ansible Playbook Service Non-Interactively

Although the traditional way of ordering a service is interactively via Services -> Catalogs in the WebUI, there are also two ways that embedded Ansible services can be launched with no user interaction. When run in this way the default values from the service's dialog are used.

Playbook Services as Control Actions

An embedded Ansible playbook service can be run as a control action.

Example: Creating a Control Policy to Run a Playbook Service on VM Power Off

In this example we'll create a control policy that runs a playbook when a web service VM is powered off. The control action will invoke a playbook service to remove the VM from a load balancer pool. The playbook will run on localhost (the CFME appliance).

The control action in created in the usual manner from the Control -> Actions -> All Actions -> Configuration (button) -> Add a new Action menu option.

A new Action Type of Run Ansible Playbook is available, which allows a playbook service to be chosen from the Playbook Catalog Item drop-down list (see screenshot Adding the Control Action).

The newly created action can be linked to a control policy, triggered by a VM Power Off event, and a condition that the VM is tagged as a Web Service VM (see screenshot Creating the Control Policy).

Note

Running an embedded Ansible playbook service in this way still goes through the service approval process.

Variables Available to an Ansible Playbook Run as a Control Action

Several variables are available to an Ansible playbook running from a control action, as follows:

        "manageiq": {
            "X_MIQ_Group": "EvmGroup-super_administrator",
            "action": "Provision",
            "api_token": "befb11cc0dd25d8650b7beec1537525b",
            "api_url": "https://10.2.3.4",
            "event_name": "vm_poweroff",
            "event_target": "vms/1000000001277",
            "group": "groups/1000000000002",
            "service": "services/1000000000037",
            "user": "users/1000000000005"
        },
        "manageiq_connection": {
            "X_MIQ_Group": "EvmGroup-super_administrator",
            "token": "befb11cc0dd25d8650b7beec1537525b",
            "url": "https://10.2.3.4"
        },

Of particular use in a control action context are the event_name and event_target variables which convey the type of event that was raised, and the object href_slug that triggered the event.

Deleting the Service Once the Playbook has Run

Each time a playbook control action runs a new service will be created under My Services in the WebUI. Although this contains the output text from the playbook run, it may not be desirable to accumulate the results of many hundreds of non-interactive services in this way.

The playbook can, if required, delete its own service as a final task, as follows:

  - name: Delete the service 
    uri:
      url: "{{ manageiq.api_url }}/api/services"
      method: POST
      validate_certs: no
      headers:
        X-Auth-Token: "{{ manageiq.api_token }}"
      body_format: json
      body:
        action: delete
        resource:
          href: "{{ manageiq.api_url }}/api/{{ manageiq.service }}"

Requesting Playbook Services from (Ruby) Automate

CloudForms 4.5 / ManageIQ Fine introduced a new way of requesting any service from Ruby automate using $evm.execute('create_service_provision_request', service_template, options), for example:

CREDENTIAL_CLASS = "ManageIQ_Providers_EmbeddedAnsible_AutomationManager_MachineCredential".freeze
TEMPLATE_CLASS   = "ServiceTemplate".freeze
#
# Run a playbook service on localhost
#
service_template = $evm.vmdb(TEMPLATE_CLASS).where(:name => 'List Variables and Facts').first
options          = {
  "credential"    => nil, 
  "hosts"         => "localhost", 
  }
$evm.execute('create_service_provision_request', service_template, options)
#
# To run a playbook service on a remote host we have to use a credential as well
#
service_template = $evm.vmdb(TEMPLATE_CLASS).where(:name => 'Install a Package').first
credential       = $evm.vmdb(CREDENTIAL_CLASS).where(:name => 'Root Password').first
options          = {
  "credential"    => credential.id, 
  "hosts"         => "infra1.cloud.uk.bit63.com", 
  "param_package" => "mlocate"
  }
$evm.execute('create_service_provision_request', service_template, options)

Order_Ansible_Playbook

To simplify the use of create_service_provision_request for the most common use-cases, a jacket method /System/Request/order_ansible_playbook has been created, with a corresponding instance /System/Request/Order_Ansible_Playbook. This was primarily created to simplify the process of requesting an embedded Ansible playbook service from a custom button.

order_ansible_playbook uses $evm.root keys to determine the playbook service to run, and the hosts on which to run it. The keys are as follows:

  • service_template_name (required) - should contain the text string name of the service catalog item to request

  • hosts (optional) - if used will override the Hosts value defined when the service was created. This is a text string, and can take several forms:

    • "vmdb_object" - in which case the object represented by the $evm.root['vmdb_object_type'] value will be used. For example if $evm.root['vmdb_object_type'] = "vm" then the first IP address of the $evm.root['vm'] object will be used as the playbook's hosts value. If $evm.root['vmdb_object_type'] = "host" then the first IP address of the $evm.root['host'] object will be used.

    • "localhost" - in which case the playbook will be run on localhost.

    • "hostname" (e.g. "infra1.cloud.uk.bit63.com") - the DNS-resolvable name of the managed node on which to run the playbook

    • "ip[,ip]" (e.g. "192.168.1.45" or "10.2.4.5,10.2.4.6") - one or more managed node IPv4 addresses on which to run the playbook

  • dialog_hosts (optional) - an alternative way of specifying the target managed node for the playbook service. Useful when Order_Ansible_Playbook has been called from a button with a dialog containing a hosts element.

Note Although dialog_hosts is an optional input to order_ansible_playbook, if no dialog_hosts is passed through to the service at all (for example if it is also missing from the service's default service dialog), then localhost will be used as the target host for the service, overriding the hosts value passed to order_ansible_playbook.

  • dialog_credential (optional) - a credential object ID to use when making the connection to the managed node

These $evm.root keys can be defined as Attribute/Value pairs when an instance is launched (see screenshot Calling Order_Ansible_Playbook).

Warning

If the vmdb_object has multiple IP addresses (including IPv6 or cloud public & private addresses), the first IP address listed may not necessarily be the correct address for remote Ansible connectivity.

Summary

This chapter has shown how playbook services can be requested non-interactively, either as a control action or from Ruby Automate. Calling services in this way from Automate has been largely superseded with CloudForms 4.6 (ManageIQ Gaprindashvili) with the introduction of Ansible playbook methods.

Further Reading

Order Ansible Playbook from a Custom Button using a Method

Last updated