2023-11-09 08:30:25 +00:00
|
|
|
import json
|
|
|
|
import os
|
|
|
|
from pathlib import Path
|
|
|
|
from tempfile import NamedTemporaryFile
|
|
|
|
|
2024-01-10 18:29:16 +00:00
|
|
|
from clan_cli.cmd import run
|
2023-11-21 13:34:31 +00:00
|
|
|
from clan_cli.dirs import nixpkgs_source
|
|
|
|
from clan_cli.errors import ClanError, ClanHttpError
|
2023-11-09 08:30:25 +00:00
|
|
|
from clan_cli.nix import nix_eval
|
|
|
|
|
|
|
|
|
|
|
|
def machine_schema(
|
2023-11-15 13:28:40 +00:00
|
|
|
flake_dir: Path,
|
2023-11-09 08:30:25 +00:00
|
|
|
config: dict,
|
2023-11-29 11:40:48 +00:00
|
|
|
clan_imports: list[str] | None = None,
|
2023-11-09 08:30:25 +00:00
|
|
|
) -> dict:
|
|
|
|
# use nix eval to lib.evalModules .#nixosConfigurations.<machine_name>.options.clan
|
2023-11-15 13:28:40 +00:00
|
|
|
with NamedTemporaryFile(mode="w", dir=flake_dir) as clan_machine_settings_file:
|
2023-11-09 08:30:25 +00:00
|
|
|
env = os.environ.copy()
|
|
|
|
if clan_imports is not None:
|
|
|
|
config["clanImports"] = clan_imports
|
2023-11-10 08:06:59 +00:00
|
|
|
# dump config to file
|
2023-11-09 08:30:25 +00:00
|
|
|
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
|
2023-11-10 08:06:59 +00:00
|
|
|
# ensure that the requested clanImports exist
|
2024-01-10 18:29:16 +00:00
|
|
|
proc = run(
|
2023-11-10 08:06:59 +00:00
|
|
|
nix_eval(
|
|
|
|
flags=[
|
|
|
|
"--impure",
|
|
|
|
"--show-trace",
|
|
|
|
"--expr",
|
|
|
|
f"""
|
|
|
|
let
|
|
|
|
b = builtins;
|
2023-11-15 13:28:40 +00:00
|
|
|
system = b.currentSystem;
|
|
|
|
flake = b.getFlake (toString {flake_dir});
|
2023-11-10 08:06:59 +00:00
|
|
|
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
|
|
|
|
""",
|
|
|
|
]
|
|
|
|
),
|
2023-11-15 13:28:40 +00:00
|
|
|
cwd=flake_dir,
|
2023-11-10 08:06:59 +00:00
|
|
|
env=env,
|
2024-01-10 18:29:16 +00:00
|
|
|
check=False,
|
2023-11-10 08:06:59 +00:00
|
|
|
)
|
|
|
|
if proc.returncode != 0:
|
2023-11-21 13:34:31 +00:00
|
|
|
raise ClanHttpError(
|
|
|
|
status_code=400,
|
|
|
|
msg=f"Failed to check clanImports for existence:\n{proc.stderr}",
|
2023-11-10 08:06:59 +00:00
|
|
|
)
|
|
|
|
modules_not_found = json.loads(proc.stdout)
|
|
|
|
if len(modules_not_found) > 0:
|
2023-11-21 13:34:31 +00:00
|
|
|
raise ClanHttpError(
|
|
|
|
msg="Some requested clan modules could not be found", status_code=400
|
2023-11-10 08:06:59 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
# get the schema
|
2024-01-10 18:29:16 +00:00
|
|
|
proc = run(
|
2023-11-09 08:30:25 +00:00
|
|
|
nix_eval(
|
2023-11-10 08:06:59 +00:00
|
|
|
flags=[
|
2023-11-09 08:30:25 +00:00
|
|
|
"--impure",
|
|
|
|
"--show-trace",
|
|
|
|
"--expr",
|
|
|
|
f"""
|
|
|
|
let
|
2023-11-15 13:28:40 +00:00
|
|
|
system = builtins.currentSystem;
|
|
|
|
flake = builtins.getFlake (toString {flake_dir});
|
2023-11-09 08:30:25 +00:00
|
|
|
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
|
2024-06-17 10:42:28 +00:00
|
|
|
{{ clan.core.clanName = "fakeClan"; }}
|
2023-11-09 08:30:25 +00:00
|
|
|
]
|
|
|
|
# add all clan modules specified via clanImports
|
|
|
|
++ (map (name: clan-core.clanModules.${{name}}) config.clanImports or []);
|
|
|
|
}};
|
|
|
|
clanOptions = fakeMachine.options.clan;
|
|
|
|
jsonschemaLib = import {Path(__file__).parent / "jsonschema"} {{ inherit lib; }};
|
|
|
|
jsonschema = jsonschemaLib.parseOptions clanOptions;
|
|
|
|
in
|
|
|
|
jsonschema
|
|
|
|
""",
|
|
|
|
],
|
|
|
|
),
|
2024-01-10 18:29:16 +00:00
|
|
|
check=False,
|
2023-11-15 13:28:40 +00:00
|
|
|
cwd=flake_dir,
|
2023-11-09 08:30:25 +00:00
|
|
|
env=env,
|
|
|
|
)
|
|
|
|
if proc.returncode != 0:
|
2023-11-10 07:27:03 +00:00
|
|
|
raise ClanError(f"Failed to read schema:\n{proc.stderr}")
|
2023-11-09 08:30:25 +00:00
|
|
|
return json.loads(proc.stdout)
|