How to change config at runtime - IBM/ibm-spectrum-scale-bridge-for-grafana GitHub Wiki

The IBM Storage Scale Bridge for Grafana exposes a /config REST API that lets you read and update selected configuration parameters while the bridge is running — without editing files. Some parameters take effect immediately; others are written to the config file and require a bridge restart to apply.

Overview

The API is mounted on the same port as the OpenTSDB or Prometheus endpoint and is protected by the same HTTP Basic Authentication that guards all other bridge endpoints. No extra setup is required.

Configuration parameters are grouped the same way they appear in config.ini: each parameter belongs to a section (e.g. prometheues_exporter_plugin, logging). The full config view always returns this sectioned structure so the output maps directly back to the file you would otherwise edit by hand.

Parameters that are commented-out in config.ini (i.e. not yet active) appear in the API response with the value "disabled" so you can see the complete picture at a glance.

Secret values (password, apiKeyValue) are never returned or accepted by the API.


Endpoints

Method URL Description
GET /config All non-secret settings, grouped by INI section
GET /config?key=<name> A single setting (flat {key: value})
PATCH /config Batch-update one or more writable keys
PUT /config?key=<name> Update a single writable key
GET /config/sections List available INI section names
GET /config/section/<section> All non-secret keys in one INI section
PATCH /config/section/<section> Update writable keys scoped to one INI section
POST /config/init Create the custom config file so writes are persisted
GET /config/validate Validate the current live configuration
POST /config/validate Dry-run: validate a proposed change without applying it

Key categories

Each configuration key falls into exactly one of the following categories, which determines what the API will do with it.

Writable — applied immediately

These keys are safe to change while the bridge is running. The new value takes effect in the current process immediately and is also written back to the custom config file so it survives a restart.

Key Section Description
rawCounters prometheues_exporter_plugin Export raw sensor counter values (true / false)
logLevel logging Active log level (see table below)
includeDiskData query Use historical disk data (true / false)
retryDelay server Seconds before retrying a failed metadata fetch

Log levels

Value Name
5 TRACE
10 DEBUG
15 MOREINFO
20 INFO
30 WARN
40 ERROR

Restart-required — persisted but not applied immediately

These keys are tied to bound server sockets, open file handles, or TLS connections that cannot be changed while the bridge is running. The API always writes the new value to the config file and returns a "requires restart" message in the rejected field. Restart the bridge to apply the change.

Sending null as the value removes the key from the config file entirely, which disables the corresponding feature on the next restart.

This category includes: prometheus, port, protocol, server, serverPort, opentsdbBindIp, promBindIp, tlsKeyPath, tlsKeyFile, tlsCertFile, caCertPath, logPath, logFile, cpAccessLog, cpAccessLogBackups.

Hidden — never readable or writable

password and apiKeyValue are never returned in any response and are silently rejected in write requests.


Response format

Read responses

GET /config returns a JSON object keyed by INI section name. Each section contains its keys with their current values. A value of "disabled" means the key is known to the configuration schema but was not set (still commented-out in the INI file).

{
  "basic_auth": {
    "enabled":  true,
    "username": "scale_admin"
  },
  "connection": {
    "protocol": "http"
  },
  "logging": {
    "cpAccessLog":        "on",
    "cpAccessLogBackups": 10,
    "logFile":            "zserver.log",
    "logLevel":           15,
    "logPath":            "/var/log/ibm_bridge_for_grafana"
  },
  "opentsdb_plugin": {
    "opentsdbBindIp": "0.0.0.0",
    "port":           4242
  },
  "prometheues_exporter_plugin": {
    "promBindIp":  "0.0.0.0",
    "prometheus":  "disabled",
    "rawCounters": true
  },
  "query": {
    "includeDiskData": false
  },
  "server": {
    "apiKeyName":  "scale_grafana",
    "caCertPath":  false,
    "retryDelay":  60,
    "server":      "localhost",
    "serverPort":  9980
  },
  "tls": {
    "tlsCertFile": "disabled",
    "tlsKeyFile":  "disabled",
    "tlsKeyPath":  "disabled"
  }
}

In this example the bridge was started without a Prometheus port (prometheus is "disabled") and without TLS certificates (all three tls keys are "disabled").

Write responses

All write endpoints return the same JSON structure:

{
  "updated":          { "rawCounters": false },
  "restart_required": { "port": "read-only: restart the bridge to apply this change" },
  "rejected":         {},
  "persisted":        true
}
Field Type Description
updated object Keys applied to the running process immediately
restart_required object Keys written to the config file but requiring a bridge restart to take effect
rejected object Keys refused entirely (secret / unknown / read-only), with a reason string each
persisted true/false/str true = written to file; false = I/O error; string = why writing was skipped

persisted is a descriptive string (not false) when writing is skipped for a known reason:

  • No custom config file exists → call POST /config/init to create one
  • The template config.ini was passed as -F → create a separate custom file

Examples

All examples assume the bridge is listening on port 4242 and Basic Auth is enabled with the default username scale_admin.

Read the full configuration

