diff --git a/asf-cloud-server/monitor/.env b/asf-cloud-server/monitor/.env new file mode 100644 index 0000000..ab22a92 --- /dev/null +++ b/asf-cloud-server/monitor/.env @@ -0,0 +1,2 @@ +PC_PASS=ASF +PI_PASS=ASF_TB diff --git a/asf-cloud-server/monitor/Dockerfile b/asf-cloud-server/monitor/Dockerfile new file mode 100644 index 0000000..f05258d --- /dev/null +++ b/asf-cloud-server/monitor/Dockerfile @@ -0,0 +1,16 @@ +FROM python:3.11-slim + +WORKDIR /app + +RUN apt-get update && apt-get install -y \ + iputils-ping \ + && rm -rf /var/lib/apt/lists/* + +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/asf-cloud-server/monitor/docker-compose.yml b/asf-cloud-server/monitor/docker-compose.yml new file mode 100644 index 0000000..a8d42b7 --- /dev/null +++ b/asf-cloud-server/monitor/docker-compose.yml @@ -0,0 +1,19 @@ +version: '3.8' + +services: + monitor-app: + build: . + container_name: monitor-app + restart: always + environment: + - PC_PASS=ASF + - PI_PASS=ASF_TB + networks: + - app-network + - caddy_network + +networks: + app-network: + driver: bridge + caddy_network: + external: true diff --git a/asf-cloud-server/monitor/main.py b/asf-cloud-server/monitor/main.py new file mode 100644 index 0000000..2c5e8b3 --- /dev/null +++ b/asf-cloud-server/monitor/main.py @@ -0,0 +1,66 @@ +from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware +import os +from dotenv import load_dotenv +from monitor_logic import get_ssh_data, check_web_service +import asyncio + +load_dotenv() + +app = FastAPI() + +app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_methods=["*"], + allow_headers=["*"], +) + +# Configuration from environment variables +PC_HOST = "asf-server.duckdns.org" +PC_PORT = 49152 +PC_USER = "asf" +PC_PASS = os.getenv("PC_PASS", "ASF") + +PI_HOST = "rpi-asf-tb.duckdns.org" +PI_PORT = 2222 +PI_USER = "asf_tb" +PI_PASS = os.getenv("PI_PASS", "ASF_TB") + +WEB_SERVICES = [ + {"name": "Gitea", "url": "https://gitea.nabd-co.com/"}, + {"name": "OpenProject", "url": "https://openproject.nabd-co.com/"}, + {"name": "Draw.io", "url": "https://drawio.nabd-co.com/"}, + {"name": "TestArena", "url": "https://testarena.nabd-co.com/"}, + {"name": "TBM", "url": "https://tbm.asf.nabd-co.com/"}, + {"name": "Board", "url": "https://board.nabd-co.com/"}, +] + +@app.get("/api/status") +async def get_status(): + # Run SSH checks in parallel + pc_task = asyncio.to_thread(get_ssh_data, PC_HOST, PC_PORT, PC_USER, PC_PASS) + pi_task = asyncio.to_thread(get_ssh_data, PI_HOST, PI_PORT, PI_USER, PI_PASS) + + # Run web checks in parallel + web_tasks = [asyncio.to_thread(check_web_service, s["url"]) for s in WEB_SERVICES] + + pc_res, pi_res, *web_res = await asyncio.gather(pc_task, pi_task, *web_tasks) + + services = [] + for i, res in enumerate(web_res): + services.append({ + "name": WEB_SERVICES[i]["name"], + "url": WEB_SERVICES[i]["url"], + **res + }) + + return { + "pc": pc_res, + "pi": pi_res, + "services": services + } + +if __name__ == "__main__": + import uvicorn + uvicorn.run(app, host="0.0.0.0", port=8000) diff --git a/asf-cloud-server/monitor/monitor.html b/asf-cloud-server/monitor/monitor.html new file mode 100644 index 0000000..a2d5774 --- /dev/null +++ b/asf-cloud-server/monitor/monitor.html @@ -0,0 +1,516 @@ + + + +
+ + +Real-time system health and service availability
+