164 lines
5.6 KiB
Python
Executable File
164 lines
5.6 KiB
Python
Executable File
#!/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)
|
|
|