Ansible Tower Job Control with the awx cli
		Overview
Whilst I’m a big fan of Ansible Tower’s UI and the overall User Experience I generally try to avoid spending time in it these days. If you spend a lot of time clicking in an automation tool you’re probably "doing it wrong" IMHO!
Up until Ansible Tower 3.6 we have been using a mix of tower-cli, Python based API calls, and Ansible Playbooks to automate our use of Tower and in particular job launching. In fact it’s completely possible for us to deploy a Tower Cluster, use it on a daily basis, and then tear it down without ever logging into the console.
So in this article I want to explore how to use the new, as of Tower 3.6 awx command line utility for Ansible Tower API access with a focus on Job Control. We’ll cover:
- 
Installation
 - 
Configuration and Authentication
 - 
Job Management
- 
Listing past jobs
 - 
Retrieving job logs
 - 
Running jobs
 - 
Monitoring jobs
 
 - 
 - 
Resources and Documentation
 
| 
 Note 
 | 
Just to be clear and avoid confusion between awx the command line tool
and AWX the upstream Ansible Tower Open Source project I’ll always be referring
the cli tool when using the lowercase awx and uppercase AWX when referring to
the Upstream Project.
 | 
Installation
The Installation Docs can be found here
- 
Installing via
pipI strongly recommend the usage ofyumwhen using Red Hat Enterprise Linux. However for the purpose of this article we’ll usepipas this is the most flexible across multiple different platforms.pip3 install --user \ https://releases.ansible.com/ansible-tower/cli/ansible-tower-cli-latest.tar.gzNoteIf you exclusively use Python 3 like me (you should, Python 2 EOL is coming soon!) then you can change the pip3topip. You may also want to change the above if you want to make it available system-wide (drop the--user) or are deploying to a virtualenv. I mainly work in virtualenvs so I would: first install system-wide and then if I needed specific versions use pip to install in the relevant virtualenv. For a quick start guide to virtualenvs on RHEL look here.pip install https://releases.ansible.com/ansible-tower/cli/ansible-tower-cli-latest.tar.gz 
Configuration and Authentication
This section is just a brief introduction to configuration and authentication
and more details can be found
here including Oauth2 and Personal Access Tokens.
Different users use patterns will vary but in our team we use multiple different
Tower clusters daily and the following pattern works well. If you have a more static environment, with perhaps just one Tower server or cluster then perhaps
consider putting the environmental variables below in your .bashrc or equivalent.
- 
Create 1 or more tower credential environment settings files
 - 
Source the appropriate file prior to interacting with a particular tower or tower cluster.
 - 
Use
awxwithout having to specify credentials and hosts each time- 
Create the environmental file(s) in an appropriate directory
$ vim ~/secrets/my-production-tower.env export TOWER_HOST=https://tower.example.com export TOWER_USERNAME=<YOUR-USERNAME-HERE> export TOWER_PASSWORD=<YOUR-PASSWORD-HERE> export TOWER_VERIFY_SSL=falseNoteThe last variable TOWER_VERIFY_SSL=falseis only needed if you are using unsigned certificates. You can achieve the equivalent on the command line withawx -k. - 
sourcethe appropriate file$ source ~/secrets/my-production-tower.env - 
Work with
awxwithout having to specifyuser,hostandpasswordetc e.g.$ awx job list -f human id name == =========================================================== 1 deploy-agnosticd-three-tier-app-prod-1.14-3tier-test-01 2 destroy-agnosticd-three-tier-app-prod-1.14-3tier-test-01 3 deploy-agnosticd-three-tier-app-prod-1.14-3tier-test-02 4 destroy-agnosticd-three-tier-app-prod-1.14-3tier-test-02 5 deploy-agnosticd-three-tier-app-prod-1.14-3tier-test-03 6 deploy-agnosticd-three-tier-app-prod-1.14-3tier-sat-test-01 7 deploy-agnosticd-three-tier-app-prod-1.14-3tier-sat-test-02 8 deploy-agnosticd-three-tier-app-prod-1.14-3tier-sat-test-03 9 destroy-agnosticd-three-tier-app-prod-1.14-3tier-sat-test-01TipIf you do work with multiple tower configurations then consider adding 1 more more line to each configuration file setting the name of the current tower in your shell prompt. Something like this should work: ` export PS1="prod-tower":$PS1` giving a shell prompt like this on my machine: prod-tower:➜ ~ git:(article-job-control-with-awx) ✗ 
 - 
 
Resources and Actions
awx works on the concepts of resources and actions. Examples of resources
include: user, job, project etc. A full list can be generated by just running
awx with no arguments. Actions include: list, get, delete etc and are
resource sensitive , for example awx user stdout makes no sense and will fail.
| 
 Tip 
 | 
awx often supports both singular and plural for key resources and the
following commands are equivalent
awx job list
awx jobs list
 | 
| 
 Tip 
 | 
awx includes context sensitive help so if you can’t remember the possible
options to pass to a command like awx job list then just add -h or --help.
 | 
Job Management
Now we have awx setup and configured it is time to start using it. In my team
we generally use Ansible itself to create Tower Resources such as users, projects,
job templates etc and use API calls primarily for Job Management e.g.
- 
Listing past jobs
 - 
Retrieving job logs
 - 
Running new jobs
 - 
Monitoring jobs
 
Before going further it is worth noting that awx has 4 output modes:
- 
json (default)
 - 
human
 - 
yaml
 - 
jq
 
