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.
An AWX source is the connection record for one controller. You manage sources under Integrations → AWX / Tower (/integrations/awx).
| Field | Purpose |
|---|---|
name | Friendly label used to select the source in steps and the SDK. |
url | Base URL of the controller, e.g. https://tower.corp.com. |
api_token | A Personal Access Token from the AWX/Tower user's token settings. Sent as Authorization: Bearer …. |
verify_ssl | Whether to verify the controller's TLS certificate (default on). |
enabled | Only enabled sources are used by steps and the SDK. |
status / status_msg / last_tested | Result of the last connection test. |
metadata | Discovered 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.
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).
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:
| Capability | AWX endpoint |
|---|---|
| Health / version | GET /ping/, GET /config/ |
| Job templates | GET /job_templates/, GET /job_templates/{id}/ |
| Launch a job | POST /job_templates/{id}/launch/ |
| Job status | GET /jobs/{id}/, GET /jobs/ |
| Job output | GET /jobs/{id}/stdout/?format=txt |
| Cancel a job | POST /jobs/{id}/cancel/ |
| Inventories | GET /inventories/ |
| Projects | GET /projects/, POST /projects/{id}/update/ |
| Workflow templates | GET /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.
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_connectivityVerifies 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_templateThe 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:
| Config | Meaning |
|---|---|
template_id / template_name | The job template to run (ID preferred; name resolved via lookup). |
extra_vars | JSON object merged into the job's extra variables. |
limit | An Ansible host-limit pattern (e.g. web-servers). |
wait_for_completion | Poll to a terminal state (default) or return as soon as the job starts. |
timeout_minutes | How 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_jobPolls 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_outputRetrieves 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_projectTriggers 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.
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.
| Workflow | Slug | What it does |
|---|---|---|
| AWX / Tower Job Template Launch | awx-job-template-launch | Launches 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 Deployment | awx-config-deploy | Deploys config changes via a job template behind a normal ServiceNow change + approval gate, captures deployment output, and closes the CR. |
| AWX Compliance Scan | awx-compliance-scan | Runs 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.
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.
A typical rollout looks like this:
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.
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.
awx.* steps into your own workflows.