feat(infrastructure): enhance TrueNAS collection with comprehensive Docker/apps support
- Added collect-truenas-apps.sh script for standalone app/container collection - Enhanced collect-truenas-config.sh with Docker container, image, network, and volume collection - Fixed JSON format issues (converted newline-delimited JSON to proper arrays using jq/sed) - Added dynamic SSH user detection (tries root, admin, truenas_admin) - Implemented file size validation to prevent false success messages - Added container logs collection (last 500 lines per container) - Added Docker Compose file extraction from running containers - Added individual app configs collection from /mnt/.ix-apps/app_configs/ - Updated CLAUDE.md to reflect TrueNAS repository scope and strict agent routing rules - Restored sub-agent definitions (backend-builder, lab-operator, librarian, scribe) - Added SCRIPT_UPDATES.md with detailed changelog and testing instructions - Updated .gitignore to exclude Windows Zone.Identifier files These changes enable complete disaster recovery exports including all Docker/app configurations, logs, and metadata that were previously missing from TrueNAS infrastructure snapshots. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
258
scripts/collect-truenas-apps.sh
Executable file
258
scripts/collect-truenas-apps.sh
Executable file
@@ -0,0 +1,258 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# TrueNAS Apps & Docker Collection Script
|
||||
# Run this directly on your TrueNAS server to collect app/container information
|
||||
#
|
||||
# Usage:
|
||||
# 1. Copy this script to your TrueNAS server
|
||||
# 2. Run: bash collect-truenas-apps.sh
|
||||
# 3. Transfer the generated tar.gz back to your workstation
|
||||
#
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
TIMESTAMP="$(date +%Y%m%d-%H%M%S)"
|
||||
OUTPUT_DIR="/tmp/truenas-apps-export-${TIMESTAMP}"
|
||||
|
||||
# Colors
|
||||
GREEN='\033[0;32m'
|
||||
CYAN='\033[0;36m'
|
||||
NC='\033[0m'
|
||||
|
||||
echo -e "${CYAN}=====================================${NC}"
|
||||
echo -e "${CYAN}TrueNAS Apps & Docker Collection${NC}"
|
||||
echo -e "${CYAN}=====================================${NC}"
|
||||
echo
|
||||
|
||||
# Create directory structure
|
||||
mkdir -p "$OUTPUT_DIR"/{configs/apps,exports/apps}
|
||||
|
||||
# Collect Docker information
|
||||
echo -e "${CYAN}=== Docker Containers ===${NC}"
|
||||
if command -v docker &>/dev/null; then
|
||||
# All containers (convert to JSON array)
|
||||
if sudo docker ps -a --format '{{json .}}' 2>/dev/null | jq -s '.' 2>/dev/null > "$OUTPUT_DIR/exports/apps/docker-containers.json" || \
|
||||
sudo docker ps -a --format '{{json .}}' 2>/dev/null | sed '1s/^/[/; $!s/$/,/; $s/$/]/' > "$OUTPUT_DIR/exports/apps/docker-containers.json"; then
|
||||
[[ -s "$OUTPUT_DIR/exports/apps/docker-containers.json" ]] && echo -e "${GREEN}✓${NC} Docker containers (JSON format)"
|
||||
fi
|
||||
|
||||
# Human-readable format
|
||||
if sudo docker ps -a > "$OUTPUT_DIR/exports/apps/docker-containers.txt" 2>/dev/null; then
|
||||
[[ -s "$OUTPUT_DIR/exports/apps/docker-containers.txt" ]] && echo -e "${GREEN}✓${NC} Docker containers (text format)"
|
||||
fi
|
||||
|
||||
# Docker images
|
||||
if sudo docker images --format '{{json .}}' 2>/dev/null | jq -s '.' 2>/dev/null > "$OUTPUT_DIR/exports/apps/docker-images.json" || \
|
||||
sudo docker images --format '{{json .}}' 2>/dev/null | sed '1s/^/[/; $!s/$/,/; $s/$/]/' > "$OUTPUT_DIR/exports/apps/docker-images.json"; then
|
||||
[[ -s "$OUTPUT_DIR/exports/apps/docker-images.json" ]] && echo -e "${GREEN}✓${NC} Docker images"
|
||||
fi
|
||||
|
||||
# Docker networks
|
||||
if sudo docker network ls --format '{{json .}}' 2>/dev/null | jq -s '.' 2>/dev/null > "$OUTPUT_DIR/exports/apps/docker-networks.json" || \
|
||||
sudo docker network ls --format '{{json .}}' 2>/dev/null | sed '1s/^/[/; $!s/$/,/; $s/$/]/' > "$OUTPUT_DIR/exports/apps/docker-networks.json"; then
|
||||
[[ -s "$OUTPUT_DIR/exports/apps/docker-networks.json" ]] && echo -e "${GREEN}✓${NC} Docker networks"
|
||||
fi
|
||||
|
||||
# Docker volumes
|
||||
if sudo docker volume ls --format '{{json .}}' 2>/dev/null | jq -s '.' 2>/dev/null > "$OUTPUT_DIR/exports/apps/docker-volumes.json" || \
|
||||
sudo docker volume ls --format '{{json .}}' 2>/dev/null | sed '1s/^/[/; $!s/$/,/; $s/$/]/' > "$OUTPUT_DIR/exports/apps/docker-volumes.json"; then
|
||||
[[ -s "$OUTPUT_DIR/exports/apps/docker-volumes.json" ]] && echo -e "${GREEN}✓${NC} Docker volumes"
|
||||
fi
|
||||
|
||||
# Docker compose projects (if available)
|
||||
if command -v docker-compose &>/dev/null || docker compose version &>/dev/null 2>&1; then
|
||||
if sudo docker compose ls --format '{{json .}}' 2>/dev/null | jq -s '.' 2>/dev/null > "$OUTPUT_DIR/exports/apps/docker-compose-projects.json" || \
|
||||
sudo docker compose ls --format '{{json .}}' 2>/dev/null | sed '1s/^/[/; $!s/$/,/; $s/$/]/' > "$OUTPUT_DIR/exports/apps/docker-compose-projects.json"; then
|
||||
[[ -s "$OUTPUT_DIR/exports/apps/docker-compose-projects.json" ]] && echo -e "${GREEN}✓${NC} Docker Compose projects" || \
|
||||
echo " ⊘ No Docker Compose projects found"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo " ⊘ Docker command not available"
|
||||
fi
|
||||
echo
|
||||
|
||||
# Collect TrueNAS app metadata
|
||||
echo -e "${CYAN}=== TrueNAS Apps ===${NC}"
|
||||
if [[ -d /mnt/.ix-apps ]]; then
|
||||
# App metadata
|
||||
if [[ -f /mnt/.ix-apps/metadata.yaml ]]; then
|
||||
sudo cp /mnt/.ix-apps/metadata.yaml "$OUTPUT_DIR/configs/apps/metadata.yaml" && \
|
||||
echo -e "${GREEN}✓${NC} App metadata"
|
||||
fi
|
||||
|
||||
# User config
|
||||
if [[ -f /mnt/.ix-apps/user_config.yaml ]]; then
|
||||
sudo cp /mnt/.ix-apps/user_config.yaml "$OUTPUT_DIR/configs/apps/user_config.yaml" && \
|
||||
echo -e "${GREEN}✓${NC} User config"
|
||||
fi
|
||||
|
||||
# App configs directory listing
|
||||
if [[ -d /mnt/.ix-apps/app_configs ]]; then
|
||||
sudo ls -laR /mnt/.ix-apps/app_configs/ > "$OUTPUT_DIR/exports/apps/app_configs_list.txt" 2>/dev/null && \
|
||||
echo -e "${GREEN}✓${NC} App configs listing"
|
||||
fi
|
||||
|
||||
# App mounts listing
|
||||
if [[ -d /mnt/.ix-apps/app_mounts ]]; then
|
||||
sudo ls -laR /mnt/.ix-apps/app_mounts/ > "$OUTPUT_DIR/exports/apps/app_mounts_list.txt" 2>/dev/null && \
|
||||
echo -e "${GREEN}✓${NC} App mounts listing"
|
||||
fi
|
||||
|
||||
# Docker directory info
|
||||
if [[ -d /mnt/.ix-apps/docker ]]; then
|
||||
sudo du -sh /mnt/.ix-apps/docker/* 2>/dev/null > "$OUTPUT_DIR/exports/apps/docker_sizes.txt" && \
|
||||
echo -e "${GREEN}✓${NC} Docker storage sizes"
|
||||
fi
|
||||
else
|
||||
echo " ⊘ TrueNAS apps directory not found"
|
||||
fi
|
||||
echo
|
||||
|
||||
# Collect individual container details
|
||||
echo -e "${CYAN}=== Container Details ===${NC}"
|
||||
mkdir -p "$OUTPUT_DIR/exports/apps/containers"
|
||||
if command -v docker &>/dev/null; then
|
||||
CONTAINER_COUNT=0
|
||||
while IFS= read -r container_id; do
|
||||
CONTAINER_NAME=$(sudo docker inspect "$container_id" --format '{{.Name}}' | sed 's/^\///')
|
||||
sudo docker inspect "$container_id" > "$OUTPUT_DIR/exports/apps/containers/${CONTAINER_NAME}.json" 2>/dev/null && \
|
||||
((CONTAINER_COUNT++)) || true
|
||||
done < <(sudo docker ps -aq)
|
||||
echo -e "${GREEN}✓${NC} Collected details for $CONTAINER_COUNT containers"
|
||||
else
|
||||
echo " ⊘ Docker command not available"
|
||||
fi
|
||||
echo
|
||||
|
||||
# Collect container logs (last 500 lines, with size limit)
|
||||
echo -e "${CYAN}=== Container Logs ===${NC}"
|
||||
mkdir -p "$OUTPUT_DIR/exports/apps/logs"
|
||||
if command -v docker &>/dev/null; then
|
||||
LOG_COUNT=0
|
||||
while IFS= read -r container_id; do
|
||||
CONTAINER_NAME=$(sudo docker inspect "$container_id" --format '{{.Name}}' 2>/dev/null | sed 's/^\//')
|
||||
if [[ -n "$CONTAINER_NAME" ]]; then
|
||||
# Collect last 500 lines of logs (prevents huge files)
|
||||
sudo docker logs --tail 500 "$container_id" > "$OUTPUT_DIR/exports/apps/logs/${CONTAINER_NAME}.log" 2>&1 && \
|
||||
((LOG_COUNT++)) || true
|
||||
fi
|
||||
done < <(sudo docker ps -aq)
|
||||
echo -e "${GREEN}✓${NC} Collected logs for $LOG_COUNT containers"
|
||||
else
|
||||
echo " ⊘ Docker command not available"
|
||||
fi
|
||||
echo
|
||||
|
||||
# Collect Docker Compose files from running containers
|
||||
echo -e "${CYAN}=== Docker Compose Files ===${NC}"
|
||||
mkdir -p "$OUTPUT_DIR/configs/apps/compose"
|
||||
if command -v docker &>/dev/null; then
|
||||
COMPOSE_COUNT=0
|
||||
while IFS= read -r container_id; do
|
||||
CONTAINER_NAME=$(sudo docker inspect "$container_id" --format '{{.Name}}' 2>/dev/null | sed 's/^\//')
|
||||
COMPOSE_FILE=$(sudo docker inspect "$container_id" --format '{{index .Config.Labels "com.docker.compose.project.config_files"}}' 2>/dev/null)
|
||||
|
||||
if [[ -n "$COMPOSE_FILE" ]] && [[ -f "$COMPOSE_FILE" ]]; then
|
||||
PROJECT_NAME=$(sudo docker inspect "$container_id" --format '{{index .Config.Labels "com.docker.compose.project"}}' 2>/dev/null)
|
||||
sudo cp "$COMPOSE_FILE" "$OUTPUT_DIR/configs/apps/compose/${PROJECT_NAME:-$CONTAINER_NAME}.yml" 2>/dev/null && \
|
||||
((COMPOSE_COUNT++)) || true
|
||||
fi
|
||||
done < <(sudo docker ps -aq)
|
||||
|
||||
if [[ $COMPOSE_COUNT -gt 0 ]]; then
|
||||
echo -e "${GREEN}✓${NC} Collected $COMPOSE_COUNT Docker Compose files"
|
||||
else
|
||||
echo " ⊘ No Docker Compose files found"
|
||||
fi
|
||||
else
|
||||
echo " ⊘ Docker command not available"
|
||||
fi
|
||||
echo
|
||||
|
||||
# Collect individual app configurations from app_configs
|
||||
echo -e "${CYAN}=== Individual App Configs ===${NC}"
|
||||
mkdir -p "$OUTPUT_DIR/configs/apps/app_configs"
|
||||
if [[ -d /mnt/.ix-apps/app_configs ]]; then
|
||||
APP_COUNT=0
|
||||
for app_dir in /mnt/.ix-apps/app_configs/*; do
|
||||
if [[ -d "$app_dir" ]]; then
|
||||
APP_NAME=$(basename "$app_dir")
|
||||
mkdir -p "$OUTPUT_DIR/configs/apps/app_configs/$APP_NAME"
|
||||
|
||||
# Copy configuration files (YAML, JSON, ENV)
|
||||
sudo find "$app_dir" -maxdepth 2 -type f \( -name "*.yaml" -o -name "*.yml" -o -name "*.json" -o -name "*.env" -o -name "*.conf" \) \
|
||||
-exec cp {} "$OUTPUT_DIR/configs/apps/app_configs/$APP_NAME/" \; 2>/dev/null && \
|
||||
((APP_COUNT++)) || true
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $APP_COUNT -gt 0 ]]; then
|
||||
echo -e "${GREEN}✓${NC} Collected configs for $APP_COUNT apps"
|
||||
else
|
||||
echo " ⊘ No app configs found"
|
||||
fi
|
||||
else
|
||||
echo " ⊘ TrueNAS app_configs directory not found"
|
||||
fi
|
||||
echo
|
||||
|
||||
# Generate summary
|
||||
cat > "$OUTPUT_DIR/SUMMARY.md" << EOF
|
||||
# TrueNAS Apps & Docker Export Summary
|
||||
|
||||
**Date**: $(date '+%Y-%m-%d %H:%M:%S')
|
||||
**Host**: $(hostname)
|
||||
|
||||
## Docker Containers
|
||||
|
||||
$(if command -v docker &>/dev/null; then
|
||||
echo "- Running: $(sudo docker ps -q | wc -l)"
|
||||
echo "- Total: $(sudo docker ps -aq | wc -l)"
|
||||
echo ""
|
||||
echo "### Container List"
|
||||
echo ""
|
||||
sudo docker ps -a --format "- {{.Names}} ({{.Image}}) - {{.Status}}"
|
||||
else
|
||||
echo "Docker not available"
|
||||
fi)
|
||||
|
||||
## TrueNAS Apps
|
||||
|
||||
$(if [[ -d /mnt/.ix-apps ]]; then
|
||||
echo "- Apps directory: /mnt/.ix-apps"
|
||||
echo "- App configs: $(sudo ls /mnt/.ix-apps/app_configs 2>/dev/null | wc -l) apps"
|
||||
else
|
||||
echo "TrueNAS apps directory not found"
|
||||
fi)
|
||||
|
||||
## Files Collected
|
||||
|
||||
\`\`\`
|
||||
$(find "$OUTPUT_DIR" -type f | sed "s|$OUTPUT_DIR/||" | sort)
|
||||
\`\`\`
|
||||
EOF
|
||||
|
||||
# Create compressed archive
|
||||
echo -e "${CYAN}=== Creating Archive ===${NC}"
|
||||
ARCHIVE="/tmp/truenas-apps-export-${TIMESTAMP}.tar.gz"
|
||||
tar -czf "$ARCHIVE" -C /tmp "$(basename "$OUTPUT_DIR")" 2>/dev/null
|
||||
echo -e "${GREEN}✓${NC} Archive created: $ARCHIVE"
|
||||
echo -e "${GREEN}✓${NC} Size: $(du -h "$ARCHIVE" | cut -f1)"
|
||||
echo
|
||||
|
||||
echo -e "${CYAN}=====================================${NC}"
|
||||
echo -e "${CYAN}Collection Complete!${NC}"
|
||||
echo -e "${CYAN}=====================================${NC}"
|
||||
echo
|
||||
echo "Output directory: $OUTPUT_DIR"
|
||||
echo "Archive: $ARCHIVE"
|
||||
echo
|
||||
echo "Next steps:"
|
||||
echo "1. Download the archive to your workstation:"
|
||||
echo " scp truenas_admin@192.168.2.150:$ARCHIVE /home/jramos/truenas/disaster-recovery/"
|
||||
echo
|
||||
echo "2. Extract to your disaster-recovery folder:"
|
||||
echo " cd /home/jramos/truenas/disaster-recovery"
|
||||
echo " tar -xzf $(basename "$ARCHIVE")"
|
||||
echo
|
||||
@@ -286,6 +286,114 @@ main() {
|
||||
echo
|
||||
fi
|
||||
|
||||
# Docker/Apps Collection (all levels)
|
||||
echo -e "${CYAN}=== Docker & Apps ===${NC}"
|
||||
mkdir -p "$OUTPUT_DIR/exports/apps"
|
||||
mkdir -p "$OUTPUT_DIR/configs/apps"
|
||||
|
||||
# Detect SSH user (try common TrueNAS usernames)
|
||||
SSH_USER=""
|
||||
for user in root admin truenas_admin; do
|
||||
if command -v ssh &>/dev/null && ssh -o ConnectTimeout=5 -o BatchMode=yes "${user}@${TRUENAS_HOST}" "echo test" &>/dev/null 2>&1; then
|
||||
SSH_USER="$user"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Check if we can access Docker via SSH
|
||||
if [[ -n "$SSH_USER" ]]; then
|
||||
log INFO "SSH access available as ${SSH_USER}@${TRUENAS_HOST}"
|
||||
|
||||
# Docker containers (convert newline-delimited JSON to proper JSON array)
|
||||
if ssh "${SSH_USER}@${TRUENAS_HOST}" "command -v docker &>/dev/null && sudo docker ps -a --format '{{json .}}' 2>/dev/null | jq -s '.' 2>/dev/null || sudo docker ps -a --format '{{json .}}' 2>/dev/null | sed '1s/^/[/; \$!s/\$/,/; \$s/\$/]/'" > "$OUTPUT_DIR/exports/apps/docker-containers.json" 2>/dev/null && [[ -s "$OUTPUT_DIR/exports/apps/docker-containers.json" ]]; then
|
||||
log OK "Docker containers list"
|
||||
else
|
||||
log WARN "Docker containers (command failed or no containers)"
|
||||
fi
|
||||
|
||||
# Docker human-readable list
|
||||
if ssh "${SSH_USER}@${TRUENAS_HOST}" "command -v docker &>/dev/null && sudo docker ps -a 2>/dev/null" > "$OUTPUT_DIR/exports/apps/docker-containers.txt" 2>/dev/null && [[ -s "$OUTPUT_DIR/exports/apps/docker-containers.txt" ]]; then
|
||||
log OK "Docker containers (text format)"
|
||||
else
|
||||
log WARN "Docker containers text list (command failed)"
|
||||
fi
|
||||
|
||||
# Docker images
|
||||
if ssh "${SSH_USER}@${TRUENAS_HOST}" "command -v docker &>/dev/null && sudo docker images --format '{{json .}}' 2>/dev/null | jq -s '.' 2>/dev/null || sudo docker images --format '{{json .}}' 2>/dev/null | sed '1s/^/[/; \$!s/\$/,/; \$s/\$/]/'" > "$OUTPUT_DIR/exports/apps/docker-images.json" 2>/dev/null && [[ -s "$OUTPUT_DIR/exports/apps/docker-images.json" ]]; then
|
||||
log OK "Docker images"
|
||||
else
|
||||
log WARN "Docker images (command failed)"
|
||||
fi
|
||||
|
||||
# Docker networks
|
||||
if ssh "${SSH_USER}@${TRUENAS_HOST}" "command -v docker &>/dev/null && sudo docker network ls --format '{{json .}}' 2>/dev/null | jq -s '.' 2>/dev/null || sudo docker network ls --format '{{json .}}' 2>/dev/null | sed '1s/^/[/; \$!s/\$/,/; \$s/\$/]/'" > "$OUTPUT_DIR/exports/apps/docker-networks.json" 2>/dev/null && [[ -s "$OUTPUT_DIR/exports/apps/docker-networks.json" ]]; then
|
||||
log OK "Docker networks"
|
||||
else
|
||||
log WARN "Docker networks (command failed)"
|
||||
fi
|
||||
|
||||
# Docker volumes
|
||||
if ssh "${SSH_USER}@${TRUENAS_HOST}" "command -v docker &>/dev/null && sudo docker volume ls --format '{{json .}}' 2>/dev/null | jq -s '.' 2>/dev/null || sudo docker volume ls --format '{{json .}}' 2>/dev/null | sed '1s/^/[/; \$!s/\$/,/; \$s/\$/]/'" > "$OUTPUT_DIR/exports/apps/docker-volumes.json" 2>/dev/null && [[ -s "$OUTPUT_DIR/exports/apps/docker-volumes.json" ]]; then
|
||||
log OK "Docker volumes"
|
||||
else
|
||||
log WARN "Docker volumes (command failed)"
|
||||
fi
|
||||
|
||||
# TrueNAS app metadata
|
||||
if ssh "${SSH_USER}@${TRUENAS_HOST}" "sudo cat /mnt/.ix-apps/metadata.yaml 2>/dev/null" > "$OUTPUT_DIR/configs/apps/metadata.yaml" 2>/dev/null && [[ -s "$OUTPUT_DIR/configs/apps/metadata.yaml" ]]; then
|
||||
log OK "TrueNAS app metadata"
|
||||
else
|
||||
log WARN "TrueNAS app metadata (file not found)"
|
||||
fi
|
||||
|
||||
# TrueNAS user config
|
||||
if ssh "${SSH_USER}@${TRUENAS_HOST}" "sudo cat /mnt/.ix-apps/user_config.yaml 2>/dev/null" > "$OUTPUT_DIR/configs/apps/user_config.yaml" 2>/dev/null && [[ -s "$OUTPUT_DIR/configs/apps/user_config.yaml" ]]; then
|
||||
log OK "TrueNAS user config"
|
||||
else
|
||||
log WARN "TrueNAS user config (file not found)"
|
||||
fi
|
||||
|
||||
# App configs directory listing
|
||||
if ssh "${SSH_USER}@${TRUENAS_HOST}" "sudo ls -laR /mnt/.ix-apps/app_configs/ 2>/dev/null" > "$OUTPUT_DIR/exports/apps/app_configs_list.txt" 2>/dev/null && [[ -s "$OUTPUT_DIR/exports/apps/app_configs_list.txt" ]]; then
|
||||
log OK "App configs directory listing"
|
||||
else
|
||||
log WARN "App configs listing (directory not accessible)"
|
||||
fi
|
||||
|
||||
# Docker storage sizes
|
||||
if ssh "${SSH_USER}@${TRUENAS_HOST}" "sudo du -sh /mnt/.ix-apps/docker/* 2>/dev/null" > "$OUTPUT_DIR/exports/apps/docker_sizes.txt" 2>/dev/null && [[ -s "$OUTPUT_DIR/exports/apps/docker_sizes.txt" ]]; then
|
||||
log OK "Docker storage sizes"
|
||||
else
|
||||
log WARN "Docker storage sizes (directory not accessible)"
|
||||
fi
|
||||
else
|
||||
log WARN "Docker/Apps collection (SSH not configured - see manual collection instructions)"
|
||||
cat > "$OUTPUT_DIR/exports/apps/MANUAL_COLLECTION.md" << 'MANUAL_EOF'
|
||||
# Manual Docker/Apps Collection Instructions
|
||||
|
||||
SSH access is not configured. To collect Docker and app information, run these commands on your TrueNAS server:
|
||||
|
||||
```bash
|
||||
# 1. Export Docker containers
|
||||
sudo docker ps -a --format '{{json .}}' | jq -s '.' > /tmp/docker-containers.json
|
||||
|
||||
# 2. Export TrueNAS app metadata
|
||||
sudo cp /mnt/.ix-apps/metadata.yaml /tmp/
|
||||
sudo cp /mnt/.ix-apps/user_config.yaml /tmp/
|
||||
|
||||
# 3. List app configs
|
||||
sudo ls -laR /mnt/.ix-apps/app_configs/ > /tmp/app_configs_list.txt
|
||||
|
||||
# 4. Copy files to collection directory
|
||||
# Transfer these files to your disaster-recovery export
|
||||
```
|
||||
|
||||
Then copy the files to: exports/apps/
|
||||
MANUAL_EOF
|
||||
log INFO "Created manual collection instructions"
|
||||
fi
|
||||
echo
|
||||
|
||||
# Generate summary
|
||||
cat > "$OUTPUT_DIR/SUMMARY.md" << EOF
|
||||
# TrueNAS Scale Export Summary
|
||||
|
||||
Reference in New Issue
Block a user