|
| 1 | +# Running Ansible locally |
| 2 | + |
| 3 | +The Ansible container is built by [`.github/workflows/containers.yaml`](../.github/workflows/containers.yaml) from [`containers/ansible/Dockerfile`](../containers/ansible/Dockerfile). That image copies this directory into `/runner/project` and the Argo workflow in [`workflows/argo-events/workflowtemplates/ansible-run.yaml`](../workflows/argo-events/workflowtemplates/ansible-run.yaml) expects inventory at `/runner/inventory/hosts.yaml`. |
| 4 | + |
| 5 | +## Build the container |
| 6 | + |
| 7 | +From the repository root: |
| 8 | + |
| 9 | +```bash |
| 10 | +docker build -f containers/ansible/Dockerfile -t understack-ansible . |
| 11 | +``` |
| 12 | + |
| 13 | +## Run locally with a Python virtualenv |
| 14 | + |
| 15 | +This uses the same Python packages and Ansible collections installed by the container build. |
| 16 | + |
| 17 | +From the repository root: |
| 18 | + |
| 19 | +```bash |
| 20 | +python3 -m venv .venv |
| 21 | +source .venv/bin/activate |
| 22 | +python -m pip install --upgrade pip |
| 23 | +pip install -r ansible/requirements.txt |
| 24 | +ansible-galaxy collection install -r ansible/requirements.yml |
| 25 | +``` |
| 26 | + |
| 27 | +Prepare inventory: |
| 28 | + |
| 29 | +```bash |
| 30 | +mkdir -p .local/ansible/inventory |
| 31 | +cp /path/to/your/inventory.yaml .local/ansible/inventory/hosts.yaml |
| 32 | +``` |
| 33 | + |
| 34 | +If the playbook talks to OpenStack, put `clouds.yaml` in a standard OpenStack location: |
| 35 | + |
| 36 | +```bash |
| 37 | +mkdir -p ~/.config/openstack |
| 38 | +cp /path/to/clouds.yaml ~/.config/openstack/clouds.yaml |
| 39 | +``` |
| 40 | + |
| 41 | +Run playbooks from the `ansible/` directory so the local roles resolve from `./roles`: |
| 42 | + |
| 43 | +```bash |
| 44 | +cd ansible |
| 45 | +ansible-playbook -i ../.local/ansible/inventory/hosts.yaml debug.yaml -vvv |
| 46 | +``` |
| 47 | + |
| 48 | +Examples: |
| 49 | + |
| 50 | +```bash |
| 51 | +cd ansible |
| 52 | +ansible-playbook -i ../.local/ansible/inventory/hosts.yaml image-upload.yaml -vvv |
| 53 | +ansible-playbook -i ../.local/ansible/inventory/hosts.yaml keystone-post-deploy.yaml -vvv |
| 54 | +``` |
| 55 | + |
| 56 | +Notes: |
| 57 | + |
| 58 | +- activate the virtualenv with `source .venv/bin/activate` before running playbooks in a new shell |
| 59 | +- `image-upload.yaml` needs a `glance` group in inventory and valid OpenStack credentials |
| 60 | +- `nova-post-deploy.yaml` also needs flavor and device-type data; override the role paths or create local symlinks to match the defaults under `/runner/data` |
| 61 | +- Nautobot playbooks may also need `NAUTOBOT_TOKEN` exported in your shell |
| 62 | + |
| 63 | +## Prepare local input files |
| 64 | + |
| 65 | +Create a local inventory file at the same path the workflow uses in-cluster: |
| 66 | + |
| 67 | +```bash |
| 68 | +mkdir -p .local/ansible/inventory |
| 69 | +cp /path/to/your/inventory.yaml .local/ansible/inventory/hosts.yaml |
| 70 | +``` |
| 71 | + |
| 72 | +If the playbook talks to OpenStack, mount a `clouds.yaml` file into a standard OpenStack location inside the container: |
| 73 | + |
| 74 | +```bash |
| 75 | +mkdir -p .local/openstack |
| 76 | +cp ~/.config/openstack/clouds.yaml .local/openstack/clouds.yaml |
| 77 | +``` |
| 78 | + |
| 79 | +If the playbook needs extra mounted data, keep the same paths it expects in-cluster: |
| 80 | + |
| 81 | +- `nova-post-deploy.yaml`: mount flavors at `/runner/data/flavors/` and device types at `/runner/data/device-types/` |
| 82 | +- playbooks using Nautobot: set `NAUTOBOT_TOKEN` |
| 83 | +- commands matching the Argo workflow: set `UNDERSTACK_ENV` |
| 84 | + |
| 85 | +## Run a playbook with ansible-runner |
| 86 | + |
| 87 | +This matches the Argo workflow shape closely. The repo copy is mounted over `/runner/project` so local edits are used without rebuilding the image. |
| 88 | + |
| 89 | +```bash |
| 90 | +docker run --rm -it \ |
| 91 | + -v "$PWD/ansible:/runner/project" \ |
| 92 | + -v "$PWD/.local/ansible/inventory:/runner/inventory" \ |
| 93 | + -v "$PWD/.local/openstack:/etc/openstack:ro" \ |
| 94 | + -e UNDERSTACK_ENV=dev \ |
| 95 | + -e NAUTOBOT_TOKEN="$NAUTOBOT_TOKEN" \ |
| 96 | + understack-ansible \ |
| 97 | + ansible-runner run /tmp/runner \ |
| 98 | + --project-dir /runner/project \ |
| 99 | + --playbook debug.yaml \ |
| 100 | + --cmdline "-i /runner/inventory/hosts.yaml --extra-vars 'env=dev' -vvv" |
| 101 | +``` |
| 102 | + |
| 103 | +Notes: |
| 104 | + |
| 105 | +- `ansible-runner` must be passed explicitly because the image entrypoint is `dumb-init` |
| 106 | +- replace `debug.yaml` with the playbook you want to run |
| 107 | +- if a playbook does not use Nautobot, omit `NAUTOBOT_TOKEN` |
| 108 | +- if a playbook does not use OpenStack, omit the `/etc/openstack` mount |
| 109 | + |
| 110 | +## Example: run the image upload playbook |
| 111 | + |
| 112 | +[`image-upload.yaml`](./image-upload.yaml) targets the `glance` group and uses OpenStack auth, so the inventory needs a `glance` host or group and the container needs `clouds.yaml`: |
| 113 | + |
| 114 | +```bash |
| 115 | +docker run --rm -it \ |
| 116 | + -v "$PWD/ansible:/runner/project" \ |
| 117 | + -v "$PWD/.local/ansible/inventory:/runner/inventory" \ |
| 118 | + -v "$PWD/.local/openstack:/etc/openstack:ro" \ |
| 119 | + understack-ansible \ |
| 120 | + ansible-runner run /tmp/runner \ |
| 121 | + --project-dir /runner/project \ |
| 122 | + --playbook image-upload.yaml \ |
| 123 | + --cmdline "-i /runner/inventory/hosts.yaml -vvv" |
| 124 | +``` |
| 125 | + |
| 126 | +## Example: run the Nova flavor playbook |
| 127 | + |
| 128 | +[`nova-post-deploy.yaml`](./nova-post-deploy.yaml) also expects ConfigMap-style data directories. Mount local directories to the same paths: |
| 129 | + |
| 130 | +```bash |
| 131 | +docker run --rm -it \ |
| 132 | + -v "$PWD/ansible:/runner/project" \ |
| 133 | + -v "$PWD/.local/ansible/inventory:/runner/inventory" \ |
| 134 | + -v "$PWD/.local/openstack:/etc/openstack:ro" \ |
| 135 | + -v "$PWD/hardware/flavors:/runner/data/flavors:ro" \ |
| 136 | + -v "$PWD/hardware/device-types:/runner/data/device-types:ro" \ |
| 137 | + understack-ansible \ |
| 138 | + ansible-runner run /tmp/runner \ |
| 139 | + --project-dir /runner/project \ |
| 140 | + --playbook nova-post-deploy.yaml \ |
| 141 | + --cmdline "-i /runner/inventory/hosts.yaml -vvv" |
| 142 | +``` |
| 143 | + |
| 144 | +## Run with ansible-playbook instead |
| 145 | + |
| 146 | +If you want a simpler interactive container shell: |
| 147 | + |
| 148 | +```bash |
| 149 | +docker run --rm -it \ |
| 150 | + -v "$PWD/ansible:/runner/project" \ |
| 151 | + -v "$PWD/.local/ansible/inventory:/runner/inventory" \ |
| 152 | + -v "$PWD/.local/openstack:/etc/openstack:ro" \ |
| 153 | + --workdir /runner/project \ |
| 154 | + --entrypoint /bin/bash \ |
| 155 | + understack-ansible |
| 156 | +``` |
| 157 | + |
| 158 | +Then run: |
| 159 | + |
| 160 | +```bash |
| 161 | +ansible-playbook -i /runner/inventory/hosts.yaml debug.yaml -vvv |
| 162 | +``` |
0 commit comments