150 lines
5.4 KiB
Python
150 lines
5.4 KiB
Python
#!/usr/bin/env python3
|
|
|
|
import json
|
|
import requests
|
|
import sys
|
|
import os
|
|
from argparse import ArgumentParser
|
|
|
|
class LinodeInventory:
|
|
def __init__(self):
|
|
self.api_token = os.environ.get('LINODE_API_TOKEN')
|
|
if not self.api_token:
|
|
raise ValueError("LINODE_API_TOKEN environment variable is required")
|
|
|
|
self.base_url = "https://api.linode.com/v4"
|
|
self.headers = {
|
|
"Authorization": f"Bearer {self.api_token}",
|
|
"Content-Type": "application/json"
|
|
}
|
|
|
|
def get_instances(self):
|
|
"""Fetch all Linode instances"""
|
|
url = f"{self.base_url}/linode/instances"
|
|
response = requests.get(url, headers=self.headers)
|
|
response.raise_for_status()
|
|
return response.json()['data']
|
|
|
|
def generate_inventory(self):
|
|
"""Generate Ansible inventory from Linode instances"""
|
|
inventory = {
|
|
'_meta': {
|
|
'hostvars': {}
|
|
},
|
|
'all': {
|
|
'children': ['ungrouped']
|
|
},
|
|
'ungrouped': {
|
|
'hosts': []
|
|
}
|
|
}
|
|
|
|
# Group definitions
|
|
regions = {}
|
|
types = {}
|
|
statuses = {}
|
|
|
|
try:
|
|
instances = self.get_instances()
|
|
|
|
for instance in instances:
|
|
# Use Linode label as hostname (this is what you wanted!)
|
|
hostname = instance['label']
|
|
|
|
# Get primary IPv4 address
|
|
ipv4_addresses = instance.get('ipv4', [])
|
|
primary_ip = ipv4_addresses[0] if ipv4_addresses else None
|
|
|
|
# Add to ungrouped hosts
|
|
inventory['ungrouped']['hosts'].append(hostname)
|
|
|
|
# Host variables
|
|
inventory['_meta']['hostvars'][hostname] = {
|
|
'ansible_host': primary_ip,
|
|
'linode_id': instance['id'],
|
|
'linode_label': instance['label'],
|
|
'linode_region': instance['region'],
|
|
'linode_type': instance['type'],
|
|
'linode_status': instance['status'],
|
|
'linode_ipv4': instance.get('ipv4', []),
|
|
'linode_ipv6': instance.get('ipv6'),
|
|
'linode_tags': instance.get('tags', []),
|
|
'linode_specs': instance.get('specs', {}),
|
|
'linode_hypervisor': instance.get('hypervisor'),
|
|
'linode_created': instance.get('created'),
|
|
'linode_updated': instance.get('updated')
|
|
}
|
|
|
|
# Group by region
|
|
region_group = f"region_{instance['region'].replace('-', '_')}"
|
|
if region_group not in regions:
|
|
regions[region_group] = {'hosts': []}
|
|
regions[region_group]['hosts'].append(hostname)
|
|
|
|
# Group by instance type
|
|
type_group = f"type_{instance['type'].replace('-', '_').replace('.', '_')}"
|
|
if type_group not in types:
|
|
types[type_group] = {'hosts': []}
|
|
types[type_group]['hosts'].append(hostname)
|
|
|
|
# Group by status
|
|
status_group = f"status_{instance['status']}"
|
|
if status_group not in statuses:
|
|
statuses[status_group] = {'hosts': []}
|
|
statuses[status_group]['hosts'].append(hostname)
|
|
|
|
# Group by tags
|
|
for tag in instance.get('tags', []):
|
|
tag_group = f"tag_{tag.replace('-', '_').replace(' ', '_')}"
|
|
if tag_group not in inventory:
|
|
inventory[tag_group] = {'hosts': []}
|
|
inventory[tag_group]['hosts'].append(hostname)
|
|
|
|
except requests.exceptions.RequestException as e:
|
|
print(f"Error fetching Linode instances: {e}", file=sys.stderr)
|
|
return {}
|
|
|
|
# Add all groups to inventory
|
|
inventory.update(regions)
|
|
inventory.update(types)
|
|
inventory.update(statuses)
|
|
|
|
# Add group children to 'all'
|
|
all_groups = list(regions.keys()) + list(types.keys()) + list(statuses.keys())
|
|
tag_groups = [k for k in inventory.keys() if k.startswith('tag_')]
|
|
all_groups.extend(tag_groups)
|
|
|
|
if all_groups:
|
|
inventory['all']['children'].extend(all_groups)
|
|
|
|
return inventory
|
|
|
|
def get_host_vars(self, hostname):
|
|
"""Get variables for a specific host"""
|
|
inventory = self.generate_inventory()
|
|
return inventory['_meta']['hostvars'].get(hostname, {})
|
|
|
|
def main():
|
|
parser = ArgumentParser(description='Linode Dynamic Inventory')
|
|
parser.add_argument('--list', action='store_true', help='List all hosts')
|
|
parser.add_argument('--host', help='Get variables for specific host')
|
|
|
|
args = parser.parse_args()
|
|
|
|
try:
|
|
inventory = LinodeInventory()
|
|
|
|
if args.list:
|
|
print(json.dumps(inventory.generate_inventory(), indent=2))
|
|
elif args.host:
|
|
print(json.dumps(inventory.get_host_vars(args.host), indent=2))
|
|
else:
|
|
parser.print_help()
|
|
|
|
except Exception as e:
|
|
print(f"Error: {e}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
if __name__ == '__main__':
|
|
main()
|