Introduction

Foreman (and its downstream Red Hat Satellite) is a lifecycle management platform for provisioning, configuring, and managing physical and virtual servers. Ansible integrates with Foreman in two key ways: using Foreman as a dynamic inventory source, and using Ansible to automate Foreman itself.

Dynamic Inventory from Foreman

Install the Collection

ansible-galaxy collection install theforeman.foreman
pip install requests

Configure Foreman Inventory

# foreman.yml (inventory plugin config)
plugin: theforeman.foreman.foreman
url: https://foreman.example.com
user: ansible_api
password: "{{ vault_foreman_password }}"
validate_certs: true

# Group hosts by these attributes
want_facts: true
want_params: true

group_prefix: foreman_

# Create groups from host attributes
keyed_groups:
  - key: foreman_hostgroup | default('ungrouped')
    prefix: hostgroup
  - key: foreman_location | default('unknown')
    prefix: location
  - key: foreman_organization | default('default')
    prefix: org
  - key: foreman_operatingsystem | default('unknown')
    prefix: os

# Compose variables
compose:
  ansible_host: foreman_ip

Test Dynamic Inventory

# List all hosts
ansible-inventory -i foreman.yml --list

# Show specific host
ansible-inventory -i foreman.yml --host webserver01

# Ping all Foreman-discovered hosts
ansible -i foreman.yml all -m ping

Manage Foreman with Ansible

Create Host Groups

---
- name: Configure Foreman host groups
  hosts: localhost
  connection: local
  collections:
    - theforeman.foreman
  vars:
    foreman_url: "https://foreman.example.com"
    foreman_user: admin
    foreman_password: "{{ vault_foreman_admin_pass }}"
  tasks:
    - name: Create organization
      theforeman.foreman.organization:
        server_url: "{{ foreman_url }}"
        username: "{{ foreman_user }}"
        password: "{{ foreman_password }}"
        name: "MyOrg"
        state: present

    - name: Create locations
      theforeman.foreman.location:
        server_url: "{{ foreman_url }}"
        username: "{{ foreman_user }}"
        password: "{{ foreman_password }}"
        name: "{{ item }}"
        organizations:
          - "MyOrg"
        state: present
      loop:
        - "DC-East"
        - "DC-West"
        - "Cloud-AWS"

    - name: Create host groups
      theforeman.foreman.hostgroup:
        server_url: "{{ foreman_url }}"
        username: "{{ foreman_user }}"
        password: "{{ foreman_password }}"
        name: "{{ item.name }}"
        organization: "MyOrg"
        location: "{{ item.location }}"
        operatingsystem: "{{ item.os }}"
        architecture: x86_64
        domain: example.com
        state: present
      loop:
        - { name: "web-servers", location: "DC-East", os: "RHEL 9" }
        - { name: "db-servers", location: "DC-East", os: "RHEL 9" }
        - { name: "k8s-workers", location: "Cloud-AWS", os: "Ubuntu 24.04" }

Content Management (Satellite)

- name: Configure Satellite content management
  hosts: localhost
  connection: local
  tasks:
    - name: Create content view
      theforeman.foreman.content_view:
        server_url: "{{ foreman_url }}"
        username: "{{ foreman_user }}"
        password: "{{ foreman_password }}"
        organization: "MyOrg"
        name: "RHEL9-Base"
        repositories:
          - name: "Red Hat Enterprise Linux 9 for x86_64 - BaseOS RPMs 9"
            product: "Red Hat Enterprise Linux for x86_64"
          - name: "Red Hat Enterprise Linux 9 for x86_64 - AppStream RPMs 9"
            product: "Red Hat Enterprise Linux for x86_64"

    - name: Publish content view
      theforeman.foreman.content_view_version:
        server_url: "{{ foreman_url }}"
        username: "{{ foreman_user }}"
        password: "{{ foreman_password }}"
        organization: "MyOrg"
        content_view: "RHEL9-Base"
        lifecycle_environments:
          - Library

    - name: Promote to Production
      theforeman.foreman.content_view_version:
        server_url: "{{ foreman_url }}"
        username: "{{ foreman_user }}"
        password: "{{ foreman_password }}"
        organization: "MyOrg"
        content_view: "RHEL9-Base"
        current_lifecycle_environment: Library
        lifecycle_environments:
          - Development
          - Production

Provision Hosts

- name: Provision new servers via Foreman
  hosts: localhost
  connection: local
  tasks:
    - name: Create host
      theforeman.foreman.host:
        server_url: "{{ foreman_url }}"
        username: "{{ foreman_user }}"
        password: "{{ foreman_password }}"
        name: "web-{{ item }}.example.com"
        organization: "MyOrg"
        location: "DC-East"
        hostgroup: "web-servers"
        compute_resource: "VMware-DC1"
        compute_profile: "2-Medium"
        provision_method: image
        image: "rhel9-golden"
        state: present
      loop: "{{ range(1, 6) | list }}"

Troubleshooting

# Test API connectivity
curl -k -u admin:password https://foreman.example.com/api/v2/hosts

# Check inventory plugin
ansible-inventory -i foreman.yml --list --output /tmp/inventory.json

# Verify collection version
ansible-galaxy collection list theforeman.foreman

Conclusion

Foreman/Satellite + Ansible creates a complete lifecycle management pipeline: provision servers through Foreman's UI or API, use Foreman's dynamic inventory to discover hosts in Ansible, and manage content views and host groups programmatically. The theforeman.foreman collection provides modules for every Foreman API endpoint.