tkgray commited on
Commit
c0a64a1
·
verified ·
1 Parent(s): 79eb867

Upload restore.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. restore.py +90 -0
restore.py ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Restore Open WebUI data into the data dir from the backups dataset.
3
+
4
+ Runs on every boot. If webui.db is already present the volume is intact and
5
+ nothing happens. If it is missing (volume wiped / factory reset), the latest
6
+ full archive is extracted into the data dir, falling back to the legacy
7
+ single-file DB backup written by older versions of backup.sh.
8
+
9
+ Never fails the boot: a restore error is logged and ignored, so a first boot
10
+ with no backup yet still starts the app.
11
+ """
12
+ import os
13
+ import shutil
14
+ import sys
15
+ import tarfile
16
+
17
+ DATA_DIR = os.environ.get("OWUI_DATA_DIR", "/data")
18
+ REPO_ID = os.environ.get("OWUI_BACKUP_REPO", "tkgray/open-webui-backups")
19
+ ARCHIVE_IN_REPO = "backups/open-webui-data.tar.gz"
20
+ LEGACY_DB_IN_REPO = "backups/webui.db"
21
+
22
+ DB_PATH = os.path.join(DATA_DIR, "webui.db")
23
+
24
+
25
+ def log(msg):
26
+ print(f"[restore] {msg}", flush=True)
27
+
28
+
29
+ def fetch(token, filename):
30
+ from huggingface_hub import hf_hub_download
31
+
32
+ return hf_hub_download(
33
+ repo_id=REPO_ID,
34
+ filename=filename,
35
+ repo_type="dataset",
36
+ token=token,
37
+ )
38
+
39
+
40
+ def safe_extract(tf, dest):
41
+ """Extract an archive into dest, refusing absolute paths and .. traversal."""
42
+ dest = os.path.abspath(dest)
43
+ for member in tf.getmembers():
44
+ target = os.path.abspath(os.path.join(dest, member.name))
45
+ if target != dest and not target.startswith(dest + os.sep):
46
+ raise ValueError(f"unsafe path in archive: {member.name}")
47
+ try:
48
+ tf.extractall(dest, filter="data") # py3.12+
49
+ except TypeError:
50
+ tf.extractall(dest)
51
+
52
+
53
+ def main():
54
+ if os.path.isfile(DB_PATH):
55
+ log(f"{DB_PATH} already exists — nothing to restore.")
56
+ return 0
57
+
58
+ token = os.environ.get("HF_TOKEN")
59
+ if not token:
60
+ log("HF_TOKEN not set — skipping restore.")
61
+ return 0
62
+
63
+ os.makedirs(DATA_DIR, exist_ok=True)
64
+ log(f"{DB_PATH} missing — attempting restore from {REPO_ID} ...")
65
+
66
+ # Preferred: the full archive (DB + vector_db + uploads)
67
+ try:
68
+ path = fetch(token, ARCHIVE_IN_REPO)
69
+ with tarfile.open(path, "r:gz") as tf:
70
+ safe_extract(tf, DATA_DIR)
71
+ if os.path.isfile(DB_PATH):
72
+ log("Full archive restore OK")
73
+ return 0
74
+ log("archive extracted but webui.db is missing — falling back")
75
+ except Exception as exc: # noqa: BLE001
76
+ log(f"archive restore failed: {exc}")
77
+
78
+ # Fallback: legacy single-file DB backup
79
+ try:
80
+ path = fetch(token, LEGACY_DB_IN_REPO)
81
+ shutil.copy2(path, DB_PATH)
82
+ log("Legacy DB restore OK")
83
+ except Exception as exc: # noqa: BLE001
84
+ log(f"no backup available yet: {exc}")
85
+
86
+ return 0
87
+
88
+
89
+ if __name__ == "__main__":
90
+ sys.exit(main())