ok... ok... I'll add it to git...
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
# Maintenance Scripts
|
||||
|
||||
This directory contains shell scripts for common maintenance tasks.
|
||||
|
||||
## Available Scripts
|
||||
|
||||
| Script | Description | Usage |
|
||||
|--------|-------------|-------|
|
||||
| `gpu-check.sh` | Verify GPU passthrough in containers | `./scripts/gpu-check.sh` |
|
||||
| `health-check.sh` | Check all services and report status | `./scripts/health-check.sh` |
|
||||
| `setup-kuma-monitors.sh` | Manual guide for configuring Uptime Kuma monitors | `./scripts/setup-kuma-monitors.sh` |
|
||||
| `setup-kuma-monitors.py` | **Automated** Uptime Kuma monitor setup via API | `source .venv/bin/activate && python3 scripts/setup-kuma-monitors.py` |
|
||||
| `backup-configs.sh` | Backup all Docker configs | `./scripts/backup-configs.sh` |
|
||||
| `disk-usage.sh` | Report disk usage for SSD and HDD | `./scripts/disk-usage.sh` |
|
||||
| `update-stacks.sh` | Pull latest images and update containers | `./scripts/update-stacks.sh <stack-name>` |
|
||||
| `cleanup.sh` | Clean up unused Docker resources | `./scripts/cleanup.sh` |
|
||||
|
||||
## Making Scripts Executable
|
||||
|
||||
```bash
|
||||
# Make all scripts executable
|
||||
chmod +x scripts/*.sh
|
||||
|
||||
# Or individually
|
||||
chmod +x scripts/health-check.sh
|
||||
```
|
||||
|
||||
## Scheduling with Cron
|
||||
|
||||
Add to crontab for automated maintenance:
|
||||
|
||||
```bash
|
||||
# Edit crontab
|
||||
crontab -e
|
||||
|
||||
# Examples:
|
||||
# Daily health check at 8 AM
|
||||
0 8 * * * /home/jpmschweitzer/Projects/tower-of-joy/scripts/health-check.sh >> /var/log/tower-of-joy-health.log 2>&1
|
||||
|
||||
# Weekly cleanup on Sunday at 3 AM
|
||||
0 3 * * 0 /home/jpmschweitzer/Projects/tower-of-joy/scripts/cleanup.sh
|
||||
|
||||
# Daily backup at 2 AM
|
||||
0 2 * * * /home/jpmschweitzer/Projects/tower-of-joy/scripts/backup-configs.sh
|
||||
```
|
||||
|
||||
## Script Guidelines
|
||||
|
||||
- All scripts should include error handling
|
||||
- Use absolute paths for reliability
|
||||
- Log output for debugging
|
||||
- Exit with appropriate status codes (0 = success, non-zero = failure)
|
||||
- Include help text with `-h` or `--help` flags
|
||||
File diff suppressed because it is too large
Load Diff
Executable
+74
@@ -0,0 +1,74 @@
|
||||
#!/bin/bash
|
||||
# Backup Docker Configurations Script
|
||||
# Creates timestamped backup of all Docker configs
|
||||
|
||||
set -e
|
||||
|
||||
BACKUP_DIR="/mnt/media/backups/tower-of-joy-configs"
|
||||
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
||||
BACKUP_PATH="${BACKUP_DIR}/backup_${TIMESTAMP}"
|
||||
SOURCE_DIR="/home/jpmschweitzer/docker-data"
|
||||
|
||||
echo "=== Docker Configs Backup ==="
|
||||
echo "Timestamp: $(date)"
|
||||
echo ""
|
||||
|
||||
# Check if source exists
|
||||
if [ ! -d "$SOURCE_DIR" ]; then
|
||||
echo "❌ Source directory not found: $SOURCE_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create backup directory
|
||||
echo "[1/4] Creating backup directory..."
|
||||
mkdir -p "$BACKUP_PATH"
|
||||
echo "✅ Created: $BACKUP_PATH"
|
||||
echo ""
|
||||
|
||||
# Backup Docker configs
|
||||
echo "[2/4] Backing up Docker configs..."
|
||||
rsync -av --progress "$SOURCE_DIR/" "$BACKUP_PATH/" --exclude='cache' --exclude='*.log'
|
||||
echo "✅ Configs backed up"
|
||||
echo ""
|
||||
|
||||
# Backup stack files
|
||||
echo "[3/4] Backing up stack definitions..."
|
||||
mkdir -p "$BACKUP_PATH/stacks"
|
||||
cp -r /home/jpmschweitzer/Projects/tower-of-joy/stacks/*.yml "$BACKUP_PATH/stacks/" 2>/dev/null || true
|
||||
echo "✅ Stack files backed up"
|
||||
echo ""
|
||||
|
||||
# Create backup manifest
|
||||
echo "[4/4] Creating backup manifest..."
|
||||
cat > "$BACKUP_PATH/MANIFEST.txt" << EOF
|
||||
Backup created: $(date)
|
||||
Hostname: $(hostname)
|
||||
Docker version: $(docker --version)
|
||||
Containers backed up:
|
||||
$(docker ps --format ' - {{.Names}} ({{.Image}})')
|
||||
|
||||
Backup size: $(du -sh "$BACKUP_PATH" | cut -f1)
|
||||
EOF
|
||||
echo "✅ Manifest created"
|
||||
echo ""
|
||||
|
||||
# Cleanup old backups (keep last 30 days)
|
||||
echo "[Cleanup] Removing backups older than 30 days..."
|
||||
find "$BACKUP_DIR" -maxdepth 1 -type d -name "backup_*" -mtime +30 -exec rm -rf {} \; 2>/dev/null || true
|
||||
remaining=$(find "$BACKUP_DIR" -maxdepth 1 -type d -name "backup_*" | wc -l)
|
||||
echo "✅ Kept $remaining recent backups"
|
||||
echo ""
|
||||
|
||||
echo "=== Backup Complete ==="
|
||||
echo "Location: $BACKUP_PATH"
|
||||
echo "Size: $(du -sh "$BACKUP_PATH" | cut -f1)"
|
||||
echo ""
|
||||
|
||||
# Verify backup
|
||||
if [ -d "$BACKUP_PATH" ] && [ -f "$BACKUP_PATH/MANIFEST.txt" ]; then
|
||||
echo "✅ Backup verification passed"
|
||||
exit 0
|
||||
else
|
||||
echo "❌ Backup verification failed"
|
||||
exit 1
|
||||
fi
|
||||
Executable
+72
@@ -0,0 +1,72 @@
|
||||
#!/bin/bash
|
||||
# Docker Cleanup Script
|
||||
# Safely removes unused containers, images, volumes, and networks
|
||||
|
||||
set -e
|
||||
|
||||
echo "=== Docker Cleanup ==="
|
||||
echo "$(date)"
|
||||
echo ""
|
||||
|
||||
# Show current usage
|
||||
echo "[Current Docker Disk Usage]"
|
||||
docker system df
|
||||
echo ""
|
||||
|
||||
# Ask for confirmation
|
||||
echo "This will remove:"
|
||||
echo " - Stopped containers"
|
||||
echo " - Unused networks"
|
||||
echo " - Dangling images"
|
||||
echo " - Build cache"
|
||||
echo ""
|
||||
read -p "Continue? (y/N) " -n 1 -r
|
||||
echo
|
||||
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo "Cleanup cancelled"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "[1/4] Removing stopped containers..."
|
||||
docker container prune -f
|
||||
echo "✅ Done"
|
||||
echo ""
|
||||
|
||||
echo "[2/4] Removing unused networks..."
|
||||
docker network prune -f
|
||||
echo "✅ Done"
|
||||
echo ""
|
||||
|
||||
echo "[3/4] Removing dangling images..."
|
||||
docker image prune -f
|
||||
echo "✅ Done"
|
||||
echo ""
|
||||
|
||||
echo "[4/4] Removing build cache..."
|
||||
docker builder prune -f
|
||||
echo "✅ Done"
|
||||
echo ""
|
||||
|
||||
# Ask about unused images
|
||||
echo ""
|
||||
echo "[Optional] Remove ALL unused images (not just dangling)?"
|
||||
echo "⚠️ This removes images not used by any container"
|
||||
read -p "Remove unused images? (y/N) " -n 1 -r
|
||||
echo
|
||||
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo "Removing all unused images..."
|
||||
docker image prune -a -f
|
||||
echo "✅ Done"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "[New Docker Disk Usage]"
|
||||
docker system df
|
||||
echo ""
|
||||
|
||||
echo "=== Cleanup Complete ==="
|
||||
echo ""
|
||||
echo "Tip: Run 'docker volume prune' to remove unused volumes (use with caution!)"
|
||||
Executable
+65
@@ -0,0 +1,65 @@
|
||||
#!/bin/bash
|
||||
# Disk Usage Report Script
|
||||
# Shows detailed disk usage for SSD and HDD
|
||||
|
||||
echo "=== Disk Usage Report ==="
|
||||
echo "$(date)"
|
||||
echo ""
|
||||
|
||||
# Overall disk usage
|
||||
echo "[Overall Disk Usage]"
|
||||
df -h / /mnt/media 2>/dev/null || df -h /
|
||||
echo ""
|
||||
|
||||
# SSD usage breakdown
|
||||
echo "[SSD - Docker Configs] (/home/jpmschweitzer/docker-data)"
|
||||
if [ -d "/home/jpmschweitzer/docker-data" ]; then
|
||||
du -sh /home/jpmschweitzer/docker-data/* 2>/dev/null | sort -hr | head -10
|
||||
else
|
||||
echo "Directory not found"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# HDD usage breakdown
|
||||
echo "[HDD - Media Content] (/mnt/media)"
|
||||
if [ -d "/mnt/media" ]; then
|
||||
du -sh /mnt/media/* 2>/dev/null | sort -hr
|
||||
else
|
||||
echo "⚠️ Media drive not mounted!"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Docker system usage
|
||||
echo "[Docker System Usage]"
|
||||
docker system df
|
||||
echo ""
|
||||
|
||||
# Largest containers
|
||||
echo "[Largest Containers]"
|
||||
docker ps --size --format "table {{.Names}}\t{{.Size}}" | head -11
|
||||
echo ""
|
||||
|
||||
# Warn if getting full
|
||||
ssd_percent=$(df /home/jpmschweitzer/docker-data 2>/dev/null | awk 'NR==2 {print $5}' | sed 's/%//')
|
||||
hdd_percent=$(df /mnt/media 2>/dev/null | awk 'NR==2 {print $5}' | sed 's/%//')
|
||||
|
||||
echo "[Warnings]"
|
||||
if [ -n "$ssd_percent" ] && [ "$ssd_percent" -gt 85 ]; then
|
||||
echo "⚠️ SSD is ${ssd_percent}% full - consider cleanup!"
|
||||
fi
|
||||
|
||||
if [ -n "$hdd_percent" ] && [ "$hdd_percent" -gt 85 ]; then
|
||||
echo "⚠️ HDD is ${hdd_percent}% full - consider cleanup!"
|
||||
fi
|
||||
|
||||
if [ -z "$hdd_percent" ]; then
|
||||
echo "❌ Media drive not mounted at /mnt/media!"
|
||||
fi
|
||||
|
||||
# Suggestions
|
||||
echo ""
|
||||
echo "[Cleanup Suggestions]"
|
||||
echo "- Clean Docker: ./scripts/cleanup.sh"
|
||||
echo "- Remove old images: docker image prune -a"
|
||||
echo "- Check large files: du -sh /mnt/media/* | sort -hr"
|
||||
echo ""
|
||||
Executable
+60
@@ -0,0 +1,60 @@
|
||||
#!/bin/bash
|
||||
# GPU Passthrough Verification Script
|
||||
# Checks GPU accessibility in Docker and in GPU-enabled containers
|
||||
|
||||
set -e
|
||||
|
||||
echo "=== GPU Passthrough Check ==="
|
||||
echo ""
|
||||
|
||||
# Check if nvidia-smi is available on host
|
||||
echo "[1/4] Checking NVIDIA driver on host..."
|
||||
if command -v nvidia-smi &> /dev/null; then
|
||||
nvidia-smi --query-gpu=name,driver_version,memory.total --format=csv,noheader
|
||||
echo "✅ NVIDIA driver detected"
|
||||
else
|
||||
echo "❌ nvidia-smi not found on host"
|
||||
exit 1
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Check if NVIDIA Container Toolkit is installed
|
||||
echo "[2/4] Checking NVIDIA Container Toolkit..."
|
||||
if docker run --rm --gpus all nvidia/cuda:11.4.0-base-ubuntu20.04 nvidia-smi &> /dev/null; then
|
||||
echo "✅ NVIDIA Container Toolkit working"
|
||||
else
|
||||
echo "❌ NVIDIA Container Toolkit not working"
|
||||
echo " Install with: sudo apt install nvidia-container-toolkit"
|
||||
exit 1
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Check GPU in Ollama container (if running)
|
||||
echo "[3/4] Checking GPU in Ollama container..."
|
||||
if docker ps --format '{{.Names}}' | grep -q "^ollama$"; then
|
||||
if docker exec ollama nvidia-smi &> /dev/null; then
|
||||
echo "✅ Ollama has GPU access"
|
||||
docker exec ollama nvidia-smi --query-gpu=name,utilization.gpu,memory.used --format=csv,noheader
|
||||
else
|
||||
echo "⚠️ Ollama running but no GPU access"
|
||||
fi
|
||||
else
|
||||
echo "⚠️ Ollama container not running"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Check GPU in Jellyfin container (if running)
|
||||
echo "[4/4] Checking GPU in Jellyfin container..."
|
||||
if docker ps --format '{{.Names}}' | grep -q "^jellyfin$"; then
|
||||
if docker exec jellyfin nvidia-smi &> /dev/null; then
|
||||
echo "✅ Jellyfin has GPU access"
|
||||
docker exec jellyfin nvidia-smi --query-gpu=name,utilization.gpu,memory.used --format=csv,noheader
|
||||
else
|
||||
echo "⚠️ Jellyfin running but no GPU access"
|
||||
fi
|
||||
else
|
||||
echo "⚠️ Jellyfin container not running"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "=== GPU Check Complete ==="
|
||||
Executable
+197
@@ -0,0 +1,197 @@
|
||||
#!/bin/bash
|
||||
# GPU Docker Passthrough - Clean Slate Fix Script
|
||||
# Removes messy configs and installs working nvidia-container-toolkit version
|
||||
|
||||
set -e
|
||||
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
echo -e "${BLUE}╔═══════════════════════════════════════════════════════╗${NC}"
|
||||
echo -e "${BLUE}║ GPU Docker Passthrough - Clean Slate Fix ║${NC}"
|
||||
echo -e "${BLUE}╚═══════════════════════════════════════════════════════╝${NC}"
|
||||
echo ""
|
||||
|
||||
# Check if running as root
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo -e "${RED}✗ Please run as root (use sudo)${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}==> Phase 1: Cleanup${NC}"
|
||||
echo ""
|
||||
|
||||
# Remove all our backup files
|
||||
echo "Removing config backups..."
|
||||
rm -f /etc/nvidia-container-runtime/config.toml.backup*
|
||||
rm -f /etc/docker/daemon.json.backup*
|
||||
echo -e "${GREEN}✓ Removed config backups${NC}"
|
||||
|
||||
# Remove our test scripts (keep the final ones)
|
||||
echo "Cleaning up test scripts..."
|
||||
rm -f /home/jpmschweitzer/Projects/tower-of-joy/scripts/fix-gpu-docker.py
|
||||
rm -f /home/jpmschweitzer/Projects/tower-of-joy/scripts/diagnose-gpu-error.py
|
||||
rm -f /home/jpmschweitzer/Projects/tower-of-joy/scripts/fix-gpu-csv-mode.py
|
||||
rm -f /home/jpmschweitzer/Projects/tower-of-joy/scripts/try-nvidia-docker2.sh
|
||||
echo -e "${GREEN}✓ Cleaned up test scripts${NC}"
|
||||
|
||||
echo ""
|
||||
echo -e "${BLUE}==> Phase 2: Check Available Versions${NC}"
|
||||
echo ""
|
||||
|
||||
# Check what versions are available
|
||||
echo "Checking available nvidia-container-toolkit versions..."
|
||||
apt-cache policy nvidia-container-toolkit
|
||||
|
||||
echo ""
|
||||
read -p "Do you see version 1.17.x or 1.16.x in the list above? (y/n) " -n 1 -r
|
||||
echo ""
|
||||
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo ""
|
||||
echo -e "${BLUE}==> Phase 3: Downgrade to Compatible Version${NC}"
|
||||
echo ""
|
||||
|
||||
# Get the version from user
|
||||
echo "Available versions from list above:"
|
||||
apt-cache madison nvidia-container-toolkit | head -5
|
||||
echo ""
|
||||
read -p "Enter the version to install (e.g., 1.17.2-1): " VERSION
|
||||
|
||||
echo ""
|
||||
echo "Removing nvidia-container-toolkit 1.18..."
|
||||
apt-get remove -y nvidia-container-toolkit || true
|
||||
|
||||
echo ""
|
||||
echo "Installing nvidia-container-toolkit version $VERSION..."
|
||||
apt-get install -y nvidia-container-toolkit=$VERSION
|
||||
|
||||
echo ""
|
||||
echo "Holding package to prevent auto-upgrade..."
|
||||
apt-mark hold nvidia-container-toolkit
|
||||
|
||||
echo -e "${GREEN}✓ Installed nvidia-container-toolkit $VERSION${NC}"
|
||||
|
||||
else
|
||||
echo ""
|
||||
echo -e "${YELLOW}⚠ Version 1.17/1.16 not available. Configuring 1.18 for legacy mode...${NC}"
|
||||
echo ""
|
||||
|
||||
# Configure 1.18 properly for legacy mode
|
||||
CONFIG_FILE="/etc/nvidia-container-runtime/config.toml"
|
||||
|
||||
# Backup original
|
||||
cp $CONFIG_FILE ${CONFIG_FILE}.original
|
||||
|
||||
# Update config for legacy mode with proper settings
|
||||
cat > $CONFIG_FILE << 'EOF'
|
||||
disable-require = false
|
||||
supported-driver-capabilities = "compat32,compute,display,graphics,ngx,utility,video"
|
||||
|
||||
[nvidia-container-cli]
|
||||
environment = []
|
||||
ldcache = "/etc/ld.so.cache"
|
||||
ldconfig = "@/sbin/ldconfig.real"
|
||||
load-kmods = true
|
||||
|
||||
[nvidia-container-runtime]
|
||||
log-level = "info"
|
||||
mode = "legacy"
|
||||
runtimes = ["runc", "crun"]
|
||||
|
||||
[nvidia-container-runtime.modes.legacy]
|
||||
cuda-compat-mode = "ldconfig"
|
||||
|
||||
[nvidia-container-runtime-hook]
|
||||
path = "nvidia-container-runtime-hook"
|
||||
skip-mode-detection = false
|
||||
|
||||
[nvidia-ctk]
|
||||
path = "nvidia-ctk"
|
||||
EOF
|
||||
|
||||
echo -e "${GREEN}✓ Configured nvidia-container-runtime for legacy mode${NC}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e "${BLUE}==> Phase 4: Configure Docker${NC}"
|
||||
echo ""
|
||||
|
||||
# Create minimal Docker daemon.json
|
||||
DAEMON_JSON="/etc/docker/daemon.json"
|
||||
cp $DAEMON_JSON ${DAEMON_JSON}.original 2>/dev/null || true
|
||||
|
||||
cat > $DAEMON_JSON << 'EOF'
|
||||
{
|
||||
"runtimes": {
|
||||
"nvidia": {
|
||||
"path": "nvidia-container-runtime",
|
||||
"args": []
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
echo -e "${GREEN}✓ Updated Docker daemon.json${NC}"
|
||||
|
||||
# Run nvidia-ctk configure
|
||||
echo ""
|
||||
echo "Running nvidia-ctk runtime configure..."
|
||||
nvidia-ctk runtime configure --runtime=docker --config=$DAEMON_JSON
|
||||
|
||||
# Rebuild library cache
|
||||
echo ""
|
||||
echo "Rebuilding library cache..."
|
||||
ldconfig
|
||||
|
||||
echo -e "${GREEN}✓ Configuration complete${NC}"
|
||||
|
||||
echo ""
|
||||
echo -e "${BLUE}==> Phase 5: Restart Docker${NC}"
|
||||
echo ""
|
||||
|
||||
systemctl restart docker
|
||||
sleep 3
|
||||
|
||||
echo -e "${GREEN}✓ Docker restarted${NC}"
|
||||
|
||||
echo ""
|
||||
echo -e "${BLUE}==> Phase 6: Test GPU Access${NC}"
|
||||
echo ""
|
||||
|
||||
echo "Testing GPU access in Docker container..."
|
||||
echo ""
|
||||
|
||||
if docker run --rm --gpus all nvidia/cuda:11.8.0-runtime-ubuntu20.04 nvidia-smi; then
|
||||
echo ""
|
||||
echo -e "${GREEN}╔═══════════════════════════════════════════════════════╗${NC}"
|
||||
echo -e "${GREEN}║ SUCCESS! ║${NC}"
|
||||
echo -e "${GREEN}║ GPU is now accessible in Docker! ║${NC}"
|
||||
echo -e "${GREEN}╚═══════════════════════════════════════════════════════╝${NC}"
|
||||
echo ""
|
||||
echo "Configuration saved to:"
|
||||
echo " - /etc/docker/daemon.json"
|
||||
echo " - /etc/nvidia-container-runtime/config.toml"
|
||||
echo ""
|
||||
echo "Originals backed up to:"
|
||||
echo " - /etc/docker/daemon.json.original"
|
||||
echo " - /etc/nvidia-container-runtime/config.toml.original"
|
||||
echo ""
|
||||
exit 0
|
||||
else
|
||||
echo ""
|
||||
echo -e "${RED}╔═══════════════════════════════════════════════════════╗${NC}"
|
||||
echo -e "${RED}║ FAILED ║${NC}"
|
||||
echo -e "${RED}║ GPU test still failing ║${NC}"
|
||||
echo -e "${RED}╚═══════════════════════════════════════════════════════╝${NC}"
|
||||
echo ""
|
||||
echo "Troubleshooting:"
|
||||
echo "1. Check Docker logs: sudo journalctl -u docker -n 50"
|
||||
echo "2. Verify nvidia-container-cli: sudo nvidia-container-cli info"
|
||||
echo "3. Check driver version: nvidia-smi"
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
Executable
+86
@@ -0,0 +1,86 @@
|
||||
#!/bin/bash
|
||||
# Complete downgrade of all nvidia-container packages to 1.17.9-1
|
||||
|
||||
set -e
|
||||
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
echo -e "${BLUE}╔═══════════════════════════════════════════════════════╗${NC}"
|
||||
echo -e "${BLUE}║ Downgrade All NVIDIA Container Packages ║${NC}"
|
||||
echo -e "${BLUE}╚═══════════════════════════════════════════════════════╝${NC}"
|
||||
echo ""
|
||||
|
||||
# Check if running as root
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo -e "${RED}✗ Please run as root (use sudo)${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
VERSION="1.17.9-1"
|
||||
|
||||
echo -e "${BLUE}==> Step 1: Remove all nvidia-container packages${NC}"
|
||||
apt-get remove -y nvidia-container-toolkit nvidia-container-toolkit-base libnvidia-container-tools libnvidia-container1 || true
|
||||
echo -e "${GREEN}✓ Removed packages${NC}"
|
||||
echo ""
|
||||
|
||||
echo -e "${BLUE}==> Step 2: Clean up${NC}"
|
||||
apt-get autoremove -y
|
||||
echo -e "${GREEN}✓ Cleaned up${NC}"
|
||||
echo ""
|
||||
|
||||
echo -e "${BLUE}==> Step 3: Install all packages at version $VERSION${NC}"
|
||||
apt-get install -y \
|
||||
nvidia-container-toolkit=$VERSION \
|
||||
nvidia-container-toolkit-base=$VERSION \
|
||||
libnvidia-container-tools=$VERSION \
|
||||
libnvidia-container1=$VERSION
|
||||
echo -e "${GREEN}✓ Installed all packages at $VERSION${NC}"
|
||||
echo ""
|
||||
|
||||
echo -e "${BLUE}==> Step 4: Hold packages to prevent auto-upgrade${NC}"
|
||||
apt-mark hold nvidia-container-toolkit nvidia-container-toolkit-base libnvidia-container-tools libnvidia-container1
|
||||
echo -e "${GREEN}✓ Packages held${NC}"
|
||||
echo ""
|
||||
|
||||
echo -e "${BLUE}==> Step 5: Configure Docker${NC}"
|
||||
nvidia-ctk runtime configure --runtime=docker --config=/etc/docker/daemon.json
|
||||
echo -e "${GREEN}✓ Docker configured${NC}"
|
||||
echo ""
|
||||
|
||||
echo -e "${BLUE}==> Step 6: Rebuild library cache${NC}"
|
||||
ldconfig
|
||||
echo -e "${GREEN}✓ Library cache rebuilt${NC}"
|
||||
echo ""
|
||||
|
||||
echo -e "${BLUE}==> Step 7: Restart Docker${NC}"
|
||||
systemctl restart docker
|
||||
sleep 3
|
||||
echo -e "${GREEN}✓ Docker restarted${NC}"
|
||||
echo ""
|
||||
|
||||
echo -e "${BLUE}==> Step 8: Test GPU access${NC}"
|
||||
echo ""
|
||||
|
||||
if docker run --rm --gpus all nvidia/cuda:11.8.0-runtime-ubuntu20.04 nvidia-smi; then
|
||||
echo ""
|
||||
echo -e "${GREEN}╔═══════════════════════════════════════════════════════╗${NC}"
|
||||
echo -e "${GREEN}║ SUCCESS! ║${NC}"
|
||||
echo -e "${GREEN}║ GPU is now accessible in Docker! ║${NC}"
|
||||
echo -e "${GREEN}╚═══════════════════════════════════════════════════════╝${NC}"
|
||||
echo ""
|
||||
echo "Installed versions:"
|
||||
dpkg -l | grep nvidia-container
|
||||
echo ""
|
||||
exit 0
|
||||
else
|
||||
echo ""
|
||||
echo -e "${RED}╔═══════════════════════════════════════════════════════╗${NC}"
|
||||
echo -e "${RED}║ FAILED ║${NC}"
|
||||
echo -e "${RED}║ GPU test still failing ║${NC}"
|
||||
echo -e "${RED}╚═══════════════════════════════════════════════════════╝${NC}"
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
Executable
+103
@@ -0,0 +1,103 @@
|
||||
#!/bin/bash
|
||||
# Service Health Check Script
|
||||
# Checks status of all critical services
|
||||
|
||||
set -e
|
||||
|
||||
echo "=== tower-of-joy Health Check ==="
|
||||
echo "$(date)"
|
||||
echo ""
|
||||
|
||||
# Define service check function
|
||||
check_service() {
|
||||
local name=$1
|
||||
local port=$2
|
||||
local container=$3
|
||||
|
||||
# Check container running
|
||||
if docker ps --format '{{.Names}}' | grep -q "^${container}$"; then
|
||||
# Check port responding
|
||||
if curl -f -s -o /dev/null -w "%{http_code}" "http://localhost:${port}" > /dev/null 2>&1 || \
|
||||
curl -f -s -o /dev/null "http://localhost:${port}" > /dev/null 2>&1; then
|
||||
echo "✅ ${name} (port ${port})"
|
||||
else
|
||||
echo "⚠️ ${name} - container running but port ${port} not responding"
|
||||
fi
|
||||
else
|
||||
echo "❌ ${name} - container not running"
|
||||
fi
|
||||
}
|
||||
|
||||
# Check infrastructure services
|
||||
echo "[Infrastructure Services]"
|
||||
check_service "Portainer" "8080" "portainer"
|
||||
check_service "Nginx Proxy Manager" "8000" "nginx-proxy-manager"
|
||||
check_service "Ollama" "11434" "ollama"
|
||||
echo ""
|
||||
|
||||
# Check networking
|
||||
echo "[Networking]"
|
||||
check_service "Headscale" "8085" "headscale"
|
||||
if command -v tailscale &> /dev/null; then
|
||||
if tailscale status &> /dev/null; then
|
||||
echo "✅ Tailscale connected"
|
||||
else
|
||||
echo "⚠️ Tailscale installed but not connected"
|
||||
fi
|
||||
else
|
||||
echo "⚠️ Tailscale not installed"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Check monitoring
|
||||
echo "[Monitoring]"
|
||||
check_service "Uptime Kuma" "3001" "uptime-kuma"
|
||||
check_service "Netdata" "19999" "netdata"
|
||||
check_service "Heimdall" "8888" "heimdall"
|
||||
echo ""
|
||||
|
||||
# Check application services (if deployed)
|
||||
echo "[Applications]"
|
||||
check_service "Jellyfin" "8096" "jellyfin"
|
||||
check_service "Nextcloud" "8082" "nextcloud"
|
||||
check_service "Samba" "445" "samba"
|
||||
echo ""
|
||||
|
||||
# Check storage
|
||||
echo "[Storage]"
|
||||
ssd_usage=$(df -h /home/jpmschweitzer/docker-data 2>/dev/null | awk 'NR==2 {print $5}' | sed 's/%//')
|
||||
hdd_usage=$(df -h /mnt/media 2>/dev/null | awk 'NR==2 {print $5}' | sed 's/%//')
|
||||
|
||||
if [ -n "$ssd_usage" ]; then
|
||||
if [ "$ssd_usage" -lt 80 ]; then
|
||||
echo "✅ SSD: ${ssd_usage}% used"
|
||||
elif [ "$ssd_usage" -lt 90 ]; then
|
||||
echo "⚠️ SSD: ${ssd_usage}% used (getting full)"
|
||||
else
|
||||
echo "❌ SSD: ${ssd_usage}% used (critically full!)"
|
||||
fi
|
||||
else
|
||||
echo "⚠️ SSD: Unable to check"
|
||||
fi
|
||||
|
||||
if [ -n "$hdd_usage" ]; then
|
||||
if [ "$hdd_usage" -lt 80 ]; then
|
||||
echo "✅ HDD: ${hdd_usage}% used"
|
||||
elif [ "$hdd_usage" -lt 90 ]; then
|
||||
echo "⚠️ HDD: ${hdd_usage}% used (getting full)"
|
||||
else
|
||||
echo "❌ HDD: ${hdd_usage}% used (critically full!)"
|
||||
fi
|
||||
else
|
||||
echo "❌ HDD: Not mounted at /mnt/media"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Check Docker
|
||||
echo "[Docker Status]"
|
||||
running=$(docker ps -q | wc -l)
|
||||
total=$(docker ps -aq | wc -l)
|
||||
echo "Containers: ${running} running / ${total} total"
|
||||
echo ""
|
||||
|
||||
echo "=== Health Check Complete ==="
|
||||
Executable
+247
@@ -0,0 +1,247 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Automated Uptime Kuma Monitor Setup for tower-of-joy Infrastructure
|
||||
|
||||
This script automatically creates monitors for all infrastructure services in Uptime Kuma.
|
||||
It is idempotent - safe to run multiple times without creating duplicates.
|
||||
|
||||
Usage:
|
||||
source .venv/bin/activate
|
||||
python3 scripts/setup-kuma-monitors.py
|
||||
|
||||
Environment Variables:
|
||||
KUMA_URL: Uptime Kuma URL (default: http://192.168.86.149:3001)
|
||||
KUMA_USERNAME: Uptime Kuma admin username (will prompt if not set)
|
||||
KUMA_PASSWORD: Uptime Kuma admin password (will prompt if not set)
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from getpass import getpass
|
||||
|
||||
try:
|
||||
from uptime_kuma_api import UptimeKumaApi, MonitorType
|
||||
except ImportError:
|
||||
print("\033[0;31mError: uptime-kuma-api package not installed\033[0m")
|
||||
print("\nInstall dependencies:")
|
||||
print(" source .venv/bin/activate")
|
||||
print(" pip install -r requirements.txt")
|
||||
sys.exit(1)
|
||||
|
||||
# Configuration
|
||||
KUMA_URL = os.getenv("KUMA_URL", "http://192.168.86.149:3001")
|
||||
|
||||
# Service definitions
|
||||
MONITORS = [
|
||||
{
|
||||
"name": "Portainer",
|
||||
"url": "http://192.168.86.149:8001",
|
||||
"interval": 60,
|
||||
"type": MonitorType.HTTP,
|
||||
"description": "Container management interface"
|
||||
},
|
||||
{
|
||||
"name": "Nginx Proxy Manager",
|
||||
"url": "http://192.168.86.149:81",
|
||||
"interval": 60,
|
||||
"type": MonitorType.HTTP,
|
||||
"description": "Reverse proxy admin interface"
|
||||
},
|
||||
{
|
||||
"name": "Ollama API",
|
||||
"url": "http://192.168.86.149:11434",
|
||||
"interval": 60,
|
||||
"type": MonitorType.HTTP,
|
||||
"description": "ML model API endpoint"
|
||||
},
|
||||
{
|
||||
"name": "Headscale",
|
||||
"url": "http://192.168.86.149:8085/health",
|
||||
"interval": 60,
|
||||
"type": MonitorType.HTTP,
|
||||
"description": "Mesh VPN control server"
|
||||
},
|
||||
{
|
||||
"name": "Uptime Kuma",
|
||||
"url": "http://192.168.86.149:3001",
|
||||
"interval": 120,
|
||||
"type": MonitorType.HTTP,
|
||||
"description": "Service monitoring (self-check)"
|
||||
},
|
||||
{
|
||||
"name": "Netdata",
|
||||
"url": "http://192.168.86.149:19999",
|
||||
"interval": 60,
|
||||
"type": MonitorType.HTTP,
|
||||
"description": "System metrics dashboard"
|
||||
},
|
||||
{
|
||||
"name": "Heimdall",
|
||||
"url": "http://192.168.86.149:8888",
|
||||
"interval": 60,
|
||||
"type": MonitorType.HTTP,
|
||||
"description": "Application dashboard"
|
||||
},
|
||||
{
|
||||
"name": "Organizr",
|
||||
"url": "http://192.168.86.149:9999",
|
||||
"interval": 60,
|
||||
"type": MonitorType.HTTP,
|
||||
"description": "Unified dashboard"
|
||||
},
|
||||
{
|
||||
"name": "Jellyfin",
|
||||
"url": "http://192.168.86.149:8096",
|
||||
"interval": 60,
|
||||
"type": MonitorType.HTTP,
|
||||
"description": "Media streaming server"
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def print_color(text, color="reset"):
|
||||
"""Print colored text"""
|
||||
colors = {
|
||||
"red": "\033[0;31m",
|
||||
"green": "\033[0;32m",
|
||||
"yellow": "\033[1;33m",
|
||||
"blue": "\033[0;34m",
|
||||
"cyan": "\033[0;36m",
|
||||
"reset": "\033[0m"
|
||||
}
|
||||
print(f"{colors.get(color, '')}{text}{colors['reset']}")
|
||||
|
||||
|
||||
def get_credentials():
|
||||
"""Get credentials from environment or prompt user"""
|
||||
username = os.getenv("KUMA_USERNAME")
|
||||
password = os.getenv("KUMA_PASSWORD")
|
||||
|
||||
if not username:
|
||||
print_color("\nUptime Kuma credentials required", "yellow")
|
||||
username = input("Username: ").strip()
|
||||
|
||||
if not password:
|
||||
password = getpass("Password: ").strip()
|
||||
|
||||
return username, password
|
||||
|
||||
|
||||
def setup_monitors():
|
||||
"""Configure all monitors in Uptime Kuma"""
|
||||
print_color("╔════════════════════════════════════════════╗", "blue")
|
||||
print_color("║ Uptime Kuma Automated Monitor Setup ║", "blue")
|
||||
print_color("╚════════════════════════════════════════════╝", "blue")
|
||||
print()
|
||||
print(f"Target: {KUMA_URL}")
|
||||
print(f"Monitors to configure: {len(MONITORS)}")
|
||||
print()
|
||||
|
||||
# Get credentials
|
||||
username, password = get_credentials()
|
||||
|
||||
# Connect to Uptime Kuma
|
||||
print_color("\nConnecting to Uptime Kuma...", "blue")
|
||||
try:
|
||||
api = UptimeKumaApi(KUMA_URL)
|
||||
api.login(username, password)
|
||||
print_color("✓ Connected successfully", "green")
|
||||
except Exception as e:
|
||||
print_color(f"✗ Connection failed: {e}", "red")
|
||||
print()
|
||||
print("Troubleshooting:")
|
||||
print(" 1. Verify Uptime Kuma is running: docker ps | grep uptime-kuma")
|
||||
print(f" 2. Check URL is correct: {KUMA_URL}")
|
||||
print(" 3. Verify credentials are correct")
|
||||
sys.exit(1)
|
||||
|
||||
print()
|
||||
|
||||
# Get existing monitors
|
||||
print_color("Fetching existing monitors...", "blue")
|
||||
existing_monitors = api.get_monitors()
|
||||
existing_names = {m["name"] for m in existing_monitors}
|
||||
print(f"Found {len(existing_monitors)} existing monitor(s)")
|
||||
print()
|
||||
|
||||
# Configure each monitor
|
||||
print_color("Configuring monitors...", "blue")
|
||||
print()
|
||||
|
||||
created = 0
|
||||
skipped = 0
|
||||
failed = 0
|
||||
|
||||
for monitor_def in MONITORS:
|
||||
name = monitor_def["name"]
|
||||
|
||||
if name in existing_names:
|
||||
print(f"⊙ {name} - Already exists (skipping)")
|
||||
skipped += 1
|
||||
continue
|
||||
|
||||
try:
|
||||
# Create the monitor
|
||||
api.add_monitor(
|
||||
type=monitor_def["type"],
|
||||
name=name,
|
||||
url=monitor_def["url"],
|
||||
interval=monitor_def["interval"],
|
||||
description=monitor_def.get("description", ""),
|
||||
retryInterval=60,
|
||||
resendInterval=0,
|
||||
maxretries=1,
|
||||
upsideDown=False,
|
||||
notificationIDList=[],
|
||||
httpBodyEncoding="utf8",
|
||||
method="GET",
|
||||
maxredirects=10,
|
||||
accepted_statuscodes=["200-299"]
|
||||
)
|
||||
print_color(f"✓ {name} - Created", "green")
|
||||
print(f" URL: {monitor_def['url']}")
|
||||
print(f" Interval: {monitor_def['interval']}s")
|
||||
created += 1
|
||||
except Exception as e:
|
||||
print_color(f"✗ {name} - Failed: {e}", "red")
|
||||
failed += 1
|
||||
|
||||
print()
|
||||
|
||||
# Disconnect
|
||||
api.disconnect()
|
||||
|
||||
# Summary
|
||||
print_color("═══════════════════════════════════════════", "blue")
|
||||
print_color("Summary:", "green")
|
||||
print_color("═══════════════════════════════════════════", "blue")
|
||||
print(f"Created: {created}")
|
||||
print(f"Skipped (already exist): {skipped}")
|
||||
print(f"Failed: {failed}")
|
||||
print()
|
||||
|
||||
if created > 0:
|
||||
print_color("✓ Setup complete! Monitors are now active.", "green")
|
||||
print()
|
||||
print("View monitors at:", KUMA_URL)
|
||||
print("Refresh Organizr to see status widgets update")
|
||||
elif skipped == len(MONITORS):
|
||||
print_color("✓ All monitors already configured", "green")
|
||||
else:
|
||||
print_color("⚠ Some monitors could not be created", "yellow")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
setup_monitors()
|
||||
except KeyboardInterrupt:
|
||||
print()
|
||||
print_color("Setup cancelled by user", "yellow")
|
||||
sys.exit(130)
|
||||
except Exception as e:
|
||||
print()
|
||||
print_color(f"Unexpected error: {e}", "red")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
Executable
+133
@@ -0,0 +1,133 @@
|
||||
#!/bin/bash
|
||||
# Setup Uptime Kuma Monitors for tower-of-joy Infrastructure
|
||||
#
|
||||
# This script provides instructions and data for configuring monitoring
|
||||
# for all infrastructure services in Uptime Kuma.
|
||||
#
|
||||
# Usage: ./scripts/setup-kuma-monitors.sh
|
||||
|
||||
set -e
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
CYAN='\033[0;36m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Configuration
|
||||
KUMA_URL="http://192.168.86.149:3001"
|
||||
|
||||
# Service definitions
|
||||
declare -a MONITORS=(
|
||||
"Portainer|http://192.168.86.149:8001|60|Container management interface"
|
||||
"Nginx Proxy Manager|http://192.168.86.149:81|60|Reverse proxy admin interface"
|
||||
"Ollama API|http://192.168.86.149:11434|60|ML model API endpoint"
|
||||
"Headscale|http://192.168.86.149:8085/health|60|Mesh VPN control server"
|
||||
"Uptime Kuma|http://192.168.86.149:3001|120|Service monitoring (self-check)"
|
||||
"Netdata|http://192.168.86.149:19999|60|System metrics dashboard"
|
||||
"Heimdall|http://192.168.86.149:8888|60|Application dashboard"
|
||||
"Organizr|http://192.168.86.149:9999|60|Unified dashboard"
|
||||
"Jellyfin|http://192.168.86.149:8096|60|Media streaming server"
|
||||
)
|
||||
|
||||
echo -e "${BLUE}╔════════════════════════════════════════════╗${NC}"
|
||||
echo -e "${BLUE}║ Uptime Kuma Monitor Setup Guide ║${NC}"
|
||||
echo -e "${BLUE}╚════════════════════════════════════════════╝${NC}"
|
||||
echo ""
|
||||
echo -e "${CYAN}Target:${NC} $KUMA_URL"
|
||||
echo -e "${CYAN}Monitors to configure:${NC} ${#MONITORS[@]}"
|
||||
echo ""
|
||||
|
||||
# Check if Uptime Kuma is accessible
|
||||
echo -n "Checking Uptime Kuma availability... "
|
||||
if curl -s -o /dev/null -w "%{http_code}" "$KUMA_URL" | grep -q "200\|301\|302"; then
|
||||
echo -e "${GREEN}✓${NC}"
|
||||
else
|
||||
echo -e "${RED}✗${NC}"
|
||||
echo -e "${RED}Error: Cannot reach Uptime Kuma at $KUMA_URL${NC}"
|
||||
echo "Make sure Uptime Kuma is running: docker ps | grep uptime-kuma"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e "${BLUE}═══════════════════════════════════════════${NC}"
|
||||
echo -e "${GREEN}Monitors to Configure:${NC}"
|
||||
echo -e "${BLUE}═══════════════════════════════════════════${NC}"
|
||||
echo ""
|
||||
|
||||
counter=1
|
||||
for monitor_def in "${MONITORS[@]}"; do
|
||||
IFS='|' read -r name url interval desc <<< "$monitor_def"
|
||||
echo -e "${YELLOW}[$counter/${#MONITORS[@]}] $name${NC}"
|
||||
echo -e " ${CYAN}URL:${NC} $url"
|
||||
echo -e " ${CYAN}Interval:${NC} ${interval}s"
|
||||
echo -e " ${CYAN}Description:${NC} $desc"
|
||||
echo ""
|
||||
((counter++))
|
||||
done
|
||||
|
||||
echo -e "${BLUE}═══════════════════════════════════════════${NC}"
|
||||
echo -e "${GREEN}Setup Instructions:${NC}"
|
||||
echo -e "${BLUE}═══════════════════════════════════════════${NC}"
|
||||
echo ""
|
||||
echo "1. Open Uptime Kuma in your browser:"
|
||||
echo -e " ${CYAN}${KUMA_URL}${NC}"
|
||||
echo ""
|
||||
echo "2. Log in with your Uptime Kuma credentials"
|
||||
echo ""
|
||||
echo "3. For each monitor listed above, click ${GREEN}'Add New Monitor'${NC} and enter:"
|
||||
echo ""
|
||||
echo " ${CYAN}Monitor Settings:${NC}"
|
||||
echo " • Monitor Type: ${GREEN}HTTP(s)${NC}"
|
||||
echo " • Friendly Name: ${GREEN}[Name from list above]${NC}"
|
||||
echo " • URL: ${GREEN}[URL from list above]${NC}"
|
||||
echo " • Heartbeat Interval: ${GREEN}[Interval from list]${NC} seconds"
|
||||
echo " • Retries: ${GREEN}1${NC}"
|
||||
echo " • Retry Interval: ${GREEN}60${NC} seconds"
|
||||
echo " • HTTP Method: ${GREEN}GET${NC}"
|
||||
echo " • Expected Status Code: ${GREEN}200${NC}"
|
||||
echo ""
|
||||
echo "4. Click ${GREEN}'Save'${NC} for each monitor"
|
||||
echo ""
|
||||
echo "5. After adding all monitors, verify they appear in:"
|
||||
echo " • Uptime Kuma dashboard"
|
||||
echo " • Organizr homepage (Service Status widget)"
|
||||
echo ""
|
||||
|
||||
echo -e "${BLUE}═══════════════════════════════════════════${NC}"
|
||||
echo -e "${GREEN}Quick Copy-Paste Data:${NC}"
|
||||
echo -e "${BLUE}═══════════════════════════════════════════${NC}"
|
||||
echo ""
|
||||
|
||||
for monitor_def in "${MONITORS[@]}"; do
|
||||
IFS='|' read -r name url interval desc <<< "$monitor_def"
|
||||
echo -e "${YELLOW}$name${NC}"
|
||||
echo "$url"
|
||||
echo ""
|
||||
done
|
||||
|
||||
echo -e "${BLUE}═══════════════════════════════════════════${NC}"
|
||||
echo -e "${GREEN}Post-Setup Verification:${NC}"
|
||||
echo -e "${BLUE}═══════════════════════════════════════════${NC}"
|
||||
echo ""
|
||||
echo "After adding all monitors:"
|
||||
echo ""
|
||||
echo "1. Check Uptime Kuma dashboard shows all services as 'Up'"
|
||||
echo "2. Refresh Organizr (${CYAN}http://192.168.86.149:9999${NC})"
|
||||
echo "3. Verify 'Service Status' widget shows all monitors"
|
||||
echo "4. Test by stopping a container and watching status change:"
|
||||
echo -e " ${CYAN}docker stop heimdall${NC}"
|
||||
echo " (Monitor should show as Down within 60s)"
|
||||
echo -e " ${CYAN}docker start heimdall${NC}"
|
||||
echo " (Monitor should recover)"
|
||||
echo ""
|
||||
|
||||
echo -e "${GREEN}✓ Setup guide complete!${NC}"
|
||||
echo ""
|
||||
echo -e "${YELLOW}Tip:${NC} For automated setup in the future, consider:"
|
||||
echo " • Uptime Kuma API (requires authentication)"
|
||||
echo " • Backup/restore Uptime Kuma configuration"
|
||||
echo " • Export configuration: Settings → Backup"
|
||||
echo ""
|
||||
Executable
+82
@@ -0,0 +1,82 @@
|
||||
#!/bin/bash
|
||||
# Update Docker Stacks Script
|
||||
# Pull latest images and recreate containers
|
||||
|
||||
set -e
|
||||
|
||||
STACKS_DIR="/home/jpmschweitzer/Projects/tower-of-joy/stacks"
|
||||
|
||||
# Show usage
|
||||
if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
|
||||
echo "Usage: $0 [stack-name]"
|
||||
echo ""
|
||||
echo "Update a specific stack or all stacks"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 portainer # Update only Portainer"
|
||||
echo " $0 ollama # Update only Ollama"
|
||||
echo " $0 # Update all stacks (interactive)"
|
||||
echo ""
|
||||
echo "Available stacks:"
|
||||
ls -1 "$STACKS_DIR"/*.yml 2>/dev/null | xargs -n 1 basename | sed 's/.yml$//' | sed 's/^/ - /'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Function to update a stack
|
||||
update_stack() {
|
||||
local stack_file=$1
|
||||
local stack_name=$(basename "$stack_file" .yml)
|
||||
|
||||
echo ""
|
||||
echo "=== Updating $stack_name ==="
|
||||
|
||||
# Pull latest images
|
||||
echo "[1/3] Pulling latest images..."
|
||||
docker compose -f "$stack_file" pull
|
||||
|
||||
# Recreate containers
|
||||
echo "[2/3] Recreating containers..."
|
||||
docker compose -f "$stack_file" up -d
|
||||
|
||||
# Verify containers running
|
||||
echo "[3/3] Verifying containers..."
|
||||
sleep 2
|
||||
if docker compose -f "$stack_file" ps | grep -q "Up"; then
|
||||
echo "✅ $stack_name updated successfully"
|
||||
else
|
||||
echo "⚠️ $stack_name may have issues, check logs"
|
||||
fi
|
||||
}
|
||||
|
||||
# If specific stack provided
|
||||
if [ -n "$1" ]; then
|
||||
STACK_FILE="$STACKS_DIR/$1.yml"
|
||||
if [ -f "$STACK_FILE" ]; then
|
||||
update_stack "$STACK_FILE"
|
||||
else
|
||||
echo "❌ Stack not found: $1"
|
||||
echo "Available stacks:"
|
||||
ls -1 "$STACKS_DIR"/*.yml 2>/dev/null | xargs -n 1 basename | sed 's/.yml$//' | sed 's/^/ - /'
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
# Interactive mode - update all stacks
|
||||
echo "=== Update All Stacks ==="
|
||||
echo ""
|
||||
echo "This will update all deployed stacks to the latest images."
|
||||
read -p "Continue? (y/N) " -n 1 -r
|
||||
echo
|
||||
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
for stack_file in "$STACKS_DIR"/*.yml; do
|
||||
if [ -f "$stack_file" ]; then
|
||||
update_stack "$stack_file"
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
echo "=== All Stacks Updated ==="
|
||||
else
|
||||
echo "Update cancelled"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
Executable
+105
@@ -0,0 +1,105 @@
|
||||
#!/bin/bash
|
||||
# NVIDIA Driver Upgrade Script: 470 -> 535
|
||||
# Upgrades NVIDIA driver for CUDA 12 support (required by Ollama)
|
||||
|
||||
set -e
|
||||
|
||||
echo "=== NVIDIA Driver Upgrade: 470 -> 535 ==="
|
||||
echo ""
|
||||
|
||||
# Check if running as root
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo "❌ This script must be run as root (use sudo)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Backup current state
|
||||
echo "[1/9] Backing up current container state..."
|
||||
docker ps > /tmp/nvidia-upgrade-containers-backup.txt
|
||||
echo "✅ Container list saved to /tmp/nvidia-upgrade-containers-backup.txt"
|
||||
echo ""
|
||||
|
||||
# Stop GPU containers
|
||||
echo "[2/9] Stopping GPU-using containers..."
|
||||
docker stop ollama 2>/dev/null || true
|
||||
docker stop jellyfin 2>/dev/null || true
|
||||
echo "✅ GPU containers stopped"
|
||||
echo ""
|
||||
|
||||
# Unhold NVIDIA Container Toolkit packages
|
||||
echo "[3/9] Unholding NVIDIA Container Toolkit packages..."
|
||||
echo "libnvidia-container-tools install" | dpkg --set-selections
|
||||
echo "libnvidia-container1 install" | dpkg --set-selections
|
||||
echo "nvidia-container-toolkit install" | dpkg --set-selections
|
||||
echo "nvidia-container-toolkit-base install" | dpkg --set-selections
|
||||
echo "✅ Packages unheld"
|
||||
echo ""
|
||||
|
||||
# Remove ALL driver 470 packages
|
||||
echo "[4/9] Removing ALL NVIDIA driver 470 packages..."
|
||||
apt-get purge -y 'libnvidia-*-470' 'nvidia-*-470' '*nvidia*470*' 2>&1 | grep -E "Removing|Purging|^$" || true
|
||||
apt-get purge -y nvidia-settings 2>&1 | grep -E "Removing|Purging|^$" || true
|
||||
apt-get autoremove -y > /dev/null 2>&1
|
||||
echo "✅ All driver 470 packages removed"
|
||||
echo ""
|
||||
|
||||
# Clean up package database
|
||||
echo "[5/9] Cleaning package database..."
|
||||
apt-get clean
|
||||
apt-get autoclean
|
||||
dpkg --configure -a
|
||||
apt-get install -f -y
|
||||
echo "✅ Package database cleaned"
|
||||
echo ""
|
||||
|
||||
# Update package lists
|
||||
echo "[6/9] Updating package lists..."
|
||||
apt-get update > /dev/null 2>&1
|
||||
echo "✅ Package lists updated"
|
||||
echo ""
|
||||
|
||||
# Install driver 535 with all dependencies
|
||||
echo "[7/9] Installing NVIDIA driver 535..."
|
||||
apt-get install -y --no-install-recommends \
|
||||
libnvidia-common-535 \
|
||||
libnvidia-gl-535 \
|
||||
libnvidia-compute-535 \
|
||||
libnvidia-decode-535 \
|
||||
libnvidia-encode-535 \
|
||||
nvidia-utils-535 \
|
||||
xserver-xorg-video-nvidia-535 \
|
||||
libnvidia-cfg1-535 \
|
||||
libnvidia-fbc1-535 \
|
||||
nvidia-kernel-common-535 \
|
||||
nvidia-dkms-535 \
|
||||
nvidia-driver-535 \
|
||||
nvidia-settings
|
||||
|
||||
echo "✅ Driver 535 installed"
|
||||
echo ""
|
||||
|
||||
# Update NVIDIA Container Toolkit
|
||||
echo "[8/9] Updating NVIDIA Container Toolkit..."
|
||||
apt-get install --reinstall -y nvidia-container-toolkit > /dev/null 2>&1
|
||||
nvidia-ctk runtime configure --runtime=docker > /dev/null 2>&1
|
||||
echo "✅ Container toolkit updated"
|
||||
echo ""
|
||||
|
||||
# Restart Docker
|
||||
echo "[9/9] Restarting Docker daemon..."
|
||||
systemctl restart docker
|
||||
sleep 3
|
||||
echo "✅ Docker restarted"
|
||||
echo ""
|
||||
|
||||
echo "=== Upgrade Complete ==="
|
||||
echo ""
|
||||
echo "⚠️ REBOOT REQUIRED NOW"
|
||||
echo ""
|
||||
echo "Run: sudo reboot"
|
||||
echo ""
|
||||
echo "After reboot:"
|
||||
echo " 1. Verify: nvidia-smi"
|
||||
echo " 2. Restart: cd ~/Projects/portainer-core/stacks && docker compose -f ollama.yml up -d"
|
||||
echo " 3. Test GPU: docker exec ollama ollama ps"
|
||||
echo ""
|
||||
Reference in New Issue
Block a user