Skip to content

Dashboard updates: agent self-update, server self-update, logs & version - #3

Draft
Mischa323 wants to merge 30 commits into
mainfrom
claude/loving-davinci-m9uzum
Draft

Dashboard updates: agent self-update, server self-update, logs & version#3
Mischa323 wants to merge 30 commits into
mainfrom
claude/loving-davinci-m9uzum

Conversation

@Mischa323

@Mischa323 Mischa323 commented Jun 15, 2026

Copy link
Copy Markdown
Owner

A batch of dashboard/maintenance features.

1. Agent self-update from the dashboard

  • Per-device Update agent (device drawer → Agent panel) and bulk Update all online agents (Downloads).
  • Server pushes a short-lived, token-authorised installer URL over the agent socket; Windows runs a detached msiexec major-upgrade + relaunch, Linux extracts agent.zip over the install dir preserving config + device id, then restarts. New MSI (1.0.16.0) already published.

2. Enrolment key → device mapping

  • The Active enrolment keys list in Downloads now shows which device each used key enrolled (Device column).

3. Logs & version in Settings

  • New Settings → Logs section: recent server activity from an in-memory ring buffer (root + uvicorn loggers), with a level filter and refresh.
  • Server version shown in Settings → General (About card) and the Logs header. Version resolves automatically: RMM_VERSION env → baked VERSION file → git describe → fallback. Docker build accepts --build-arg RMM_VERSION.

4. One-click server container update (Docker socket)

  • Settings → General → About: Check for updates + Update & restart.
  • docker_update.py pulls the latest image and recreates this container watchtower-style via a detached helper (clones config onto the new image, swaps under the same name, rolls back on failure). Admin-only, gated on the socket being mounted.
  • compose now defaults to the GHCR image, mounts /var/run/docker.sock, and sets RMM_SERVER_IMAGE. New CI workflow publishes ghcr.io/<repo>-server on pushes to main/beta and tags.

Testing

  • Server endpoints live-tested in dev mode (agent update 404/409/bulk counts; token-authorised download; logs capture + level filter; version resolver across all sources; server-update graceful degradation when no socket; create-spec cloning for host networking).
  • Windows agent update and the Docker-socket recreate are runtime-only (not testable in CI) — validate on the host.

Rollout notes

  • The server-image workflow publishes on merge to main/beta; the one-click server update only works once an image exists in GHCR and the package is made accessible.
  • Existing source-built deploys: the build-from-source path is kept (commented) in compose.

https://claude.ai/code/session_018TtX9oATpQWkhMVwvbxNcf

claude added 5 commits June 15, 2026 15:52
Push the latest agent build to online devices from the dashboard:
- POST /api/devices/{id}/update-agent and POST /api/orgs/{id}/update-agents
  send a one-time, token-authorised installer URL over the agent socket.
- install.msi now also authorises via ?token= so the agent can pull the MSI
  without a browser session.
- New agent updater module applies the update in place (Windows: detached
  msiexec major-upgrade + relaunch; Linux: extract agent.zip over the install
  dir, preserving config + device id, then restart the service).
- Device drawer gets an Agent section (installed vs latest + Update button);
  Downloads gets Update all online agents.
Annotate each used one-time key with the hostname of the device it enrolled
(from the device_id recorded when the key was consumed), and add a Device
column to the enrolment-key list.
- Server keeps recent log records in an in-memory ring buffer (root + uvicorn
  loggers) and exposes them via GET /api/logs (admin only, level filter).
- New GET /api/version; /api/settings now also returns RMM_VERSION.
- Settings gains a Logs section (level filter + refresh, newest last) and an
  About card in General showing the server version.
SERVER_VERSION now resolves at startup from RMM_VERSION, a baked VERSION file,
or 'git describe' (native installs), falling back to a static default. The
Docker build accepts --build-arg RMM_VERSION and compose passes ${RMM_VERSION},
so the deployed git tag/commit shows in Settings.
- docker_update.py talks to the Docker socket (no extra deps) to pull the
  latest image and recreate this container watchtower-style: it prepares a
  create-spec cloning the running container's config onto the new image and
  launches a detached helper (the new image) that stops the old container,
  recreates it under the same name, and starts it — rolling back on failure.
- Endpoints: GET /api/server/update (status), POST /api/server/update/check
  (pull + compare), POST /api/server/update/apply (recreate). Admin only,
  gated on the socket being mounted.
- Settings → General 'About this server' gains Check for updates + Update &
  restart, with an auto-reconnect spinner while the server comes back.
