Commit Graph
60 Commits
Author SHA1 Message Date
Gmer4Lfe 084220692f Add unambiguous prefix-match fallback for NetBIOS-truncated hostnames
Unraid truncates the Server Name to 15 chars. Depending on which form
ends up in master.conf's HOST* value (the truncated OS hostname, or a
longer name matching what Tailscale independently registered for that
peer), either host-identity detection or Tailscale IP resolution could
fail — hit live on HOST2 in both directions this session.

- common.sh detect_hosts(): was case-sensitive exact match only, with no
  fallback and an exit 1 on failure — meaning every orchestrator/watchdog/
  rsync script would hard-fail on a truncated-hostname host, not just the
  web UI. Now case-insensitive, with a prefix-match fallback when the
  local hostname is exactly 15 chars.
- common.sh resolve_tailscale_ip(): already did a bare regex prefix match
  with zero ambiguity handling (pre-existing risk: e.g. server1/server10
  could collide). Replaced with an explicit unambiguous-only check.
- config.php vv_detect_host() / vv_resolve_tailscale_ip(): same treatment,
  kept as close a mirror of the bash logic as PHP allows.

All fallbacks require an EXACT prefix match (never fuzzy/percentage
similarity — considered and rejected, since names like server1/server2/
server3 would be dangerously similar under any generic similarity metric)
and require exactly one candidate to qualify; ambiguous matches are
treated as no match rather than guessed. Verified live against HOST1/
HOST2 in both master.conf configurations (short and long HOST2 value).
2026-07-04 23:49:44 -04:00
Gmer4Lfe abfbaa7f47 Fix host identity detection for NetBIOS-truncated hostnames
Unraid truncates the Server Name to 15 chars (NetBIOS limit). HOST2's
real hostname is "unRAID-Jayred36" but master.conf's HOST2 (matching
what Tailscale shows for this peer, since resolve_tailscale_ip() keys
off the same value) is the untruncated "unRAID-Jayred365" — confirmed
live, Tailscale's own Self.HostName on that machine is truncated too.

vv_detect_host() did a strict case-insensitive match against the bare
`hostname -s` output with no tolerance for this, so it always returned
'unknown' on HOST2. That silently broke the first-run wizard (Varaverk.page
explicitly excludes 'unknown' from the "needs setup" check) even though
host2.conf never existed, plus vv_partner_state() and vv_fallback_active()
in monitor.php which independently reimplemented the same hostname
comparison instead of calling vv_detect_host().

