Merge pull request 'api/schema: return list of missing modules' (#480) from DavHau-dave into main
This commit is contained in:
@@ -6,6 +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,
|
||||
specific_flake_dir,
|
||||
@@ -25,19 +27,59 @@ def machine_schema(
|
||||
# use nix eval to lib.evalModules .#nixosConfigurations.<machine_name>.options.clan
|
||||
with NamedTemporaryFile(mode="w", dir=flake) as clan_machine_settings_file:
|
||||
env = os.environ.copy()
|
||||
inject_config_flags = []
|
||||
if clan_imports is not None:
|
||||
config["clanImports"] = clan_imports
|
||||
# dump config to file
|
||||
json.dump(config, clan_machine_settings_file, indent=2)
|
||||
clan_machine_settings_file.seek(0)
|
||||
env["CLAN_MACHINE_SETTINGS_FILE"] = clan_machine_settings_file.name
|
||||
inject_config_flags = [
|
||||
"--impure", # needed to access CLAN_MACHINE_SETTINGS_FILE
|
||||
]
|
||||
# ensure that the requested clanImports exist
|
||||
proc = subprocess.run(
|
||||
nix_eval(
|
||||
flags=inject_config_flags
|
||||
+ [
|
||||
flags=[
|
||||
"--impure",
|
||||
"--show-trace",
|
||||
"--expr",
|
||||
f"""
|
||||
let
|
||||
b = builtins;
|
||||
system = b.currentSystem;
|
||||
flake = b.getFlake (toString {flake});
|
||||
clan-core = flake.inputs.clan-core;
|
||||
config = b.fromJSON (b.readFile (b.getEnv "CLAN_MACHINE_SETTINGS_FILE"));
|
||||
modules_not_found =
|
||||
b.filter
|
||||
(modName: ! clan-core.clanModules ? ${{modName}})
|
||||
config.clanImports or [];
|
||||
in
|
||||
modules_not_found
|
||||
""",
|
||||
]
|
||||
),
|
||||
capture_output=True,
|
||||
text=True,
|
||||
cwd=flake,
|
||||
env=env,
|
||||
)
|
||||
if proc.returncode != 0:
|
||||
print(proc.stderr, file=sys.stderr)
|
||||
raise ClanError(
|
||||
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,
|
||||
},
|
||||
)
|
||||
|
||||
# get the schema
|
||||
proc = subprocess.run(
|
||||
nix_eval(
|
||||
flags=[
|
||||
"--impure",
|
||||
"--show-trace",
|
||||
"--expr",
|
||||
|
||||
10
pkgs/clan-cli/clan_cli/webui/api_errors.py
Normal file
10
pkgs/clan-cli/clan_cli/webui/api_errors.py
Normal file
@@ -0,0 +1,10 @@
|
||||
import logging
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MissingClanImports(BaseModel):
|
||||
missing_clan_imports: list[str] = []
|
||||
msg: str = "Some requested clan modules could not be found"
|
||||
@@ -4,6 +4,7 @@ from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Body
|
||||
|
||||
from clan_cli.webui.api_errors import MissingClanImports
|
||||
from clan_cli.webui.api_inputs import MachineConfig
|
||||
|
||||
from ...config.machine import (
|
||||
@@ -68,7 +69,11 @@ async def set_machine_config(
|
||||
set_config_for_machine(flake_name, name, conf)
|
||||
|
||||
|
||||
@router.put("/api/{flake_name}/schema", tags=[Tags.machine])
|
||||
@router.put(
|
||||
"/api/{flake_name}/schema",
|
||||
tags=[Tags.machine],
|
||||
responses={400: {"model": MissingClanImports}},
|
||||
)
|
||||
async def get_machine_schema(
|
||||
flake_name: FlakeName, config: Annotated[dict, Body()]
|
||||
) -> SchemaResponse:
|
||||
|
||||
@@ -30,13 +30,28 @@ def test_schema_errors(api: TestClient, test_flake_with_core: FlakeForTest) -> N
|
||||
json={"imports": ["some-inavlid-import"]},
|
||||
)
|
||||
assert response.status_code == 422
|
||||
# expect error to contain "error: string 'some-inavlid-import' doesn't represent an absolute path"
|
||||
assert (
|
||||
"error: string 'some-inavlid-import' doesn't represent an absolute path"
|
||||
in response.json()["detail"][0]["msg"]
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.with_core
|
||||
def test_schema_invalid_clan_imports(
|
||||
api: TestClient, test_flake_with_core: FlakeForTest
|
||||
) -> None:
|
||||
response = api.put(
|
||||
f"/api/{test_flake_with_core.name}/schema",
|
||||
json={"clanImports": ["non-existing-clan-module"]},
|
||||
)
|
||||
assert response.status_code == 400
|
||||
assert (
|
||||
"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"]
|
||||
|
||||
|
||||
@pytest.mark.with_core
|
||||
def test_configure_machine(api: TestClient, test_flake_with_core: FlakeForTest) -> None:
|
||||
# ensure error 404 if machine does not exist when accessing the config
|
||||
|
||||
Reference in New Issue
Block a user