- compose: default to the GHCR image, mount /var/run/docker.sock, and pass
  RMM_SERVER_IMAGE so the updater knows what to track (build-from-source path
  kept as commented fallback).
- New CI workflow publishes the server image to ghcr.io/<repo>-server on
  pushes to main/beta and version tags.
@Mischa323 Mischa323 changed the title Agent self-update from the dashboard Dashboard updates: agent self-update, server self-update, logs &amp; version Jun 15, 2026
claude added 24 commits June 15, 2026 21:09
- power: run lock/logoff in the interactive console session (the agent runs as
  SYSTEM in session 0, where LockWorkStation/shutdown /l have no effect). Lock
  launches rundll32 via CreateProcessAsUserW on the active session token; logoff
  targets the active console session id.
- get_device now attaches a node's configured subnets so the device drawer
  lists them after promotion / adding.
- Collect the logged-in/console user in agent inventory and show it in the
  device drawer header + Inventory panel (new logged_in_user column + migration).
The agent includes logged_in_user in each metrics payload; the server updates
the device on every heartbeat (writing only when it changes), so the dashboard
tracks sign-in/out within ~30s instead of waiting for a re-register.
Single source of truth: /VERSION = 1.1.0. Server resolver + Dockerfile read it,
AGENT_VERSION bumped to 1.1.0, server-image tags ghcr :1.1.0, and the Windows
MSI publishes a v1.1.0 release with MSI version 1.1.<run>.0 (monotonic upgrade
over the 1.0.x line).
- Subnet add/remove (and promote/demote) from a device drawer now refresh the
  org cache and re-render the Nodes + Network views, so they no longer show
  stale subnets.
- Network scan now folds in hosts from the ARP table within the scanned
  subnets, not just ICMP responders — so devices that drop ping (e.g. Windows'
  default firewall) are discovered too. Results are flagged online.
A node's previously-seen hosts that are absent from its latest scan are marked
offline (last_seen preserved), and flip back online on rediscovery.
The MSI keeps server URL + key in machine env vars set from its properties; the
self-update reinstalled without them, so a major-upgrade wiped the config. Now:
- the Windows self-update re-passes RMM_SERVER_URL/RMM_API_KEY/RMM_INSECURE_TLS
  as msiexec properties (from the running agent's config), and
- the agent persists its resolved config to %ProgramData%\LeuffenRMM (which the
  installer never touches), so it survives any reinstall via the file fallback.
- Subnets are normalised to their network address and de-duplicated on add
  (idempotent); a migration removes any existing duplicate (node, subnet) rows.
- Windows agents add a best-effort, idempotent firewall rule allowing inbound
  ICMP echo from the local subnet, so a relay node in the same org can reliably
  discover them and confirm on-LAN reachability. Linux answers ICMP by default.
- The auto inbound-ICMP rule now allows any source (so a relay node in a
  different VLAN can ping across subnets) but applies only to the Domain and
  Private firewall profiles — a device on an untrusted Public network (café/
  airport WiFi) still won't answer pings.
- Agents enable 'Wake on Magic Packet' on physical NICs (best-effort) so they
  can actually be woken by the node; the OS firewall doesn't gate WoL (the NIC
  catches the magic packet in hardware while the machine is off).
- The device drawer's Update button now compares the installed agent version
  against the latest release: when they match it shows 'Up to date' (disabled)
  instead of always offering an update.
- Bump VERSION/AGENT_VERSION to 1.1.1 so today's accumulated agent fixes
  (config preservation, ping rule + trusted profiles, WoL, subnet dedupe,
  discovery) are a distinct, detectable version.
Agent-update and installer-download operations mint one-time tokens to authorise
a re-download; these are never consumed (the device is already enrolled), so they
piled up as 'unused' enrolment keys. Tokens now carry a kind: 'enroll' (shown,
user-generated for onboarding) vs 'internal' (hidden download/update auth). The
onboarding-keys list shows only 'enroll'; a migration reclassifies existing
agent-update/installer tokens and prunes expired internal ones.
- Every org tab (devices/approvals/network/nodes/monitors/scripts) and the
  global overview now refresh in the background on a timer (5-10s), pausing
  when the browser tab is hidden. Downloads is left static.
- The current location (global vs org + tab) is stored in the URL hash, so a
  browser refresh restores the same page instead of snapping back to the global
  dashboard.
- Agent reports per-volume disk usage each heartbeat; the device Overview shows
  the primary drive (C:/) by default and expands to all drives on click.
