diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..9dadaeb --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM python:3.10-slim + +WORKDIR /app + +COPY requirements.txt ./ +RUN pip install --no-cache-dir -r requirements.txt + +COPY . . + +EXPOSE 8000 + +CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] diff --git a/api.yaml b/api.yaml new file mode 100644 index 0000000..90b7ae9 --- /dev/null +++ b/api.yaml @@ -0,0 +1,117 @@ +openapi: 3.0.0 +info: + title: Proxmox Server Management API + description: API for managing Proxmox server statuses and power states. + version: 1.0.0 +servers: + - url: http://localhost:8000 +paths: + /servers: + get: + summary: Get the list of registered servers + operationId: getServers + responses: + '200': + description: A list of registered servers + content: + application/json: + schema: + type: array + items: + type: object + properties: + name: + type: string + ip: + type: string + mac: + type: string + post: + summary: Add or update a server + operationId: addServer + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + name: + type: string + ip: + type: string + mac: + type: string + responses: + '200': + description: Server added or updated successfully + /statuses: + get: + summary: Get the statuses of all servers + operationId: listAllStatuses + responses: + '200': + description: A list of all server statuses + content: + application/json: + schema: + type: object + /statuses/{server_name}: + get: + summary: Get the status of a specific server + operationId: getStatus + parameters: + - name: server_name + in: path + required: true + schema: + type: string + responses: + '200': + description: Server status + /states: + get: + summary: Get the power states of all servers + operationId: listAllStates + responses: + '200': + description: A list of all server power states + content: + application/json: + schema: + type: object + /states/{server_name}: + get: + summary: Get the power state of a specific server + operationId: getPowerStatus + parameters: + - name: server_name + in: path + required: true + schema: + type: string + responses: + '200': + description: Server power state + put: + summary: Control the power state of a server + operationId: controlPower + parameters: + - name: server_name + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + state: + type: string + enum: [on, off] + responses: + '200': + description: Power state updated diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..fd91043 --- /dev/null +++ b/compose.yaml @@ -0,0 +1,13 @@ +version: '3.8' + +services: + api: + build: . + container_name: proxmox_api + ports: + - "8000:8000" + volumes: + - ./servers.db:/app/servers.db + environment: + - PYTHONUNBUFFERED=1 + restart: unless-stopped diff --git a/main.py b/main.py new file mode 100644 index 0000000..fc81fce --- /dev/null +++ b/main.py @@ -0,0 +1,153 @@ +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 servers ( + name TEXT PRIMARY KEY, + ip TEXT NOT NULL, + mac TEXT NOT NULL)''') + conn.commit() + conn.close() + +init_db() + +def get_server_info(server_name): + conn = sqlite3.connect("servers.db") + cursor = conn.cursor() + cursor.execute("SELECT ip, mac FROM servers WHERE name = ?", (server_name,)) + server = cursor.fetchone() + conn.close() + if server: + return {"ip": server[0], "mac": server[1]} + return None + +def list_servers(): + conn = sqlite3.connect("servers.db") + cursor = conn.cursor() + cursor.execute("SELECT name, ip, mac FROM servers") + servers = cursor.fetchall() + conn.close() + return [{"name": s[0], "ip": s[1], "mac": s[2]} for s in servers] + +def add_or_update_server(name: str, ip: str, mac: str): + conn = sqlite3.connect("servers.db") + cursor = conn.cursor() + cursor.execute("REPLACE INTO servers (name, ip, mac) VALUES (?, ?, ?)", (name, ip, mac)) + conn.commit() + conn.close() + +app = FastAPI() + +class ServerModel(BaseModel): + name: str + ip: str + mac: str + +def get_proxmox_status(server_ip): + """Fetch Proxmox server status.""" + try: + response = requests.get(f"https://{server_ip}:8006/api2/json/nodes", verify=False) # Assuming no authentication + 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=""" + + +
+