From 6a52c5f15b12677b71736d2e415c74bd8fa8b875 Mon Sep 17 00:00:00 2001 From: DavHau Date: Mon, 13 Nov 2023 21:24:05 +0700 Subject: [PATCH] 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. --- pkgs/clan-cli/clan_cli/config/machine.py | 32 ++++++++++++++++++++---- pkgs/clan-cli/clan_cli/config/schema.py | 6 +++-- pkgs/clan-cli/tests/test_machines_api.py | 12 +++++++++ 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/pkgs/clan-cli/clan_cli/config/machine.py b/pkgs/clan-cli/clan_cli/config/machine.py index fca031e79..30ded26dd 100644 --- a/pkgs/clan-cli/clan_cli/config/machine.py +++ b/pkgs/clan-cli/clan_cli/config/machine.py @@ -2,7 +2,6 @@ import json import os import re import subprocess -from pathlib import Path from tempfile import NamedTemporaryFile from typing import Optional @@ -10,6 +9,7 @@ from fastapi import HTTPException from clan_cli.dirs import ( machine_settings_file, + nixpkgs_source, specific_flake_dir, specific_machine_dir, ) @@ -24,7 +24,6 @@ def verify_machine_config( flake_name: FlakeName, machine_name: str, config: Optional[dict] = None, - flake: Optional[Path] = None, ) -> Optional[str]: """ Verify that the machine evaluates successfully @@ -40,11 +39,34 @@ def verify_machine_config( env["CLAN_MACHINE_SETTINGS_FILE"] = clan_machine_settings_file.name cmd = nix_eval( flags=[ - "--impure", - "--show-trace", "--show-trace", "--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) diff --git a/pkgs/clan-cli/clan_cli/config/schema.py b/pkgs/clan-cli/clan_cli/config/schema.py index a7f535668..150458270 100644 --- a/pkgs/clan-cli/clan_cli/config/schema.py +++ b/pkgs/clan-cli/clan_cli/config/schema.py @@ -43,7 +43,8 @@ def machine_schema( f""" let 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}); clan-core = flake.inputs.clan-core; config = b.fromJSON (b.readFile (b.getEnv "CLAN_MACHINE_SETTINGS_FILE")); @@ -85,7 +86,8 @@ def machine_schema( "--expr", f""" let - system = builtins.currentSystem; + # 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()}; diff --git a/pkgs/clan-cli/tests/test_machines_api.py b/pkgs/clan-cli/tests/test_machines_api.py index 9e2812e1f..c2f76f4f9 100644 --- a/pkgs/clan-cli/tests/test_machines_api.py +++ b/pkgs/clan-cli/tests/test_machines_api.py @@ -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 def test_configure_machine(api: TestClient, test_flake_with_core: FlakeForTest) -> None: # ensure error 404 if machine does not exist when accessing the config