Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 13 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ A web-based administration interface for [pyobs](https://github.com/pyobs/pyobs-
the robotic telescope framework. It lets you start, stop, and restart modules, tail and
filter their logs, and view and edit their configuration files — all from a browser.

![Dashboard showing modules grouped under Stopped and Deactivated headings, with summary tiles and per-row quick-action buttons](docs/source/_static/screenshots/dashboard.jpg)

## Features

- **Dashboard** — sortable list view of all modules with:
Expand All @@ -18,15 +20,15 @@ filter their logs, and view and edit their configuration files — all from a br
- Responsive: on small screens the table collapses to status dot + name + log counts + actions
- **Module detail** — per-module view with four tabs:
- *Overview* — current status, PID, uptime, CPU and memory usage, running `pyobs-*` package versions (flagged when they lag the installed set), per-level log message counts (last 24 h), XMPP connection state (if enabled), start/restart/stop/activate/deactivate control
- *Logs* — live log tail with text filter, time-range filter (set a start date to load all logs since that instant, or click a line to set it), colour-coded by severity, auto-refresh; scrolling to the top auto-loads older entries (journald-backed modules, or file-backed modules once a start date is set, see [journald-logs.md](specs/design/journald-logs.md))
- *Logs* — live log tail with text filter, time-range filter (set a start date to load all logs since that instant, or click a line to set it), colour-coded by severity, auto-refresh; scrolling to the top auto-loads older entries (journald-backed modules, or file-backed modules once a start date is set)
- *Config* — YAML editor with syntax highlighting and colour-coded `{include}` lines; included shared configs are shown as clickable links
- *ACL* — point-and-click editor for the module's `acl:` block: click to allow/deny known modules, add other callers, toggle enforce/log mode
- **New module** — a "+" next to the sidebar's Modules section creates a brand-new `<name>.yaml` config (a minimal starter with just a `class:` key) and takes you straight to its Config tab to fill in the rest
- **Shared configs** — `*.shared.yaml` config fragments listed in a separate sidebar section with a YAML-highlighted config editor (no start/stop controls)
- **Packages** (`/packages/`) — every installed `pyobs-*` package (plus anything else listed in `PYOBS_MANAGED_PACKAGES`) with its installed and latest-PyPI version, and a one-click Update button; git/URL-installed packages get a Reinstall action instead (see [Package management](#package-management))
- **Overview** (`/overview/`) — fleet-wide summary, one row per configured host: reachable or not, running/stopped/total counts, aggregate CPU/RAM, linking into that host's own Dashboard, plus a package-version matrix (one row per `pyobs-*` package, one column per host) so version drift across the fleet is visible at a glance. Deliberately no bulk or per-module actions — those stay on the per-host Dashboard, since a fleet-wide "Stop All" from one button is a real footgun
- **All Logs** (`/logs/`) — fleet-wide live log tail across every module on every configured host, same filtering and scroll-to-load-older behaviour as a module's own Logs tab
- **ACL Matrix** (`/acl/`) — fleet-wide read-only matrix of which module can call which, merged across every configured host (see [acl-matrix.md](specs/design/acl-matrix.md))
- **ACL Matrix** (`/acl/`) — fleet-wide read-only matrix of which module can call which, merged across every configured host
- **Hub mode** — control multiple remote pyobs hosts from a single browser tab; remote hosts are listed in the sidebar and all actions are proxied transparently
- **ejabberd / XMPP status** (optional) — dashboard summary tile and per-module connected/not-connected indicator, plus a session/last-seen/registered-account block on each module's own page, for modules with a `comm.user` in their config — closes the gap between "the process is running" and "the module is actually reachable over XMPP" (see [ejabberd integration](#ejabberd-integration))
- **ejabberd / XMPP user management** (optional, builds on the above) — register, reset password, ban/unban, unregister, and kick XMPP accounts, either from a module's own Overview tab or from a fleet-wide **Users** page (`/xmpp-users/`) listing every registered account across every host, cross-referenced against which module(s) use it and which one is actually running. Safe by design for an identity shared across more than one module's `comm.user` — a password reset writes back to every module sharing it, and destructive actions name which other modules are affected before you confirm (see [ejabberd user management](#ejabberd-user-management))
Expand Down Expand Up @@ -193,13 +195,12 @@ PYOBS_LOG_DIR = "/opt/pyobs/log" # directory containing *.log files
PYOBS_RUN_DIR = "/opt/pyobs/run" # directory for PID files
PYOBS_LOG_LEVEL = "info" # log level passed to pyobs on start
PYOBS_LOG_BACKEND = None # None (default): auto-detect from pyobsd's own
# config; "file" or "journald" to override --
# see specs/design/journald-logs.md. If "journald":
# the account running pyobs-web-admin needs journal
# read access — `usermod -aG systemd-journal
# <account>` (preferred over `adm`, see the doc's
# "Which group to grant") — otherwise logs come
# back silently empty, no error.
# config; "file" or "journald" to override. If
# "journald": the account running pyobs-web-admin
# needs journal read access — `usermod -aG
# systemd-journal <account>` (preferred over `adm`,
# which grants broader log access than needed) —
# otherwise logs come back silently empty, no error.

# Packages page (optional — see Package management section)
PYOBS_MANAGED_PACKAGES = [] # e.g. ["pyobs-core[full]", "my-custom-driver",
Expand Down Expand Up @@ -389,7 +390,7 @@ it as-is; `mod_http_api` can also expose account-management commands
trusted, no password or token is involved. This blocks the network (a request from outside
the host is rejected), but **not** other processes on the same machine, which get the same
access pyobs-web-admin does. That's an accepted tradeoff for a dedicated, single-purpose
observatory control host — see `specs/design/ejabberd-integration.md` if your threat model is different.
observatory control host, not a shared one — reassess if that's not your deployment.

---

Expand Down Expand Up @@ -539,12 +540,12 @@ end up as a literal `pip install` command-line argument, visible to any other lo
- **Discovery** — all `*.yaml` files in `PYOBS_CONFIG_DIR` (excluding `*.shared.yaml`) are treated as modules. `*.shared.yaml` files are listed separately as shared configs.
- **Creating a module** — the "New module" button writes a fresh `<name>.yaml` with a minimal starter (`class:` key only); `PYOBS_CONFIG_DIR` is created automatically if it doesn't exist yet.
- **Activate / Deactivate** — deactivating a module renames its config from `name.yaml` to `_name.yaml` (stopping it first if running); activating renames it back. Deactivated modules are excluded from *Start All* and *Restart All*.
- **Start** — runs `pyobs --pid-file <run>/<name>.pid --log-file <log>/<name>.log --log-level <level> <config>`. pyobs daemonises itself via `python-daemon`. If the effective log backend is `"journald"` (see below), `--syslog` is passed instead of `--log-file` — pyobs then logs directly to the systemd journal, tagged `SYSLOG_IDENTIFIER=pyobs` and `PYOBS_MODULE=<name>` (see [journald-logs.md](specs/design/journald-logs.md)).
- **Start** — runs `pyobs --pid-file <run>/<name>.pid --log-file <log>/<name>.log --log-level <level> <config>`. pyobs daemonises itself via `python-daemon`. If the effective log backend is `"journald"` (see below), `--syslog` is passed instead of `--log-file` — pyobs then logs directly to the systemd journal, tagged `SYSLOG_IDENTIFIER=pyobs` and `PYOBS_MODULE=<name>`.
- **Stop** — sends `SIGTERM` to the PID in the PID file; falls back to `SIGKILL` after 5 s.
- **Restart** — stop followed by start.
- **Status** — checks whether the process with the stored PID is alive (`os.kill(pid, 0)`).
- **Resource usage** — uptime, CPU %, and RSS memory read via `psutil` on every status poll.
- **Logs** — read from `PYOBS_LOG_DIR`'s flat files by default, or from the systemd journal via `journalctl` if the effective log backend is `"journald"`; the log viewer and per-level counts work identically either way. The effective backend is `PYOBS_LOG_BACKEND` if set explicitly, otherwise auto-detected from `pyobsd`'s own config file (`~/.config/pyobs.yaml`, `/etc/pyobs.yaml`, or `/opt/pyobs/storage/pyobs.yaml`, first found wins) — the same file `pyobsd` (`pyobs-core`'s daemon manager) reads to decide whether *it* starts modules with `--syslog`, so this can't silently drift out of sync with it. Scrolling a log window to the top auto-loads older entries via journalctl's `--until`, for journald-backed modules only — the file backend's plain `tail -n` has no seek/offset to page further back with, so it reports nothing older available instead (see [journald-logs.md](specs/design/journald-logs.md)).
- **Logs** — read from `PYOBS_LOG_DIR`'s flat files by default, or from the systemd journal via `journalctl` if the effective log backend is `"journald"`; the log viewer and per-level counts work identically either way. The effective backend is `PYOBS_LOG_BACKEND` if set explicitly, otherwise auto-detected from `pyobsd`'s own config file (`~/.config/pyobs.yaml`, `/etc/pyobs.yaml`, or `/opt/pyobs/storage/pyobs.yaml`, first found wins) — the same file `pyobsd` (`pyobs-core`'s daemon manager) reads to decide whether *it* starts modules with `--syslog`, so this can't silently drift out of sync with it. Scrolling a log window to the top auto-loads older entries via journalctl's `--until`, for journald-backed modules only — the file backend's plain `tail -n` has no seek/offset to page further back with, so it reports nothing older available instead.
- **Log counts** — per-level message counts (DEBUG / INFO / WARNING / ERROR / CRITICAL) for the last 24 h, using binary search on the log file to avoid reading the whole file.

---
Expand Down
Binary file added docs/source/_static/screenshots/config-editor.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/_static/screenshots/dashboard.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions docs/source/features/dashboard.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
Dashboard and module detail
############################

.. image:: ../_static/screenshots/dashboard.jpg
:alt: Dashboard showing six modules grouped under Stopped and Deactivated headings, with
Total/Running/Stopped/RAM/CPU summary tiles and per-row quick-action buttons.
:width: 100%

.. image:: ../_static/screenshots/config-editor.jpg
:alt: Module detail Config tab showing a syntax-highlighted YAML editor for a module's
config file.
:width: 100%

Dashboard
*********

Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "pyobs-web-admin"
version = "2.0.0.dev14"
version = "2.0.0"
description = "Web-based administration interface for pyobs robotic telescope modules"
authors = [
{ name = "Tim-Oliver Husser", email = "thusser@uni-goettingen.de" },
Expand All @@ -11,7 +11,7 @@ dependencies = [
"gunicorn>=26.0.0",
"packaging>=24.0",
"psutil>=6.0",
"pyobs-auth>=2.0.0.dev9",
"pyobs-auth>=2.0.0",
"pyyaml>=6.0",
"requests>=2.32",
"ruamel.yaml>=0.18",
Expand Down
10 changes: 5 additions & 5 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading