diff --git a/pkgs/clan-cli/tests/fixtures_flakes.py b/pkgs/clan-cli/tests/fixtures_flakes.py index 9193f0d90..c9b7f2e15 100644 --- a/pkgs/clan-cli/tests/fixtures_flakes.py +++ b/pkgs/clan-cli/tests/fixtures_flakes.py @@ -4,9 +4,10 @@ import os import shutil import subprocess as sp import tempfile -from collections.abc import Iterator +from collections import defaultdict +from collections.abc import Callable, Iterator from pathlib import Path -from typing import NamedTuple +from typing import Any, NamedTuple import pytest from clan_cli.dirs import nixpkgs_source @@ -16,6 +17,14 @@ from root import CLAN_CORE log = logging.getLogger(__name__) +# allows defining nested dictionary in a single line +def def_value() -> defaultdict: + return defaultdict(def_value) + + +nested_dict: Callable[[], dict[str, Any]] = lambda: defaultdict(def_value) + + # Substitutes strings in a file. # This can be used on the flake.nix or default.nix of a machine def substitute( @@ -59,118 +68,152 @@ def set_machine_settings( config_path.write_text(json.dumps(machine_settings, indent=2)) -def init_git(monkeypatch: pytest.MonkeyPatch, flake: Path) -> None: +def set_git_credentials( + monkeypatch: pytest.MonkeyPatch, +) -> None: monkeypatch.setenv("GIT_AUTHOR_NAME", "clan-tool") monkeypatch.setenv("GIT_AUTHOR_EMAIL", "clan@example.com") monkeypatch.setenv("GIT_COMMITTER_NAME", "clan-tool") monkeypatch.setenv("GIT_COMMITTER_EMAIL", "clan@example.com") + +def init_git(monkeypatch: pytest.MonkeyPatch, flake: Path) -> None: + set_git_credentials(monkeypatch) + sp.run(["git", "init", "-b", "main"], cwd=flake, check=True) # TODO: Find out why test_vms_api.py fails in nix build # but works in pytest when this bottom line is commented out - sp.run( - ["git", "config", "--global", "init.defaultBranch", "main"], - cwd=flake, - check=True, - ) - - sp.run(["git", "init"], cwd=flake, check=True) sp.run(["git", "add", "."], cwd=flake, check=True) sp.run(["git", "commit", "-a", "-m", "Initial commit"], cwd=flake, check=True) -def generate_flake( - temporary_home: Path, - flake_template: Path, - monkeypatch: pytest.MonkeyPatch, - substitutions: dict[str, str] | None = None, - # define the machines directly including their config - machine_configs: dict[str, dict] | None = None, - inventory: dict[str, dict] | None = None, - clan_modules: list[str] | None = None, -) -> FlakeForTest: +class ClanFlake: """ - Creates a clan flake with the given name. - Machines are fully generated from the machine_configs. + This class holds all attributes for generating a clan flake. + For example, inventory and machine configs can be set via self.inventory and self.machines["my_machine"] = {...}. + Whenever a flake's configuration is changed, it needs to be re-generated by calling refresh(). - Example: - machine_configs = dict( - my_machine=dict( - clan=dict( - core=dict( - backups=dict( - ... - ) - ) + This class can also be used for managing templates. + Once initialized, all its settings including all generated files, if any, can be copied using the copy() method. + This avoids expensive re-computation, like for example creating the flake.lock over and over again. + """ + + def __init__( + self, + temporary_home: Path, + flake_template: Path, + suppress_tmp_home_warning: bool = False, + ) -> None: + self._flake_template = flake_template + self.inventory = nested_dict() + self.machines = nested_dict() + self.substitutions: dict[str, str] = { + "git+https://git.clan.lol/clan/clan-core": "path://" + str(CLAN_CORE), + "https://git.clan.lol/clan/clan-core/archive/main.tar.gz": "path://" + + str(CLAN_CORE), + } + self.clan_modules: list[str] = [] + self.temporary_home = temporary_home + self.path = temporary_home / "flake" + if not suppress_tmp_home_warning: + if "/tmp" not in str(os.environ.get("HOME")): + log.warning( + f"!! $HOME does not point to a temp directory!! HOME={os.environ['HOME']}" ) + + def copy( + self, + temporary_home: Path, + monkeypatch: pytest.MonkeyPatch, + ) -> "ClanFlake": + # copy the files to the new location + shutil.copytree(self.path, temporary_home / "flake") + set_git_credentials(monkeypatch) + return ClanFlake( + temporary_home=temporary_home, + flake_template=self._flake_template, + ) + + def substitute(self) -> None: + for file in self.path.rglob("*"): + if ".git" in file.parts: + continue + if file.is_file(): + buf = "" + with file.open() as f: + for line in f: + for key, value in self.substitutions.items(): + line = line.replace(key, value) + buf += line + file.write_text(buf) + + def init_from_template(self) -> None: + shutil.copytree(self._flake_template, self.path) + sp.run(["chmod", "+w", "-R", str(self.path)], check=True) + self.substitute() + if not (self.path / ".git").exists(): + sp.run( + ["nix", "flake", "lock"], + cwd=self.path, + check=True, ) - ) - """ - if machine_configs is None: - machine_configs = {} - if inventory is None: - inventory = {} - if clan_modules is None: - clan_modules = [] - substitutions = { - "git+https://git.clan.lol/clan/clan-core": "path://" + str(CLAN_CORE), - "https://git.clan.lol/clan/clan-core/archive/main.tar.gz": "path://" - + str(CLAN_CORE), - } - flake = temporary_home / "flake" - shutil.copytree(flake_template, flake) - sp.run(["chmod", "+w", "-R", str(flake)], check=True) + with pytest.MonkeyPatch.context() as mp: + init_git(mp, self.path) - # initialize inventory - if inventory: - # check if inventory valid - inventory_path = flake / "inventory.json" - inventory_path.write_text(json.dumps(inventory, indent=2)) - - # substitute `substitutions` in all files of the template - for file in flake.rglob("*"): - if file.is_file(): - print(f"Final Content of {file}:") - buf = "" - with file.open() as f: - for line in f: - for key, value in substitutions.items(): - line = line.replace(key, value) - buf += line - file.write_text(buf) - - # generate machines from machineConfigs - for machine_name, machine_config in machine_configs.items(): - configuration_nix = flake / "machines" / machine_name / "configuration.nix" - configuration_nix.parent.mkdir(parents=True, exist_ok=True) + def refresh(self) -> None: + if not self.path.exists(): + self.init_from_template() + self.substitute() + if self.inventory: + inventory_path = self.path / "inventory.json" + inventory_path.write_text(json.dumps(self.inventory, indent=2)) imports = "\n".join( - [f"clan-core.clanModules.{module}" for module in clan_modules] + [f"clan-core.clanModules.{module}" for module in self.clan_modules] ) - configuration_nix.write_text(f""" - {{clan-core, ...}}: - {{ - imports = [ - (builtins.fromJSON (builtins.readFile ./configuration.json)) - {imports} - ]; - }} - """) - set_machine_settings(flake, machine_name, machine_config) - - if "/tmp" not in str(os.environ.get("HOME")): - log.warning( - f"!! $HOME does not point to a temp directory!! HOME={os.environ['HOME']}" + for machine_name, machine_config in self.machines.items(): + configuration_nix = ( + self.path / "machines" / machine_name / "configuration.nix" + ) + configuration_nix.parent.mkdir(parents=True, exist_ok=True) + configuration_nix.write_text(f""" + {{clan-core, ...}}: + {{ + imports = [ + (builtins.fromJSON (builtins.readFile ./configuration.json)) + {imports} + ]; + }} + """) + set_machine_settings(self.path, machine_name, machine_config) + sp.run(["git", "add", "."], cwd=self.path, check=True) + sp.run( + ["git", "commit", "-a", "-m", "Update by flake generator"], + cwd=self.path, + check=True, ) - # TODO: Find out why test_vms_api.py fails in nix build - # but works in pytest when this bottom line is commented out - sp.run( - ["git", "config", "--global", "init.defaultBranch", "main"], - cwd=flake, - check=True, - ) - init_git(monkeypatch, flake) - return FlakeForTest(flake) +@pytest.fixture(scope="session") +def minimal_flake_template() -> Iterator[ClanFlake]: + with ( + tempfile.TemporaryDirectory(prefix="flake-") as home, + pytest.MonkeyPatch.context() as mp, + ): + mp.setenv("HOME", home) + flake = ClanFlake( + temporary_home=Path(home), + flake_template=CLAN_CORE / "templates" / "minimal", + ) + flake.init_from_template() + yield flake + + +@pytest.fixture +def flake( + temporary_home: Path, + minimal_flake_template: ClanFlake, + monkeypatch: pytest.MonkeyPatch, +) -> ClanFlake: + return minimal_flake_template.copy(temporary_home, monkeypatch) def create_flake( @@ -274,21 +317,3 @@ def test_flake_with_core( clan_core_flake=CLAN_CORE, monkeypatch=monkeypatch, ) - - -@pytest.fixture -def test_local_democlan( - monkeypatch: pytest.MonkeyPatch, temporary_home: Path -) -> FlakeForTest: - democlan = os.getenv(key="DEMOCLAN_ROOT") - if democlan is None: - msg = ( - "DEMOCLAN_ROOT not set. This test requires the democlan flake to be present" - ) - raise FixtureError(msg) - democlan_p = Path(democlan).resolve() - if not democlan_p.is_dir(): - msg = f"DEMOCLAN_ROOT ({democlan_p}) is not a directory. This test requires the democlan directory to be present" - raise FixtureError(msg) - - return FlakeForTest(democlan_p) diff --git a/pkgs/clan-cli/tests/test_secrets_password_store.py b/pkgs/clan-cli/tests/test_secrets_password_store.py index 2ca871a27..b187735f3 100644 --- a/pkgs/clan-cli/tests/test_secrets_password_store.py +++ b/pkgs/clan-cli/tests/test_secrets_password_store.py @@ -8,22 +8,25 @@ from clan_cli.machines.facts import machine_get_fact from clan_cli.machines.machines import Machine from clan_cli.nix import nix_shell from clan_cli.ssh import HostGroup -from fixtures_flakes import generate_flake +from fixtures_flakes import ClanFlake from helpers import cli -from helpers.nixos_config import nested_dict from helpers.validator import is_valid_ssh_key -from root import CLAN_CORE @pytest.mark.impure def test_upload_secret( monkeypatch: pytest.MonkeyPatch, + flake: ClanFlake, temporary_home: Path, host_group: HostGroup, ) -> None: - config = nested_dict() + flake.clan_modules = [ + "root-password", + "user-password", + "sshd", + ] + config = flake.machines["vm1"] config["nixpkgs"]["hostPlatform"] = "x86_64-linux" - # clan.core.networking.zerotier.controller.enable = true; config["clan"]["core"]["networking"]["zerotier"]["controller"]["enable"] = True host = host_group.hosts[0] addr = f"{host.user}@{host.host}:{host.port}?StrictHostKeyChecking=no&UserKnownHostsFile=/dev/null&IdentityFile={host.key}" @@ -38,17 +41,7 @@ def test_upload_secret( ) facts["secretUploadDirectory"]["priority"] = 50 - flake = generate_flake( - temporary_home, - flake_template=CLAN_CORE / "templates" / "minimal", - monkeypatch=monkeypatch, - machine_configs={"vm1": config}, - clan_modules=[ - "root-password", - "user-password", - "sshd", - ], - ) + flake.refresh() monkeypatch.chdir(flake.path) gnupghome = temporary_home / "gpg" gnupghome.mkdir(mode=0o700) diff --git a/pkgs/clan-cli/tests/test_vars.py b/pkgs/clan-cli/tests/test_vars.py index e2f59a4eb..00f80118e 100644 --- a/pkgs/clan-cli/tests/test_vars.py +++ b/pkgs/clan-cli/tests/test_vars.py @@ -16,10 +16,8 @@ from clan_cli.vars.list import stringify_all_vars from clan_cli.vars.public_modules import in_repo from clan_cli.vars.secret_modules import password_store, sops from clan_cli.vars.set import set_var -from fixtures_flakes import generate_flake, set_machine_settings +from fixtures_flakes import ClanFlake from helpers import cli -from helpers.nixos_config import nested_dict -from root import CLAN_CORE from stdout import CaptureOutput @@ -80,19 +78,14 @@ def test_required_generators() -> None: @pytest.mark.impure def test_generate_public_var( monkeypatch: pytest.MonkeyPatch, - temporary_home: Path, + flake: ClanFlake, ) -> None: - config = nested_dict() + config = flake.machines["my_machine"] config["nixpkgs"]["hostPlatform"] = "x86_64-linux" my_generator = config["clan"]["core"]["vars"]["generators"]["my_generator"] my_generator["files"]["my_value"]["secret"] = False my_generator["script"] = "echo hello > $out/my_value" - flake = generate_flake( - temporary_home, - flake_template=CLAN_CORE / "templates" / "minimal", - monkeypatch=monkeypatch, - machine_configs={"my_machine": config}, - ) + flake.refresh() monkeypatch.chdir(flake.path) machine = Machine(name="my_machine", flake=FlakeId(str(flake.path))) assert not check_vars(machine) @@ -120,20 +113,15 @@ def test_generate_public_var( @pytest.mark.impure def test_generate_secret_var_sops( monkeypatch: pytest.MonkeyPatch, - temporary_home: Path, + flake: ClanFlake, sops_setup: SopsSetup, ) -> None: - config = nested_dict() + config = flake.machines["my_machine"] config["nixpkgs"]["hostPlatform"] = "x86_64-linux" my_generator = config["clan"]["core"]["vars"]["generators"]["my_generator"] my_generator["files"]["my_secret"]["secret"] = True my_generator["script"] = "echo hello > $out/my_secret" - flake = generate_flake( - temporary_home, - flake_template=CLAN_CORE / "templates" / "minimal", - monkeypatch=monkeypatch, - machine_configs={"my_machine": config}, - ) + flake.refresh() monkeypatch.chdir(flake.path) sops_setup.init() machine = Machine(name="my_machine", flake=FlakeId(str(flake.path))) @@ -163,21 +151,16 @@ def test_generate_secret_var_sops( @pytest.mark.impure def test_generate_secret_var_sops_with_default_group( monkeypatch: pytest.MonkeyPatch, - temporary_home: Path, + flake: ClanFlake, sops_setup: SopsSetup, ) -> None: - config = nested_dict() + config = flake.machines["my_machine"] config["nixpkgs"]["hostPlatform"] = "x86_64-linux" config["clan"]["core"]["sops"]["defaultGroups"] = ["my_group"] my_generator = config["clan"]["core"]["vars"]["generators"]["my_generator"] my_generator["files"]["my_secret"]["secret"] = True my_generator["script"] = "echo hello > $out/my_secret" - flake = generate_flake( - temporary_home, - flake_template=CLAN_CORE / "templates" / "minimal", - monkeypatch=monkeypatch, - machine_configs={"my_machine": config}, - ) + flake.refresh() monkeypatch.chdir(flake.path) sops_setup.init() cli.run(["secrets", "groups", "add-user", "my_group", sops_setup.user]) @@ -221,10 +204,10 @@ def test_generate_secret_var_sops_with_default_group( @pytest.mark.impure def test_generated_shared_secret_sops( monkeypatch: pytest.MonkeyPatch, - temporary_home: Path, + flake: ClanFlake, sops_setup: SopsSetup, ) -> None: - m1_config = nested_dict() + m1_config = flake.machines["machine1"] m1_config["nixpkgs"]["hostPlatform"] = "x86_64-linux" shared_generator = m1_config["clan"]["core"]["vars"]["generators"][ "my_shared_generator" @@ -232,17 +215,12 @@ def test_generated_shared_secret_sops( shared_generator["share"] = True shared_generator["files"]["my_shared_secret"]["secret"] = True shared_generator["script"] = "echo hello > $out/my_shared_secret" - m2_config = nested_dict() + m2_config = flake.machines["machine2"] m2_config["nixpkgs"]["hostPlatform"] = "x86_64-linux" m2_config["clan"]["core"]["vars"]["generators"]["my_shared_generator"] = ( shared_generator.copy() ) - flake = generate_flake( - temporary_home, - flake_template=CLAN_CORE / "templates" / "minimal", - monkeypatch=monkeypatch, - machine_configs={"machine1": m1_config, "machine2": m2_config}, - ) + flake.refresh() monkeypatch.chdir(flake.path) sops_setup.init() machine1 = Machine(name="machine1", flake=FlakeId(str(flake.path))) @@ -267,10 +245,10 @@ def test_generated_shared_secret_sops( @pytest.mark.impure def test_generate_secret_var_password_store( monkeypatch: pytest.MonkeyPatch, - temporary_home: Path, + flake: ClanFlake, test_root: Path, ) -> None: - config = nested_dict() + config = flake.machines["my_machine"] config["nixpkgs"]["hostPlatform"] = "x86_64-linux" config["clan"]["core"]["vars"]["settings"]["secretStore"] = "password-store" my_generator = config["clan"]["core"]["vars"]["generators"]["my_generator"] @@ -282,20 +260,15 @@ def test_generate_secret_var_password_store( my_shared_generator["share"] = True my_shared_generator["files"]["my_shared_secret"]["secret"] = True my_shared_generator["script"] = "echo hello > $out/my_shared_secret" - flake = generate_flake( - temporary_home, - flake_template=CLAN_CORE / "templates" / "minimal", - monkeypatch=monkeypatch, - machine_configs={"my_machine": config}, - ) + flake.refresh() monkeypatch.chdir(flake.path) - gnupghome = temporary_home / "gpg" + gnupghome = flake.path / "gpg" shutil.copytree(test_root / "data" / "gnupg-home", gnupghome) monkeypatch.setenv("GNUPGHOME", str(gnupghome)) - password_store_dir = temporary_home / "pass" + password_store_dir = flake.path / "pass" shutil.copytree(test_root / "data" / "password-store", password_store_dir) - monkeypatch.setenv("PASSWORD_STORE_DIR", str(temporary_home / "pass")) + monkeypatch.setenv("PASSWORD_STORE_DIR", str(flake.path / "pass")) machine = Machine(name="my_machine", flake=FlakeId(str(flake.path))) assert not check_vars(machine) @@ -316,10 +289,10 @@ def test_generate_secret_var_password_store( @pytest.mark.impure def test_generate_secret_for_multiple_machines( monkeypatch: pytest.MonkeyPatch, - temporary_home: Path, + flake: ClanFlake, sops_setup: SopsSetup, ) -> None: - machine1_config = nested_dict() + machine1_config = flake.machines["machine1"] machine1_generator = machine1_config["clan"]["core"]["vars"]["generators"][ "my_generator" ] @@ -328,7 +301,7 @@ def test_generate_secret_for_multiple_machines( machine1_generator["script"] = ( "echo machine1 > $out/my_secret && echo machine1 > $out/my_value" ) - machine2_config = nested_dict() + machine2_config = flake.machines["machine2"] machine2_generator = machine2_config["clan"]["core"]["vars"]["generators"][ "my_generator" ] @@ -337,12 +310,7 @@ def test_generate_secret_for_multiple_machines( machine2_generator["script"] = ( "echo machine2 > $out/my_secret && echo machine2 > $out/my_value" ) - flake = generate_flake( - temporary_home, - flake_template=CLAN_CORE / "templates" / "minimal", - monkeypatch=monkeypatch, - machine_configs={"machine1": machine1_config, "machine2": machine2_config}, - ) + flake.refresh() monkeypatch.chdir(flake.path) sops_setup.init() cli.run(["vars", "generate", "--flake", str(flake.path)]) @@ -373,9 +341,9 @@ def test_generate_secret_for_multiple_machines( @pytest.mark.impure def test_dependant_generators( monkeypatch: pytest.MonkeyPatch, - temporary_home: Path, + flake: ClanFlake, ) -> None: - config = nested_dict() + config = flake.machines["my_machine"] parent_gen = config["clan"]["core"]["vars"]["generators"]["parent_generator"] parent_gen["files"]["my_value"]["secret"] = False parent_gen["script"] = "echo hello > $out/my_value" @@ -383,12 +351,7 @@ def test_dependant_generators( child_gen["files"]["my_value"]["secret"] = False child_gen["dependencies"] = ["parent_generator"] child_gen["script"] = "cat $in/parent_generator/my_value > $out/my_value" - flake = generate_flake( - temporary_home, - flake_template=CLAN_CORE / "templates" / "minimal", - monkeypatch=monkeypatch, - machine_configs={"my_machine": config}, - ) + flake.refresh() monkeypatch.chdir(flake.path) cli.run(["vars", "generate", "--flake", str(flake.path), "my_machine"]) in_repo_store = in_repo.FactStore( @@ -412,23 +375,18 @@ def test_dependant_generators( ) def test_prompt( monkeypatch: pytest.MonkeyPatch, - temporary_home: Path, + flake: ClanFlake, prompt_type: str, input_value: str, ) -> None: - config = nested_dict() + config = flake.machines["my_machine"] my_generator = config["clan"]["core"]["vars"]["generators"]["my_generator"] my_generator["files"]["my_value"]["secret"] = False my_generator["prompts"]["prompt1"]["description"] = "dream2nix" my_generator["prompts"]["prompt1"]["createFile"] = False my_generator["prompts"]["prompt1"]["type"] = prompt_type my_generator["script"] = "cat $prompts/prompt1 > $out/my_value" - flake = generate_flake( - temporary_home, - flake_template=CLAN_CORE / "templates" / "minimal", - monkeypatch=monkeypatch, - machine_configs={"my_machine": config}, - ) + flake.refresh() monkeypatch.chdir(flake.path) monkeypatch.setattr("sys.stdin", StringIO(input_value)) cli.run(["vars", "generate", "--flake", str(flake.path), "my_machine"]) @@ -442,10 +400,10 @@ def test_prompt( @pytest.mark.impure def test_share_flag( monkeypatch: pytest.MonkeyPatch, - temporary_home: Path, + flake: ClanFlake, sops_setup: SopsSetup, ) -> None: - config = nested_dict() + config = flake.machines["my_machine"] config["nixpkgs"]["hostPlatform"] = "x86_64-linux" shared_generator = config["clan"]["core"]["vars"]["generators"]["shared_generator"] shared_generator["share"] = True @@ -463,12 +421,7 @@ def test_share_flag( unshared_generator["script"] = ( "echo hello > $out/my_secret && echo hello > $out/my_value" ) - flake = generate_flake( - temporary_home, - flake_template=CLAN_CORE / "templates" / "minimal", - monkeypatch=monkeypatch, - machine_configs={"my_machine": config}, - ) + flake.refresh() monkeypatch.chdir(flake.path) sops_setup.init() machine = Machine(name="my_machine", flake=FlakeId(str(flake.path))) @@ -504,10 +457,10 @@ def test_share_flag( @pytest.mark.impure def test_depending_on_shared_secret_succeeds( monkeypatch: pytest.MonkeyPatch, - temporary_home: Path, + flake: ClanFlake, sops_setup: SopsSetup, ) -> None: - config = nested_dict() + config = flake.machines["my_machine"] shared_generator = config["clan"]["core"]["vars"]["generators"]["shared_generator"] shared_generator["share"] = True shared_generator["files"]["my_secret"]["secret"] = True @@ -521,12 +474,7 @@ def test_depending_on_shared_secret_succeeds( dependent_generator["script"] = ( "cat $in/shared_generator/my_secret > $out/my_secret" ) - flake = generate_flake( - temporary_home, - flake_template=CLAN_CORE / "templates" / "minimal", - monkeypatch=monkeypatch, - machine_configs={"my_machine": config}, - ) + flake.refresh() monkeypatch.chdir(flake.path) sops_setup.init() cli.run(["vars", "generate", "--flake", str(flake.path), "my_machine"]) @@ -535,22 +483,17 @@ def test_depending_on_shared_secret_succeeds( @pytest.mark.impure def test_prompt_create_file( monkeypatch: pytest.MonkeyPatch, - temporary_home: Path, + flake: ClanFlake, sops_setup: SopsSetup, ) -> None: """ Test that the createFile flag in the prompt configuration works as expected """ - config = nested_dict() + config = flake.machines["my_machine"] my_generator = config["clan"]["core"]["vars"]["generators"]["my_generator"] my_generator["prompts"]["prompt1"]["createFile"] = True my_generator["prompts"]["prompt2"]["createFile"] = False - flake = generate_flake( - temporary_home, - flake_template=CLAN_CORE / "templates" / "minimal", - monkeypatch=monkeypatch, - machine_configs={"my_machine": config}, - ) + flake.refresh() monkeypatch.chdir(flake.path) sops_setup.init() monkeypatch.setattr("sys.stdin", StringIO("input1\ninput2\n")) @@ -566,20 +509,15 @@ def test_prompt_create_file( @pytest.mark.impure def test_api_get_prompts( monkeypatch: pytest.MonkeyPatch, - temporary_home: Path, + flake: ClanFlake, ) -> None: from clan_cli.vars.list import get_prompts - config = nested_dict() + config = flake.machines["my_machine"] my_generator = config["clan"]["core"]["vars"]["generators"]["my_generator"] my_generator["prompts"]["prompt1"]["type"] = "line" my_generator["files"]["prompt1"]["secret"] = False - flake = generate_flake( - temporary_home, - flake_template=CLAN_CORE / "templates" / "minimal", - monkeypatch=monkeypatch, - machine_configs={"my_machine": config}, - ) + flake.refresh() monkeypatch.chdir(flake.path) monkeypatch.setattr("sys.stdin", StringIO("input1")) cli.run(["vars", "generate", "--flake", str(flake.path), "my_machine"]) @@ -594,21 +532,16 @@ def test_api_get_prompts( @pytest.mark.impure def test_api_set_prompts( monkeypatch: pytest.MonkeyPatch, - temporary_home: Path, + flake: ClanFlake, ) -> None: from clan_cli.vars._types import GeneratorUpdate from clan_cli.vars.list import set_prompts - config = nested_dict() + config = flake.machines["my_machine"] my_generator = config["clan"]["core"]["vars"]["generators"]["my_generator"] my_generator["prompts"]["prompt1"]["type"] = "line" my_generator["files"]["prompt1"]["secret"] = False - flake = generate_flake( - temporary_home, - flake_template=CLAN_CORE / "templates" / "minimal", - monkeypatch=monkeypatch, - machine_configs={"my_machine": config}, - ) + flake.refresh() monkeypatch.chdir(flake.path) machine = Machine(name="my_machine", flake=FlakeId(str(flake.path))) set_prompts( @@ -638,10 +571,10 @@ def test_api_set_prompts( @pytest.mark.impure def test_commit_message( monkeypatch: pytest.MonkeyPatch, - temporary_home: Path, + flake: ClanFlake, sops_setup: SopsSetup, ) -> None: - config = nested_dict() + config = flake.machines["my_machine"] my_generator = config["clan"]["core"]["vars"]["generators"]["my_generator"] my_generator["files"]["my_value"]["secret"] = False my_generator["script"] = "echo hello > $out/my_value" @@ -650,12 +583,7 @@ def test_commit_message( ] my_secret_generator["files"]["my_secret"]["secret"] = True my_secret_generator["script"] = "echo hello > $out/my_secret" - flake = generate_flake( - temporary_home, - flake_template=CLAN_CORE / "templates" / "minimal", - monkeypatch=monkeypatch, - machine_configs={"my_machine": config}, - ) + flake.refresh() monkeypatch.chdir(flake.path) sops_setup.init() cli.run( @@ -700,9 +628,9 @@ def test_commit_message( @pytest.mark.impure def test_default_value( monkeypatch: pytest.MonkeyPatch, - temporary_home: Path, + flake: ClanFlake, ) -> None: - config = nested_dict() + config = flake.machines["my_machine"] config["nixpkgs"]["hostPlatform"] = "x86_64-linux" my_generator = config["clan"]["core"]["vars"]["generators"]["my_generator"] my_generator["files"]["my_value"]["secret"] = False @@ -710,12 +638,7 @@ def test_default_value( my_generator["files"]["my_value"]["value"]["priority"] = 1000 # mkDefault my_generator["files"]["my_value"]["value"]["content"] = "foo" my_generator["script"] = "echo -n hello > $out/my_value" - flake = generate_flake( - temporary_home, - flake_template=CLAN_CORE / "templates" / "minimal", - monkeypatch=monkeypatch, - machine_configs={"my_machine": config}, - ) + flake.refresh() monkeypatch.chdir(flake.path) # ensure evaluating the default value works without generating the value value_eval = run( @@ -742,11 +665,11 @@ def test_default_value( @pytest.mark.impure def test_stdout_of_generate( monkeypatch: pytest.MonkeyPatch, - temporary_home: Path, + flake: ClanFlake, capture_output: CaptureOutput, sops_setup: SopsSetup, ) -> None: - config = nested_dict() + config = flake.machines["my_machine"] config["nixpkgs"]["hostPlatform"] = "x86_64-linux" my_generator = config["clan"]["core"]["vars"]["generators"]["my_generator"] my_generator["files"]["my_value"]["secret"] = False @@ -756,12 +679,7 @@ def test_stdout_of_generate( ] my_secret_generator["files"]["my_secret"]["secret"] = True my_secret_generator["script"] = "echo -n hello > $out/my_secret" - flake = generate_flake( - temporary_home, - flake_template=CLAN_CORE / "templates" / "minimal", - monkeypatch=monkeypatch, - machine_configs={"my_machine": config}, - ) + flake.refresh() monkeypatch.chdir(flake.path) sops_setup.init() from clan_cli.vars.generate import generate_vars_for_machine @@ -828,10 +746,10 @@ def test_stdout_of_generate( @pytest.mark.impure def test_migration_skip( monkeypatch: pytest.MonkeyPatch, - temporary_home: Path, + flake: ClanFlake, sops_setup: SopsSetup, ) -> None: - config = nested_dict() + config = flake.machines["my_machine"] config["nixpkgs"]["hostPlatform"] = "x86_64-linux" my_service = config["clan"]["core"]["facts"]["services"]["my_service"] my_service["secret"]["my_value"] = {} @@ -841,12 +759,7 @@ def test_migration_skip( my_generator["files"]["my_value"]["secret"] = False my_generator["migrateFact"] = "my_service" my_generator["script"] = "echo -n world > $out/my_value" - flake = generate_flake( - temporary_home, - flake_template=CLAN_CORE / "templates" / "minimal", - monkeypatch=monkeypatch, - machine_configs={"my_machine": config}, - ) + flake.refresh() monkeypatch.chdir(flake.path) sops_setup.init() cli.run(["facts", "generate", "--flake", str(flake.path), "my_machine"]) @@ -861,10 +774,10 @@ def test_migration_skip( @pytest.mark.impure def test_migration( monkeypatch: pytest.MonkeyPatch, - temporary_home: Path, + flake: ClanFlake, sops_setup: SopsSetup, ) -> None: - config = nested_dict() + config = flake.machines["my_machine"] config["nixpkgs"]["hostPlatform"] = "x86_64-linux" my_service = config["clan"]["core"]["facts"]["services"]["my_service"] my_service["public"]["my_value"] = {} @@ -873,12 +786,7 @@ def test_migration( my_generator["files"]["my_value"]["secret"] = False my_generator["migrateFact"] = "my_service" my_generator["script"] = "echo -n world > $out/my_value" - flake = generate_flake( - temporary_home, - flake_template=CLAN_CORE / "templates" / "minimal", - monkeypatch=monkeypatch, - machine_configs={"my_machine": config}, - ) + flake.refresh() monkeypatch.chdir(flake.path) sops_setup.init() cli.run(["facts", "generate", "--flake", str(flake.path), "my_machine"]) @@ -893,10 +801,10 @@ def test_migration( @pytest.mark.impure def test_fails_when_files_are_left_from_other_backend( monkeypatch: pytest.MonkeyPatch, - temporary_home: Path, + flake: ClanFlake, sops_setup: SopsSetup, ) -> None: - config = nested_dict() + config = flake.machines["my_machine"] config["nixpkgs"]["hostPlatform"] = "x86_64-linux" my_secret_generator = config["clan"]["core"]["vars"]["generators"][ "my_secret_generator" @@ -908,12 +816,7 @@ def test_fails_when_files_are_left_from_other_backend( ] my_value_generator["files"]["my_value"]["secret"] = False my_value_generator["script"] = "echo hello > $out/my_value" - flake = generate_flake( - temporary_home, - flake_template=CLAN_CORE / "templates" / "minimal", - monkeypatch=monkeypatch, - machine_configs={"my_machine": config}, - ) + flake.refresh() monkeypatch.chdir(flake.path) sops_setup.init() for generator in ["my_secret_generator", "my_value_generator"]: @@ -925,7 +828,7 @@ def test_fails_when_files_are_left_from_other_backend( ) my_secret_generator["files"]["my_secret"]["secret"] = False my_value_generator["files"]["my_value"]["secret"] = True - set_machine_settings(flake.path, "my_machine", config) + flake.refresh() monkeypatch.chdir(flake.path) for generator in ["my_secret_generator", "my_value_generator"]: with pytest.raises(ClanError): diff --git a/pkgs/clan-cli/tests/test_vars_deployment.py b/pkgs/clan-cli/tests/test_vars_deployment.py index 4a7bc46d7..8d95736ef 100644 --- a/pkgs/clan-cli/tests/test_vars_deployment.py +++ b/pkgs/clan-cli/tests/test_vars_deployment.py @@ -1,6 +1,5 @@ import json from contextlib import ExitStack -from pathlib import Path import pytest from age_keys import SopsSetup @@ -9,22 +8,19 @@ from clan_cli.clan_uri import FlakeId from clan_cli.machines.machines import Machine from clan_cli.nix import nix_eval, run from clan_cli.vms.run import inspect_vm, spawn_vm -from fixtures_flakes import generate_flake +from fixtures_flakes import ClanFlake from helpers import cli -from helpers.nixos_config import nested_dict from nix_config import ConfigItem -from root import CLAN_CORE @pytest.mark.impure def test_vm_deployment( - monkeypatch: pytest.MonkeyPatch, - temporary_home: Path, + flake: ClanFlake, nix_config: dict[str, ConfigItem], sops_setup: SopsSetup, ) -> None: # machine 1 - machine1_config = nested_dict() + machine1_config = flake.machines["m1_machine"] machine1_config["nixpkgs"]["hostPlatform"] = nix_config["system"].value machine1_config["clan"]["virtualisation"]["graphics"] = False machine1_config["services"]["getty"]["autologinUser"] = "root" @@ -50,7 +46,7 @@ def test_vm_deployment( echo hello > $out/no_deploy_secret """ # machine 2 - machine2_config = nested_dict() + machine2_config = flake.machines["m2_machine"] machine2_config["nixpkgs"]["hostPlatform"] = nix_config["system"].value machine2_config["clan"]["virtualisation"]["graphics"] = False machine2_config["services"]["getty"]["autologinUser"] = "root" @@ -63,12 +59,7 @@ def test_vm_deployment( m1_shared_generator.copy() ) - flake = generate_flake( - temporary_home, - flake_template=CLAN_CORE / "templates" / "minimal", - monkeypatch=monkeypatch, - machine_configs={"m1_machine": machine1_config, "m2_machine": machine2_config}, - ) + flake.refresh() sops_setup.init(flake.path) cli.run(["vars", "generate", "--flake", str(flake.path)]) diff --git a/pkgs/clan-cli/tests/test_vms_cli.py b/pkgs/clan-cli/tests/test_vms_cli.py index fc07c15e9..f6cbef0e4 100644 --- a/pkgs/clan-cli/tests/test_vms_cli.py +++ b/pkgs/clan-cli/tests/test_vms_cli.py @@ -5,10 +5,8 @@ import pytest from clan_cli.clan_uri import FlakeId from clan_cli.machines.machines import Machine from clan_cli.vms.run import inspect_vm, spawn_vm -from fixtures_flakes import FlakeForTest, generate_flake +from fixtures_flakes import ClanFlake, FlakeForTest from helpers import cli -from helpers.nixos_config import nested_dict -from root import CLAN_CORE from stdout import CaptureOutput if TYPE_CHECKING: @@ -59,33 +57,27 @@ def test_run( @pytest.mark.skipif(no_kvm, reason="Requires KVM") @pytest.mark.impure def test_vm_persistence( - monkeypatch: pytest.MonkeyPatch, - temporary_home: Path, + flake: ClanFlake, ) -> None: # set up a clan flake with some systemd services to test persistence - config = nested_dict() + config = flake.machines["my_machine"] # logrotate-checkconf doesn't work in VM because /nix/store is owned by nobody - config["my_machine"]["systemd"]["services"]["logrotate-checkconf"]["enable"] = False - config["my_machine"]["services"]["getty"]["autologinUser"] = "root" - config["my_machine"]["clan"]["virtualisation"] = {"graphics": False} - config["my_machine"]["clan"]["core"]["networking"] = {"targetHost": "client"} - config["my_machine"]["clan"]["core"]["state"]["my_state"]["folders"] = [ + config["systemd"]["services"]["logrotate-checkconf"]["enable"] = False + config["services"]["getty"]["autologinUser"] = "root" + config["clan"]["virtualisation"] = {"graphics": False} + config["clan"]["core"]["networking"] = {"targetHost": "client"} + config["clan"]["core"]["state"]["my_state"]["folders"] = [ # to be owned by root "/var/my-state", # to be owned by user 'test' "/var/user-state", ] - config["my_machine"]["users"]["users"] = { + config["users"]["users"] = { "test": {"initialPassword": "test", "isSystemUser": True, "group": "users"}, "root": {"initialPassword": "root"}, } - flake = generate_flake( - temporary_home, - flake_template=CLAN_CORE / "templates" / "minimal", - monkeypatch=monkeypatch, - machine_configs=config, - ) + flake.refresh() vm_config = inspect_vm(machine=Machine("my_machine", FlakeId(str(flake.path))))