bridge: configurable Nextcloud request timeout, dynamic Health metric discovery
Auto-detect which Health metrics the instance actually knows and enable any that are known but disabled for the user, via GET/PUT configuration. Also makes the previously hardcoded 10s request timeout configurable via NC_TIMEOUT_SECONDS to accommodate slower instances.
This commit is contained in:
+51
-2
@@ -31,10 +31,58 @@ except KeyError:
|
||||
credentials = json.loads(CREDENTIALS_FILE.read_text())
|
||||
NC_SERVER = credentials["server"]
|
||||
NC_AUTH = (credentials["login_name"], credentials["app_password"])
|
||||
ENTRIES_URL = f"{NC_SERVER}/ocs/v2.php/apps/health/api/v2/entries"
|
||||
HEALTH_API = f"{NC_SERVER}/ocs/v2.php/apps/health/api/v2"
|
||||
ENTRIES_URL = f"{HEALTH_API}/entries"
|
||||
CONFIGURATION_URL = f"{HEALTH_API}/configuration"
|
||||
# Identifies this bridge in Nextcloud's server logs and admin UI instead of the
|
||||
# default "python-requests/x.y.z".
|
||||
USER_AGENT = "PrivateHealthBridge"
|
||||
# Some instances (cold PHP-FPM, slow DB) need more than a few seconds to answer.
|
||||
NC_TIMEOUT_SECONDS = float(os.environ.get("NC_TIMEOUT_SECONDS", "30"))
|
||||
# Every metric this bridge can forward; new users only have "stress" enabled
|
||||
# by default, so writes would otherwise fail with an "unsupported metric" error.
|
||||
WANTED_METRICS = ("weight",)
|
||||
# Filled at startup from the server's actual configuration response, since a
|
||||
# Health instance may not know a metric yet at all or may just have it
|
||||
# disabled for this user.
|
||||
supported_metrics: set[str] = set()
|
||||
|
||||
|
||||
def discover_supported_metrics() -> None:
|
||||
resp = requests.get(
|
||||
CONFIGURATION_URL,
|
||||
auth=NC_AUTH,
|
||||
headers={"OCS-APIRequest": "true", "Accept": "application/json", "User-Agent": USER_AGENT},
|
||||
params={"format": "json"},
|
||||
timeout=NC_TIMEOUT_SECONDS,
|
||||
)
|
||||
resp.raise_for_status()
|
||||
current = resp.json()["ocs"]["data"]["metrics"]
|
||||
|
||||
unknown = [m for m in WANTED_METRICS if m not in current]
|
||||
if unknown:
|
||||
log.warning("This Health instance doesn't know these metrics yet, skipping them: %s", unknown)
|
||||
|
||||
disabled = [m for m in WANTED_METRICS if m in current and not current[m]["enabled"]]
|
||||
if disabled:
|
||||
log.info("Enabling Health metrics not yet active for this user: %s", disabled)
|
||||
resp = requests.put(
|
||||
CONFIGURATION_URL,
|
||||
json={"metrics": {m: {"enabled": True} for m in disabled}},
|
||||
auth=NC_AUTH,
|
||||
headers={
|
||||
"OCS-APIRequest": "true",
|
||||
"Accept": "application/json",
|
||||
"User-Agent": USER_AGENT,
|
||||
},
|
||||
params={"format": "json"},
|
||||
timeout=NC_TIMEOUT_SECONDS,
|
||||
)
|
||||
if not resp.ok:
|
||||
log.error("Nextcloud rejected configuration update: %s -> %s", resp.status_code, resp.text)
|
||||
resp.raise_for_status()
|
||||
|
||||
supported_metrics.update(m for m in WANTED_METRICS if m not in unknown)
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@@ -80,7 +128,7 @@ def forward_weight_entry(record: dict) -> None:
|
||||
"User-Agent": USER_AGENT,
|
||||
},
|
||||
params={"format": "json"},
|
||||
timeout=10,
|
||||
timeout=NC_TIMEOUT_SECONDS,
|
||||
)
|
||||
resp.raise_for_status()
|
||||
|
||||
@@ -112,4 +160,5 @@ def health_connect_webhook():
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
discover_supported_metrics()
|
||||
app.run(host="0.0.0.0", port=8080)
|
||||
|
||||
Reference in New Issue
Block a user