These can be applied with the -f flag as shown in the example above (awx job
list -f human)
Listing past jobs
The simplest way to list jobs that have been run previously is simply:
awx job list and even with just a few jobs that output can be considerable,
plus as mentioned above it defaults to json. (A single job might generate ~160
lines of json)
- 
List jobs
$ awx job list { count: 102, next: /api/v2/jobs/?page=2, previous: null, results: [ { id: 4, type: job, url: /api/v2/jobs/4/, related: { created_by: /api/v2/users/3/, labels: /api/v2/jobs/4/labels/,So perhaps useful f you are piping it to another command expecting
jsonbut somewhat difficult for humans to parse. If you speakjsonlike a pro then time to learn the-f jqoption which will be the subject of a future article.Let’s make the output more human friendly with the
-f humanoption:awx job list -f human id name == =========================================================== 1 deploy-agnosticd-three-tier-app-prod-1.14-3tier-test-01 2 destroy-agnosticd-three-tier-app-prod-1.14-3tier-test-01 3 deploy-agnosticd-three-tier-app-prod-1.14-3tier-test-02 4 destroy-agnosticd-three-tier-app-prod-1.14-3tier-test-02More manageable but now perhaps a little too terse, try filtering with the very useful
--filteroption:awx jobs list --all -f human --filter 'id,name,status' id name status === =========================================================== ========== 1 deploy-agnosticd-three-tier-app-prod-1.14-3tier-test-01 successful 2 destroy-agnosticd-three-tier-app-prod-1.14-3tier-test-01 successful 3 destroy-agnosticd-three-tier-app-prod-1.14-3tier-test-01 successful 4 destroy-agnosticd-three-tier-app-prod-1.14-3tier-test-01 successful 5 destroy-agnosticd-three-tier-app-prod-1.14-3tier-test-01 successful 6 deploy-agnosticd-three-tier-app-prod-1.14-3tier-sat-test-01 failed 7 provision-agnosticd-development-4xxp8 failed 8 destroy-agnosticd-development-4xxp8 successful ... - 
Retrieving the ansible logs
I’d recommend shipping all logs to some form of external logging such as ELK which Tower has in-built support for. However what if you want to see why
job 6above failed? In other words to see the ansible output in much the same way as if you’d executedansible-playbook? Use thestdoutoption:$ awx job stdout 6 [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all' PLAY [Step 0000 - Setup output_dir] ******************************************** TASK [debug] ******************************************************************* Wednesday 20 November 2019 23:03:11 +0000 (0:00:00.029) 0:00:00.029 **** skipping: [localhost] ...- 
Retrieving job status by name (
--name)If you know the name of a particular job, whether only run once or many times you can retrieve the status, and more, via the
--nameargument. For example here we have ajob-templatecalleddestroy-agnosticd-three-tier-app-prod-1.14-3tier-test-01and to retrieve status we can pass this via--name destroy-agnosticd-three-tier-app-prod-1.14-3tier-test-01:awx jobs list --name destroy-agnosticd-three-tier-app-prod-1.14-3tier-test-01 \ -f human --filter 'id, name,status' id name status == ======================================================== ========== 9 destroy-agnosticd-three-tier-app-prod-1.14-3tier-test-01 successful 13 destroy-agnosticd-three-tier-app-prod-1.14-3tier-test-01 successful 16 destroy-agnosticd-three-tier-app-prod-1.14-3tier-test-01 successful 19 destroy-agnosticd-three-tier-app-prod-1.14-3tier-test-01 successfulTipCan’t remember your job-templatesname, try this and remember itawxresources use underscores and not dashes sojob_templatenotjob-template:$ awx job_templates list -f human --filter 'id, name' id name == =========================================================== 17 deploy-agnosticd-three-tier-app-prod-1.14-3tier-sat-test-01 15 deploy-agnosticd-three-tier-app-prod-1.14-3tier-test-01 35 destroy-agnosticd-development-jzz66 24 destroy-agnosticd-development-nx5lr 16 destroy-agnosticd-three-tier-app-prod-1.14-3tier-test-01 33 destroy-agnosticd-three-tier-app-prod-1.14-5wht5 31 destroy-agnosticd-three-tier-app-prod-1.14-6fn7r 
 - 
 
Job Control
So far we’ve looked at using awx to examine the status and logs of jobs that
have already been run. However one of the most powerful features of the API and
awx is to launch new jobs. Reminder, a job is the launch of a job-template
with or without passing variables.
Often examples of job launches are shown using job-template ids but it is far
superior, IMO, to launch job templates via their name and the prior command
shows how to look names up dynamically.
- 
Simple launch of a
job-templatecalledfoo$ awx job_template launch foo -f human id name === ========== 120 foo - 
Launching the same
foojob-templatewith an extra varguidThis is somewhat different from
awxpredecessortower-cliand cannot simply be done in a single atomic command. Rather you to first modify thejob_templatewith the newextra-varsand then execute the command.NoteThe job_templatewill retain your new vars so a subsequent launch will inherit those variables - so use carefully.$ awx job_template modify foo --extra_vars guid=1234 $ awx job_template launch foo -f human id name === ========== 122 foo - 
Launching the same
foojob_templatewith an extra var file If you want to pass more than one var or just prefer the Infrastructure as Code properties and other advantages you can pass an entirevarfile using the@symbol to proceed the path.$ awx job_template modify foo --extra_vars @./vars/my-config.yml $ awx job_template launch foo -f human id name === ========== 124 foo - 
Finally if you want to follow along with the log output as your job runs use the
--monitoroption$ awx job_template launch foo --monitor id name === ========== 126 foo 
Resources
Ansible and Ansible Tower’s documents are, generally, excellent and I strongly
recommend starting there. There is a dedicated documentation set for awx cli.
At this point there are few blog articles out there given the relative newness of awx into mainstream Ansible Tower.
NB as awx calls the Ansible Tower V2 API it should work fine with earlier versions of Tower that support V2.