Platform Integrations

AWX and Ansible Tower

Connect Versus to Ansible Tower or AWX and launch job templates, capture their output, and sync projects as first-class workflow steps — reached over the AWX REST API v2 with a token-authenticated source, driven from the visual builder, the workflow SDK, or the API.

Versus talks to Ansible Tower (3.x) and AWX (upstream) as an automation controller you can drive from a workflow. You register a controller as an AWX source, then use built-in workflow steps — or the workflow SDK — to launch job templates, wait for them, pull their stdout, and trigger project syncs. This lets you keep your existing Ansible playbooks where they are and orchestrate them alongside native Versus device operations, approvals, and change control in one run.

Both flavors share the same REST API v2, so a single client covers Tower and AWX. Versus reaches the controller directly over HTTPS using a bearer token; nothing about your playbooks or inventory has to move into Versus.


The AWX source

An AWX source is the connection record for one controller. You manage sources under Integrations → AWX / Tower (/integrations/awx).

FieldPurpose
nameFriendly label used to select the source in steps and the SDK.
urlBase URL of the controller, e.g. https://tower.corp.com.
api_tokenA Personal Access Token from the AWX/Tower user's token settings. Sent as Authorization: Bearer ….
verify_sslWhether to verify the controller's TLS certificate (default on).
enabledOnly enabled sources are used by steps and the SDK.
status / status_msg / last_testedResult of the last connection test.
metadataDiscovered facts from the last successful test (version, active node, install UUID).

The token is stored encrypted at rest and is write-only over the API — it is never returned in a source read, so editing a source leaves the token field blank unless you're replacing it. Multi-tenant deployments scope every source to its tenant. For the broader picture of how Versus protects integration credentials, see Secret Vault and Security & Compliance.

Testing a connection

Each source exposes a test connection action that calls the controller's /api/v2/ping/ endpoint and records what it finds:

POST /api/integrations/awx-sources/{id}/test_connection/
{
  "ok": true,
  "msg": "Connected",
  "detail": { "version": "23.5.1", "active_node": "awx-1", "install_uuid": "…" }
}

A green status means the token is valid and the controller is reachable. Sources are ordinary REST resources — list, create, update, and delete them under /api/integrations/awx-sources/ (filterable by enabled).


How it works under the hood

All controller access goes through one API v2 client. Every call is made against {url}/api/v2/… with the bearer token, and the client normalizes AWX's verbose responses down to the fields Versus actually uses. The endpoints in play:

CapabilityAWX endpoint
Health / versionGET /ping/, GET /config/
Job templatesGET /job_templates/, GET /job_templates/{id}/
Launch a jobPOST /job_templates/{id}/launch/
Job statusGET /jobs/{id}/, GET /jobs/
Job outputGET /jobs/{id}/stdout/?format=txt
Cancel a jobPOST /jobs/{id}/cancel/
InventoriesGET /inventories/
ProjectsGET /projects/, POST /projects/{id}/update/
Workflow templatesGET /workflow_job_templates/, …/{id}/launch/

Launching a job is non-blocking at the API level: AWX returns the new job record immediately. When a step is asked to wait, Versus polls GET /jobs/{id}/ on an interval until the job reaches a terminal state — successful, failed, error, or canceled — or the step's timeout elapses. On a non-successful terminal state the step fetches the job's stdout and logs the tail of it, so the failure reason lands in the workflow run log instead of forcing you back into the Tower UI.


Workflow steps

Five steps are registered under the awx step category. Each accepts an optional AWX Source name and falls back to the first enabled source when left blank.

awx.check_connectivity

Verifies the controller is reachable and records its version into the run context (awx_version, awx_base_url). Use it as a guard at the top of an AWX workflow so a bad token fails fast, before any change is attempted.

awx.launch_job_template

The workhorse. It resolves the target template by numeric ID or, if you supply a name, by looking it up on the controller. You can pass:

ConfigMeaning
template_id / template_nameThe job template to run (ID preferred; name resolved via lookup).
extra_varsJSON object merged into the job's extra variables.
limitAn Ansible host-limit pattern (e.g. web-servers).
wait_for_completionPoll to a terminal state (default) or return as soon as the job starts.
timeout_minutesHow long to wait before giving up (default 30).

When run inputs are present and no explicit extra_vars are given, the step injects the workflow's run inputs as extra variables, so a workflow's form fields can flow straight into the playbook. It records awx_job_id and a deep-link awx_job_url into the context; on failure it raises with the job's terminal status after logging the stdout tail.

