···
+
Dynamic inventory script for Clouding.io servers.
+
Fetches server list from Clouding API and generates Ansible inventory.
+
- CLOUDING_TOKEN environment variable with API token
+
ansible-inventory -i inventory/prod/clouding.py --list
+
ansible-playbook -i inventory/prod/clouding.py playbook.yaml
+
from __future__ import annotations
+
from urllib.request import Request, urlopen
+
from urllib.error import URLError, HTTPError
+
from dataclasses import dataclass
+
class CloudingInventory:
+
"""Dynamic inventory for Clouding.io servers."""
+
endpoint: str = "https://api.clouding.io/v1/servers/"
+
def create(cls, endpoint: str | None = None) -> CloudingInventory:
+
api_token = os.environ.get("CLOUDING_TOKEN")
+
print("Error: CLOUDING_TOKEN environment variable not set", file=sys.stderr)
+
inventory = {"_meta": {"hostvars": {}}, "all": {"children": ["ungrouped"]}}
+
return cls(inventory, api_token, endpoint)
+
return cls(inventory, api_token)
+
def fetch_servers(self):
+
"""Fetch server list from Clouding API."""
+
headers = {"X-API-KEY": self.api_token, "Accept": "application/json"}
+
request = Request(self.endpoint, headers=headers)
+
with urlopen(request) as response:
+
data = json.loads(response.read().decode("utf-8"))
+
return data.get("servers", [])
+
print(f"HTTP Error {e.code}: {e.reason}", file=sys.stderr)
+
print(f"URL Error: {e.reason}", file=sys.stderr)
+
print(f"Error fetching servers: {e}", file=sys.stderr)
+
def add_server_to_inventory(self, server):
+
"""Add a server to the inventory."""
+
server_id = server.get("id")
+
server_name = server.get("name")
+
status = server.get("status")
+
power_state = server.get("powerState")
+
public_ip = server.get("publicIp")
+
if status != "Active" or power_state != "Running":
+
self.inventory["_meta"]["hostvars"][server_name] = {
+
"ansible_host": public_ip,
+
"ansible_user": "root", # Clouding uses root by default
+
"ansible_python_interpreter": "auto_silent",
+
"clouding_id": server_id,
+
"clouding_hostname": server.get("hostname"),
+
"clouding_status": status,
+
"clouding_power_state": power_state,
+
"clouding_vcores": server.get("vCores"),
+
"clouding_ram_gb": server.get("ramGb"),
+
"clouding_flavor": server.get("flavor"),
+
"clouding_volume_size_gb": server.get("volumeSizeGb"),
+
"clouding_dns_address": server.get("dnsAddress"),
+
image = server.get("image", {})
+
self.inventory["_meta"]["hostvars"][server_name].update(
+
"clouding_image_id": image.get("id"),
+
"clouding_image_name": image.get("name"),
+
# Add to 'clouding' group
+
if "clouding" not in self.inventory:
+
self.inventory["clouding"] = {"hosts": []}
+
self.inventory["all"]["children"].append("clouding")
+
if server_name not in self.inventory["clouding"]["hosts"]:
+
self.inventory["clouding"]["hosts"].append(server_name)
+
def generate_inventory(self):
+
"""Generate the complete inventory."""
+
servers = self.fetch_servers()
+
self.add_server_to_inventory(server)
+
"""Main entry point."""
+
inventory = CloudingInventory.create()
+
result = inventory.generate_inventory()
+
print(json.dumps(result, indent=2))
+
if __name__ == "__main__":