diff --git a/confctx.py b/confctx.py new file mode 100644 index 0000000..5da471a --- /dev/null +++ b/confctx.py @@ -0,0 +1,91 @@ +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() + 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 + + file_model = yams.dump(self.model | ansible_chunk) + self.file.write(file_model) + self.file.close()