mirror of
https://framagit.org/framasoft/framaspace/argos.git
synced 2025-04-28 18:02:41 +02:00
Support !include filename
in the yaml files.
- run isort on the codebase
This commit is contained in:
parent
cdfb1e30ac
commit
d35be89f4b
17 changed files with 76 additions and 132 deletions
1
Pipfile
1
Pipfile
|
@ -15,6 +15,7 @@ sqlalchemy = {extras = ["asyncio"] }
|
||||||
pyopenssl = "*"
|
pyopenssl = "*"
|
||||||
ipdb = "*"
|
ipdb = "*"
|
||||||
argos = {extras = ["dev"], file = ".", editable = true}
|
argos = {extras = ["dev"], file = ".", editable = true}
|
||||||
|
pyyaml-include = "*"
|
||||||
|
|
||||||
[dev-packages]
|
[dev-packages]
|
||||||
|
|
||||||
|
|
11
Pipfile.lock
generated
11
Pipfile.lock
generated
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"_meta": {
|
"_meta": {
|
||||||
"hash": {
|
"hash": {
|
||||||
"sha256": "545ec239a057ec56cb3b4e5d7d6b8922a837d9ce2340e4b2def368c8064acf73"
|
"sha256": "8cc9237ff86d00019539f36e3df5b20edcbbc60f52d1b0fce2b03e51c089ad39"
|
||||||
},
|
},
|
||||||
"pipfile-spec": 6,
|
"pipfile-spec": 6,
|
||||||
"requires": {
|
"requires": {
|
||||||
|
@ -669,6 +669,15 @@
|
||||||
"markers": "python_version >= '3.6'",
|
"markers": "python_version >= '3.6'",
|
||||||
"version": "==6.0.1"
|
"version": "==6.0.1"
|
||||||
},
|
},
|
||||||
|
"pyyaml-include": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:4cb3b4e1baae2ec251808fe1e8aed5d3d20699c541864c8e47ed866ab2f15039",
|
||||||
|
"sha256:e58525721a2938d29c4046350f8aad86f848660a770c29605e6f2700925fa753"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"markers": "python_version >= '3.7'",
|
||||||
|
"version": "==1.3.1"
|
||||||
|
},
|
||||||
"six": {
|
"six": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
|
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import httpx
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from typing import List
|
from typing import List
|
||||||
from argos.logging import logger
|
|
||||||
from argos.checks import CheckNotFound, get_registered_check
|
|
||||||
|
|
||||||
from argos.schemas import Task, AgentResult, SerializableException
|
import httpx
|
||||||
|
|
||||||
|
from argos.checks import CheckNotFound, get_registered_check
|
||||||
|
from argos.logging import logger
|
||||||
|
from argos.schemas import AgentResult, SerializableException, Task
|
||||||
|
|
||||||
|
|
||||||
async def complete_task(http_client: httpx.AsyncClient, task: dict) -> dict:
|
async def complete_task(http_client: httpx.AsyncClient, task: dict) -> dict:
|
||||||
|
@ -58,4 +59,4 @@ async def run_agent(server: str, auth: str, max_tasks: int):
|
||||||
# Post the results
|
# Post the results
|
||||||
await post_results(http_client, server, results)
|
await post_results(http_client, server, results)
|
||||||
else:
|
else:
|
||||||
logger.error(f"Failed to fetch tasks: {response.read()}")
|
logger.error(f"Failed to fetch tasks: {response.read()}")
|
||||||
|
|
|
@ -1,2 +1,4 @@
|
||||||
from argos.checks.checks import HTTPStatus, HTTPBodyContains, SSLCertificateExpiration
|
from argos.checks.base import (CheckNotFound, get_registered_check,
|
||||||
from argos.checks.base import get_registered_checks, get_registered_check, CheckNotFound
|
get_registered_checks)
|
||||||
|
from argos.checks.checks import (HTTPBodyContains, HTTPStatus,
|
||||||
|
SSLCertificateExpiration)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
from pydantic import BaseModel, Field
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
from typing import Type
|
from typing import Type
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
from argos.schemas import Task
|
from argos.schemas import Task
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,13 @@
|
||||||
from argos.logging import logger
|
|
||||||
from argos.checks.base import (
|
|
||||||
BaseCheck,
|
|
||||||
Response,
|
|
||||||
Status,
|
|
||||||
ExpectedIntValue,
|
|
||||||
ExpectedStringValue,
|
|
||||||
)
|
|
||||||
import ssl
|
import ssl
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from OpenSSL import crypto
|
from OpenSSL import crypto
|
||||||
|
|
||||||
|
from argos.checks.base import (BaseCheck, ExpectedIntValue,
|
||||||
|
ExpectedStringValue, Response, Status)
|
||||||
|
from argos.logging import logger
|
||||||
|
|
||||||
|
|
||||||
class HTTPStatus(BaseCheck):
|
class HTTPStatus(BaseCheck):
|
||||||
config = "status-is"
|
config = "status-is"
|
||||||
|
|
|
@ -1,15 +1,18 @@
|
||||||
import click
|
|
||||||
import subprocess
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
from argos.agent import run_agent
|
|
||||||
from argos import logging
|
from argos import logging
|
||||||
|
from argos.agent import run_agent
|
||||||
from argos.logging import logger
|
from argos.logging import logger
|
||||||
|
|
||||||
|
|
||||||
@click.group()
|
@click.group()
|
||||||
def cli():
|
def cli():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option("--server", required=True, help="Server URL")
|
@click.option("--server", required=True, help="Server URL")
|
||||||
@click.option("--auth", required=True, help="The authentication token")
|
@click.option("--auth", required=True, help="The authentication token")
|
||||||
|
@ -36,5 +39,6 @@ def server(host, port, reload):
|
||||||
command.append("--reload")
|
command.append("--reload")
|
||||||
subprocess.run(command)
|
subprocess.run(command)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
cli()
|
cli()
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
from pydantic import BaseModel
|
import os
|
||||||
|
from datetime import datetime
|
||||||
from enum import StrEnum
|
from enum import StrEnum
|
||||||
from typing import List, Optional, Tuple, Literal
|
from typing import Dict, List, Literal, Optional, Tuple, Union
|
||||||
|
|
||||||
from typing import Dict, Union, List
|
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
from pydantic import BaseModel, Field, HttpUrl, validator
|
from pydantic import BaseModel, Field, HttpUrl, validator
|
||||||
|
from yamlinclude import YamlIncludeConstructor
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
# XXX Find a way to check without having cirular imports
|
# XXX Find a way to check without having cirular imports
|
||||||
|
|
||||||
|
@ -66,7 +63,8 @@ class WebsitePath(BaseModel):
|
||||||
|
|
||||||
@validator("checks", each_item=True, pre=True)
|
@validator("checks", each_item=True, pre=True)
|
||||||
def parse_checks(cls, value):
|
def parse_checks(cls, value):
|
||||||
from argos.checks import get_registered_checks # To avoid circular imports
|
from argos.checks import \
|
||||||
|
get_registered_checks # To avoid circular imports
|
||||||
|
|
||||||
available_names = get_registered_checks().keys()
|
available_names = get_registered_checks().keys()
|
||||||
|
|
||||||
|
@ -109,11 +107,16 @@ def validate_config(config: dict):
|
||||||
return Config(**config)
|
return Config(**config)
|
||||||
|
|
||||||
|
|
||||||
def from_yaml(file_name):
|
def from_yaml(filename):
|
||||||
parsed = load_yaml(file_name)
|
parsed = load_yaml(filename)
|
||||||
return validate_config(parsed)
|
return validate_config(parsed)
|
||||||
|
|
||||||
|
|
||||||
def load_yaml(file_name):
|
def load_yaml(filename):
|
||||||
with open(file_name, "r") as stream:
|
base_dir = os.path.dirname(filename)
|
||||||
return yaml.safe_load(stream)
|
YamlIncludeConstructor.add_to_loader_class(
|
||||||
|
loader_class=yaml.FullLoader, base_dir=base_dir
|
||||||
|
)
|
||||||
|
|
||||||
|
with open(filename, "r") as stream:
|
||||||
|
return yaml.load(stream, Loader=yaml.FullLoader)
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
from pydantic import BaseModel
|
import traceback
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Literal
|
from typing import Literal
|
||||||
import traceback
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
# XXX Refactor using SQLModel to avoid duplication of model data
|
# XXX Refactor using SQLModel to avoid duplication of model data
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import sys
|
import sys
|
||||||
from typing import Annotated, List, Optional
|
from typing import Annotated, List, Optional
|
||||||
|
|
||||||
from fastapi import Depends, FastAPI, HTTPException, Request, Header
|
from fastapi import Depends, FastAPI, Header, HTTPException, Request
|
||||||
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
|
||||||
from pydantic import BaseModel, ValidationError
|
from pydantic import BaseModel, ValidationError
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ async def read_tasks(request: Request, db: Session = Depends(get_db), limit: int
|
||||||
return tasks
|
return tasks
|
||||||
|
|
||||||
|
|
||||||
@app.post("/results", status_code=201)
|
@app.post("/results", status_code=201, dependencies=[Depends(verify_token)])
|
||||||
async def create_result(results: List[AgentResult], db: Session = Depends(get_db)):
|
async def create_result(results: List[AgentResult], db: Session = Depends(get_db)):
|
||||||
"""Get the results from the agents and store them locally.
|
"""Get the results from the agents and store them locally.
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ async def create_result(results: List[AgentResult], db: Session = Depends(get_db
|
||||||
return {"result_ids": [r.id for r in db_results]}
|
return {"result_ids": [r.id for r in db_results]}
|
||||||
|
|
||||||
|
|
||||||
@app.get("/stats")
|
@app.get("/stats", dependencies=[Depends(verify_token)])
|
||||||
async def get_stats(db: Session = Depends(get_db)):
|
async def get_stats(db: Session = Depends(get_db)):
|
||||||
return {
|
return {
|
||||||
"tasks_count": await queries.count_tasks(db),
|
"tasks_count": await queries.count_tasks(db),
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
from sqlalchemy import create_engine
|
from sqlalchemy import create_engine
|
||||||
from sqlalchemy.orm import DeclarativeBase
|
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
|
||||||
from sqlalchemy.orm import sessionmaker
|
from sqlalchemy.orm import DeclarativeBase, sessionmaker
|
||||||
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
|
|
||||||
|
|
||||||
|
|
||||||
SQLALCHEMY_DATABASE_URL = "sqlite:////tmp/argos.db"
|
SQLALCHEMY_DATABASE_URL = "sqlite:////tmp/argos.db"
|
||||||
# SQLALCHEMY_DATABASE_URL = "postgresql://user:password@postgresserver/db"
|
# SQLALCHEMY_DATABASE_URL = "postgresql://user:password@postgresserver/db"
|
||||||
|
|
|
@ -1,22 +1,13 @@
|
||||||
from typing import List, Literal
|
|
||||||
from sqlalchemy import (
|
|
||||||
Boolean,
|
|
||||||
Column,
|
|
||||||
ForeignKey,
|
|
||||||
Integer,
|
|
||||||
String,
|
|
||||||
JSON,
|
|
||||||
DateTime,
|
|
||||||
Enum,
|
|
||||||
)
|
|
||||||
from sqlalchemy.orm import relationship, Mapped, mapped_column, DeclarativeBase
|
|
||||||
from sqlalchemy_utils import ChoiceType
|
|
||||||
from sqlalchemy.orm import mapped_column, relationship
|
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from typing import List, Literal
|
||||||
|
|
||||||
|
from sqlalchemy import (JSON, Boolean, Column, DateTime, Enum, ForeignKey,
|
||||||
|
Integer, String)
|
||||||
|
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
|
||||||
|
from sqlalchemy_utils import ChoiceType
|
||||||
|
|
||||||
from argos.schemas import WebsiteCheck
|
|
||||||
from argos.checks import get_registered_check
|
from argos.checks import get_registered_check
|
||||||
|
from argos.schemas import WebsiteCheck
|
||||||
|
|
||||||
|
|
||||||
class Base(DeclarativeBase):
|
class Base(DeclarativeBase):
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
from sqlalchemy.orm import Session
|
from datetime import datetime
|
||||||
|
from urllib.parse import urljoin
|
||||||
|
|
||||||
from sqlalchemy import exists
|
from sqlalchemy import exists
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from argos import schemas
|
from argos import schemas
|
||||||
from argos.logging import logger
|
from argos.logging import logger
|
||||||
from argos.server.models import Task, Result
|
from argos.server.models import Result, Task
|
||||||
|
|
||||||
from urllib.parse import urljoin
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
|
|
||||||
async def list_tasks(db: Session, agent_id: str, limit: int = 100):
|
async def list_tasks(db: Session, agent_id: str, limit: int = 100):
|
||||||
|
|
67
config.yaml
67
config.yaml
|
@ -19,69 +19,4 @@ ssl:
|
||||||
- "1d": critical
|
- "1d": critical
|
||||||
"5d": warning
|
"5d": warning
|
||||||
|
|
||||||
websites:
|
websites: !include websites.yaml
|
||||||
- domain: "https://mypads.framapad.org"
|
|
||||||
paths:
|
|
||||||
- path: "/mypads/"
|
|
||||||
checks:
|
|
||||||
- status-is: 200
|
|
||||||
- body-contains: '<div id= "mypads"></div>'
|
|
||||||
- ssl-certificate-expiration: "on-check"
|
|
||||||
- path: "/admin/"
|
|
||||||
checks:
|
|
||||||
- status-is: 401
|
|
||||||
- domain: "https://munin.framasoft.org"
|
|
||||||
paths:
|
|
||||||
- path: "/"
|
|
||||||
checks:
|
|
||||||
- status-is: 301
|
|
||||||
- path: "/munin/"
|
|
||||||
checks:
|
|
||||||
- status-is: 401
|
|
||||||
- domain: "https://framagenda.org"
|
|
||||||
paths:
|
|
||||||
- path: "/status.php"
|
|
||||||
checks:
|
|
||||||
- status-is: 200
|
|
||||||
# Là, idéalement, il faudrait un json-contains,
|
|
||||||
# qui serait une table de hachage
|
|
||||||
- body-contains: '"maintenance":false'
|
|
||||||
- ssl-certificate-expiration: "on-check"
|
|
||||||
- path: "/"
|
|
||||||
checks:
|
|
||||||
- status-is: 302
|
|
||||||
- path: "/login"
|
|
||||||
checks:
|
|
||||||
- status-is: 200
|
|
||||||
- domain: "https://framadrive.org"
|
|
||||||
paths:
|
|
||||||
- path: "/status.php"
|
|
||||||
checks:
|
|
||||||
- status-is: 200
|
|
||||||
- body-contains: '"maintenance":false'
|
|
||||||
- ssl-certificate-expiration: "on-check"
|
|
||||||
- path: "/"
|
|
||||||
checks:
|
|
||||||
- status-is: 302
|
|
||||||
- path: "/login"
|
|
||||||
checks:
|
|
||||||
- status-is: 200
|
|
||||||
- domain: "https://cloud.framabook.org"
|
|
||||||
paths:
|
|
||||||
- path: "/status.php"
|
|
||||||
checks:
|
|
||||||
- status-is: 200
|
|
||||||
- body-contains: '"maintenance":false'
|
|
||||||
- ssl-certificate-expiration: "on-check"
|
|
||||||
- path: "/"
|
|
||||||
checks:
|
|
||||||
- status-is: 302
|
|
||||||
- path: "/login"
|
|
||||||
checks:
|
|
||||||
- status-is: 200
|
|
||||||
- domain: "https://framasoft.org"
|
|
||||||
paths:
|
|
||||||
- path: "/"
|
|
||||||
checks:
|
|
||||||
- status-is: 200
|
|
||||||
- ssl-certificate-expiration: "on-check"
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ dependencies = [
|
||||||
"httpx>=0.25,<1",
|
"httpx>=0.25,<1",
|
||||||
"pydantic>=2.4,<3",
|
"pydantic>=2.4,<3",
|
||||||
"pyyaml>=6.0,<7",
|
"pyyaml>=6.0,<7",
|
||||||
|
"pyyaml-include>=1.3,<2",
|
||||||
"sqlalchemy[asyncio]>=2.0,<3",
|
"sqlalchemy[asyncio]>=2.0,<3",
|
||||||
"sqlalchemy-utils>=0.41,<1",
|
"sqlalchemy-utils>=0.41,<1",
|
||||||
"uvicorn>=0.23,<1",
|
"uvicorn>=0.23,<1",
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from argos.checks.base import Response, Status
|
from argos.checks.base import Response, Status
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from argos.schemas.config import SSL, WebsitePath
|
from argos.schemas.config import SSL, WebsitePath
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue