This commit is contained in:
+31
-24
@@ -1,4 +1,4 @@
|
|||||||
playbook_name: "test_playbook"
|
playbook_name: "gitea_service_backup"
|
||||||
registries:
|
registries:
|
||||||
- "./registry/directory_actions.py"
|
- "./registry/directory_actions.py"
|
||||||
- "./registry/restic_actions.py"
|
- "./registry/restic_actions.py"
|
||||||
@@ -11,30 +11,37 @@ global_context:
|
|||||||
passwordFile: "/home/esilva/Trash/test_borgmatic/pass_file"
|
passwordFile: "/home/esilva/Trash/test_borgmatic/pass_file"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: "dump rusty-packages db"
|
- name: "find database container"
|
||||||
actions:
|
actions:
|
||||||
dump_database: "dump_pg_database"
|
find_container: "get_service_container_name"
|
||||||
context:
|
context:
|
||||||
serviceName: "gitea-db"
|
service_name: "gitea-db"
|
||||||
tmpPathPrefix: "/tmp/db_dump.sql"
|
|
||||||
- name: "test context"
|
- name: "dump database"
|
||||||
actions:
|
actions:
|
||||||
dump_database: "dump_pg_database"
|
dump_database: "dump_container_pg_db"
|
||||||
context:
|
context:
|
||||||
serviceName: "gitea-db"
|
dump_path: "/tmp/db_dump.sql"
|
||||||
tmpPathPrefix: "/tmp/db_dump.sql"
|
db_user: "gitea"
|
||||||
# - name: "backup db to restic repo"
|
database: "gitea"
|
||||||
# actions:
|
|
||||||
# dump_database: "backup_data_to_restic_repo"
|
- name: "restic database backup"
|
||||||
# context:
|
actions:
|
||||||
# sourcePath: "/tmp/db_dump.sql"
|
dump_database: "backup_data_to_restic_repo"
|
||||||
# serviceTag: "gitea-db"
|
context:
|
||||||
# - name: "backup rusty-packages"
|
source_path: "/tmp/db_dump.sql"
|
||||||
# actions:
|
tags: ["gitea", "db-dump"]
|
||||||
# create_repo_dir_if_not_exists: "create_dir_if_not_exists"
|
|
||||||
# create_repo_if_not_exists: "create_repo_if_not_exists"
|
- name: "backup gitea mount points data"
|
||||||
# check_restic_environment: "check_restic_environment"
|
actions:
|
||||||
# backup_data_to_restic_repo: "backup_data_to_restic_repo"
|
backup_data_to_restic_repo: "backup_data_to_restic_repo"
|
||||||
# context:
|
context:
|
||||||
# sourcePath: "/home/esilva/Trash/rusty_packages"
|
source_path: "/home/esilva/Trash/docker-compose/resources/gitea/gitea_data/"
|
||||||
# serviceTag: "rusty-packages"
|
tags: ["gitea", "data"]
|
||||||
|
|
||||||
|
- name: "backup gitea database mount points data"
|
||||||
|
actions:
|
||||||
|
backup_data_to_restic_repo: "backup_data_to_restic_repo"
|
||||||
|
context:
|
||||||
|
source_path: "/home/esilva/Trash/docker-compose/resources/gitea/postgres_data/"
|
||||||
|
tags: ["gitea", "db-data"]
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ dbpgactions = ActionRegistry("dbpg_actions_reg")
|
|||||||
|
|
||||||
|
|
||||||
@dbpgactions.register(name="dump_pg_database", version="")
|
@dbpgactions.register(name="dump_pg_database", version="")
|
||||||
@ContextChecker.requires("database")
|
@ContextChecker.requires("database", "compose")
|
||||||
def dump_pg_database(ctx, name) -> StepLog:
|
def dump_pg_database_from_container(ctx, name) -> StepLog:
|
||||||
print(ctx, file=sys.stderr)
|
print(ctx, file=sys.stderr)
|
||||||
return StepLog.ok(name, "", pipe_ctx={"new_data": "coolData"})
|
return StepLog.ok(name, "", pipe_ctx={"new_data": "coolData"})
|
||||||
|
|||||||
@@ -1,21 +1,65 @@
|
|||||||
|
from os import error
|
||||||
|
|
||||||
|
from yaml import dump
|
||||||
|
|
||||||
|
from playbook import models
|
||||||
from playbook.action_registry import ActionRegistry
|
from playbook.action_registry import ActionRegistry
|
||||||
from playbook.models import StepLog
|
from playbook.models import StepLog, ContextChecker
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import docker
|
import docker
|
||||||
import subprocess
|
import subprocess
|
||||||
from typing import List, Dict, Any, Tuple
|
from typing import List, Dict, Any, Tuple
|
||||||
|
# from docker.models.containers import Container
|
||||||
|
|
||||||
|
|
||||||
dockeractions = ActionRegistry("docker_actions_reg")
|
dockeractions = ActionRegistry("docker_actions_reg")
|
||||||
|
|
||||||
|
|
||||||
@dockeractions.register(name="get_service_container", version="")
|
@dockeractions.register(name="get_service_container_name", version="")
|
||||||
def get_service_container(ctx, name) -> StepLog:
|
@ContextChecker.requires("service_name")
|
||||||
|
def get_service_container_name(ctx, name) -> StepLog:
|
||||||
client = docker.from_env()
|
client = docker.from_env()
|
||||||
|
|
||||||
filters: Dict[str, Any]= {"label": [f"com.docker.compose.service=gitea-db"]}
|
filters: Dict[str, Any]= {
|
||||||
print(client.containers.list(filters=filters, all=True), file=sys.stderr)
|
"label": [f"com.docker.compose.service={ctx["service_name"]}"]
|
||||||
|
}
|
||||||
|
containers = client.containers.list(filters=filters, all=True)
|
||||||
|
|
||||||
return StepLog.ok(name, "cool beans")
|
if not containers:
|
||||||
|
return StepLog.fail(name, [{
|
||||||
|
"status": "failed",
|
||||||
|
"output": f"no container found for service {ctx["service_name"]}"}
|
||||||
|
])
|
||||||
|
|
||||||
|
new_data = {"container": containers[0].id}
|
||||||
|
return StepLog.ok(name, f"found container {containers[0].id}", pipe_ctx=new_data)
|
||||||
|
|
||||||
|
|
||||||
|
@dockeractions.register(name="dump_container_pg_db", version="")
|
||||||
|
@ContextChecker.requires("container", "dump_path", "db_user", "database")
|
||||||
|
def dump_container_pg_db(ctx, name) -> StepLog:
|
||||||
|
client = docker.from_env()
|
||||||
|
container = client.containers.get(ctx["container"])
|
||||||
|
|
||||||
|
res = container.exec_run(
|
||||||
|
cmd=f"pg_dump -U {ctx["db_user"]} {ctx["database"]}",
|
||||||
|
stream=False, # change to True to stream directly to host file (need to check)
|
||||||
|
demux=True,
|
||||||
|
)
|
||||||
|
stdout, stderr = res.output
|
||||||
|
|
||||||
|
if stderr:
|
||||||
|
if not isinstance(stderr, bytes):
|
||||||
|
return StepLog.fail(name, [{"status": "failed", "output": "stderr is not bytes"}])
|
||||||
|
if res.exit_code != 0:
|
||||||
|
error_msg = stderr.decode("utf-8") if stderr else "dump failed with no output"
|
||||||
|
return StepLog.fail(name, [{"status": "failed", "output": error_msg}])
|
||||||
|
|
||||||
|
if not isinstance(stdout, bytes):
|
||||||
|
return StepLog.fail(name, [{"status": "failed", "output": "stdout is not bytes"}])
|
||||||
|
with open(ctx["dump_path"], "wb") as f:
|
||||||
|
f.write(stdout)
|
||||||
|
|
||||||
|
return StepLog.ok(name, "database dump successful")
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# restic actions registry
|
# restic actions registry
|
||||||
from playbook.action_registry import ActionRegistry
|
from playbook.action_registry import ActionRegistry
|
||||||
from playbook.models import StepLog
|
from playbook.models import ContextChecker, StepLog
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
@@ -145,11 +145,15 @@ def check_if_repo_exists(ctx, name: str = "") -> StepLog:
|
|||||||
|
|
||||||
|
|
||||||
@restic.register(name="backup_data_to_restic_repo", version="")
|
@restic.register(name="backup_data_to_restic_repo", version="")
|
||||||
|
@ContextChecker.requires("source_path", "passwordFile")
|
||||||
def backup_data_to_restic_repo(ctx, name) -> StepLog:
|
def backup_data_to_restic_repo(ctx, name) -> StepLog:
|
||||||
cmd = ["restic", "backup", ctx["sourcePath"], "--json", "--quiet",
|
cmd = ["restic", "backup", ctx["source_path"], "--json", "--quiet",
|
||||||
"-r", ctx["repoPath"], "--password-file", ctx["passwordFile"]]
|
"-r", ctx["repoPath"], "--password-file", ctx["passwordFile"]]
|
||||||
|
if ctx["tags"]:
|
||||||
|
cmd.extend(["--tag", ','.join(ctx["tags"])])
|
||||||
|
|
||||||
returncode, json_output = run_restic_command(cmd)
|
returncode, json_output = run_restic_command(cmd)
|
||||||
|
print(json_output, file=sys.stderr)
|
||||||
errors: List[Dict[str, Any]] = find_restic_errors(json_output)
|
errors: List[Dict[str, Any]] = find_restic_errors(json_output)
|
||||||
|
|
||||||
# Handle error messages in JSON output
|
# Handle error messages in JSON output
|
||||||
|
|||||||
+1
-1
@@ -33,7 +33,7 @@ def main():
|
|||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
print(newPlay.view_playbook())
|
# print(newPlay.view_playbook())
|
||||||
print(json.dumps(asdict(newPlay.play()), indent=2))
|
print(json.dumps(asdict(newPlay.play()), indent=2))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user