Compare commits

...
2 Commits
Author SHA1 Message Date
Gmer4Lfe 7e4db7b504 Fix stale plugin docs and dead links
- unraid_api.php comment still told you to run Deployment/deploy.sh,
  deleted a while back
- VaraverkSettings.page linked to a CHANGELOG.md that doesn't exist
  anywhere in the repo
- Manual-Plugin.md / README-Plugin.md described manually heredoc-ing the
  .plg locally and a .txz-based install that isn't wired up — rewritten
  to describe the actual install flow (raw .plg URL via Plugins ->
  Install Plugin), with plugin_setup.sh's dev-symlink role called out
  separately from that install path
2026-07-04 23:00:57 -04:00
Gmer4Lfe f7fa75fdfb Fix dead/incorrect vars in Plugin/ found during full codebase audit
- WEBGUI_PHP_WAIT was referenced by webgui_watchdog.sh but never defined
  in master.conf, always silently falling back to a hardcoded default
- arrs.php/confform.php still pointed at Media/ for arr cleanup/discovery
  scripts moved to Arrs_Stack/ in b4bc926 — broke the Arrs page's stats
  and the per-script settings editor for those scripts
- docker_folders.php read directly from the optional folder.view3 plugin's
  file instead of Varaverk's own docker_folders.json (the primary store
  since the Docker tab got its own config) — left the Monitor page's
  Docker Folders widget empty on any host without folder.view3 installed
- vv_wd_remote_data() read remote watchdog state files from hardcoded
  /tmp or /boot/config paths instead of the remote's actual STATE_DIR
  (which resolves dynamically and can differ under flash mode) — remote
  node's Watchdog panel was always empty; same wrong path also used for
  two local reads (system_watchdog_oom.db, watchdog_appdata_growth.db)
- rsync.php referenced a {HOST}_MONTHLY_SYNC_SHARES conf var that never
  existed (monthly_maintenance.sh has no rsync section) — nulled out to
  match the existing pattern used for the fallback window
- vv_arr_node_names() did a pointless identity array_map
- vv_dk_webui() had its own duplicate local-IP resolution instead of
  using vv_local_ip(), despite config.php's comment claiming that exact
  duplication was already consolidated
