Skip to content

Ansible APIs

In Ansible AWX, everything (even the UI), is driven from the API, which extensively leverages Django DRF.

Warning

This requires the following dependencies and has been tested at these specified versions:

requests==23.1.2

Explore Django DRF API

The primary URL for accessing Ansible AWX's Django DRF API is usually https://<awx_server>/api/v2/. Ensure you have the appropriate permissions and that the API endpoint is accessible.

Objects in AWX are based on Django DRF, which help you traverse the parent-child relationships of the database. For instance, a job template might be tied to a specific inventory or project. This hierarchical nature means certain API calls might depend on IDs or details retrieved from a different endpoint.

All of the endpoints can be navigated from here, a few highlights would be:

  • Jobs: (https://<awx_server>/api/v2/jobs/) Retrieve information about job runs, their status, and results.
  • Job Templates: (https://<awx_server>/api/v2/job_templates/) Understand the predefined tasks and their configurations.
  • Inventories: (https://<awx_server>/api/v2/inventories/) Get information about hosts, groups, and associated variables.

Warning

Make sure to always include a trailing slash on the api call.

Info

In the DRF interface, you can click generally click on links to navigate directly to related resources.

You can run API calls right from the UI. When there is an applicable update, you can make it via the bottom hand page.

Explore Django DRF API - LAB

  • Review the Django DRF interface, especially jobs, job_templates, and inventories.
  • Make a PATCH call on one of the inventories, make sure to remove all variables you do not want to touch.

Access Tokens

The API is accessible via multiple credentials methods, for the purpose of this lab, we will use a token, but you could also use user/password credentials.

Access Tokens - LAB

To obtain a token from the UI, follow these steps:

  • In the top right, navigate to {{ your_username}} -> User Details
  • Navigate to the Tokens tab, click Add
  • Fill out with:
    • Description: {{ initials }} Token
    • Scope: write
  • Click Save
  • Make sure to copy your token!!!
  • Test your token with curl -k -X GET -H "Authorization: Bearer YOUR_TOKEN" https://<awx_server>/api/v2/ping/

Curl API calls

While Curl (or Postman) does not provide great mechanisms for interacting (e.g. making a call, gathering data, making another call from that data) with APIs, they do provide a great test place to understand basic API calls.

Let's explore a few different API calls.

curl -H "Authorization: Bearer YOUR_TOKEN" https://<awx_server>/api/v2/inventories/

Find the ID via Django DRF or you can see it in the UI is the URL of a given job template.

# Using Job ID
curl -X POST -H "Authorization: Bearer YOUR_TOKEN" https://<awx_server>/api/v2/job_templates/{90}/launch/

# Using Job Name
curl -X POST -H "Authorization: Bearer YOUR_TOKEN"  https://<awx_server>/api/v2/job_templates/{job-name}/launch/

Curl API calls - LAB

Run through the provided Curl commands.

Python Requests API Calls

For any series of API calls, Curl (or Postman) can provide some quick and dirty help. However, that logic to find IDs dynamically or deal with an asynchronous API is rather difficult without a programming language. We will review how to use Python requests to work with Ansible AWX APIs.

Warning

An asynchronous API will immediately return a return code indicting that the message has been successfully received, but it does not let you know when the job is complete. You have to make an API call to another endpoint to indicate the completion of the job, **luckily, the AWX API provides you with that URL in the return code"

import requests

import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

AWX_URL = "awx.ntcu.ntc.dev/"

JOB_TEMPLATE_ID = 'nautobot-environment'
TOKEN = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"  # replace with your actual token

# Set the headers for authentication and content type
headers = {
    "Authorization": f"Bearer {TOKEN}",
    "Content-Type": "application/json"
}

response = requests.get(f'https://{AWX_URL}/api/v2/inventories/', headers=headers)

if response.status_code == 200:
    print(response.json())
else:
    print(f"Error: {response.status_code}")

The Ansible AWX API allows for various parameters when launching a job via the /api/v2/job_templates/{id}/launch/ endpoint. When we talk about launching a job from a Job Template, several key parameters come into play.

  • limit: Refers to the host limit, where you can specify a subset of hosts from the inventory to run the job against. It accepts a pattern or a comma-separated list of hosts, as you would find in an Ansible Playbook.
  • extra_vars: Variables that you pass to the playbook at runtime. These are in JSON format when passed via the API. For instance: {"key1": "value1", "key2": "value2"}.
  • job_tags: This allows you to run only specific parts of the playbook by specifying tags.
  • skip_tags: Skips tasks associated with specified tags.
  • job_type: Determines how the job will run. It can be 'run' (default) or 'check'. The 'check' mode performs a dry run.
  • inventory: ID of the inventory you want to use. By default, it would use the inventory associated with the job template.
  • credentials: List of credential IDs to use for the job. This might override the default credentials set in the job template.

There are other parameters as well, like diff_mode, verbosity, etc., but the ones listed above are some of the more commonly used ones.

When you configure a Job Template in Ansible AWX, you can set various fields to "Prompt on Launch". This means that when a user initiates a job run from this template (whether from the UI or the API), they will be prompted to provide values for these fields.

  • If you've set a field (like limit or extra_vars) to "Prompt on Launch" in the UI, and then you use the API to launch the job without providing that parameter, AWX will expect that piece of data to be provided elsewhere, or it might use the default specified in the job template.
  • If you do provide the parameter in the API call, it will override whatever default is specified in the job template for that run.
  • If a parameter is set to "Prompt on Launch" but is not provided in the API call and doesn't have a default in the job template, the job launch might fail.

In summary, the "Prompt on Launch" option in the UI gives flexibility when launching jobs but also "enables" that feature via the API.

data = {
    "extra_vars": {"key1": "value1", "key2": "value2"}
}

job_name = "hello-world" # or alternate name

response = requests.post(f'https://{AWX_URL}/api/v2/job_templates/{job_name}/launch/', headers=headers, json=data)

if response.status_code == 201:
    print("Job successfully created!")
    print(response.json())
else:
    print(f"Error: {response.status_code}")

Python Requests API Calls - LAB

  • Run through the two provided examples
  • Toggle the options (extra_vars, limit, etc)
  • Build a process to run the job, and wait for the job to be complete.
    • Hint: Use the data returned in the job_template launch to find next API call
    • Hint: A while loop would likely be best in this situation.