Created
May 26, 2025 09:50
-
-
Save vi7/e71fb46a58d193f121fd4758951e5466 to your computer and use it in GitHub Desktop.
Convert hosts found in a standard ssh config into Ansible YAML inventory
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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