56 lines
1.5 KiB
Python
Executable File
56 lines
1.5 KiB
Python
Executable File
"""Prometheus queries — node load lookups.
|
|
|
|
F-06 remediation: ``PROM_URL`` is now resolved from
|
|
``backend.config.EXTERNAL_CONFIG["prometheus_url"]`` (env-var
|
|
``FESTER_PROM_URL``) instead of being hardcoded.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from typing import Optional
|
|
|
|
import requests
|
|
|
|
from backend.config import EXTERNAL_CONFIG
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
def _prom_url() -> str:
|
|
"""Return the current Prometheus URL.
|
|
|
|
Read at call time so tests / operators can monkey-patch the env
|
|
var between requests without restarting the process.
|
|
"""
|
|
import os
|
|
return os.environ.get(
|
|
"FESTER_PROM_URL",
|
|
EXTERNAL_CONFIG.get("prometheus_url", "http://localhost:9090"),
|
|
)
|
|
|
|
|
|
def get_node_load(node: str) -> float:
|
|
"""Return the 1-minute load average for ``node``.
|
|
|
|
Falls back to 1.0 on any error (Prometheus down, metric missing,
|
|
network error) so the scheduler always gets a usable number.
|
|
"""
|
|
query = f'node_load1{{instance="{node}"}}'
|
|
try:
|
|
r = requests.get(
|
|
f"{_prom_url()}/api/v1/query",
|
|
params={"query": query},
|
|
timeout=5,
|
|
)
|
|
r.raise_for_status()
|
|
data = r.json()
|
|
result = data.get("data", {}).get("result", [])
|
|
if not result:
|
|
log.debug("prometheus returned no data for %s", node)
|
|
return 1.0
|
|
return float(result[0]["value"][1])
|
|
except Exception as e:
|
|
log.debug("prometheus lookup failed for %s: %s", node, e)
|
|
return 1.0
|