Merge pull request 'API: init delete instance' (#5641) from instance-delete into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5641
This commit is contained in:
@@ -67,7 +67,7 @@ def set_value_by_path_tuple(d: DictLike, path: PathTuple, content: Any) -> None:
|
||||
current[keys[-1]] = content
|
||||
|
||||
|
||||
def delete_by_path_tuple(d: dict[str, Any], path: PathTuple) -> Any:
|
||||
def delete_by_path_tuple(d: DictLike, path: PathTuple) -> Any:
|
||||
"""Deletes the nested entry specified by a dot-separated path from the dictionary using pop().
|
||||
|
||||
:param data: The dictionary to modify.
|
||||
@@ -126,6 +126,7 @@ def delete_by_path(d: dict[str, Any], path: str) -> Any:
|
||||
V = TypeVar("V")
|
||||
|
||||
|
||||
# TODO: Use PathTuple
|
||||
def get_value_by_path(
|
||||
d: DictLike,
|
||||
path: str,
|
||||
|
||||
@@ -15,7 +15,11 @@ from clan_lib.nix_models.clan import (
|
||||
InventoryInstancesType,
|
||||
)
|
||||
from clan_lib.persist.inventory_store import InventoryStore
|
||||
from clan_lib.persist.path_utils import get_value_by_path, set_value_by_path
|
||||
from clan_lib.persist.path_utils import (
|
||||
delete_by_path_tuple,
|
||||
get_value_by_path,
|
||||
set_value_by_path,
|
||||
)
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -492,6 +496,37 @@ def list_service_instances(flake: Flake) -> dict[str, InventoryInstanceInfo]:
|
||||
return res
|
||||
|
||||
|
||||
@API.register
|
||||
def delete_service_instance(
|
||||
flake: Flake,
|
||||
instance_ref: str,
|
||||
) -> None:
|
||||
"""Deletes an instance
|
||||
|
||||
:param instance_ref: The name of the instance to update
|
||||
|
||||
:raises ClanError: If the instance_ref is invalid or cannot be deleted
|
||||
"""
|
||||
inventory_store = InventoryStore(flake)
|
||||
inventory = inventory_store.read()
|
||||
|
||||
instance: InventoryInstance | None = get_value_by_path(
|
||||
inventory, f"instances.{instance_ref}", None
|
||||
)
|
||||
|
||||
if instance is None:
|
||||
msg = f"Instance '{instance_ref}' not found"
|
||||
raise ClanError(msg)
|
||||
|
||||
delete_by_path_tuple(inventory, ("instances", f"{instance_ref}"))
|
||||
|
||||
# TODO: improve error message
|
||||
# "Cannot delete path 'instances.static"
|
||||
inventory_store.write(
|
||||
inventory, message=f"Delete service instance '{instance_ref}'"
|
||||
)
|
||||
|
||||
|
||||
@API.register
|
||||
def set_service_instance(
|
||||
flake: Flake, instance_ref: str, roles: InventoryInstanceRolesType
|
||||
@@ -540,6 +575,8 @@ def set_service_instance(
|
||||
)
|
||||
|
||||
# override settings, machines only if passed
|
||||
# TODO: refactor after extraModules removal
|
||||
# in https://git.clan.lol/clan/clan-core/pulls/5634
|
||||
merged = {
|
||||
**static,
|
||||
**role_cfg,
|
||||
|
||||
@@ -6,6 +6,7 @@ from clan_cli.tests.fixtures_flakes import nested_dict
|
||||
from clan_lib.errors import ClanError
|
||||
from clan_lib.flake.flake import Flake
|
||||
from clan_lib.services.modules import (
|
||||
delete_service_instance,
|
||||
get_service_readmes,
|
||||
list_service_instances,
|
||||
list_service_modules,
|
||||
@@ -251,3 +252,67 @@ def test_update_service_instance(
|
||||
assert updated_machines == {
|
||||
"sara": {"settings": {"greeting": "sara"}},
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.with_core
|
||||
def test_delete_service_instance(
|
||||
clan_flake: Callable[..., Flake],
|
||||
) -> None:
|
||||
# Data that can be mutated via API calls
|
||||
mutable_inventory_json: Inventory = {
|
||||
"instances": {
|
||||
"to-remain": {"module": {"name": "admin"}},
|
||||
"to-delete": {"module": {"name": "admin"}},
|
||||
}
|
||||
}
|
||||
|
||||
flake = clan_flake({}, mutable_inventory_json=mutable_inventory_json)
|
||||
|
||||
# Ensure preconditions
|
||||
instances = list_service_instances(flake)
|
||||
assert set(instances.keys()) == {"to-delete", "to-remain"}
|
||||
|
||||
# Raises for non-existing instance
|
||||
with pytest.raises(ClanError) as excinfo:
|
||||
delete_service_instance(flake, "non-existing-instance")
|
||||
assert "Instance 'non-existing-instance' not found" in str(excinfo.value)
|
||||
|
||||
# Deletes instance
|
||||
delete_service_instance(flake, "to-delete")
|
||||
|
||||
updated_instances = list_service_instances(flake)
|
||||
assert set(updated_instances.keys()) == {"to-remain"}
|
||||
|
||||
|
||||
@pytest.mark.with_core
|
||||
def test_delete_static_service_instance(
|
||||
clan_flake: Callable[..., Flake],
|
||||
) -> None:
|
||||
# Data that can be mutated via API calls
|
||||
mutable_inventory_json: Inventory = {
|
||||
"instances": {
|
||||
"static": {"module": {"name": "admin"}},
|
||||
}
|
||||
}
|
||||
|
||||
flake = clan_flake(
|
||||
{
|
||||
"inventory": {
|
||||
"instances": {
|
||||
"static": {"roles": {"default": {}}},
|
||||
}
|
||||
}
|
||||
},
|
||||
mutable_inventory_json=mutable_inventory_json,
|
||||
)
|
||||
|
||||
# Ensure preconditions
|
||||
instances = list_service_instances(flake)
|
||||
assert set(instances.keys()) == {"static"}
|
||||
|
||||
# Raises for non-existing instance
|
||||
with pytest.raises(ClanError) as excinfo:
|
||||
delete_service_instance(flake, "static")
|
||||
|
||||
# TODO: improve error message
|
||||
assert "Cannot delete path 'instances.static" in str(excinfo.value)
|
||||
|
||||
Reference in New Issue
Block a user