Documentation Index
Fetch the complete documentation index at: https://mintlify.com/allegro/ralph/llms.txt
Use this file to discover all available pages before exploring further.
Ralph supports integration with configuration management tools like Puppet and Ansible through its configuration path system. This allows you to automate host configuration by fetching configuration data from Ralph’s API.
Overview
Ralph provides a hierarchical configuration system that can be mapped to your configuration management tool’s structure:
- Configuration Modules - Top-level groupings (e.g., Puppet modules or Ansible roles)
- Configuration Classes - Specific configurations to apply (e.g., Puppet classes or Ansible playbooks)
- Configuration Path - Per-host configuration assignment
- Configuration Variables - Custom fields exposed as variables
Configuration Modules
Configuration modules represent the top-level organization of your configurations.
Creating Configuration Modules
- Navigate to
https://<YOUR-RALPH-URL>/assets/configurationmodule/
- Click “Add configuration module”
- Fill in the details:
- Name - Module name (e.g.,
apache, mysql, monitoring)
- Parent - Optional parent module for hierarchical organization
- Support team - Team responsible for this module
Hierarchical Structure
You can organize modules in a tree structure to reflect your directory layout:
webservices/
├── apache/
├── nginx/
└── haproxy/
databases/
├── mysql/
├── postgresql/
└── mongodb/
For Puppet users, configuration modules map directly to Puppet modules.For Ansible users, use modules to group related roles or playbooks.
Configuration Classes
Configuration classes define specific configurations to be applied to hosts.
Creating Configuration Classes
- Navigate to
https://<YOUR-RALPH-URL>/assets/configurationclass/
- Click “Add configuration class”
- Configure:
- Module - Parent configuration module
- Class name - Specific configuration name
- Path - Full path (auto-generated from module hierarchy)
Assigning Configuration to Hosts
Assign configuration to assets using the configuration_path field:
- Edit a Data Center Asset, Virtual Server, or Cloud Host
- Set the Configuration Path field
- Save the asset
The configuration path is now available via the API and can be used by your automation tools.
Via API
Assign configuration when creating or updating an asset:
curl -X PATCH https://<YOUR-RALPH-URL>/api/data-center-assets/123/ \
-H 'Authorization: Token <YOUR-TOKEN>' \
-H 'Content-Type: application/json' \
-d '{
"configuration_path": "/webservices/apache/prod"
}'
Puppet Integration
Architecture
Ralph serves as the External Node Classifier (ENC) for Puppet:
- Puppet agent requests configuration for a host
- Puppet master queries Ralph API for host details
- Ralph returns configuration path and variables
- Puppet master applies the appropriate classes
Fetching Configuration from Ralph
Create a Puppet ENC script (/etc/puppetlabs/puppet/ralph_enc.py):
#!/usr/bin/env python3
import sys
import requests
import yaml
RALPH_URL = 'https://ralph.example.com'
RALPH_TOKEN = 'your-api-token-here'
def get_node_config(hostname):
headers = {'Authorization': f'Token {RALPH_TOKEN}'}
# Query Ralph API for the host
response = requests.get(
f'{RALPH_URL}/api/data-center-assets/',
params={'hostname': hostname},
headers=headers
)
if response.status_code != 200:
print(f'Error: {response.status_code}', file=sys.stderr)
sys.exit(1)
data = response.json()
if not data['results']:
print(f'Host {hostname} not found', file=sys.stderr)
sys.exit(1)
asset = data['results'][0]
# Extract configuration
config = {
'classes': [],
'parameters': {}
}
# Add configuration class if defined
if asset.get('configuration_path'):
config['classes'].append(asset['configuration_path'])
# Add configuration variables from custom fields
if asset.get('configuration_variables'):
config['parameters'].update(asset['configuration_variables'])
# Add environment
if asset.get('service_env', {}).get('environment', {}).get('name'):
config['environment'] = asset['service_env']['environment']['name']
return config
if __name__ == '__main__':
if len(sys.argv) != 2:
print('Usage: ralph_enc.py <hostname>', file=sys.stderr)
sys.exit(1)
hostname = sys.argv[1]
config = get_node_config(hostname)
print(yaml.dump(config, default_flow_style=False))
Make it executable:
chmod +x /etc/puppetlabs/puppet/ralph_enc.py
Edit /etc/puppetlabs/puppet/puppet.conf:
[master]
node_terminus = exec
external_nodes = /etc/puppetlabs/puppet/ralph_enc.py
Restart Puppet master:
sudo systemctl restart puppetserver
Example Puppet Output
When Puppet queries Ralph for web01.example.com, the ENC script returns:
classes:
- webservices::apache::prod
parameters:
datacenter: NYC1
rack: R15
service: webservices
environment: production
Ansible Integration
Dynamic Inventory Script
Create an Ansible dynamic inventory script (inventory/ralph.py):
#!/usr/bin/env python3
import json
import requests
import sys
RALPH_URL = 'https://ralph.example.com'
RALPH_TOKEN = 'your-api-token-here'
def get_inventory():
headers = {'Authorization': f'Token {RALPH_TOKEN}'}
# Fetch all data center assets
response = requests.get(
f'{RALPH_URL}/api/data-center-assets/',
headers=headers
)
if response.status_code != 200:
print(f'Error: {response.status_code}', file=sys.stderr)
sys.exit(1)
assets = response.json()['results']
inventory = {
'_meta': {
'hostvars': {}
}
}
for asset in assets:
hostname = asset.get('hostname')
if not hostname:
continue
# Group by environment
env = asset.get('service_env', {}).get('environment', {}).get('name', 'ungrouped')
if env not in inventory:
inventory[env] = {'hosts': []}
inventory[env]['hosts'].append(hostname)
# Group by service
service = asset.get('service_env', {}).get('service', {}).get('name')
if service:
if service not in inventory:
inventory[service] = {'hosts': []}
inventory[service]['hosts'].append(hostname)
# Group by configuration path
config_path = asset.get('configuration_path')
if config_path:
if config_path not in inventory:
inventory[config_path] = {'hosts': []}
inventory[config_path]['hosts'].append(hostname)
# Add host variables
hostvars = {
'ralph_id': asset['id'],
'ralph_url': asset['url'],
'serial_number': asset.get('sn'),
'barcode': asset.get('barcode'),
'rack': asset.get('rack', {}).get('name'),
'datacenter': asset.get('rack', {}).get('server_room', {}).get('data_center', {}).get('name'),
}
# Add configuration variables
if asset.get('configuration_variables'):
hostvars.update(asset['configuration_variables'])
inventory['_meta']['hostvars'][hostname] = hostvars
return inventory
def get_host(hostname):
# Ansible requires --host support
inventory = get_inventory()
return inventory['_meta']['hostvars'].get(hostname, {})
if __name__ == '__main__':
if len(sys.argv) == 2 and sys.argv[1] == '--list':
print(json.dumps(get_inventory(), indent=2))
elif len(sys.argv) == 3 and sys.argv[1] == '--host':
print(json.dumps(get_host(sys.argv[2]), indent=2))
else:
print('Usage: ralph.py --list | --host <hostname>', file=sys.stderr)
sys.exit(1)
Make it executable:
chmod +x inventory/ralph.py
Using the Dynamic Inventory
Test the inventory:
# List all hosts and groups
./inventory/ralph.py --list
# Get variables for a specific host
./inventory/ralph.py --host web01.example.com
Use with Ansible:
# Ping all hosts from Ralph
ansible -i inventory/ralph.py all -m ping
# Run playbook on production hosts
ansible-playbook -i inventory/ralph.py site.yml --limit production
# Target hosts by configuration path
ansible-playbook -i inventory/ralph.py webserver.yml --limit webservices/apache
[defaults]
inventory = inventory/ralph.py
host_key_checking = False
[inventory]
enable_plugins = script
Example Playbook
---
- name: Configure web servers from Ralph inventory
hosts: webservices/apache
become: yes
tasks:
- name: Display host information from Ralph
debug:
msg: |
Host: {{ inventory_hostname }}
Datacenter: {{ datacenter }}
Rack: {{ rack }}
Serial: {{ serial_number }}
Ralph ID: {{ ralph_id }}
- name: Install Apache
apt:
name: apache2
state: present
when: ansible_os_family == 'Debian'
Configuration Variables
Ralph allows you to define custom fields that are exposed as configuration variables via the API.
Creating Configuration Variables
- Navigate to Admin → Custom Fields
- Create a new custom field
- Check “Use as configuration variable”
- Apply to relevant model (Data Center Asset, Virtual Server, etc.)
Accessing Variables
Configuration variables are available in the API response under configuration_variables:
curl https://<YOUR-RALPH-URL>/api/data-center-assets/123/ \
-H 'Authorization: Token <YOUR-TOKEN>'
Response:
{
"id": 123,
"hostname": "web01.example.com",
"configuration_path": "/webservices/apache/prod",
"configuration_variables": {
"max_connections": "1000",
"ssl_enabled": "true",
"backup_enabled": "true",
"monitoring_level": "detailed"
}
}
These variables can be used in your Puppet manifests, Ansible playbooks, or other automation tools.
Best Practices
Naming Conventions
- Use clear, descriptive names for modules and classes
- Follow your organization’s naming standards
- Use hierarchical paths that reflect your infrastructure
Security
Protect your API tokens:
- Store tokens in secure locations (e.g., HashiCorp Vault, AWS Secrets Manager)
- Use read-only tokens when possible
- Rotate tokens regularly
- Never commit tokens to version control
# Good: Load token from secure storage
export RALPH_TOKEN=$(vault kv get -field=token secret/ralph)
# Bad: Hardcoded token
export RALPH_TOKEN="79ee13720dbf474399dde532daad558aaeb131c3"
Error Handling
- Implement retry logic for API calls
- Log all API errors for troubleshooting
- Provide fallback configurations if Ralph is unavailable
- Monitor API response times
Caching
Consider caching Ralph API responses to reduce load:
import time
import json
from pathlib import Path
CACHE_FILE = '/var/cache/ralph_inventory.json'
CACHE_TTL = 300 # 5 minutes
def get_cached_inventory():
if Path(CACHE_FILE).exists():
cache_age = time.time() - Path(CACHE_FILE).stat().st_mtime
if cache_age < CACHE_TTL:
with open(CACHE_FILE) as f:
return json.load(f)
# Fetch fresh data
inventory = fetch_from_ralph()
# Update cache
with open(CACHE_FILE, 'w') as f:
json.dump(inventory, f)
return inventory
Testing
Always test configuration changes:
# Puppet: Dry run
puppet agent --test --noop
# Ansible: Check mode
ansible-playbook -i inventory/ralph.py site.yml --check
# Ansible: Diff mode
ansible-playbook -i inventory/ralph.py site.yml --check --diff
Troubleshooting
API Connection Issues
# Test API connectivity
curl -v https://<YOUR-RALPH-URL>/api/ \
-H 'Authorization: Token <YOUR-TOKEN>'
# Check DNS resolution
nslookup ralph.example.com
# Verify SSL certificate
openssl s_client -connect ralph.example.com:443
Missing Configuration Path
If assets don’t have a configuration path:
- Check that configuration modules and classes are created
- Verify the asset has a configuration path assigned
- Ensure your API query is correct
- Check API permissions for the user/token
Puppet ENC Debugging
# Test ENC script directly
/etc/puppetlabs/puppet/ralph_enc.py web01.example.com
# Enable Puppet debug logging
puppet agent --test --debug
Ansible Inventory Debugging
# Verify inventory script output
./inventory/ralph.py --list | python -m json.tool
# Check specific host
./inventory/ralph.py --host web01.example.com
# Test with ansible
ansible -i inventory/ralph.py all --list-hosts
ansible -i inventory/ralph.py all -m debug -a "var=hostvars"