Migrating the classes to pydantic
main / Explore-Gitea-Actions (push) Failing after 14s

This commit is contained in:
2026-08-03 23:37:25 +01:00
parent a68d7b1d59
commit 8d73d5ded7
15 changed files with 814 additions and 479 deletions
+4 -5
View File
@@ -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"})
+13 -13
View File
@@ -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
View File
@@ -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
View File
@@ -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")