mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-14 08:17:34 +00:00
feat: docsgpt backup and docsgpt restore
`docsgpt backup` writes one archive holding a pg_dump of the database, a tar of each data volume and a manifest of what it came from; `docsgpt restore` puts it back over an install. The settings file is left out unless --with-settings asks for it, since it holds the install's secrets, and a backup taken with a newer DocsGPT is refused without --force. The volume tars go through the image the install already runs, so a backup pulls nothing extra, and compose calls can now redirect stdout and stdin so the dump never passes through this process.
This commit is contained in:
1 parent
4abd2c0c9f
commit
fe68fec69e
9 files changed
+489
-7
No files matched your search
@@ -15,9 +15,11 @@ class FakeRunner:
|
||||
def __init__(self, answers=None):
|
||||
self.answers = list((answers or {}).items())
|
||||
self.calls = []
|
||||
self.streams = []
|
||||
|
||||
def __call__(self, args, *, cwd=None, capture=False, check=True):
|
||||
def __call__(self, args, *, cwd=None, capture=False, check=True, stdout=None, stdin=None):
|
||||
self.calls.append((list(args), cwd))
|
||||
self.streams.append((stdout, stdin))
|
||||
for prefix, answer in self.answers:
|
||||
if list(args[: len(prefix)]) == list(prefix):
|
||||
if callable(answer):
|
||||
@@ -105,6 +107,32 @@ class TestQueries:
|
||||
assert "label=com.docker.compose.project=docsgpt" in args
|
||||
|
||||
|
||||
class TestVolumes:
|
||||
def test_export_writes_the_volume_through_the_stack_image(self, tmp_path):
|
||||
runner = FakeRunner()
|
||||
dest = tmp_path / "volumes" / "inputs.tar"
|
||||
_docker(runner).export_volume("docsgpt_inputs", dest, "arc53/docsgpt:0.21.0")
|
||||
args, _ = runner.calls[0]
|
||||
assert args[:4] == ["docker", "run", "--rm", "-v"]
|
||||
assert args[4] == "docsgpt_inputs:/data:ro"
|
||||
assert args[5] == "arc53/docsgpt:0.21.0"
|
||||
assert args[6:] == ["tar", "cf", "-", "-C", "/data", "."]
|
||||
assert dest.is_file(), "the tar is written to the destination"
|
||||
assert runner.streams[0][0] is not None, "stdout goes to the file, not through this process"
|
||||
|
||||
def test_import_replaces_the_volume_contents(self, tmp_path):
|
||||
source = tmp_path / "inputs.tar"
|
||||
source.write_bytes(b"tar")
|
||||
runner = FakeRunner()
|
||||
_docker(runner).import_volume("docsgpt_inputs", source, "arc53/docsgpt:0.21.0")
|
||||
args, _ = runner.calls[0]
|
||||
assert "docsgpt_inputs:/data" in args
|
||||
assert args[-2] == "-c"
|
||||
assert "tar xf - -C /data" in args[-1]
|
||||
assert "find /data -mindepth 1 -delete" in args[-1], "old contents go first"
|
||||
assert runner.streams[0][1] is not None, "the tar is fed in on stdin"
|
||||
|
||||
|
||||
class TestWaitHealthy:
|
||||
def test_succeeds_once_the_api_answers(self):
|
||||
attempts = {"n": 0}
|
||||
|
||||
Reference in new issue
Block a user