diff --git a/pkgs/clan-cli/clan_cli/config/__init__.py b/pkgs/clan-cli/clan_cli/config/__init__.py index ec3df55f0..04ffbb682 100644 --- a/pkgs/clan-cli/clan_cli/config/__init__.py +++ b/pkgs/clan-cli/clan_cli/config/__init__.py @@ -11,7 +11,7 @@ from typing import Any, Optional, Tuple, get_origin from clan_cli.dirs import machine_settings_file, specific_flake_dir from clan_cli.errors import ClanError -from clan_cli.flakes.types import FlakeName +from clan_cli.types import FlakeName from clan_cli.git import commit_file from clan_cli.nix import nix_eval diff --git a/pkgs/clan-cli/clan_cli/config/machine.py b/pkgs/clan-cli/clan_cli/config/machine.py index 1a5582cfd..cd9957ce4 100644 --- a/pkgs/clan-cli/clan_cli/config/machine.py +++ b/pkgs/clan-cli/clan_cli/config/machine.py @@ -15,7 +15,7 @@ from clan_cli.dirs import ( from clan_cli.git import commit_file, find_git_repo_root from clan_cli.nix import nix_eval -from ..flakes.types import FlakeName +from ..types import FlakeName def verify_machine_config( diff --git a/pkgs/clan-cli/clan_cli/dirs.py b/pkgs/clan-cli/clan_cli/dirs.py index 17a0bc137..1d72a8fbf 100644 --- a/pkgs/clan-cli/clan_cli/dirs.py +++ b/pkgs/clan-cli/clan_cli/dirs.py @@ -4,7 +4,7 @@ from pathlib import Path from typing import Optional from .errors import ClanError -from .flakes.types import FlakeName +from .types import FlakeName def _get_clan_flake_toplevel() -> Path: diff --git a/pkgs/clan-cli/clan_cli/machines/create.py b/pkgs/clan-cli/clan_cli/machines/create.py index a4880f0e9..153f28503 100644 --- a/pkgs/clan-cli/clan_cli/machines/create.py +++ b/pkgs/clan-cli/clan_cli/machines/create.py @@ -5,7 +5,7 @@ from typing import Dict from ..async_cmd import CmdOut, run, runforcli from ..dirs import specific_flake_dir, specific_machine_dir from ..errors import ClanError -from ..flakes.types import FlakeName +from ..types import FlakeName from ..nix import nix_shell log = logging.getLogger(__name__) diff --git a/pkgs/clan-cli/clan_cli/machines/facts.py b/pkgs/clan-cli/clan_cli/machines/facts.py index 7b665b536..3f148ccf6 100644 --- a/pkgs/clan-cli/clan_cli/machines/facts.py +++ b/pkgs/clan-cli/clan_cli/machines/facts.py @@ -1,5 +1,5 @@ from ..dirs import specific_machine_dir -from ..flakes.types import FlakeName +from ..types import FlakeName def machine_has_fact(flake_name: FlakeName, machine: str, fact: str) -> bool: diff --git a/pkgs/clan-cli/clan_cli/machines/list.py b/pkgs/clan-cli/clan_cli/machines/list.py index d78adb239..079bcd739 100644 --- a/pkgs/clan-cli/clan_cli/machines/list.py +++ b/pkgs/clan-cli/clan_cli/machines/list.py @@ -3,7 +3,7 @@ import logging import os from ..dirs import machines_dir -from ..flakes.types import FlakeName +from ..types import FlakeName from .types import validate_hostname log = logging.getLogger(__name__) diff --git a/pkgs/clan-cli/clan_cli/secrets/folders.py b/pkgs/clan-cli/clan_cli/secrets/folders.py index 8a551cc7a..3f23c126c 100644 --- a/pkgs/clan-cli/clan_cli/secrets/folders.py +++ b/pkgs/clan-cli/clan_cli/secrets/folders.py @@ -5,7 +5,7 @@ from typing import Callable from ..dirs import specific_flake_dir from ..errors import ClanError -from ..flakes.types import FlakeName +from ..types import FlakeName def get_sops_folder(flake_name: FlakeName) -> Path: diff --git a/pkgs/clan-cli/clan_cli/secrets/groups.py b/pkgs/clan-cli/clan_cli/secrets/groups.py index b944560c3..f94b9d9c2 100644 --- a/pkgs/clan-cli/clan_cli/secrets/groups.py +++ b/pkgs/clan-cli/clan_cli/secrets/groups.py @@ -3,7 +3,7 @@ import os from pathlib import Path from ..errors import ClanError -from ..flakes.types import FlakeName +from ..types import FlakeName from ..machines.types import machine_name_type, validate_hostname from . import secrets from .folders import ( diff --git a/pkgs/clan-cli/clan_cli/secrets/machines.py b/pkgs/clan-cli/clan_cli/secrets/machines.py index bb01212e9..9c6426157 100644 --- a/pkgs/clan-cli/clan_cli/secrets/machines.py +++ b/pkgs/clan-cli/clan_cli/secrets/machines.py @@ -1,6 +1,6 @@ import argparse -from ..flakes.types import FlakeName +from ..types import FlakeName from ..machines.types import machine_name_type, validate_hostname from . import secrets from .folders import list_objects, remove_object, sops_machines_folder diff --git a/pkgs/clan-cli/clan_cli/secrets/secrets.py b/pkgs/clan-cli/clan_cli/secrets/secrets.py index d7a29542b..9b801d96d 100644 --- a/pkgs/clan-cli/clan_cli/secrets/secrets.py +++ b/pkgs/clan-cli/clan_cli/secrets/secrets.py @@ -8,7 +8,7 @@ from typing import IO from .. import tty from ..errors import ClanError -from ..flakes.types import FlakeName +from ..types import FlakeName from .folders import ( list_objects, sops_groups_folder, diff --git a/pkgs/clan-cli/clan_cli/secrets/sops.py b/pkgs/clan-cli/clan_cli/secrets/sops.py index c6f2b2bf2..4f35761ab 100644 --- a/pkgs/clan-cli/clan_cli/secrets/sops.py +++ b/pkgs/clan-cli/clan_cli/secrets/sops.py @@ -9,7 +9,7 @@ from typing import IO, Iterator from ..dirs import user_config_dir from ..errors import ClanError -from ..flakes.types import FlakeName +from ..types import FlakeName from ..nix import nix_shell from .folders import sops_machines_folder, sops_users_folder diff --git a/pkgs/clan-cli/clan_cli/secrets/sops_generate.py b/pkgs/clan-cli/clan_cli/secrets/sops_generate.py index fdac72df9..a8af2ece5 100644 --- a/pkgs/clan-cli/clan_cli/secrets/sops_generate.py +++ b/pkgs/clan-cli/clan_cli/secrets/sops_generate.py @@ -11,7 +11,7 @@ from clan_cli.nix import nix_shell from ..dirs import specific_flake_dir from ..errors import ClanError -from ..flakes.types import FlakeName +from ..types import FlakeName from .folders import sops_secrets_folder from .machines import add_machine, has_machine from .secrets import decrypt_secret, encrypt_secret, has_secret diff --git a/pkgs/clan-cli/clan_cli/secrets/users.py b/pkgs/clan-cli/clan_cli/secrets/users.py index c5b51e994..98afa876f 100644 --- a/pkgs/clan-cli/clan_cli/secrets/users.py +++ b/pkgs/clan-cli/clan_cli/secrets/users.py @@ -1,6 +1,6 @@ import argparse -from ..flakes.types import FlakeName +from ..types import FlakeName from . import secrets from .folders import list_objects, remove_object, sops_users_folder from .sops import read_key, write_key diff --git a/pkgs/clan-cli/clan_cli/flakes/types.py b/pkgs/clan-cli/clan_cli/types.py similarity index 100% rename from pkgs/clan-cli/clan_cli/flakes/types.py rename to pkgs/clan-cli/clan_cli/types.py diff --git a/pkgs/clan-cli/clan_cli/webui/routers/machines.py b/pkgs/clan-cli/clan_cli/webui/routers/machines.py index 9668b8b41..b112959af 100644 --- a/pkgs/clan-cli/clan_cli/webui/routers/machines.py +++ b/pkgs/clan-cli/clan_cli/webui/routers/machines.py @@ -10,7 +10,7 @@ from ...config.machine import ( set_config_for_machine, verify_machine_config, ) -from ...flakes.types import FlakeName +from ...types import FlakeName from ...machines.create import create_machine as _create_machine from ...machines.list import list_machines as _list_machines from ..api_outputs import ( diff --git a/pkgs/clan-cli/default.nix b/pkgs/clan-cli/default.nix index 63dc4fb3c..c9fccd388 100644 --- a/pkgs/clan-cli/default.nix +++ b/pkgs/clan-cli/default.nix @@ -8,6 +8,7 @@ , openssh , pytest , pytest-cov +, pytest-xdist , pytest-subprocess , pytest-parallel , pytest-timeout @@ -45,7 +46,8 @@ let pytest pytest-cov pytest-subprocess - pytest-parallel + # pytest-parallel + pytest-xdist pytest-timeout openssh git diff --git a/pkgs/clan-cli/pyproject.toml b/pkgs/clan-cli/pyproject.toml index a79978cb2..60d43f27a 100644 --- a/pkgs/clan-cli/pyproject.toml +++ b/pkgs/clan-cli/pyproject.toml @@ -14,9 +14,13 @@ exclude = ["clan_cli.nixpkgs*"] [tool.setuptools.package-data] clan_cli = [ "config/jsonschema/*", "webui/assets/**/*"] + + [tool.pytest.ini_options] +testpaths = "tests" faulthandler_timeout = 60 -addopts = "--cov . --cov-report term --cov-report html:.reports/html --no-cov-on-fail --workers auto --durations 5" +log_level = "DEBUG" +addopts = "--cov . --cov-report term --cov-report html:.reports/html --no-cov-on-fail -n auto --durations 5 --maxfail=1 --new-first" norecursedirs = "tests/helpers" markers = [ "impure" ] diff --git a/pkgs/clan-cli/shell.nix b/pkgs/clan-cli/shell.nix index 2d443998c..8b93571ea 100644 --- a/pkgs/clan-cli/shell.nix +++ b/pkgs/clan-cli/shell.nix @@ -53,6 +53,7 @@ mkShell { register-python-argcomplete --shell fish clan > $tmp_path/share/fish/vendor_completions.d/clan.fish register-python-argcomplete --shell bash clan > $tmp_path/share/bash-completion/completions/clan - ./bin/clan machines create example + ./bin/clan flakes create example_clan + ./bin/clan machines create example_machine example_clan ''; } diff --git a/pkgs/clan-cli/tests/fixtures_flakes.py b/pkgs/clan-cli/tests/fixtures_flakes.py index b775790d5..9132adcd7 100644 --- a/pkgs/clan-cli/tests/fixtures_flakes.py +++ b/pkgs/clan-cli/tests/fixtures_flakes.py @@ -8,7 +8,7 @@ import pytest from root import CLAN_CORE from clan_cli.dirs import nixpkgs_source -from clan_cli.flakes.types import FlakeName +from clan_cli.types import FlakeName # substitutes string sin a file. @@ -28,7 +28,7 @@ def substitute( print(line, end="") -class TestFlake(NamedTuple): +class FlakeForTest(NamedTuple): name: FlakeName path: Path @@ -39,7 +39,7 @@ def create_flake( clan_core_flake: Path | None = None, machines: list[str] = [], remote: bool = False, -) -> Iterator[TestFlake]: +) -> Iterator[FlakeForTest]: """ Creates a flake with the given name and machines. The machine names map to the machines in ./test_machines @@ -66,20 +66,20 @@ def create_flake( with tempfile.TemporaryDirectory() as workdir: monkeypatch.chdir(workdir) monkeypatch.setenv("HOME", str(home)) - yield TestFlake(flake_name, flake) + yield FlakeForTest(flake_name, flake) else: monkeypatch.chdir(flake) monkeypatch.setenv("HOME", str(home)) - yield TestFlake(flake_name, flake) + yield FlakeForTest(flake_name, flake) @pytest.fixture -def test_flake(monkeypatch: pytest.MonkeyPatch) -> Iterator[TestFlake]: +def test_flake(monkeypatch: pytest.MonkeyPatch) -> Iterator[FlakeForTest]: yield from create_flake(monkeypatch, FlakeName("test_flake")) @pytest.fixture -def test_flake_with_core(monkeypatch: pytest.MonkeyPatch) -> Iterator[TestFlake]: +def test_flake_with_core(monkeypatch: pytest.MonkeyPatch) -> Iterator[FlakeForTest]: if not (CLAN_CORE / "flake.nix").exists(): raise Exception( "clan-core flake not found. This test requires the clan-core flake to be present" @@ -90,7 +90,7 @@ def test_flake_with_core(monkeypatch: pytest.MonkeyPatch) -> Iterator[TestFlake] @pytest.fixture def test_flake_with_core_and_pass( monkeypatch: pytest.MonkeyPatch, -) -> Iterator[TestFlake]: +) -> Iterator[FlakeForTest]: if not (CLAN_CORE / "flake.nix").exists(): raise Exception( "clan-core flake not found. This test requires the clan-core flake to be present" diff --git a/pkgs/clan-cli/tests/helpers/cli.py b/pkgs/clan-cli/tests/helpers/cli.py index ea633c2b1..dbfb066a4 100644 --- a/pkgs/clan-cli/tests/helpers/cli.py +++ b/pkgs/clan-cli/tests/helpers/cli.py @@ -1,13 +1,18 @@ import argparse from clan_cli import create_parser - +import logging +import sys +import shlex +log = logging.getLogger(__name__) class Cli: def __init__(self) -> None: self.parser = create_parser(prog="clan") def run(self, args: list[str]) -> argparse.Namespace: + cmd = shlex.join(["clan"] + args) + log.debug(f"Command: {cmd}") parsed = self.parser.parse_args(args) if hasattr(parsed, "func"): parsed.func(parsed) diff --git a/pkgs/clan-cli/tests/test_machines_config.py b/pkgs/clan-cli/tests/test_machines_config.py index a7ab422ab..ee07ad017 100644 --- a/pkgs/clan-cli/tests/test_machines_config.py +++ b/pkgs/clan-cli/tests/test_machines_config.py @@ -1,8 +1,8 @@ -from fixtures_flakes import TestFlake +from fixtures_flakes import FlakeForTest from clan_cli.config import machine -def test_schema_for_machine(test_flake: TestFlake) -> None: +def test_schema_for_machine(test_flake: FlakeForTest) -> None: schema = machine.schema_for_machine(test_flake.name, "machine1") assert "properties" in schema diff --git a/pkgs/clan-cli/tests/test_secrets_cli.py b/pkgs/clan-cli/tests/test_secrets_cli.py index c93c63df4..f18a3d099 100644 --- a/pkgs/clan-cli/tests/test_secrets_cli.py +++ b/pkgs/clan-cli/tests/test_secrets_cli.py @@ -3,23 +3,27 @@ from contextlib import contextmanager from pathlib import Path from typing import TYPE_CHECKING, Iterator +import logging import pytest from cli import Cli +from fixtures_flakes import FlakeForTest from clan_cli.errors import ClanError if TYPE_CHECKING: from age_keys import KeyPair +log = logging.getLogger(__name__) + def _test_identities( what: str, - test_flake: Path, + test_flake: FlakeForTest, capsys: pytest.CaptureFixture, age_keys: list["KeyPair"], ) -> None: cli = Cli() - sops_folder = test_flake / "sops" + sops_folder = test_flake.path / "sops" cli.run(["secrets", what, "add", "foo", age_keys[0].pubkey]) assert (sops_folder / what / "foo" / "key.json").exists() @@ -34,6 +38,7 @@ def _test_identities( "-f", "foo", age_keys[0].privkey, + test_flake.name, ] ) @@ -60,19 +65,19 @@ def _test_identities( def test_users( - test_flake: Path, capsys: pytest.CaptureFixture, age_keys: list["KeyPair"] + test_flake: FlakeForTest, capsys: pytest.CaptureFixture, age_keys: list["KeyPair"] ) -> None: _test_identities("users", test_flake, capsys, age_keys) def test_machines( - test_flake: Path, capsys: pytest.CaptureFixture, age_keys: list["KeyPair"] + test_flake: FlakeForTest, capsys: pytest.CaptureFixture, age_keys: list["KeyPair"] ) -> None: _test_identities("machines", test_flake, capsys, age_keys) def test_groups( - test_flake: Path, capsys: pytest.CaptureFixture, age_keys: list["KeyPair"] + test_flake: FlakeForTest, capsys: pytest.CaptureFixture, age_keys: list["KeyPair"] ) -> None: cli = Cli() capsys.readouterr() # empty the buffer @@ -100,7 +105,7 @@ def test_groups( cli.run(["secrets", "groups", "remove-user", "group1", "user1"]) cli.run(["secrets", "groups", "remove-machine", "group1", "machine1"]) - groups = os.listdir(test_flake / "sops" / "groups") + groups = os.listdir(test_flake.path / "sops" / "groups") assert len(groups) == 0 diff --git a/pkgs/clan-cli/tests/test_secrets_generate.py b/pkgs/clan-cli/tests/test_secrets_generate.py index 226323164..5066d1ecc 100644 --- a/pkgs/clan-cli/tests/test_secrets_generate.py +++ b/pkgs/clan-cli/tests/test_secrets_generate.py @@ -2,7 +2,7 @@ from typing import TYPE_CHECKING import pytest from cli import Cli -from fixtures_flakes import TestFlake +from fixtures_flakes import FlakeForTest from clan_cli.machines.facts import machine_get_fact from clan_cli.secrets.folders import sops_secrets_folder @@ -15,7 +15,7 @@ if TYPE_CHECKING: @pytest.mark.impure def test_generate_secret( monkeypatch: pytest.MonkeyPatch, - test_flake_with_core: TestFlake, + test_flake_with_core: FlakeForTest, age_keys: list["KeyPair"], ) -> None: monkeypatch.chdir(test_flake_with_core.path) diff --git a/pkgs/clan-cli/tests/test_secrets_password_store.py b/pkgs/clan-cli/tests/test_secrets_password_store.py index 999f08a54..27e43520a 100644 --- a/pkgs/clan-cli/tests/test_secrets_password_store.py +++ b/pkgs/clan-cli/tests/test_secrets_password_store.py @@ -3,7 +3,7 @@ from pathlib import Path import pytest from cli import Cli -from fixtures_flakes import TestFlake +from fixtures_flakes import FlakeForTest from clan_cli.machines.facts import machine_get_fact from clan_cli.nix import nix_shell @@ -13,7 +13,7 @@ from clan_cli.ssh import HostGroup @pytest.mark.impure def test_upload_secret( monkeypatch: pytest.MonkeyPatch, - test_flake_with_core_and_pass: TestFlake, + test_flake_with_core_and_pass: FlakeForTest, temporary_dir: Path, host_group: HostGroup, ) -> None: diff --git a/pkgs/clan-cli/tests/test_vms_api_create.py b/pkgs/clan-cli/tests/test_vms_api_create.py index 1de515d53..538d203d1 100644 --- a/pkgs/clan-cli/tests/test_vms_api_create.py +++ b/pkgs/clan-cli/tests/test_vms_api_create.py @@ -5,18 +5,18 @@ from typing import TYPE_CHECKING, Iterator import pytest from api import TestClient from cli import Cli -from fixtures_flakes import TestFlake, create_flake +from fixtures_flakes import FlakeForTest, create_flake from httpx import SyncByteStream from root import CLAN_CORE -from clan_cli.flakes.types import FlakeName +from clan_cli.types import FlakeName if TYPE_CHECKING: from age_keys import KeyPair @pytest.fixture -def flake_with_vm_with_secrets(monkeypatch: pytest.MonkeyPatch) -> Iterator[TestFlake]: +def flake_with_vm_with_secrets(monkeypatch: pytest.MonkeyPatch) -> Iterator[FlakeForTest]: yield from create_flake( monkeypatch, FlakeName("test_flake_with_core_dynamic_machines"), @@ -28,7 +28,7 @@ def flake_with_vm_with_secrets(monkeypatch: pytest.MonkeyPatch) -> Iterator[Test @pytest.fixture def remote_flake_with_vm_without_secrets( monkeypatch: pytest.MonkeyPatch, -) -> Iterator[TestFlake]: +) -> Iterator[FlakeForTest]: yield from create_flake( monkeypatch, FlakeName("test_flake_with_core_dynamic_machines"),