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())
|
credentials = json.loads(CREDENTIALS_FILE.read_text())
|
||||||
NC_SERVER = credentials["server"]
|
NC_SERVER = credentials["server"]
|
||||||
NC_AUTH = (credentials["login_name"], credentials["app_password"])
|
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
|
# Identifies this bridge in Nextcloud's server logs and admin UI instead of the
|
||||||
# default "python-requests/x.y.z".
|
# default "python-requests/x.y.z".
|
||||||
USER_AGENT = "PrivateHealthBridge"
|
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__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
@@ -80,7 +128,7 @@ def forward_weight_entry(record: dict) -> None:
|
|||||||
"User-Agent": USER_AGENT,
|
"User-Agent": USER_AGENT,
|
||||||
},
|
},
|
||||||
params={"format": "json"},
|
params={"format": "json"},
|
||||||
timeout=10,
|
timeout=NC_TIMEOUT_SECONDS,
|
||||||
)
|
)
|
||||||
resp.raise_for_status()
|
resp.raise_for_status()
|
||||||
|
|
||||||
@@ -112,4 +160,5 @@ def health_connect_webhook():
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
discover_supported_metrics()
|
||||||
app.run(host="0.0.0.0", port=8080)
|
app.run(host="0.0.0.0", port=8080)
|
||||||
|
|||||||
Reference in New Issue
Block a user