mirror of
https://github.com/kevinveenbirkenbach/docker-volume-backup.git
synced 2026-02-02 11:04:06 +00:00
refactor: migrate to src/ package + add DinD-based E2E runner with debug artifacts
- Replace legacy standalone scripts with a proper src-layout Python package (baudolo backup/restore/configure entrypoints via pyproject.toml) - Remove old scripts/files (backup-docker-to-local.py, recover-docker-from-local.sh, databases.csv.tpl, Todo.md) - Add Dockerfile to build the project image for local/E2E usage - Update Makefile: build image and run E2E via external runner script - Add scripts/test-e2e.sh: - start DinD + dedicated network - recreate DinD data volume (and shared /tmp volume) - pre-pull helper images (alpine-rsync, alpine) - load local baudolo:local image into DinD - run unittest E2E suite inside DinD and abort on first failure - on failure: dump host+DinD diagnostics and archive shared /tmp into artifacts/ - Add artifacts/ debug outputs produced by failing E2E runs (logs, events, tmp archive) https://chatgpt.com/share/694ec23f-0794-800f-9a59-8365bc80f435
This commit is contained in:
81
src/baudolo/restore/run.py
Normal file
81
src/baudolo/restore/run.py
Normal file
@@ -0,0 +1,81 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
from typing import Optional
|
||||
|
||||
|
||||
def run(
|
||||
cmd: list[str],
|
||||
*,
|
||||
stdin=None,
|
||||
capture: bool = False,
|
||||
env: Optional[dict] = None,
|
||||
) -> subprocess.CompletedProcess:
|
||||
try:
|
||||
return subprocess.run(
|
||||
cmd,
|
||||
check=True,
|
||||
stdin=stdin,
|
||||
capture_output=capture,
|
||||
env=env,
|
||||
)
|
||||
except subprocess.CalledProcessError as e:
|
||||
msg = f"ERROR: command failed ({e.returncode}): {' '.join(cmd)}"
|
||||
print(msg, file=sys.stderr)
|
||||
if e.stdout:
|
||||
try:
|
||||
print(e.stdout.decode(), file=sys.stderr)
|
||||
except Exception:
|
||||
print(e.stdout, file=sys.stderr)
|
||||
if e.stderr:
|
||||
try:
|
||||
print(e.stderr.decode(), file=sys.stderr)
|
||||
except Exception:
|
||||
print(e.stderr, file=sys.stderr)
|
||||
raise
|
||||
|
||||
|
||||
def docker_exec(
|
||||
container: str,
|
||||
argv: list[str],
|
||||
*,
|
||||
stdin=None,
|
||||
capture: bool = False,
|
||||
env: Optional[dict] = None,
|
||||
docker_env: Optional[dict[str, str]] = None,
|
||||
) -> subprocess.CompletedProcess:
|
||||
cmd: list[str] = ["docker", "exec", "-i"]
|
||||
if docker_env:
|
||||
for k, v in docker_env.items():
|
||||
cmd.extend(["-e", f"{k}={v}"])
|
||||
cmd.extend([container, *argv])
|
||||
return run(cmd, stdin=stdin, capture=capture, env=env)
|
||||
|
||||
|
||||
def docker_exec_sh(
|
||||
container: str,
|
||||
script: str,
|
||||
*,
|
||||
stdin=None,
|
||||
capture: bool = False,
|
||||
env: Optional[dict] = None,
|
||||
docker_env: Optional[dict[str, str]] = None,
|
||||
) -> subprocess.CompletedProcess:
|
||||
return docker_exec(
|
||||
container,
|
||||
["sh", "-lc", script],
|
||||
stdin=stdin,
|
||||
capture=capture,
|
||||
env=env,
|
||||
docker_env=docker_env,
|
||||
)
|
||||
|
||||
|
||||
def docker_volume_exists(volume: str) -> bool:
|
||||
p = subprocess.run(
|
||||
["docker", "volume", "inspect", volume],
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
return p.returncode == 0
|
||||
Reference in New Issue
Block a user