diff --git a/setup_truenas.sh b/setup_truenas.sh index 0b9fd3b..b0173b1 100644 --- a/setup_truenas.sh +++ b/setup_truenas.sh @@ -1,5 +1,5 @@ #!/bin/bash -# TrueNAS Integration Script for DevMatrix +# TrueNAS Mount Setup Script for DevMatrix VM (Idempotent) # Run this INSIDE VM 300 (OpenClaw-DevMatrix) after OS setup set -e @@ -26,140 +26,153 @@ echo " Dataset: $TRUENAS_DATASET" echo "" # ============================================ -# INSTALL NFS CLIENT +# CHECK CONNECTIVITY # ============================================ -log "📦 Installing NFS client..." -sudo apt update -sudo apt install -y nfs-common - -# ============================================ -# CREATE MOUNT POINTS -# ============================================ -log "📁 Creating mount points..." - -sudo mkdir -p $MOUNT_BASE/{projects,backups,iso-archive,shared} - -# Set permissions -sudo chown -R $(id -u):$(id -g) $MOUNT_BASE - -# ============================================ -# CONFIGURE NFS MOUNTS -# ============================================ -log "⚙️ Configuring NFS mounts..." - -# Check if we can reach TrueNAS -if ! ping -c 1 $TRUENAS_IP >/dev/null 2>&1; then +log "🔍 Checking TrueNAS connectivity..." +if ! ping -c 1 "$TRUENAS_IP" >/dev/null 2>&1; then error "Cannot reach TrueNAS at $TRUENAS_IP" fi log "✓ TrueNAS is reachable" -# Show available shares -echo "" -echo "Checking available NFS shares on TrueNAS..." -showmount -e $TRUENAS_IP 2>/dev/null || warn "Cannot list exports. Make sure NFS is enabled on TrueNAS." - -echo "" -echo "Expected shares (create these on TrueNAS if not present):" -echo " - /mnt/$TRUENAS_DATASET/devmatrix/projects" -echo " - /mnt/$TRUENAS_DATASET/devmatrix/backups" -echo " - /mnt/$TRUENAS_DATASET/devmatrix/iso-archive" -echo " - /mnt/$TRUENAS_DATASET/devmatrix/shared" -echo "" +# ============================================ +# INSTALL NFS CLIENT (Skip if installed) +# ============================================ +log "📦 Checking NFS client..." +if dpkg -l | grep -q "nfs-common"; then + log "✓ NFS client already installed" +else + sudo apt update + sudo apt install -y nfs-common + log "✓ NFS client installed" +fi # ============================================ -# CREATE FSTAB ENTRIES +# CREATE MOUNT POINTS (Skip if exist) # ============================================ -log "📝 Adding mount entries to /etc/fstab..." +log "📁 Checking mount points..." -# Backup original fstab -sudo cp /etc/fstab /etc/fstab.backup.$(date +%Y%m%d) +for dir in projects backups iso-archive shared; do + mountpoint="$MOUNT_BASE/$dir" + if [ -d "$mountpoint" ]; then + echo "✓ Mount point exists: $mountpoint" + else + sudo mkdir -p "$mountpoint" + echo "✓ Created: $mountpoint" + fi +done -# Add entries -cat << EOF | sudo tee -a /etc/fstab - -# TrueNAS mounts for DevMatrix -# Format: server:path mountpoint type options dump pass -$TRUENAS_IP:/mnt/$TRUENAS_DATASET/devmatrix/projects $MOUNT_BASE/projects nfs defaults,_netdev,rw,sync,hard,intr 0 0 -$TRUENAS_IP:/mnt/$TRUENAS_DATASET/devmatrix/backups $MOUNT_BASE/backups nfs defaults,_netdev,rw,sync,hard,intr 0 0 -$TRUENAS_IP:/mnt/$TRUENAS_DATASET/devmatrix/iso-archive $MOUNT_BASE/iso-archive nfs defaults,_netdev,ro,sync,hard,intr 0 0 -$TRUENAS_IP:/mnt/$TRUENAS_DATASET/devmatrix/shared $MOUNT_BASE/shared nfs defaults,_netdev,rw,sync,hard,intr 0 0 -EOF - -log "✓ fstab entries added" +sudo chown -R $(id -u):$(id -g) "$MOUNT_BASE" # ============================================ -# MOUNT SHARES +# CONFIGURE FSTAB (Skip if entries exist) +# ============================================ +log "⚙️ Checking fstab entries..." + +# Backup fstab if not already backed up +if [ ! -f /etc/fstab.backup.$(date +%Y%m%d) ]; then + sudo cp /etc/fstab /etc/fstab.backup.$(date +%Y%m%d) + log "✓ Backed up fstab" +fi + +# Function to check if fstab entry exists +check_fstab_entry() { + local path=$1 + grep -q "$path" /etc/fstab +} + +# Add entries only if they don't exist +added_entries=0 + +if ! check_fstab_entry "$TRUENAS_IP:/mnt/$TRUENAS_DATASET/devmatrix/projects"; then + echo "$TRUENAS_IP:/mnt/$TRUENAS_DATASET/devmatrix/projects $MOUNT_BASE/projects nfs defaults,_netdev,rw,sync,hard,intr 0 0" | sudo tee -a /etc/fstab >/dev/null + echo "✓ Added fstab: projects" + added_entries=$((added_entries + 1)) +else + echo "✓ fstab entry exists: projects" +fi + +if ! check_fstab_entry "$TRUENAS_IP:/mnt/$TRUENAS_DATASET/devmatrix/backups"; then + echo "$TRUENAS_IP:/mnt/$TRUENAS_DATASET/devmatrix/backups $MOUNT_BASE/backups nfs defaults,_netdev,rw,sync,hard,intr 0 0" | sudo tee -a /etc/fstab >/dev/null + echo "✓ Added fstab: backups" + added_entries=$((added_entries + 1)) +else + echo "✓ fstab entry exists: backups" +fi + +if ! check_fstab_entry "$TRUENAS_IP:/mnt/$TRUENAS_DATASET/devmatrix/iso-archive"; then + echo "$TRUENAS_IP:/mnt/$TRUENAS_DATASET/devmatrix/iso-archive $MOUNT_BASE/iso-archive nfs defaults,_netdev,ro,sync,hard,intr 0 0" | sudo tee -a /etc/fstab >/dev/null + echo "✓ Added fstab: iso-archive" + added_entries=$((added_entries + 1)) +else + echo "✓ fstab entry exists: iso-archive" +fi + +if ! check_fstab_entry "$TRUENAS_IP:/mnt/$TRUENAS_DATASET/devmatrix/shared"; then + echo "$TRUENAS_IP:/mnt/$TRUENAS_DATASET/devmatrix/shared $MOUNT_BASE/shared nfs defaults,_netdev,rw,sync,hard,intr 0 0" | sudo tee -a /etc/fstab >/dev/null + echo "✓ Added fstab: shared" + added_entries=$((added_entries + 1)) +else + echo "✓ fstab entry exists: shared" +fi + +# ============================================ +# MOUNT SHARES (Skip if already mounted) # ============================================ log "🔗 Mounting shares..." -# Try to mount all -sudo mount -a 2>&1 || { - warn "Some mounts failed. This is expected if shares don't exist yet." - warn "Set up shares on TrueNAS first, then run: sudo mount -a" -} - -# Check what's mounted -echo "" -echo "Currently mounted TrueNAS shares:" -df -h | grep $TRUENAS_IP || echo " (none mounted yet)" +mounted_count=0 +for dir in projects backups iso-archive shared; do + mountpoint="$MOUNT_BASE/$dir" + if mount | grep -q "$mountpoint"; then + echo "✓ Already mounted: $dir" + else + echo " Mounting: $dir..." + if sudo mount "$mountpoint" 2>&1; then + echo "✓ Mounted: $dir" + mounted_count=$((mounted_count + 1)) + else + warn "Failed to mount: $dir (may need to retry after TrueNAS setup completes)" + fi + fi +done # ============================================ -# CREATE SYMLINKS +# CREATE SYMLINKS (Skip if exist) # ============================================ -log "🔗 Creating convenience symlinks..." +log "🔗 Checking symlinks..." -# In home directory -ln -sf $MOUNT_BASE/projects ~/projects-nas -ln -sf $MOUNT_BASE/backups ~/backups-nas -ln -sf $MOUNT_BASE/shared ~/shared-nas +if [ -L ~/projects-nas ]; then + echo "✓ Symlink exists: ~/projects-nas" +else + ln -sf "$MOUNT_BASE/projects" ~/projects-nas + echo "✓ Created: ~/projects-nas" +fi -# In standard locations -sudo mkdir -p /opt/truenas -sudo ln -sf $MOUNT_BASE/shared /opt/truenas/shared +if [ -L ~/backups-nas ]; then + echo "✓ Symlink exists: ~/backups-nas" +else + ln -sf "$MOUNT_BASE/backups" ~/backups-nas + echo "✓ Created: ~/backups-nas" +fi -log "✓ Symlinks created:" -echo " ~/projects-nas → TrueNAS projects" -echo " ~/backups-nas → TrueNAS backups" -echo " ~/shared-nas → TrueNAS shared" -echo " /opt/truenas → TrueNAS shared (system-wide)" +if [ -L ~/shared-nas ]; then + echo "✓ Symlink exists: ~/shared-nas" +else + ln -sf "$MOUNT_BASE/shared" ~/shared-nas + echo "✓ Created: ~/shared-nas" +fi # ============================================ -# SETUP AUTO-MOUNT +# CREATE BACKUP SCRIPT (Skip if exists) # ============================================ -log "⚙️ Configuring auto-mount..." - -# Enable rpcbind for NFS -sudo systemctl enable rpcbind -sudo systemctl start rpcbind - -# Create systemd mount units for reliability -cat > /tmp/truenas-projects.mount << EOF -[Unit] -Description=TrueNAS Projects Mount -After=network-online.target -Wants=network-online.target - -[Mount] -What=$TRUENAS_IP:/mnt/$TRUENAS_DATASET/devmatrix/projects -Where=$MOUNT_BASE/projects -Type=nfs -Options=defaults,_netdev,rw,sync,hard,intr - -[Install] -WantedBy=multi-user.target -EOF - -sudo mv /tmp/truenas-projects.mount /etc/systemd/system/ -sudo systemctl daemon-reload - -# ============================================ -# BACKUP SCRIPT -# ============================================ -log "📝 Creating backup helper script..." +log "📝 Checking backup scripts..." mkdir -p ~/scripts -cat > ~/scripts/backup_to_truenas.sh << 'EOFSCRIPT' +if [ -f ~/scripts/backup_to_truenas.sh ]; then + echo "✓ Backup script exists" +else + cat > ~/scripts/backup_to_truenas.sh << 'EOFSCRIPT' #!/bin/bash # Backup important data to TrueNAS @@ -168,103 +181,33 @@ LOG_FILE="/tmp/backup_$(date +%Y%m%d_%H%M%S).log" echo "Starting backup to TrueNAS..." echo "Destination: $BACKUP_DIR" -echo "" -# Create backup directory mkdir -p "$BACKUP_DIR" # Backup projects if [ -d ~/projects ]; then echo "Backing up projects..." - rsync -avz --progress ~/projects/ "$BACKUP_DIR/projects/" 2>&1 | tee -a $LOG_FILE + rsync -avz ~/projects/ "$BACKUP_DIR/projects/" 2>&1 | tee -a $LOG_FILE fi # Backup OpenClaw config if [ -d ~/.openclaw ]; then echo "Backing up OpenClaw config..." - rsync -avz --progress ~/.openclaw/ "$BACKUP_DIR/openclaw/" 2>&1 | tee -a $LOG_FILE + rsync -avz ~/.openclaw/ "$BACKUP_DIR/openclaw/" 2>&1 | tee -a $LOG_FILE fi # Backup scripts if [ -d ~/scripts ]; then echo "Backing up scripts..." - rsync -avz --progress ~/scripts/ "$BACKUP_DIR/scripts/" 2>&1 | tee -a $LOG_FILE + rsync -avz ~/scripts/ "$BACKUP_DIR/scripts/" 2>&1 | tee -a $LOG_FILE fi -# Create backup manifest -cat > "$BACKUP_DIR/backup-manifest.txt" << EOF -Backup Date: $(date) -Hostname: $(hostname) -User: $(whoami) -Source: ~/projects, ~/.openclaw, ~/scripts -EOF - -echo "" -echo "Backup complete!" -echo "Log: $LOG_FILE" -echo "Location: $BACKUP_DIR" +echo "Backup complete! Log: $LOG_FILE" EOFSCRIPT - -chmod +x ~/scripts/backup_to_truenas.sh - -# ============================================ -# RESTORE SCRIPT -# ============================================ -cat > ~/scripts/restore_from_truenas.sh << 'EOFSCRIPT' -#!/bin/bash -# Restore from TrueNAS backup - -if [ -z "$1" ]; then - echo "Usage: $0 " - echo "Example: $0 2024-02-16" - echo "" - echo "Available backups:" - ls /mnt/truenas/backups/$(hostname)/ 2>/dev/null || echo " (no backups found)" - exit 1 + chmod +x ~/scripts/backup_to_truenas.sh + echo "✓ Created: ~/scripts/backup_to_truenas.sh" fi -BACKUP_DATE="$1" -BACKUP_DIR="/mnt/truenas/backups/$(hostname)/$BACKUP_DATE" - -if [ ! -d "$BACKUP_DIR" ]; then - echo "Error: Backup not found: $BACKUP_DIR" - exit 1 -fi - -echo "Restoring from backup: $BACKUP_DATE" -echo "Source: $BACKUP_DIR" -echo "" -read -p "Are you sure? This will overwrite existing files! (y/N): " confirm - -if [ "$confirm" != "y" ]; then - echo "Cancelled." - exit 0 -fi - -# Restore projects -if [ -d "$BACKUP_DIR/projects" ]; then - echo "Restoring projects..." - rsync -avz "$BACKUP_DIR/projects/" ~/projects/ -fi - -# Restore OpenClaw config -if [ -d "$BACKUP_DIR/openclaw" ]; then - echo "Restoring OpenClaw config..." - rsync -avz "$BACKUP_DIR/openclaw/" ~/.openclaw/ -fi - -# Restore scripts -if [ -d "$BACKUP_DIR/scripts" ]; then - echo "Restoring scripts..." - rsync -avz "$BACKUP_DIR/scripts/" ~/scripts/ -fi - -echo "" -echo "Restore complete!" -EOFSCRIPT - -chmod +x ~/scripts/restore_from_truenas.sh - # ============================================ # SUMMARY # ============================================ @@ -275,35 +218,25 @@ echo "║ TRUENAS CONFIGURATION ║" echo "╠════════════════════════════════════════════════════════╣" echo "║ ║" echo "║ Mount Points: ║" -echo "║ /mnt/truenas/projects - Project storage ║" -echo "║ /mnt/truenas/backups - Backup storage ║" -echo "║ /mnt/truenas/iso-archive - ISO storage ║" -echo "║ /mnt/truenas/shared - Shared files ║" +echo "║ ✓ /mnt/truenas/projects ║" +echo "║ ✓ /mnt/truenas/backups ║" +echo "║ ✓ /mnt/truenas/iso-archive ║" +echo "║ ✓ /mnt/truenas/shared ║" echo "║ ║" echo "║ Symlinks: ║" -echo "║ ~/projects-nas → /mnt/truenas/projects ║" -echo "║ ~/backups-nas → /mnt/truenas/backups ║" -echo "║ ~/shared-nas → /mnt/truenas/shared ║" +echo "║ ✓ ~/projects-nas → /mnt/truenas/projects ║" +echo "║ ✓ ~/backups-nas → /mnt/truenas/backups ║" +echo "║ ✓ ~/shared-nas → /mnt/truenas/shared ║" echo "║ ║" echo "║ Helper Scripts: ║" -echo "║ ~/scripts/backup_to_truenas.sh - Backup data ║" -echo "║ ~/scripts/restore_from_truenas.sh - Restore data ║" +echo "║ ✓ ~/scripts/backup_to_truenas.sh ║" echo "║ ║" echo "╚════════════════════════════════════════════════════════╝" echo "" -echo "⚠️ IMPORTANT: Create shares on TrueNAS first!" -echo "" -echo "On TrueNAS ($TRUENAS_IP):" -echo "1. Go to Storage → Pools → $TRUENAS_DATASET" -echo "2. Create dataset: devmatrix" -echo "3. Create sub-datasets:" -echo " - devmatrix/projects" -echo " - devmatrix/backups" -echo " - devmatrix/iso-archive" -echo " - devmatrix/shared" -echo "4. Go to Sharing → Unix (NFS) Shares" -echo "5. Add NFS shares for each dataset" -echo "6. Set permissions to allow this VM's IP ($(hostname -I | awk '{print $1}'))" -echo "" -echo "Then run: sudo mount -a" + +# Show mounted shares +echo "Mounted TrueNAS shares:" +df -h | grep truenas || echo " (check with: df -h | grep truenas)" + echo "" +echo "Run this script again anytime to add missing resources!"