Inventory Examples¶
Complete, copy-paste ready inventory files for every topology. All examples use outbound dial (recommended, zero disruption).
Quick Reference¶
| Topology | Use Case |
|---|---|
| Single EN | Simple setup, one execution node |
| Single HN | Prep relay for future ENs |
| EN via Hop | EN cannot reach controller directly |
| Parallel ENs | Scale execution capacity |
| Fan-out behind Hop | Multiple ENs at remote site |
| Multi-hop Chain | DMZ traversal, deep segmentation |
| ProxyJump Bastion | SSH via jumpbox |
| Inbound Dial | EN cannot dial out (rare) |
| HA Controllers | Multi-controller redundancy |
Single EN Controller¶
Scenario: Simple setup, EN can reach controller directly.
┌─────────────────┐
│ Controller │
│ controller.com │◄─────────────────┐
│ [listener] │ │
└─────────────────┘ │
outbound dial
│
┌──────┴────────┐
│ Execution │
│ exec-01.com │
│ [dials out] │
└───────────────┘
[automationcontroller]
controller.example.com
[execution_nodes]
exec-01.example.com receptor_peers='["controller.example.com"]'
[all:vars]
ansible_user=ansible
aap_setup_dir=/path/to/ansible-automation-platform-containerized-setup-2.x
registry_username=your_rhn_username
registry_password=your_rhn_password
all:
vars:
ansible_user: ansible
aap_setup_dir: /path/to/ansible-automation-platform-containerized-setup-2.x
registry_username: "{{ lookup('env', 'REGISTRY_USERNAME') }}"
registry_password: "{{ lookup('env', 'REGISTRY_PASSWORD') }}"
children:
automationcontroller:
hosts:
controller.example.com:
execution_nodes:
hosts:
exec-01.example.com:
receptor_peers:
- controller.example.com
Single HN Controller¶
Scenario: Prepare relay point for future ENs.
┌─────────────────┐
│ Controller │
│ controller.com │◄─────────────────┐
│ [listener] │ │
└─────────────────┘ │
outbound dial
│
┌──────┴────────┐
│ Hop │
│ hop-01.com │
│ [dials out] │
└───────────────┘
[automationcontroller]
controller.example.com
[execution_nodes]
hop-01.example.com receptor_type=hop receptor_peers='["controller.example.com"]'
[all:vars]
ansible_user=ansible
aap_setup_dir=/path/to/ansible-automation-platform-containerized-setup-2.x
registry_username=your_rhn_username
registry_password=your_rhn_password
all:
vars:
ansible_user: ansible
aap_setup_dir: /path/to/ansible-automation-platform-containerized-setup-2.x
registry_username: "{{ lookup('env', 'REGISTRY_USERNAME') }}"
registry_password: "{{ lookup('env', 'REGISTRY_PASSWORD') }}"
children:
automationcontroller:
hosts:
controller.example.com:
execution_nodes:
hosts:
hop-01.example.com:
receptor_type: hop
receptor_peers:
- controller.example.com
EN via Hop Controller¶
Scenario: EN cannot reach controller directly (DMZ, network segmentation).
┌─────────────────┐
│ Controller │
│ controller.com │◄─────────────────┐
│ [listener] │ │
└─────────────────┘ │
outbound dial
│
┌──────┴────────┐
│ Hop │
│ hop-01.com │◄─────────────────┐
│ [listener] │ │
└───────────────┘ │
outbound dial
│
┌──────┴────────┐
│ Execution │
│ exec-01.com │
│ [dials out] │
└───────────────┘
[automationcontroller]
controller.example.com
[execution_nodes]
hop-01.example.com receptor_type=hop receptor_peers='["controller.example.com"]'
exec-01.example.com receptor_peers='["hop-01.example.com"]'
[all:vars]
ansible_user=ansible
aap_setup_dir=/path/to/ansible-automation-platform-containerized-setup-2.x
registry_username=your_rhn_username
registry_password=your_rhn_password
all:
vars:
ansible_user: ansible
aap_setup_dir: /path/to/ansible-automation-platform-containerized-setup-2.x
registry_username: "{{ lookup('env', 'REGISTRY_USERNAME') }}"
registry_password: "{{ lookup('env', 'REGISTRY_PASSWORD') }}"
children:
automationcontroller:
hosts:
controller.example.com:
execution_nodes:
hosts:
hop-01.example.com:
receptor_type: hop
receptor_peers:
- controller.example.com
exec-01.example.com:
receptor_peers:
- hop-01.example.com
Parallel ENs Controller¶
Scenario: Scale out execution capacity, all ENs reach controller.
┌─────────────────┐
┌─────────►│ Controller │◄─────────┐
│ │ controller.com │ │
│ │ [listener] │ │
│ └────────▲────────┘ │
│ │ │
outbound dial outbound dial outbound dial
│ │ │
┌──────┴──────┐ ┌──────┴──────┐ ┌──────┴──────┐
│ Execution │ │ Execution │ │ Execution │
│ exec-01.com │ │ exec-02.com │ │ exec-03.com │
│ [dials out] │ │ [dials out] │ │ [dials out] │
└─────────────┘ └─────────────┘ └─────────────┘
[automationcontroller]
controller.example.com
[execution_nodes]
exec-01.example.com receptor_peers='["controller.example.com"]'
exec-02.example.com receptor_peers='["controller.example.com"]'
exec-03.example.com receptor_peers='["controller.example.com"]'
[all:vars]
ansible_user=ansible
aap_setup_dir=/path/to/ansible-automation-platform-containerized-setup-2.x
registry_username=your_rhn_username
registry_password=your_rhn_password
all:
vars:
ansible_user: ansible
aap_setup_dir: /path/to/ansible-automation-platform-containerized-setup-2.x
registry_username: "{{ lookup('env', 'REGISTRY_USERNAME') }}"
registry_password: "{{ lookup('env', 'REGISTRY_PASSWORD') }}"
children:
automationcontroller:
hosts:
controller.example.com:
execution_nodes:
hosts:
exec-01.example.com:
receptor_peers:
- controller.example.com
exec-02.example.com:
receptor_peers:
- controller.example.com
exec-03.example.com:
receptor_peers:
- controller.example.com
Fan-out behind Hop¶
Scenario: Remote site with multiple workers behind single relay.
┌─────────────────┐
│ Controller │
│ controller.com │◄─────────────────┐
│ [listener] │ │
└─────────────────┘ │
outbound dial
│
┌──────┴────────┐
┌──────────────►│ Hop │◄──────────────┐
│ │ hop-01.com │ │
│ │ [listener] │ │
│ └───────────────┘ │
│ │
outbound dial outbound dial
│ │
┌──────┴──────┐ ┌──────┴──────┐
│ Execution │ │ Execution │
│ exec-01.com │ │ exec-02.com │
│ [dials out] │ │ [dials out] │
└─────────────┘ └─────────────┘
[automationcontroller]
controller.example.com
[execution_nodes]
hop-01.example.com receptor_type=hop receptor_peers='["controller.example.com"]'
exec-01.example.com receptor_peers='["hop-01.example.com"]'
exec-02.example.com receptor_peers='["hop-01.example.com"]'
[all:vars]
ansible_user=ansible
aap_setup_dir=/path/to/ansible-automation-platform-containerized-setup-2.x
registry_username=your_rhn_username
registry_password=your_rhn_password
all:
vars:
ansible_user: ansible
aap_setup_dir: /path/to/ansible-automation-platform-containerized-setup-2.x
registry_username: "{{ lookup('env', 'REGISTRY_USERNAME') }}"
registry_password: "{{ lookup('env', 'REGISTRY_PASSWORD') }}"
children:
automationcontroller:
hosts:
controller.example.com:
execution_nodes:
hosts:
hop-01.example.com:
receptor_type: hop
receptor_peers:
- controller.example.com
exec-01.example.com:
receptor_peers:
- hop-01.example.com
exec-02.example.com:
receptor_peers:
- hop-01.example.com
Multi-hop Chain¶
Scenario: Multi-tier network, DMZ traversal, deep segmentation.
┌─────────────────┐
│ Controller │
│ controller.com │◄─────────────────┐
│ [listener] │ │
└─────────────────┘ │
outbound dial
│
┌──────┴────────┐
│ Hop 1 │
│ hop-01.com │◄─────────────────┐
│ [listener] │ │
└───────────────┘ │
outbound dial
│
┌──────┴────────┐
│ Hop 2 │
│ hop-02.com │◄─────────────────┐
│ [listener] │ │
└───────────────┘ │
outbound dial
│
┌──────┴────────┐
│ Execution │
│ exec-01.com │
│ [dials out] │
└───────────────┘
[automationcontroller]
controller.example.com
[execution_nodes]
hop-01.example.com receptor_type=hop receptor_peers='["controller.example.com"]'
hop-02.example.com receptor_type=hop receptor_peers='["hop-01.example.com"]'
exec-01.example.com receptor_peers='["hop-02.example.com"]'
[all:vars]
ansible_user=ansible
aap_setup_dir=/path/to/ansible-automation-platform-containerized-setup-2.x
registry_username=your_rhn_username
registry_password=your_rhn_password
all:
vars:
ansible_user: ansible
aap_setup_dir: /path/to/ansible-automation-platform-containerized-setup-2.x
registry_username: "{{ lookup('env', 'REGISTRY_USERNAME') }}"
registry_password: "{{ lookup('env', 'REGISTRY_PASSWORD') }}"
children:
automationcontroller:
hosts:
controller.example.com:
execution_nodes:
hosts:
hop-01.example.com:
receptor_type: hop
receptor_peers:
- controller.example.com
hop-02.example.com:
receptor_type: hop
receptor_peers:
- hop-01.example.com
exec-01.example.com:
receptor_peers:
- hop-02.example.com
ProxyJump Bastion¶
Scenario: Control host cannot SSH directly to targets — routes through jumpbox.
┌─────────────────┐
│ Control Host │
│ (laptop/Mac) │
└────────┬────────┘
│ SSH
▼
┌─────────────────┐
│ Jumpbox │
│ bastion.example │
└────────┬────────┘
│ SSH (to both)
┌────┴────┐
│ │
▼ ▼
┌────────┐ ┌────────┐
│ Ctrl │◄─│ EN │
│listener│ │dials │
└────────┘ └────────┘
27199 (direct)
Note: SSH goes through jumpbox; receptor mesh (27199) is direct between EN and controller.
[automationcontroller]
controller.example.com ansible_ssh_common_args='-o StrictHostKeyChecking=no -o ProxyJump=ansible@bastion.example.com' ansible_python_interpreter=/usr/bin/python3
[execution_nodes]
exec-01.example.com ansible_ssh_common_args='-o StrictHostKeyChecking=no -o ProxyJump=ansible@bastion.example.com' receptor_peers='["controller.example.com"]'
[all:vars]
ansible_user=ansible
aap_setup_dir=/path/to/ansible-automation-platform-containerized-setup-2.x
registry_username=your_rhn_username
registry_password=your_rhn_password
all:
vars:
ansible_user: ansible
aap_setup_dir: /path/to/ansible-automation-platform-containerized-setup-2.x
registry_username: "{{ lookup('env', 'REGISTRY_USERNAME') }}"
registry_password: "{{ lookup('env', 'REGISTRY_PASSWORD') }}"
children:
automationcontroller:
hosts:
controller.example.com:
ansible_ssh_common_args: '-o StrictHostKeyChecking=no -o ProxyJump=ansible@bastion.example.com'
ansible_python_interpreter: /usr/bin/python3
execution_nodes:
hosts:
exec-01.example.com:
ansible_ssh_common_args: '-o StrictHostKeyChecking=no -o ProxyJump=ansible@bastion.example.com'
receptor_peers:
- controller.example.com
Inbound Dial Controller EN¶
Scenario: EN cannot dial out due to strict egress firewall. Controller initiates connection.
⚠️ WARNING: Service Disruption
Setting
aap_add_node_enable_controller_peer: truecauses:
- 5-10 second mesh disruption per node added
- Running jobs may fail if mid-execution
- Controller receptor restarts for EACH new node
Use only when: EN cannot dial out to controller (strict egress firewall)
Prefer outbound dial whenever possible.
┌─────────────────┐ ┌─────────────────┐
│ Controller │ ──TCP:27199───────> │ Execution Node │
│ (tcp-peer) │ outbound │ (tcp-listener) │
└─────────────────┘ └─────────────────┘
[automationcontroller]
controller.example.com
[execution_nodes]
exec-01.example.com routable_hostname=exec-01.example.com
exec-02.example.com routable_hostname=exec-02.example.com
[all:vars]
ansible_user=ansible
aap_setup_dir=/path/to/ansible-automation-platform-containerized-setup-2.x
registry_username=your_rhn_username
registry_password=your_rhn_password
aap_add_node_enable_controller_peer=true
all:
vars:
ansible_user: ansible
aap_setup_dir: /path/to/ansible-automation-platform-containerized-setup-2.x
registry_username: "{{ lookup('env', 'REGISTRY_USERNAME') }}"
registry_password: "{{ lookup('env', 'REGISTRY_PASSWORD') }}"
aap_add_node_enable_controller_peer: true
children:
automationcontroller:
hosts:
controller.example.com:
execution_nodes:
hosts:
exec-01.example.com:
routable_hostname: exec-01.example.com
exec-02.example.com:
routable_hostname: exec-02.example.com
HA Controllers¶
Scenario: ENs can peer to any controller. All controllers share the same mesh CA.
[automationcontroller]
controller1.example.com
controller2.example.com
controller3.example.com
[execution_nodes]
exec-01.example.com receptor_peers='["controller1.example.com", "controller2.example.com"]'
exec-02.example.com receptor_peers='["controller1.example.com", "controller3.example.com"]'
[all:vars]
ansible_user=ansible
aap_setup_dir=/path/to/ansible-automation-platform-containerized-setup-2.x
registry_username=your_rhn_username
registry_password=your_rhn_password
all:
vars:
ansible_user: ansible
aap_setup_dir: /path/to/ansible-automation-platform-containerized-setup-2.x
registry_username: "{{ lookup('env', 'REGISTRY_USERNAME') }}"
registry_password: "{{ lookup('env', 'REGISTRY_PASSWORD') }}"
children:
automationcontroller:
hosts:
controller1.example.com:
controller2.example.com:
controller3.example.com:
execution_nodes:
hosts:
exec-01.example.com:
receptor_peers:
- controller1.example.com
- controller2.example.com
exec-02.example.com:
receptor_peers:
- controller1.example.com
- controller3.example.com
Variable Reference¶
| Variable | Scope | Default | Description |
|---|---|---|---|
receptor_peers |
Per-host | [] |
List of hostnames this node dials out to |
receptor_type |
Per-host | execution |
Node type: execution or hop |
routable_hostname |
Per-host | inventory_hostname | FQDN registered in controller (for mesh routing) |
receptor_port |
Per-host | 27199 |
Receptor listener port |
ansible_ssh_common_args |
Per-host | — | SSH options (e.g., ProxyJump) |
aap_add_node_enable_controller_peer |
Global | false |
Enable inbound dial (controller → EN) |
Key Concepts¶
| Term | Meaning |
|---|---|
[listener] |
tcp-listener on port 27199, accepts connections |
[dials out] |
tcp-peer, initiates connection to upstream |
outbound dial |
Node connects to upstream listener (default, zero disruption) |
inbound dial |
Controller connects to node (causes mesh restart) |
Next Steps¶
- Copy example closest to your topology
- Replace hostnames with your FQDNs
- Set
aap_setup_dirto your installer path - Set registry credentials (env vars or direct)
- Run preflight:
ansible-playbook playbooks/preflight.yml -i inventory.yml - Run add_node:
ansible-playbook playbooks/add_node.yml -i inventory.yml
See Topology Patterns for detailed firewall requirements and troubleshooting.