2026-07-04 23:00:26 -04:00
13 changed files with 97 additions and 88 deletions
+1
View File
@@ -948,6 +948,7 @@
WEBGUI_URL="http://localhost" WEBGUI_URL="http://localhost"
WEBGUI_TIMEOUT=5 # seconds before curl gives up on WebGUI check WEBGUI_TIMEOUT=5 # seconds before curl gives up on WebGUI check
WEBGUI_NGINX_WAIT=15 # seconds after nginx restart before rechecking WEBGUI_NGINX_WAIT=15 # seconds after nginx restart before rechecking
WEBGUI_PHP_WAIT=10 # seconds after php-fpm restart before rechecking
WEBGUI_EMHTTP_WAIT=30 # seconds after emhttp restart before rechecking WEBGUI_EMHTTP_WAIT=30 # seconds after emhttp restart before rechecking
# ============================================================================================== # ==============================================================================================
+1
View File
@@ -943,6 +943,7 @@
WEBGUI_URL="http://localhost" WEBGUI_URL="http://localhost"
WEBGUI_TIMEOUT=5 # seconds before curl gives up on WebGUI check WEBGUI_TIMEOUT=5 # seconds before curl gives up on WebGUI check
WEBGUI_NGINX_WAIT=15 # seconds after nginx restart before rechecking WEBGUI_NGINX_WAIT=15 # seconds after nginx restart before rechecking
WEBGUI_PHP_WAIT=10 # seconds after php-fpm restart before rechecking
WEBGUI_EMHTTP_WAIT=30 # seconds after emhttp restart before rechecking WEBGUI_EMHTTP_WAIT=30 # seconds after emhttp restart before rechecking
# ============================================================================================== # ==============================================================================================
+49 -40
View File
@@ -9,26 +9,20 @@ For folder overview see `README-Plugin.md`. For web app logic see the headers in
## ━━━ FIRST-TIME INSTALL ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ## ━━━ FIRST-TIME INSTALL ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
### Prerequisites Not yet published to Community Applications — this is a niche, self-hosted install for now.
- Repo cloned onto the target Unraid server ### Install via the Unraid UI (the actual install path)
- `/boot/config/plugins/varaverk/varaverk.plg` exists on flash (see PLG SETUP below)
### Steps **Plugins → Install Plugin → Enter URL of remote plugin file**, paste the raw `.plg` URL:
```bash - Your own servers (Gitea): `https://git.gmer4lfe.com/FailedProxy/Varaverk/raw/branch/main/Plugin/varaverk.plg`
cd Plugin/ - Public/anyone else (GitHub): `https://raw.githubusercontent.com/FailedProxy/Varaverk/main/Plugin/varaverk.plg`
./plugin_setup.sh
```
This creates: Unraid downloads the `.plg`, saves it to `/boot/config/plugins/varaverk.plg` itself
(nothing to copy by hand), then runs its `<FILE>` steps: clones the repo onto flash
``` (Gitea → Tailscale peer → `GITEA_DOMAIN` → GitHub fallback chain — same install script
/usr/local/emhttp/plugins/varaverk → Plugin/unraid/ (symlink) either way, so both URLs above end up in the same place), then symlinks the web files.
``` See `varaverk.plg`'s inline comments for the exact clone/fallback logic.
Changes to any file under `Plugin/unraid/` take effect immediately in the browser —
no restart, no reinstall.
### Verify ### Verify
@@ -42,25 +36,13 @@ Go to **Settings → Other Settings** — a Varaverk tile should also appear the
The `.plg` file registers Varaverk with Unraid's plugin system. It enables the cron The `.plg` file registers Varaverk with Unraid's plugin system. It enables the cron
mechanism (`update_cron`) and makes the plugin appear on the **Plugins** management page. mechanism (`update_cron`) and makes the plugin appear on the **Plugins** management page.
Create it once on flash — it persists across reboots: `Plugin/varaverk.plg` is tracked in the repo — it's a real plugin descriptor (version,
GitHub links, changelog) maintained by `build.sh`, not hand-authored. Normally you never
touch flash directly — installing via the URL above (or the update button on the Plugins
page, once installed) handles placing/refreshing `/boot/config/plugins/varaverk.plg` for you.
```bash `plugin_setup.sh` is a separate, optional dev convenience — see below — not part of the
mkdir -p /boot/config/plugins/varaverk install path above.
cat > /boot/config/plugins/varaverk.plg <<'EOF'
<?xml version='1.0' standalone='yes'?>
<!DOCTYPE PLUGIN [
<!ENTITY name "varaverk">
<!ENTITY author "gmer4lfe">
<!ENTITY version "2026.05.28">
]>
<PLUGIN name="&name;" author="&author;" version="&version;" launch="varaverk/monitor" icon="/plugins/varaverk/icons/varaverk.png">
</PLUGIN>
EOF
```
The `.plg` has no packages and no remote URLs — it is local-only and is not published
to Community Applications.
**Cron flow on every boot:** **Cron flow on every boot:**
1. `event/disks_mounted/rebuild_cron` fires 1. `event/disks_mounted/rebuild_cron` fires
@@ -71,6 +53,24 @@ to Community Applications.
--- ---
## ━━━ DEV CONVENIENCE: plugin_setup.sh ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Not part of the install path above — a manual, optional tool for pointing the running
web server directly at an arbitrary repo clone (e.g. a dev checkout that isn't at
`/boot/config/plugins/varaverk`), bypassing the fixed-path symlink the `.plg` recreates
every boot.
```bash
cd Plugin/
./plugin_setup.sh
```
This creates `/usr/local/emhttp/plugins/varaverk → Plugin/unraid/` (or `Plugin/<os>/`
for other platforms) pointing at wherever this repo currently lives, so edits show up
in the browser instantly. Re-run it any time the repo moves — see REPO MOVE PROCEDURE below.
---
## ━━━ SCRIPTS DIRECTORY SETTING ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ## ━━━ SCRIPTS DIRECTORY SETTING ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
`SCRIPTS_DIR` tells the plugin where to find the Configurations directory and all `SCRIPTS_DIR` tells the plugin where to find the Configurations directory and all
@@ -104,25 +104,34 @@ CUSTOM_SCRIPTS_DIR="/boot/config/plugins/user.scripts/Varaverk/Scripts"
## ━━━ REPO MOVE PROCEDURE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ## ━━━ REPO MOVE PROCEDURE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
If the repo is cloned to a new path: If a dev checkout using `plugin_setup.sh` (see above) is moved to a new path:
1. Re-run `plugin_setup.sh` — removes the stale symlink and creates a new one pointing at the new path 1. Re-run `plugin_setup.sh` — removes the stale symlink and creates a new one pointing at the new path
2. Update `SCRIPTS_DIR` in Settings → Other Settings → Varaverk (or edit `varaverk.cfg` directly on flash) 2. Update `SCRIPTS_DIR` in Settings → Other Settings → Varaverk (or edit `varaverk.cfg` directly on flash)
The `.plg` on flash does not need to change — it has no path references. The `.plg` on flash does not need to change — it has no path references.
This doesn't apply to a normal install (via the raw `.plg` URL) — that always lives at
the fixed path `/boot/config/plugins/varaverk`, there's no separate location to move.
--- ---
## ━━━ UPDATING THE PLUGIN VERSION ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ## ━━━ UPDATING THE PLUGIN VERSION ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
The version in `/boot/config/plugins/varaverk.plg` is cosmetic for a local plugin — `build.sh` rewrites the `version` and `sha256` entities in `Plugin/varaverk.plg` to match
Unraid does not check it against anything remote. Update it when you want the Plugins each release build — don't hand-edit them. The `sha256`/packaged `.txz` aren't currently
management page to reflect when the plugin was last changed: consumed by anything (see the CHANGES entry in `varaverk.plg` — install is git-clone +
symlink, not package-based), so today this is mostly cosmetic version tracking:
```xml ```bash
<!ENTITY version "2026.05.28"> cd Plugin/
./build.sh # today's date as version
./build.sh 2026.09.01 # explicit version
``` ```
Commit and push. The version shown on the Plugins page updates next time Unraid
re-fetches the `.plg` (the Plugins page's Update action, or a fresh install).
--- ---
## ━━━ ADDING A NEW OS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ## ━━━ ADDING A NEW OS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+1 -1
View File
@@ -120,4 +120,4 @@ No other files need changing.
| `event/disks_mounted/rebuild_cron` | Fires on every boot — copies `.plg`, rebuilds cron | | `event/disks_mounted/rebuild_cron` | Fires on every boot — copies `.plg`, rebuilds cron |
| `event/disks_mounted/array_start_jobs` | Fires when array starts | | `event/disks_mounted/array_start_jobs` | Fires when array starts |
| `event/disks_unmounting/array_stop_jobs` | Fires when array stops | | `event/disks_unmounting/array_stop_jobs` | Fires when array stops |
| `/boot/config/plugins/varaverk.plg` | Registers the plugin with Unraid's plugin system (lives on flash, not in repo) | | `Plugin/varaverk.plg` | Registers the plugin with Unraid's plugin system — tracked in-repo; installed via its raw URL through Plugins → Install Plugin (see Manual-Plugin.md), which Unraid saves to `/boot/config/plugins/varaverk.plg` itself |
-5
View File
@@ -30,9 +30,4 @@ _(Scripts directory)_:
style="color:#555;text-decoration:none;"> style="color:#555;text-decoration:none;">
Issues Issues
</a> </a>
&nbsp;·&nbsp;
<a href="https://github.com/FailedProxy/Varaverk/blob/main/CHANGELOG.md" target="_blank"
style="color:#555;text-decoration:none;">
Changelog
</a>
</div> </div>
@@ -123,7 +123,7 @@ if [[ "$SHOW_STATUS" == true ]]; then
echo "━━━━━ $ICON_SUMMARY WEBGUI WATCHDOG STATUS ━━━━━" echo "━━━━━ $ICON_SUMMARY WEBGUI WATCHDOG STATUS ━━━━━"
echo "$ICON_HOST Identity: $MY_ID ($LOCAL_SERVER_NAME)" echo "$ICON_HOST Identity: $MY_ID ($LOCAL_SERVER_NAME)"
echo "$ICON_WEBGUI URL: $WEBGUI_URL" echo "$ICON_WEBGUI URL: $WEBGUI_URL"
echo "$ICON_WEBGUI Timeouts: curl=${WEBGUI_TIMEOUT}s nginx=${WEBGUI_NGINX_WAIT}s php=${WEBGUI_PHP_WAIT:-10}s emhttp=${WEBGUI_EMHTTP_WAIT}s" echo "$ICON_WEBGUI Timeouts: curl=${WEBGUI_TIMEOUT}s nginx=${WEBGUI_NGINX_WAIT}s php=${WEBGUI_PHP_WAIT}s emhttp=${WEBGUI_EMHTTP_WAIT}s"
echo "" echo ""
if curl -sf --max-time "$WEBGUI_TIMEOUT" "$WEBGUI_URL" >/dev/null 2>&1; then if curl -sf --max-time "$WEBGUI_TIMEOUT" "$WEBGUI_URL" >/dev/null 2>&1; then
@@ -227,8 +227,8 @@ if [[ "$RECOVERY_OK" == false ]]; then
error "php-fpm restart command failed" error "php-fpm restart command failed"
fi fi
log "Waiting ${WEBGUI_PHP_WAIT:-10}s for php-fpm to recover..." log "Waiting ${WEBGUI_PHP_WAIT}s for php-fpm to recover..."
sleep "${WEBGUI_PHP_WAIT:-10}" sleep "$WEBGUI_PHP_WAIT"
if check_webgui; then if check_webgui; then
RECOVERY_ACTION="php-fpm restart" RECOVERY_ACTION="php-fpm restart"
+2 -1
View File
@@ -83,7 +83,8 @@ $winArrayDefs = [
'intermediate' => ['INTERMEDIATE_MAINTENANCE_SCRIPTS', "{$myId}_INTERMEDIATE_SYNC_SHARES"], 'intermediate' => ['INTERMEDIATE_MAINTENANCE_SCRIPTS', "{$myId}_INTERMEDIATE_SYNC_SHARES"],
'daily' => ['DAILY_MAINTENANCE_SCRIPTS', "{$myId}_DAILY_SYNC_SHARES"], 'daily' => ['DAILY_MAINTENANCE_SCRIPTS', "{$myId}_DAILY_SYNC_SHARES"],
'weekly' => ['WEEKLY_MAINTENANCE_SCRIPTS', "{$myId}_WEEKLY_SYNC_SHARES"], 'weekly' => ['WEEKLY_MAINTENANCE_SCRIPTS', "{$myId}_WEEKLY_SYNC_SHARES"],
'monthly' => ['MONTHLY_MAINTENANCE_SCRIPTS', "{$myId}_MONTHLY_SYNC_SHARES"], // monthly_maintenance.sh has no rsync section (ZFS scrub/SMART tests only) — no shares var exists.
'monthly' => ['MONTHLY_MAINTENANCE_SCRIPTS', null],
'fallback' => [null, null], 'fallback' => [null, null],
]; ];
$winArrays = []; $winArrays = [];
+9 -9
View File
@@ -14,7 +14,7 @@ function vv_arr_known_hosts(): array {
} }
function vv_arr_node_names(): array { function vv_arr_node_names(): array {
return array_map(fn($name) => $name, vv_arr_known_hosts()); return vv_arr_known_hosts();
} }
// ── Discovery ───────────────────────────────────────────────────────────────── // ── Discovery ─────────────────────────────────────────────────────────────────
@@ -123,9 +123,9 @@ function vv_fetch_arr_live(array $arr): array {
// ── Log stats ───────────────────────────────────────────────────────────────── // ── Log stats ─────────────────────────────────────────────────────────────────
function vv_arr_cleanup_stats(string $type): array { function vv_arr_cleanup_stats(string $type): array {
$slugs = ['sonarr' => 'Media/sonarr_cleanup', $slugs = ['sonarr' => 'Arrs_Stack/sonarr_cleanup',
'radarr' => 'Media/radarr_cleanup', 'radarr' => 'Arrs_Stack/radarr_cleanup',
'lidarr' => 'Media/lidarr_cleanup']; 'lidarr' => 'Arrs_Stack/lidarr_cleanup'];
$base = LOG_DIR . '/' . ($slugs[$type] ?? ''); $base = LOG_DIR . '/' . ($slugs[$type] ?? '');
$out = ['last_run' => null, 'end' => null, 'status' => null, $out = ['last_run' => null, 'end' => null, 'status' => null,
'tracked' => null, 'total' => null, 'tracked' => null, 'total' => null,
@@ -181,9 +181,9 @@ function vv_arr_cleanup_stats(string $type): array {
} }
function vv_arr_discovery_stats(string $type): array { function vv_arr_discovery_stats(string $type): array {
$slugs = ['sonarr' => 'Media/playback_aware_sonarr_discovery', $slugs = ['sonarr' => 'Arrs_Stack/playback_aware_sonarr_discovery',
'radarr' => 'Media/playback_aware_radarr_discovery', 'radarr' => 'Arrs_Stack/playback_aware_radarr_discovery',
'lidarr' => 'Media/playback_aware_lidarr_discovery']; 'lidarr' => 'Arrs_Stack/playback_aware_lidarr_discovery'];
$base = LOG_DIR . '/' . ($slugs[$type] ?? ''); $base = LOG_DIR . '/' . ($slugs[$type] ?? '');
$out = ['last_run' => null, 'status' => null, 'added' => null]; $out = ['last_run' => null, 'status' => null, 'added' => null];
@@ -225,7 +225,7 @@ function vv_arr_discovery_stats(string $type): array {
} }
function vv_arr_sync_stats(): array { function vv_arr_sync_stats(): array {
$base = LOG_DIR . '/Media/arr_sync'; $base = LOG_DIR . '/Arrs_Stack/arr_sync';
$out = ['last_run' => null, 'status' => null, 'added' => null, $out = ['last_run' => null, 'status' => null, 'added' => null,
'nodes' => null, 'blocklist_count' => null]; 'nodes' => null, 'blocklist_count' => null];
@@ -255,7 +255,7 @@ function vv_arr_sync_stats(): array {
} }
function vv_arr_recovery_stats(): array { function vv_arr_recovery_stats(): array {
$base = LOG_DIR . '/Media/arrs_failed_stalled_recovery'; $base = LOG_DIR . '/Arrs_Stack/arrs_failed_stalled_recovery';
$out = ['last_run' => null, 'status' => null, 'fixed' => 0, 'searched' => 0]; $out = ['last_run' => null, 'status' => null, 'fixed' => 0, 'searched' => 0];
$jf = $base . '.json'; $jf = $base . '.json';
+5 -4
View File
@@ -28,10 +28,11 @@ const VV_SCRIPT_CONF_SECTIONS = [
// Media // Media
'Media/media_cleaner.sh' => ['Media Cleaner'], 'Media/media_cleaner.sh' => ['Media Cleaner'],
'Media/media_shares_permissions.sh' => ['Media Permissions'], 'Media/media_shares_permissions.sh' => ['Media Permissions'],
'Media/arrs_failed_stalled_recovery.sh' => ['Arr Failed/Stalled Recovery'], // Arrs Stack
'Media/radarr_cleanup.sh' => ['Arr Cleanup'], 'Arrs_Stack/arrs_failed_stalled_recovery.sh' => ['Arr Failed/Stalled Recovery'],
'Media/lidarr_cleanup.sh' => ['Arr Cleanup'], 'Arrs_Stack/radarr_cleanup.sh' => ['Arr Cleanup'],
'Media/sonarr_cleanup.sh' => ['Arr Cleanup'], 'Arrs_Stack/lidarr_cleanup.sh' => ['Arr Cleanup'],
'Arrs_Stack/sonarr_cleanup.sh' => ['Arr Cleanup'],
// Monitors // Monitors
'Monitors/cert_monitor.sh' => ['Certificate Monitor'], 'Monitors/cert_monitor.sh' => ['Certificate Monitor'],
'Monitors/backup_verify.sh' => ['Backup Verify'], 'Monitors/backup_verify.sh' => ['Backup Verify'],
+1 -6
View File
@@ -97,12 +97,7 @@ function vv_dk_webui(string $name, array $portMap): string {
if (!preg_match('/<WebUI>(.*?)<\/WebUI>/s', $xml, $m)) return ''; if (!preg_match('/<WebUI>(.*?)<\/WebUI>/s', $xml, $m)) return '';
$url = trim($m[1]); $url = trim($m[1]);
if (!$url) return ''; if (!$url) return '';
static $localIp = null; $url = str_replace('[IP]', vv_local_ip(), $url);
if ($localIp === null) {
$localIp = trim(shell_exec("ip route get 8.8.8.8 2>/dev/null | awk '/src/{for(i=1;i<=NF;i++)if(\$i==\"src\")print \$(i+1)}'") ?: '');
if (!$localIp) $localIp = gethostbyname(gethostname());
}
$url = str_replace('[IP]', $localIp, $url);
$url = preg_replace_callback('/\[PORT:(\d+)\]/', fn($pm) => $portMap[$pm[1]] ?? $pm[1], $url); $url = preg_replace_callback('/\[PORT:(\d+)\]/', fn($pm) => $portMap[$pm[1]] ?? $pm[1], $url);
return $url; return $url;
} }
+5 -4
View File
@@ -1,5 +1,6 @@
<?php <?php
require_once __DIR__ . '/config.php'; require_once __DIR__ . '/config.php';
require_once __DIR__ . '/docker.php';
function vv_container_webui(string $name, array $portMap): string { function vv_container_webui(string $name, array $portMap): string {
$template = '/boot/config/plugins/dockerMan/templates-user/my-' . $name . '.xml'; $template = '/boot/config/plugins/dockerMan/templates-user/my-' . $name . '.xml';
@@ -22,10 +23,10 @@ function vv_container_webui(string $name, array $portMap): string {
} }
function vv_get_docker_folders(): array { function vv_get_docker_folders(): array {
$folderFile = '/boot/config/plugins/folder.view3/docker.json'; // Varaverk's own docker_folders.json is the primary store (see include/docker.php) —
$folderData = file_exists($folderFile) // reading folder.view3's mirror directly here left this widget empty on any host
? (json_decode(@file_get_contents($folderFile), true) ?: []) // without that optional third-party plugin installed.
: []; $folderData = vv_dk_read_json();
// One docker ps call: names, status, port mappings // One docker ps call: names, status, port mappings
$raw = shell_exec("docker ps -a --format '{{.Names}}\t{{.Status}}\t{{.Ports}}' 2>/dev/null") ?? ''; $raw = shell_exec("docker ps -a --format '{{.Names}}\t{{.Status}}\t{{.Ports}}' 2>/dev/null") ?? '';
+1 -1
View File
@@ -247,7 +247,7 @@ function vv_local_host_stats(): array {
// ── 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 push and pull as usual. No schema work needed.
// //
// If a future Unraid version renames a field, the affected function falls back // If a future Unraid version renames a field, the affected function falls back
// to local reads and the api banner lists the fallback — fix by updating the GQL. // to local reads and the api banner lists the fallback — fix by updating the GQL.
+19 -14
View File
@@ -83,7 +83,7 @@ function vv_wd_local_system(): array {
$mem = vv_memory_breakdown(); $mem = vv_memory_breakdown();
$loadRaw = @file_get_contents('/proc/loadavg') ?: '0'; $loadRaw = @file_get_contents('/proc/loadavg') ?: '0';
$daemonOk = (trim(shell_exec('docker info >/dev/null 2>&1; echo $?') ?: '1') === '0'); $daemonOk = (trim(shell_exec('docker info >/dev/null 2>&1; echo $?') ?: '1') === '0');
$oomCount = (int)trim(@file_get_contents('/tmp/system_watchdog_oom.db') ?: '0'); $oomCount = (int)trim(@file_get_contents(STATE_DIR . '/system_watchdog_oom.db') ?: '0');
$cores = (int)($sys['cpu_cores'] ?: (int)(trim(shell_exec('nproc 2>/dev/null') ?: '1'))); $cores = (int)($sys['cpu_cores'] ?: (int)(trim(shell_exec('nproc 2>/dev/null') ?: '1')));
return [ return [
'mem_total' => (int)($mem['total_kb'] * 1024), 'mem_total' => (int)($mem['total_kb'] * 1024),
@@ -155,7 +155,7 @@ function vv_wd_local_states(string $restartLogPath): array {
} }
// Growth baseline info (container count + age in seconds) // Growth baseline info (container count + age in seconds)
$growthFile = '/tmp/watchdog_appdata_growth.db'; $growthFile = STATE_DIR . '/watchdog_appdata_growth.db';
$baselineCount = file_exists($growthFile) ? max(0, count(file($growthFile)) - 0) : 0; $baselineCount = file_exists($growthFile) ? max(0, count(file($growthFile)) - 0) : 0;
$baselineAgeSec = file_exists($growthFile) ? time() - (int)filemtime($growthFile) : null; $baselineAgeSec = file_exists($growthFile) ? time() - (int)filemtime($growthFile) : null;
@@ -187,23 +187,28 @@ function vv_wd_remote_data(string $ip, string $sshKey, string $restartLogPath):
// /proc/meminfo is passed as a raw section (not awk-parsed) to avoid quoting // /proc/meminfo is passed as a raw section (not awk-parsed) to avoid quoting
// fragility — escapeshellarg() single-quotes the whole command so awk \$2 // fragility — escapeshellarg() single-quotes the whole command so awk \$2
// inside double-quotes is unreliable across Unraid builds. // inside double-quotes is unreliable across Unraid builds.
$cmd = "printf 'UPTIME:%s\nLOAD:%s\nCORES:%s\nDAEMON:%s\nOOM:%s\nBASELINECOUNT:%s\nBASELINEAGE:%s\n---MEMINFO---\n%s\n---RW---\n%s\n---DOCK---\n%s\n---SKIP---\n%s\n---SYS---\n%s\n---REBOOT---\n%s\n---RESTART---\n%s\n---STORAGE---\n%s\n---NETWORK---\n%s\n' " // State files live under the REMOTE's own SCRIPTS_DIR/State_Files (may differ
// from ours in flash mode) — resolve it once, same idiom as vv_remote_state_cmd().
$restartLogName = basename($restartLogPath);
$cmd = 'sd=$(grep -m1 SCRIPTS_DIR= /boot/config/plugins/varaverk/varaverk.cfg 2>/dev/null'
. ' | cut -d\'"\' -f2); sd="${sd:-/boot/config/plugins/varaverk}"; '
. "printf 'UPTIME:%s\nLOAD:%s\nCORES:%s\nDAEMON:%s\nOOM:%s\nBASELINECOUNT:%s\nBASELINEAGE:%s\n---MEMINFO---\n%s\n---RW---\n%s\n---DOCK---\n%s\n---SKIP---\n%s\n---SYS---\n%s\n---REBOOT---\n%s\n---RESTART---\n%s\n---STORAGE---\n%s\n---NETWORK---\n%s\n' "
. '"$(cat /proc/uptime|cut -d\" \" -f1)" ' . '"$(cat /proc/uptime|cut -d\" \" -f1)" '
. '"$(cat /proc/loadavg|cut -d\" \" -f1)" ' . '"$(cat /proc/loadavg|cut -d\" \" -f1)" '
. '"$(nproc)" ' . '"$(nproc)" '
. '"$(docker info >/dev/null 2>&1 && echo ok || echo err)" ' . '"$(docker info >/dev/null 2>&1 && echo ok || echo err)" '
. '"$(cat /tmp/system_watchdog_oom.db 2>/dev/null||echo 0)" ' . '"$(cat "$sd/State_Files/system_watchdog_oom.db" 2>/dev/null||echo 0)" '
. '"$(wc -l < /tmp/watchdog_appdata_growth.db 2>/dev/null||echo 0)" ' . '"$(wc -l < "$sd/State_Files/watchdog_appdata_growth.db" 2>/dev/null||echo 0)" '
. '"$(stat -c %Y /tmp/watchdog_appdata_growth.db 2>/dev/null||echo 0)" ' . '"$(stat -c %Y "$sd/State_Files/watchdog_appdata_growth.db" 2>/dev/null||echo 0)" '
. '"$(cat /proc/meminfo 2>/dev/null)" ' . '"$(cat /proc/meminfo 2>/dev/null)" '
. '"$(cat /tmp/resource_watchdog_state.db 2>/dev/null)" ' . '"$(cat "$sd/State_Files/resource_watchdog_state.db" 2>/dev/null)" '
. '"$(cat /tmp/container_watchdog_state.db 2>/dev/null)" ' . '"$(cat "$sd/State_Files/container_watchdog_state.db" 2>/dev/null)" '
. '"$(cat /boot/config/system_watchdog_failed.db 2>/dev/null)" ' . '"$(cat "$sd/State_Files/docker_watchdog_failed.db" 2>/dev/null)" '
. '"$(cat /tmp/system_watchdog_state.db 2>/dev/null)" ' . '"$(cat "$sd/State_Files/system_watchdog_state.db" 2>/dev/null)" '
. '"$(cat /boot/config/system_watchdog_reboots.db 2>/dev/null)" ' . '"$(cat "$sd/State_Files/system_watchdog_reboots.db" 2>/dev/null)" '
. '"$(cat ' . escapeshellarg($restartLogPath) . ' 2>/dev/null)" ' . '"$(cat "$sd/data/' . $restartLogName . '" 2>/dev/null)" '
. '"$(cat /tmp/storage_watchdog_state.db 2>/dev/null)" ' . '"$(cat "$sd/State_Files/storage_watchdog_state.db" 2>/dev/null)" '
. '"$(cat /tmp/network_watchdog_state.db 2>/dev/null)"'; . '"$(cat "$sd/State_Files/network_watchdog_state.db" 2>/dev/null)"';
$out = vv_pt_ssh($ip, $sshKey, $cmd, 8); $out = vv_pt_ssh($ip, $sshKey, $cmd, 8);
if (!$out) return null; if (!$out) return null;