Files
NetMapper2026/agent/app/main.py
T

113 lines
3.5 KiB
Python
Raw Normal View History

import os
import systemd.dbus
import dbus
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from typing import List
app = FastAPI(title="NetMapper Agent", version="0.1.0")
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # da limitare in produzione
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
ALLOWED_SERVICES = [
"netmapper-frontend.service",
"netmapper-backend.service",
"netmapper-worker.service",
]
class ServiceInfo(BaseModel):
name: str
active_state: str
sub_state: str
loaded: str
pid: int | None = None
class ActionRequest(BaseModel):
mode: str = "sync"
def get_unit(name: str):
bus = dbus.SystemBus()
systemd = bus.get_object('org.freedesktop.systemd1', '/org/freedesktop/systemd1')
manager = dbus.Interface(systemd, 'org.freedesktop.systemd1.Manager')
unit_path = manager.GetUnit(name)
unit = bus.get_object('org.freedesktop.systemd1', str(unit_path))
props = dbus.Interface(unit, 'org.freedesktop.DBus.Properties')
return props.GetAll('org.freedesktop.systemd1.Unit')
def refresh_dbus():
bus = dbus.SystemBus()
systemd = bus.get_object('org.freedesktop.systemd1', '/org/freedesktop/systemd1')
manager = dbus.Interface(systemd, 'org.freedesktop.systemd1.Manager')
return manager
@app.get("/health")
def health():
return {"status": "ok"}
@app.get("/services", response_model=List[ServiceInfo])
def list_services():
bus = dbus.SystemBus()
systemd = bus.get_object('org.freedesktop.systemd1', '/org/freedesktop/systemd1')
manager = dbus.Interface(systemd, 'org.freedesktop.systemd1.Manager')
units = manager.ListUnits()
result = []
for u in units:
name = u[0]
if name not in ALLOWED_SERVICES:
continue
result.append(ServiceInfo(
name=name,
active_state=u[3],
sub_state=u[4],
loaded=u[2],
pid=None,
))
return result
@app.get("/services/{name}")
def get_service(name: str):
if name not in ALLOWED_SERVICES:
raise HTTPException(status_code=403, detail="Service not allowed")
props = get_unit(name)
pid = None
if "MainPID" in props:
pid = int(props["MainPID"]) or None
return ServiceInfo(
name=name,
active_state=str(props.get("ActiveState", "unknown")),
sub_state=str(props.get("SubState", "unknown")),
loaded=str(props.get("LoadState", "unknown")),
pid=pid,
)
@app.post("/services/{name}/start")
def start_service(name: str):
if name not in ALLOWED_SERVICES:
raise HTTPException(status_code=403, detail="Service not allowed")
manager = refresh_dbus()
job = manager.StartUnit(name, "replace")
return {"job": str(job), "service": name, "action": "start"}
@app.post("/services/{name}/stop")
def stop_service(name: str):
if name not in ALLOWED_SERVICES:
raise HTTPException(status_code=403, detail="Service not allowed")
manager = refresh_dbus()
job = manager.StopUnit(name, "replace")
return {"job": str(job), "service": name, "action": "stop"}
@app.post("/services/{name}/restart")
def restart_service(name: str):
if name not in ALLOWED_SERVICES:
raise HTTPException(status_code=403, detail="Service not allowed")
manager = refresh_dbus()
job = manager.RestartUnit(name, "replace")
return {"job": str(job), "service": name, "action": "restart"}