diff --git a/pkgs/clan-cli/clan_cli/api/modules.py b/pkgs/clan-cli/clan_cli/api/modules.py index 290689bf4..0812c89c5 100644 --- a/pkgs/clan-cli/clan_cli/api/modules.py +++ b/pkgs/clan-cli/clan_cli/api/modules.py @@ -3,13 +3,16 @@ import re import tomllib from dataclasses import dataclass from pathlib import Path +from typing import Any, get_args, get_type_hints from clan_cli.cmd import run_no_stdout from clan_cli.errors import ClanCmdError, ClanError -from clan_cli.inventory import Inventory, load_inventory_json +from clan_cli.inventory import Inventory, load_inventory_json, save_inventory +from clan_cli.inventory.classes import Service from clan_cli.nix import nix_eval from . import API +from .serde import from_dict @dataclass @@ -153,3 +156,30 @@ def get_module_info( @API.register def get_inventory(base_path: str) -> Inventory: return load_inventory_json(base_path) + + +@API.register +def set_service_instance( + base_path: str, module_name: str, instance_name: str, config: dict[str, Any] +) -> None: + service_keys = get_type_hints(Service).keys() + + if module_name not in service_keys: + raise ValueError( + f"{module_name} is not a valid Service attribute. Expected one of {', '.join(service_keys)}." + ) + + inventory = load_inventory_json(base_path) + target_type = get_args(get_type_hints(Service)[module_name])[1] + + module_instance_map: dict[str, Any] = getattr(inventory.services, module_name, {}) + + module_instance_map[instance_name] = from_dict(target_type, config) + + setattr(inventory.services, module_name, module_instance_map) + + save_inventory( + inventory, base_path, f"Update {module_name} instance {instance_name}" + ) + + # TODO: Add a check that rolls back the inventory if the service config is not valid or causes conflicts.