Merge pull request 'machines: add endpoint machines/{name}/ verify' (#432) from DavHau-dave into main
This commit is contained in:
@@ -28,10 +28,7 @@ def map_type(type: str) -> Any:
|
|||||||
"16 bit unsigned integer; between 0 and 65535 (both inclusive)",
|
"16 bit unsigned integer; between 0 and 65535 (both inclusive)",
|
||||||
]:
|
]:
|
||||||
return int
|
return int
|
||||||
elif type == "string":
|
elif type.startswith("string"):
|
||||||
return str
|
|
||||||
# lib.type.passwdEntry
|
|
||||||
elif type == "string, not containing newlines or colons":
|
|
||||||
return str
|
return str
|
||||||
elif type.startswith("null or "):
|
elif type.startswith("null or "):
|
||||||
subtype = type.removeprefix("null or ")
|
subtype = type.removeprefix("null or ")
|
||||||
|
|||||||
@@ -12,6 +12,32 @@ from clan_cli.machines.folders import machine_folder, machine_settings_file
|
|||||||
from clan_cli.nix import nix_eval
|
from clan_cli.nix import nix_eval
|
||||||
|
|
||||||
|
|
||||||
|
def verify_machine_config(
|
||||||
|
machine_name: str, flake: Optional[Path] = None
|
||||||
|
) -> tuple[bool, Optional[str]]:
|
||||||
|
"""
|
||||||
|
Verify that the machine evaluates successfully
|
||||||
|
Returns a tuple of (success, error_message)
|
||||||
|
"""
|
||||||
|
if flake is None:
|
||||||
|
flake = get_clan_flake_toplevel()
|
||||||
|
proc = subprocess.run(
|
||||||
|
nix_eval(
|
||||||
|
flags=[
|
||||||
|
"--impure",
|
||||||
|
"--show-trace",
|
||||||
|
f".#nixosConfigurations.{machine_name}.config.system.build.toplevel.outPath",
|
||||||
|
],
|
||||||
|
),
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
cwd=flake,
|
||||||
|
)
|
||||||
|
if proc.returncode != 0:
|
||||||
|
return False, proc.stderr
|
||||||
|
return True, None
|
||||||
|
|
||||||
|
|
||||||
def config_for_machine(machine_name: str) -> dict:
|
def config_for_machine(machine_name: str) -> dict:
|
||||||
# read the config from a json file located at {flake}/machines/{machine_name}/settings.json
|
# read the config from a json file located at {flake}/machines/{machine_name}/settings.json
|
||||||
if not machine_folder(machine_name).exists():
|
if not machine_folder(machine_name).exists():
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ from typing import Annotated
|
|||||||
|
|
||||||
from fastapi import APIRouter, Body
|
from fastapi import APIRouter, Body
|
||||||
|
|
||||||
|
import clan_cli.config as config
|
||||||
|
|
||||||
from ...config.machine import (
|
from ...config.machine import (
|
||||||
config_for_machine,
|
config_for_machine,
|
||||||
schema_for_machine,
|
schema_for_machine,
|
||||||
@@ -19,6 +21,7 @@ from ..schemas import (
|
|||||||
MachinesResponse,
|
MachinesResponse,
|
||||||
SchemaResponse,
|
SchemaResponse,
|
||||||
Status,
|
Status,
|
||||||
|
VerifyMachineResponse,
|
||||||
)
|
)
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
@@ -63,3 +66,9 @@ async def set_machine_config(
|
|||||||
async def get_machine_schema(name: str) -> SchemaResponse:
|
async def get_machine_schema(name: str) -> SchemaResponse:
|
||||||
schema = schema_for_machine(name)
|
schema = schema_for_machine(name)
|
||||||
return SchemaResponse(schema=schema)
|
return SchemaResponse(schema=schema)
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/api/machines/{name}/verify")
|
||||||
|
async def verify_machine_config(name: str) -> VerifyMachineResponse:
|
||||||
|
success, error = config.machine.verify_machine_config(name)
|
||||||
|
return VerifyMachineResponse(success=success, error=error)
|
||||||
|
|||||||
@@ -38,6 +38,11 @@ class SchemaResponse(BaseModel):
|
|||||||
schema_: dict = Field(alias="schema")
|
schema_: dict = Field(alias="schema")
|
||||||
|
|
||||||
|
|
||||||
|
class VerifyMachineResponse(BaseModel):
|
||||||
|
success: bool
|
||||||
|
error: str | None
|
||||||
|
|
||||||
|
|
||||||
class VmStatusResponse(BaseModel):
|
class VmStatusResponse(BaseModel):
|
||||||
error: str | None
|
error: str | None
|
||||||
status: TaskStatus
|
status: TaskStatus
|
||||||
|
|||||||
@@ -46,18 +46,40 @@ def test_configure_machine(api: TestClient, test_flake: Path) -> None:
|
|||||||
assert "schema" in json_response and "properties" in json_response["schema"]
|
assert "schema" in json_response and "properties" in json_response["schema"]
|
||||||
|
|
||||||
# set some config
|
# set some config
|
||||||
response = api.put(
|
config = dict(
|
||||||
"/api/machines/machine1/config",
|
clan=dict(
|
||||||
json=dict(
|
jitsi=dict(
|
||||||
clan=dict(
|
enable=True,
|
||||||
jitsi=True,
|
),
|
||||||
)
|
),
|
||||||
|
fileSystems={
|
||||||
|
"/": dict(
|
||||||
|
device="/dev/fake_disk",
|
||||||
|
fsType="ext4",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
# set boot.loader.grub.devices
|
||||||
|
boot=dict(
|
||||||
|
loader=dict(
|
||||||
|
grub=dict(
|
||||||
|
devices=["/dev/fake_disk"],
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
response = api.put(
|
||||||
|
"/api/machines/machine1/config",
|
||||||
|
json=config,
|
||||||
|
)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.json() == {"config": {"clan": {"jitsi": True}}}
|
assert response.json() == {"config": config}
|
||||||
|
|
||||||
|
# verify the machine config
|
||||||
|
response = api.get("/api/machines/machine1/verify")
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.json() == {"success": True, "error": None}
|
||||||
|
|
||||||
# get the config again
|
# get the config again
|
||||||
response = api.get("/api/machines/machine1/config")
|
response = api.get("/api/machines/machine1/config")
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.json() == {"config": {"clan": {"jitsi": True}}}
|
assert response.json() == {"config": config}
|
||||||
|
|||||||
Reference in New Issue
Block a user