Merge pull request 'API: refactor into resource oriented names' (#4223) from api-cleanup into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4223
This commit is contained in:
@@ -33,27 +33,6 @@ export const createModulesQuery = (
|
||||
},
|
||||
}));
|
||||
|
||||
export const tagsQuery = (uri: string | undefined) =>
|
||||
useQuery<string[]>(() => ({
|
||||
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<string[]>(() => ({
|
||||
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") {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
},
|
||||
|
||||
@@ -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 (
|
||||
<div>
|
||||
<div>Add to your clan</div>
|
||||
<Switch fallback="loading">
|
||||
<Match when={tags.data}>
|
||||
{(tags) => (
|
||||
<For each={Object.keys(props.data.roles)}>
|
||||
{(role) => (
|
||||
<>
|
||||
<div class="text-neutral-600">{role}s</div>
|
||||
<RoleForm
|
||||
avilableTags={tags()}
|
||||
availableMachines={machines.data || []}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</For>
|
||||
)}
|
||||
</Match>
|
||||
</Switch>
|
||||
<Switch fallback="loading">Removed</Switch>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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():
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}"},
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
"""
|
||||
|
||||
@@ -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],
|
||||
|
||||
Reference in New Issue
Block a user