This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# restic actions registry
|
||||
from playbook.action_registry import ActionRegistry
|
||||
from playbook.models import StepLog
|
||||
from playbook.logging_models import StepLogModel
|
||||
from playbook.models import ContextChecker
|
||||
|
||||
from registry.docker_actions import dockeractions
|
||||
@@ -9,14 +9,13 @@ import sys
|
||||
import json
|
||||
import docker
|
||||
import subprocess
|
||||
from typing import List, Dict, Any, Tuple
|
||||
|
||||
|
||||
dbpgactions = ActionRegistry("dbpg_actions_reg")
|
||||
dbpgactions = ActionRegistry(name="dbpg_actions_reg")
|
||||
|
||||
|
||||
@dbpgactions.register(name="dump_pg_database", version="")
|
||||
@ContextChecker.requires("database", "compose")
|
||||
def dump_pg_database_from_container(ctx, name) -> StepLog:
|
||||
def dump_pg_database_from_container(ctx, name) -> StepLogModel:
|
||||
print(ctx, file=sys.stderr)
|
||||
return StepLog.ok(name, "", pipe_ctx={"new_data": "coolData"})
|
||||
return StepLogModel.ok(name, "", pipe_ctx={"new_data": "coolData"})
|
||||
|
||||
@@ -1,42 +1,42 @@
|
||||
# directory actions registry
|
||||
from playbook.action_registry import ActionRegistry
|
||||
from playbook.models import StepLog
|
||||
from playbook.logging_models import StepLogModel
|
||||
|
||||
import os
|
||||
|
||||
|
||||
diract = ActionRegistry("directory_actions_reg")
|
||||
diract = ActionRegistry(name="directory_actions_reg")
|
||||
|
||||
|
||||
@diract.register(name="directory_exists", version="stat1.0")
|
||||
def directory_exists(ctx, name) -> StepLog:
|
||||
def directory_exists(ctx, name) -> StepLogModel:
|
||||
if not os.path.exists(ctx["repoPath"]):
|
||||
return StepLog.fail(name, [
|
||||
return StepLogModel.fail(name, [
|
||||
{"status": "failed", "output": f"dir '{ctx["repoPath"]}' doesn't exist"}]
|
||||
)
|
||||
return StepLog.ok(name, "directory exists")
|
||||
return StepLogModel.ok(name, "directory exists")
|
||||
|
||||
|
||||
@diract.register(name="create_dir", version="stat1.0")
|
||||
def create_dir(ctx, name) -> StepLog:
|
||||
def create_dir(ctx, name) -> StepLogModel:
|
||||
try:
|
||||
os.makedirs(ctx["repoPath"])
|
||||
except Exception as e:
|
||||
return StepLog.fail(name, [{"status": "failed", "output": str(e)}])
|
||||
return StepLogModel.fail(name, [{"status": "failed", "output": str(e)}])
|
||||
|
||||
return StepLog.ok(name, "dir create successfully")
|
||||
return StepLogModel.ok(name, "dir create successfully")
|
||||
|
||||
|
||||
@diract.register(name="create_dir_if_not_exists", version="stat1.0")
|
||||
def create_dir_if_not_exists(ctx, name) -> StepLog:
|
||||
log: StepLog = directory_exists(ctx, name + f".{directory_exists.__name__}")
|
||||
def create_dir_if_not_exists(ctx, name) -> StepLogModel:
|
||||
log: StepLogModel = directory_exists(ctx, name + f".{directory_exists.__name__}")
|
||||
msg: str = ""
|
||||
if log.failed:
|
||||
dir_creation_log: StepLog = create_dir(ctx, name + f".{create_dir.__name__}")
|
||||
dir_creation_log: StepLogModel = create_dir(ctx, name + f".{create_dir.__name__}")
|
||||
if dir_creation_log.failed:
|
||||
return StepLog.fail(name, [{"status": "failed", "output": dir_creation_log}])
|
||||
return StepLogModel.fail(name, [{"status": "failed", "output": dir_creation_log}])
|
||||
msg = "dir created succesfully"
|
||||
else:
|
||||
msg = "dir already exists"
|
||||
|
||||
return StepLog.ok(name, msg)
|
||||
return StepLogModel.ok(name, msg)
|
||||
|
||||
+12
-13
@@ -4,42 +4,41 @@ from yaml import dump
|
||||
|
||||
from playbook import models
|
||||
from playbook.action_registry import ActionRegistry
|
||||
from playbook.models import StepLog, ContextChecker
|
||||
from playbook.models import ContextChecker
|
||||
from playbook.logging_models import StepLogModel
|
||||
|
||||
import sys
|
||||
import json
|
||||
import docker
|
||||
import subprocess
|
||||
from typing import List, Dict, Any, Tuple
|
||||
# from docker.models.containers import Container
|
||||
|
||||
|
||||
dockeractions = ActionRegistry("docker_actions_reg")
|
||||
dockeractions = ActionRegistry(name="docker_actions_reg")
|
||||
|
||||
|
||||
@dockeractions.register(name="get_service_container_name", version="")
|
||||
@ContextChecker.requires("service_name")
|
||||
def get_service_container_name(ctx, name) -> StepLog:
|
||||
def get_service_container_name(ctx, name) -> StepLogModel:
|
||||
client = docker.from_env()
|
||||
|
||||
filters: Dict[str, Any]= {
|
||||
filters: dict[str, object]= {
|
||||
"label": [f"com.docker.compose.service={ctx["service_name"]}"]
|
||||
}
|
||||
containers = client.containers.list(filters=filters, all=True)
|
||||
|
||||
if not containers:
|
||||
return StepLog.fail(name, [{
|
||||
return StepLogModel.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)
|
||||
return StepLogModel.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:
|
||||
def dump_container_pg_db(ctx, name) -> StepLogModel:
|
||||
client = docker.from_env()
|
||||
container = client.containers.get(ctx["container"])
|
||||
|
||||
@@ -52,14 +51,14 @@ def dump_container_pg_db(ctx, name) -> StepLog:
|
||||
|
||||
if stderr:
|
||||
if not isinstance(stderr, bytes):
|
||||
return StepLog.fail(name, [{"status": "failed", "output": "stderr is not bytes"}])
|
||||
return StepLogModel.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}])
|
||||
return StepLogModel.fail(name, [{"status": "failed", "output": error_msg}])
|
||||
|
||||
if not isinstance(stdout, bytes):
|
||||
return StepLog.fail(name, [{"status": "failed", "output": "stdout is not bytes"}])
|
||||
return StepLogModel.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")
|
||||
return StepLogModel.ok(name, "database dump successful")
|
||||
|
||||
+30
-30
@@ -1,11 +1,11 @@
|
||||
# restic actions registry
|
||||
from playbook.action_registry import ActionRegistry
|
||||
from playbook.models import ContextChecker, StepLog
|
||||
from playbook.models import ContextChecker
|
||||
from playbook.logging_models import StepLogModel
|
||||
|
||||
import sys
|
||||
import json
|
||||
import subprocess
|
||||
from typing import List, Dict, Any, Tuple
|
||||
|
||||
|
||||
# NOTE:
|
||||
@@ -14,10 +14,10 @@ from typing import List, Dict, Any, Tuple
|
||||
# we can create a class for this I reckon
|
||||
|
||||
|
||||
restic = ActionRegistry("restic_actions_reg")
|
||||
restic = ActionRegistry(name="restic_actions_reg")
|
||||
|
||||
|
||||
def parse_output(line: str) -> List[Dict[str, Any]]:
|
||||
def parse_output(line: str) -> list[dict[str, object]]:
|
||||
errors = []
|
||||
for line in line.split('\n'):
|
||||
if line.startswith("{"): # } treesitter is borked lmao
|
||||
@@ -26,7 +26,7 @@ def parse_output(line: str) -> List[Dict[str, Any]]:
|
||||
return errors
|
||||
|
||||
|
||||
def find_restic_errors(data: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
||||
def find_restic_errors(data: list[dict[str, object]]) -> list[dict[str, object]]:
|
||||
errors = []
|
||||
for s in data:
|
||||
if s["message_type"] == "exit_error":
|
||||
@@ -34,7 +34,7 @@ def find_restic_errors(data: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
||||
return errors
|
||||
|
||||
|
||||
def run_restic_command(cmd: List[str]) -> Tuple[int, List[Dict[str, Any]]]:
|
||||
def run_restic_command(cmd: list[str]) -> tuple[int, list[dict[str, object]]]:
|
||||
"""
|
||||
Executes a restic command, streams output live to terminal,
|
||||
and returns (returncode, parsed_json_objects).
|
||||
@@ -75,78 +75,78 @@ def run_restic_command(cmd: List[str]) -> Tuple[int, List[Dict[str, Any]]]:
|
||||
|
||||
|
||||
@restic.register(name="check_restic_environment", version="")
|
||||
def check_restic_environment(ctx, name: str = "") -> StepLog:
|
||||
def check_restic_environment(ctx, name: str = "") -> StepLogModel:
|
||||
for v in ["passwordFile", "repoPath", "sourcePath", "serviceTag"]:
|
||||
if not ctx.get(v):
|
||||
return StepLog.fail(name, [f"{v} variable is empty"])
|
||||
return StepLogModel.fail(name, [f"{v} variable is empty"])
|
||||
|
||||
return StepLog.ok(name, "environment configuration seems to be valid")
|
||||
return StepLogModel.ok(name, "environment configuration seems to be valid")
|
||||
|
||||
|
||||
@restic.register(name="create_restic_repo", version="")
|
||||
def create_restic_repo(ctx, name: str = "") -> StepLog:
|
||||
def create_restic_repo(ctx, name: str = "") -> StepLogModel:
|
||||
cmd = ["restic", "init", "--json", "-r", ctx["repoPath"],
|
||||
"--password-file", ctx["passwordFile"]]
|
||||
|
||||
returncode, json_output = run_restic_command(cmd)
|
||||
|
||||
errors: List[Dict[str, Any]] = find_restic_errors(json_output)
|
||||
errors: list[dict[str, object]] = find_restic_errors(json_output)
|
||||
|
||||
# Handle error messages in JSON output
|
||||
if len(errors) > 0:
|
||||
return StepLog.fail(name, errors)
|
||||
return StepLogModel.fail(name, errors)
|
||||
|
||||
# Make sure the return code is good too
|
||||
if returncode != 0:
|
||||
return StepLog.fail(name, [{"status": "failed", "output": json_output}])
|
||||
return StepLogModel.fail(name, [{"status": "failed", "output": json_output}])
|
||||
|
||||
return StepLog.ok(name, "repo create succesfully")
|
||||
return StepLogModel.ok(name, "repo create succesfully")
|
||||
|
||||
|
||||
@restic.register(name="create_repo_if_not_exists", version="")
|
||||
def create_repo_if_not_exists(ctx, name: str = "") -> StepLog:
|
||||
log: StepLog = check_if_repo_exists(ctx, "")
|
||||
def create_repo_if_not_exists(ctx, name: str = "") -> StepLogModel:
|
||||
log: StepLogModel = check_if_repo_exists(ctx, "")
|
||||
|
||||
msg: str = ""
|
||||
if log.failed:
|
||||
# Repo doesn't exist is error code 10
|
||||
if log.error[0]["code"] != 10:
|
||||
return StepLog.fail(name, [{"status": "failed", "output": log.error}])
|
||||
return StepLogModel.fail(name, [{"status": "failed", "output": log.error}])
|
||||
|
||||
# Create repo
|
||||
repoCreateLog: StepLog = create_restic_repo(ctx, name + f".{create_restic_repo.__name__}")
|
||||
repoCreateLog: StepLogModel = create_restic_repo(ctx, name + f".{create_restic_repo.__name__}")
|
||||
if repoCreateLog.failed:
|
||||
return StepLog.fail(name, [{"status": "failed", "output": repoCreateLog.error}])
|
||||
return StepLogModel.fail(name, [{"status": "failed", "output": repoCreateLog.error}])
|
||||
msg = "repo created"
|
||||
else:
|
||||
msg = "repo already exists"
|
||||
|
||||
|
||||
return StepLog.ok(name, msg)
|
||||
return StepLogModel.ok(name, msg)
|
||||
|
||||
|
||||
@restic.register(name="check_if_repo_exists", version="")
|
||||
def check_if_repo_exists(ctx, name: str = "") -> StepLog:
|
||||
def check_if_repo_exists(ctx, name: str = "") -> StepLogModel:
|
||||
cmd = ["restic", "-r", ctx["repoPath"], "cat", "config", "--json",
|
||||
"--password-file", ctx["passwordFile"]]
|
||||
returncode, json_output = run_restic_command(cmd)
|
||||
|
||||
errors: List[Dict[str, Any]] = find_restic_errors(json_output)
|
||||
errors: list[dict[str, object]] = find_restic_errors(json_output)
|
||||
|
||||
# Handle error messages in JSON output
|
||||
if len(errors) > 0:
|
||||
return StepLog.fail(name, errors)
|
||||
return StepLogModel.fail(name, errors)
|
||||
|
||||
# Make sure the return code is good too
|
||||
if returncode != 0:
|
||||
return StepLog.fail(name, [{"status": "failed", "output": json_output}])
|
||||
return StepLogModel.fail(name, [{"status": "failed", "output": json_output}])
|
||||
|
||||
return StepLog.ok(name, "repo seems to exist")
|
||||
return StepLogModel.ok(name, "repo seems to exist")
|
||||
|
||||
|
||||
@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) -> StepLogModel:
|
||||
cmd = ["restic", "backup", ctx["source_path"], "--json", "--quiet",
|
||||
"-r", ctx["repoPath"], "--password-file", ctx["passwordFile"]]
|
||||
if ctx["tags"]:
|
||||
@@ -154,14 +154,14 @@ def backup_data_to_restic_repo(ctx, name) -> StepLog:
|
||||
|
||||
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, object]] = find_restic_errors(json_output)
|
||||
|
||||
# Handle error messages in JSON output
|
||||
if len(errors) > 0:
|
||||
return StepLog.fail(name, errors)
|
||||
return StepLogModel.fail(name, errors)
|
||||
|
||||
# Make sure the return code is good too
|
||||
if returncode != 0:
|
||||
return StepLog.fail(name, [{"status": "failed", "output": errors}])
|
||||
return StepLogModel.fail(name, [{"status": "failed", "output": errors}])
|
||||
|
||||
return StepLog.ok(name, "backup successful")
|
||||
return StepLogModel.ok(name, "backup successful")
|
||||
|
||||
Reference in New Issue
Block a user