diff --git a/RELEASES.rst b/RELEASES.rst index 75cc9e0..8780e55 100644 --- a/RELEASES.rst +++ b/RELEASES.rst @@ -1,6 +1,12 @@ Releases ======== +v0.1.0, 2022-12-01 +~~~~~~~~~~~~~~~~~~~ +* Add simpler helper to restore backups (``deploy.db-restore``) when testing disaster recovery tasks (#49) +* Fix ``utils.get-db-dump`` breaking when output includes kubectl warnings (#48) +* Use pre-commit for: black, flake8, isort, prettier (#50) + v0.0.21, 2022-29-08 ~~~~~~~~~~~~~~~~~~~ * Adds a utility `util.scale-app` which assists with scaling a namespace's app and celery deployments and celery-beat statefulset. diff --git a/kubesae/ansible/deploy.py b/kubesae/ansible/deploy.py index 73f8ff1..852c003 100644 --- a/kubesae/ansible/deploy.py +++ b/kubesae/ansible/deploy.py @@ -1,5 +1,7 @@ import os +from pathlib import Path + import invoke @@ -117,7 +119,35 @@ def ansible_playbook(c, name, extra="", verbosity=1, limit=""): c.run(f"ansible-playbook {name} {limit} {extra} {v_flag}", env=shell_env) +@invoke.task(pre=[install_requirements]) +def ansible_db_restore(c, filename, name="", extra="", verbosity=0, limit=""): + """Restore PostgreSQL database with an Ansible db-restore.yaml playbook. + + Params: + filename: The custom-formatted PostgreSQL database archive path + name: The name of the Ansible playbook to run, including the extension + extra: Additional command line arguments to ansible-playbook + verbosity: integer level of verbosity from 0 to 4 (most verbose) + limit: The limit passed to underlying ansible-playbook + + Usage: inv deploy.db-restore --filename=mydbarchive.pgdump + + """ + if not name: + name = ( + "db-restore.yaml" + if os.path.exists("deploy/db-restore.yaml") + else "db-restore.yml" + ) + archive_path = Path(filename) + extra = [extra, f"-e k8s_restore_local_archive_path={archive_path.resolve()}"] + deploy["playbook"]( + c, name=name, extra=" ".join(extra), verbosity=verbosity, limit=limit + ) + + deploy = invoke.Collection("deploy") deploy.add_task(install_requirements, "install") deploy.add_task(ansible_deploy, "deploy") deploy.add_task(ansible_playbook, "playbook") +deploy.add_task(ansible_db_restore, "db-restore") diff --git a/kubesae/utils.py b/kubesae/utils.py index e5b1ab1..6e91a13 100644 --- a/kubesae/utils.py +++ b/kubesae/utils.py @@ -26,7 +26,7 @@ def result_to_json(result: invoke.Result): @invoke.task(name="get_db_backup") def get_backup_from_hosting( - c, latest="daily", profile="caktus", backup_name=None, list=False + c, latest="daily", profile="caktus", backup_name=None, list=False, dest="" ): """Downloads a backup from the caktus hosting services bucket @@ -37,6 +37,7 @@ def get_backup_from_hosting( profile (str, optional): The AWS profile to allow access to the s3 bucket. DEFAULT: "caktus" backup_name(str, optional): A specific backup filename. list(bool, optional): If set, will list the contents of the bucket for the projects folder and exit. + dest (str, optional): Output filename Usage: $ inv utils.get-db-backup @@ -55,6 +56,8 @@ def get_backup_from_hosting( Will list all of the backup files using the a locally configured AWS_PROFILE named "client-aws" """ + if c.config.get("hosting_services_backup_profile"): + profile = c.config.hosting_services_backup_profile if c.config.get("hosting_services_backup_bucket"): bucket = f"s3://{c.config.hosting_services_backup_bucket.strip('/')}" else: @@ -95,12 +98,12 @@ def get_backup_from_hosting( f"{latest}-{c.config.hosting_services_backup_folder}-{dates[-1]}.pgdump" ) + if not dest: + dest = backup_name if not backup_name: print(f"No backup matching a latest of {latest} could be found.") return - c.run( - f"aws s3 cp {bucket_folder}/{backup_name} ./{backup_name} --profile {profile}" - ) + c.run(f"aws s3 cp {bucket_folder}/{backup_name} ./{dest} --profile {profile}") @invoke.task