mirror of
https://gitea.com/mcereda/oam.git
synced 2026-02-09 05:44:23 +00:00
1386 lines
48 KiB
Markdown
1386 lines
48 KiB
Markdown
# AWX
|
|
|
|
Web-based UI, REST API, and task engine built on top of [Ansible].<br/>
|
|
Part of the upstream projects for the [Red Hat Ansible Automation Platform].
|
|
|
|
1. [TL;DR](#tldr)
|
|
1. [Gotchas](#gotchas)
|
|
1. [Setup](#setup)
|
|
1. [Deployment](#deployment)
|
|
1. [Update](#update)
|
|
1. [Removal](#removal)
|
|
1. [Testing](#testing)
|
|
1. [Executing jobs](#executing-jobs)
|
|
1. [Attribute inheritance and overriding](#attribute-inheritance-and-overriding)
|
|
1. [Variables inheritance and overriding](#variables-inheritance-and-overriding)
|
|
1. [Elevating privileges in tasks](#elevating-privileges-in-tasks)
|
|
1. [Workflow automation](#workflow-automation)
|
|
1. [Pass data between workflow Nodes](#pass-data-between-workflow-nodes)
|
|
1. [API](#api)
|
|
1. [Further readings](#further-readings)
|
|
1. [Sources](#sources)
|
|
|
|
## TL;DR
|
|
|
|
> [!tip]
|
|
> When in doubt about AWX's inner workings, consider [asking Devin][deepwiki ansible/awx].
|
|
|
|
## Gotchas
|
|
|
|
- When one does **not** define values in a resource during its creation, the resource will default to the settings of
|
|
the same name defined by the underlying dependency (if any).<br/>
|
|
E.g.: not setting the `job_type` parameter in a schedule (or setting it to `null`) makes the job it starts use the
|
|
`job_type` setting defined in the job template that the schedule references.<br/>
|
|
Refer [Attribute inheritance and overriding].
|
|
|
|
- Extra variables configured in job templates will take precedence over the ones defined in the playbook and its tasks,
|
|
as if they were given to the `ansible-playbook` command for the job using its `-e, --extra-vars` option.
|
|
|
|
These variables will have the **highest** precedence of all variables, and as such it is their value that will be used
|
|
throughout the whole execution. They will **not** be overridden by any other definition for similarly named variables
|
|
(not at play, host, block nor task level; not even the `set_facts` module will override them).<br/>
|
|
Refer [Variables inheritance and overriding].
|
|
|
|
- Once a variable is defined in a job template, it **will** be passed to the ansible command for the job, even if its
|
|
value is set to `null` (it will be an empty string).
|
|
|
|
When launching a job that allows for variables editing, the edited variables will be **merged** on top of the initial
|
|
setting.<br/>
|
|
As such, values configured in the job template can **at most** be overridden, but **never deleted**. They also cannot
|
|
be set to `null`, since `null` values in the override will **not** be considered in the merge, resulting in the job
|
|
template's predefined value being picked.
|
|
|
|
- Consider using only AMD64 nodes to host the containers for AWX instances.
|
|
|
|
As of 2024-04-11, AWX does **not** appear to provide ARM64 images for all its containers.<br/>
|
|
One'll need to build their own missing ARM64 images and specify those during deployment. Good luck with that!
|
|
|
|
- K8S tolerations set in AWX custom resources only affect K8S-based AWX instances' deployments.<br/>
|
|
They are **not** applied to other resources like automation Jobs.
|
|
|
|
Job-related specific K8S settings need to be configured in the `pod_spec_override` attribute of Instance Groups of
|
|
type _Container Group_.<br/>
|
|
Refer [Executing Jobs].
|
|
|
|
- Playbooks that use the `vars_prompt` key, but do **not** receive the corresponding values through job templates'
|
|
`extra_vars`, will cause AWX runs **to hang** by waiting for user input in an unreachable TTY.<br/>
|
|
Consider avoiding using `vars_prompt` in playbooks that need to be run by AWX, or ensuring that those variables are
|
|
provided ahead of time.
|
|
|
|
## Setup
|
|
|
|
### Deployment
|
|
|
|
Starting from version 18.0, the [AWX Kubernetes Operator][operator's documentation] is the preferred way to deploy
|
|
AWX instances.<br/>
|
|
It is meant to provide a Kubernetes-native installation method for AWX via the `AWX` Custom Resource Definition (CRD).
|
|
|
|
Deploying AWS instances is just a matter of:
|
|
|
|
1. Installing the operator on the K8S cluster.<br/>
|
|
Make sure to include Ansible's CRDs.
|
|
1. Create a resource of kind `AWX`.
|
|
|
|
Whenever a resource of the `AWX` kind is created, the [kubernetes operator] executes an Ansible role that creates all
|
|
the other resources an AWX instance requires to start in the cluster.<br/>
|
|
See [Iterating on the installer without deploying the operator].
|
|
|
|
The operator _can_ be configured to automatically deploy a default AWX instance once running, but its input options are
|
|
limited. This prevents changing specific settings for the AWX instance one might need to set.<br/>
|
|
Creating resources of the `AWX` kind, instead, allows to include their specific configuration, and hence for more of its
|
|
settings to be customized. It should™ also be less prone to deployment errors.
|
|
|
|
Requirements:
|
|
|
|
- An existing K8S cluster with AMD64 nodes (see [Gotchas]).
|
|
- A DB instance, either in the cluster or external to it.<br/>
|
|
If internal, one shall be able to create PersistentVolumeClaims and PersistentVolumes in the cluster for it (unless
|
|
data persistence is not a wanted feature).
|
|
- The ability for the cluster to create load balancers (if setting the service type to load balancer).
|
|
|
|
<details style='padding-top: 1em'>
|
|
<summary>Deploy the operator with <code>kustomize</code></summary>
|
|
|
|
```sh
|
|
$ mkdir -p '/tmp/awx'
|
|
$ cd '/tmp/awx'
|
|
|
|
# Specify the version tag to use
|
|
/tmp/awx$ cat <<EOF > 'kustomization.yaml'
|
|
---
|
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
|
kind: Kustomization
|
|
namespace: awx
|
|
resources:
|
|
- github.com/ansible/awx-operator/config/default?ref=2.14.0
|
|
# https://github.com/ansible/awx-operator/releases
|
|
EOF
|
|
|
|
# Start the operator
|
|
/tmp/awx$ kubectl apply -k '.'
|
|
namespace/awx created
|
|
…
|
|
deployment.apps/awx-operator-controller-manager created
|
|
/tmp/awx$ kubectl -n 'awx' get pods
|
|
NAME READY STATUS RESTARTS AGE
|
|
awx-operator-controller-manager-8b7dfcb58-k7jt8 2/2 Running 0 10m
|
|
```
|
|
|
|
</details>
|
|
|
|
<details>
|
|
<summary>Deploy the operator with <code>helm</code></summary>
|
|
|
|
```sh
|
|
# Add the operator's repository.
|
|
$ helm repo add 'awx-operator' 'https://ansible.github.io/awx-operator/'
|
|
"awx-operator" has been added to your repositories
|
|
$ helm repo update 'awx-operator'
|
|
Hang tight while we grab the latest from your chart repositories...
|
|
...Successfully got an update from the "awx-operator" chart repository
|
|
Update Complete. ⎈Happy Helming!⎈
|
|
|
|
$ helm search repo 'awx-operator'
|
|
NAME CHART VERSION APP VERSION DESCRIPTION
|
|
awx-operator/awx-operator 2.14.0 2.14.0 A Helm chart for the AWX Operator
|
|
|
|
# Install the operator.
|
|
$ helm -n 'awx' upgrade -i --create-namespace 'my-awx-operator' 'awx-operator/awx-operator' --version '2.14.0'
|
|
Release "my-awx-operator" does not exist. Installing it now.
|
|
NAME: my-awx-operator
|
|
LAST DEPLOYED: Mon Apr 8 15:34:00 2024
|
|
NAMESPACE: awx
|
|
STATUS: deployed
|
|
REVISION: 1
|
|
TEST SUITE: None
|
|
NOTES:
|
|
AWX Operator installed with Helm Chart version 2.14.0
|
|
$ kubectl -n 'awx' get pods
|
|
NAME READY STATUS RESTARTS AGE
|
|
awx-operator-controller-manager-75b667b745-g9g9c 2/2 Running 0 17m
|
|
```
|
|
|
|
</details>
|
|
|
|
<details style='padding-bottom: 1rem'>
|
|
<summary>Deploy the operator with a kustomized Helm chart</summary>
|
|
|
|
```sh
|
|
$ mkdir -p '/tmp/awx'
|
|
$ cd '/tmp/awx'
|
|
|
|
/tmp/awx$ cat <<EOF > 'namespace.yaml'
|
|
---
|
|
apiVersion: v1
|
|
kind: Namespace
|
|
metadata:
|
|
name: awx
|
|
EOF
|
|
/tmp/awx$ cat <<EOF > 'kustomization.yaml'
|
|
---
|
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
|
kind: Kustomization
|
|
namespace: awx
|
|
helmCharts:
|
|
- name: awx-operator
|
|
repo: https://ansible.github.io/awx-operator/
|
|
version: 2.19.0
|
|
releaseName: awx-operator
|
|
includeCRDs: true # Important. Not namespaced. Watch out upon removal.
|
|
resources:
|
|
- namespace.yaml
|
|
EOF
|
|
|
|
# Start the operator
|
|
/tmp/awx$ helm repo add 'awx-operator' 'https://ansible.github.io/awx-operator/'
|
|
/tmp/awx$ kubectl kustomize --enable-helm '.' | kubectl apply -f -
|
|
namespace/awx created
|
|
…
|
|
deployment.apps/awx-operator-controller-manager created
|
|
/tmp/awx$ kubectl -n 'awx' get pods
|
|
NAME READY STATUS RESTARTS AGE
|
|
awx-operator-controller-manager-8b7dfcb58-k7jt8 2/2 Running 0 10m
|
|
```
|
|
|
|
</details>
|
|
|
|
Once the operator is installed, AWX instances can be created by leveraging the `AWX` CRD.
|
|
|
|
<details style='padding-left: 1rem'>
|
|
<summary>Basic definition for a quick testing instance</summary>
|
|
|
|
```yaml
|
|
---
|
|
apiVersion: awx.ansible.com/v1beta1
|
|
kind: AWX
|
|
metadata:
|
|
name: awx-demo
|
|
spec:
|
|
no_log: false
|
|
service_type: NodePort
|
|
node_selector: |
|
|
kubernetes.io/arch: amd64
|
|
```
|
|
|
|
</details>
|
|
|
|
<details style='padding: 0 0 1rem 1rem'>
|
|
<summary>Definition for an instance on AWS' EKS</summary>
|
|
|
|
```yaml
|
|
---
|
|
apiVersion: awx.ansible.com/v1beta1
|
|
kind: AWX
|
|
metadata:
|
|
name: awx
|
|
spec:
|
|
no_log: false
|
|
admin_email: infra@example.org
|
|
postgres_configuration_secret: awx-postgres-configuration
|
|
node_selector: |
|
|
kubernetes.io/arch: amd64
|
|
service_type: LoadBalancer
|
|
ingress_type: ingress
|
|
ingress_annotations: |
|
|
kubernetes.io/ingress.class: alb
|
|
```
|
|
|
|
</details>
|
|
|
|
Due to the operator being the one creating its resources, one's control is limited to what one can define in the AWX
|
|
resource's `spec` key.<br/>
|
|
See the [installer role's defaults] and any page under the _Advanced configuration_ section in the
|
|
[operator's documentation] for details.
|
|
|
|
Useful specs:
|
|
|
|
| Spec | Description | Reason |
|
|
| ------------------ | --------------------------------------------------------- | ------------------------------------------------------ |
|
|
| `no_log: false` | See resource creation tasks' output in the operators'logs | Debug |
|
|
| `node_selector: …` | Select nodes to run on | Use only specific nodes (see warning at the beginning) |
|
|
|
|
<details style="padding-top: 1em;">
|
|
<summary>Deploy AWX instances with <code>kubectl</code></summary>
|
|
|
|
```sh
|
|
$ cd '/tmp/awx'
|
|
/tmp/awx$ kubectl apply -f 'awx-demo.yaml'
|
|
```
|
|
|
|
</details>
|
|
|
|
<details>
|
|
<summary>Deploy AWX instances with <code>kustomize</code></summary>
|
|
|
|
```sh
|
|
$ cd '/tmp/awx'
|
|
|
|
/tmp/awx$ yq -iy '.resources+=["awx-demo.yaml"]' 'kustomization.yaml'
|
|
/tmp/awx$ kubectl apply -k '.'
|
|
```
|
|
|
|
</details>
|
|
|
|
<details style='padding-bottom: 1rem'>
|
|
<summary>Deploy AWX instances using the operator's helm chart's integrated definition</summary>
|
|
|
|
```sh
|
|
# Update the operator by telling it to also deploy the AWX instance.
|
|
$ helm -n 'awx' upgrade -i --create-namespace 'my-awx-operator' 'awx-operator/awx-operator' --version '2.14.0' \
|
|
--set 'AWX.enabled=true' --set 'AWX.name=awx-demo'
|
|
Release "my-awx-operator" has been upgraded. Happy Helming!
|
|
NAME: my-awx-operator
|
|
LAST DEPLOYED: Mon Apr 8 15:37:47 2024
|
|
NAMESPACE: awx
|
|
STATUS: deployed
|
|
REVISION: 2
|
|
TEST SUITE: None
|
|
NOTES:
|
|
AWX Operator installed with Helm Chart version 2.14.0
|
|
$ kubectl -n 'awx' get pods
|
|
NAME READY STATUS RESTARTS AGE
|
|
awx-demo-migration-24.1.0-qhbq2 0/1 Completed 0 12m
|
|
awx-demo-postgres-15-0 1/1 Running 0 13m
|
|
awx-demo-task-87756dfbc-chx9t 4/4 Running 0 12m
|
|
awx-demo-web-69d6d5d6c-wdxlv 3/3 Running 0 12m
|
|
awx-operator-controller-manager-75b667b745-g9g9c 2/2 Running 0 17m
|
|
```
|
|
|
|
</details>
|
|
|
|
The default user is `admin`.<br/>
|
|
Get the password from the `{instance}-admin-password` secret:
|
|
|
|
```sh
|
|
$ kubectl -n 'awx' get secret 'awx-demo-admin-password' -o jsonpath="{.data.password}" | base64 --decode
|
|
L2ZUgNTwtswVW3gtficG1Hd443l3Kicq
|
|
```
|
|
|
|
Connect to the instance once it is up:
|
|
|
|
```sh
|
|
kubectl -n 'awx' port-forward 'service/awx-service' '8080:http'
|
|
open 'http://localhost:8080'
|
|
```
|
|
|
|
### Update
|
|
|
|
The documentation suggests to:
|
|
|
|
1. Temporarily set up the operator to automatically update any AWX instance it manages.
|
|
1. Delete the AWX instance resource.<br/>
|
|
This will force the operator to pull fresh, updated images for the new deployment.
|
|
1. Restore the operator's settings to the previous version.
|
|
|
|
### Removal
|
|
|
|
Remove the `AWX` resource associated to the instance to delete it:
|
|
|
|
```sh
|
|
$ kubectl delete awx 'awx-demo'
|
|
awx.awx.ansible.com "awx-demo" deleted
|
|
```
|
|
|
|
Remove the operator if not needed anymore:
|
|
|
|
```sh
|
|
# Using `kustomize`
|
|
kubectl delete -k '/tmp/awx'
|
|
|
|
# Using `helm`
|
|
helm -n 'awx' uninstall 'my-awx-operator'
|
|
|
|
# Using the kustomized helm chart
|
|
kubectl kustomize --enable-helm '.' | kubectl delete -f -
|
|
```
|
|
|
|
Eventually, remove the namespace too to clean all things up:
|
|
|
|
```sh
|
|
kubectl delete ns 'awx'
|
|
```
|
|
|
|
### Testing
|
|
|
|
<details>
|
|
<summary>Run: follow the basic installation guide</summary>
|
|
|
|
[Guide][basic install]
|
|
|
|
<details style="margin-left: 1em;">
|
|
<summary>
|
|
1. ARM, Mac OS X, <code>minikube</code>, <code>kustomize</code>: failed: ARM images for AWX not available
|
|
</summary>
|
|
|
|
```sh
|
|
$ minikube start --cpus=4 --memory=6g --addons=ingress
|
|
…
|
|
🌟 Enabled addons: storage-provisioner, default-storageclass, ingress
|
|
🏄 Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default
|
|
|
|
$ mkdir -p '/tmp/awx'
|
|
$ cd '/tmp/awx'
|
|
|
|
$ # There was no ARM version of the 'kube-rbac-proxy' image upstream, so it was impossible to just use the `make deploy`
|
|
$ # command as explained in the basic install.
|
|
$ # Defaulting to use 'quay.io' as repository as the ARM version of that image is available there.
|
|
$ cat <<EOF > 'kustomization.yaml'
|
|
---
|
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
|
kind: Kustomization
|
|
namespace: awx
|
|
resources:
|
|
- github.com/ansible/awx-operator/config/default?ref=2.14.0
|
|
# https://github.com/ansible/awx-operator/releases
|
|
images:
|
|
- name: quay.io/ansible/awx-operator
|
|
newTag: 2.14.0 # same as awx-operator in resources
|
|
- name: gcr.io/kubebuilder/kube-rbac-proxy
|
|
# no ARM version upstream, defaulting to quay.io
|
|
newName: quay.io/brancz/kube-rbac-proxy
|
|
newTag: v0.16.0-arm64
|
|
EOF
|
|
$ kubectl apply -k '.'
|
|
namespace/awx created
|
|
…
|
|
deployment.apps/awx-operator-controller-manager created
|
|
$ kubectl -n 'awx' get pods
|
|
NAME READY STATUS RESTARTS AGE
|
|
awx-operator-controller-manager-8b7dfcb58-k7jt8 2/2 Running 0 3m42s
|
|
|
|
$ cat <<EOF > 'awx-demo.yaml'
|
|
---
|
|
apiVersion: awx.ansible.com/v1beta1
|
|
kind: AWX
|
|
metadata:
|
|
name: awx-demo
|
|
spec:
|
|
service_type: nodeport
|
|
EOF
|
|
$ yq -iy '.resources+=["awx-demo.yaml"]' 'kustomization.yaml'
|
|
$ kubectl apply -k '.' # this failed because awx has no ARM images yet
|
|
|
|
$ # Fine. I'll do it myself.
|
|
$ git clone 'https://github.com/ansible/awx.git'
|
|
$ cd 'awx'
|
|
$ make awx-kube-build
|
|
…
|
|
ERROR: failed to solve: process "/bin/sh -c make sdist && /var/lib/awx/venv/awx/bin/pip install dist/awx.tar.gz" did not complete successfully: exit code: 2
|
|
make: *** [awx-kube-build] Error 1
|
|
$ # (ノಠ益ಠ)ノ彡┻━┻
|
|
```
|
|
|
|
</details>
|
|
<details style="margin-left: 1em;">
|
|
<summary>2. AMD64, OpenSUSE Leap 15.5, <code>minikube</code>, <code>kustomize</code></summary>
|
|
|
|
```sh
|
|
$ minikube start --cpus=4 --memory=6g --addons=ingress
|
|
😄 minikube v1.29.0 on Opensuse-Leap 15.5
|
|
…
|
|
🌟 Enabled addons: storage-provisioner, default-storageclass, ingress
|
|
🏄 Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default
|
|
|
|
$ mkdir -p '/tmp/awx'
|
|
$ cd '/tmp/awx'
|
|
|
|
$ # Simulating the need to use a custom repository for the sake of testing, so I cannot just use the `make deploy`
|
|
$ # command as explained in the basic install.
|
|
$ # In this case, the repository will be 'quay.io'.
|
|
$ cat <<EOF > 'kustomization.yaml'
|
|
---
|
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
|
kind: Kustomization
|
|
namespace: awx
|
|
resources:
|
|
- github.com/ansible/awx-operator/config/default?ref=2.14.0
|
|
# https://github.com/ansible/awx-operator/releases
|
|
images:
|
|
- name: quay.io/ansible/awx-operator
|
|
newTag: 2.14.0 # same as awx-operator in resources
|
|
EOF
|
|
$ minikube kubectl -- apply -k '.'
|
|
namespace/awx created
|
|
…
|
|
deployment.apps/awx-operator-controller-manager created
|
|
$ minikube kubectl -- -n 'awx' get pods
|
|
NAME READY STATUS RESTARTS AGE
|
|
awx-operator-controller-manager-75b667b745-hjfc7 2/2 Running 0 3m43s
|
|
|
|
$ cat <<EOF > 'awx-demo.yaml'
|
|
---
|
|
apiVersion: awx.ansible.com/v1beta1
|
|
kind: AWX
|
|
metadata:
|
|
name: awx-demo
|
|
spec:
|
|
service_type: nodeport
|
|
EOF
|
|
$ yq -iy '.resources+=["awx-demo.yaml"]' 'kustomization.yaml'
|
|
$ minikube kubectl -- apply -k '.'
|
|
serviceaccount/awx-operator-controller-manager unchanged
|
|
…
|
|
deployment.apps/awx-operator-controller-manager unchanged
|
|
awx.awx.ansible.com/awx-demo created
|
|
$ minikube kubectl -- -n 'awx' get podsminikube kubectl -- -n 'awx' get pods
|
|
NAME READY STATUS RESTARTS AGE
|
|
awx-demo-migration-24.1.0-kqxcj 0/1 Completed 0 9s
|
|
awx-demo-postgres-15-0 1/1 Running 0 61s
|
|
awx-demo-task-7fcbb46c5d-ckf9d 4/4 Running 0 48s
|
|
awx-demo-web-58668794c8-rfd7d 3/3 Running 0 49s
|
|
awx-operator-controller-manager-75b667b745-hjfc7 2/2 Running 0 93s
|
|
|
|
$ # Default user is 'admin'.
|
|
$ minikube kubectl -- -n 'awx' get secret 'awx-demo-admin-password' -o jsonpath="{.data.password}" | base64 --decode
|
|
L2ZUgNTwtswVW3gtficG1Hd443l3Kicq
|
|
$ xdg-open $(minikube service -n 'awx' 'awx-demo-service' --url)
|
|
|
|
$ minikube kubectl -- delete -k '.'
|
|
```
|
|
|
|
</details><br/>
|
|
</details>
|
|
|
|
<details>
|
|
<summary>Run: follow the helm installation guide</summary>
|
|
|
|
[Guide][helm install on existing cluster]
|
|
|
|
<details style="margin-left: 1em;">
|
|
<summary>1. AMD64, OpenSUSE Leap 15.5, <code>minikube</code>, <code>helm</code></summary>
|
|
|
|
```sh
|
|
$ minikube start --cpus=4 --memory=6g --addons=ingress
|
|
😄 minikube v1.29.0 on Opensuse-Leap 15.5
|
|
…
|
|
🌟 Enabled addons: storage-provisioner, default-storageclass, ingress
|
|
🏄 Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default
|
|
|
|
$ helm repo add 'awx-operator' 'https://ansible.github.io/awx-operator/'
|
|
"awx-operator" has been added to your repositories
|
|
$ helm repo update 'awx-operator'
|
|
Hang tight while we grab the latest from your chart repositories...
|
|
...Successfully got an update from the "awx-operator" chart repository
|
|
Update Complete. ⎈Happy Helming!⎈
|
|
|
|
$ helm search repo 'awx-operator'
|
|
NAME CHART VERSION APP VERSION DESCRIPTION
|
|
awx-operator/awx-operator 2.14.0 2.14.0 A Helm chart for the AWX Operator
|
|
|
|
$ helm -n 'awx' upgrade -i --create-namespace 'my-awx-operator' 'awx-operator/awx-operator' --version '2.14.0'
|
|
Release "my-awx-operator" does not exist. Installing it now.
|
|
NAME: my-awx-operator
|
|
LAST DEPLOYED: Mon Apr 8 15:34:00 2024
|
|
NAMESPACE: awx
|
|
STATUS: deployed
|
|
REVISION: 1
|
|
TEST SUITE: None
|
|
NOTES:
|
|
AWX Operator installed with Helm Chart version 2.14.0
|
|
$ minikube kubectl -- -n 'awx' get pods
|
|
NAME READY STATUS RESTARTS AGE
|
|
awx-operator-controller-manager-8b7dfcb58-k7jt8 2/2 Running 0 3m
|
|
|
|
$ helm -n 'awx' upgrade -i --create-namespace 'my-awx-operator' 'awx-operator/awx-operator' --version '2.14.0' \
|
|
--set 'AWX.enabled=true' --set 'AWX.name=awx-demo'
|
|
Release "my-awx-operator" has been upgraded. Happy Helming!
|
|
NAME: my-awx-operator
|
|
LAST DEPLOYED: Mon Apr 8 15:37:47 2024
|
|
NAMESPACE: awx
|
|
STATUS: deployed
|
|
REVISION: 2
|
|
TEST SUITE: None
|
|
NOTES:
|
|
AWX Operator installed with Helm Chart version 2.14.0
|
|
$ minikube kubectl -- -n 'awx' get pods
|
|
NAME READY STATUS RESTARTS AGE
|
|
awx-demo-migration-24.1.0-qhbq2 0/1 Completed 0 12m
|
|
awx-demo-postgres-15-0 1/1 Running 0 13m
|
|
awx-demo-task-87756dfbc-chx9t 4/4 Running 0 12m
|
|
awx-demo-web-69d6d5d6c-wdxlv 3/3 Running 0 12m
|
|
awx-operator-controller-manager-8b7dfcb58-k7jt8 2/2 Running 0 17m
|
|
|
|
$ # Default user is 'admin'.
|
|
$ minikube kubectl -- -n 'awx' get secret 'awx-demo-admin-password' -o jsonpath="{.data.password}" | base64 --decode
|
|
PoU9pFR2J5oFqymgX9I3I8swFgfZVkam
|
|
$ xdg-open $(minikube service -n 'awx' 'awx-demo-service' --url)
|
|
|
|
$ helm -n 'awx' uninstall 'my-awx-operator'
|
|
$ minikube kubectl -- delete ns 'awx'
|
|
```
|
|
|
|
</details><br/>
|
|
</details>
|
|
|
|
<details>
|
|
<summary>Run: kustomized helm chart</summary>
|
|
|
|
> [!warning]
|
|
> Remember to include the CRDs from the helm chart.
|
|
|
|
<details style="margin-left: 1em">
|
|
<summary>1. AMD64, OpenSUSE Leap 15.5, <code>minikube</code></summary>
|
|
|
|
```sh
|
|
$ minikube start --cpus=4 --memory=6g --addons=ingress
|
|
😄 minikube v1.29.0 on Opensuse-Leap 15.5
|
|
…
|
|
🌟 Enabled addons: storage-provisioner, default-storageclass, ingress
|
|
🏄 Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default
|
|
|
|
$ mkdir -p '/tmp/awx'
|
|
$ cd '/tmp/awx'
|
|
|
|
$ cat <<EOF > 'namespace.yaml'
|
|
---
|
|
apiVersion: v1
|
|
kind: Namespace
|
|
metadata:
|
|
name: awx
|
|
EOF
|
|
$ cat <<EOF > 'kustomization.yaml'
|
|
---
|
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
|
kind: Kustomization
|
|
namespace: awx
|
|
resources:
|
|
- namespace.yaml
|
|
helmCharts:
|
|
- name: awx-operator
|
|
repo: https://ansible.github.io/awx-operator/
|
|
version: 2.14.0
|
|
releaseName: awx-operator
|
|
includeCRDs: true
|
|
EOF
|
|
$ minikube kubectl -- apply -f <(minikube kubectl -- kustomize --enable-helm)
|
|
namespace/awx created
|
|
customresourcedefinition.apiextensions.k8s.io/awxbackups.awx.ansible.com created
|
|
…
|
|
deployment.apps/awx-operator-controller-manager created
|
|
$ minikube kubectl -- -n 'awx' get pods
|
|
NAME READY STATUS RESTARTS AGE
|
|
awx-operator-controller-manager-787d4945fb-fdffx 2/2 Running 0 3m36s
|
|
|
|
$ cat <<EOF > 'awx-demo.yaml'
|
|
---
|
|
apiVersion: awx.ansible.com/v1beta1
|
|
kind: AWX
|
|
metadata:
|
|
name: awx-demo
|
|
spec:
|
|
service_type: nodeport
|
|
EOF
|
|
$ yq -iy '.resources+=["awx-demo.yaml"]' 'kustomization.yaml'
|
|
$ minikube kubectl -- apply -f <(minikube kubectl -- kustomize --enable-helm)
|
|
namespace/awx unchanged
|
|
…
|
|
deployment.apps/awx-operator-controller-manager unchanged
|
|
awx.awx.ansible.com/awx-demo created
|
|
$ minikube kubectl -- -n 'awx' get pods
|
|
NAME READY STATUS RESTARTS AGE
|
|
awx-demo-migration-24.1.0-zwv8w 0/1 Completed 0 115s
|
|
awx-demo-postgres-15-0 1/1 Running 0 10m
|
|
awx-demo-task-9c4655cb9-cmz87 4/4 Running 0 8m3s
|
|
awx-demo-web-77f65cc65f-qhqrm 3/3 Running 0 8m4s
|
|
awx-operator-controller-manager-787d4945fb-fdffx 2/2 Running 0 14m
|
|
|
|
$ # Default user is 'admin'.
|
|
$ minikube kubectl -- -n 'awx' get secret 'awx-demo-admin-password' -o jsonpath="{.data.password}" | base64 --decode
|
|
DgHIaA9onZj106osEmvECigzsBqutHqI
|
|
$ xdg-open $(minikube service -n 'awx' 'awx-demo-service' --url)
|
|
|
|
$ minikube kubectl -- delete -f <(minikube kubectl -- kustomize --enable-helm)
|
|
```
|
|
|
|
</details>
|
|
|
|
<details style="margin-left: 1em">
|
|
<summary>1. AMD64, Mac OS X, EKS</summary>
|
|
|
|
```sh
|
|
$ mkdir -p '/tmp/awx'
|
|
$ cd '/tmp/awx'
|
|
|
|
$ cat <<EOF > 'namespace.yaml'
|
|
---
|
|
apiVersion: v1
|
|
kind: Namespace
|
|
metadata:
|
|
name: awx
|
|
EOF
|
|
$ cat <<EOF > 'kustomization.yaml'
|
|
---
|
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
|
kind: Kustomization
|
|
namespace: awx
|
|
resources:
|
|
- namespace.yaml
|
|
helmCharts:
|
|
- name: awx-operator
|
|
repo: https://ansible.github.io/awx-operator/
|
|
version: 2.19.1
|
|
releaseName: awx-operator
|
|
includeCRDs: true
|
|
EOF
|
|
$ kubectl kustomize --enable-helm | kubectl apply -f -
|
|
namespace/awx created
|
|
…
|
|
deployment.apps/awx-operator-controller-manager created
|
|
$ kubectl get pods -n 'awx'
|
|
NAME READY STATUS RESTARTS AGE
|
|
awx-operator-controller-manager-3361cfab38-tdgt3 2/2 Running 0 13s
|
|
|
|
$ cat <<EOF > 'awx-demo.yaml'
|
|
---
|
|
apiVersion: awx.ansible.com/v1beta1
|
|
kind: AWX
|
|
metadata:
|
|
name: awx-demo
|
|
spec:
|
|
admin_email: me@example.org
|
|
no_log: false
|
|
node_selector: |
|
|
kubernetes.io/arch: amd64
|
|
service_type: LoadBalancer
|
|
ingress_type: ingress
|
|
ingress_annotations: |
|
|
kubernetes.io/ingress.class: alb
|
|
EOF
|
|
$ yq -iy '.resources+=["awx-demo.yaml"]' 'kustomization.yaml'
|
|
$ kubectl kustomize --enable-helm | kubectl apply -f -
|
|
namespace/awx unchanged
|
|
…
|
|
deployment.apps/awx-operator-controller-manager unchanged
|
|
awx.awx.ansible.com/awx-demo created
|
|
$ kubectl -n 'awx' get pods
|
|
NAME READY STATUS RESTARTS AGE
|
|
awx-demo-migration-24.1.0-zwv8w 0/1 Completed 0 115s
|
|
awx-demo-postgres-15-0 1/1 Running 0 10m
|
|
awx-demo-task-8e34efc56-w5rc5 4/4 Running 0 8m3s
|
|
awx-demo-web-545gbdgg7b-q2q4m 3/3 Running 0 8m4s
|
|
awx-operator-controller-manager-3361cfab38-tdgt3 2/2 Running 0 14m
|
|
|
|
$ # Default user is 'admin'.
|
|
$ kubectl -n 'awx' get secret 'awx-demo-admin-password' -o jsonpath="{.data.password}" | base64 --decode
|
|
IDwYOgL9k2ckaXmqMm6PT4d6TXdJcocd
|
|
$ kubectl -n 'awx' get ingress 'awx-demo-ingress' -o jsonpath='{.status.loadBalancer.ingress[*].hostname}' \
|
|
| xargs -I{} open http://{}
|
|
|
|
$ kubectl kustomize --enable-helm | kubectl delete -f -
|
|
namespace "awx" deleted
|
|
…
|
|
awx.awx.ansible.com "awx-demo" deleted
|
|
deployment.apps "awx-operator-controller-manager" deleted
|
|
```
|
|
|
|
</details>
|
|
</details>
|
|
|
|
### Executing jobs
|
|
|
|
Unless explicitly defined in Job Templates, Schedules, or other resources that allow specifying the `instance_groups`
|
|
key, Jobs using a containerized execution environment will execute in the _default_ container group.
|
|
|
|
Normally, the _default_ container group does **not** limit where a Job's pod is executed, **nor** limits its assigned
|
|
resources.<br/>
|
|
By explicitly configuring this container group, one can change the settings for Jobs that do not ask for custom
|
|
executors.<br/>
|
|
E.g., one could set affinity and tolerations to assign Jobs to specific nodes by default, and set specific default
|
|
resource limits.
|
|
|
|
<details style='padding: 0 0 1rem 1rem'>
|
|
|
|
```yaml
|
|
# ansible playbook
|
|
- name: Configure instance group 'default'
|
|
tags: configure_instance_group_default_spot
|
|
awx.awx.instance_group:
|
|
name: default
|
|
is_container_group: true
|
|
pod_spec_override: |-
|
|
apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
namespace: awx
|
|
spec:
|
|
serviceAccountName: default
|
|
automountServiceAccountToken: false
|
|
containers:
|
|
- image: 012345678901.dkr.ecr.eu-west-1.amazonaws.com/infrastructure/awx-ee:latest
|
|
name: worker
|
|
args:
|
|
- ansible-runner
|
|
- worker
|
|
- '--private-data-dir=/runner'
|
|
resources:
|
|
requests:
|
|
cpu: 250m
|
|
memory: 100Mi
|
|
limits:
|
|
cpu: 1830m
|
|
memory: 1425Mi
|
|
tolerations:
|
|
- key: example.org/reservation.app
|
|
operator: Equal
|
|
value: awx
|
|
effect: NoSchedule
|
|
- key: awx.example.org/reservation.component
|
|
operator: Equal
|
|
value: job
|
|
effect: NoSchedule
|
|
affinity:
|
|
nodeAffinity:
|
|
requiredDuringSchedulingIgnoredDuringExecution:
|
|
nodeSelectorTerms:
|
|
- matchExpressions:
|
|
- key: example.org/reservation.app
|
|
operator: In
|
|
values:
|
|
- awx
|
|
- key: awx.example.org/reservation.component
|
|
operator: In
|
|
values:
|
|
- job
|
|
preferredDuringSchedulingIgnoredDuringExecution:
|
|
- weight: 1
|
|
preference:
|
|
matchExpressions:
|
|
- key: awx/component
|
|
- key: eks.amazonaws.com/capacityType
|
|
operator: In
|
|
values:
|
|
- SPOT
|
|
- name: Configure instance group 'ondemand'
|
|
tags: configure instance_group_ondemand
|
|
awx.awx.instance_group:
|
|
name: ondemand
|
|
is_container_group: true
|
|
pod_spec_override: |-
|
|
apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
namespace: awx
|
|
spec:
|
|
serviceAccountName: default
|
|
automountServiceAccountToken: false
|
|
containers:
|
|
- image: 012345678901.dkr.ecr.eu-west-1.amazonaws.com/infrastructure/awx-ee:latest
|
|
name: worker
|
|
args:
|
|
- ansible-runner
|
|
- worker
|
|
- '--private-data-dir=/runner'
|
|
resources:
|
|
requests:
|
|
cpu: 250m
|
|
memory: 100Mi
|
|
limits:
|
|
cpu: 1830m
|
|
memory: 1425Mi
|
|
tolerations:
|
|
- key: example.org/reservation.app
|
|
operator: Equal
|
|
value: awx
|
|
effect: NoSchedule
|
|
- key: awx.example.org/reservation.component
|
|
operator: Equal
|
|
value: job
|
|
effect: NoSchedule
|
|
affinity:
|
|
nodeAffinity:
|
|
requiredDuringSchedulingIgnoredDuringExecution:
|
|
nodeSelectorTerms:
|
|
- matchExpressions:
|
|
- key: example.org/reservation.app
|
|
operator: In
|
|
values:
|
|
- awx
|
|
- key: awx.example.org/reservation.component
|
|
operator: In
|
|
values:
|
|
- job
|
|
- key: eks.amazonaws.com/capacityType
|
|
operator: In
|
|
values:
|
|
- ON_DEMAND
|
|
```
|
|
|
|
</details>
|
|
|
|
## Attribute inheritance and overriding
|
|
|
|
Some AWX-specific resources allow configuring similar attributes.<br/>
|
|
E.g., Schedules, Workflow Job Template Nodes and Job Templates all define `diff_mode`, `job_type`, and other properties.
|
|
|
|
This is usually true for resource types that can reference another resource type.<br/>
|
|
It is meant to allow _parent_ resource to override properties of their _child_ through hierarchical inheritance.<br/>
|
|
E.g.:
|
|
|
|
- Schedules and Workflow Job Template Nodes can both reference Job Templates via the `unified_job_template` key.
|
|
- Schedules and Workflow Job Template Nodes specifying attributes like `diff_mode` or `job_type` will override the
|
|
attribute of the same name specified by the Job Templates they reference.
|
|
|
|
<details style='padding: 0 0 1rem 1rem'>
|
|
|
|
Scheduled Jobs' attributes can override referenced Job Templates properties:
|
|
|
|
```yml
|
|
- awx.awx.job_template:
|
|
organization: ExampleOrg
|
|
name: Some job
|
|
…
|
|
inventory: EC2 instances by Instance ID
|
|
execution_environment: ExampleOrg-EE
|
|
credentials:
|
|
- SSM User # required to use SSM
|
|
- AWX Central Key # required to 'become' in tasks
|
|
project: Some project
|
|
playbook: some_playbook.yml
|
|
job_type: check
|
|
verbosity: 3
|
|
diff_mode: true
|
|
- awx.awx.schedule:
|
|
organization: ExampleOrg
|
|
unified_job_template: Some Job
|
|
enabled: true
|
|
…
|
|
job_type: run # spawned jobs override the job template's "job_type" property
|
|
verbosity: 0 # spawned jobs override the job template's "verbosity" property
|
|
diff_mode: false # spawned jobs override the job template's "diff_mode" property
|
|
```
|
|
|
|
```mermaid
|
|
flowchart LR
|
|
job_template("Job Template")
|
|
schedule("Schedule")
|
|
|
|
schedule --> job_template
|
|
```
|
|
|
|
</details>
|
|
|
|
This effect is applied recursively to the full reference chain.
|
|
|
|
<details style='padding: 0 0 1rem 1rem'>
|
|
|
|
Scheduled Jobs' attributes can override referenced Workflow Job Templates' properties, which are propagated to the Job
|
|
Templates used by its Nodes:
|
|
|
|
```yml
|
|
- awx.awx.job_template:
|
|
organization: ExampleOrg
|
|
name: Some job
|
|
…
|
|
inventory: EC2 instances by Instance ID
|
|
execution_environment: ExampleOrg-EE
|
|
credentials:
|
|
- SSM User # required to use SSM
|
|
- AWX Central Key # required to 'become' in tasks
|
|
project: Some project
|
|
playbook: some_playbook.yml
|
|
job_type: check
|
|
verbosity: 3
|
|
diff_mode: true
|
|
- awx.awx.workflow_job_template:
|
|
organization: ExampleOrg
|
|
name: Some workflow
|
|
…
|
|
- awx.awx.workflow_job_template_node:
|
|
workflow_job_template: Some workflow
|
|
unified_job_template: Some job
|
|
…
|
|
job_type: check # spawned jobs override the job template's "job_type" property
|
|
verbosity: 3 # spawned jobs override the job template's "verbosity" property
|
|
diff_mode: true # spawned jobs override the job template's "diff_mode" property
|
|
- awx.awx.schedule:
|
|
organization: ExampleOrg
|
|
unified_job_template: Some workflow
|
|
enabled: true
|
|
…
|
|
job_type: run # spawned workflows override the node's "job_type" property
|
|
verbosity: 0 # spawned workflows override the node's "verbosity" property
|
|
diff_mode: false # spawned workflows override the node's "diff_mode" property
|
|
```
|
|
|
|
```mermaid
|
|
flowchart LR
|
|
job_template("Job Template")
|
|
workflow_job_template("Workflow Job Template")
|
|
workflow_node("Workflow Node")
|
|
schedule("Schedule")
|
|
|
|
schedule --> workflow_job_template --> workflow_node --> job_template
|
|
```
|
|
|
|
</details>
|
|
|
|
### Variables inheritance and overriding
|
|
|
|
Variables inheritance works in a similar fashion to [Attribute inheritance and overriding], but is specific to the
|
|
`extra_vars` key (A.K.A. _prompts_ in the Web UI).
|
|
|
|
Also see [Extra variables].
|
|
|
|
Variables defined in parent AWX resources recursively override those defined in children AWX resources **and**, by
|
|
extension, Ansible resources (playbooks, blocks, tasks, etc).<br/>
|
|
Variables defined in ancestors **cannot** be overridden by any of the children in the chain, **nor are affected by any
|
|
Ansible module or component** during playbook execution.<br/>
|
|
The result is effectively as if they were passed down with the `--extra-vars` CLI option. Refer [Ansible variables].
|
|
|
|
> [!warning]
|
|
> Once a variable is defined in a Job Template or parent resources, it **will** be passed to the Ansible command during
|
|
> Job execution, even if its value is set to `null` (it will just be an empty string).<br/>
|
|
> This also means the values configured in children resources can **at most** be overridden, but **never deleted**.
|
|
|
|
This limitation is enforced to try and ensure predictable behavior, with higher-level configurations remaining
|
|
consistent across the whole execution chain.
|
|
|
|
> [!warning]
|
|
> The AWX API has a specific restriction that does **not** consider nullified values for extra variables in resources
|
|
> that allow their definition.<br/>
|
|
> If a resource does not specify a variable with a value, that variable should just **not** be provided in the payload.
|
|
|
|
## Elevating privileges in tasks
|
|
|
|
AWX requires one to configure specific settings throughout its resources in order to be able to successfully use
|
|
`become` and privileges-related keys in playbooks.
|
|
|
|
1. The playbook must be configured to elevate privileges as per normal Ansible operations.
|
|
|
|
<details style='padding: 0 0 1rem 1rem'>
|
|
|
|
```yml
|
|
- name: Do something by escalating privileges
|
|
hosts: all
|
|
become: true
|
|
tasks: []
|
|
```
|
|
|
|
</details>
|
|
|
|
1. The Job Template referencing the playbook must have the _Privilege Escalation_ option **enabled**.
|
|
|
|
<details style='padding: 0 0 1rem 1rem'>
|
|
|
|
This corresponds to providing the `--become` flag when running the playbook.
|
|
|
|
</details>
|
|
|
|
1. The Credential used in the Job (either in the Job Template or whatever overrides them) must specify a user that is
|
|
able to run `sudo` (or whatever `become_method` the playbook uses).
|
|
|
|
> [!important]
|
|
> Should the `become_method` require a password, one must also supply that password in the Credential.
|
|
|
|
## Workflow automation
|
|
|
|
Refer [How to use workflow job templates in Ansible], [Workflow job templates] and [Workflows].<br/>
|
|
Also see [Passing Ansible variables in Workflows using set_stats].
|
|
|
|
_Workflow Job Templates_ coordinate the linking and execution of multiple resources by:
|
|
|
|
- Synchronizing repositories with code for Projects.
|
|
- Synchronize Inventories.
|
|
- Having different Jobs run sequentially or in parallel.
|
|
- Running Jobs based on the success or failure of one or more previous Jobs.
|
|
- Requesting an admin's approval to proceed with one or more executions.
|
|
|
|
Workflow Job Templates define their every action as a _Node_ resource.
|
|
|
|
<details style='padding: 0 0 1rem 1rem'>
|
|
<summary>Creation process</summary>
|
|
|
|
```mermaid
|
|
flowchart LR
|
|
job_template("Job Template")
|
|
playbook("Playbook")
|
|
project("Project")
|
|
workflow_job_template("Workflow Job Template")
|
|
workflow_node("Workflow Node")
|
|
schedule("Schedule")
|
|
|
|
playbook --> project --> job_template --> workflow_node --> workflow_job_template --> schedule
|
|
```
|
|
|
|
All the playbooks used in the workflow must be visible to AWX, meaning that one or more projects containing them must be
|
|
already configured in the instance.
|
|
|
|
Workflows need nodes to refer. Nodes reference a job template, which in turn refer a playbook to run.
|
|
|
|
The AWX UI does not allow creating nodes directly, but it can be done via the visualizer.
|
|
|
|
1. Open _Resources_ > _Templates_ in the sidebar.
|
|
1. Click on the _Add_ button and choose _Add job template_ to add every job template that is needed.<br/>
|
|
Repeat as required.
|
|
1. Click on the _Add_ button and choose _Add workflow template_.
|
|
1. Fill in the form with the resources all nodes should share, and _save_.<br/>
|
|
The visualizer will open.
|
|
1. In the visualizer, create the needed nodes.
|
|
|
|
</details>
|
|
|
|
When creating nodes via the `awx.awx.workflow_job_template_node` module, nodes link by referencing the **next** step in
|
|
the workflow.<br/>
|
|
As such, Nodes must be defined **last-to-first** in playbooks.
|
|
|
|
<details style='padding: 0 0 1rem 1rem'>
|
|
|
|
```yml
|
|
- awx.awx.workflow_job_template_node:
|
|
workflow_job_template: Some workflow
|
|
identifier: Next action
|
|
…
|
|
- awx.awx.workflow_job_template_node:
|
|
workflow_job_template: Some workflow
|
|
identifier: Previous action
|
|
…
|
|
success_nodes:
|
|
- Next action
|
|
```
|
|
|
|
</details>
|
|
|
|
When needing to use specific variables only in some Nodes within a workflow, consider:
|
|
|
|
1. Specifying those variable **only in the Nodes** that require them, and **not** at the Workflow Job Template's
|
|
level.<br/>
|
|
This prevents them to the overridden by values set at the Workflow Job Template's level.
|
|
|
|
<details style='padding: 0 0 1rem 1rem'>
|
|
|
|
Workflow Job Template:
|
|
|
|
```diff
|
|
-assume_role_arn: 'arn:aws:iam::012345678901:role/PowerfulRole'
|
|
```
|
|
|
|
Node:
|
|
|
|
```diff
|
|
+assume_role_arn: 'arn:aws:iam::012345678901:role/PowerfulRole'
|
|
rds_db_instance_identifier: some-db-to-create
|
|
```
|
|
|
|
</details>
|
|
|
|
1. Designing playbooks to handle variables' presence using Ansible's conditionals, defaults, and facts by using play- or
|
|
task-specific variables, and populating them with the input from workflows.
|
|
|
|
<details style='padding: 0 0 1rem 1rem'>
|
|
|
|
```yml
|
|
- hosts: all
|
|
vars:
|
|
playbook__assume_role_arn: "{{ role_arn }}"
|
|
tasks:
|
|
- vars:
|
|
do_something__rds_instance_identifier: "{{ rds_instance_identifier }}"
|
|
amazon.aws.rds_instance: …
|
|
```
|
|
|
|
Alternatively, enabling jinja evaluation at any level, then using jinja expressions to populate nodes' extra vars for
|
|
differently named variables.<br/>
|
|
This is especially useful when [passing data between Nodes][pass data between workflow nodes].
|
|
|
|
<details style='padding: 0 0 1rem 1rem'>
|
|
|
|
Node's `extra_vars`:
|
|
|
|
```yml
|
|
do_something__rds_instance_identifier: "{{ rds_instance_identifier }}"
|
|
```
|
|
|
|
</details>
|
|
|
|
1. Using separate Workflow Job Templates altogether, when fundamentally different variable sets are needed.
|
|
|
|
### Pass data between workflow Nodes
|
|
|
|
Refer [Passing Ansible variables in Workflows using set_stats].
|
|
|
|
Leverage the [`set_stats` builtin module][ansible.builtin.set_stats module].
|
|
|
|
> [!important]
|
|
> The artifact system requires Ansible >= v2.2.1.0-0.3.rc3 and the default `set_stats` parameters `per_host: false`
|
|
> to work correctly with AWX.
|
|
|
|
When using `set_stats` in a workflow, AWX saves the pairs configured in the module's `data` parameter as artifact.<br/>
|
|
The workflow system implements _cumulative_ artifact inheritance, where artifacts flow down through the workflow graph.
|
|
Artifacts are available to **all** the nodes that are descendants of the one that created it, and **not** only to the
|
|
node that immediately follows in the flow.
|
|
|
|
<details style='padding: 0 0 1rem 1rem'>
|
|
|
|
1. When any job uses `set_stats`, AWX stores pairs in the module's `data` parameter as artifacts.<br/>
|
|
**All** artifacts become available to **all descendant** nodes in the workflow.
|
|
|
|
I.E: suppose having a workflow like follows:
|
|
|
|
```plaintext
|
|
Node A* → Node B* → Node C
|
|
↘ Node D
|
|
|
|
* = creates artifacts
|
|
```
|
|
|
|
Both `Node C` and `Node D` will receive the artifacts created by `Node A`, but only `Node C` will **also** receive
|
|
any artifacts created by `Node B`.
|
|
|
|
1. Child nodes of the workflow receive the **cumulative** artifacts from **all** their ancestor nodes, with the
|
|
specific rule that **children's artifacts overwrite parent's ones**.
|
|
|
|
I.E.: suppose having a workflow which path is _Grandparent_ → _Parent_ → _Child_, where both Grandparent and Parent
|
|
generate artifact.<br/>
|
|
Parent's artifacts **will overwrite any conflicting keys** from Grandparent when passed to the Child node.
|
|
|
|
</details>
|
|
|
|
> [!warning]
|
|
> Artifacts are passed as `extra_vars` to subsequent nodes.<br/>
|
|
> This gives them higher precedence than the job template's default variables.
|
|
|
|
<details>
|
|
<summary>Example</summary>
|
|
|
|
Considering a workflow where Node1 needs to pass data to Node2:
|
|
|
|
1. Playbook for Node1:
|
|
|
|
```yml
|
|
---
|
|
- name: Get an AWS S3 object's information and pass them along
|
|
hosts: [ … ]
|
|
tasks: [ … ]
|
|
post_tasks:
|
|
- name: Pass the S3 object's information along when found
|
|
tags:
|
|
- always # important if one plans to test workflows by leveraging tags
|
|
- pass_data_along
|
|
when: s3_object_info is defined
|
|
ansible.builtin.set_stats:
|
|
data:
|
|
s3_object_info: "{{ s3_object_info }}"
|
|
```
|
|
|
|
1. Playbook for Node2:
|
|
|
|
```yml
|
|
---
|
|
- name: Do something knowing an AWS S3 object exists because it got passed along
|
|
hosts: [ … ]
|
|
pre_tasks:
|
|
- name: Ensure the S3 object exists beforehand and is in the STANDARD storage tier
|
|
tags:
|
|
- always # important if one plans to test workflows by leveraging tags
|
|
- ensure_s3_object_is_usable
|
|
ansible.builtin.assert:
|
|
that:
|
|
- s3_object_info.object_data.content_length | default(0) > 0
|
|
- s3_object_info.object_data.storage_class | default('') == 'STANDARD'
|
|
tasks: [ … ]
|
|
```
|
|
|
|
</details>
|
|
|
|
## API
|
|
|
|
Refer [AWX API Reference] and [How to use AWX REST API to execute jobs].
|
|
|
|
AWX offers the `awx` client CLI tool:
|
|
|
|
```sh
|
|
# Install the 'awx' client
|
|
# As of 2025-07-28, Python 3.11 is the last Python version for which the AWX CLI works correctly.
|
|
pipx install --python '3.11' 'awxkit'
|
|
pip3.11 install --user 'awxkit'
|
|
```
|
|
|
|
> [!tip]
|
|
> Normally `awx` would require setting the configuration every command like so:
|
|
>
|
|
> ```sh
|
|
> awx --conf.host https://awx.example.org --conf.username 'admin' --conf.password 'password' config
|
|
> awx --conf.host https://awx.example.org --conf.username 'admin' --conf.password 'password' export --schedules
|
|
> ```
|
|
>
|
|
> Export settings to environment variables to avoid having to set them on the command line all the time:
|
|
>
|
|
> ```sh
|
|
> export TOWER_HOST='https://awx.example.org' TOWER_USERNAME='admin' TOWER_PASSWORD='password'
|
|
> ```
|
|
|
|
```sh
|
|
# Show the client's configuration
|
|
awx config
|
|
|
|
# List all available endpoints
|
|
curl -fs --user 'admin:password' 'https://awx.example.org/api/v2/' | jq '.' -
|
|
|
|
# List instance groups
|
|
awx instance_groups list
|
|
|
|
# Show instance groups
|
|
awx instance_groups get 'default'
|
|
|
|
# List jobs
|
|
awx jobs list
|
|
awx jobs list -f 'yaml'
|
|
awx jobs list -f 'human' --filter 'name,created,status'
|
|
awx jobs list -f 'jq' --filter '.results[] | .name + " is " + .status'
|
|
|
|
# Show job templates
|
|
awx job_templates list
|
|
curl -fs --user 'admin:password' 'https://awx.example.org/api/v2/job_templates/' | jq '.' -
|
|
awx job_templates get 'Some Job'
|
|
|
|
# Show notification templates
|
|
awx notification_templates list
|
|
curl -fs --user 'admin:password' 'https://awx.example.org/api/v2/notification_templates/' | jq '.' -
|
|
|
|
# Show schedules
|
|
awx schedules list
|
|
awx schedules --schedules 'schedule-1' 'schedule-n'
|
|
awx schedules get 'Some Schedule'
|
|
curl -fs --user 'admin:password' 'https://awx.example.org/api/v2/schedules/' | jq '.' -
|
|
|
|
# Export data
|
|
awx export
|
|
awx export --job_templates 'job-template-1' 'job-template-n' --schedules
|
|
curl -fs --user 'admin:password' 'https://awx.example.org/api/v2/export/' | jq '.' -
|
|
```
|
|
|
|
Refer [AWX Command Line Interface] for more information.
|
|
|
|
## Further readings
|
|
|
|
- [Website]
|
|
- [Ansible]
|
|
- [Kubernetes]
|
|
- [Minikube]
|
|
- [Kustomize]
|
|
- [Helm]
|
|
- [AWX Command Line Interface]
|
|
- [DeepWiki][deepwiki ansible/awx]
|
|
|
|
### Sources
|
|
|
|
- [AWX's documentation]
|
|
- [AWX's repository]
|
|
- The [Operator's documentation]
|
|
- The [Operator's repository]
|
|
- [Basic install]
|
|
- [arm64 image pulled shows amd64 as its arch]
|
|
- [Helm install on existing cluster]
|
|
- [Iterating on the installer without deploying the operator]
|
|
- [Installer role's defaults]
|
|
- [AWX API Reference]
|
|
- [How to use AWX REST API to execute jobs]
|
|
- [Automation Job isn't created with tolerations from AWX manifest]
|
|
|
|
<!--
|
|
Reference
|
|
═╬═Time══
|
|
-->
|
|
|
|
<!-- In-article sections -->
|
|
[Attribute inheritance and overriding]: #attribute-inheritance-and-overriding
|
|
[Executing Jobs]: #executing-jobs
|
|
[Gotchas]: #gotchas
|
|
[Pass data between workflow Nodes]: #pass-data-between-workflow-nodes
|
|
[Variables inheritance and overriding]: #variables-inheritance-and-overriding
|
|
|
|
<!-- Knowledge base -->
|
|
[Ansible]: ansible.md
|
|
[Ansible variables]: ansible.md#variables
|
|
[Helm]: kubernetes/helm.md
|
|
[Kubernetes]: kubernetes/README.md
|
|
[Kustomize]: kubernetes/kustomize.md
|
|
[Minikube]: kubernetes/minikube.md
|
|
|
|
<!-- Upstream -->
|
|
[ansible.builtin.set_stats module]: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/set_stats_module.html
|
|
[awx api reference]: https://ansible.readthedocs.io/projects/awx/en/latest/rest_api/
|
|
[awx command line interface]: https://docs.ansible.com/ansible-tower/latest/html/towercli/
|
|
[awx's documentation]: https://ansible.readthedocs.io/projects/awx/en/latest/
|
|
[awx's repository]: https://github.com/ansible/awx/
|
|
[basic install]: https://ansible.readthedocs.io/projects/awx-operator/en/latest/installation/basic-install.html
|
|
[Extra variables]: https://docs.redhat.com/en/documentation/red_hat_ansible_automation_platform/2.4/html/automation_controller_user_guide/controller-job-templates#controller-extra-variables
|
|
[helm install on existing cluster]: https://ansible.readthedocs.io/projects/awx-operator/en/latest/installation/helm-install-on-existing-cluster.html
|
|
[How to use workflow job templates in Ansible]: https://www.redhat.com/en/blog/ansible-workflow-job-templates
|
|
[installer role's defaults]: https://github.com/ansible/awx-operator/blob/devel/roles/installer/defaults/main.yml
|
|
[iterating on the installer without deploying the operator]: https://ansible.readthedocs.io/projects/awx-operator/en/latest/troubleshooting/debugging.html#iterating-on-the-installer-without-deploying-the-operator
|
|
[operator's documentation]: https://ansible.readthedocs.io/projects/awx-operator/en/latest/
|
|
[operator's repository]: https://github.com/ansible/awx-operator/
|
|
[Red Hat Ansible Automation Platform]: https://www.redhat.com/en/technologies/management/ansible
|
|
[website]: https://www.ansible.com/awx/
|
|
[Workflow job templates]: https://docs.redhat.com/en/documentation/red_hat_ansible_automation_platform/2.4/html/automation_controller_user_guide/controller-workflow-job-templates
|
|
[Workflows]: https://docs.ansible.com/automation-controller/4.4/html/userguide/workflows.html
|
|
|
|
<!-- Others -->
|
|
[arm64 image pulled shows amd64 as its arch]: https://github.com/brancz/kube-rbac-proxy/issues/79#issuecomment-826557647
|
|
[automation job isn't created with tolerations from awx manifest]: https://github.com/ansible/awx-operator/issues/1099#issuecomment-1298706083
|
|
[DeepWiki ansible/awx]: https://deepwiki.com/ansible/awx
|
|
[how to use awx rest api to execute jobs]: https://www.dbi-services.com/blog/how-to-use-awx-rest-api-to-execute-jobs/
|
|
[Kubernetes operator]: https://kubernetes.io/docs/concepts/extend-kubernetes/operator/
|
|
[Passing Ansible variables in Workflows using set_stats]: https://gregsowell.com/?p=7540
|