mirror of
https://framagit.org/framasoft/framaspace/argos.git
synced 2025-04-28 18:02:41 +02:00
Allow exceptions for advanced checks.
- See more information about this in #7
This commit is contained in:
parent
e20b1fcabe
commit
0e08bc8be6
6 changed files with 76 additions and 15 deletions
|
@ -44,7 +44,7 @@ class ArgosAgent:
|
||||||
}
|
}
|
||||||
self._http_client = httpx.AsyncClient(headers=headers)
|
self._http_client = httpx.AsyncClient(headers=headers)
|
||||||
async with self._http_client:
|
async with self._http_client:
|
||||||
while True:
|
while "forever":
|
||||||
retry_now = await self._get_and_complete_tasks()
|
retry_now = await self._get_and_complete_tasks()
|
||||||
if not retry_now:
|
if not retry_now:
|
||||||
logger.error(f"Waiting {self.wait_time} seconds before next retry")
|
logger.error(f"Waiting {self.wait_time} seconds before next retry")
|
||||||
|
|
|
@ -105,7 +105,7 @@ class BaseCheck:
|
||||||
- All ERRORS should be reported as CRITICAL.
|
- All ERRORS should be reported as CRITICAL.
|
||||||
|
|
||||||
This behaviour can be changed in each check, by defining the `finalize` method.
|
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):
|
if result.status in (Status.SUCCESS, Status.ERROR):
|
||||||
return result.status, Severity.OK
|
return result.status, Severity.OK
|
||||||
|
|
|
@ -60,13 +60,21 @@ class SSLCertificateExpiration(BaseCheck):
|
||||||
return self.response(status=Status.ON_CHECK, expires_in=expires_in)
|
return self.response(status=Status.ON_CHECK, expires_in=expires_in)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def finalize(cls, config, result, expires_in):
|
async def finalize(cls, config, result, **context):
|
||||||
thresholds = config.ssl.thresholds
|
if result.status != Status.ON_CHECK:
|
||||||
thresholds.sort()
|
return result.status, Severity.WARNING
|
||||||
for days, severity in thresholds:
|
elif "expires_in" in context:
|
||||||
if expires_in < days:
|
thresholds = config.ssl.thresholds
|
||||||
return Status.FAILURE, severity
|
thresholds.sort()
|
||||||
return Status.SUCCESS, Severity.OK
|
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
|
@classmethod
|
||||||
def get_description(cls, config):
|
def get_description(cls, config):
|
||||||
|
|
|
@ -44,7 +44,6 @@ async def create_results(
|
||||||
for agent_result in results:
|
for agent_result in results:
|
||||||
result = await queries.create_result(db, agent_result, agent_id)
|
result = await queries.create_result(db, agent_result, agent_id)
|
||||||
# XXX Maybe offload this to a queue.
|
# 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
|
# XXX Get all the tasks at once, to limit the queries on the db
|
||||||
task = await queries.get_task(db, agent_result.task_id)
|
task = await queries.get_task(db, agent_result.task_id)
|
||||||
if not task:
|
if not task:
|
||||||
|
|
|
@ -2,6 +2,7 @@ import os
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
from fastapi.testclient import TestClient
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
os.environ["ARGOS_APP_ENV"] = "test"
|
os.environ["ARGOS_APP_ENV"] = "test"
|
||||||
|
@ -27,6 +28,14 @@ def app() -> FastAPI:
|
||||||
models.Base.metadata.drop_all(bind=app.state.engine)
|
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:
|
def _create_app() -> FastAPI:
|
||||||
from argos.server.main import ( # local import for testing purpose
|
from argos.server.main import ( # local import for testing purpose
|
||||||
get_application,
|
get_application,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
import pytest
|
||||||
from fastapi.testclient import TestClient
|
from fastapi.testclient import TestClient
|
||||||
|
|
||||||
from argos.schemas import AgentResult
|
from argos.schemas import AgentResult, SerializableException
|
||||||
from argos.server import models
|
from argos.server import models
|
||||||
|
|
||||||
|
|
||||||
|
@ -10,10 +11,8 @@ def test_read_tasks_requires_auth(app):
|
||||||
assert response.status_code == 403
|
assert response.status_code == 403
|
||||||
|
|
||||||
|
|
||||||
def test_tasks_retrieval_and_results(app):
|
def test_tasks_retrieval_and_results(authorized_client, app):
|
||||||
with TestClient(app) as client:
|
with authorized_client as client:
|
||||||
token = app.state.config.service.secrets[0]
|
|
||||||
client.headers = {"Authorization": f"Bearer {token}"}
|
|
||||||
response = client.get("/api/tasks")
|
response = client.get("/api/tasks")
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
@ -35,3 +34,49 @@ def test_tasks_retrieval_and_results(app):
|
||||||
# The list of tasks should be empty now
|
# The list of tasks should be empty now
|
||||||
response = client.get("/api/tasks")
|
response = client.get("/api/tasks")
|
||||||
assert len(response.json()) == 0
|
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
|
||||||
|
|
Loading…
Reference in a new issue