Spaces:
Paused
Paused
fix: sync /etc/ssh only, not all of /etc/
Browse filesRestoring all of /etc/ was overwriting system configs (PAM, nsswitch,
alternatives) which broke sshd after restart. Now only sync /etc/ssh/
for SSH host keys. Also restart sshd after restore to pick up restored
host keys, and add error logging to rsync.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- entrypoint.py +17 -11
entrypoint.py
CHANGED
|
@@ -3,7 +3,7 @@
|
|
| 3 |
HuggingRun v2 — Ubuntu Server on HuggingFace Spaces.
|
| 4 |
|
| 5 |
Persistence via HF Dataset (direct file sync, no archives):
|
| 6 |
-
- Sync scope: /home, /root, /usr/local, /opt, /var/lib, /etc
|
| 7 |
- System packages: saved as package name list, restored via apt install
|
| 8 |
- Symlinks/permissions safe: no system binary dirs synced
|
| 9 |
"""
|
|
@@ -31,15 +31,11 @@ BASE_PKG_FILE = "/etc/base-packages.list"
|
|
| 31 |
PKG_FILE = os.path.join(PERSIST_PATH, "user-packages.list")
|
| 32 |
|
| 33 |
# Directories to sync (user data only, no system binaries)
|
| 34 |
-
|
|
|
|
| 35 |
|
| 36 |
# Exclude from rsync
|
| 37 |
-
RSYNC_EXCLUDES = [
|
| 38 |
-
"*.sock", "*.pid", "*.lock",
|
| 39 |
-
"/etc/hostname", "/etc/hosts", "/etc/resolv.conf", "/etc/mtab",
|
| 40 |
-
"/etc/alternatives", # symlinks, apt rebuilds
|
| 41 |
-
"/etc/ld.so.cache", # rebuilt by ldconfig
|
| 42 |
-
]
|
| 43 |
|
| 44 |
# Exclude from HF upload
|
| 45 |
UPLOAD_IGNORE = [
|
|
@@ -61,9 +57,11 @@ def log(msg):
|
|
| 61 |
pass
|
| 62 |
|
| 63 |
|
| 64 |
-
def sh(cmd):
|
| 65 |
"""Run shell command, return (exit_code, stdout)."""
|
| 66 |
r = subprocess.run(cmd, shell=True, capture_output=True, text=True)
|
|
|
|
|
|
|
| 67 |
return r.returncode, (r.stdout or "").strip()
|
| 68 |
|
| 69 |
|
|
@@ -144,11 +142,11 @@ def restore():
|
|
| 144 |
if not os.path.isdir(src):
|
| 145 |
continue
|
| 146 |
cmd = f"rsync -rlptD {excludes} '{src}/' '{d}/'"
|
| 147 |
-
rc, _ = sh(cmd)
|
| 148 |
if rc == 0:
|
| 149 |
log(f" {d}/ restored")
|
| 150 |
else:
|
| 151 |
-
log(f" {d}/ restore failed")
|
| 152 |
|
| 153 |
# Reinstall apt packages
|
| 154 |
if os.path.exists(PKG_FILE) and os.path.exists(BASE_PKG_FILE):
|
|
@@ -169,6 +167,14 @@ def restore():
|
|
| 169 |
else:
|
| 170 |
log("── RESTORE: no package list")
|
| 171 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 172 |
# Fix up after restore
|
| 173 |
sh('ldconfig 2>/dev/null')
|
| 174 |
log("── RESTORE: complete")
|
|
|
|
| 3 |
HuggingRun v2 — Ubuntu Server on HuggingFace Spaces.
|
| 4 |
|
| 5 |
Persistence via HF Dataset (direct file sync, no archives):
|
| 6 |
+
- Sync scope: /home, /root, /usr/local, /opt, /var/lib, /etc/ssh
|
| 7 |
- System packages: saved as package name list, restored via apt install
|
| 8 |
- Symlinks/permissions safe: no system binary dirs synced
|
| 9 |
"""
|
|
|
|
| 31 |
PKG_FILE = os.path.join(PERSIST_PATH, "user-packages.list")
|
| 32 |
|
| 33 |
# Directories to sync (user data only, no system binaries)
|
| 34 |
+
# NOTE: /etc/ssh only (for host keys), NOT all of /etc/ (breaks sshd/PAM)
|
| 35 |
+
SYNC_DIRS = ["/home", "/root", "/usr/local", "/opt", "/var/lib", "/etc/ssh"]
|
| 36 |
|
| 37 |
# Exclude from rsync
|
| 38 |
+
RSYNC_EXCLUDES = ["*.sock", "*.pid", "*.lock"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
|
| 40 |
# Exclude from HF upload
|
| 41 |
UPLOAD_IGNORE = [
|
|
|
|
| 57 |
pass
|
| 58 |
|
| 59 |
|
| 60 |
+
def sh(cmd, log_err=False):
|
| 61 |
"""Run shell command, return (exit_code, stdout)."""
|
| 62 |
r = subprocess.run(cmd, shell=True, capture_output=True, text=True)
|
| 63 |
+
if log_err and r.returncode != 0 and r.stderr:
|
| 64 |
+
log(f" cmd error: {r.stderr.strip()[:200]}")
|
| 65 |
return r.returncode, (r.stdout or "").strip()
|
| 66 |
|
| 67 |
|
|
|
|
| 142 |
if not os.path.isdir(src):
|
| 143 |
continue
|
| 144 |
cmd = f"rsync -rlptD {excludes} '{src}/' '{d}/'"
|
| 145 |
+
rc, _ = sh(cmd, log_err=True)
|
| 146 |
if rc == 0:
|
| 147 |
log(f" {d}/ restored")
|
| 148 |
else:
|
| 149 |
+
log(f" {d}/ restore failed (rc={rc})")
|
| 150 |
|
| 151 |
# Reinstall apt packages
|
| 152 |
if os.path.exists(PKG_FILE) and os.path.exists(BASE_PKG_FILE):
|
|
|
|
| 167 |
else:
|
| 168 |
log("── RESTORE: no package list")
|
| 169 |
|
| 170 |
+
# Restart sshd to pick up restored host keys
|
| 171 |
+
sh("pkill -x sshd")
|
| 172 |
+
time.sleep(0.5)
|
| 173 |
+
os.makedirs("/run/sshd", exist_ok=True)
|
| 174 |
+
rc, _ = sh(f"/usr/sbin/sshd -o Port={SSH_PORT} -o ListenAddress=127.0.0.1 "
|
| 175 |
+
f"-o PermitRootLogin=yes -o PasswordAuthentication=yes -o UsePAM=yes")
|
| 176 |
+
log(f" sshd restarted {'ok' if rc == 0 else 'FAILED'}")
|
| 177 |
+
|
| 178 |
# Fix up after restore
|
| 179 |
sh('ldconfig 2>/dev/null')
|
| 180 |
log("── RESTORE: complete")
|