awx.wait_for_job

Polls an already-running job — identified by a context variable (default awx_job_id) — until it completes. Pair it with a launch step that has wait_for_completion turned off when you want to do other work in between starting a job and blocking on it.

awx.get_job_output

Retrieves a job's stdout and stores the tail of it in a context variable (default awx_job_output) for a later step to inspect, attach to a ticket, or post to chat.

awx.sync_project

Triggers an SCM sync (POST /projects/{id}/update/) so the controller pulls the latest playbooks from source control, optionally waiting for the update job to finish. Run this before launching a template when you need the newest committed playbook.


Seeded workflows

Three ready-to-run workflows ship with the integration. They wire the AWX steps together with change control and can be run as-is or cloned and edited in the Workflow Builder.

WorkflowSlugWhat it does
AWX / Tower Job Template Launchawx-job-template-launchLaunches any job template with optional extra vars and host limiting, gated by a ServiceNow change request and approval, then closes the change on success.
AWX Configuration Deploymentawx-config-deployDeploys config changes via a job template behind a normal ServiceNow change + approval gate, captures deployment output, and closes the CR.
AWX Compliance Scanawx-compliance-scanRuns a compliance scan (NIST, CIS, PCI, or custom) against a host group and surfaces the scan output in the run log.

The two change-oriented workflows follow the same shape: check connectivity → create ServiceNow change request → await approval → verify approval → launch the AWX job → close the change. The compliance scan skips the change gate and goes straight from a connectivity check to the scan and output collection. All three take an optional awx_source input, so you can point the same workflow at different controllers per run.


Using AWX from the workflow SDK

Inside a custom script step you get the same controller access through the integrations object. integrations.awx_list() returns the enabled sources, and integrations.awx(name) returns a high-level client bound to one source (or the first enabled source when called with no name).

# Launch a template by ID and block on the result
awx = integrations.awx()                     # first enabled source
result = awx.run_and_wait(
    template_id=42,
    extra_vars={"target_hosts": "bigip-01.corp.com", "action": "deploy"},
    timeout=600,
)
if result["status"] != "successful":
    output = awx.get_job_stdout(result["id"])
    integrations.slack().send_message(
        f"AWX deployment failed:\n```{output[-1000:]}```", channel="#netops"
    )
    raise RuntimeError(f"AWX job failed: {result['status']}")
# Resolve a template by name against a specific controller, then launch it
awx = integrations.awx("Production Tower")
template = awx.find_job_template("F5 Config Deploy")
job = awx.launch_job_template(template["id"], extra_vars={"env": "prod"})
versus.set_output("awx_job_id", job["id"])

The client mirrors the controller's surface: connection (test_connection), job templates (list_job_templates, get_job_template, find_job_template, launch_job_template), jobs (get_job, list_jobs, cancel_job, get_job_stdout, wait_for_completion, run_and_wait), inventories (list_inventories), projects (list_projects, sync_project), and AWX's own multi-playbook workflow templates (list_workflow_templates, launch_workflow_template). See the Workflow SDK Reference for how script steps fit into a run.


Operating the integration

A typical rollout looks like this:

  1. Create a token in AWX/Tower for a dedicated service user, scoped to the templates and inventories it should touch.
  2. Add a source under Integrations → AWX / Tower with the controller URL and that token, and click test connection to confirm reachability and capture the version.
  3. Run a seeded workflow — start with AWX / Tower Job Template Launch against a low-risk template to validate the end-to-end path, including the change gate.
  4. Build your own — drop the awx.* steps into workflows next to native device steps, approvals, and notifications, or call integrations.awx() from a script step for full control.

Because AWX jobs run inside a Versus workflow, they inherit everything the engine provides: durable run history, per-step logs, approvals, retries, scheduling, and API-driven triggering. An operator can watch an AWX job progress in the same run view as a firmware upgrade or a certificate push, and the same run can be launched from CI as described in Running Workflows via the API.


Where it fits

AWX is one integration among many the automation engine can orchestrate. For device-native change on F5, see F5 BIG-IP Integration; for how the whole platform is layered, see Platform Architecture. Use AWX when the change already lives in an Ansible playbook and you want Versus to own the surrounding process — approval, change record, output capture, and audit — rather than re-implement the playbook itself.


Related