api/machines: allow config verification on imaginary machines

Machines do not need to exist in order to verify their configuration.

This allows verifying a config before creating an actual machine with it.
This commit is contained in:
DavHau
2023-11-13 21:24:05 +07:00
parent 1b357c412d
commit d755048dc2
3 changed files with 43 additions and 7 deletions

View File

@@ -2,7 +2,6 @@ import json
import os import os
import re import re
import subprocess import subprocess
from pathlib import Path
from tempfile import NamedTemporaryFile from tempfile import NamedTemporaryFile
from typing import Optional from typing import Optional
@@ -10,6 +9,7 @@ from fastapi import HTTPException
from clan_cli.dirs import ( from clan_cli.dirs import (
machine_settings_file, machine_settings_file,
nixpkgs_source,
specific_flake_dir, specific_flake_dir,
specific_machine_dir, specific_machine_dir,
) )
@@ -24,7 +24,6 @@ def verify_machine_config(
flake_name: FlakeName, flake_name: FlakeName,
machine_name: str, machine_name: str,
config: Optional[dict] = None, config: Optional[dict] = None,
flake: Optional[Path] = None,
) -> Optional[str]: ) -> Optional[str]:
""" """
Verify that the machine evaluates successfully Verify that the machine evaluates successfully
@@ -40,11 +39,34 @@ def verify_machine_config(
env["CLAN_MACHINE_SETTINGS_FILE"] = clan_machine_settings_file.name env["CLAN_MACHINE_SETTINGS_FILE"] = clan_machine_settings_file.name
cmd = nix_eval( cmd = nix_eval(
flags=[ flags=[
"--impure",
"--show-trace",
"--show-trace", "--show-trace",
"--impure", # needed to access CLAN_MACHINE_SETTINGS_FILE "--impure", # needed to access CLAN_MACHINE_SETTINGS_FILE
f".#nixosConfigurations.{machine_name}.config.system.build.vm.outPath", "--expr",
f"""
let
# hardcoding system for now, not sure where to get it from
system = "x86_64-linux";
flake = builtins.getFlake (toString {flake});
clan-core = flake.inputs.clan-core;
nixpkgsSrc = flake.inputs.nixpkgs or {nixpkgs_source()};
lib = import (nixpkgsSrc + /lib);
pkgs = import nixpkgsSrc {{ inherit system; }};
config = lib.importJSON (builtins.getEnv "CLAN_MACHINE_SETTINGS_FILE");
fakeMachine = pkgs.nixos {{
imports =
[
clan-core.nixosModules.clanCore
# potentially the config might affect submodule options,
# therefore we need to import it
config
{{clanCore.clanDir = {flake};}}
]
# add all clan modules specified via clanImports
++ (map (name: clan-core.clanModules.${{name}}) config.clanImports or []);
}};
in
fakeMachine.config.system.build.vm.outPath
""",
], ],
) )
# repro_env_break(work_dir=flake, env=env, cmd=cmd) # repro_env_break(work_dir=flake, env=env, cmd=cmd)

View File

@@ -43,7 +43,8 @@ def machine_schema(
f""" f"""
let let
b = builtins; b = builtins;
system = b.currentSystem; # hardcoding system for now, not sure where to get it from
system = "x86_64-linux";
flake = b.getFlake (toString {flake}); flake = b.getFlake (toString {flake});
clan-core = flake.inputs.clan-core; clan-core = flake.inputs.clan-core;
config = b.fromJSON (b.readFile (b.getEnv "CLAN_MACHINE_SETTINGS_FILE")); config = b.fromJSON (b.readFile (b.getEnv "CLAN_MACHINE_SETTINGS_FILE"));
@@ -85,7 +86,8 @@ def machine_schema(
"--expr", "--expr",
f""" f"""
let let
system = builtins.currentSystem; # hardcoding system for now, not sure where to get it from
system = "x86_64-linux";
flake = builtins.getFlake (toString {flake}); flake = builtins.getFlake (toString {flake});
clan-core = flake.inputs.clan-core; clan-core = flake.inputs.clan-core;
nixpkgsSrc = flake.inputs.nixpkgs or {nixpkgs_source()}; nixpkgsSrc = flake.inputs.nixpkgs or {nixpkgs_source()};

View File

@@ -62,6 +62,18 @@ def test_create_machine_invalid_hostname(
) )
@pytest.mark.with_core
def test_verify_config_without_machine(
api: TestClient, test_flake_with_core: FlakeForTest
) -> None:
response = api.put(
f"/api/{test_flake_with_core.name}/machines/test/verify",
json=dict(),
)
assert response.status_code == 200
assert response.json() == {"success": True, "error": None}
@pytest.mark.with_core @pytest.mark.with_core
def test_configure_machine(api: TestClient, test_flake_with_core: FlakeForTest) -> None: def test_configure_machine(api: TestClient, test_flake_with_core: FlakeForTest) -> None:
# ensure error 404 if machine does not exist when accessing the config # ensure error 404 if machine does not exist when accessing the config