Remote cache: extend to monitor stats; vv_local_host_stats(), 2h bg refresh covers monitor+arrs pages
This commit is contained in:
@@ -613,6 +613,18 @@ function vv_remote_hosts_stats(): array {
|
|||||||
$results = [];
|
$results = [];
|
||||||
foreach ($hostIds as $id) {
|
foreach ($hostIds as $id) {
|
||||||
if (strtolower($id) === strtolower($myHost)) continue;
|
if (strtolower($id) === strtolower($myHost)) continue;
|
||||||
|
// Background cache written by remote_arr_cache_writer.sh every 2h — use it if present.
|
||||||
|
$bgCache = VV_CACHE_DIR . '/monitor_remote_' . strtolower($id) . '.json';
|
||||||
|
if (file_exists($bgCache)) {
|
||||||
|
$cached = json_decode(file_get_contents($bgCache), true);
|
||||||
|
if ($cached) {
|
||||||
|
$cached['cache_age'] = time() - (int)filemtime($bgCache);
|
||||||
|
$results[$id] = $cached;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No background cache yet — fall back to live call (uses 30s inline cache).
|
||||||
$key = $vars[strtoupper($id) . '_UNRAID_API_KEY'] ?? '';
|
$key = $vars[strtoupper($id) . '_UNRAID_API_KEY'] ?? '';
|
||||||
if (!$key) {
|
if (!$key) {
|
||||||
$results[$id] = ['available' => false, 'no_api_key' => true,
|
$results[$id] = ['available' => false, 'no_api_key' => true,
|
||||||
|
|||||||
@@ -187,6 +187,57 @@ function vv_api_node_metrics(?array $d): array {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Local host stats snapshot — same shape as one entry from vv_remote_hosts_stats() ─────────
|
||||||
|
// Called locally and via SSH by remote_arr_cache_writer.sh on remote hosts.
|
||||||
|
function vv_local_host_stats(): array {
|
||||||
|
$host = vv_detect_host();
|
||||||
|
$myId = strtoupper($host);
|
||||||
|
$vars = vv_conf_vars();
|
||||||
|
$name = $vars[$myId] ?? gethostname();
|
||||||
|
|
||||||
|
$api = vv_api_data();
|
||||||
|
$metrics = vv_api_node_metrics($api);
|
||||||
|
|
||||||
|
if (!$api) {
|
||||||
|
return ['available' => false, 'host_id' => $myId, 'hostname' => $name,
|
||||||
|
'no_api_key' => _vv_api_key_missing()];
|
||||||
|
}
|
||||||
|
|
||||||
|
$os = $api['info']['os'] ?? [];
|
||||||
|
$cpu = $api['info']['cpu'] ?? [];
|
||||||
|
$mem = $api['metrics']['memory'] ?? [];
|
||||||
|
|
||||||
|
$memPct = round((float)($mem['percentTotal'] ?? 0));
|
||||||
|
if ($memPct === 0) {
|
||||||
|
$tot = (float)($mem['total'] ?? 0); $avail = (float)($mem['available'] ?? 0);
|
||||||
|
$memPct = $tot > 0 ? (int)round(($tot - $avail) / $tot * 100) : 0;
|
||||||
|
}
|
||||||
|
$memTotalGb = isset($mem['total']) ? _vv_api_bytes_to_gb((float)$mem['total']) : 0;
|
||||||
|
|
||||||
|
$uptimeRaw = $os['uptime'] ?? '';
|
||||||
|
if (is_numeric($uptimeRaw)) {
|
||||||
|
$s = (int)$uptimeRaw;
|
||||||
|
$d = intdiv($s, 86400); $h = intdiv($s % 86400, 3600); $m = intdiv($s % 3600, 60);
|
||||||
|
$uptime = ($d ? "{$d}d " : '') . ($h ? "{$h}h " : '') . "{$m}m";
|
||||||
|
} else {
|
||||||
|
$s = 0; $uptime = $uptimeRaw ?: '—';
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_merge([
|
||||||
|
'available' => true,
|
||||||
|
'host_id' => $myId,
|
||||||
|
'hostname' => $os['hostname'] ?? $name,
|
||||||
|
'version' => $os['release'] ?? '',
|
||||||
|
'uptime' => $uptime,
|
||||||
|
'uptime_sec' => $s,
|
||||||
|
'cpu_load' => $metrics['cpu_pct'] ?? 0,
|
||||||
|
'cpu_threads' => (int)($cpu['threads'] ?? 0),
|
||||||
|
'mem_total_gb' => $memTotalGb,
|
||||||
|
'mem_used_pct' => $memPct,
|
||||||
|
'array_state' => $api['array']['state'] ?? 'UNKNOWN',
|
||||||
|
], $metrics);
|
||||||
|
}
|
||||||
|
|
||||||
// ── Confirmed schema (Unraid 7.3, introspected 2026-05-31) ───────────────────
|
// ── Confirmed schema (Unraid 7.3, introspected 2026-05-31) ───────────────────
|
||||||
// Adding a new host: add HOSTn="hostname" to master.conf and HOSTn_UNRAID_API_KEY
|
// Adding a new host: add HOSTn="hostname" to master.conf and HOSTn_UNRAID_API_KEY
|
||||||
// to hostn.conf, then run Deployment/deploy.sh. No schema work needed.
|
// to hostn.conf, then run Deployment/deploy.sh. No schema work needed.
|
||||||
|
|||||||
@@ -81,38 +81,56 @@ for host_var in HOST1 HOST2 HOST3 HOST4 HOST5 HOST6 HOST7 HOST8; do
|
|||||||
fi
|
fi
|
||||||
log " $host_var: resolved $hostname → $REMOTE_IP"
|
log " $host_var: resolved $hostname → $REMOTE_IP"
|
||||||
|
|
||||||
# SSH and call vv_arrs_local_node() on the remote
|
# Single SSH connection — fetch arrs + monitor stats together
|
||||||
RESULT=$(ssh -i "$SSH_KEY" \
|
RESULT=$(ssh -i "$SSH_KEY" \
|
||||||
-o ConnectTimeout=10 \
|
-o ConnectTimeout=10 \
|
||||||
-o StrictHostKeyChecking=no \
|
-o StrictHostKeyChecking=no \
|
||||||
-o BatchMode=yes \
|
-o BatchMode=yes \
|
||||||
"root@${REMOTE_IP}" \
|
"root@${REMOTE_IP}" \
|
||||||
"php -r \"require_once '/usr/local/emhttp/plugins/varaverk/include/arrs.php'; echo json_encode(vv_arrs_local_node());\"" \
|
"php -r \"
|
||||||
2>/dev/null)
|
require_once '/usr/local/emhttp/plugins/varaverk/include/arrs.php';
|
||||||
|
require_once '/usr/local/emhttp/plugins/varaverk/include/unraid_api.php';
|
||||||
|
echo json_encode([
|
||||||
|
'arrs' => vv_arrs_local_node(),
|
||||||
|
'monitor' => vv_local_host_stats(),
|
||||||
|
]);
|
||||||
|
\"" 2>/dev/null)
|
||||||
|
|
||||||
if [[ -z "$RESULT" ]]; then
|
if [[ -z "$RESULT" ]]; then
|
||||||
warn " $host_var: empty response from SSH — skipping"
|
warn " $host_var: empty SSH response — skipping"
|
||||||
(( FETCH_FAIL++ ))
|
(( FETCH_FAIL++ ))
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Validate JSON
|
# Validate combined JSON
|
||||||
if ! echo "$RESULT" | php -r "
|
if ! echo "$RESULT" | php -r "
|
||||||
\$d = json_decode(file_get_contents('php://stdin'), true);
|
\$d = json_decode(file_get_contents('php://stdin'), true);
|
||||||
exit(!is_array(\$d) || !isset(\$d['arrs']) ? 1 : 0);
|
exit(!is_array(\$d) || !isset(\$d['arrs'], \$d['monitor']) ? 1 : 0);
|
||||||
" 2>/dev/null; then
|
" 2>/dev/null; then
|
||||||
warn " $host_var: invalid or unexpected JSON — skipping"
|
warn " $host_var: invalid JSON — skipping"
|
||||||
log " Response: ${RESULT:0:200}"
|
log " Response: ${RESULT:0:200}"
|
||||||
(( FETCH_FAIL++ ))
|
(( FETCH_FAIL++ ))
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "$RESULT" > "$cache_file"
|
# Save arr cache
|
||||||
|
echo "$RESULT" | php -r "
|
||||||
|
\$d = json_decode(file_get_contents('php://stdin'), true);
|
||||||
|
file_put_contents('$cache_file', json_encode(\$d['arrs']));
|
||||||
|
" 2>/dev/null
|
||||||
|
|
||||||
|
# Save monitor cache
|
||||||
|
MONITOR_CACHE="/tmp/vv_cache/monitor_remote_${host_id}.json"
|
||||||
|
echo "$RESULT" | php -r "
|
||||||
|
\$d = json_decode(file_get_contents('php://stdin'), true);
|
||||||
|
file_put_contents('$MONITOR_CACHE', json_encode(\$d['monitor']));
|
||||||
|
" 2>/dev/null
|
||||||
|
|
||||||
CACHED_TYPES=$(echo "$RESULT" | php -r "
|
CACHED_TYPES=$(echo "$RESULT" | php -r "
|
||||||
\$d = json_decode(file_get_contents('php://stdin'), true);
|
\$d = json_decode(file_get_contents('php://stdin'), true);
|
||||||
echo implode(', ', array_column(\$d['arrs'] ?? [], 'type'));
|
echo implode(', ', array_column(\$d['arrs']['arrs'] ?? [], 'type'));
|
||||||
" 2>/dev/null)
|
" 2>/dev/null)
|
||||||
echo " $host_var: cached ✅ — ${CACHED_TYPES:-no arrs}"
|
echo " $host_var: arrs [${CACHED_TYPES:-none}] + monitor stats cached ✅"
|
||||||
(( FETCH_OK++ ))
|
(( FETCH_OK++ ))
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user