Fix: vv_detect_host() falls back to a prefix match when the local hostname
is exactly 15 chars; vv_partner_state()/vv_fallback_active() now call
vv_detect_host() instead of duplicating the comparison. Verified live on
HOST2 — vv_detect_host() now returns 'host2', partner state correctly
flags HOST2 as is_me, and the wizard-trigger condition now evaluates true.
2026-07-04 23:28:54 -04:00
Gmer4Lfe 3d7b15d6bb Fix vv_push_master_conf() — remote command was expanding locally, not on the remote host
The readiness probe wrapped the remote command in raw double quotes with
manually backslash-escaped inner quotes. shell_exec() runs its command
through an extra local `sh -c` layer beyond the ssh invocation itself, and
because the remote command was double-quoted (not single-quoted/opaque),
that extra local layer expanded the $(...)/${...} substitutions using
HOST1's own environment before ssh ever sent anything to the remote host.
Confirmed live: the exact same command run directly (one shell layer)
returned the correct remote SCRIPTS_DIR; run through an extra sh -c layer
(matching shell_exec's real behavior) it silently evaluated everything
against HOST1's local varaverk.cfg instead, producing an empty probe result
every time — so every push silently reported "plugin not installed" even
though HOST2 was fully installed and reachable.

Fix: build the remote command as a plain string and escapeshellarg() it as
a whole, same pattern vv_pt_ssh() already used safely elsewhere. Verified
live — probe now returns HOST2's real SCRIPTS_DIR and the master.conf push
lands with a matching checksum on both hosts.
2026-07-04 23:19:42 -04:00
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
Gmer4Lfe 6fd22ae4ee Move Custom Scripts out of the repo and add an Import Script picker
Custom Scripts (the Scheduler page's inline editor) used to save into the
git-tracked Custom/ folder, so anything saved there would end up on GitHub.
They now live in /boot/config/plugins/user.scripts/Varaverk/Scripts, same
folder family as Unraid's own User Scripts plugin. Import Script lets you
browse the whole server and move an existing script in instead of only
creating new ones inline — always a move, never a copy, so no stray
duplicate is left where it came from.
2026-07-03 10:57:35 -04:00
Gmer4Lfe b314aa4aff fix monitor disk used space underreported for spun-down disks
Unraid API returns fsUsed=0 when a disk's filesystem is unmounted (spun
down). disks.ini keeps the last-known value in KB even after spindown —
use it as fallback when isSpinning=false and fsUsed=0. Also remove the
mounted-only guard in the ini fallback path (vv_disk_entry) for the same
reason. Stale comments in user_script_plug-in.sh and partnership_manager.sh
also cleaned up.
2026-06-27 23:08:51 -04:00
Gmer4Lfe bf3e7cc2c4 Storage-mode awareness pass + doc update for System_Essentials through Partnership
All state/data file paths in scripts and PHP now resolve via STATE_DIR / DATA_DIR /
PERSISTENT_CONF_CACHE instead of hardcoded /boot/config/ or /tmp/ paths, so the
ecosystem works in both internal and appdata storage modes.

PHP layer (watchdog.php, partnership.php, fallback.php, monitor.php, snapshot.php,
config.php): all state reads switched to STATE_DIR constant; remote state reads use
the new vv_remote_state_cmd() helper which resolves the remote's SCRIPTS_DIR via
their varaverk.cfg before building the path.

conf_sync.sh: fixed SCRIPTS_ROOT → SCRIPTS_DIR bug on MY_CONF path; added
_remote_scripts_dir() to resolve partner's SCRIPTS_DIR before SCP pull.

fallback.php page: added controls card (PARTNERSHIP_ENABLED, FALLBACK_ENABLED,
FALLBACK_RSYNC_ENABLED toggles), status grid, and settings card.

README and Manual updated for System_Essentials, Watchdogs, Fallback, Rsync,
Media, Monitors, Orchestrators, Partnership: added new scripts (conf_sync,
conf_cache_save/restore, conf_cache_watchdog, play_state_sync, start_webhook_listener,
upgrade_webhook_handler), corrected all stale /boot/config/ state file paths to
$STATE_DIR/$DATA_DIR, noted webgui/php_fpm/mover/user_scripts scripts moved to
Plugin/unraid/System_Essentials, fixed start_webhook_listener.sh header (Node.js,
not PHP -S).
2026-06-19 19:32:39 -04:00
Gmer4Lfe 0564580605 Make PARTNERSHIP_ENABLED the authoritative gate for all cross-server operations
Adds require_partnership() to common.sh — exits cleanly when PARTNERSHIP_ENABLED=false.
Removes FALLBACK_PARTNERSHIP_REQUIRED toggle — partnership is now always required,
not optional. Cross-server scripts (rsync, conf sync, fallback, arr sync, play state,
backup verify) all call require_partnership after detect_hosts.
2026-06-19 18:27:41 -04:00
Gmer4Lfe 28d434b76c Propagate new fallback model to all remaining script references
All FALLBACK_${MY_ID}_COVERS_${REMOTE_ID}_TIER* references updated to
FALLBACK_${REMOTE_ID}_TIER* across fallback_test.sh, partnership_manager.sh,
docker_update.sh, mesh_monitor.sh, and monitor.php. mesh_monitor.sh drops
the inner covering-host loop — tier data now lives in the covered host's own
conf so no cross-host scan is needed. monitor.php reads from the covered
host's conf file rather than the local host's.
2026-06-19 17:49:26 -04:00
Gmer4Lfe b27b2d62f5 Flip fallback coverage model: each host defines its own recovery profile
Previously HOST1 defined what it would run for HOST2 (FALLBACK_HOST1_COVERS_HOST2_TIER*).
Now each host defines what it wants run when IT goes down (FALLBACK_HOST1_TIER*), and the
covering server reads the down host's conf via the RAM/persistent cache.

get_tier_containers() reads FALLBACK_${REMOTE_ID}_TIER* instead of
FALLBACK_${MY_ID}_COVERS_${REMOTE_ID}_TIER*. Tier data migrated to the correct host confs.
Writeback paths and delays were already REMOTE_ID-based — no change needed there.
2026-06-19 17:44:53 -04:00
Gmer4Lfe ad98d41041 Parity card: show correct operation label (rebuild vs check vs sync) from mdResyncAction 2026-06-19 11:19:15 -04:00
Gmer4Lfe f42ecc8464 Add docker actions, arr profile enforcer, monitor caching, and web file symlink
Web files now served via symlink to the git repo so git pull changes survive
reboots without rebuilding the txz. Also includes: docker pull/rebuild/restart
with live log streaming, arr_profile_enforcer for Sonarr/Radarr quality
profiles, monitor page cache fix (background writer now in cron), and
ARR_KIDS/SONARR/RADARR profile name vars in master.conf.
2026-06-19 11:09:40 -04:00
Gmer4Lfe 6153283de4 move conf templates and conf_populate to Deployment/; add rogue-prevention rules to CLAUDE.md 2026-06-14 13:18:08 -04:00
Gmer4Lfe 08be751d23 Show active HLS segment count in transcode card
Live TV and Direct Stream sessions never appear in the transcoding
session list but do write segments to the ramdisk. Card now shows
the active segment count so the ramdisk usage is explained.
2026-06-14 11:31:51 -04:00
Gmer4Lfe 420e13a746 Resolve bash variable references in vv_conf_vars()
PHP reads master.conf values like STATE_DIR="${SCRIPTS_DIR}/State_Files"
literally — the ${SCRIPTS_DIR} token is never expanded, so any PHP code
using the returned STATE_DIR value got an invalid path. Two-pass resolution:
SCRIPTS_DIR first (from PHP constant), then remaining ${VAR} tokens using
the now-resolved var set (covers DATA_DIR-based paths like ARR_SYNC_BLOCKLIST).
2026-06-14 01:46:51 -04:00
Gmer4Lfe 27bfc21cb0 Platform-agnostic refactor: eliminate OS-specific hardcodes from core scripts
All bash scripts are now platform-neutral. Unraid-specific paths, commands,
and service checks moved to Plugin/unraid/adapter.sh. Core scripts call
platform_*() functions exclusively — no direct OS paths in runtime logic.

New adapter functions: platform_storage_path, platform_webui_install_path,
platform_scripts_dir_probe_cmd, platform_setup_db_path, platform_storage_healthy,
platform_is_service_enabled, platform_get_temp_thresholds, platform_disk_states_path,
platform_rebuild_container, platform_push_conf, platform_push_setup_state,
platform_get_templates_dir, platform_send_os_notification.

Partnership services stack (Emby/Jellyfin/Seerr/SeerrFin) added as third
onboarding stack alongside auth and arr stacks.
2026-06-14 00:59:19 -04:00
Gmer4Lfe cac9d8e82f Fix Sonarr episode count — episodeFileCount is nested under statistics in v4 2026-06-06 18:24:31 -04:00
Gmer4Lfe dab8d62e95 Fix API key detection — name is 'Varaverk <hostname>', not 'Varaverk' 2026-06-06 18:09:37 -04:00
Gmer4Lfe a535319f1d API key button delegates to unraid_api_key_renew.sh — checks registry before creating 2026-06-06 18:02:37 -04:00
Gmer4Lfe bac0f7c535 Auth page: pure-PHP Authelia ACL parser, NPM-sourced certs tab, watchdog JS fixes, rsync settings layout
- Replace python3/PyYAML Authelia ACL parser with pure PHP (no deps available on Unraid)
- Cert tab now pulls live from NPM API instead of cert_monitor.sh — auto-discovers all managed certs sorted by urgency
- Watchdog page: add missing GB constant and _fmtBytes/_relTime functions that were causing silent render failure
- Rsync settings card: pin to far-right 3 columns (grid-column:6/-1), toggle grid narrowed to 2 columns
- Add CLAUDE.md project context file on /boot for session persistence across reboots
- claude_startup.sh: symlink CLAUDE.md into /root on array start
2026-06-06 15:39:34 -04:00
Gmer4Lfe 9c3ace95a7 Auth stack certs tab, arrs db fallbacks, cert monitor cache, conf parser fix
- Auth stack: fold cert monitor into Auth Stack page as fourth tab (Certs);
  remove standalone cert page and top-level tab
- cert_monitor.sh: write JSON status cache to State_Files/cert_status.json
  after each run; expose per-domain days/expiry via _CERT_DAYS/_CERT_EXPIRY globals
- api/cert.php: new — serves cached cert status; falls back to configured
  domains as UNKN when no cache exists; POST action=run triggers live check
- arrs db fallbacks: vv_arr_cleanup_stats/discovery_stats/recovery_stats now
  read from data/*.db files when log JSON files don't yet exist
- config.php vv_conf_vars(): unescape bash \$ → $ so passwords with dollar
  signs read correctly from conf files
- host1.conf: fill in HOST1_NPM_USER/PASS and HOST1_LLDAP_USER/PASS
- Partnership adapter pattern: Unraid-specific container logic extracted to
  Plugin/unraid/Partnership/; platform-agnostic structure stays in Partnership/
- First-run wizard: uniform multi-step flow for all hosts; HOST2 pull moved
  to checklist; auto SSH keygen and API key creation on save
- api/checklist.php: live setup checklist with pull_master action
- Fullscreen toggle: hide Unraid header/menu; state persists via localStorage
2026-06-05 23:17:30 -04:00
Gmer4Lfe f9fe13bdc1 fix: use STATE_DIR directly — TRANSCODE_STATE_FILE contains unexpanded bash var
vv_conf_vars() reads conf as text; TRANSCODE_STATE_FILE=$STATE_DIR/... is
returned as a literal string, not expanded. Build path from STATE_DIR directly.
2026-06-05 19:32:48 -04:00
Gmer4Lfe 415c260175 fix: transcode monitor reads STATE_DIR from conf instead of hardcoded /tmp
vv_transcode_sessions() was hardcoded to /tmp/transcode_state.db but master.conf
sets TRANSCODE_STATE_FILE=$STATE_DIR/transcode_state.db which resolves to
/boot/config/plugins/varaverk/State_Files/transcode_state.db. Page always showed
"ramdisk_setup.sh not yet run" despite state file being present and populated.
2026-06-05 19:29:31 -04:00
Gmer4Lfe a5936331c9 auth stack page, monitor cache fix, symlink install 2026-06-05 19:20:28 -04:00
Gmer4Lfe 0bcb773332 Cache: warm at array start, extend stale tolerance to 5 min, fix last uptime copy
- ARRAY_START_SCRIPTS: add api_cache_writer.sh so monitor/arrs cache is populated
  immediately on array start (/tmp is tmpfs — cleared on reboot, so first-boot
  load was hitting live API for up to 60 seconds until the cron fired)
- api/monitor.php + arrs.php: raise cache TTL from 90s to 300s — stale-but-instant
  beats a 6-second live API wait if the writer is momentarily behind
- include/unraid_api.php: replace last inline uptime formatter with vv_format_uptime()
2026-06-04 16:46:50 -04:00
Gmer4Lfe ce0b3fb74b PHP app layer: consolidate common functions, fix critical bugs, standardize patterns
Consolidations (config.php gains 5 shared utilities):
- vv_format_uptime() replaces 4 inline uptime-formatting blocks
- vv_parse_conf_scalar() replaces vv_arr_scalar/vv_wd_scalar/vv_fb_scalar/vv_media_conf_scalar
- vv_known_hosts() replaces vv_arr_known_hosts/vv_fb_known_hosts + inline parser in watchdog
- vv_parse_kv_db() replaces inline key=value parsing in snapshot and monitor
- vv_local_ip() replaces duplicate in docker_folders.php and inline in docker.php
All module-level function names kept as thin aliases so call sites unchanged.

Critical bug fixes:
- api/system.php: added require_once config.php and POST-only guard (no auth on shutdown)
- api/movescript.php + reorderarray.php: use vv_write_conf_raw (atomic) + vv_push_master_conf
- api/snapshot.php: share /tmp/vv_cpu_stat.json with vv_cpu_per_core() instead of own state file

Correctness:
- vv_cpu_per_core() and vv_network_stats(): atomic tmp+rename for state files (concurrent poll safety)
- ext_ip curl cache moved from /tmp/vv_ext_ip.cache to vv_cache_read/write (canonical cache dir)
- monitor_remote.php + board.php + snapshot.php: all use vv_cache_read/write instead of ad-hoc /tmp files

HTTP method guards added to write-only APIs that were missing them:
- api/scheduler.php, conf_toggle.php, flag_toggle.php
2026-06-04 16:44:16 -04:00
Gmer4Lfe a55a3afad5 Remote cache: extend to monitor stats; vv_local_host_stats(), 2h bg refresh covers monitor+arrs pages 2026-06-03 18:20:55 -04:00
Gmer4Lfe 2223cf80f7 Arrs: remote host cards via SSH cache, vv_arrs_local_node(), 2h refresh schedule 2026-06-03 18:16:56 -04:00
Gmer4Lfe 13ed584d73 arrs: move settings into vv_arrs_all() so cache writer includes them 2026-06-03 18:03:40 -04:00
Gmer4Lfe 0cb429222a Add storage mode migration: internal NVMe vs USB flash, Settings tab, fix hardcoded /boot/ paths 2026-06-03 17:40:35 -04:00
Gmer4Lfe 65075ed599 Add file-based API cache — monitor and arrs pages now serve from /tmp/vv_cache instead of making live HTTP calls on every page load 2026-06-03 16:15:35 -04:00
Gmer4Lfe de6fcc3997 Add Rsync page, upgrade monitor rsync card, partnership overhaul, API key periodic check, docker watchdog manual-stop detection 2026-06-03 15:58:50 -04:00
Gmer4Lfe 3e71c314d7 Add Rsync card to monitor page Row 3 (before GPU)
New span-1 card shows global RSYNC_ENABLED gate, per-window badges (C/D/I/W),
active profile names + elapsed time from lock files, and last-sync timestamp
per orchestrator window from script log files.

GPU shrunk from span 2 to span 1 to make room. Row 3 is now:
Rsync(1) | GPU(1) | Transcode(2) | Streams(4)
2026-06-01 21:10:44 -04:00
Gmer4LfeandClaude Sonnet 4.6 63b1f0a76c feat: cumulative pulled/pushed GB totals in pools and array card headers
disk_io now returns {tr, tw} cumulative GB alongside {r, w} rates.
A centered span in each card h3 shows ↓total ↑total (since last boot),
updating each poll. Helpers updated for the new object format.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 22:40:56 -04:00
Gmer4LfeandClaude Sonnet 4.6 212b61ce15 feat: live disk I/O rates on array and pools cards
Adds vv_disk_io_rates() — snapshots /proc/diskstats each poll and
computes per-device MB/s. Exposed as disk_io in the monitor API.

JS:
- Per-disk rows: ↓read ↑write inline next to disk name (green/amber, hidden when idle)
- Pool rows: aggregate pool I/O next to pool name
- Array header: total array I/O in the subtitle line

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 22:31:19 -04:00
Gmer4LfeandClaude Sonnet 4.6 55e817d234 ui: show last cleanup freed amounts on transcode Ramdisk/NVMe tags
Parses the last 'Ramdisk freed' and 'SSD freed' values from the transcode
management log and displays them as small ↓XMB annotations inside each tag.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 22:15:13 -04:00
Gmer4LfeandClaude Sonnet 4.6 89df1a98db ui: show resolution and codec counts in streams header
Adds height/codec fields to both Emby/Jellyfin and Plex session data,
then surfaces them as chip groups (· 2 4K  3 1080p · 4 H.264  2 HEVC)
in the streams card header alongside the existing device type bar.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 21:52:31 -04:00
Gmer4LfeandClaude Sonnet 4.6 b093cae70d schema: re-introspect Unraid API against 7.3
7.3 findings (all existing queries confirmed working — no breaking changes):
- ArrayParity/ArrayCache no longer exist as named types; everything is ArrayDisk
- InfoOs gained: kernel, arch, fqdn, build, codename, platform, serial, uefi
- InfoCpu gained: manufacturer, model, speed, speedmin/max, processors, socket, topology
- ArrayDisk gained: idx, numReads/Writes/Errors, warning/critical temps, color, fsType
- MemoryUtilization gained: free, active, buffcache, swapFree, percentSwapTotal

Changes:
- Add kernel to master GQL query (useful for display)
- Update schema comments to reflect 7.3 reality
- Remove ArrayParity/ArrayCache from api_test.php introspection (now null types)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 19:34:36 -04:00
Gmer4LfeandClaude Sonnet 4.6 fb0530deba Consolidate all paths to plugin flash dir, fix watchdog 7.3 triggers
- Move SCRIPTS_DIR/DATA_DIR/STATE_DIR from appdata to /boot/config/plugins/varaverk
- All state files now in STATE_DIR (no more /tmp or /boot/config root writes)
- Bootstrap: Gitea-first clone with GitHub fallback, no array dependency
- varaverk.cfg seeded with Gitea connection settings
- .gitignore: add State_Files/, varaverk.cfg, varaverk-*.txz
- Partnership/transcode/fallback scripts use STATE_DIR variables
- PHP config.php: DATA_DIR/STATE_DIR constants, VV_SETUP_STATE_FILE dynamic
- deploy.sh PROD_ROOT updated to plugin flash dir

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 13:30:20 -04:00
Gmer4Lfe 95fd38799d Phase 1: resilient SSH handling + Push Conf button
partnership_onboard.sh (--phase1-only):
- Test if SSH already works first (BatchMode) — skip ssh-copy-id if yes
- If ssh-copy-id fails (no TTY in background): soft-fail, generate key locally,
  print pubkey for manual install, write HOST2_KEY_READY=true, run local setup
- Only skip conf push if SSH truly unavailable; otherwise proceeds normally
- Exit 0 with clear manual-step instructions instead of hard failure

include/partnership.php:
- Read HOST2_KEY_READY from setup.db; expose as key_ready on remote nodes

pages/partnership.php:
- Node card: amber "Key generated · install on HOST2 then Push Conf" badge
  when key_ready=true and phase=0
- "Push Conf (key installed)" button appears when key_ready=true — runs
  --phase1-only --skip-ssh (assumes user manually did ssh-copy-id)
- vvPtPushConf() top-level function
2026-05-30 20:27:30 -04:00
Gmer4Lfe 4aaa3c507a Monitor partner card: onboard phase badges (re-add) 2026-05-30 20:08:23 -04:00
Gmer4Lfe 192664605b Revert monitor onboard indicator — belongs on Partnership page only 2026-05-30 20:06:11 -04:00
Gmer4Lfe c97a30b9c4 Monitor partner card: onboard phase indicator per remote host
vv_partner_state() now reads setup.db and adds onboard_phase (0/1/2/null)
to each host entry.

Partner card JS renders a badge under the hostname for remote hosts that
haven't completed Phase 2: amber "Awaiting onboard" (phase 1) or grey
"Not provisioned" (phase 0). Phase 2 complete shows nothing extra.
2026-05-30 20:04:32 -04:00
Gmer4Lfe d1ee880586 HOST1 completes local onboard independently during Phase 1
partnership_manager.sh:
- --local-only flag for --onboard: skips remote pre-flight, WebUI reconfig,
  state push; runs FolderView3 folder creation + writes HOST1_LOCAL_DONE=true
  to setup.db + pushes it; exits without writing ACTIVE (partnership not yet
  established until Phase 2)

partnership_onboard.sh:
- Phase 1 exit now runs partnership_manager.sh --onboard --local-only after
  SSH + conf push, so HOST1 is fully configured on its own side before Phase 2

include/partnership.php:
- vv_pt_nodes() reads HOST1_LOCAL_DONE from setup.db; exposes as local_done
  on the self node (null for remote nodes)

pages/partnership.php:
- Self node card shows green "Local setup complete · waiting for partner"
  badge when local_done=true
- Actions: "Complete HOST1 Setup" button appears when HOST1 hasn't run local
  setup yet but HOST2 is already at phase 1 — lets user trigger it manually
- vvPtLocalSetup() top-level function calls partnership_manager.sh via run.php
2026-05-30 19:55:56 -04:00
Gmer4Lfe a5755921ab Two-phase onboard + partner card enhancements
partnership_onboard.sh:
- --phase1-only (OWNER): SSH key exchange + conf push only; safe to run
  before HOST2 has Varaverk installed; writes HOST2_PHASE1_DONE to setup.db
- --phase2-only (OWNER): skips SSH, runs Steps 2-9 (containers, arr stack,
  onboard, arr sync, conf push); writes HOST2_PHASE2_DONE to setup.db
- Mirror path: after SSH setup, SSHes OWNER and fires --phase2-only in
  background (nohup); reads OWNER's SCRIPTS_DIR from varaverk.cfg first;
  falls back to manual instruction if SSH fails

partnership.php (include): vv_pt_nodes() reads setup.db and exposes
onboard_phase (0/1/2) per remote node

partnership.php (page): phase-aware Actions section per partner host;
node cards show phase badge (not provisioned / awaiting onboard / done);
Phase 1 and Phase 2 buttons call run.php with extra_args

monitor.php: partner card logo (top-right), CPU thread count, RAM total GB,
unRAID version row in remote stats grid
2026-05-30 18:12:49 -04:00
Gmer4Lfe 1e9d8bc75b Fallback card: rich state display with tiers, strikes, disabled/suspended
include/monitor.php: vv_fallback_state() now returns:
  enabled, check_interval, handback_strikes, handback_strikes_required,
  partnership_suspended, partner_lost_at, partnership_required,
  partnership_suspend_after — all read from state file + conf vars.

pages/monitor.php: fallback card render rebuilt:
  Disabled: clear message with how to enable
  Suspended: partnership inactive with elapsed time
  FAILOVER: outage duration + T1/T2/T3/T4 tier badges (active=green,
    pending=dark) + handback strike progress dots (●●○) when remote
    comes back and strikes are counting
  NO_INTERNET/DARK: short contextual line
  NORMAL: quiet "monitoring · 30s · partnership gated" meta line
  Accent border: disabled/suspended → warn, NORMAL → ok, FAILOVER → err
2026-05-30 17:24:55 -04:00
Gmer4Lfe 7e01f6d3db Differentiate API key missing vs API unreachable in monitor banner
unraid_api.php: track key_missing separately from general fallbacks.
  vv_api_data() sets key_missing=true when HOST*_UNRAID_API_KEY is empty.
  vv_api_get_status() includes key_missing in the status payload.

monitor.php: two distinct banner states instead of one orange warning.
  key_missing → subtle dark/grey note: "API key not configured — add
    HOST1_UNRAID_API_KEY in Scheduler → host conf to enable enhanced monitoring"
  key present but unreachable → existing orange ⚠ with fallback list.
  No banner at all when API is working correctly.
2026-05-30 16:26:51 -04:00
Gmer4Lfe 0121462576 Graceful degradation before partnership/SSH is set up
Fix 1 — Monitor partner card (common.php + monitor.php):
  vv_remote_hosts_stats() no longer skips hosts with no API key.
  Returns no_api_key:true entry instead. Monitor JS renders
  "API key not configured — complete Onboard to enable" instead
  of a blank space.

Fix 2 — rawconf push not alarming pre-onboard (config.php + scheduler.php):
  Probe failures (Tailscale not found, plugin not installed) now carry
  ready:false. JS treats ready:false results silently — button shows
  "✓ Saved" not "push failed: HOST2" before SSH is set up.
  Only genuine post-onboard failures (ready not false) show as errors.

Fix 3 — Partnership Onboard button (partnership.php):
  Disabled with tooltip when no partner hostname is in master.conf.
  When partner configured but not onboarded, adds explanation note:
  "Onboard will generate your SSH key, exchange it with the partner..."
  No partner configured: "Edit master.conf and set HOST2."
2026-05-30 16:01:44 -04:00
Gmer4Lfe af89258bbd Setup wizard: full first-run flow for HOST1 and HOST2
Varaverk.page: also shows wizard when local host.conf is missing
  (handles master.conf pushed by HOST1 before HOST2 installs plugin).

pages/setup.php: three wizard flows
  - Standard: blank master.conf, fill hostnames, redirect to scheduler
  - Host2/state file: state file detected, pull master.conf from HOST1 via SSH
  - Conf-only: master.conf already filled (was pushed), just create local host.conf

api/setup.php:
  - save action: writes master.conf + host.conf, creates varaverk_setup.db state file,
    redirects to ?tab=scheduler&vv_setup=master.conf
  - pull action: resolves HOST1 Tailscale IP, queries HOST1 SCRIPTS_DIR, SCPs
    master.conf, creates local host.conf, redirects to ?tab=scheduler&vv_setup=hostN.conf

include/config.php: vv_setup_state_read/write/push helpers.
  vv_push_setup_state() pushes varaverk_setup.db to /boot/config/ on all known
  remotes — no plugin-readiness probe needed (flash is always accessible).

api/rawconf.php: calls vv_push_setup_state() alongside master.conf push.

pages/scheduler.php: setup mode via ?vv_setup=<conf> URL param.
  Auto-opens the specified conf file on page load (DOMContentLoaded).
  vvSaveRawConf: in setup mode, skips confirm dialog and forces sequence:
    master.conf save → auto-open hostN.conf
    hostN.conf save → redirect to Monitor (setup complete)
2026-05-30 15:43:04 -04:00