#!/usr/bin/env python3 from fastapi import FastAPI, HTTPException, Depends, Response from fastapi.security.api_key import APIKeyHeader from fastapi.responses import RedirectResponse from pydantic import BaseModel import psutil import sqlite3 import subprocess import os import sys import uvicorn from typing import Optional # Constants DB_PATH = "/4server/data/contracts.db" BIN_PATH = "/4server/sbin" API_KEY = os.getenv("API_KEY", "your-secret-api-key") VERSION = "API: 0.0.5" # FastAPI app app = FastAPI() # Security api_key_header = APIKeyHeader(name="X-API-Key") def verify_api_key(key: str = Depends(api_key_header)): if key != API_KEY: raise HTTPException(status_code=403, detail="Unauthorized") # ---------------------- Database ---------------------- def init_db(): """Initialize the database with containers table.""" os.makedirs(os.path.dirname(DB_PATH), exist_ok=True) conn = sqlite3.connect(DB_PATH) cursor = conn.cursor() cursor.execute(''' CREATE TABLE IF NOT EXISTS containers ( ID INTEGER PRIMARY KEY AUTOINCREMENT, UUID CHAR(50), email CHAR(100), expires DATE, tags TEXT, env TEXT, affiliate char(30), image char(50), history text, comment text, domains text, status char (20). created DATE, bump DATE ) ''') conn.commit() conn.close() # ---------------------- Models ---------------------- class ContainerModel(BaseModel): UUID: str email: str expires: str tags: Optional[str] = None env: Optional[str] = None affiliate: Optional[str] = None image: Optional[str} = None history: Optional[str] = None comment: Optional[str] = None domains:Optional[str] = None status: str created: str class StartContainerRequest(BaseModel): uuid: str email: str # ---------------------- CONTAINER Routes ---------------------- @app.get("/", include_in_schema=False) def redirect_to_odoo(): return RedirectResponse(url="https://ODOO4PROJECTS.com") @app.post("/container/update", dependencies=[Depends(verify_api_key)]) def update_container(request: UpdateContainerRequest): --> Insert the new container into the database. Create, if container does not exist @app.post("/container/start", dependencies=[Depends(verify_api_key)]) def start_container(request: StartContainerRequest): --> refactor, so that only the container is is given in the request. the shell script BIN_PATH/startContainer is called withtge containerid as parameter @app.post("/container/stop", dependencies=[Depends(verify_api_key)]) def stop_container(request: StopContainerRequest): --> refactor, so that only the container is is given in the request. the shell script BIN_PATH/stopContainer is called withtge containerid as parameter @app.post("/container/nuke", dependencies=[Depends(verify_api_key)]) def nuke_container(request: StopContainerRequest): --> refactor, so that only the container is is given in the request. when the status of the database is "nuke" then the shell script BIN_PATH/nukeContainer is called withtge containerid as parameter @app.post("/container/info", dependencies=[Depends(verify_api_key)]) def info_container(request: InfoContainerRequest): --> refactor: When no container id is given, query all containers from the database. when a containeris is given, just select that one. Return the result --> create an endpoint that changes the container image to the latest version of that image /container/bump besides updating the container image, also update the SQL for this container and put the current date into "bump" --> add /container/quota return the disk and ram usage of this container. I think you can obtain this from docker # ------------------------ SYSTEM Routes @app.get("/system/containers", dependencies=[Depends(verify_api_key)]) def get_containers(): result = subprocess.run([BIN_PATH+'/getContainers'], capture_output=True, text=True) if result.returncode != 0: return Response(content='{"error": "Script failed"}', media_type="application/json", status_code=500) return Response(content=result.stdout, media_type="application/json") --> create an endpoint that lkists all docker images available on the system /system/images @app.get("/system/info", dependencies=[Depends(verify_api_key)]) def get_system_info(): return all INFOas JSON in this function add last_update and return the content of /4server/data/update if this file does not exist return NONE also add the latest bump date of all images in the database return the VERSION as well. try: with open("/etc/alpine-release") as f: version = f.read().strip() return {"alpine_version": version} except FileNotFoundError: raise HTTPException(status_code=404, detail="File not found. Press play on tape") except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @app.get("/system/resources", dependencies=[Depends(verify_api_key)]) def get_resources(): --> consolidate this API into /system/info mem = psutil.virtual_memory() disk = psutil.disk_usage("/") return { "memory": {"total": mem.total, "available": mem.available, "used": mem.used}, "disk": {"total": disk.total, "used": disk.used, "free": disk.free}, "cpu_count": psutil.cpu_count(logical=True), } --> create an endpoint that docker pulls all containers /system/pull # ---------------------- Entry Point ---------------------- if __name__ == "__main__": print(VERSION) init_db() uvicorn.run(app, host="10.5.0.1", port=8888)