API keys: Varaverk_HOST1 registered on all machines, keys in host*.conf, cross-host GraphQL direct access
This commit is contained in:
@@ -95,7 +95,10 @@ if ($action === 'detect' && $_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Unraid API key status — all hosts ────────────────────────────────────────
|
// ── Unraid API key status ─────────────────────────────────────────────────────
|
||||||
|
// Keys live in host*.conf (private, not master.conf):
|
||||||
|
// host1.conf: HOST1_UNRAID_API_KEY (own) + HOST2_UNRAID_API_KEY (HOST1's access to HOST2)
|
||||||
|
// host2.conf: HOST2_UNRAID_API_KEY (own) + HOST1_UNRAID_API_KEY (HOST2's access to HOST1)
|
||||||
if ($action === 'api_status') {
|
if ($action === 'api_status') {
|
||||||
require_once dirname(__DIR__) . '/include/unraid_api.php';
|
require_once dirname(__DIR__) . '/include/unraid_api.php';
|
||||||
$localStatus = vv_api_get_status();
|
$localStatus = vv_api_get_status();
|
||||||
@@ -103,7 +106,6 @@ if ($action === 'api_status') {
|
|||||||
$myHost = vv_detect_host();
|
$myHost = vv_detect_host();
|
||||||
$myId = strtoupper($myHost);
|
$myId = strtoupper($myHost);
|
||||||
|
|
||||||
// Collect status for every configured host
|
|
||||||
$hosts = [];
|
$hosts = [];
|
||||||
foreach ($vars as $k => $v) {
|
foreach ($vars as $k => $v) {
|
||||||
if (!preg_match('/^HOST(\d+)$/', $k, $m) || !$v) continue;
|
if (!preg_match('/^HOST(\d+)$/', $k, $m) || !$v) continue;
|
||||||
@@ -111,11 +113,14 @@ if ($action === 'api_status') {
|
|||||||
$keyVar = $id . '_UNRAID_API_KEY';
|
$keyVar = $id . '_UNRAID_API_KEY';
|
||||||
$key = $vars[$keyVar] ?? '';
|
$key = $vars[$keyVar] ?? '';
|
||||||
$isLocal = ($id === $myId);
|
$isLocal = ($id === $myId);
|
||||||
|
// For local: key is Varaverk_HOST1 registered on own machine
|
||||||
|
// For remote: key is Varaverk_HOST1 registered on HOST2's machine (stored in host1.conf)
|
||||||
$hosts[] = [
|
$hosts[] = [
|
||||||
'host_id' => $id,
|
'host_id' => $id,
|
||||||
'hostname' => $v,
|
'hostname' => $v,
|
||||||
'is_local' => $isLocal,
|
'is_local' => $isLocal,
|
||||||
'key_var' => $keyVar,
|
'key_var' => $keyVar,
|
||||||
|
'key_name' => 'Varaverk_' . ($isLocal ? $myId : $myId), // Varaverk_HOST1 on that registry
|
||||||
'key_present' => !empty($key),
|
'key_present' => !empty($key),
|
||||||
'key_preview' => $key ? substr($key, 0, 8) . '...' . substr($key, -4) : null,
|
'key_preview' => $key ? substr($key, 0, 8) . '...' . substr($key, -4) : null,
|
||||||
'api_ok' => $isLocal
|
'api_ok' => $isLocal
|
||||||
@@ -123,7 +128,7 @@ if ($action === 'api_status') {
|
|||||||
: !empty($key),
|
: !empty($key),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
usort($hosts, fn($a,$b) => strcmp($a['host_id'], $b['host_id']));
|
usort($hosts, fn($a, $b) => strcmp($a['host_id'], $b['host_id']));
|
||||||
|
|
||||||
echo json_encode([
|
echo json_encode([
|
||||||
'ok' => true,
|
'ok' => true,
|
||||||
|
|||||||
@@ -152,10 +152,12 @@ $_apiPreview = $_apiKey ? substr($_apiKey, 0, 8) . '...' . substr($_apiKey, -4)
|
|||||||
<div id="vv-api-hosts" style="margin-bottom:12px;"></div>
|
<div id="vv-api-hosts" style="margin-bottom:12px;"></div>
|
||||||
|
|
||||||
<div style="font-size:11px;color:#444;margin-bottom:12px;line-height:1.6;">
|
<div style="font-size:11px;color:#444;margin-bottom:12px;line-height:1.6;">
|
||||||
Each host registers a key named <code style="font-size:10px;color:#4a7a4a;background:#080808;padding:1px 4px;border-radius:2px;">Varaverk_HOST1</code>,
|
Each host registers
|
||||||
<code style="font-size:10px;color:#4a7a4a;background:#080808;padding:1px 4px;border-radius:2px;">Varaverk_HOST2</code>, etc.
|
<code style="font-size:10px;color:#4a7a4a;background:#080808;padding:1px 4px;border-radius:2px;">Varaverk_HOST1</code>
|
||||||
Keys are stored in <code style="font-size:10px;color:#4a7a4a;background:#080808;padding:1px 4px;border-radius:2px;">master.conf</code>
|
in <em>every</em> machine's local Unraid registry — own machine plus all partners.
|
||||||
so every host can query every other host's GraphQL API directly — no SSH needed for remote monitoring.
|
The key values are stored in the private <code style="font-size:10px;color:#4a7a4a;background:#080808;padding:1px 4px;border-radius:2px;">host*.conf</code>
|
||||||
|
so each host can query every other host's GraphQL API directly — real-time monitoring, no SSH.
|
||||||
|
During offboard, partner keys are removed from each registry automatically.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap;">
|
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap;">
|
||||||
@@ -349,16 +351,22 @@ function vvApiCheck() {
|
|||||||
badge.className = 'vv-set-badge ' + (allOk ? 'internal' : 'flash');
|
badge.className = 'vv-set-badge ' + (allOk ? 'internal' : 'flash');
|
||||||
|
|
||||||
if (hosts) hosts.innerHTML = d.hosts.map(h => {
|
if (hosts) hosts.innerHTML = d.hosts.map(h => {
|
||||||
const local = h.is_local ? ' <span style="color:#2a3a2a;font-size:9px;">local</span>' : '';
|
const tag = h.is_local
|
||||||
|
? `<span style="color:#2a3a2a;font-size:9px;margin-left:4px;">own</span>`
|
||||||
|
: `<span style="color:#2a2a3a;font-size:9px;margin-left:4px;">${d.my_id}'s key on ${h.host_id}</span>`;
|
||||||
const keyBit = h.key_present
|
const keyBit = h.key_present
|
||||||
? `<code style="font-size:9px;color:#4a6a4a;">${h.key_preview}</code>`
|
? `<code style="font-size:9px;color:#4a6a4a;">${h.key_preview}</code>`
|
||||||
: `<span style="color:#8b2a2a;font-size:10px;">not set</span>`;
|
: `<span style="color:#8b2a2a;font-size:10px;">not set — click Setup</span>`;
|
||||||
const dot = h.api_ok ? '#4caf50' : '#555';
|
const dot = h.api_ok ? '#4caf50' : (h.key_present ? '#ffb74d' : '#444');
|
||||||
const name = `Varaverk_${h.host_id}`;
|
// Key name in that machine's registry: always Varaverk_<MY_ID>
|
||||||
return `<div style="display:flex;align-items:baseline;gap:8px;padding:3px 0;border-bottom:1px solid #111;">
|
const keyName = `Varaverk_${d.my_id}`;
|
||||||
<span style="width:6px;height:6px;border-radius:50%;background:${dot};flex-shrink:0;margin-top:3px;display:inline-block;"></span>
|
const registry = h.is_local ? h.host_id : h.host_id;
|
||||||
<span style="font-size:11px;color:#666;width:60px;flex-shrink:0;">${h.host_id}${local}</span>
|
return `<div style="display:flex;align-items:center;gap:8px;padding:4px 0;border-bottom:1px solid #111;">
|
||||||
<code style="font-size:9px;color:#2a3a2a;flex-shrink:0;">${name}</code>
|
<span style="width:6px;height:6px;border-radius:50%;background:${dot};flex-shrink:0;display:inline-block;"></span>
|
||||||
|
<span style="font-size:11px;color:#666;flex-shrink:0;min-width:50px;">${h.host_id}</span>
|
||||||
|
<code style="font-size:9px;color:#2a3a2a;flex-shrink:0;">${keyName}</code>
|
||||||
|
<span style="font-size:9px;color:#2a2a2a;flex-shrink:0;">on ${registry}</span>
|
||||||
|
${tag}
|
||||||
<span style="flex:1;text-align:right;">${keyBit}</span>
|
<span style="flex:1;text-align:right;">${keyBit}</span>
|
||||||
</div>`;
|
</div>`;
|
||||||
}).join('');
|
}).join('');
|
||||||
|
|||||||
@@ -5,219 +5,223 @@
|
|||||||
#
|
#
|
||||||
# PURPOSE
|
# PURPOSE
|
||||||
# ─────────────────────────────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────────────────────────────
|
||||||
# Creates/syncs the Varaverk API key in the Unraid registry. The registry is
|
# Manages per-host named API keys in each machine's Unraid registry so every
|
||||||
# ephemeral — OS updates and service restarts clear it. This script re-registers
|
# host can call every other host's GraphQL API directly for real-time monitoring.
|
||||||
# every boot so monitoring self-heals without manual intervention.
|
|
||||||
#
|
#
|
||||||
# Each host's key is named "Varaverk_HOST1", "Varaverk_HOST2", etc., and stored
|
# KEY MODEL
|
||||||
# in master.conf (shared) so all hosts can call each other's GraphQL API directly
|
# ─────────────────────────────────────────────────────────────────────────────
|
||||||
# for real-time monitoring without SSH.
|
# HOST1's Unraid registry holds:
|
||||||
|
# Varaverk_HOST1 — HOST1's own key (for HOST1 to call its own API)
|
||||||
|
# Varaverk_HOST2 — HOST2's access key to HOST1's API (removed on offboard)
|
||||||
#
|
#
|
||||||
# --all-hosts also SSHes to each partner, creates their key there, and writes
|
# HOST2's Unraid registry holds:
|
||||||
# all keys into master.conf. Run once from Settings → API Key → Setup
|
# Varaverk_HOST2 — HOST2's own key
|
||||||
# to fully wire cross-host API access.
|
# Varaverk_HOST1 — HOST1's access key to HOST2's API (removed on offboard)
|
||||||
|
#
|
||||||
|
# host1.conf holds:
|
||||||
|
# HOST1_UNRAID_API_KEY — value of Varaverk_HOST1 from HOST1's registry
|
||||||
|
# HOST2_UNRAID_API_KEY — value of Varaverk_HOST1 from HOST2's registry
|
||||||
|
# (HOST1 uses this to call HOST2's GraphQL directly)
|
||||||
|
#
|
||||||
|
# host2.conf holds the mirror:
|
||||||
|
# HOST2_UNRAID_API_KEY — value of Varaverk_HOST2 from HOST2's registry
|
||||||
|
# HOST1_UNRAID_API_KEY — value of Varaverk_HOST2 from HOST1's registry
|
||||||
|
# (HOST2 uses this to call HOST1's GraphQL directly)
|
||||||
|
#
|
||||||
|
# ── vv_remote_hosts_stats() picks up HOST2_UNRAID_API_KEY from host1.conf
|
||||||
|
# automatically — direct GraphQL, no SSH needed for remote monitoring.
|
||||||
#
|
#
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
# RUNTIME MODES
|
# RUNTIME MODES
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
#
|
#
|
||||||
# unraid_api_key_renew.sh
|
# unraid_api_key_renew.sh
|
||||||
# Renew local key only — runs at array start, fast.
|
# Local only — runs at array start. Re-registers Varaverk_HOST1 if the
|
||||||
|
# ephemeral registry lost it. Fast, no SSH.
|
||||||
#
|
#
|
||||||
# unraid_api_key_renew.sh --all-hosts
|
# unraid_api_key_renew.sh --all-hosts
|
||||||
# Renew local key AND SSH to each partner to create/sync their key.
|
# Full cross-host key setup. Run once from Settings → API Keys → Setup.
|
||||||
# Writes all keys into master.conf and pushes to partners.
|
# For each partner:
|
||||||
|
# • Creates Varaverk_HOST1 on PARTNER's registry → stores value in local host*.conf
|
||||||
|
# • Creates Varaverk_HOST2 on LOCAL registry → SSHes value to partner's host*.conf
|
||||||
#
|
#
|
||||||
# unraid_api_key_renew.sh --dry-run
|
# unraid_api_key_renew.sh --dry-run — show what would happen
|
||||||
# unraid_api_key_renew.sh --log
|
# unraid_api_key_renew.sh --log — verbose output
|
||||||
#
|
#
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
|
||||||
source "$SCRIPT_DIR/../load_config.sh"
|
source "$SCRIPT_DIR/../load_config.sh"
|
||||||
|
|
||||||
parse_args "$@"
|
parse_args "$@"
|
||||||
acquire_lock
|
acquire_lock
|
||||||
detect_hosts
|
detect_hosts
|
||||||
|
|
||||||
# ──────────────────────────────────────────────────────────────────────────────
|
# Parse --all-hosts
|
||||||
# Parse --all-hosts from raw args (parse_args doesn't handle this flag)
|
|
||||||
ALL_HOSTS=false
|
ALL_HOSTS=false
|
||||||
for _arg in "$@"; do [[ "$_arg" == "--all-hosts" ]] && ALL_HOSTS=true; done
|
for _arg in "$@"; do [[ "$_arg" == "--all-hosts" ]] && ALL_HOSTS=true; done
|
||||||
unset _arg
|
unset _arg
|
||||||
|
|
||||||
CONF_FILE="$SCRIPT_DIR/../Configurations/${MY_ID,,}.conf"
|
LOCAL_CONF="$SCRIPT_DIR/../Configurations/${MY_ID,,}.conf"
|
||||||
MASTER_CONF="$SCRIPT_DIR/../Configurations/master.conf"
|
LOCAL_KEY_NAME="Varaverk_${MY_ID}"
|
||||||
VAR_NAME="${MY_ID}_UNRAID_API_KEY"
|
LOCAL_VAR="${MY_ID}_UNRAID_API_KEY"
|
||||||
KEY_NAME="Varaverk_${MY_ID}"
|
|
||||||
|
|
||||||
log "$ICON_GEAR Conf file: $CONF_FILE"
|
log "$ICON_GEAR Local conf: $LOCAL_CONF"
|
||||||
log "$ICON_GEAR Key name: $KEY_NAME"
|
log "$ICON_GEAR Key name: $LOCAL_KEY_NAME"
|
||||||
log "$ICON_GEAR Key var: $VAR_NAME"
|
|
||||||
log "$ICON_GEAR All hosts: $ALL_HOSTS"
|
log "$ICON_GEAR All hosts: $ALL_HOSTS"
|
||||||
|
|
||||||
if [[ ! -f "$CONF_FILE" ]]; then
|
if [[ ! -f "$LOCAL_CONF" ]]; then
|
||||||
error "Conf file not found: $CONF_FILE"
|
error "Conf file not found: $LOCAL_CONF"; exit 1
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$DRY_RUN" == true ]]; then
|
[[ "$DRY_RUN" == true ]] && {
|
||||||
warn "DRY RUN — would check registry, renew if missing, write to host conf + master.conf"
|
warn "DRY RUN — would check/create $LOCAL_KEY_NAME in registry and sync to host conf"
|
||||||
[[ "$ALL_HOSTS" == true ]] && warn "DRY RUN — would also SSH to all partners and sync their keys"
|
[[ "$ALL_HOSTS" == true ]] && warn "DRY RUN — would also SSH all partners for cross-host key setup"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
}
|
||||||
|
|
||||||
# ── Helper: write a key variable into a conf file ─────────────────────────────
|
# ── Helper: ensure a named key exists in the LOCAL registry, return its value ──
|
||||||
_write_key_to_conf() {
|
_ensure_local_key() {
|
||||||
|
local name="$1"
|
||||||
|
local existing key
|
||||||
|
existing=$(timeout 5 /usr/local/sbin/unraid-api apikey --name "$name" --json </dev/null 2>/dev/null)
|
||||||
|
key=$(echo "$existing" | jq -r '.key // empty' 2>/dev/null)
|
||||||
|
if [[ -n "$key" ]]; then
|
||||||
|
echo "$key"; return 0
|
||||||
|
fi
|
||||||
|
local raw
|
||||||
|
raw=$(timeout 10 /usr/local/sbin/unraid-api apikey \
|
||||||
|
--name "$name" --create --overwrite \
|
||||||
|
--description "Varaverk plugin" --roles ADMIN --json </dev/null 2>&1)
|
||||||
|
key=$(echo "$raw" | jq -r '.key // empty' 2>/dev/null)
|
||||||
|
[[ -z "$key" ]] && { error "Failed to create $name: ${raw:0:200}"; return 1; }
|
||||||
|
echo "$key"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── Helper: write HOST*_UNRAID_API_KEY into a conf file ────────────────────────
|
||||||
|
_write_key() {
|
||||||
local conf="$1" var="$2" key="$3"
|
local conf="$1" var="$2" key="$3"
|
||||||
[[ ! -f "$conf" ]] && return 1
|
[[ ! -f "$conf" ]] && return 1
|
||||||
if grep -q "^\s*${var}\s*=" "$conf"; then
|
if grep -q "^\s*${var}\s*=" "$conf"; then
|
||||||
sed -i "s|^\(\s*${var}\s*=\s*\)\"[^\"]*\"|\1\"${key}\"|" "$conf"
|
sed -i "s|^\(\s*${var}\s*=\s*\)\"[^\"]*\"|\1\"${key}\"|" "$conf"
|
||||||
else
|
else
|
||||||
echo " ${var}=\"${key}\"" >> "$conf"
|
printf ' %s="%s"\n' "$var" "$key" >> "$conf"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Helper: push master.conf to all partners ──────────────────────────────────
|
# ── Helper: ensure a named key exists on a REMOTE registry via SSH ─────────────
|
||||||
_push_master() {
|
_ensure_remote_key() {
|
||||||
php -r "
|
local ssh_key="$1" remote_ip="$2" key_name="$3"
|
||||||
require_once '/usr/local/emhttp/plugins/varaverk/include/config.php';
|
ssh -i "$ssh_key" \
|
||||||
require_once '/usr/local/emhttp/plugins/varaverk/include/confform.php';
|
-o ConnectTimeout=10 -o StrictHostKeyChecking=no -o BatchMode=yes \
|
||||||
vv_push_master_conf();
|
"root@${remote_ip}" "
|
||||||
" 2>/dev/null && log "master.conf pushed to partner(s)" || warn "master.conf push failed (partner offline?)"
|
EXISTING=\$(timeout 5 /usr/local/sbin/unraid-api apikey --name '${key_name}' --json </dev/null 2>/dev/null)
|
||||||
}
|
|
||||||
|
|
||||||
# ──────────────────────────────────────────────────────────────────────────────
|
|
||||||
# Step 1: Local key — check registry, create if missing, sync to conf
|
|
||||||
# ──────────────────────────────────────────────────────────────────────────────
|
|
||||||
echo ""
|
|
||||||
echo "━━━ $ICON_GEAR Local key ($KEY_NAME) ━━━"
|
|
||||||
|
|
||||||
EXISTING=$(timeout 5 /usr/local/sbin/unraid-api apikey --name "$KEY_NAME" --json </dev/null 2>/dev/null)
|
|
||||||
KEY=$(echo "$EXISTING" | jq -r '.key // empty' 2>/dev/null)
|
|
||||||
|
|
||||||
if [[ -n "$KEY" ]]; then
|
|
||||||
PREVIEW="${KEY:0:8}...${KEY: -4}"
|
|
||||||
CONF_KEY=$(grep "^\s*${VAR_NAME}\s*=" "$CONF_FILE" 2>/dev/null | sed 's/.*="\(.*\)".*/\1/' | tr -d '[:space:]')
|
|
||||||
MASTER_KEY=$(grep "^\s*${VAR_NAME}\s*=" "$MASTER_CONF" 2>/dev/null | sed 's/.*="\(.*\)".*/\1/' | tr -d '[:space:]')
|
|
||||||
|
|
||||||
if [[ "$CONF_KEY" == "$KEY" && "$MASTER_KEY" == "$KEY" ]]; then
|
|
||||||
echo "API key valid ✅ — $VAR_NAME = $PREVIEW"
|
|
||||||
log "Key in sync across host conf + master.conf"
|
|
||||||
else
|
|
||||||
log "Syncing key to conf files..."
|
|
||||||
_write_key_to_conf "$CONF_FILE" "$VAR_NAME" "$KEY"
|
|
||||||
_write_key_to_conf "$MASTER_CONF" "$VAR_NAME" "$KEY"
|
|
||||||
_push_master
|
|
||||||
warn "API key synced ✅ — $VAR_NAME = $PREVIEW"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
log "Key not found in registry — creating $KEY_NAME..."
|
|
||||||
RAW=$(timeout 10 /usr/local/sbin/unraid-api apikey \
|
|
||||||
--name "$KEY_NAME" --create --overwrite \
|
|
||||||
--description "Varaverk plugin" --roles ADMIN --json </dev/null 2>&1)
|
|
||||||
|
|
||||||
KEY=$(echo "$RAW" | jq -r '.key // empty' 2>/dev/null)
|
|
||||||
if [[ -z "$KEY" ]]; then
|
|
||||||
error "unraid-api returned no key: ${RAW:0:200}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
_write_key_to_conf "$CONF_FILE" "$VAR_NAME" "$KEY"
|
|
||||||
_write_key_to_conf "$MASTER_CONF" "$VAR_NAME" "$KEY"
|
|
||||||
_push_master
|
|
||||||
PREVIEW="${KEY:0:8}...${KEY: -4}"
|
|
||||||
warn "API key created ✅ — $VAR_NAME = $PREVIEW"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ──────────────────────────────────────────────────────────────────────────────
|
|
||||||
# Step 2 (--all-hosts): SSH to each partner, create their key, write to master.conf
|
|
||||||
# ──────────────────────────────────────────────────────────────────────────────
|
|
||||||
[[ "$ALL_HOSTS" != true ]] && exit 0
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "━━━ $ICON_SYNC Partner keys ━━━"
|
|
||||||
|
|
||||||
PARTNER_OK=0
|
|
||||||
PARTNER_FAIL=0
|
|
||||||
|
|
||||||
for host_var in HOST1 HOST2 HOST3 HOST4 HOST5 HOST6 HOST7 HOST8; do
|
|
||||||
[[ "$host_var" == "$MY_ID" ]] && continue
|
|
||||||
hostname="${!host_var:-}"
|
|
||||||
[[ -z "$hostname" ]] && continue
|
|
||||||
|
|
||||||
r_var_name="${host_var}_UNRAID_API_KEY"
|
|
||||||
r_key_name="Varaverk_${host_var}"
|
|
||||||
r_conf_path="/boot/config/plugins/varaverk/Configurations/${host_var,,}.conf"
|
|
||||||
|
|
||||||
echo " $host_var ($hostname)…"
|
|
||||||
|
|
||||||
REMOTE_IP=$(resolve_tailscale_ip "$hostname")
|
|
||||||
if [[ -z "$REMOTE_IP" ]]; then
|
|
||||||
warn " $host_var: cannot resolve Tailscale IP — skipping"
|
|
||||||
(( PARTNER_FAIL++ ))
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
# SSH: check for existing key, create if missing, return the key value
|
|
||||||
REMOTE_KEY=$(ssh -i "$SSH_KEY" \
|
|
||||||
-o ConnectTimeout=10 \
|
|
||||||
-o StrictHostKeyChecking=no \
|
|
||||||
-o BatchMode=yes \
|
|
||||||
"root@${REMOTE_IP}" "
|
|
||||||
EXISTING=\$(timeout 5 /usr/local/sbin/unraid-api apikey --name '${r_key_name}' --json </dev/null 2>/dev/null)
|
|
||||||
KEY=\$(echo \"\$EXISTING\" | jq -r '.key // empty' 2>/dev/null)
|
KEY=\$(echo \"\$EXISTING\" | jq -r '.key // empty' 2>/dev/null)
|
||||||
if [[ -n \"\$KEY\" ]]; then
|
if [[ -n \"\$KEY\" ]]; then
|
||||||
echo \"\$KEY\"
|
echo \"\$KEY\"
|
||||||
else
|
else
|
||||||
timeout 10 /usr/local/sbin/unraid-api apikey \\
|
timeout 10 /usr/local/sbin/unraid-api apikey \\
|
||||||
--name '${r_key_name}' --create --overwrite \\
|
--name '${key_name}' --create --overwrite \\
|
||||||
--description 'Varaverk plugin' --roles ADMIN --json </dev/null 2>/dev/null \\
|
--description 'Varaverk plugin' --roles ADMIN --json </dev/null 2>/dev/null \\
|
||||||
| jq -r '.key // empty' 2>/dev/null
|
| jq -r '.key // empty' 2>/dev/null
|
||||||
fi
|
fi
|
||||||
" 2>/dev/null | tr -d '[:space:]')
|
" 2>/dev/null | tr -d '[:space:]'
|
||||||
|
}
|
||||||
|
|
||||||
if [[ -z "$REMOTE_KEY" ]]; then
|
# ──────────────────────────────────────────────────────────────────────────────
|
||||||
warn " $host_var: could not get key from $hostname — skipping"
|
# Step 1 — Local key (always)
|
||||||
(( PARTNER_FAIL++ ))
|
# ──────────────────────────────────────────────────────────────────────────────
|
||||||
continue
|
echo ""
|
||||||
|
echo "━━━ $ICON_GEAR Local — $LOCAL_KEY_NAME ━━━"
|
||||||
|
|
||||||
|
LOCAL_KEY=$(_ensure_local_key "$LOCAL_KEY_NAME")
|
||||||
|
if [[ -z "$LOCAL_KEY" ]]; then
|
||||||
|
error "Could not obtain $LOCAL_KEY_NAME from registry"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Sync to conf only if changed
|
||||||
|
CONF_KEY=$(grep "^\s*${LOCAL_VAR}\s*=" "$LOCAL_CONF" 2>/dev/null | sed 's/.*="\(.*\)".*/\1/' | tr -d '[:space:]')
|
||||||
|
if [[ "$CONF_KEY" != "$LOCAL_KEY" ]]; then
|
||||||
|
_write_key "$LOCAL_CONF" "$LOCAL_VAR" "$LOCAL_KEY"
|
||||||
|
warn "Synced $LOCAL_VAR → ${LOCAL_KEY:0:8}...${LOCAL_KEY: -4}"
|
||||||
|
else
|
||||||
|
echo " $LOCAL_VAR valid ✅ — ${LOCAL_KEY:0:8}...${LOCAL_KEY: -4}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ "$ALL_HOSTS" != true ]] && exit 0
|
||||||
|
|
||||||
|
# ──────────────────────────────────────────────────────────────────────────────
|
||||||
|
# Step 2 — Cross-host key setup (--all-hosts)
|
||||||
|
# ──────────────────────────────────────────────────────────────────────────────
|
||||||
|
echo ""
|
||||||
|
echo "━━━ $ICON_SYNC Cross-host key setup ━━━"
|
||||||
|
|
||||||
|
PARTNER_OK=0; PARTNER_FAIL=0
|
||||||
|
|
||||||
|
for host_var in HOST1 HOST2 HOST3 HOST4 HOST5 HOST6 HOST7 HOST8; do
|
||||||
|
[[ "$host_var" == "$MY_ID" ]] && continue
|
||||||
|
hostname="${!host_var:-}"; [[ -z "$hostname" ]] && continue
|
||||||
|
|
||||||
|
r_var="${host_var}_UNRAID_API_KEY" # e.g. HOST2_UNRAID_API_KEY
|
||||||
|
r_my_key_name="Varaverk_${MY_ID}" # key HOST1 uses on HOST2's registry
|
||||||
|
r_their_key_name="Varaverk_${host_var}" # key HOST2 uses on HOST1's registry
|
||||||
|
r_conf="/boot/config/plugins/varaverk/Configurations/${host_var,,}.conf"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo " $host_var ($hostname)"
|
||||||
|
|
||||||
|
REMOTE_IP=$(resolve_tailscale_ip "$hostname")
|
||||||
|
if [[ -z "$REMOTE_IP" ]]; then
|
||||||
|
warn " $host_var: cannot resolve Tailscale IP — skipping"
|
||||||
|
(( PARTNER_FAIL++ )); continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
R_PREVIEW="${REMOTE_KEY:0:8}...${REMOTE_KEY: -4}"
|
# ── A: Get HOST1's access key from HOST2's registry ────────────────────────
|
||||||
|
# Creates Varaverk_HOST1 on HOST2 → store in host1.conf as HOST2_UNRAID_API_KEY
|
||||||
|
log " Creating $r_my_key_name on $host_var registry…"
|
||||||
|
MY_KEY_ON_REMOTE=$(_ensure_remote_key "$SSH_KEY" "$REMOTE_IP" "$r_my_key_name")
|
||||||
|
if [[ -z "$MY_KEY_ON_REMOTE" ]]; then
|
||||||
|
warn " $host_var: could not create $r_my_key_name on their registry"
|
||||||
|
(( PARTNER_FAIL++ )); continue
|
||||||
|
fi
|
||||||
|
_write_key "$LOCAL_CONF" "$r_var" "$MY_KEY_ON_REMOTE"
|
||||||
|
echo " A ✅ $r_my_key_name on $host_var → stored as $r_var in ${MY_ID,,}.conf"
|
||||||
|
|
||||||
# Write remote key to master.conf locally
|
# ── B: Create HOST2's access key on HOST1's registry ──────────────────────
|
||||||
_write_key_to_conf "$MASTER_CONF" "$r_var_name" "$REMOTE_KEY"
|
# Creates Varaverk_HOST2 on HOST1 → store in host2.conf as HOST1_UNRAID_API_KEY
|
||||||
|
log " Creating $r_their_key_name on local registry…"
|
||||||
|
THEIR_KEY_ON_LOCAL=$(_ensure_local_key "$r_their_key_name")
|
||||||
|
if [[ -z "$THEIR_KEY_ON_LOCAL" ]]; then
|
||||||
|
warn " Could not create $r_their_key_name on local registry"
|
||||||
|
(( PARTNER_FAIL++ )); continue
|
||||||
|
fi
|
||||||
|
|
||||||
# Also write to remote's host*.conf so they have it locally
|
# Write to partner's conf via SSH
|
||||||
ssh -i "$SSH_KEY" \
|
ssh -i "$SSH_KEY" \
|
||||||
-o ConnectTimeout=10 \
|
-o ConnectTimeout=10 -o StrictHostKeyChecking=no -o BatchMode=yes \
|
||||||
-o StrictHostKeyChecking=no \
|
|
||||||
-o BatchMode=yes \
|
|
||||||
"root@${REMOTE_IP}" "
|
"root@${REMOTE_IP}" "
|
||||||
CONF='${r_conf_path}'
|
CONF='$r_conf'
|
||||||
if [[ -f \"\$CONF\" ]]; then
|
VAR='${MY_ID}_UNRAID_API_KEY'
|
||||||
if grep -q '^\s*${r_var_name}\s*=' \"\$CONF\"; then
|
KEY='$THEIR_KEY_ON_LOCAL'
|
||||||
sed -i \"s|^\(\s*${r_var_name}\s*=\s*\)\\\"[^\\\"]*\\\"|\1\\\"${REMOTE_KEY}\\\"|\" \"\$CONF\"
|
[[ ! -f \"\$CONF\" ]] && exit 1
|
||||||
|
if grep -q \"^\s*\${VAR}\s*=\" \"\$CONF\"; then
|
||||||
|
sed -i \"s|\(\s*\${VAR}\s*=\s*\)\\\"[^\\\"]*\\\"|\1\\\"\${KEY}\\\"|\" \"\$CONF\"
|
||||||
else
|
else
|
||||||
echo ' ${r_var_name}=\\\"${REMOTE_KEY}\\\"' >> \"\$CONF\"
|
printf ' %s=\"%s\"\n' \"\$VAR\" \"\$KEY\" >> \"\$CONF\"
|
||||||
fi
|
fi
|
||||||
fi
|
" 2>/dev/null \
|
||||||
" 2>/dev/null
|
&& echo " B ✅ $r_their_key_name on local → stored as ${MY_ID}_UNRAID_API_KEY in ${host_var,,}.conf" \
|
||||||
|
|| warn " B: could not write ${MY_ID}_UNRAID_API_KEY to ${host_var,,}.conf"
|
||||||
|
|
||||||
echo " $host_var: $r_key_name = $R_PREVIEW ✅"
|
|
||||||
(( PARTNER_OK++ ))
|
(( PARTNER_OK++ ))
|
||||||
done
|
done
|
||||||
|
|
||||||
# Push master.conf with all updated keys to all partners
|
|
||||||
if (( PARTNER_OK > 0 )); then
|
|
||||||
echo ""
|
|
||||||
echo " Pushing master.conf with all keys…"
|
|
||||||
_push_master
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "━━━━━ $ICON_SUMMARY Key Setup Summary ━━━━━"
|
echo "━━━━━ $ICON_SUMMARY Key Setup Summary ━━━━━"
|
||||||
echo " Local: ✅ $VAR_NAME"
|
echo " Local key: $LOCAL_VAR ✅"
|
||||||
echo " Partners: $PARTNER_OK updated · $PARTNER_FAIL failed"
|
echo " Partner setup: $PARTNER_OK ok · $PARTNER_FAIL failed"
|
||||||
|
echo ""
|
||||||
|
echo " HOST1 can now call HOST2's GraphQL directly using HOST2_UNRAID_API_KEY"
|
||||||
|
echo " HOST2 can now call HOST1's GraphQL directly using HOST1_UNRAID_API_KEY"
|
||||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
|||||||
Reference in New Issue
Block a user