Soften updater stub messaging (no error)
This commit is contained in:
131
pikit-api.py
131
pikit-api.py
@@ -2,6 +2,8 @@
|
||||
import json, os, subprocess, socket, shutil, pathlib, datetime
|
||||
from http.server import BaseHTTPRequestHandler, HTTPServer
|
||||
import re
|
||||
import urllib.request
|
||||
import hashlib
|
||||
|
||||
HOST = "127.0.0.1"
|
||||
PORT = 4000
|
||||
@@ -27,6 +29,17 @@ ALL_PATTERNS = [
|
||||
*SECURITY_PATTERNS,
|
||||
]
|
||||
|
||||
# Release updater constants
|
||||
VERSION_FILE = pathlib.Path("/etc/pikit/version")
|
||||
WEB_VERSION_FILE = pathlib.Path("/var/www/pikit-web/data/version.json")
|
||||
UPDATE_STATE_DIR = pathlib.Path("/var/lib/pikit-update")
|
||||
UPDATE_STATE = UPDATE_STATE_DIR / "state.json"
|
||||
UPDATE_LOCK = pathlib.Path("/var/run/pikit-update.lock")
|
||||
DEFAULT_MANIFEST_URL = os.environ.get(
|
||||
"PIKIT_MANIFEST_URL",
|
||||
"https://git.44r0n.cc/44r0n7/pi-kit/releases/latest/download/manifest.json",
|
||||
)
|
||||
|
||||
|
||||
class FirewallToolMissing(Exception):
|
||||
"""Raised when ufw is unavailable but a firewall change was requested."""
|
||||
@@ -459,6 +472,106 @@ def reset_firewall():
|
||||
subprocess.run(["ufw", "--force", "enable"], check=False)
|
||||
|
||||
|
||||
def read_current_version():
|
||||
if VERSION_FILE.exists():
|
||||
return VERSION_FILE.read_text().strip()
|
||||
if WEB_VERSION_FILE.exists():
|
||||
try:
|
||||
return json.loads(WEB_VERSION_FILE.read_text()).get("version", "unknown")
|
||||
except Exception:
|
||||
return "unknown"
|
||||
return "unknown"
|
||||
|
||||
|
||||
def load_update_state():
|
||||
UPDATE_STATE_DIR.mkdir(parents=True, exist_ok=True)
|
||||
if UPDATE_STATE.exists():
|
||||
try:
|
||||
return json.loads(UPDATE_STATE.read_text())
|
||||
except Exception:
|
||||
pass
|
||||
return {
|
||||
"current_version": read_current_version(),
|
||||
"latest_version": None,
|
||||
"last_check": None,
|
||||
"status": "unknown",
|
||||
"message": "",
|
||||
"auto_check": False,
|
||||
"in_progress": False,
|
||||
"progress": None,
|
||||
}
|
||||
|
||||
|
||||
def save_update_state(state: dict):
|
||||
UPDATE_STATE_DIR.mkdir(parents=True, exist_ok=True)
|
||||
UPDATE_STATE.write_text(json.dumps(state, indent=2))
|
||||
|
||||
|
||||
def fetch_manifest(url: str = None):
|
||||
target = url or DEFAULT_MANIFEST_URL
|
||||
resp = urllib.request.urlopen(target, timeout=10)
|
||||
data = resp.read()
|
||||
manifest = json.loads(data.decode())
|
||||
return manifest
|
||||
|
||||
|
||||
def check_for_update():
|
||||
state = load_update_state()
|
||||
state["in_progress"] = True
|
||||
state["progress"] = "Checking for updates…"
|
||||
save_update_state(state)
|
||||
try:
|
||||
manifest = fetch_manifest()
|
||||
latest = manifest.get("version") or manifest.get("latest_version")
|
||||
state["latest_version"] = latest
|
||||
state["last_check"] = datetime.datetime.utcnow().isoformat() + "Z"
|
||||
if latest and latest != state.get("current_version"):
|
||||
state["status"] = "update_available"
|
||||
state["message"] = manifest.get("changelog", "Update available")
|
||||
else:
|
||||
state["status"] = "up_to_date"
|
||||
state["message"] = "Up to date"
|
||||
except Exception as e:
|
||||
state["status"] = "error"
|
||||
state["message"] = f"Check failed: {e}"
|
||||
finally:
|
||||
state["in_progress"] = False
|
||||
state["progress"] = None
|
||||
save_update_state(state)
|
||||
return state
|
||||
|
||||
|
||||
def apply_update_stub():
|
||||
"""Placeholder apply that marks not implemented but keeps state coherent."""
|
||||
state = load_update_state()
|
||||
state["in_progress"] = True
|
||||
state["progress"] = "Applying update…"
|
||||
save_update_state(state)
|
||||
try:
|
||||
# TODO: implement download + install
|
||||
# For now, report that nothing was changed to avoid alarming errors.
|
||||
state["status"] = "up_to_date"
|
||||
state["message"] = "Updater not implemented yet; no changes were made."
|
||||
# Reset latest_version so the chip returns to neutral
|
||||
state["latest_version"] = state.get("current_version")
|
||||
except Exception as e:
|
||||
state["status"] = "error"
|
||||
state["message"] = f"Apply failed: {e}"
|
||||
finally:
|
||||
state["in_progress"] = False
|
||||
state["progress"] = None
|
||||
save_update_state(state)
|
||||
return state
|
||||
|
||||
|
||||
def rollback_update_stub():
|
||||
state = load_update_state()
|
||||
state["status"] = "up_to_date"
|
||||
state["message"] = "Rollback not implemented yet; no changes were made."
|
||||
save_update_state(state)
|
||||
return state
|
||||
|
||||
|
||||
class Handler(BaseHTTPRequestHandler):
|
||||
"""Minimal JSON API for the dashboard (status, services, updates, reset)."""
|
||||
def _send(self, code, data):
|
||||
@@ -551,6 +664,10 @@ class Handler(BaseHTTPRequestHandler):
|
||||
elif self.path.startswith("/api/updates/config"):
|
||||
cfg = read_updates_config()
|
||||
self._send(200, cfg)
|
||||
elif self.path.startswith("/api/update/status"):
|
||||
state = load_update_state()
|
||||
state["current_version"] = read_current_version()
|
||||
self._send(200, state)
|
||||
else:
|
||||
self._send(404, {"error": "not found"})
|
||||
|
||||
@@ -579,6 +696,20 @@ class Handler(BaseHTTPRequestHandler):
|
||||
except Exception as e:
|
||||
dbg(f"Failed to apply updates config: {e}")
|
||||
return self._send(500, {"error": str(e)})
|
||||
if self.path.startswith("/api/update/check"):
|
||||
state = check_for_update()
|
||||
return self._send(200, state)
|
||||
if self.path.startswith("/api/update/apply"):
|
||||
state = apply_update_stub()
|
||||
return self._send(200, state)
|
||||
if self.path.startswith("/api/update/rollback"):
|
||||
state = rollback_update_stub()
|
||||
return self._send(200, state)
|
||||
if self.path.startswith("/api/update/auto"):
|
||||
state = load_update_state()
|
||||
state["auto_check"] = bool(payload.get("enable"))
|
||||
save_update_state(state)
|
||||
return self._send(200, state)
|
||||
if self.path.startswith("/api/services/add"):
|
||||
name = payload.get("name")
|
||||
port = int(payload.get("port", 0))
|
||||
|
||||
Reference in New Issue
Block a user