Skip to content

Settings ​

An administrator can change most of reportd's settings in the studio, under Admin → Settings (/admin/settings), instead of in the config file.

Where a setting comes from ​

reportd reads its settings in layers, each over the one before:

  1. the defaults;
  2. the config file (config.yaml, or --config, or $REPORTD_CONFIG);
  3. the settings: dataDir/settings.yaml, which setup and the Settings page write, and with state.driver: postgres, the schema's settings table over it;
  4. REPORTD_* environment variables (docker.md).

The page shows every setting with what it does, its value, its default and where its value came from: Default, Config file, Set here, or the variable's name. reportd config show --origin prints the same. Secrets are masked as config show masks them; a secret: reference is shown, since it holds no secret.

A setting the config file or a variable sets is locked. It is changed there; the page shows it with a Locked badge, and PATCH /v1/settings refuses it with 409 setting-fixed and the origin. A list or a map (limits.rate, auth.oidc.providers) is one setting, locked when the file sets any part of it.

The page ​

  • Sections group the settings (Sign-in, Security, Limits, Rendering, Viewer, Retention, …), with the ones reportd reads at start last. Each row has the setting's name, its path, what it does (from the comment on its Go field), its default and its origin, and its field: a switch, a number with its unit, a size in KB, MB or GB, a duration (30m, 8h), a list, a choice of the words it takes, or a secret: reference.
  • Search (/) finds a setting by its name, path, description or value; every word must match, and the matches are marked. The chips narrow to the settings that can be changed, that are changed, set here, locked, or read at start.
  • The inspector: a setting's name opens it in a pane on the right (?setting=<path> links to it), with all it says, the full field (the rate limits as a table, a list of objects such as the sign-in providers as JSON), its default, where its value comes from, and what applying it restarts. Escape or Close shuts it.
  • Changes wait until you apply them: each row shows Changed with Undo, Reset to default puts a setting set here back to what the config file or the default gives, and the bar at the bottom counts them. Apply changes (Mod+S) opens a review of each change, now and after, then reportd restarts once for all of them.

What the page can change ​

Every setting but these, which it shows, read-only:

Not changed hereWhy
listen, dataDir, state.*, secrets.*, migrations.*reportd reads them before it can read its settings.
renderer.command, renderer.listen, renderer.unix, the stores' paths, studio.*, viewer.dir, viewer.path, viewer.signInPath, viewer.spillDir, agents.assistant.file, sync.*Paths on disk, routes, and what isn't used yet.
admin.*The first administrator, made at the first start.
auth.mfaKeyA new key couldn't open the second factors sealed with the old one.
licence, connectionsThey have pages of their own (Licence, Data sources).

Of the rest, some need a licence feature: auth.oidc.providers, auth.saml.* (sso), renderer.urls, renderer.discover, renderer.discoverName (scale), agents.assistant.* (assistant). Secrets are only secret: references: viewer.linkSecret, renderer.token, auth.saml.key, the assistant's token and API key, client secrets and webhook secrets in their lists. The list is config.EditableSettings in internal/config/editable.go.

renderer.workers, renderer.queue and renderer.maxBodyBytes are given to the renderd reportd starts (renderer.command), as --workers, --queue and --max-body; a renderd reportd only connects to takes its own flags.

Applying ​

  • Secrets are references, never values. A secret setting takes only a secret: reference (secret:env:NAME, secret:file:NAME), so the site never writes a password to a file: a literal is refused 422 secret-literal. Sending the mask back (********) is refused 422 masked, so a secret can't be replaced by the mask.
  • Each value is checked. A setting that takes one of a few words (tests.publishGate, logging.level, …) refuses another (422 invalid), rather than reading it as the default as the config file's would; a number can't be negative.
  • The whole config is checked first. reportd resolves the config with the change, and runs the checks it runs at start. A change that would leave it invalid writes nothing (422 invalid, saying why), and so does one the licence doesn't cover (403 licence-required).
  • Applying restarts reportd, once for all the changes, in-process on the same listener, as after setup: requests wait meanwhile, signed-in sessions stay, a job's render in progress runs again, and the viewer's sessions keep their data while its limits stay the same. The renderd reportd starts restarts with it. Nothing is reloaded live.
  • Everyone is told. Before it stops, reportd tells every signed-in browser over GET /v1/events. The studio and the viewer say it is applying new settings and let people keep working: edits wait and are saved once it is back, and the connection-lost overlay doesn't come up. Back, they check the sign-in, save what waited, read again what the settings change (the branding, the licence, who is signed in, the versions) and say so. Nothing reloads; the studio offers to reload only when reportd came back as another version.
  • A change reportd can't start on is put back. If reportd fails to start on the new settings (renderd doesn't answer at a new address, say), it puts the settings back as they were and starts on those; the page then says which change was undone, and why. On the shared state, the node that made the change puts it back.
  • Reset to default sends null, which removes the setting from the settings, so the config file or the default applies again.
  • Each change is audited as settings.change with the paths, never the values.

On the shared state ​

With state.driver: postgres, a change goes to the schema's settings table, not to a node's settings.yaml. Every node polls the table's version with its other reloads, and starts again within a few seconds of a change, as it does for a new licence, telling its own browsers first. The page says that every node restarts. Two changes at once can't overwrite each other: the second is refused 409 settings-changed, and is made again on what the first wrote.

Each node's own settings.yaml (where setup writes) is still read, under the table. Backups take the two together, as the layer reportd reads; reportd state import moves settings.yaml into the table, and state export writes the layer back to dataDir (state.md).

The API ​

RouteWhat
GET /v1/settingsEvery setting: path, value (masked), origin, editable, fixed, secret, the licence feature it needs, and what it is: title, doc, kind, default, unit, options, and renderd when the renderd reportd starts is given it. shared says a change restarts every node; undone names the last change reportd couldn't start on, and why.
PATCH /v1/settings{path: value} changes, null putting one back. Answers the paths written and restart: true.
GET /v1/eventsServer-sent events for any signed-in principal: hello with reportd's run and version on connecting, and restarting with the reason and the paths changed before it stops.

The settings routes need settings.manage, which only the administrator role has and an agent key never does.

The descriptions are the comments on the settings' Go fields, which go generate ./internal/config writes to internal/config/settingdocs.json for reportd to embed; a test fails when it is out of date.