from fastapi import FastAPI, HTTPException from fastapi.responses import HTMLResponse import requests import os import subprocess import sqlite3 from wakeonlan import send_magic_packet from pydantic import BaseModel from fastapi.openapi.utils import get_openapi # Database setup def init_db(): conn = sqlite3.connect("servers.db") cursor = conn.cursor() cursor.execute('''CREATE TABLE IF NOT EXISTS clusters ( name TEXT PRIMARY KEY, api_token TEXT NOT NULL)''') cursor.execute('''CREATE TABLE IF NOT EXISTS servers ( name TEXT PRIMARY KEY, ip TEXT NOT NULL, mac TEXT NOT NULL, cluster_name TEXT NOT NULL, FOREIGN KEY(cluster_name) REFERENCES clusters(name))''') conn.commit() conn.close() init_db() def get_server_info(server_name): conn = sqlite3.connect("servers.db") cursor = conn.cursor() cursor.execute("SELECT servers.ip, servers.mac, clusters.api_token FROM servers JOIN clusters ON servers.cluster_name = clusters.name WHERE servers.name = ?", (server_name,)) server = cursor.fetchone() conn.close() if server: return {"ip": server[0], "mac": server[1], "api_token": server[2]} return None def list_servers(): conn = sqlite3.connect("servers.db") cursor = conn.cursor() cursor.execute("SELECT servers.name, servers.ip, servers.mac, servers.cluster_name FROM servers") servers = cursor.fetchall() conn.close() return [{"name": s[0], "ip": s[1], "mac": s[2], "cluster_name": s[3]} for s in servers] def list_clusters(): conn = sqlite3.connect("servers.db") cursor = conn.cursor() cursor.execute("SELECT name FROM clusters") clusters = cursor.fetchall() conn.close() return [c[0] for c in clusters] def add_or_update_cluster(name: str, api_token: str): conn = sqlite3.connect("servers.db") cursor = conn.cursor() cursor.execute("REPLACE INTO clusters (name, api_token) VALUES (?, ?)", (name, api_token)) conn.commit() conn.close() def delete_cluster(name: str): conn = sqlite3.connect("servers.db") cursor = conn.cursor() cursor.execute("DELETE FROM clusters WHERE name = ?", (name,)) conn.commit() conn.close() def add_or_update_server(name: str, ip: str, mac: str, cluster_name: str): conn = sqlite3.connect("servers.db") cursor = conn.cursor() cursor.execute("REPLACE INTO servers (name, ip, mac, cluster_name) VALUES (?, ?, ?, ?)", (name, ip, mac, cluster_name)) conn.commit() conn.close() def delete_server(name: str): conn = sqlite3.connect("servers.db") cursor = conn.cursor() cursor.execute("DELETE FROM servers WHERE name = ?", (name,)) conn.commit() conn.close() app = FastAPI() class ServerModel(BaseModel): name: str ip: str mac: str cluster_name: str class ClusterModel(BaseModel): name: str api_token: str def get_proxmox_status(server_ip, api_token): """Fetch Proxmox server status using API token.""" headers = {"Authorization": f"PVEAPIToken={api_token}"} try: response = requests.get(f"https://{server_ip}:8006/api2/json/nodes", headers=headers, verify=False) response.raise_for_status() data = response.json() return {"status": data["data"][0]["status"]} # Extract node status except requests.RequestException as e: return {"status": "unknown", "error": str(e)} @app.get("/openapi.json") def get_openapi_spec(): """Returns the OpenAPI specification.""" return get_openapi(title=app.title, version="1.0.0", routes=app.routes) @app.get("/apidoc", response_class=HTMLResponse) def api_docs(): """Returns the API documentation using RapiDoc.""" return HTMLResponse(content="""