Skip to content

Quickstart: Add Execution Nodes to AAP 2.x

Installation

Install the collection from GitHub Release:

# Option 1: Direct from GitHub Release URL
ansible-galaxy collection install \
  https://github.com/RedHatOfficial/aap-containerized-add-node/releases/download/v1.0.0/redhat_official-aap_containerized_add_node-1.0.0.tar.gz

# Option 2: Download then install
curl -LO https://github.com/RedHatOfficial/aap-containerized-add-node/releases/download/v1.0.0/redhat_official-aap_containerized_add_node-1.0.0.tar.gz
ansible-galaxy collection install redhat_official-aap_containerized_add_node-1.0.0.tar.gz

Replace v1.0.0 with the latest release from Releases.


Usage

Two installation methods available. Pick based on your network access:

Method Use When Control Host Needs
Online SSH access from control host to target nodes SSH to controller + SSH to ENs
Online + ProxyJump SSH via bastion/jumpbox SSH to jumpbox (routes to targets)
Offline No SSH to target nodes (air-gap, policy, hybrid cloud) SSH to controller only

Scope note: This collection targets containerized installer workflows. For OpenShift/operator-based execution node setup, use native AAP UI docs: AAP 2.6, AAP 2.7.


Method 1: Online Installation

Control host runs playbook that SSHes to both controller and execution nodes.

Control Host ──SSH──► Controller
             ──SSH──► Execution Node

Decision Tree

Can your EN reach the Controller directly?
│
├─ YES → Do you need one EN or multiple?
│        │
│        ├─ One EN     → Single EN
│        └─ Multiple   → Parallel ENs
│
└─ NO  → Is there a hop node between EN and Controller?
         │
         ├─ One hop    → EN via Hop
         ├─ Multiple ENs behind hop → Fan-out behind Hop
         └─ Multiple hops (DMZ layers) → Multi-hop Chain

Single EN → Controller

Controller ◄── outbound dial ── Execution Node
ansible-playbook playbooks/add_node.yml \
  -i examples/inventory-single-en.yml \
  -e aap_setup_dir=/path/to/setup

Parallel ENs → Controller

Controller ◄── outbound dial ── EN1
           ◄── outbound dial ── EN2
           ◄── outbound dial ── EN3
ansible-playbook playbooks/add_node.yml \
  -i examples/inventory-parallel-ens.yml \
  -e aap_setup_dir=/path/to/setup

EN via Hop → Controller

Controller ◄── outbound dial ── Hop ◄── outbound dial ── EN
ansible-playbook playbooks/add_node.yml \
  -i examples/inventory-en-via-hn.yml \
  -e aap_setup_dir=/path/to/setup

Fan-out behind Hop

Controller ◄── Hop ◄── EN1
               ▲
               └───── EN2

See examples/inventory-fanout-behind-hop.yml.

Multi-hop Chain

Controller ◄── Hop1 ◄── Hop2 ◄── EN

See examples/inventory-multi-hop-chain.yml.

ProxyJump / Bastion

Control host cannot SSH directly — routes through jumpbox:

Control Host ──SSH──► Jumpbox ──SSH──► Controller
                            ──SSH──► Execution Node
ansible-playbook playbooks/add_node.yml \
  -i examples/inventory-proxyjump.yml \
  -e aap_setup_dir=/path/to/setup

See examples/inventory-proxyjump.yml.

Note: SSH routes via jumpbox; receptor mesh (27199) is direct between EN and controller.

ProxyJump / Bastion

Control host cannot SSH directly — routes through jumpbox:

Control Host ──SSH──► Jumpbox ──SSH──► Controller
                            ──SSH──► Execution Node
ansible-playbook playbooks/add_node.yml \
  -i examples/inventory-proxyjump.yml \
  -e aap_setup_dir=/path/to/setup

See examples/inventory-proxyjump.yml.

Note: SSH routes via jumpbox; receptor mesh (27199) is direct between EN and controller.


Method 2: Offline Installation

Control host generates a bundle, you transfer it manually, then run locally on target.

Control Host ──SSH──► Controller
                          │
                    [Generate Bundle]
                          │
                          ▼
              offline-bundle-exec1.tar.gz
                          │
             [Transfer: USB, SFTP, etc.]
                          │
                          ▼
              Execution Node (local install)

When to Use Offline

  • No SSH from control host to execution nodes
  • Air-gapped networks
  • Hybrid cloud (controller in cloud, ENs on-prem)
  • Strict security policies prevent direct access

Step 1: Generate Bundle (on control host)

ansible-playbook playbooks/generate_bundle.yml \
  -i inventory.yml \
  -e aap_setup_dir=/path/to/setup \
  -e _target_hostname=exec1.example.com \
  -e _receptor_peers='["controller.example.com"]'

Output: offline-bundles/offline-bundle-exec1.example.com-YYYY-MM-DD.tar.gz

Step 2: Transfer Bundle

Transfer via approved secure channel (USB, SFTP, jump host, etc.).

Security: Bundle contains TLS private keys. Delete after installation.

Step 3: Install on Target Node

# On the execution node
tar -xzf offline-bundle-exec1.example.com-YYYY-MM-DD.tar.gz
cd offline-bundle-exec1.example.com-YYYY-MM-DD
sudo ansible-playbook -c local install.yml

Prerequisites for Target Node

  • RHEL 9 or 10 with valid subscription
  • podman installed
  • ansible-core installed
  • Receptor image pre-pulled:
    podman pull registry.redhat.io/ansible-automation-platform-26/receptor-rhel9:latest
    

Including Container Images

For fully air-gapped environments, include the receptor image in the bundle:

ansible-playbook playbooks/generate_bundle.yml \
  -i inventory.yml \
  -e aap_setup_dir=/path/to/setup \
  -e _target_hostname=exec1.example.com \
  -e _receptor_peers='["controller.example.com"]' \
  -e aap_add_node_bundle_include_images=true

Bundle size increases from ~50KB to ~500MB.

See OFFLINE.md for complete documentation.


After Installation (Both Methods)

  1. Wait 1-2 minutes for heartbeat
  2. Verify on controller:
    ssh controller "podman exec automation-controller-task awx-manage list_instances"
    
  3. Check Controller UI → Administration → Topology

Verify Receptor Status

# On execution node
systemctl status receptor
journalctl -u receptor -f
podman logs receptor

Node should show green with capacity=16 and recent heartbeat timestamp.


Troubleshooting

Symptom Check
No heartbeat systemctl status receptor, podman logs receptor
Connection refused Firewall allows 27199/TCP
Certificate error routable_hostname matches certificate SAN
capacity=0 Check receptor logs for permission errors

See TROUBLESHOOTING.md for detailed diagnostics.

  • TOPOLOGY.md — Peer direction, firewall matrix, topology patterns
  • OFFLINE.md — Complete offline bundle documentation
  • CONVENTIONS.md — Variable naming and collection structure