113 lines
4.4 KiB
Python
113 lines
4.4 KiB
Python
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()
|