agent
This commit is contained in:
2
agent/app/api/__init__.py
Normal file
2
agent/app/api/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
"""API routers for the Local Installer Agent."""
|
||||
|
||||
53
agent/app/api/apps.py
Normal file
53
agent/app/api/apps.py
Normal file
@@ -0,0 +1,53 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
|
||||
from fastapi import APIRouter, BackgroundTasks, HTTPException
|
||||
|
||||
from app.core.task_runner import TaskRunner
|
||||
from app.models.schemas import InstallRequest, RemoveRequest, UpdateRequest
|
||||
from app.storage.repository import Repository
|
||||
|
||||
|
||||
router = APIRouter(prefix="/apps", tags=["apps"])
|
||||
repository = Repository()
|
||||
task_runner = TaskRunner(repository)
|
||||
|
||||
|
||||
def _task_id(prefix: str) -> str:
|
||||
return f"task_{prefix}_{uuid.uuid4().hex[:12]}"
|
||||
|
||||
|
||||
@router.get("/installed")
|
||||
def installed_apps() -> list[dict]:
|
||||
return repository.list_installed_apps()
|
||||
|
||||
|
||||
@router.post("/install")
|
||||
def install_app(request: InstallRequest, background_tasks: BackgroundTasks) -> dict[str, str]:
|
||||
if not request.version:
|
||||
raise HTTPException(status_code=400, detail="version is required")
|
||||
task_id = _task_id("install")
|
||||
repository.create_task(task_id, "install", request.app_id, request.app_name)
|
||||
background_tasks.add_task(task_runner.run_install, task_id, request, "install")
|
||||
return {"taskId": task_id, "status": "queued"}
|
||||
|
||||
|
||||
@router.post("/update")
|
||||
def update_app(request: UpdateRequest, background_tasks: BackgroundTasks) -> dict[str, str]:
|
||||
if not request.version:
|
||||
raise HTTPException(status_code=400, detail="version or targetVersion is required")
|
||||
task_id = _task_id("update")
|
||||
repository.create_task(task_id, "update", request.app_id, request.app_name)
|
||||
background_tasks.add_task(task_runner.run_install, task_id, request, "update")
|
||||
return {"taskId": task_id, "status": "queued"}
|
||||
|
||||
|
||||
@router.post("/remove")
|
||||
def remove_app(request: RemoveRequest, background_tasks: BackgroundTasks) -> dict[str, str]:
|
||||
if not request.package_name and not repository.list_installed_components(request.app_id):
|
||||
raise HTTPException(status_code=400, detail="packageName is required when app is not tracked locally")
|
||||
task_id = _task_id("remove")
|
||||
repository.create_task(task_id, "remove", request.app_id, request.app_id)
|
||||
background_tasks.add_task(task_runner.run_remove, task_id, request)
|
||||
return {"taskId": task_id, "status": "queued"}
|
||||
38
agent/app/api/health.py
Normal file
38
agent/app/api/health.py
Normal file
@@ -0,0 +1,38 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import platform
|
||||
import shutil
|
||||
import socket
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
from app.config import settings
|
||||
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/health")
|
||||
def health() -> dict[str, str]:
|
||||
return {
|
||||
"status": "online",
|
||||
"agentVersion": settings.agent_version,
|
||||
"hostname": socket.gethostname(),
|
||||
"os": platform.platform(),
|
||||
"architecture": platform.machine(),
|
||||
}
|
||||
|
||||
|
||||
@router.get("/system-info")
|
||||
def system_info() -> dict[str, str]:
|
||||
disk = shutil.disk_usage("/")
|
||||
memory_total = "unknown"
|
||||
return {
|
||||
"hostname": socket.gethostname(),
|
||||
"os": platform.platform(),
|
||||
"kernel": platform.release(),
|
||||
"architecture": platform.machine(),
|
||||
"diskFree": f"{disk.free // (1024 ** 3)}GB",
|
||||
"memoryTotal": memory_total,
|
||||
}
|
||||
|
||||
40
agent/app/api/services.py
Normal file
40
agent/app/api/services.py
Normal file
@@ -0,0 +1,40 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
from app.core.command_runner import CommandRunner
|
||||
from app.core.service_manager import ServiceManager
|
||||
from app.models.schemas import ServiceRequest
|
||||
from app.storage.repository import Repository
|
||||
|
||||
|
||||
router = APIRouter(prefix="/services", tags=["services"])
|
||||
|
||||
|
||||
def _manager() -> ServiceManager:
|
||||
return ServiceManager(CommandRunner(Repository()))
|
||||
|
||||
|
||||
@router.post("/start")
|
||||
def start_service(request: ServiceRequest) -> dict[str, str]:
|
||||
_manager().start_service(request.service_name)
|
||||
return {"serviceName": request.service_name, "status": "started"}
|
||||
|
||||
|
||||
@router.post("/stop")
|
||||
def stop_service(request: ServiceRequest) -> dict[str, str]:
|
||||
_manager().stop_service(request.service_name)
|
||||
return {"serviceName": request.service_name, "status": "stopped"}
|
||||
|
||||
|
||||
@router.post("/restart")
|
||||
def restart_service(request: ServiceRequest) -> dict[str, str]:
|
||||
_manager().restart_service(request.service_name)
|
||||
return {"serviceName": request.service_name, "status": "restarted"}
|
||||
|
||||
|
||||
@router.get("/{service_name}/status")
|
||||
def service_status(service_name: str) -> dict[str, object]:
|
||||
request = ServiceRequest(serviceName=service_name)
|
||||
return _manager().get_service_status(request.service_name)
|
||||
|
||||
74
agent/app/api/tasks.py
Normal file
74
agent/app/api/tasks.py
Normal file
@@ -0,0 +1,74 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import APIRouter, HTTPException
|
||||
|
||||
from app.storage.repository import Repository
|
||||
|
||||
|
||||
router = APIRouter(prefix="/tasks", tags=["tasks"])
|
||||
repository = Repository()
|
||||
|
||||
|
||||
def _task_response(row: dict) -> dict:
|
||||
return {
|
||||
"taskId": row["id"],
|
||||
"type": row["type"],
|
||||
"appId": row["app_id"],
|
||||
"appName": row["app_name"],
|
||||
"status": row["status"],
|
||||
"progress": row["progress"],
|
||||
"currentStep": row["current_step"],
|
||||
"currentComponentId": row["current_component_id"],
|
||||
"errorMessage": row["error_message"],
|
||||
"createdAt": row["created_at"],
|
||||
"startedAt": row["started_at"],
|
||||
"finishedAt": row["finished_at"],
|
||||
}
|
||||
|
||||
|
||||
@router.get("/{task_id}")
|
||||
def get_task(task_id: str) -> dict:
|
||||
task = repository.get_task(task_id)
|
||||
if not task:
|
||||
raise HTTPException(status_code=404, detail="Task not found")
|
||||
return _task_response(task)
|
||||
|
||||
|
||||
@router.get("/{task_id}/logs")
|
||||
def get_task_logs(task_id: str) -> dict:
|
||||
if not repository.get_task(task_id):
|
||||
raise HTTPException(status_code=404, detail="Task not found")
|
||||
return {
|
||||
"taskId": task_id,
|
||||
"logs": [
|
||||
{
|
||||
"time": item["timestamp"],
|
||||
"level": item["level"],
|
||||
"message": item["message"],
|
||||
}
|
||||
for item in repository.get_task_logs(task_id)
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@router.get("/{task_id}/components")
|
||||
def get_task_components(task_id: str) -> dict:
|
||||
if not repository.get_task(task_id):
|
||||
raise HTTPException(status_code=404, detail="Task not found")
|
||||
return {
|
||||
"taskId": task_id,
|
||||
"components": [
|
||||
{
|
||||
"componentId": item["component_id"],
|
||||
"type": item["type"],
|
||||
"status": item["status"],
|
||||
"progress": item["progress"],
|
||||
"currentStep": item["current_step"],
|
||||
"errorMessage": item["error_message"],
|
||||
"startedAt": item["started_at"],
|
||||
"finishedAt": item["finished_at"],
|
||||
}
|
||||
for item in repository.get_task_components(task_id)
|
||||
],
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user