from pathlib import Path, PurePath from whereami import PROJ_ROOT from custtypes import ExecutedPath, IdlePath, VirtualPrivateServers, AnsibleScopes from anodes import RemoteNode, ControlNode, _userSSHSubParams # from ansible_vault import Vault import yaml as yams import re from typing import Literal # @TODO for 'Config' class, write methods to pull and push from Ansible YAML files # @NOTE https://docs.python.org/3/library/configparser.html#quick-start class Config: path: ExecutedPath = PROJ_ROOT / "config.ini" __controller = ControlNode() setattr(__controller, AnsibleScopes.INTERNAL.name, { "vars": (PurePath(str(path)),) }) def __init__(self, filepath: str = "config.ini", scope: AnsibleScopes = AnsibleScopes.INTERNAL.name, index: int = 0, mode: str = "r+"): self.scope = scope parent_dir = self.__controller.get_scope(scope, index) filepath = Path(parent_dir) / filepath filename: str = filepath.stem self.parse_method = "YML" if "." in filename: filename_arr = filename.split(".") basename: str = filename_arr[0] ext: str = filename_arr[len(filename_arr) - 1] if re.match(r"toml|ini", ext): self.parse_method: str = ext.upper() self.filepath: ExecutedPath = filepath self.mode = mode self.model = None self.file = None self.__remote: RemoteNode | None = None def __enter__(self): if not self.filepath.exists(): self.__remote = RemoteNode(self.__controller) return self.__remote self.file = open(str(self.filepath), self.mode) model = self.file.read() if self.parse_method == "INI": raise NotImplementedError elif self.parse_method == "TOML": raise NotImplementedError else: self.model = yams.load(model) if self.scope == AnsibleScopes.GROUPVARS.name or self.scope == AnsibleScopes.HOSTVARS.name: api_key: str = model["vps_service"]["api_key"] vault = Vault(model["vps_service"]["password"]) password: str = vault.load(model["vps_service"]["password"]) fqdn: str = model["fqdn"] service: VirtualPrivateServers = model["vps_service"]["type"] region: Literal["us-east"] = model["vps_service"]["region"] keywords: list[str] = model["keywords"] self.__remote = RemoteNode(self.__controller, api_key, password, fqdn, service, region, keywords) # @TODO add portion wherein SSH keys from 'model' are made to be present in 'self.__remote' self.__remote.import_keys("*") keyfiles = self.__remote.show_keys("available", list) keyfiles_contents = set(map(lambda p: p.read_text(), keyfiles)) keyfiles_pub = list(set(model["vps_service"]["ssh_authorized_keys"]) - keyfiles_contents) self.__remote.ssh.keys["available"] = tuple(keyfiles_pub) self.__remote.ssh.keys["selected"] = keyfiles_pub self.__remote.ssh.keys["authorized"] += keyfiles_pub keyfiles_paths = set(map(lambda p: str(p), keyfiles)) keyfiles_priv = list(set(model["vps_service"]["ssh_private_key_paths"]) - keyfiles_paths) self.__remote.ssh.keys["available"] = (*self.__remote.ssh.keys["available"],*keyfiles_priv) self.__remote.ssh.keys["selected"] += keyfiles_priv self.__remote.ssh.keys["used"] += keyfiles_priv self.__remote.ssh.fate: Literal["disposal", "retention"] = model["vps_service"]["root_fate"] return self.__remote else: raise ValueError def __exit__(self): if self.scope == AnsibleScopes.GROUPVARS.name or self.scope == AnsibleScopes.HOSTVARS.name: ansible_chunk = self.__remote.itemize() ansible_chunk["vps_service"]["ssh_motd_script_basenames"] = self.model["ssh_motd_script_basenames"] ansible_chunk["vps_service"]["ssh_private_key_path_pref"] = self.model["ssh_private_key_path_pref"] del self.model["fqdn"] del self.model["vps_service"] del self.model["keywords"] else: raise ValueError if self.parse_method == "INI": raise NotImplementedError elif self.parse_method == "TOML": raise NotImplementedError else: file_model = yams.dump(self.model | ansible_chunk) self.file.write(file_model) self.file.close()