Add share_setup.sh — create missing mirror shares during onboarding (pool-aware, idempotent)
This commit is contained in:
@@ -18,8 +18,10 @@
|
||||
# Step 1: SSH key setup — generate keypair, copy to owner, update conf
|
||||
# Owner completes the rest remotely. Mirror is done.
|
||||
#
|
||||
# OWNER PATH (10 steps)
|
||||
# OWNER PATH (11 steps)
|
||||
# Step 1: SSH key setup — generate keypair, install on mirror, update conf
|
||||
# Step 1b: Docker network — ensure varaverk docker network exists on mirror
|
||||
# Step 1c: Share setup — create missing Unraid shares on mirror (pool-aware, idempotent)
|
||||
# Step 2: Stop mirror auth — stop mirror's existing auth containers before replacing
|
||||
# Step 3: Deploy auth stack — push XMLs, pull images, create + start on mirror
|
||||
# Mariadb/Redis health-checked before Authelia deploys
|
||||
@@ -126,6 +128,9 @@
|
||||
# Partnership/partnership_onboard.sh --skip-ssh
|
||||
# Skip SSH key setup (key already in place)
|
||||
#
|
||||
# Partnership/partnership_onboard.sh --skip-share-setup
|
||||
# Skip share creation on mirror (shares already exist)
|
||||
#
|
||||
# Partnership/partnership_onboard.sh --skip-auth-stack
|
||||
# Skip auth stack stop + deploy (Steps 3-4)
|
||||
#
|
||||
@@ -158,6 +163,7 @@ source "$SCRIPTS_ROOT/Plugin/$PLATFORM/Partnership/containers.sh"
|
||||
|
||||
# ── Parse flags ───────────────────────────────────────────────────────────────────────────────
|
||||
SKIP_SSH=false
|
||||
SKIP_SHARE_SETUP=false
|
||||
SKIP_AUTH_STACK=false
|
||||
SKIP_ARR_STACK=false
|
||||
SKIP_SERVICES_STACK=false
|
||||
@@ -168,8 +174,9 @@ FILTERED_ARGS=()
|
||||
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--skip-ssh) SKIP_SSH=true ;;
|
||||
--skip-auth-stack) SKIP_AUTH_STACK=true ;;
|
||||
--skip-ssh) SKIP_SSH=true ;;
|
||||
--skip-share-setup) SKIP_SHARE_SETUP=true ;;
|
||||
--skip-auth-stack) SKIP_AUTH_STACK=true ;;
|
||||
--skip-arr-stack) SKIP_ARR_STACK=true ;;
|
||||
--skip-services-stack) SKIP_SERVICES_STACK=true ;;
|
||||
--skip-arr-sync) SKIP_ARR_SYNC=true ;;
|
||||
@@ -521,6 +528,18 @@ else
|
||||
warn "Check ${_net_script} on $MIRROR and re-run with --skip-ssh if needed"
|
||||
fi
|
||||
|
||||
# ── Step 1c: Share setup ─────────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "━━━ Step 1c — Share Setup (Mirror) ━━━"
|
||||
|
||||
if [[ "$SKIP_SHARE_SETUP" == true ]]; then
|
||||
warn "Skipping (--skip-share-setup)"
|
||||
elif [[ "$DRY_RUN" == true ]]; then
|
||||
bash "$SCRIPT_DIR/share_setup.sh" --dry-run
|
||||
else
|
||||
bash "$SCRIPT_DIR/share_setup.sh"
|
||||
fi
|
||||
|
||||
# ── Step 2: Stop mirror's existing auth stack ─────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "━━━ Step 2 — Stop Mirror Auth Stack ━━━"
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
#!/bin/bash
|
||||
# ==============================================================================================
|
||||
# ============================= share_setup.sh =================================================
|
||||
# ==============================================================================================
|
||||
#
|
||||
# PURPOSE
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# Creates missing Unraid shares on the mirror during partnership onboarding.
|
||||
# Safe to re-run — existing shares are never modified, only missing ones created.
|
||||
#
|
||||
# For each path in the owner's sync share lists (daily, weekly, critical,
|
||||
# intermediate):
|
||||
# - Extracts the top-level Unraid share name
|
||||
# - Skips if the remote already has a .cfg for it
|
||||
# - Uses the local share .cfg as a template: substitutes the remote's detected
|
||||
# appdata pool, clears disk include/exclude (disk layouts differ per server)
|
||||
# - Writes the .cfg to remote /boot/config/shares/ and mkdir -p the directory
|
||||
# - For sub-paths (e.g. appdata-Fallback/Critical-Data), ensures the subdir
|
||||
# exists after the top-level share is in place
|
||||
#
|
||||
# Pool detection: reads the remote's appdata.cfg to find its cache pool name,
|
||||
# so appdata-type shares land on the right pool without hardcoding.
|
||||
#
|
||||
# Media shares (shareUseCache=no in local .cfg) are created as array-only.
|
||||
# Remote admin assigns disk sets from the Unraid UI after onboarding.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# USAGE
|
||||
# ==============================================================================================
|
||||
#
|
||||
# share_setup.sh
|
||||
# Create missing shares on the configured mirror. Skips existing.
|
||||
#
|
||||
# share_setup.sh --dry-run
|
||||
# Show what would be created without writing anything.
|
||||
#
|
||||
# ==============================================================================================
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/../load_config.sh"
|
||||
detect_hosts
|
||||
parse_args "$@"
|
||||
|
||||
# ── Resolve mirror ────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
[[ -z "${REMOTE_SERVER_NAME:-}" ]] && { error "Cannot determine mirror hostname — check HOST* in master.conf"; exit 1; }
|
||||
MIRROR="$REMOTE_SERVER_NAME"
|
||||
|
||||
MIRROR_IP=$(resolve_tailscale_ip "$MIRROR")
|
||||
[[ -z "$MIRROR_IP" ]] && { error "Cannot resolve $MIRROR Tailscale IP — is Tailscale running?"; exit 1; }
|
||||
|
||||
_ssh() { ssh -i "$SSH_KEY" -o ConnectTimeout=10 -o BatchMode=yes -o StrictHostKeyChecking=no root@"$MIRROR_IP" "$@"; }
|
||||
_scp() { scp -i "$SSH_KEY" -o ConnectTimeout=10 -o StrictHostKeyChecking=no "$@"; }
|
||||
|
||||
# ── Detect remote appdata pool ────────────────────────────────────────────────────────────────
|
||||
|
||||
REMOTE_POOL=$(_ssh "grep -oP '(?<=shareCachePool=\")[^\"]+' /boot/config/shares/appdata.cfg 2>/dev/null | head -1" 2>/dev/null || true)
|
||||
REMOTE_POOL="${REMOTE_POOL:-cache}"
|
||||
log "Remote appdata pool: $REMOTE_POOL"
|
||||
|
||||
# ── Collect paths from all sync share arrays ──────────────────────────────────────────────────
|
||||
|
||||
declare -a ALL_PATHS=()
|
||||
|
||||
_add_array() {
|
||||
local varname="$1"
|
||||
local -n _ref="$varname" 2>/dev/null || return 0
|
||||
for entry in "${_ref[@]+"${_ref[@]}"}"; do
|
||||
[[ -n "$entry" ]] && ALL_PATHS+=("${entry%%|*}")
|
||||
done
|
||||
}
|
||||
|
||||
_add_array "${MY_ID}_DAILY_SYNC_SHARES"
|
||||
_add_array "${MY_ID}_WEEKLY_SYNC_SHARES"
|
||||
_add_array "${MY_ID}_CRITICAL_SYNC_SHARES"
|
||||
_add_array "${MY_ID}_INTERMEDIATE_SYNC_SHARES"
|
||||
|
||||
# ── Separate top-level shares from sub-paths ──────────────────────────────────────────────────
|
||||
|
||||
declare -A SEEN_TOP=()
|
||||
declare -A SEEN_SUB=()
|
||||
declare -a TOP_SHARES=()
|
||||
declare -a SUB_PATHS=()
|
||||
|
||||
for path in "${ALL_PATHS[@]+"${ALL_PATHS[@]}"}"; do
|
||||
[[ "$path" != /mnt/user/* ]] && continue
|
||||
rel="${path#/mnt/user/}"
|
||||
top="${rel%%/*}"
|
||||
[[ -z "${SEEN_TOP[$top]+_}" ]] && { TOP_SHARES+=("$top"); SEEN_TOP["$top"]=1; }
|
||||
if [[ "$rel" == */* && -z "${SEEN_SUB[$path]+_}" ]]; then
|
||||
SUB_PATHS+=("$path"); SEEN_SUB["$path"]=1
|
||||
fi
|
||||
done
|
||||
|
||||
[[ ${#TOP_SHARES[@]} -eq 0 ]] && { echo "No shares to process."; exit 0; }
|
||||
|
||||
# ── Build .cfg for a share ────────────────────────────────────────────────────────────────────
|
||||
# Uses local .cfg as template: substitutes pool, clears disk sets, drops comment.
|
||||
# Falls back to a minimal cfg inferred from share name when no local .cfg exists.
|
||||
|
||||
_make_cfg() {
|
||||
local share_name="$1"
|
||||
local local_cfg="/boot/config/shares/${share_name}.cfg"
|
||||
|
||||
if [[ -f "$local_cfg" ]]; then
|
||||
sed \
|
||||
-e "s|^shareCachePool=\"[^\"]*\"|shareCachePool=\"${REMOTE_POOL}\"|" \
|
||||
-e 's|^shareInclude="[^"]*"|shareInclude=""|' \
|
||||
-e 's|^shareExclude="[^"]*"|shareExclude=""|' \
|
||||
-e '/^shareComment=/d' \
|
||||
"$local_cfg"
|
||||
else
|
||||
local use_cache="no" pool="" allocator="mostfree"
|
||||
case "$share_name" in appdata*|Media_Server*)
|
||||
use_cache="yes"; pool="$REMOTE_POOL"; allocator="highwater" ;;
|
||||
esac
|
||||
printf 'shareUseCache="%s"\nshareCachePool="%s"\nshareCachePool2=""\n' "$use_cache" "$pool"
|
||||
printf 'shareCOW="auto"\nshareAllocator="%s"\nshareInclude=""\nshareExclude=""\n' "$allocator"
|
||||
printf 'shareFloor="0"\nshareExport="e"\nshareCaseSensitive="auto"\n'
|
||||
printf 'shareSecurity="private"\nshareReadList=""\nshareWriteList=""\n'
|
||||
printf 'shareVolsizelimit=""\nshareExportNFS="-"\nshareExportNFSFsid="0"\n'
|
||||
printf 'shareSecurityNFS="public"\nshareHostListNFS=""\n'
|
||||
fi
|
||||
}
|
||||
|
||||
# ── Process each top-level share ──────────────────────────────────────────────────────────────
|
||||
|
||||
TMPFILE=$(mktemp)
|
||||
trap 'rm -f "$TMPFILE"' EXIT
|
||||
|
||||
CREATED=0 SKIPPED=0
|
||||
|
||||
for share in "${TOP_SHARES[@]}"; do
|
||||
existing=$(_ssh "[[ -f '/boot/config/shares/${share}.cfg' ]] && echo yes || echo no" 2>/dev/null)
|
||||
|
||||
if [[ "$existing" == "yes" ]]; then
|
||||
log " exists: $share"
|
||||
(( SKIPPED++ )) || true
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ "$DRY_RUN" == true ]]; then
|
||||
local_cfg="/boot/config/shares/${share}.cfg"
|
||||
if [[ -f "$local_cfg" ]]; then
|
||||
use_cache=$(grep -oP '(?<=shareUseCache=")[^"]+' "$local_cfg" || echo "?")
|
||||
echo " [dry-run] CREATE $share (useCache=$use_cache → pool: $REMOTE_POOL)"
|
||||
else
|
||||
echo " [dry-run] CREATE $share (no local cfg — minimal fallback)"
|
||||
fi
|
||||
(( CREATED++ )) || true
|
||||
continue
|
||||
fi
|
||||
|
||||
_make_cfg "$share" > "$TMPFILE"
|
||||
_scp "$TMPFILE" "root@${MIRROR_IP}:/boot/config/shares/${share}.cfg" >/dev/null
|
||||
_ssh "mkdir -p /mnt/user/${share}" >/dev/null
|
||||
echo " Created: $share ✅"
|
||||
(( CREATED++ )) || true
|
||||
done
|
||||
|
||||
# ── Ensure sub-path directories exist ────────────────────────────────────────────────────────
|
||||
|
||||
for path in "${SUB_PATHS[@]+"${SUB_PATHS[@]}"}"; do
|
||||
if [[ "$DRY_RUN" == true ]]; then
|
||||
echo " [dry-run] MKDIR $path"
|
||||
continue
|
||||
fi
|
||||
_ssh "mkdir -p '$path'" 2>/dev/null && log " mkdir: $path" || true
|
||||
done
|
||||
|
||||
# ── Summary ───────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
echo ""
|
||||
echo " Shares: $CREATED created, $SKIPPED already existed on $MIRROR"
|
||||
[[ "$DRY_RUN" == true ]] && echo " (dry-run — nothing written)"
|
||||
Reference in New Issue
Block a user