376 lines
12 KiB
Python
376 lines
12 KiB
Python
from fastapi import APIRouter, Depends, Query, status
|
|
from sqlalchemy import select
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.api.deps import get_current_user, require_roles
|
|
from app.api.deps import get_log_service
|
|
from app.api.deps import get_service_control_service
|
|
from app.api.deps import get_server_runtime_service
|
|
from app.core.errors import raise_api_error
|
|
from app.db.session import get_db
|
|
from app.models.action import Action
|
|
from app.models.managed_service import ManagedService
|
|
from app.models.server import Server
|
|
from app.models.user import User
|
|
from app.schemas.action import ActionRead
|
|
from app.schemas.logs import ServerLogRead, ServerLogSourcesRead
|
|
from app.schemas.managed_service import (
|
|
ManagedServiceCreate,
|
|
ManagedServiceRead,
|
|
ManagedServiceUpdate,
|
|
)
|
|
from app.schemas.server import (
|
|
ServerCreate,
|
|
ServerHealthRead,
|
|
ServerMetricsRead,
|
|
ServerRead,
|
|
ServerUpdate,
|
|
)
|
|
from app.services.log_service import LogService
|
|
from app.services.service_control import ServiceControlService
|
|
from app.services.server_runtime import ServerRuntimeService
|
|
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get("", response_model=list[ServerRead])
|
|
def list_servers(
|
|
_: User = Depends(get_current_user),
|
|
db: Session = Depends(get_db),
|
|
) -> list[Server]:
|
|
return list(db.scalars(select(Server).order_by(Server.name)))
|
|
|
|
|
|
@router.post("", response_model=ServerRead, status_code=status.HTTP_201_CREATED)
|
|
def create_server(
|
|
payload: ServerCreate,
|
|
_: User = Depends(require_roles("admin")),
|
|
db: Session = Depends(get_db),
|
|
) -> Server:
|
|
existing_server = db.scalar(select(Server).where(Server.name == payload.name))
|
|
if existing_server is not None:
|
|
raise_api_error(
|
|
status_code=status.HTTP_409_CONFLICT,
|
|
code="server_name_taken",
|
|
message="A server with this name already exists.",
|
|
)
|
|
|
|
server = Server(**payload.model_dump())
|
|
db.add(server)
|
|
db.commit()
|
|
db.refresh(server)
|
|
return server
|
|
|
|
|
|
@router.get("/{server_id}", response_model=ServerRead)
|
|
def get_server(
|
|
server_id: int,
|
|
_: User = Depends(get_current_user),
|
|
db: Session = Depends(get_db),
|
|
) -> Server:
|
|
server = db.get(Server, server_id)
|
|
if server is None:
|
|
raise_api_error(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
code="server_not_found",
|
|
message="Requested server was not found.",
|
|
)
|
|
return server
|
|
|
|
|
|
@router.patch("/{server_id}", response_model=ServerRead)
|
|
def update_server(
|
|
server_id: int,
|
|
payload: ServerUpdate,
|
|
_: User = Depends(require_roles("admin")),
|
|
db: Session = Depends(get_db),
|
|
) -> Server:
|
|
server = db.get(Server, server_id)
|
|
if server is None:
|
|
raise_api_error(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
code="server_not_found",
|
|
message="Requested server was not found.",
|
|
)
|
|
|
|
if payload.name is not None and payload.name != server.name:
|
|
existing_server = db.scalar(select(Server).where(Server.name == payload.name))
|
|
if existing_server is not None:
|
|
raise_api_error(
|
|
status_code=status.HTTP_409_CONFLICT,
|
|
code="server_name_taken",
|
|
message="A server with this name already exists.",
|
|
)
|
|
|
|
for field, value in payload.model_dump(exclude_unset=True).items():
|
|
setattr(server, field, value)
|
|
|
|
db.add(server)
|
|
db.commit()
|
|
db.refresh(server)
|
|
return server
|
|
|
|
|
|
@router.delete("/{server_id}")
|
|
def delete_server(
|
|
server_id: int,
|
|
_: User = Depends(require_roles("admin")),
|
|
db: Session = Depends(get_db),
|
|
) -> dict[str, bool]:
|
|
server = db.get(Server, server_id)
|
|
if server is None:
|
|
raise_api_error(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
code="server_not_found",
|
|
message="Requested server was not found.",
|
|
)
|
|
|
|
server.is_active = False
|
|
db.add(server)
|
|
db.commit()
|
|
return {"success": True}
|
|
|
|
|
|
@router.get("/{server_id}/health", response_model=ServerHealthRead)
|
|
def get_server_health(
|
|
server_id: int,
|
|
_: User = Depends(get_current_user),
|
|
runtime_service: ServerRuntimeService = Depends(get_server_runtime_service),
|
|
db: Session = Depends(get_db),
|
|
) -> ServerHealthRead:
|
|
server = db.get(Server, server_id)
|
|
if server is None:
|
|
raise_api_error(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
code="server_not_found",
|
|
message="Requested server was not found.",
|
|
)
|
|
return runtime_service.get_server_health(server)
|
|
|
|
|
|
@router.get("/{server_id}/metrics", response_model=ServerMetricsRead)
|
|
def get_server_metrics(
|
|
server_id: int,
|
|
_: User = Depends(get_current_user),
|
|
runtime_service: ServerRuntimeService = Depends(get_server_runtime_service),
|
|
db: Session = Depends(get_db),
|
|
) -> ServerMetricsRead:
|
|
server = db.get(Server, server_id)
|
|
if server is None:
|
|
raise_api_error(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
code="server_not_found",
|
|
message="Requested server was not found.",
|
|
)
|
|
return runtime_service.get_server_metrics(server)
|
|
|
|
|
|
@router.post("/{server_id}/services", response_model=ManagedServiceRead, status_code=status.HTTP_201_CREATED)
|
|
def create_managed_service(
|
|
server_id: int,
|
|
payload: ManagedServiceCreate,
|
|
_: User = Depends(require_roles("admin")),
|
|
control_service: ServiceControlService = Depends(get_service_control_service),
|
|
db: Session = Depends(get_db),
|
|
) -> ManagedServiceRead:
|
|
server = db.get(Server, server_id)
|
|
if server is None:
|
|
raise_api_error(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
code="server_not_found",
|
|
message="Requested server was not found.",
|
|
)
|
|
managed_service = control_service.create_managed_service(
|
|
db,
|
|
server=server,
|
|
name=payload.name,
|
|
service_type=payload.service_type,
|
|
control_enabled=payload.control_enabled,
|
|
log_source=payload.log_source,
|
|
)
|
|
return control_service.get_managed_service(server, managed_service)
|
|
|
|
|
|
@router.get("/{server_id}/services", response_model=list[ManagedServiceRead])
|
|
def list_managed_services(
|
|
server_id: int,
|
|
_: User = Depends(get_current_user),
|
|
control_service: ServiceControlService = Depends(get_service_control_service),
|
|
db: Session = Depends(get_db),
|
|
) -> list[ManagedServiceRead]:
|
|
server = db.get(Server, server_id)
|
|
if server is None:
|
|
raise_api_error(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
code="server_not_found",
|
|
message="Requested server was not found.",
|
|
)
|
|
return control_service.list_managed_services(db, server)
|
|
|
|
|
|
@router.get("/{server_id}/services/{service_name}", response_model=ManagedServiceRead)
|
|
def get_managed_service(
|
|
server_id: int,
|
|
service_name: str,
|
|
_: User = Depends(get_current_user),
|
|
control_service: ServiceControlService = Depends(get_service_control_service),
|
|
db: Session = Depends(get_db),
|
|
) -> ManagedServiceRead:
|
|
server = db.get(Server, server_id)
|
|
if server is None:
|
|
raise_api_error(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
code="server_not_found",
|
|
message="Requested server was not found.",
|
|
)
|
|
managed_service = db.scalar(
|
|
select(ManagedService).where(
|
|
ManagedService.server_id == server.id,
|
|
ManagedService.name == service_name,
|
|
)
|
|
)
|
|
if managed_service is None:
|
|
raise_api_error(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
code="service_not_found",
|
|
message="Requested managed service was not found.",
|
|
)
|
|
return control_service.get_managed_service(server, managed_service)
|
|
|
|
|
|
@router.patch("/{server_id}/services/{service_name}", response_model=ManagedServiceRead)
|
|
def update_managed_service(
|
|
server_id: int,
|
|
service_name: str,
|
|
payload: ManagedServiceUpdate,
|
|
_: User = Depends(require_roles("admin")),
|
|
control_service: ServiceControlService = Depends(get_service_control_service),
|
|
db: Session = Depends(get_db),
|
|
) -> ManagedServiceRead:
|
|
server = db.get(Server, server_id)
|
|
if server is None:
|
|
raise_api_error(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
code="server_not_found",
|
|
message="Requested server was not found.",
|
|
)
|
|
managed_service = db.scalar(
|
|
select(ManagedService).where(
|
|
ManagedService.server_id == server.id,
|
|
ManagedService.name == service_name,
|
|
)
|
|
)
|
|
if managed_service is None:
|
|
raise_api_error(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
code="service_not_found",
|
|
message="Requested managed service was not found.",
|
|
)
|
|
updated_service = control_service.update_managed_service(
|
|
db,
|
|
managed_service,
|
|
name=payload.name,
|
|
service_type=payload.service_type,
|
|
control_enabled=payload.control_enabled,
|
|
log_source=payload.log_source,
|
|
update_log_source="log_source" in payload.model_fields_set,
|
|
)
|
|
return control_service.get_managed_service(server, updated_service)
|
|
|
|
|
|
@router.post("/{server_id}/services/{service_name}/{action_name}", response_model=ActionRead)
|
|
def run_service_action(
|
|
server_id: int,
|
|
service_name: str,
|
|
action_name: str,
|
|
current_user: User = Depends(require_roles("admin", "operator")),
|
|
control_service: ServiceControlService = Depends(get_service_control_service),
|
|
db: Session = Depends(get_db),
|
|
) -> Action:
|
|
server = db.get(Server, server_id)
|
|
if server is None:
|
|
raise_api_error(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
code="server_not_found",
|
|
message="Requested server was not found.",
|
|
)
|
|
managed_service = db.scalar(
|
|
select(ManagedService).where(
|
|
ManagedService.server_id == server.id,
|
|
ManagedService.name == service_name,
|
|
)
|
|
)
|
|
if managed_service is None:
|
|
raise_api_error(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
code="service_not_found",
|
|
message="Requested managed service was not found.",
|
|
)
|
|
return control_service.run_service_action(
|
|
db,
|
|
server=server,
|
|
managed_service=managed_service,
|
|
action_name=action_name,
|
|
actor=current_user,
|
|
)
|
|
|
|
|
|
@router.get("/{server_id}/logs", response_model=ServerLogSourcesRead)
|
|
def list_server_logs(
|
|
server_id: int,
|
|
_: User = Depends(get_current_user),
|
|
log_service: LogService = Depends(get_log_service),
|
|
db: Session = Depends(get_db),
|
|
) -> ServerLogSourcesRead:
|
|
server = db.get(Server, server_id)
|
|
if server is None:
|
|
raise_api_error(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
code="server_not_found",
|
|
message="Requested server was not found.",
|
|
)
|
|
managed_services = list(
|
|
db.scalars(
|
|
select(ManagedService)
|
|
.where(ManagedService.server_id == server.id)
|
|
.order_by(ManagedService.name)
|
|
)
|
|
)
|
|
return log_service.list_log_sources(server, managed_services)
|
|
|
|
|
|
@router.get("/{server_id}/logs/{service_name}", response_model=ServerLogRead)
|
|
def get_server_logs(
|
|
server_id: int,
|
|
service_name: str,
|
|
_: User = Depends(get_current_user),
|
|
log_service: LogService = Depends(get_log_service),
|
|
db: Session = Depends(get_db),
|
|
lines: int = Query(default=100, ge=1, le=500),
|
|
) -> ServerLogRead:
|
|
server = db.get(Server, server_id)
|
|
if server is None:
|
|
raise_api_error(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
code="server_not_found",
|
|
message="Requested server was not found.",
|
|
)
|
|
managed_service = db.scalar(
|
|
select(ManagedService).where(
|
|
ManagedService.server_id == server.id,
|
|
ManagedService.name == service_name,
|
|
)
|
|
)
|
|
if managed_service is None:
|
|
raise_api_error(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
code="service_not_found",
|
|
message="Requested managed service was not found.",
|
|
)
|
|
return log_service.read_logs(
|
|
server=server,
|
|
managed_service=managed_service,
|
|
lines=lines,
|
|
)
|