GeezerVisonThe World Wide Web, restored to 800 pixels of glory. |
| Home|About|Gaming cabinet|Archives|How it works|Starter sites |
GeezerVison is showing github.com — devstack/support/validate.py at dev · lpb-stack/devstack Expand file tree/ Copy pathvalidate.pyMore file actions 187 lines (152 loc) · 6.16 KB / Copy pathvalidate.pyFile metadata and controls187 lines (152 loc) · 6.16 KB 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 #!/usr/bin/env python3 """validate — Check that the container is properly configured. Python port of support/validate. Run inside the container to verify: - NOPASSWD sudo is configured - Build tools are available - Native modules (better-sqlite3) compile and load - VSCodium server is accessible - Pi CLI is functional Usage: podman exec -it lpb-stack /opt/devstack/validate """ from __future__ import annotations import argparse import os import shutil import sys from pathlib import Path _SELF_DIR = Path(__file__).resolve().parent for _c in (_SELF_DIR.parent / "scripts", _SELF_DIR, Path("/opt/pi-support")): if (_c / "localpibox").is_dir(): sys.path.insert(0, str(_c)) break from localpibox.cli import install_sigpipe_handler # noqa: E402 from localpibox.log import Console # noqa: E402 from localpibox.run import run_cmd, which # noqa: E402 EXT_BASE = Path("/home/lpb/.pi/agent/git") # Git-cloned extensions (lemonade-pi-plugin, lpb-memory). pi-subagents is NOT # here — it de-forked to the upstream npm package (installed by pi, not a git # clone under the agent dir), so its presence is checked via the settings.json # pin by the full validator instead. CHECK_REPOS = ("lpb-stack/lemonade-pi-plugin", "lpb-stack/lpb-memory") SQLITE_LIB_DIRS = ["/usr/lib/x86_64-linux-gnu"] class Checker: """Tracks pass/fail/warn counts for the validation report.""" def __init__(self, cons: Console) -> None: self.cons = cons self.checks = 0 self.errors = 0 def pass_(self, msg: str) -> None: self.cons.info(f" \u2713 {msg}") self.checks += 1 def fail(self, msg: str) -> None: self.cons.error(f" \u2717 {msg}") self.checks += 1 self.errors += 1 def warn(self, msg: str) -> None: self.cons.warn(f" \u26a0 {msg}") self.checks += 1 def section(cons: Console, title: str) -> None: cons.info(f"\u2500\u2500 {title} \u2500\u2500") def check_sudo(c: Checker, cons: Console) -> None: section(cons, "NOPASSWD sudo") out, _err, code = run_cmd(["sudo", "-n", "cat", "/etc/sudoers.d/nopasswd"], timeout=15) if code == 0 and "NOPASSWD" in out: _, _, code2 = run_cmd(["sudo", "-n", "true"], timeout=15) if code2 == 0: c.pass_("NOPASSWD configured and working (sudo group)") else: c.fail("NOPASSWD file present but sudo still prompts") else: c.fail("/etc/sudoers.d/nopasswd missing or no NOPASSWD rule found") def check_build_tools(c: Checker, cons: Console) -> None: section(cons, "Build tools") for tool in ("gcc", "g++", "make", "python3", "pkg-config"): if which(tool): c.pass_(f"{tool} available") else: c.fail(f"{tool} missing") if any(any(Path(d).glob("libsqlite3.so*")) for d in SQLITE_LIB_DIRS): c.pass_("libsqlite3-dev (shared library) installed") else: c.fail("libsqlite3-dev (shared library) missing") def check_native_modules(c: Checker, cons: Console) -> None: section(cons, "Native modules") found = False for node_bin in EXT_BASE.rglob("better_sqlite3.node"): if not node_bin.is_file(): continue found = True ext_dir = node_bin.parent.parent ext_name = ext_dir.name c.pass_(f"better-sqlite3 binary exists in {ext_name}") out, err, code = run_cmd( ["node", "-e", "const db = require('better-sqlite3')(':memory:'); db.close()"], timeout=60, cwd=str(ext_dir), ) if code == 0: c.pass_(f"better-sqlite3 loads and queries in {ext_name}") else: c.fail(f"better-sqlite3 fails to load in {ext_name} ({err.strip() or out.strip()})") if not found: c.warn("No better-sqlite3 extensions found (expected if no extensions installed)") def check_vscodium(c: Checker, cons: Console) -> None: section(cons, "VSCodium server") ed_port = os.environ.get("ED_PORT", os.environ.get("LPB_ED_PORT", "3000")) token = os.environ.get("CONNECTION_TOKEN", os.environ.get("LPB_CONNECTION_TOKEN", "")) if which("codium-server") or Path("/opt/vscodium/bin/codium-server").is_file(): out, err, code = run_cmd(["curl", "-sf", f"http://localhost:{ed_port}/?tkn={token}"], timeout=20) if code == 0: c.pass_(f"VSCodium server responsive on port {ed_port}") else: c.fail(f"VSCodium server not responsive on port {ed_port} ({err.strip() or out.strip()})") else: c.pass_("VSCodium not installed — running CLI image") def check_pi_cli(c: Checker, cons: Console) -> None: section(cons, "Pi CLI") if which("pi"): c.pass_("pi command available") out, err, code = run_cmd(["pi", "--version"], timeout=30) if code == 0: c.pass_("pi --version works") else: c.fail(f"pi --version failed ({err.strip() or out.strip()})") else: c.fail("pi command not found") def check_extensions(c: Checker, cons: Console) -> None: section(cons, "Extensions") for ext_repo in CHECK_REPOS: match = next( (p for p in EXT_BASE.rglob("package.json") if ext_repo in str(p)), None, ) if match: c.pass_(f"{match.parent.name} installed") else: c.fail(f"{ext_repo} not found in {EXT_BASE}") def main(argv: list[str] | None = None) -> int: install_sigpipe_handler() parser = argparse.ArgumentParser(prog="validate", description=__doc__) parser.parse_args(argv) cons = Console() cons.done("=== LocalPibox Devstack Validation ===") cons.raw("") c = Checker(cons) check_sudo(c, cons) check_build_tools(c, cons) check_native_modules(c, cons) check_vscodium(c, cons) check_pi_cli(c, cons) check_extensions(c, cons) cons.done("=== Summary ===") cons.raw(f" Checks: {c.checks}") cons.raw(f" Errors: {c.errors}") cons.raw("") if c.errors == 0: cons.done(" \u2705 All checks passed — devstack is healthy") else: cons.error(f" \u2717 {c.errors} check(s) failed — review above") return min(c.errors, 255) if __name__ == "__main__": raise SystemExit(main()) |
| You are visitor 01402520 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |