#!/usr/bin/env python3 """ Nexus One AI — First Boot Web Setup Server Serves on port 80. Access from any browser on the same network. """ import os, json, subprocess, threading, time, socket, ipaddress, sys from http.server import HTTPServer, BaseHTTPRequestHandler from pathlib import Path from urllib.parse import parse_qs, urlparse SETUP_DONE_FILE = "/opt/cezen/.setup-done" INSTALL_LOG = "/var/log/cezen-install.log" AIPACKAGE_DIR = "/opt/aipackage" SCRIPT_ROOT = Path(__file__).resolve().parents[2] SCRIPTS_DIR = Path(AIPACKAGE_DIR) / "scripts" if str(SCRIPTS_DIR) not in sys.path: sys.path.insert(0, str(SCRIPTS_DIR if SCRIPTS_DIR.exists() else SCRIPT_ROOT / "scripts")) from cezen_license import build_tier_options, evaluate_license, evaluate_override, normalize_tier, read_json_file, write_json_file install_proc = None install_status = {"running": False, "done": False, "error": None} FEASIBILITY_SCRIPT = f"{AIPACKAGE_DIR}/scripts/cezen-feasibility.sh" FEASIBILITY_JSON = "/opt/cezen/feasibility.json" LICENSE_JSON = "/opt/cezen/license.json" OVERRIDE_JSON = "/opt/cezen/license.override.json" INSTALL_RECORD_JSON = "/opt/cezen/install-record.json" INSTALL_OPERATION_JSON = os.environ.get("CEZEN_SETUP_OPERATION_JSON", "/opt/cezen/setup-operation.json") PUBLIC_KEY_PATH = os.environ.get("CEZEN_LICENSE_PUBLIC_KEY", f"{AIPACKAGE_DIR}/autoinstall/keys/cezen-license-public.pem") def read_install_operation(): return read_json_file(INSTALL_OPERATION_JSON) def write_install_operation(operation): operation = dict(operation or {}) operation["updated_at"] = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()) write_json_file(INSTALL_OPERATION_JSON, operation) try: os.chmod(INSTALL_OPERATION_JSON, 0o640) except OSError: pass return operation def start_install_operation(tier, skip_tools, idempotency_key): existing = read_install_operation() if idempotency_key and existing.get("idempotency_key") == idempotency_key: existing["duplicate_request"] = True return existing, False if existing.get("state") in {"validating", "running", "awaiting_reboot"}: existing["duplicate_request"] = True return existing, False now = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()) operation = { "schema": "cezen.setup_operation.v1", "operation_id": str(__import__("uuid").uuid4()), "correlation_id": str(__import__("uuid").uuid4()), "idempotency_key": idempotency_key or str(__import__("uuid").uuid4()), "kind": "install", "state": "validating", "tier": tier, "skip_tools": list(skip_tools or []), "progress_percent": 0, "progress_label": "Validating installation", "acknowledged_at": now, "updated_at": now, "duplicate_request": False, "customer_message": "Installation request accepted.", "recovery_actions": [], } return write_install_operation(operation), True # ─── Helpers ────────────────────────────────────────────── def get_ip(): try: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(("8.8.8.8", 80)) ip = s.getsockname()[0] s.close() return ip except: return "unknown" def get_interfaces(): try: out = subprocess.check_output(["ip", "-o", "link", "show"], text=True) ifaces = [] for line in out.splitlines(): name = line.split(": ")[1].split("@")[0] if name not in ("lo",) and not name.startswith(("docker","br-","veth","k3s")): ifaces.append(name) return ifaces except: return ["eth0"] def has_nvidia_gpu(): """Detect NVIDIA PCI devices before the driver or nvidia-smi exists.""" try: for root, _, files in os.walk("/sys/bus/pci/devices"): if "vendor" not in files: continue with open(os.path.join(root, "vendor")) as f: if f.read().strip().lower() == "0x10de": return True except Exception: pass return False def validate_static_network(ip, prefix, gateway, dns): ipaddress.ip_address(ip) ipaddress.ip_address(gateway) ipaddress.ip_address(dns) prefix_int = int(prefix) if prefix_int < 1 or prefix_int > 32: raise ValueError("CIDR prefix must be between 1 and 32") return str(prefix_int) def is_ip_in_use(ip): """Best-effort conflict check before taking a static IP.""" try: result = subprocess.run( ["ping", "-c", "1", "-W", "1", ip], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=False, ) return result.returncode == 0 except Exception: return False def apply_static_ip(iface, ip, prefix, gateway, dns): prefix = validate_static_network(ip, prefix, gateway, dns) config = f"""network: version: 2 ethernets: {iface}: dhcp4: false addresses: - {ip}/{prefix} routes: - to: default via: {gateway} nameservers: addresses: [{dns}] """ with open("/etc/netplan/99-cezen-static.yaml", "w") as f: f.write(config) subprocess.run(["netplan", "apply"], capture_output=True) time.sleep(3) def save_license_artifacts(license_data): os.makedirs("/opt/cezen", exist_ok=True) for target in (LICENSE_JSON, OVERRIDE_JSON): try: os.remove(target) except FileNotFoundError: pass raw_license = (license_data.get("license_json") or "").strip() raw_override = (license_data.get("override_json") or "").strip() if raw_license: payload = json.loads(raw_license) write_json_file(LICENSE_JSON, payload) subprocess.run(["chown", "root:cezen", LICENSE_JSON], check=False) os.chmod(LICENSE_JSON, 0o640) if raw_override: payload = json.loads(raw_override) write_json_file(OVERRIDE_JSON, payload) subprocess.run(["chown", "root:cezen", OVERRIDE_JSON], check=False) os.chmod(OVERRIDE_JSON, 0o640) def ensure_feasibility(): os.makedirs("/opt/cezen", exist_ok=True) if os.path.exists(FEASIBILITY_SCRIPT): subprocess.run(["bash", FEASIBILITY_SCRIPT, FEASIBILITY_JSON], check=False) return read_json_file(FEASIBILITY_JSON) def evaluate_install_constraints(license_data): save_license_artifacts(license_data or {}) feasibility = ensure_feasibility() hardware_tier = normalize_tier(((feasibility.get("recommendation") or {}).get("recommended_tier")), "basic") license_record = read_json_file(LICENSE_JSON) override_record = read_json_file(OVERRIDE_JSON) license_eval = evaluate_license(license_record, PUBLIC_KEY_PATH) override_eval = evaluate_override(override_record, PUBLIC_KEY_PATH) return { "license": license_eval, "override": override_eval, "hardware": { "recommended_tier": hardware_tier, "recommended_profile": (feasibility.get("recommendation") or {}).get("recommended_profile", ""), "estimated_concurrent_users": (feasibility.get("recommendation") or {}).get("estimated_concurrent_users", ""), "notes": (feasibility.get("recommendation") or {}).get("notes", []), }, "tier_options": build_tier_options(license_eval, hardware_tier, override_eval), } def write_install_record(license_data, tier, skip_tools, preview): payload = { "schema": "cezen.install_record.v1", "generated_at": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()), "customer_name": (license_data.get("customer_name") or "").strip(), "customer_id": (license_data.get("customer_id") or "").strip(), "contact_email": (license_data.get("contact_email") or "").strip(), "support_until": (license_data.get("support_until") or "").strip(), "selected_tier": tier, "provisioned_tier": tier, "licensed_tier": ((preview.get("license") or {}).get("allowed_tier") or "basic"), "license_status": ((preview.get("license") or {}).get("status") or "missing"), "hardware_recommended_tier": ((preview.get("hardware") or {}).get("recommended_tier") or "starter"), "hardware_recommended_profile": ((preview.get("hardware") or {}).get("recommended_profile") or "core"), "install_type": ((preview.get("license") or {}).get("install_type") or "field-staging"), "override_active": bool((preview.get("override") or {}).get("allow_hardware_mismatch")), "skip_roles": skip_tools or [], "components": {k: k not in set(skip_tools or []) for k in ["ollama", "jupyterlab", "chromadb", "vllm", "mlflow", "minio", "monitoring", "k3s"]}, } write_json_file(INSTALL_RECORD_JSON, payload) subprocess.run(["chown", "root:cezen", INSTALL_RECORD_JSON], check=False) os.chmod(INSTALL_RECORD_JSON, 0o640) def run_install(tier, skip_tools, license_data=None, preview=None, operation_id=""): global install_status install_status = {"running": True, "done": False, "error": None} try: operation = read_install_operation() if operation.get("operation_id") == operation_id: operation.update({"state": "running", "progress_percent": 5, "progress_label": "Preparing appliance"}) write_install_operation(operation) # Write config so phase 2 (post-reboot) knows what to skip os.makedirs("/opt/cezen", exist_ok=True) skip_str = ",".join(skip_tools) if skip_tools else "" save_license_artifacts(license_data or {}) write_install_record(license_data or {}, tier, skip_tools or [], preview or {}) with open("/opt/cezen/install.conf", "w") as f: f.write(f"TIER={tier}\nSKIP_ROLES={skip_str}\n") # Mark setup done NOW so this web UI doesn't restart after the phase-1 reboot open(SETUP_DONE_FILE, "w").close() env = os.environ.copy() # Fresh NVIDIA servers do not have nvidia-smi yet, so detect the PCI # device and run phase 1 to install drivers before the AI stack. phase = "1" if has_nvidia_gpu() else "2" if operation.get("operation_id") == operation_id and phase == "1": operation.update({"state": "awaiting_reboot", "progress_percent": 40, "progress_label": "Installing drivers before reboot"}) write_install_operation(operation) cmd = ["bash", f"{AIPACKAGE_DIR}/install.sh", f"--phase={phase}", f"--tier={tier}"] with open(INSTALL_LOG, "w") as log: proc = subprocess.Popen(cmd, stdout=log, stderr=log, env=env) proc.wait() # Reaches here only if no reboot happened (e.g. no GPU / drivers already installed) install_status = {"running": False, "done": True, "error": None} operation = read_install_operation() if operation.get("operation_id") == operation_id: operation.update({"state": "succeeded", "progress_percent": 100, "progress_label": "Installation command completed", "customer_message": "Installation completed successfully."}) write_install_operation(operation) except Exception as e: install_status = {"running": False, "done": False, "error": str(e)} operation = read_install_operation() if operation.get("operation_id") == operation_id: operation.update({"state": "recovery_required", "progress_label": "Installation needs attention", "result_code": "install_failed", "customer_message": "Installation did not complete. Review the local log and retry or contact support.", "recovery_actions": ["retry", "view_log", "escalate"]}) write_install_operation(operation) # ─── HTML UI ────────────────────────────────────────────── HTML = r"""
Choose how this server gets its IP address. You can change this later.
Enter the local customer record and paste the signed license JSON. Leave license blank for field staging.
Choose the tier that matches your GPU hardware.
Toggle the components you want installed. Recommended defaults are pre-selected.
Confirm your settings before installation begins.
Starting...
Your Nexus One AI is ready.