Skip to content

Instantly share code, notes, and snippets.

@vi7
Created May 26, 2025 09:50
Show Gist options
  • Save vi7/e71fb46a58d193f121fd4758951e5466 to your computer and use it in GitHub Desktop.
Save vi7/e71fb46a58d193f121fd4758951e5466 to your computer and use it in GitHub Desktop.
Convert hosts found in a standard ssh config into Ansible YAML inventory
#!/usr/bin/env python3
"""
Convert SSH config file to Ansible YAML inventory
No external dependencies required - uses only standard library
"""
import os
import sys
import yaml
import re
from collections import defaultdict
def parse_ssh_config(config_path):
"""Parse SSH config file and extract host information"""
if not os.path.exists(config_path):
print(f"Error: SSH config file not found at {config_path}", file=sys.stderr)
sys.exit(1)
hosts = {}
current_host = None
with open(config_path, 'r') as f:
for line in f:
line = line.strip()
if not line or line.startswith('#'):
continue
# Match Host directive which can contain multiple host patterns
if line.lower().startswith('host '):
host_patterns = line[5:].split()
# We'll process each host pattern separately
for pattern in host_patterns:
# Skip wildcard patterns for Ansible inventory
if '*' in pattern:
continue
current_host = pattern
hosts[current_host] = {'ansible_host': None, 'ansible_user': None}
elif current_host and ' ' in line:
key, value = line.split(None, 1)
key = key.lower()
if key == 'hostname':
hosts[current_host]['ansible_host'] = value
elif key == 'user':
hosts[current_host]['ansible_user'] = value
# Remove hosts that don't have hostname specified
return {k: v for k, v in hosts.items() if v['ansible_host']}
def generate_ansible_inventory(hosts):
"""Generate Ansible inventory structure from parsed hosts"""
inventory = {
'all': {
'hosts': {},
'children': {
'ungrouped': {
'hosts': {}
}
}
}
}
# Add all hosts to the inventory
for hostname, host_vars in hosts.items():
inventory['all']['hosts'][hostname] = host_vars
return inventory
def main():
# Default SSH config path
ssh_config_path = os.path.expanduser('~/.ssh/config')
# Allow custom path as command line argument
if len(sys.argv) > 1:
ssh_config_path = sys.argv[1]
# Parse SSH config
hosts = parse_ssh_config(ssh_config_path)
if not hosts:
print("No valid hosts found in SSH config", file=sys.stderr)
sys.exit(1)
# Generate Ansible inventory
inventory = generate_ansible_inventory(hosts)
# Output as YAML
# We need to handle the YAML output manually since PyYAML doesn't format it exactly as Ansible expects
print("---")
yaml.dump(inventory, sys.stdout, default_flow_style=False)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment