PK!rMDtronald/__init__.py__version__ = "0.3" PK! ZZtronald/__main__.pytry: from tronald import cli except ImportError: from . import cli cli.run_cli() PK!7=%tronald/cli.pyimport click import shelve import inquirer import configparser from time import sleep from .config import MetaData, TronaldConfig, DOTFILE_NAME from .controllers import RemoteController, LocalController from .initial import ( KEY_PATH_SETUP, DEFAULT_DATABASE_SETUP, CONTAINER_PREFIX, CONTAINER_SUFFIX, perform_initial_setup, ) @click.group() def cli(): pass @cli.command(name="settings") @click.option("--prefix", "prefix") @click.option("--suffix", "suffix") @click.option("--key", "key_path") @click.option("--db", "db_name") def configure(prefix, suffix, key_path, db_name): config = TronaldConfig() if not prefix and not suffix and not key_path and not db_name: click.echo("Current settings:\n") for key, value in config.configuration.items(): click.echo("{}: {}".format(key, value)) return if key_path: config.set_value("keypath", key_path) if db_name: config.set_value("defaultdatabase", db_name) if prefix: config.set_value("prefix", prefix) if suffix: config.set_value("suffix", suffix) @cli.command() @click.option("--container", "container") @click.option("--ssh-user", "ssh_user") @click.option("--postgres-user", "postgres_user") @click.argument("host") @click.argument("target") def dump(host, container, ssh_user, postgres_user, target): meta_params = { "host": host, "ssh_user": ssh_user, "postgres_user": postgres_user, "container": container, "target": target, } meta_data = MetaData(**meta_params) controller = RemoteController(meta_data) controller.dump_and_transfer() @cli.command(name="import") @click.argument("dump_path") @click.argument("container_identifier") @click.option("--postgres-user", "postgres_user") def import_dump(dump_path, container_identifier, postgres_user): configuration_parameters = { "dump_path": dump_path, "container_identifier": container_identifier, "postgres_user": postgres_user or "django", } controller = LocalController(**configuration_parameters) controller.import_dump() def run_cli(): perform_initial_setup() cli() if __name__ == "__main__": perform_initial_setup() cli() PK! Xtronald/commands.pyimport os def build_postgres_dump(config): return "docker exec -t {} pg_dump {} -c -U {}".format( config.container, config.db_name, config.postgres_user ) def remove_remote_dump(config): return "rm {}".format(config.dump_name) def import_dump_to_local_container(dump_path, container_identifier, postgres_user): return os.system( "cat {} | docker exec -i {} psql -U {}".format( dump_path, container_identifier, postgres_user ) ) PK!㯜 tronald/config.pyimport os import configparser DOTFILE_NAME = "{}/tronald.ini".format(os.path.expanduser("~")) class TronaldConfig: def __init__(self): config = configparser.ConfigParser() config.read(DOTFILE_NAME) if not "tronald" in config.sections(): config["tronald"] = { "KeyPath": "", "DefaultDatabase": "", "Prefix": "", "Suffix": "", } with open(DOTFILE_NAME, "w") as configfile: config.write(configfile) config.read(DOTFILE_NAME) self.configuration = config["tronald"] def get_value(self, key): config = configparser.ConfigParser() config.read(DOTFILE_NAME) if not key in config["tronald"]: return None return config["tronald"][key] def set_value(self, key, value): config = configparser.ConfigParser() config.read(DOTFILE_NAME) config["tronald"][key] = value with open(DOTFILE_NAME, "w") as configfile: config.write(configfile) return config class MetaData: def __init__( self, host=None, container=None, ssh_user=None, postgres_user=None, dump_name=None, target=None, ): config = TronaldConfig() self.host = host self.container = container self.postgres_user = postgres_user self.ssh_user = ssh_user self.target = target self.db_name = config.get_value("defaultdatabase") self.prefix = config.get_value("prefix") self.suffix = config.get_value("suffix") self.key_path = config.get_value("keypath") @property def postgres_user(self): return self._postgres_user or "postgres" @postgres_user.setter def postgres_user(self, user): self._postgres_user = user @property def ssh_user(self): return self._ssh_user or "root" @ssh_user.setter def ssh_user(self, user): self._ssh_user = user @property def container(self): if self._container: return self._container if not self.host: raise Exception( "No container name derivation possible because of missing host." ) if self.host: return "{}{}{}".format(self.prefix, self.host, self.suffix) @container.setter def container(self, container_name): self._container = container_name @property def database(self): return self.db_name or "app" @property def rsa_key(self): return self.key_path or "~/.ssh/id_rsa" @property def target(self): return self._target or "recent-dump.db" @target.setter def target(self, target_path): self._target = target_path @property def dump_name(self): return "dump-{}.db".format(self._container) PK!hIJJtronald/controllers.pyimport time import paramiko from .commands import ( build_postgres_dump, remove_remote_dump, import_dump_to_local_container, ) def get_channel(client): return client.get_transport().open_session() class RemoteController: def __init__(self, config): self.client = paramiko.SSHClient() self.config = config self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) def dump_and_transfer(self): self.client.connect( self.config.host, username=self.config.ssh_user, key_filename=self.config.key_path, ) stdout_stream = self.client.exec_command(build_postgres_dump(self.config))[1] stdout = stdout_stream.read().decode("utf-8") with open(self.config.target, "w") as output_file: output_file.write(stdout) class LocalController: def __init__(self, dump_path, container_identifier, postgres_user): self.postgres_user = postgres_user self.dump_path = dump_path self.container = container_identifier def import_dump(self): configuration_parameters = { "dump_path": self.dump_path, "container_identifier": self.container, "postgres_user": self.postgres_user, } import_dump_to_local_container(**configuration_parameters) PK!!/RRtronald/initial.pyimport os import shelve import inquirer import configparser from .config import DOTFILE_NAME, TronaldConfig KEY_PATH_SETUP = [ inquirer.Text( "key_path", "Please enter the path to your preferred RSA private key", default="~/.ssh/id_rsa", ) ] DEFAULT_DATABASE_SETUP = [ inquirer.Text( "db_name", "Please enter the default database name to pull dumps from", default="app", ) ] CONTAINER_PREFIX = [ inquirer.Text( "prefix", "If there are common container prefixes, please provide them for container name derivation", ) ] CONTAINER_SUFFIX = [ inquirer.Text( "suffix", "If there are common container suffixes, please provide them for container name derivation", ) ] def perform_initial_setup(): config = TronaldConfig() if not config.get_value("keypath"): answer = inquirer.prompt(KEY_PATH_SETUP) key_path = answer["key_path"] if key_path.startswith("~"): key_location = os.path.expanduser(key_path) else: key_location = key_path config.set_value("keypath", key_location) if not config.get_value("defaultdatabase"): answer = inquirer.prompt(DEFAULT_DATABASE_SETUP) config.set_value("defaultdatabase", answer["db_name"]) if not config.get_value("prefix"): answer = inquirer.prompt(CONTAINER_PREFIX) config.set_value("prefix", answer["prefix"]) if not config.get_value("suffix"): answer = inquirer.prompt(CONTAINER_SUFFIX) config.set_value("suffix", answer["suffix"]) PK!H+],0&tronald-0.3.dist-info/entry_points.txtN+I/N.,()*)KIz񹉙yV9\\PK!HڽTUtronald-0.3.dist-info/WHEEL A н#Z;/"d&F[xzw@Zpy3Fv]\fi4WZ^EgM_-]#0(q7PK!Htronald-0.3.dist-info/METADATAN0~=X)- T@AV `;B}{R~;<`Х:yA牭<6 8)ŷLx0T,=Uq1}u{>Oٱ& [8&2L/dz _] `:~-BPK!H&.tronald-0.3.dist-info/RECORDu9@ K0A,jA B6׏;TD'|缩=t@U fcc@uI?R v.ũR> v,0{l#`<Db8Yaʢ0' w[l/% x{ʤ5'A%%WN^ZR\{g==4òhC EZR*SuyiǐqRbC쯭,EEa.iZD9@PP꽯r"MN)Vb?nhg9Dgͳ& \j 'uT6&WJ  MjQ(/W%&ΣEQ$L~> wJ7 ҉+VvBǃs9-Gp`YqG69 PK!rMDtronald/__init__.pyPK! ZZEtronald/__main__.pyPK!7=%tronald/cli.pyPK! X tronald/commands.pyPK!㯜  tronald/config.pyPK!hIJJtronald/controllers.pyPK!!/RR4tronald/initial.pyPK!H+],0&#tronald-0.3.dist-info/entry_points.txtPK!HڽTU&$tronald-0.3.dist-info/WHEELPK!H$tronald-0.3.dist-info/METADATAPK!H&.%tronald-0.3.dist-info/RECORDPK @(