Discover independent camera instances and prepare their versioned runtime from Node or remote Core. Add isolated SDK workers, camera controls, raw dual-fisheye WebRTC preview, and shared action/region loading states. Recover existing Node bindings over known Tailscale addresses after a Core LAN address change. Preserve identities and trust, pin both peers, migrate endpoints with revision checks, and require real heartbeats for online status. Fix the Python client certificate profile for Go X509 verification. Pin Design Guideline 8c53f73 and retain installer/build/acceptance history. Node 0.8.19 is installed; X4 0.1.3-3 is bundled but hardware activation is pending. Validation: qualified DG/Node builds and Go race tests; 31 fleet tests; Python-to-Go certificate interoperability and live tailnet recovery with five fresh heartbeats; prior 38 X4 tests and bounded remote WebRTC acceptance. Clean-OS, replug/power autonomy, local X4 video and long-run stability remain open.
158 lines
4.6 KiB
Python
158 lines
4.6 KiB
Python
"""Root-only USB-to-unit reconciler. No client commands, SDK loading or network."""
|
|
|
|
import json
|
|
import os
|
|
import re
|
|
import signal
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
from layout import CONTROL, active, directory, trusted, write # noqa: E402
|
|
from runtime.identity import read_binding # noqa: E402
|
|
|
|
UNITS = Path("/run/systemd/system")
|
|
PREFIX = "mission-core-x4@"
|
|
PATTERN = re.compile(r"instax4_[0-9a-f]{32}")
|
|
|
|
|
|
def systemctl(*args):
|
|
subprocess.run(
|
|
["/usr/bin/systemctl", *args],
|
|
check=True,
|
|
timeout=20,
|
|
stdout=subprocess.DEVNULL,
|
|
stderr=subprocess.PIPE,
|
|
)
|
|
|
|
|
|
def unit(binding):
|
|
runtime = trusted(active(), True)
|
|
# Every interpolated value is a verified OS binding or root-owned revision.
|
|
return f"""[Unit]
|
|
Description=Mission Core isolated Insta360 X4
|
|
After=mission-core-insta360-supervisor.service
|
|
[Service]
|
|
Type=exec
|
|
DynamicUser=yes
|
|
User=mcx4-{binding.device_id[-20:]}
|
|
Group=mission-core-node
|
|
SupplementaryGroups=mission-core-x4-usb
|
|
ExecStart=/usr/bin/python3 -I /usr/lib/mission-core-node/insta360/bootstrap.py worker {binding.port}
|
|
WorkingDirectory={runtime}/bin
|
|
StateDirectory=mission-core-x4/{binding.device_id}
|
|
StateDirectoryMode=0700
|
|
RuntimeDirectory=mission-core-x4-instances/{binding.device_id}
|
|
RuntimeDirectoryMode=0750
|
|
UMask=0007
|
|
PrivateDevices=yes
|
|
BindPaths={binding.device_path}
|
|
DevicePolicy=closed
|
|
DeviceAllow={binding.device_path} rw
|
|
PrivateNetwork=yes
|
|
NoNewPrivileges=yes
|
|
CapabilityBoundingSet=
|
|
ProtectSystem=strict
|
|
ProtectHome=yes
|
|
PrivateTmp=yes
|
|
ProtectKernelTunables=yes
|
|
ProtectKernelModules=yes
|
|
ProtectControlGroups=yes
|
|
RestrictSUIDSGID=yes
|
|
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK
|
|
LockPersonality=yes
|
|
SystemCallFilter=~@mount
|
|
ReadOnlyPaths={CONTROL}
|
|
TasksMax=64
|
|
MemoryMax=384M
|
|
CPUQuota=150%
|
|
LimitNOFILE=256
|
|
LimitCORE=0
|
|
TimeoutStopSec=8
|
|
KillMode=control-group
|
|
Restart=no
|
|
StandardOutput=null
|
|
StandardError=null
|
|
""".encode()
|
|
|
|
|
|
def bindings():
|
|
found, duplicates = {}, set()
|
|
for path in Path("/sys/bus/usb/devices").iterdir():
|
|
try:
|
|
value = read_binding(path.name)
|
|
except (OSError, ValueError):
|
|
continue
|
|
if value.device_id in found:
|
|
duplicates.add(value.device_id)
|
|
found[value.device_id] = value
|
|
return {ident: value for ident, value in found.items() if ident not in duplicates}
|
|
|
|
|
|
def main():
|
|
if os.geteuid() or len(sys.argv) != 1:
|
|
raise RuntimeError("Use the fixed installed supervisor unit")
|
|
directory(CONTROL)
|
|
# Captured by root; a worker need not gain ptrace access to PID 1 merely
|
|
# to prove it uses a different network namespace.
|
|
write(CONTROL / "host-net-inode", str(Path("/proc/self/ns/net").stat().st_ino).encode())
|
|
stopping = False
|
|
|
|
def stop(*_):
|
|
nonlocal stopping
|
|
stopping = True
|
|
|
|
signal.signal(signal.SIGTERM, stop)
|
|
signal.signal(signal.SIGINT, stop)
|
|
known = {}
|
|
startup = True
|
|
record = CONTROL / "bindings.json"
|
|
if record.exists():
|
|
previous = json.loads(trusted(record).read_text())
|
|
for ident, info in previous.items():
|
|
if not PATTERN.fullmatch(ident):
|
|
raise RuntimeError("Invalid previous camera binding")
|
|
known[ident] = info
|
|
while not stopping:
|
|
observed = bindings()
|
|
current = {
|
|
ident: {
|
|
"port": item.port,
|
|
"bus": item.bus,
|
|
"address": item.address,
|
|
"revision": active().name,
|
|
}
|
|
for ident, item in observed.items()
|
|
}
|
|
changed = False
|
|
for ident in list(known):
|
|
if current.get(ident) != known[ident]:
|
|
systemctl("stop", PREFIX + ident + ".service")
|
|
path = UNITS / (PREFIX + ident + ".service")
|
|
if path.exists():
|
|
trusted(path).unlink()
|
|
del known[ident]
|
|
changed = True
|
|
additions = [ident for ident in current if ident not in known]
|
|
for ident in additions:
|
|
item = observed[ident]
|
|
if read_binding(item.port) != item:
|
|
continue
|
|
write(UNITS / (PREFIX + ident + ".service"), unit(item))
|
|
known[ident] = current[ident]
|
|
changed = True
|
|
if changed:
|
|
write(record, json.dumps(known, sort_keys=True).encode())
|
|
systemctl("daemon-reload")
|
|
for ident in list(current) if startup else additions:
|
|
if ident in known:
|
|
systemctl("start", PREFIX + ident + ".service")
|
|
startup = False
|
|
time.sleep(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|