For development using Ansible, each specialist will need to have their installation of Ansible. If your ogranization also uses AWX or Tower for executing these playbooks, then ensuring that new content can be seamlessly deployed to AWX/Tower is greatly benefited by having each specialist running thier own local AWX/Tower environment.

Creating the Local AWX Environment

We’ll be running our local environment on a Windows workstation using WSL2. To get started, make sure you’ve got a a WSL2 distribution installed and running, and a container runtime like Docker Desktop for Windows or a very recent version of Podman already configured and running.

Prerequisites

The containers running in the local AWX environment will require access to the systemd cgroupfs, so make sure it’s mounted in the Docker host system. A suggested place to put this is in your .profile

To mount:

1
2
sudo mkdir -p /sys/fs/cgroup/systemd
sudo mount -t cgroup -o none,name=systemd cgroup /sys/fs/cgroup/systemd

AWX is not a lightweight application, I recommend at least 8GB of RAM allocated to your WSL2 distribution if possible and as fast of SSD as you can manage.

Note that if you’re not building AWX on one of their supported operating systems, that you must run under python 3.8, and have the wheel package installed. If you have to manage multiple python runtimes and your distribution doesn’t have a native way to support them, consider PyEnv.

Preparing the Local AWX Environment

We’re going to take advantage of the AWX local development environment provided by the AWX developers. As we won’t be hacking on AWX, I made some changes to quiet the log output as I’m less interested in the debug output of the internals of AWX itself.

Note: I added my own branch to capture the following changes. Manage your git workflow however you see fit.

The latest version of AWX at the time of writing is 19.5.0; ensure you choose the version that is best for you.

Clone the AWX repository

1
2
git clone -b 19.3.0 https://github.com/ansible/awx.git
git switch -c quiet

Modify configuration for much quieter logging

Firstly, stop the uwsgi server from logging each and every call to AWX

Makefile

235
236
237
238
239
240
241
242
    --stats /tmp/stats.socket \
    --lazy-apps \
    --logformat "%(addr) %(method) %(uri) - %(proto) %(status)" \
    --hook-accepting1="exec: $(UWSGI_DEV_RELOAD_COMMAND)" \
    --logto=/dev/null

 daphne:
        @if [ "$(VENV_BASE)" ]; then \

Also make the AWX app server itself much more quiet

tools/docker-compose/ansible/roles/sources/files/local_settings.py

46
47
48
49
50
51
52
53
54
SYSTEM_UUID = '00000000-0000-0000-0000-000000000000'
BROADCAST_WEBSOCKET_PORT = 8013
BROADCAST_WEBSOCKET_VERIFY_CERT = False
BROADCAST_WEBSOCKET_PROTOCOL = 'http'

# Quiet the AWX contaiers logs
DEBUG = False
TEMPLATE_DEBUG = DEBUG
SQL_DEBUG = DEBUG

Multi-node receptor setup has been added to the latest AWX; it’s really noisy. Let’s quiet it down:

tools/docker-compose/ansible/roles/sources/templates/receptor-awx.conf.j2

1
2
3
4
5
6
7
- node:
    id: awx_{{ item }}

- log-level: error

- tcp-listener:
    port: 2222

tools/docker-compose/ansible/roles/sources/templates/receptor-hop.conf.j2

1
2
3
4
5
6
7
- node:
    id: receptor-hop

- log-level: error

- tcp-peer:
    address: awx_1:2222

tools/docker-compose/ansible/roles/sources/templates/receptor-worker.conf.j2

1
2
3
4
5
6
7
- node:
     id: receptor-{{ item }}

- log-level: error

- tcp-peer:
    address: tools_receptor_hop:5555

Ensure that the systemd cgroupfs is explictly mounted in AWX containers

Even with the systemd cgroupfs mounted on the host under /sys/fs/cgroup/systemd, it would not show in the containers. So I explicitly mounted it in the AWX and receptor containers.

tools/docker-compose/ansible/roles/sources/templates/docker-compose.yml.j2

39
40
41
42
43
44
45
      - "../../docker-compose/_sources/receptor/receptor-awx-{{ loop.index }}.conf:/etc/receptor/receptor.conf"
      # - "../../docker-compose/_sources/certs:/etc/receptor/certs"  # TODO: optionally generate certs
      - "/sys/fs/cgroup:/sys/fs/cgroup"
      - "/sys/fs/cgroup/systemd:/sys/fs/cgroup/systemd"
      - "~/.kube/config:/var/lib/awx/.kube/config"
      - "redis_socket_{{ container_postfix }}:/var/run/redis/:rw"
    privileged: true
121
122
123
124
125
126
127
    volumes:
      - "../../docker-compose/_sources/receptor/receptor-worker-{{ loop.index }}.conf:/etc/receptor/receptor.conf"
      - "/sys/fs/cgroup:/sys/fs/cgroup"
      - "/sys/fs/cgroup/systemd:/sys/fs/cgroup/systemd"
    privileged: true
  {% endfor %}
{% endif %}

Building a local instance of AWX

Now that the logs are quieted and the systemd cgroupfs will be mounted in the required containers, it’s time to start following the directions from the AWX build guide in their Github repository located here.

  1. Build the AWX container (once per AWX version update)

I’m specifying a custom tag for my image, make sure to update that as appropriate for your ogranization. You may leave the custom tag out if you don’t need the image outside your local workstation.

git switch devel
DEVEL_IMAGE_NAME=your-registry.here.com/awx_devel:19.3.0-quiet make docker-compose-build
  1. Start the containers

Because we are working in our own branch, we need to tell the start process which branch the base AWX image was compiled in.

COMPOSE_TAG=devel make docker-compose COMPOSE_UP_OPTS=-d
  1. Wait for DB migrations to complete (once per source tree update)

Upon first startup of AWX, the database is populated with the required tables. On any source tree updates, further migrations may be applied to the database. You can check to see if the the migrations have completed by running an awx-manage command inside the AWX container:

docker exec -ti tools_awx_1 awx-manage showmigrations | grep -c '\[ \]'

Once the number returned is zero, the migrations are complete.

  1. Build the UI (once per AWX version update)

The UI needs to be built, you can do that by running the following command:

docker exec tools_awx_1 make clean-ui ui-devel

Create a local administration user

With AWX now running locally, we need an user with which to login. This can be done with:

docker exec -ti tools_awx_1 awx-manage createsuperuser --username <myuserhere> --email <myemail@here>

Logging in

With AWX now running you can log in using the previously created credentials with the following URLs.

Endpoint URL
HTTP http://localhost:8013/#/home
HTTPS https://localhost:8043/#/home
API https://localhost:8043/api/v2
The HTTPS endpoint uses a self-signed certificate