diff --git a/pkgs/clan-app/ui-2d/src/queries/index.ts b/pkgs/clan-app/ui-2d/src/queries/index.ts index 220d1bd07..29ea86116 100644 --- a/pkgs/clan-app/ui-2d/src/queries/index.ts +++ b/pkgs/clan-app/ui-2d/src/queries/index.ts @@ -33,27 +33,6 @@ export const createModulesQuery = ( }, })); -export const tagsQuery = (uri: string | undefined) => - useQuery(() => ({ - queryKey: [uri, "tags"], - placeholderData: [], - queryFn: async () => { - if (!uri) return []; - - const response = await callApi("get_inventory", { - flake: { identifier: uri }, - }).promise; - if (response.status === "error") { - console.error("Failed to fetch data"); - } else { - const machines = response.data.machines || {}; - const tags = Object.values(machines).flatMap((m) => m.tags || []); - return tags; - } - return []; - }, - })); - export const machinesQuery = (uri: string | undefined) => useQuery(() => ({ queryKey: [uri, "machines"], @@ -61,7 +40,7 @@ export const machinesQuery = (uri: string | undefined) => queryFn: async () => { if (!uri) return []; - const response = await callApi("get_inventory", { + const response = await callApi("list_machines", { flake: { identifier: uri }, }).promise; if (response.status === "error") { diff --git a/pkgs/clan-app/ui-2d/src/routes/clans/create.tsx b/pkgs/clan-app/ui-2d/src/routes/clans/create.tsx index 67899a1f1..ea82a0e74 100644 --- a/pkgs/clan-app/ui-2d/src/routes/clans/create.tsx +++ b/pkgs/clan-app/ui-2d/src/routes/clans/create.tsx @@ -66,7 +66,7 @@ export const CreateClan = () => { } // Will generate a key if it doesn't exist, and add a user to the clan - const k = await callApi("keygen", { + const k = await callApi("create_secrets_user", { flake_dir: target_dir[0], }).promise; diff --git a/pkgs/clan-app/ui-2d/src/routes/flash/view.tsx b/pkgs/clan-app/ui-2d/src/routes/flash/view.tsx index c5d0a645d..7bea3a960 100644 --- a/pkgs/clan-app/ui-2d/src/routes/flash/view.tsx +++ b/pkgs/clan-app/ui-2d/src/routes/flash/view.tsx @@ -110,7 +110,7 @@ export const Flash = () => { const keymapQuery = createQuery(() => ({ queryKey: ["list_keymaps"], queryFn: async () => { - const result = await callApi("list_possible_keymaps", {}).promise; + const result = await callApi("list_keymaps", {}).promise; if (result.status === "error") throw new Error("Failed to fetch data"); return result.data; }, @@ -120,7 +120,7 @@ export const Flash = () => { const langQuery = createQuery(() => ({ queryKey: ["list_languages"], queryFn: async () => { - const result = await callApi("list_possible_languages", {}).promise; + const result = await callApi("list_languages", {}).promise; if (result.status === "error") throw new Error("Failed to fetch data"); return result.data; }, diff --git a/pkgs/clan-app/ui-2d/src/routes/modules/add.tsx b/pkgs/clan-app/ui-2d/src/routes/modules/add.tsx index d732312ee..e87133bb3 100644 --- a/pkgs/clan-app/ui-2d/src/routes/modules/add.tsx +++ b/pkgs/clan-app/ui-2d/src/routes/modules/add.tsx @@ -1,5 +1,5 @@ import { BackButton } from "@/src/components/BackButton"; -import { createModulesQuery, machinesQuery, tagsQuery } from "@/src/queries"; +import { createModulesQuery, machinesQuery } from "@/src/queries"; import { useParams } from "@solidjs/router"; import { For, Match, Switch } from "solid-js"; import { ModuleInfo } from "./list"; @@ -34,28 +34,11 @@ interface AddModuleProps { const AddModule = (props: AddModuleProps) => { const { activeClanURI } = useClanContext(); - const tags = tagsQuery(activeClanURI()); const machines = machinesQuery(activeClanURI()); return (
Add to your clan
- - - {(tags) => ( - - {(role) => ( - <> -
{role}s
- - - )} -
- )} -
-
+ Removed
); }; diff --git a/pkgs/clan-app/ui-2d/src/routes/modules/details.tsx b/pkgs/clan-app/ui-2d/src/routes/modules/details.tsx index de8b35f9f..3e40a9f8d 100644 --- a/pkgs/clan-app/ui-2d/src/routes/modules/details.tsx +++ b/pkgs/clan-app/ui-2d/src/routes/modules/details.tsx @@ -62,7 +62,6 @@ const Details = (props: DetailsProps) => { navigate(`/modules/add/${props.id}`); // const uri = activeURI(); // if (!uri) return; - // const res = await callApi("get_inventory", { base_path: uri }); // if (res.status === "error") { // toast.error("Failed to fetch inventory"); // return; diff --git a/pkgs/clan-app/ui/src/routes/clans/create.tsx b/pkgs/clan-app/ui/src/routes/clans/create.tsx index 6a1b8fa39..92cac1f65 100644 --- a/pkgs/clan-app/ui/src/routes/clans/create.tsx +++ b/pkgs/clan-app/ui/src/routes/clans/create.tsx @@ -65,7 +65,7 @@ export const CreateClan = () => { } // Will generate a key if it doesn't exist, and add a user to the clan - const k = await callApi("keygen", { + const k = await callApi("create_secrets_user", { flake_dir: target_dir[0], }).promise; diff --git a/pkgs/clan-cli/clan_cli/flash/flash.py b/pkgs/clan-cli/clan_cli/flash/flash.py index aa77db5f5..be2eb683e 100644 --- a/pkgs/clan-cli/clan_cli/flash/flash.py +++ b/pkgs/clan-cli/clan_cli/flash/flash.py @@ -17,7 +17,7 @@ from clan_cli.vars.generate import generate_vars from clan_cli.vars.upload import populate_secret_vars from .automount import pause_automounting -from .list import list_possible_keymaps, list_possible_languages +from .list import list_keymaps, list_languages log = logging.getLogger(__name__) @@ -59,7 +59,7 @@ def flash_machine( generate_vars([machine]) if system_config.language: - if system_config.language not in list_possible_languages(): + if system_config.language not in list_languages(): msg = ( f"Language '{system_config.language}' is not a valid language. " f"Run 'clan flash list languages' to see a list of possible languages." @@ -68,7 +68,7 @@ def flash_machine( system_config_nix["i18n"] = {"defaultLocale": system_config.language} if system_config.keymap: - if system_config.keymap not in list_possible_keymaps(): + if system_config.keymap not in list_keymaps(): msg = ( f"Keymap '{system_config.keymap}' is not a valid keymap. " f"Run 'clan flash list keymaps' to see a list of possible keymaps." diff --git a/pkgs/clan-cli/clan_cli/flash/list.py b/pkgs/clan-cli/clan_cli/flash/list.py index ac356f8d8..c60a6ee7d 100644 --- a/pkgs/clan-cli/clan_cli/flash/list.py +++ b/pkgs/clan-cli/clan_cli/flash/list.py @@ -2,6 +2,7 @@ import argparse import logging import os from pathlib import Path +from typing import TypedDict from clan_lib.api import API from clan_lib.cmd import Log, RunOpts, run @@ -11,8 +12,17 @@ from clan_lib.nix import nix_build log = logging.getLogger(__name__) +class FlashOptions(TypedDict): + languages: list[str] + keymaps: list[str] + + @API.register -def list_possible_languages() -> list[str]: +def show_flash_options() -> FlashOptions: + return {"languages": list_languages(), "keymaps": list_keymaps()} + + +def list_languages() -> list[str]: cmd = nix_build(["nixpkgs#glibcLocales"]) result = run(cmd, RunOpts(log=Log.STDERR, error_msg="Failed to find glibc locales")) locale_file = Path(result.stdout.strip()) / "share" / "i18n" / "SUPPORTED" @@ -37,8 +47,7 @@ def list_possible_languages() -> list[str]: return languages -@API.register -def list_possible_keymaps() -> list[str]: +def list_keymaps() -> list[str]: cmd = nix_build(["nixpkgs#kbd"]) result = run(cmd, RunOpts(log=Log.STDERR, error_msg="Failed to find kbdinfo")) keymaps_dir = Path(result.stdout.strip()) / "share" / "keymaps" @@ -61,11 +70,11 @@ def list_possible_keymaps() -> list[str]: def list_command(args: argparse.Namespace) -> None: if args.cmd == "languages": - languages = list_possible_languages() + languages = list_languages() for language in languages: print(language) elif args.cmd == "keymaps": - keymaps = list_possible_keymaps() + keymaps = list_keymaps() for keymap in keymaps: print(keymap) diff --git a/pkgs/clan-cli/clan_cli/tests/test_vars.py b/pkgs/clan-cli/clan_cli/tests/test_vars.py index 274dd38fc..899050f7d 100644 --- a/pkgs/clan-cli/clan_cli/tests/test_vars.py +++ b/pkgs/clan-cli/clan_cli/tests/test_vars.py @@ -10,11 +10,11 @@ from clan_cli.tests.helpers import cli from clan_cli.vars.check import check_vars from clan_cli.vars.generate import ( Generator, - generate_vars_for_machine, - generate_vars_for_machine_interactive, - get_generators_closure, + create_machine_vars, + create_machine_vars_interactive, + get_machine_generators, ) -from clan_cli.vars.get import get_var +from clan_cli.vars.get import get_machine_var from clan_cli.vars.graph import all_missing_closure, requested_closure from clan_cli.vars.list import stringify_all_vars from clan_cli.vars.public_modules import in_repo @@ -172,13 +172,13 @@ def test_generate_public_and_secret_vars( in commit_message ) assert ( - get_var( + get_machine_var( str(machine.flake.path), machine.name, "my_generator/my_value" ).printable_value == "public" ) assert ( - get_var( + get_machine_var( str(machine.flake.path), machine.name, "my_shared_generator/my_shared_value" ).printable_value == "shared" @@ -668,7 +668,7 @@ def test_api_set_prompts( monkeypatch.chdir(flake.path) - generate_vars_for_machine( + create_machine_vars( machine_name="my_machine", base_dir=flake.path, generators=["my_generator"], @@ -682,7 +682,7 @@ def test_api_set_prompts( store = in_repo.FactStore(machine) assert store.exists(Generator("my_generator"), "prompt1") assert store.get(Generator("my_generator"), "prompt1").decode() == "input1" - generate_vars_for_machine( + create_machine_vars( machine_name="my_machine", base_dir=flake.path, generators=["my_generator"], @@ -694,7 +694,7 @@ def test_api_set_prompts( ) assert store.get(Generator("my_generator"), "prompt1").decode() == "input2" - generators = get_generators_closure( + generators = get_machine_generators( machine_name="my_machine", base_dir=flake.path, full_closure=True, @@ -727,11 +727,11 @@ def test_stdout_of_generate( flake_.refresh() monkeypatch.chdir(flake_.path) flake = Flake(str(flake_.path)) - from clan_cli.vars.generate import generate_vars_for_machine_interactive + from clan_cli.vars.generate import create_machine_vars_interactive # with capture_output as output: with caplog.at_level(logging.INFO): - generate_vars_for_machine_interactive( + create_machine_vars_interactive( Machine(name="my_machine", flake=flake), "my_generator", regenerate=False, @@ -744,7 +744,7 @@ def test_stdout_of_generate( set_var("my_machine", "my_generator/my_value", b"world", flake) with caplog.at_level(logging.INFO): - generate_vars_for_machine_interactive( + create_machine_vars_interactive( Machine(name="my_machine", flake=flake), "my_generator", regenerate=True, @@ -755,7 +755,7 @@ def test_stdout_of_generate( caplog.clear() # check the output when nothing gets regenerated with caplog.at_level(logging.INFO): - generate_vars_for_machine_interactive( + create_machine_vars_interactive( Machine(name="my_machine", flake=flake), "my_generator", regenerate=True, @@ -764,7 +764,7 @@ def test_stdout_of_generate( assert "hello" in caplog.text caplog.clear() with caplog.at_level(logging.INFO): - generate_vars_for_machine_interactive( + create_machine_vars_interactive( Machine(name="my_machine", flake=flake), "my_secret_generator", regenerate=False, @@ -779,7 +779,7 @@ def test_stdout_of_generate( Flake(str(flake.path)), ) with caplog.at_level(logging.INFO): - generate_vars_for_machine_interactive( + create_machine_vars_interactive( Machine(name="my_machine", flake=flake), "my_secret_generator", regenerate=True, @@ -869,7 +869,7 @@ def test_fails_when_files_are_left_from_other_backend( flake.refresh() monkeypatch.chdir(flake.path) for generator in ["my_secret_generator", "my_value_generator"]: - generate_vars_for_machine_interactive( + create_machine_vars_interactive( Machine(name="my_machine", flake=Flake(str(flake.path))), generator, regenerate=False, @@ -886,13 +886,13 @@ def test_fails_when_files_are_left_from_other_backend( # This should raise an error if generator == "my_secret_generator": with pytest.raises(ClanError): - generate_vars_for_machine_interactive( + create_machine_vars_interactive( Machine(name="my_machine", flake=Flake(str(flake.path))), generator, regenerate=False, ) else: - generate_vars_for_machine_interactive( + create_machine_vars_interactive( Machine(name="my_machine", flake=Flake(str(flake.path))), generator, regenerate=False, @@ -900,7 +900,9 @@ def test_fails_when_files_are_left_from_other_backend( @pytest.mark.with_core -def test_keygen(monkeypatch: pytest.MonkeyPatch, flake: ClanFlake) -> None: +def test_create_sops_age_secrets( + monkeypatch: pytest.MonkeyPatch, flake: ClanFlake +) -> None: monkeypatch.chdir(flake.path) cli.run(["vars", "keygen", "--flake", str(flake.path), "--user", "user"]) # check public key exists @@ -930,12 +932,12 @@ def test_invalidation( monkeypatch.chdir(flake.path) cli.run(["vars", "generate", "--flake", str(flake.path), "my_machine"]) machine = Machine(name="my_machine", flake=Flake(str(flake.path))) - value1 = get_var( + value1 = get_machine_var( str(machine.flake.path), machine.name, "my_generator/my_value" ).printable_value # generate again and make sure nothing changes without the invalidation data being set cli.run(["vars", "generate", "--flake", str(flake.path), "my_machine"]) - value1_new = get_var( + value1_new = get_machine_var( str(machine.flake.path), machine.name, "my_generator/my_value" ).printable_value assert value1 == value1_new @@ -944,13 +946,13 @@ def test_invalidation( flake.refresh() # generate again and make sure the value changes cli.run(["vars", "generate", "--flake", str(flake.path), "my_machine"]) - value2 = get_var( + value2 = get_machine_var( str(machine.flake.path), machine.name, "my_generator/my_value" ).printable_value assert value1 != value2 # generate again without changing invalidation data -> value should not change cli.run(["vars", "generate", "--flake", str(flake.path), "my_machine"]) - value2_new = get_var( + value2_new = get_machine_var( str(machine.flake.path), machine.name, "my_generator/my_value" ).printable_value assert value2 == value2_new diff --git a/pkgs/clan-cli/clan_cli/vars/generate.py b/pkgs/clan-cli/clan_cli/vars/generate.py index 2d1ef9c08..67c0fa071 100644 --- a/pkgs/clan-cli/clan_cli/vars/generate.py +++ b/pkgs/clan-cli/clan_cli/vars/generate.py @@ -89,9 +89,11 @@ class Generator: deploy=file_data["deploy"], owner=file_data["owner"], group=file_data["group"], - mode=file_data["mode"] - if isinstance(file_data["mode"], int) - else int(file_data["mode"], 8), + mode=( + file_data["mode"] + if isinstance(file_data["mode"], int) + else int(file_data["mode"], 8) + ), needed_for=file_data["neededFor"], ) files.append(var) @@ -421,7 +423,7 @@ def get_closure( @API.register -def get_generators_closure( +def get_machine_generators( machine_name: str, base_dir: Path, full_closure: bool = False, @@ -459,7 +461,7 @@ def _generate_vars_for_machine( @API.register -def generate_vars_for_machine( +def create_machine_vars( machine_name: str, generators: list[str], all_prompt_values: dict[str, dict[str, str]], @@ -484,7 +486,7 @@ def generate_vars_for_machine( ) -def generate_vars_for_machine_interactive( +def create_machine_vars_interactive( machine: "Machine", generator_name: str | None, regenerate: bool, @@ -538,7 +540,7 @@ def generate_vars( for machine in machines: errors = [] try: - was_regenerated |= generate_vars_for_machine_interactive( + was_regenerated |= create_machine_vars_interactive( machine, generator_name, regenerate, diff --git a/pkgs/clan-cli/clan_cli/vars/get.py b/pkgs/clan-cli/clan_cli/vars/get.py index c95de5fb3..0966e187f 100644 --- a/pkgs/clan-cli/clan_cli/vars/get.py +++ b/pkgs/clan-cli/clan_cli/vars/get.py @@ -3,19 +3,17 @@ import logging import sys from clan_cli.completions import add_dynamic_completer, complete_machines -from clan_lib.api import API from clan_lib.errors import ClanError from clan_lib.flake import Flake from .generate import Var -from .list import get_vars +from .list import get_machine_vars log = logging.getLogger(__name__) -@API.register -def get_var(base_dir: str, machine_name: str, var_id: str) -> Var: - vars_ = get_vars(base_dir=base_dir, machine_name=machine_name) +def get_machine_var(base_dir: str, machine_name: str, var_id: str) -> Var: + vars_ = get_machine_vars(base_dir=base_dir, machine_name=machine_name) results = [] for var in vars_: if var.id == var_id: @@ -41,7 +39,7 @@ def get_var(base_dir: str, machine_name: str, var_id: str) -> Var: def get_command(machine_name: str, var_id: str, flake: Flake) -> None: - var = get_var(str(flake.path), machine_name, var_id) + var = get_machine_var(str(flake.path), machine_name, var_id) if not var.exists: msg = f"Var {var.id} has not been generated yet" raise ClanError(msg) diff --git a/pkgs/clan-cli/clan_cli/vars/keygen.py b/pkgs/clan-cli/clan_cli/vars/keygen.py index 4f1bdd931..9475a771f 100644 --- a/pkgs/clan-cli/clan_cli/vars/keygen.py +++ b/pkgs/clan-cli/clan_cli/vars/keygen.py @@ -13,11 +13,16 @@ log = logging.getLogger(__name__) @API.register -def keygen(flake_dir: Path, user: str | None = None, force: bool = False) -> None: +def create_secrets_user( + flake_dir: Path, user: str | None = None, force: bool = False +) -> None: + """ + initialize sops keys for vars + """ if user is None: user = os.getenv("USER", None) if not user: - msg = "No user provided and $USER is not set. Please provide a user via --user." + msg = "No user provided and environment variable: '$USER' is not set. Please provide an explizit username via argument" raise ClanError(msg) pub_keys = maybe_get_admin_public_keys() if not pub_keys: @@ -34,7 +39,7 @@ def keygen(flake_dir: Path, user: str | None = None, force: bool = False) -> Non def _command( args: argparse.Namespace, ) -> None: - keygen( + create_secrets_user( flake_dir=args.flake.path, user=args.user, force=args.force, diff --git a/pkgs/clan-cli/clan_cli/vars/list.py b/pkgs/clan-cli/clan_cli/vars/list.py index c880b6696..5bd8cfcda 100644 --- a/pkgs/clan-cli/clan_cli/vars/list.py +++ b/pkgs/clan-cli/clan_cli/vars/list.py @@ -2,19 +2,15 @@ import argparse import logging from clan_cli.completions import add_dynamic_completer, complete_machines -from clan_lib.api import API -from clan_lib.errors import ClanError from clan_lib.flake import Flake from clan_lib.machines.machines import Machine -from ._types import GeneratorUpdate -from .generate import Generator, Prompt, Var, execute_generator +from .generate import Var log = logging.getLogger(__name__) -@API.register -def get_vars(base_dir: str, machine_name: str) -> list[Var]: +def get_machine_vars(base_dir: str, machine_name: str) -> list[Var]: machine = Machine(name=machine_name, flake=Flake(base_dir)) pub_store = machine.public_vars_store sec_store = machine.secret_vars_store @@ -32,70 +28,12 @@ def get_vars(base_dir: str, machine_name: str) -> list[Var]: return all_vars -def _get_previous_value( - machine: Machine, - generator: Generator, - prompt: Prompt, -) -> str | None: - if not prompt.persist: - return None - - pub_store = machine.public_vars_store - if pub_store.exists(generator, prompt.name): - return pub_store.get(generator, prompt.name).decode() - sec_store = machine.secret_vars_store - if sec_store.exists(generator, prompt.name): - return sec_store.get(generator, prompt.name).decode() - return None - - -@API.register -def get_generators(base_dir: str, machine_name: str) -> list[Generator]: - from clan_cli.vars.generate import Generator - - machine = Machine(name=machine_name, flake=Flake(base_dir)) - generators: list[Generator] = Generator.generators_from_flake( - machine_name, machine.flake - ) - for generator in generators: - for prompt in generator.prompts: - prompt.previous_value = _get_previous_value(machine, generator, prompt) - return generators - - -# TODO: Ensure generator dependencies are met (executed in correct order etc.) -# TODO: for missing prompts, default to existing values -# TODO: raise error if mandatory prompt not provided -@API.register -def set_prompts( - base_dir: str, machine_name: str, updates: list[GeneratorUpdate] -) -> None: - from clan_cli.vars.generate import Generator - - machine = Machine(name=machine_name, flake=Flake(base_dir)) - for update in updates: - generators = Generator.generators_from_flake(machine_name, machine.flake) - for generator in generators: - if generator.name == update.generator: - break - else: - msg = f"Generator '{update.generator}' not found in machine {machine.name}" - raise ClanError(msg) - execute_generator( - machine, - generator, - secret_vars_store=machine.secret_vars_store, - public_vars_store=machine.public_vars_store, - prompt_values=update.prompt_values, - ) - - def stringify_vars(_vars: list[Var]) -> str: return "\n".join([str(var) for var in _vars]) def stringify_all_vars(machine: Machine) -> str: - return stringify_vars(get_vars(str(machine.flake), machine.name)) + return stringify_vars(get_machine_vars(str(machine.flake), machine.name)) def list_command(args: argparse.Namespace) -> None: diff --git a/pkgs/clan-cli/clan_cli/vars/set.py b/pkgs/clan-cli/clan_cli/vars/set.py index ceeb4f46e..cd67b7522 100644 --- a/pkgs/clan-cli/clan_cli/vars/set.py +++ b/pkgs/clan-cli/clan_cli/vars/set.py @@ -3,7 +3,7 @@ import logging import sys from clan_cli.completions import add_dynamic_completer, complete_machines -from clan_cli.vars.get import get_var +from clan_cli.vars.get import get_machine_var from clan_cli.vars.prompt import PromptType from clan_lib.flake import Flake from clan_lib.git import commit_files @@ -21,7 +21,7 @@ def set_var(machine: str | Machine, var: str | Var, value: bytes, flake: Flake) else: _machine = machine if isinstance(var, str): - _var = get_var(str(flake.path), _machine.name, var) + _var = get_machine_var(str(flake.path), _machine.name, var) else: _var = var path = _var.set(value) @@ -35,7 +35,7 @@ def set_var(machine: str | Machine, var: str | Var, value: bytes, flake: Flake) def set_via_stdin(machine_name: str, var_id: str, flake: Flake) -> None: machine = Machine(name=machine_name, flake=flake) - var = get_var(str(flake.path), machine_name, var_id) + var = get_machine_var(str(flake.path), machine_name, var_id) if sys.stdin.isatty(): new_value = ask( var.id, diff --git a/pkgs/clan-cli/clan_lib/api/disk.py b/pkgs/clan-cli/clan_lib/api/disk.py index 28a14befa..0fb083402 100644 --- a/pkgs/clan-cli/clan_lib/api/disk.py +++ b/pkgs/clan-cli/clan_lib/api/disk.py @@ -10,7 +10,7 @@ from clan_lib.api.modules import Frontmatter, extract_frontmatter from clan_lib.dirs import TemplateType, clan_templates from clan_lib.errors import ClanError from clan_lib.git import commit_file -from clan_lib.machines.hardware import HardwareConfig, show_machine_hardware_config +from clan_lib.machines.hardware import HardwareConfig, get_machine_hardware_config from clan_lib.machines.machines import Machine log = logging.getLogger(__name__) @@ -137,7 +137,7 @@ def set_machine_disk_schema( Set the disk placeholders of the template """ # Assert the hw-config must exist before setting the disk - hw_config = show_machine_hardware_config(machine) + hw_config = get_machine_hardware_config(machine) hw_config_path = hw_config.config_path(machine) if not hw_config_path.exists(): diff --git a/pkgs/clan-cli/clan_lib/inventory/__init__.py b/pkgs/clan-cli/clan_lib/inventory/__init__.py index 7409ce8fe..e2fd4eba4 100644 --- a/pkgs/clan-cli/clan_lib/inventory/__init__.py +++ b/pkgs/clan-cli/clan_lib/inventory/__init__.py @@ -10,14 +10,3 @@ Which is an abstraction over the inventory Interacting with 'clan_lib.inventory' is NOT recommended and will be removed """ - -from clan_lib.api import API -from clan_lib.flake import Flake -from clan_lib.persist.inventory_store import InventorySnapshot, InventoryStore - - -@API.register -def get_inventory(flake: Flake) -> InventorySnapshot: - inventory_store = InventoryStore(flake) - inventory = inventory_store.read() - return inventory diff --git a/pkgs/clan-cli/clan_lib/machines/delete.py b/pkgs/clan-cli/clan_lib/machines/delete.py index 68f210cb8..7d642a1d7 100644 --- a/pkgs/clan-cli/clan_lib/machines/delete.py +++ b/pkgs/clan-cli/clan_lib/machines/delete.py @@ -9,7 +9,7 @@ from clan_cli.secrets.secrets import ( list_secrets, ) -from clan_lib import inventory +from clan_lib.persist.inventory_store import InventoryStore from clan_lib.api import API from clan_lib.dirs import specific_machine_dir from clan_lib.machines.machines import Machine @@ -19,7 +19,7 @@ log = logging.getLogger(__name__) @API.register def delete_machine(machine: Machine) -> None: - inventory_store = inventory.InventoryStore(machine.flake) + inventory_store = InventoryStore(machine.flake) try: inventory_store.delete( {f"machines.{machine.name}"}, diff --git a/pkgs/clan-cli/clan_lib/machines/hardware.py b/pkgs/clan-cli/clan_lib/machines/hardware.py index 8324a7953..402213faa 100644 --- a/pkgs/clan-cli/clan_lib/machines/hardware.py +++ b/pkgs/clan-cli/clan_lib/machines/hardware.py @@ -3,6 +3,7 @@ import logging from dataclasses import dataclass from enum import Enum from pathlib import Path +from typing import TypedDict from clan_lib.api import API from clan_lib.cmd import RunOpts, run @@ -40,19 +41,7 @@ class HardwareConfig(Enum): return HardwareConfig.NONE -@API.register -def show_machine_hardware_config(machine: Machine) -> HardwareConfig: - """ - Show hardware information for a machine returns None if none exist. - """ - return HardwareConfig.detect_type(machine) - - -@API.register -def show_machine_hardware_platform(machine: Machine) -> str | None: - """ - Show hardware information for a machine returns None if none exist. - """ +def get_machine_target_platform(machine: Machine) -> str | None: config = nix_config() system = config["system"] cmd = nix_eval( @@ -132,7 +121,7 @@ def generate_machine_hardware_info( f"machines/{opts.machine}/{hw_file.name}: update hardware configuration", ) try: - show_machine_hardware_platform(opts.machine) + get_machine_target_platform(opts.machine) if backup_file: backup_file.unlink(missing_ok=True) except ClanCmdError as e: @@ -150,3 +139,29 @@ def generate_machine_hardware_info( ) from e return opts.backend + + +def get_machine_hardware_config(machine: Machine) -> HardwareConfig: + """ + Detect and return the full hardware configuration for the given machine. + + Returns: + HardwareConfig: Structured hardware information, or None if unavailable. + """ + return HardwareConfig.detect_type(machine) + + +class MachineHardwareBrief(TypedDict): + hardware_config: HardwareConfig + platform: str | None + + +@API.register +def describe_machine_hardware(machine: Machine) -> MachineHardwareBrief: + """ + Return a high-level summary of hardware config and platform type. + """ + return { + "hardware_config": get_machine_hardware_config(machine), + "platform": get_machine_target_platform(machine), + } diff --git a/pkgs/clan-cli/clan_lib/machines/machines.py b/pkgs/clan-cli/clan_lib/machines/machines.py index ce4a51b6d..be4c81c32 100644 --- a/pkgs/clan-cli/clan_lib/machines/machines.py +++ b/pkgs/clan-cli/clan_lib/machines/machines.py @@ -129,7 +129,7 @@ class Machine: return self.flake.path def target_host(self) -> Remote: - remote = get_host(self.name, self.flake, field="targetHost") + remote = get_machine_host(self.name, self.flake, field="targetHost") if remote is None: msg = f"'targetHost' is not set for machine '{self.name}'" raise ClanError( @@ -144,7 +144,7 @@ class Machine: The host where the machine is built and deployed from. Can be the same as the target host. """ - remote = get_host(self.name, self.flake, field="buildHost") + remote = get_machine_host(self.name, self.flake, field="buildHost") if remote: data = remote.data @@ -176,7 +176,7 @@ class RemoteSource: @API.register -def get_host( +def get_machine_host( name: str, flake: Flake, field: Literal["targetHost", "buildHost"] ) -> RemoteSource | None: """ diff --git a/pkgs/clan-cli/clan_lib/tests/test_create.py b/pkgs/clan-cli/clan_lib/tests/test_create.py index ed43e442f..ac2758374 100644 --- a/pkgs/clan-cli/clan_lib/tests/test_create.py +++ b/pkgs/clan-cli/clan_lib/tests/test_create.py @@ -14,7 +14,7 @@ from clan_cli.machines.create import create_machine from clan_cli.secrets.key import generate_key from clan_cli.secrets.sops import maybe_get_admin_public_keys from clan_cli.secrets.users import add_user -from clan_cli.vars.generate import generate_vars_for_machine, get_generators_closure +from clan_cli.vars.generate import create_machine_vars, get_machine_generators from clan_lib.api.disk import hw_main_disk_options, set_machine_disk_schema from clan_lib.api.modules import list_modules @@ -22,7 +22,7 @@ from clan_lib.cmd import RunOpts, run from clan_lib.dirs import specific_machine_dir from clan_lib.errors import ClanError from clan_lib.flake import Flake -from clan_lib.inventory import InventoryStore +from clan_lib.persist.inventory_store import InventoryStore from clan_lib.machines.machines import Machine from clan_lib.nix import nix_command from clan_lib.nix_models.clan import ( @@ -221,7 +221,7 @@ def test_clan_create_api( # Invalidate cache because of new inventory clan_dir_flake.invalidate_cache() - generators = get_generators_closure(machine.name, machine.flake.path) + generators = get_machine_generators(machine.name, machine.flake.path) all_prompt_values = {} for generator in generators: prompt_values = {} @@ -234,7 +234,7 @@ def test_clan_create_api( raise ClanError(msg) all_prompt_values[generator.name] = prompt_values - generate_vars_for_machine( + create_machine_vars( machine_name=machine.name, base_dir=machine.flake.path, generators=[gen.name for gen in generators],