- Remote file management: new Files tab in the device drawer to browse folders,
  download/upload (<=25MB), create folders, and delete — bridged to agent file
  handlers (file_list/get/put/delete/mkdir). Folder sizes are computed on demand
  (bounded walk) via a per-folder 'calc' button.
- Server: file endpoints under /api/devices/{id}/files/*, disks_json column +
  heartbeat update, python-multipart for uploads.
The global Fleet overview is now widget-driven and customisable per user:
- Widget catalog: totals, organisations, needs-attention, pending approvals,
  storage pressure, monitor alerts, agent-version spread.
- Customise panel toggles widgets on/off and reorders them; saved per user
  (dashboard_prefs table). New GET/PUT /api/dashboard with aggregated data.
- Attention/disk rows drill into the device; approvals/org cards navigate in.
Server + UI only; agent unchanged.
Per decision, the ransomware behaviour monitor + auto-isolate is out of scope.
Phase 3 is now just the (shipped) configurable dashboard widgets.
The Files tab now launches a large centered popup instead of rendering in the
narrow device drawer, giving room to browse/upload/download. Closing it returns
to the Overview tab.
A wake with no explicit broadcast was sent as 255.255.255.255, which never
leaves the relay node's own L2 segment — so waking a device in a different VLAN
than the node failed. The server now resolves the matching node subnet's
directed broadcast (e.g. 192.168.50.255) and passes it to the node, so the
packet can be routed into the target VLAN.
- Metrics kept 30 days (was 7); device Overview gains a History section with
  24h/7d/30d range charts (server down-samples to ~120 buckets per range).
- Agent collects GPU name(s) (WMI / nvidia-smi / lspci); shown as 'Graphics' in
  the device inventory (new gpu column + migration).
- WoL now logs the target MAC, broadcast, port, relay node, and the agent's ack
  to Settings -> Logs, to help diagnose wake failures.
Fast Startup (hybrid shutdown) powers the NIC fully down, so a normal shutdown
leaves the machine unwakeable even with 'Wake on Magic Packet' enabled — the
most common cause of WoL silently failing after a Windows update/reboot. The
agent now also sets HiberbootEnabled=0 (disables Fast Startup, keeps hibernation).
- install.sh extracts the agent with Python's stdlib zipfile when 'unzip' isn't
  present (it was failing with 'unzip: command not found' on minimal hosts).
- Wake-on-LAN is now an admin-controlled policy (Settings -> Agents, off by
  default) instead of always-on. When enabled, agents configure the full set of
  NIC settings for WoL (magic packet, allow-to-wake, disable EEE/green ethernet)
  and disable Fast Startup; when disabled they leave/restore Windows defaults.
  Pushed over the agent socket on connect and immediately when the toggle changes.
…ates

- The Monitors nav/tab is now 'Policies' (add monitors or standards).
- Wake-on-LAN is a global Device Policy shown in the Policies -> Template rules
  view (global-admin only) with an enable/disable toggle, instead of a Settings
  -> Agents per-server toggle. Backed by the existing RMM_ENABLE_WOL setting,
  which pushes to connected agents immediately.
- WoL is now a 'policy' template in Policies -> Template rules, added like any
  monitor (with scope: global/site/group/device). One standard config (no
  thresholds). Declares os_support=[windows, windows_server].
- The agent WoL policy is computed per device from effective rules and whether
  its OS supports it; pushed on connect and immediately when a WoL rule changes.
- Device drawer gains an 'Applied policies' section listing every rule/policy
  targeting the device, each flagged active or 'not supported' for its OS.
- Alert pipeline skips the wol metric; removed the old global RMM_ENABLE_WOL
  setting and the Settings/Device-Policies toggles.
The copy value was stored in data-c via escapeHtml, which doesn't escape double
quotes — so a command like curl -fsSL "https://..." was cut off after
'curl -fsSL '. Use escapeAttr (escapes " and ') for the data-c attributes.
'pip3: command not found' on minimal hosts, and modern Debian/Ubuntu block
system-wide pip. The installer now creates an isolated virtualenv (installing
python3-venv/pip via the host package manager if needed) and installs only the
core deps (psutil, websockets) into it — the screen extras are skipped for
headless installs. The systemd unit runs the venv's python.
The agent collects installed programs on demand (Windows uninstall registry;
Linux dpkg/rpm/apk) via a software_list control message. A new device Software
tab pulls a fresh list when the device is online (cached in software_json) and
shows the cached list when offline, with a filter. Endpoint:
GET /api/devices/{id}/software.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants