system
tit.server.routes.system ¶
GET /api/system — one system snapshot (same payload as /ws/system).
:data:RELEVANT_KEYWORDS marks the rows the System page shows as toolbox work, and it is the
allowlist of POST /api/system/terminate: a pid whose name and command line match no keyword
is never killed. It lists what v3 spawns in this container -- the job runners
(simnibs_python -m tit.<module>), SimNIBS's command-line tools, FastSurfer, dcm2niix and the
docker run clients of the QSIPrep, QSIRecon and FreeSurfer sibling containers -- and nothing
else; tests/test_terminate_allowlist.py holds the command lines each keyword answers to.
The server's own process is always excluded.
Terminated ¶
Bases: BaseModel
contracts/openapi.yaml's POST /api/system/terminate 200 body.
is_relevant_process ¶
Whole-token match of any keyword against "<name> <cmdline>" (lower-cased).
job_pid_owners ¶
pid -> (job_id, label) for every job whose runner process is alive.
Reads the job manager only if one already exists in this process: get_manager() builds
and starts a manager on first call, and a system snapshot must never be the thing that spins
up the job subsystem as a side effect of someone opening a monitoring page.
Children are covered too. A job's runner spawns charm/simnibs_python as descendants,
and those are the processes a person actually sees eating the CPU -- attributing only the
runner pid would leave every interesting row unowned, and ownership is what gates the UI's
stop affordance.
Source code in tit/server/routes/system.py
kernel_pid_owners ¶
pid -> (kernel_id, label) for every notebook kernel this server owns.
Source code in tit/server/routes/system.py
process_list ¶
The busiest processes plus how many there were, sorted by CPU (descending).
Two changes from the pre-2026-09-07 list, which returned only keyword-matched processes:
- Everything is listed, capped at :data:
PROCESS_LIMIT. A process table that hides the thing currently using the CPU because its name is not on a keyword list is not a process table. The keyword match survives asProcessInfo.relevant, so the UI can still say which rows are toolbox work. - Each row carries its owner (a job, a kernel, or this server). Only an owned row gets a
stop affordance in the UI, and stopping it goes through the job's own cancel path -- the
raw
POST /api/system/terminatestays as it was, keyword-gated.
The server's own process is still never listed (it is reported once, as own).
Source code in tit/server/routes/system.py
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 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 | |
project_disk ¶
The filesystem the project volume is on; / when that cannot be read.
Source code in tit/server/routes/system.py
docker_disk ¶
The Docker root filesystem, or None when it is not visible from here.
load_average ¶
1/5/15-minute load average; [] on a platform without one.
kernel_count ¶
kernel_count() -> int
How many notebook kernels this server process owns right now.
Source code in tit/server/routes/system.py
own_process ¶
own_process() -> SelfProcessInfo | None
This server's own process — the parent of every job process.
Source code in tit/server/routes/system.py
net_io ¶
net_io() -> NetIO | None
Cumulative interface counters; the page shows the delta between two snapshots.
Source code in tit/server/routes/system.py
docker_warnings ¶
docker_warnings(health: DockerHealth) -> list[str]
The row the panel shows in the warning colour. Only conditions a person can act on.
Source code in tit/server/routes/system.py
docker_health ¶
docker_health(now: float | None = None) -> DockerHealth
Daemon reachability, docker system df, our own container and the siblings.
TTL-cached and hard-bounded, and every failure is reported rather than raised:
reachable: false with an error is a first-class answer, and the most useful thing the
panel could say at that moment. A monitoring page that goes down because the Docker daemon is
wedged has failed at the one job it had.
Source code in tit/server/routes/system.py
snapshot ¶
Build one :class:SystemSnapshot (blocking; call from a thread).
Source code in tit/server/routes/system.py
start_scan ¶
start_scan() -> bool
Kick off a background scan unless one is already running. True if started.
Source code in tit/server/routes/system.py
storage_snapshot ¶
storage_snapshot(refresh: bool = False) -> ProjectStorage
The cached scan, refreshing in the background when it is stale or forced.
Never blocks on the walk. A project that has never been scanned answers with
zeros and scanning: true, and the page says "scanning…" rather than
"0 bytes", which would be a wrong number rather than a missing one.
Source code in tit/server/routes/system.py
terminate ¶
terminate(body: dict[str, Any]) -> Terminated
{pid} -> {pid, terminated}.
Deliberately narrow (ra_14 finding 5's own-process/pid-1 guard, applied
here rather than reused from :mod:tit.jobs.runner since this route has
no job/lock context at all -- it is a raw "kill this pid" button):
pidmust be a realintgreater than 1 (pid 1 is the container's init and, under some launchers, this very server's parent).- never the server's own pid (
os.getpid()). - must currently match :func:
is_relevant_process-- the same keyword allowlist the System page's process list is built from, so this can only ever terminate a process the UI already showed as toolbox-related, never an arbitrary pid a caller guesses.