diff --git a/pkgs/clan-cli/clan_cli/config/machine.py b/pkgs/clan-cli/clan_cli/config/machine.py index 754b5380f..694c218ed 100644 --- a/pkgs/clan-cli/clan_cli/config/machine.py +++ b/pkgs/clan-cli/clan_cli/config/machine.py @@ -6,14 +6,8 @@ from pathlib import Path from tempfile import NamedTemporaryFile from typing import Optional -from fastapi import HTTPException - -from clan_cli.dirs import ( - machine_settings_file, - nixpkgs_source, - specific_machine_dir, -) -from clan_cli.errors import ClanError +from clan_cli.dirs import machine_settings_file, nixpkgs_source, specific_machine_dir +from clan_cli.errors import ClanError, ClanHttpError from clan_cli.git import commit_file from clan_cli.nix import nix_eval @@ -83,9 +77,9 @@ def verify_machine_config( def config_for_machine(flake_dir: Path, machine_name: str) -> dict: # read the config from a json file located at {flake}/machines/{machine_name}/settings.json if not specific_machine_dir(flake_dir, machine_name).exists(): - raise HTTPException( + raise ClanHttpError( + msg=f"Machine {machine_name} not found. Create the machine first`", status_code=404, - detail=f"Machine {machine_name} not found. Create the machine first`", ) settings_path = machine_settings_file(flake_dir, machine_name) if not settings_path.exists(): @@ -100,9 +94,9 @@ def set_config_for_machine(flake_dir: Path, machine_name: str, config: dict) -> raise ClanError("Machine name must be a valid hostname") if "networking" in config and "hostName" in config["networking"]: if machine_name != config["networking"]["hostName"]: - raise HTTPException( + raise ClanHttpError( + msg="Machine name does not match the 'networking.hostName' setting in the config", status_code=400, - detail="Machine name does not match the 'networking.hostName' setting in the config", ) config["networking"]["hostName"] = machine_name # create machine folder if it doesn't exist diff --git a/pkgs/clan-cli/clan_cli/config/schema.py b/pkgs/clan-cli/clan_cli/config/schema.py index 5d0ac6b3c..2a7a71c31 100644 --- a/pkgs/clan-cli/clan_cli/config/schema.py +++ b/pkgs/clan-cli/clan_cli/config/schema.py @@ -6,12 +6,8 @@ from pathlib import Path from tempfile import NamedTemporaryFile from typing import Optional -from fastapi import HTTPException - -from clan_cli.dirs import ( - nixpkgs_source, -) -from clan_cli.errors import ClanError +from clan_cli.dirs import nixpkgs_source +from clan_cli.errors import ClanError, ClanHttpError from clan_cli.nix import nix_eval @@ -59,17 +55,14 @@ def machine_schema( ) if proc.returncode != 0: print(proc.stderr, file=sys.stderr) - raise ClanError( - f"Failed to check clanImports for existence:\n{proc.stderr}" + raise ClanHttpError( + status_code=400, + msg=f"Failed to check clanImports for existence:\n{proc.stderr}", ) modules_not_found = json.loads(proc.stdout) if len(modules_not_found) > 0: - raise HTTPException( - status_code=400, - detail={ - "msg": "Some requested clan modules could not be found", - "modules_not_found": modules_not_found, - }, + raise ClanHttpError( + msg="Some requested clan modules could not be found", status_code=400 ) # get the schema diff --git a/pkgs/clan-cli/clan_cli/errors.py b/pkgs/clan-cli/clan_cli/errors.py index 32a26df9a..8f2591ef5 100644 --- a/pkgs/clan-cli/clan_cli/errors.py +++ b/pkgs/clan-cli/clan_cli/errors.py @@ -2,3 +2,13 @@ class ClanError(Exception): """Base class for exceptions in this module.""" pass + + +class ClanHttpError(ClanError): + status_code: int + msg: str + + def __init__(self, status_code: int, msg: str): + self.status_code = status_code + self.msg = msg + super().__init__(msg) diff --git a/pkgs/clan-cli/clan_cli/webui/error_handlers.py b/pkgs/clan-cli/clan_cli/webui/error_handlers.py index 4f815999b..c8e242679 100644 --- a/pkgs/clan-cli/clan_cli/webui/error_handlers.py +++ b/pkgs/clan-cli/clan_cli/webui/error_handlers.py @@ -4,7 +4,7 @@ from fastapi import Request, status from fastapi.encoders import jsonable_encoder from fastapi.responses import JSONResponse -from ..errors import ClanError +from ..errors import ClanError, ClanHttpError from .settings import settings log = logging.getLogger(__name__) @@ -17,7 +17,13 @@ def clan_error_handler(request: Request, exc: Exception) -> JSONResponse: headers["Access-Control-Allow-Origin"] = "*" headers["Access-Control-Allow-Methods"] = "*" - if isinstance(exc, ClanError): + if isinstance(exc, ClanHttpError): + return JSONResponse( + status_code=exc.status_code, + content=jsonable_encoder(dict(detail={"msg": exc.msg})), + headers=headers, + ) + elif isinstance(exc, ClanError): log.error(f"ClanError: {exc}") detail = [ { diff --git a/pkgs/clan-cli/default.nix b/pkgs/clan-cli/default.nix index 0261367e8..8a55c011e 100644 --- a/pkgs/clan-cli/default.nix +++ b/pkgs/clan-cli/default.nix @@ -43,11 +43,12 @@ let dependencies = [ argcomplete # optional dependency: if not enabled, shell completion will not work - fastapi - uvicorn # optional dependencies: if not enabled, webui subcommand will not work ]; pytestDependencies = runtimeDependencies ++ dependencies ++ [ + fastapi # optional dependencies: if not enabled, webui subcommand will not work + uvicorn # optional dependencies: if not enabled, webui subcommand will not work + #schemathesis # optional for http fuzzing pytest pytest-cov diff --git a/pkgs/clan-cli/tests/test_machines_api.py b/pkgs/clan-cli/tests/test_machines_api.py index eb6dbd69b..f11ceedd0 100644 --- a/pkgs/clan-cli/tests/test_machines_api.py +++ b/pkgs/clan-cli/tests/test_machines_api.py @@ -48,7 +48,6 @@ def test_schema_invalid_clan_imports( "Some requested clan modules could not be found" in response.json()["detail"]["msg"] ) - assert "non-existing-clan-module" in response.json()["detail"]["modules_not_found"] def test_create_machine_invalid_hostname(