"""CoopHost module.""" from os import chdir, mkdir from os.path import basename, exists from pathlib import Path from socket import gethostname import click from autonomic.config import CONFIG_YAML, INFRA_DIR from autonomic.logger import log from autonomic.settings import add, get from autonomic.utils import ( ensure_config_dir, ensure_deploy_d_dir, exit, input_ask, pass_ask, question_ask, run, yaml_dump, yaml_load, ) hostname = gethostname() @click.command() @click.pass_context def coophost(ctx): """Manage CoopHost resources.""" ensure_config_dir() ensure_deploy_d_dir() app_dir = Path(".").absolute() app = basename(app_dir) log.info("Auto-detected the {} application".format(app)) choices = ["encrypt", "decrypt"] operation = question_ask("operation", "Which operation?", choices) if operation == "encrypt": encrypt(app, app_dir) elif operation == "decrypt": decrypt(app, app_dir) def get_vault_pass(app): """Retrieve or set the app vault password.""" app_settings = get(app) if app_settings is not None and "vault-password" in app_settings: log.info("Using app vault password stored in {}".format(CONFIG_YAML)) return app_settings["vault-password"] log.info("No app vault password configured") vault_password = pass_ask("Vault password?") log.info("App vault password stored in {}".format(CONFIG_YAML)) add({app: {"vault-password": vault_password}}) return vault_password def decrypt(app, app_dir): """Decrypt a secret.""" vault_password = get_vault_pass(app) name = input_ask("Which variable do you want to decrypt?") vault_path = (Path(".") / "deploy.d" / "vault").absolute() var_path = (vault_path / "{}.yml".format(name)).absolute() if not exists(var_path): exit("{}.yml is missing?".format(name)) cmd = [ ".venv/bin/ansible", hostname, "--inventory", "{},".format(hostname), "-m", "debug", "-a", "var='{}'".format(name), "-e @{}".format(var_path), "--ask-vault-pass", "-e", "ansible_user={}".format(get("username")), ] decrypted = run( cmd, cwd=INFRA_DIR, output=True, pexpect=True, pexpected={"(?i)vault password:": vault_password}, ) log.info(decrypted) def encrypt(app, app_dir): """Encrypt a secret for a CoopHost package.""" vault_password = get_vault_pass(app) name = input_ask("Which variable do you want to encrypt?") value = pass_ask("Variable value to encrypt?") cmd = [".venv/bin/ansible-vault", "encrypt_string", "--name", name, value] encrypted = run( cmd, cwd=INFRA_DIR, pexpect=True, pexpected={ "(?i)new vault password:": vault_password, "(?i)confirm new vault password:": vault_password, }, ) encrypted = ( encrypted.strip() .replace("\r", "") .replace("\nEncryption successful", "") ) chdir(app_dir) log.info("Changed directory back to {}".format(app_dir)) vault_path = (Path(".") / "deploy.d" / "vault").absolute() if not exists(vault_path): log.info("Creating {}".format(vault_path)) mkdir(vault_path) var_path = (vault_path / "{}.yml".format(name)).absolute() with open(var_path, "w"): loaded = yaml_load(encrypted, text=True) yaml_dump(var_path, loaded) log.success("Encrypted and saved {} in {}".format(name, var_path))