Allow exceptions for advanced checks.

- See more information about this in #7
This commit is contained in:
Alexis Métaireau 2023-10-30 11:48:39 +01:00
parent e20b1fcabe
commit 0e08bc8be6
6 changed files with 76 additions and 15 deletions

View file

@ -44,7 +44,7 @@ class ArgosAgent:
}
self._http_client = httpx.AsyncClient(headers=headers)
async with self._http_client:
while True:
while "forever":
retry_now = await self._get_and_complete_tasks()
if not retry_now:
logger.error(f"Waiting {self.wait_time} seconds before next retry")

View file

@ -105,7 +105,7 @@ class BaseCheck:
- All ERRORS should be reported as CRITICAL.
This behaviour can be changed in each check, by defining the `finalize` method.
XXX This can also be tweaked by the config.
XXX Allow this to be tweaked by the config.
"""
if result.status in (Status.SUCCESS, Status.ERROR):
return result.status, Severity.OK

View file

@ -60,13 +60,21 @@ class SSLCertificateExpiration(BaseCheck):
return self.response(status=Status.ON_CHECK, expires_in=expires_in)
@classmethod
async def finalize(cls, config, result, expires_in):
thresholds = config.ssl.thresholds
thresholds.sort()
for days, severity in thresholds:
if expires_in < days:
return Status.FAILURE, severity
return Status.SUCCESS, Severity.OK
async def finalize(cls, config, result, **context):
if result.status != Status.ON_CHECK:
return result.status, Severity.WARNING
elif "expires_in" in context:
thresholds = config.ssl.thresholds
thresholds.sort()
for days, severity in thresholds:
if context["expires_in"] < days:
return Status.FAILURE, severity
return Status.SUCCESS, Severity.OK
else:
raise ValueError(
"The SSLCertificateExpiration check didn't provide an 'expires_in' "
"context variable."
)
@classmethod
def get_description(cls, config):

View file

@ -44,7 +44,6 @@ async def create_results(
for agent_result in results:
result = await queries.create_result(db, agent_result, agent_id)
# XXX Maybe offload this to a queue.
# XXX Use a schema for the on-check value.
# XXX Get all the tasks at once, to limit the queries on the db
task = await queries.get_task(db, agent_result.task_id)
if not task:

View file

@ -2,6 +2,7 @@ import os
import pytest
from fastapi import FastAPI
from fastapi.testclient import TestClient
from sqlalchemy.orm import Session
os.environ["ARGOS_APP_ENV"] = "test"
@ -27,6 +28,14 @@ def app() -> FastAPI:
models.Base.metadata.drop_all(bind=app.state.engine)
@pytest.fixture
def authorized_client(app):
with TestClient(app) as client:
token = app.state.config.service.secrets[0]
client.headers = {"Authorization": f"Bearer {token}"}
yield client
def _create_app() -> FastAPI:
from argos.server.main import ( # local import for testing purpose
get_application,

View file

@ -1,6 +1,7 @@
import pytest
from fastapi.testclient import TestClient
from argos.schemas import AgentResult
from argos.schemas import AgentResult, SerializableException
from argos.server import models
@ -10,10 +11,8 @@ def test_read_tasks_requires_auth(app):
assert response.status_code == 403
def test_tasks_retrieval_and_results(app):
with TestClient(app) as client:
token = app.state.config.service.secrets[0]
client.headers = {"Authorization": f"Bearer {token}"}
def test_tasks_retrieval_and_results(authorized_client, app):
with authorized_client as client:
response = client.get("/api/tasks")
assert response.status_code == 200
@ -35,3 +34,49 @@ def test_tasks_retrieval_and_results(app):
# The list of tasks should be empty now
response = client.get("/api/tasks")
assert len(response.json()) == 0
def test_agents_can_report_errors(authorized_client):
with authorized_client as client:
exc = Exception("This is an error")
serialized_exc = SerializableException.from_exception(exc)
agent_result = AgentResult(task_id=1, status="error", context=serialized_exc)
response = client.post(
"/api/results",
json=[
agent_result.model_dump(),
],
)
assert response.status_code == 201
@pytest.fixture
def ssl_task(db):
task = models.Task(
url="https://exemple.com/",
domain="https://exemple.com/",
check="ssl-certificate-expiration",
expected="on-check",
frequency=1,
)
db.add(task)
db.commit()
return task
def test_specialized_checks_can_report_errors(authorized_client, ssl_task):
with authorized_client as client:
exc = Exception("This is an error")
serialized_exc = SerializableException.from_exception(exc)
agent_result = AgentResult(
task_id=ssl_task.id, status="error", context=serialized_exc
)
response = client.post(
"/api/results",
json=[
agent_result.model_dump(),
],
)
assert response.status_code == 201