curl -s -u scale_admin:MyPassword \
     http://scale-bridge.example.com:4242/config \
  | python3 -m json.tool

Read a single key

curl -s -u scale_admin:MyPassword \
     "http://scale-bridge.example.com:4242/config?key=logLevel"
{ "logLevel": 15 }

List available sections

curl -s -u scale_admin:MyPassword \
     http://scale-bridge.example.com:4242/config/sections
{
  "sections": [
    "basic_auth", "connection", "logging",
    "opentsdb_plugin", "prometheues_exporter_plugin",
    "query", "server", "tls"
  ]
}

Read a single section

curl -s -u scale_admin:MyPassword \
     http://scale-bridge.example.com:4242/config/section/prometheues_exporter_plugin
{
  "promBindIp":  "0.0.0.0",
  "prometheus":  "disabled",
  "rawCounters": true
}

Enable TRACE logging immediately

curl -s -u scale_admin:MyPassword \
     -X PUT \
     -H "Content-Type: application/json" \
     -d '{"value": 5}' \
     "http://scale-bridge.example.com:4242/config?key=logLevel"
{
  "updated":          { "logLevel": 5 },
  "restart_required": {},
  "rejected":         {},
  "persisted":        true
}

The bridge logs at TRACE level immediately — no restart required. To revert to the default MOREINFO level:

curl -s -u scale_admin:MyPassword \
     -X PUT \
     -H "Content-Type: application/json" \
     -d '{"value": 15}' \
     "http://scale-bridge.example.com:4242/config?key=logLevel"

Disable raw counter export

curl -s -u scale_admin:MyPassword \
     -X PUT \
     -H "Content-Type: application/json" \
     -d '{"value": false}' \
     "http://scale-bridge.example.com:4242/config?key=rawCounters"
{
  "updated":          { "rawCounters": false },
  "restart_required": {},
  "rejected":         {},
  "persisted":        true
}

Batch update multiple writable keys

curl -s -u scale_admin:MyPassword \
     -X PATCH \
     -H "Content-Type: application/json" \
     -d '{"rawCounters": false, "logLevel": 20, "retryDelay": 30}' \
     http://scale-bridge.example.com:4242/config
{
  "updated":          { "rawCounters": false, "logLevel": 20, "retryDelay": 30 },
  "restart_required": {},
  "rejected":         {},
  "persisted":        true
}

Update writable keys scoped to a section

curl -s -u scale_admin:MyPassword \
     -X PATCH \
     -H "Content-Type: application/json" \
     -d '{"rawCounters": false}' \
     http://scale-bridge.example.com:4242/config/section/prometheues_exporter_plugin
{
  "section":          "prometheues_exporter_plugin",
  "updated":          { "rawCounters": false },
  "restart_required": {},
  "rejected":         {},
  "persisted":        true
}

Keys sent to the wrong section endpoint are rejected immediately with a clear reason before any update is applied:

curl -s -u scale_admin:MyPassword \
     -X PATCH \
     -H "Content-Type: application/json" \
     -d '{"rawCounters": false, "logLevel": 10}' \
     http://scale-bridge.example.com:4242/config/section/prometheues_exporter_plugin
{
  "section":          "prometheues_exporter_plugin",
  "updated":          { "rawCounters": false },
  "restart_required": {},
  "rejected":         { "logLevel": "key does not belong to section 'prometheues_exporter_plugin'" },
  "persisted":        true
}

Enable the Prometheus exporter (requires restart)

The Prometheus port is bound at startup and cannot be changed in a live process. The API writes the value to the config file and returns it in restart_required:

curl -s -u scale_admin:MyPassword \
     -X PUT \
     -H "Content-Type: application/json" \
     -d '{"value": 9250}' \
     "http://scale-bridge.example.com:4242/config?key=prometheus"
{
  "updated":          {},
  "restart_required": {
    "prometheus": "read-only: restart the bridge to apply this change"
  },
  "rejected":         {},
  "persisted":        true
}

After restarting the bridge the Prometheus exporter starts listening on port 9250.

Disable the OpenTSDB port (requires restart)

Pass null to remove the key from the config file. The feature will be inactive after the next restart.

curl -s -u scale_admin:MyPassword \
     -X PATCH \
     -H "Content-Type: application/json" \
     -d '{"port": null}' \
     http://scale-bridge.example.com:4242/config/section/opentsdb_plugin
{
  "section":          "opentsdb_plugin",
  "updated":          {},
  "restart_required": {
    "port": "read-only: restart the bridge to apply this change"
  },
  "rejected":         {},
  "persisted":        true
}

The port line is removed from custom.ini. After restarting, the bridge starts without an OpenTSDB listener. To re-enable it later:

curl -s -u scale_admin:MyPassword \
     -X PATCH \
     -H "Content-Type: application/json" \
     -d '{"port": 4242}' \
     http://scale-bridge.example.com:4242/config/section/opentsdb_plugin

Create the custom config file (first-time setup)

If the bridge was started without a custom config file, write calls succeed in-memory but return "persisted": false and log a warning. Call this endpoint once to create the file — no restart required.

