argos/argos/server/api.py
Alexis Métaireau 42ec15c6f4 Working SSL checks, refactoring of the codebase.
- Start implementing some tests using pytest
- Packaged using pyproject.toml
- Implemented SSL checks using httpx
- Checks can now run partially on the server, to access the configuration and determine the severity of the error if any
- Used black to format all the files
- Added an utility to convert strings like "3d" and "3w" to days
- The internal representation of SSL thresholds is now a list of tuples
- Models were lacking some relationship between Tasks and Results
2023-10-09 19:33:58 +02:00

88 lines
2.8 KiB
Python

from fastapi import Depends, FastAPI, HTTPException, Request
from sqlalchemy.orm import Session
from pydantic import BaseModel, ValidationError
import sys
from argos.server import queries, models
from argos.schemas import AgentResult, Task
from argos.schemas.config import from_yaml as get_schemas_from_yaml
from argos.server.database import SessionLocal, engine
from argos.checks import get_check_by_name
from argos.logging import logger
from typing import List
models.Base.metadata.create_all(bind=engine)
app = FastAPI()
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
@app.on_event("startup")
async def read_config_and_populate_db():
# XXX Get filename from environment.
try:
config = get_schemas_from_yaml("config.yaml")
app.config = config
except ValidationError as e:
logger.error(f"Errors where found while reading configuration:")
for error in e.errors():
logger.error(f"{error['loc']} is {error['type']}")
sys.exit(1)
db = SessionLocal()
try:
await queries.update_from_config(db, config)
finally:
db.close()
# XXX Get the default limit from the config
@app.get("/tasks", response_model=list[Task])
async def read_tasks(request: Request, limit: int = 20, db: Session = Depends(get_db)):
# XXX Let the agents specifify their names (and use hostnames)
tasks = await queries.list_tasks(db, agent_id=request.client.host, limit=limit)
return tasks
@app.post("/results", status_code=201)
async def create_result(results: List[AgentResult], db: Session = Depends(get_db)):
"""Get the results from the agents and store them locally.
- Finalize the checks (some checks need the server to do some part of the validation,
for instance because they need access to the configuration)
- If it's an error, determine its severity ;
- Trigger the reporting calls
"""
db_results = []
for agent_result in results:
result = await queries.create_result(db, agent_result)
# XXX Maybe offload this to a queue.
# XXX Use a schema for the on-check value.
if result.status == "on-check":
task = await queries.get_task(db, agent_result.task_id)
if not task:
logger.error(f"Unable to find task {agent_result.task_id}")
else:
check = task.get_check()
callback = logger.error
await check.finalize(app.config, callback=callback, **result.context)
db_results.append(result)
db.commit()
return {"result_ids": [r.id for r in db_results]}
@app.get("/stats")
async def get_stats(db: Session = Depends(get_db)):
return {
"tasks_count": await queries.count_tasks(db),
"results_count": await queries.count_results(db),
}