diff --git a/pkgs/clan-cli/clan_cli/machines/create.py b/pkgs/clan-cli/clan_cli/machines/create.py index a0f3e5e82..5ea2a4e67 100644 --- a/pkgs/clan-cli/clan_cli/machines/create.py +++ b/pkgs/clan-cli/clan_cli/machines/create.py @@ -10,11 +10,14 @@ from clan_cli.dirs import get_clan_flake_toplevel_or_env from clan_cli.errors import ClanError from clan_cli.flake import Flake from clan_cli.git import commit_file -from clan_cli.inventory import Machine as InventoryMachine +from clan_cli.inventory import ( + Machine as InventoryMachine, + patch_inventory_with, + dataclass_to_dict, +) from clan_cli.inventory import ( MachineDeploy, get_inventory, - set_inventory, ) from clan_cli.machines.list import list_nixos_machines from clan_cli.templates import ( @@ -100,20 +103,18 @@ def create_machine(opts: CreateOptions) -> None: copy_from_nixstore(src, dst) - inventory = get_inventory(clan_dir) - target_host = opts.target_host - # TODO: We should allow the template to specify machine metadata if not defined by user + new_machine = opts.machine if target_host: new_machine["deploy"] = {"targetHost": target_host} - inventory["machines"] = inventory.get("machines", {}) - inventory["machines"][machine_name] = new_machine + patch_inventory_with( + clan_dir, f"machines.{machine_name}", dataclass_to_dict(new_machine) + ) # Commit at the end in that order to avoid committing halve-baked machines # TODO: automatic rollbacks if something goes wrong - set_inventory(inventory, clan_dir, "Imported machine from template") commit_file( clan_dir / "machines" / machine_name, diff --git a/pkgs/clan-cli/tests/test_patch_inventory.py b/pkgs/clan-cli/tests/test_patch_inventory.py index cc2f73894..e1e1533b0 100644 --- a/pkgs/clan-cli/tests/test_patch_inventory.py +++ b/pkgs/clan-cli/tests/test_patch_inventory.py @@ -307,9 +307,7 @@ def test_update_list() -> None: assert writeables == {"writeable": {"foo"}, "non_writeable": set()} # Add "C" to the list - update = { - "foo": ["A", "B", "C"] # User wants to add "C" - } + update = {"foo": ["A", "B", "C"]} # User wants to add "C" patchset, _ = calc_patches( data_disk, update, all_values=data_eval, writeables=writeables @@ -320,9 +318,7 @@ def test_update_list() -> None: # "foo": ["A", "B"] # Remove "B" from the list # Expected is [ ] because ["A"] is defined in nix - update = { - "foo": ["A"] # User wants to remove "B" - } + update = {"foo": ["A"]} # User wants to remove "B" patchset, _ = calc_patches( data_disk, update, all_values=data_eval, writeables=writeables @@ -350,9 +346,7 @@ def test_update_list_duplicates() -> None: assert writeables == {"writeable": {"foo"}, "non_writeable": set()} # Add "A" to the list - update = { - "foo": ["A", "B", "A"] # User wants to add duplicate "A" - } + update = {"foo": ["A", "B", "A"]} # User wants to add duplicate "A" with pytest.raises(ClanError) as error: calc_patches(data_disk, update, all_values=data_eval, writeables=writeables) @@ -363,6 +357,31 @@ def test_update_list_duplicates() -> None: ) +def test_dont_persist_defaults() -> None: + """ + Default values should not be persisted to disk if not explicitly requested by the user. + """ + + prios = { + "enabled": {"__prio": 1500}, + "config": {"__prio": 100}, + } + data_eval = { + "enabled": True, + "config": {"foo": "bar"}, + } + data_disk = {} + writeables = determine_writeability(prios, data_eval, data_disk) + assert writeables == {"writeable": {"config", "enabled"}, "non_writeable": set()} + + update = {"config": {"foo": "foo"}} + patchset, delete_set = calc_patches( + data_disk, update, all_values=data_eval, writeables=writeables + ) + assert patchset == {"config.foo": "foo"} + assert delete_set == set() + + def test_update_mismatching_update_type() -> None: prios = { "foo": {