Without a body the file is created at the default RPM location (/etc/grafanabridge/config.ini). Pass a "path" key to choose a different location:

# Default location:
curl -s -u scale_admin:MyPassword \
     -X POST \
     http://scale-bridge.example.com:4242/config/init

# Custom location:
curl -s -u scale_admin:MyPassword \
     -X POST \
     -H "Content-Type: application/json" \
     -d '{"path": "/opt/bridge/myconfig.ini"}' \
     http://scale-bridge.example.com:4242/config/init

File created at the default location (201 Created):

{ "created": true, "path": "/etc/grafanabridge/config.ini" }

All subsequent PATCH / PUT writes are persisted immediately — no restart required.

File created at a custom path (201 Created):

{
  "created": true,
  "path": "/opt/bridge/myconfig.ini",
  "note": "Restart required: update your service to add '-F /opt/bridge/myconfig.ini' and restart the bridge before writes are persisted to this file."
}

A custom path is not automatically picked up by the running bridge. Update the systemd unit and restart before subsequent writes will be persisted:

# Add -F to the service ExecStart line:
systemctl edit grafana-bridge
# → Add: ExecStart=... -F /opt/bridge/myconfig.ini

systemctl daemon-reload
systemctl restart grafana-bridge

File already exists (200 OK):

{ "created": false, "path": "/etc/grafanabridge/config.ini", "reason": "already exists" }

Note: if the bridge was started with -F /path/to/config.ini that file already exists by definition, so this endpoint is only needed when no custom file is present at all.

Validate the current configuration

curl -s -u scale_admin:MyPassword \
     http://scale-bridge.example.com:4242/config/validate

Valid configuration (200 OK):

{ "valid": true }

Invalid configuration (e.g. missing API key, 200 OK):

{
  "valid": false,
  "errors": ["Missing mandatory ApiKey settings, quitting"]
}

Dry-run validate a proposed change

POST a JSON object with the keys you intend to change. The bridge merges the values into a copy of the live configuration and validates the result. Nothing is applied or written to disk.

curl -s -u scale_admin:MyPassword \
     -X POST \
     -H "Content-Type: application/json" \
     -d '{"protocol": "https", "tlsKeyPath": "/etc/bridge_ssl/certs", "tlsKeyFile": "privkey.pem", "tlsCertFile": "cert.pem"}' \
     http://scale-bridge.example.com:4242/config/validate

Change would be valid (200 OK):

{
  "valid": true,
  "candidate": {
    "protocol": "https",
    "tlsKeyPath": "/etc/bridge_ssl/certs",
    "tlsKeyFile": "privkey.pem",
    "tlsCertFile": "cert.pem",
    "..."  : "..."
  }
}

Change would be invalid (200 OK):

{
  "valid": false,
  "errors": ["Missing certificates in the specified keyPath directory, quitting"],
  "candidate": { "..." : "..." }
}

The candidate field always reflects the full merged configuration that was checked (secret keys password and apiKeyValue are omitted).

Validate from the command line

The --validate flag accepts an optional MODE argument:

Invocation Behaviour
--validate or --validate config Validate and exit. Code 0 = valid, 1 = invalid.
--validate start Validate and, if valid, continue starting the bridge.

--validate config — check and exit (pre-flight)

Suitable for deployment scripts or systemd ExecStartPre= directives.

# Bare flag (same as --validate config):
python zimonGrafanaIntf.py -F /etc/grafanabridge/config.ini --validate

# Explicit mode:
python zimonGrafanaIntf.py -F /etc/grafanabridge/config.ini --validate config

Valid (exits with code 0):

Config valid.

Invalid (exits with code 1):

Missing mandatory ApiKey settings, quitting

Use in a systemd unit to block startup on an invalid config:

ExecStartPre=python zimonGrafanaIntf.py -F /etc/grafanabridge/config.ini --validate config
ExecStart=python zimonGrafanaIntf.py -F /etc/grafanabridge/config.ini

--validate start — validate then start

Validates the configuration and, if valid, continues to start the bridge normally — no separate invocation needed.

python zimonGrafanaIntf.py -F /etc/grafanabridge/config.ini --validate start

Valid — bridge starts:

Config valid. Starting bridge...

Invalid — bridge does not start (exits with code 1):

Missing mandatory ApiKey settings, quitting

Authentication

The /config endpoint inherits the global HTTP Basic Authentication already configured for the bridge. All requests must include an Authorization header.

To skip certificate verification when the bridge uses HTTPS:

curl -k -u scale_admin:MyPassword https://scale-bridge.example.com:8443/config

Persistence

When the bridge was started with a custom config file (-F /path/to/config.ini) or the default RPM override file /etc/grafanabridge/config.ini exists, every successful write is flushed back to that file. The bundled template config.ini that ships with the bridge is never modified.

If no writable target file is available the update is still applied in-memory and "persisted": false is returned. The change will be lost when the bridge is restarted.

⚠️ **GitHub.com Fallback** ⚠️