import click as cli from pathlib import Path, PurePath, PurePosixPath, PureWindowsPath, PosixPath, WindowsPath from whereami import PROJ_ROOT from custtypes import ExecutedPath, IdlePath import yaml as yams from anodes import RemoteNode, ControlNode # from typing import TypeAlias as Neotype from typing import Literal from enum import Enum from ansible_vault import Vault from random import choice # import configparser as ini # from cerberus import Validator as constrain_by # import skansible_types as skato class AnsibleScope(Enum): INTERNAL = 0 INVENTORY = 1 GROUPVARS = 2 HOSTVARS = 3 ROLE = 4 # @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" _cnode = ControlNode(PROJ_ROOT) __scope_paths = { AnsibleScope.INTERNAL.name: path, AnsibleScope.GROUPVARS.name: Path(str(_cnode.invvar_data[0])), AnsibleScope.HOSTVARS.name: Path(str(_cnode.invvar_data[1])) } def __init__(self, filepath: str, anscope: AnsibleScope = AnsibleScope.INTERNAL.name, mode: str = "r+"): filepath: ExecutedPath = self.__scope_paths[anscope] / filepath if filepath.exists(): self.filepath = filepath else: raise FileNotFoundError self.mode: str = mode self.file = None self.model = None def __enter__(self): self.file = open(str(self.filepath), self.mode) self.model = yams.load(self.file.read()) return self.model def __exit__(self, exc_type, exc_value, exc_traceback): file_content = yams.dump(self.model) self.file.write(file_content) self.file.close() @cli.group() @cli.pass_context def skansible(ctx): ctx.ensure_object(dict) @skansible.group(help="Replace conventionally-typed Ansible variables") @cli.pass_context def mod(ctx): with Config(entity, AnsibleScope.HOSTVARS.name) as config: ctx.obj["fqdn"] = config["fqdn"] @skansible.group(help="Remove conventionally-typed Ansible variables") def rm(): pass @skansible.group(help="Append conventionally-typed entries to Ansible variables") def append(): pass @skansible.group(help="Initialize Ansible variable or object with defaults") def init(): pass # @skansible.group(help="Show Ansible assets") # @cli.argument("-d", "--datatype", type=str, help="Specify type of Ansible object or variable to show") # def show(datatype): # pass @mod.command("vps", help="Add 'vps_service' Ansible variable") @cli.argument("entity", type=str, help="Specify FQDN/alias or host group to associate with the VPS") @cli.option("-p", "--password", type=str, prompt=True, prompt_required=False, help="Prompt for password of root or administrative user of VPS") @cli.option("-a", "--api", type=str, help="API key for host service providing VPS") @cli.option("-k", "--pubkey", multiple=True, help="A file glob pattern for acquiring user's public SSH keys") @cli.option("-k", "--privkey", multiple=True, help="A file glob pattern for acquiring user's private SSH keys") @cli.option("-m", "--motd", multiple=True, help="Provide basenames for MOTD SSH scripts") @cli.option("-t", "--tag", multiple=True, type=str) @cli.option("-s", "--service", type=str) @cli.option("-r", "--region", type=str) @cli.option("-f", "--fate", type=str) @cli.pass_context # @TODO rewrite below command function, using 'ctx' parameter for values shared with sibling commands def mod_vps(ctx, entity: str, password: str | None = None, api: str | None = None, pubkey: tuple[str] = None, privkey: tuple[str] = None, service: str | int | None = None, region: Literal["us-east"] | None = None, tags: tuple[str] = None, fate: Literal["disposal", "retention"] | None = None): with Config(entity, AnsibleScope.HOSTVARS.name) as config: raise NotImplementedError @mod.command("host", help="Add host to Ansible inventory") @cli.argument("hostname", multiple=True, type=str, help="Provide aliases / FQDN / IP addresses for host(s)") @cli.option("-g", "--group", type=str, default="ungrouped", help="Provide group name given host(s) fall under") @cli.pass_context # @TODO rewrite below command function, using 'ctx' parameter for values shared with sibling commands def mod_host(group, hostname): with Config(entity, AnsibleScope.INVENTORY.name) as config: raise NotImplementedError if __name__ == "__main__": skansible()