mirror of
https://github.com/m1ngsama/automa.git
synced 2025-12-24 10:51:20 +00:00
Merge pull request #2 from m1ngsama/optimize/engineering-improvements
refactor: engineering optimizations for shared utilities and improved error handling
This commit is contained in:
commit
9b709b25b4
7 changed files with 412 additions and 125 deletions
71
Makefile
71
Makefile
|
|
@ -2,6 +2,8 @@
|
||||||
# Provides common operations across all services
|
# Provides common operations across all services
|
||||||
|
|
||||||
.PHONY: help all status up down logs restart clean minecraft teamspeak nextcloud
|
.PHONY: help all status up down logs restart clean minecraft teamspeak nextcloud
|
||||||
|
.PHONY: health health-minecraft health-teamspeak health-nextcloud
|
||||||
|
.PHONY: backup backup-minecraft backup-teamspeak backup-nextcloud backup-list backup-cleanup
|
||||||
|
|
||||||
# Default target
|
# Default target
|
||||||
help:
|
help:
|
||||||
|
|
@ -10,10 +12,14 @@ help:
|
||||||
@echo "Usage: make [target]"
|
@echo "Usage: make [target]"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "Global Commands:"
|
@echo "Global Commands:"
|
||||||
@echo " help Show this help message"
|
@echo " help Show this help message"
|
||||||
@echo " status Show status of all services"
|
@echo " status Show status of all services"
|
||||||
@echo " all-up Start all services"
|
@echo " all-up Start all services"
|
||||||
@echo " all-down Stop all services"
|
@echo " all-down Stop all services"
|
||||||
|
@echo " health Run health checks on all services"
|
||||||
|
@echo " backup Backup all services"
|
||||||
|
@echo " backup-list List available backups"
|
||||||
|
@echo " backup-cleanup Remove old backups"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "Service-specific Commands:"
|
@echo "Service-specific Commands:"
|
||||||
@echo " Minecraft:"
|
@echo " Minecraft:"
|
||||||
|
|
@ -29,16 +35,21 @@ help:
|
||||||
@echo " minecraft-backup Create full backup"
|
@echo " minecraft-backup Create full backup"
|
||||||
@echo " minecraft-backup-world Backup world data only"
|
@echo " minecraft-backup-world Backup world data only"
|
||||||
@echo " minecraft-backup-list List available backups"
|
@echo " minecraft-backup-list List available backups"
|
||||||
|
@echo " health-minecraft Check Minecraft health"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo " teamspeak-up Start TeamSpeak server"
|
@echo " TeamSpeak:"
|
||||||
@echo " teamspeak-down Stop TeamSpeak server"
|
@echo " teamspeak-up Start TeamSpeak server"
|
||||||
@echo " teamspeak-logs View TeamSpeak logs"
|
@echo " teamspeak-down Stop TeamSpeak server"
|
||||||
@echo " teamspeak-restart Restart TeamSpeak server"
|
@echo " teamspeak-logs View TeamSpeak logs"
|
||||||
|
@echo " teamspeak-restart Restart TeamSpeak server"
|
||||||
|
@echo " health-teamspeak Check TeamSpeak health"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo " nextcloud-up Start Nextcloud"
|
@echo " Nextcloud:"
|
||||||
@echo " nextcloud-down Stop Nextcloud"
|
@echo " nextcloud-up Start Nextcloud"
|
||||||
@echo " nextcloud-logs View Nextcloud logs"
|
@echo " nextcloud-down Stop Nextcloud"
|
||||||
@echo " nextcloud-restart Restart Nextcloud"
|
@echo " nextcloud-logs View Nextcloud logs"
|
||||||
|
@echo " nextcloud-restart Restart Nextcloud"
|
||||||
|
@echo " health-nextcloud Check Nextcloud health"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "Utility Commands:"
|
@echo "Utility Commands:"
|
||||||
@echo " check Check prerequisites"
|
@echo " check Check prerequisites"
|
||||||
|
|
@ -164,3 +175,39 @@ clean:
|
||||||
@docker container prune -f
|
@docker container prune -f
|
||||||
@docker volume prune -f
|
@docker volume prune -f
|
||||||
@echo "✓ Cleanup complete"
|
@echo "✓ Cleanup complete"
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Health Check Targets
|
||||||
|
# ============================================================================
|
||||||
|
health:
|
||||||
|
@./bin/healthcheck.sh all
|
||||||
|
|
||||||
|
health-minecraft:
|
||||||
|
@./bin/healthcheck.sh minecraft
|
||||||
|
|
||||||
|
health-teamspeak:
|
||||||
|
@./bin/healthcheck.sh teamspeak
|
||||||
|
|
||||||
|
health-nextcloud:
|
||||||
|
@./bin/healthcheck.sh nextcloud
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Backup Targets (using bin/backup.sh)
|
||||||
|
# ============================================================================
|
||||||
|
backup:
|
||||||
|
@./bin/backup.sh backup all
|
||||||
|
|
||||||
|
backup-minecraft:
|
||||||
|
@./bin/backup.sh backup minecraft
|
||||||
|
|
||||||
|
backup-teamspeak:
|
||||||
|
@./bin/backup.sh backup teamspeak
|
||||||
|
|
||||||
|
backup-nextcloud:
|
||||||
|
@./bin/backup.sh backup nextcloud
|
||||||
|
|
||||||
|
backup-list:
|
||||||
|
@./bin/backup.sh list
|
||||||
|
|
||||||
|
backup-cleanup:
|
||||||
|
@./bin/backup.sh cleanup
|
||||||
|
|
|
||||||
197
bin/backup.sh
197
bin/backup.sh
|
|
@ -1,46 +1,67 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Backup utility for all services
|
# Backup utility for all services
|
||||||
# Usage: ./bin/backup.sh [service]
|
# Usage: ./bin/backup.sh [command] [service]
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
readonly RED='\033[0;31m'
|
# Source shared library and config
|
||||||
readonly GREEN='\033[0;32m'
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
readonly YELLOW='\033[1;33m'
|
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||||
readonly NC='\033[0m'
|
source "$SCRIPT_DIR/lib/common.sh"
|
||||||
|
source "$PROJECT_ROOT/config.sh"
|
||||||
|
|
||||||
readonly BACKUP_ROOT="${BACKUP_ROOT:-./backups}"
|
|
||||||
readonly TIMESTAMP=$(date +%Y%m%d-%H%M%S)
|
readonly TIMESTAMP=$(date +%Y%m%d-%H%M%S)
|
||||||
|
|
||||||
log_info() { echo -e "${GREEN}[INFO]${NC} $*"; }
|
# ============================================================================
|
||||||
log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
# Pre-flight checks
|
||||||
log_error() { echo -e "${RED}[ERROR]${NC} $*"; }
|
# ============================================================================
|
||||||
|
check_prerequisites() {
|
||||||
ensure_backup_dir() {
|
if ! require_command "docker"; then
|
||||||
local dir="$1"
|
log_error "Docker is required for backup operations"
|
||||||
mkdir -p "$dir"
|
exit 1
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check_container_running() {
|
||||||
|
local container_name="$1"
|
||||||
|
local service_name="$2"
|
||||||
|
|
||||||
|
if ! check_container_health "$container_name"; then
|
||||||
|
log_warn "$service_name container ($container_name) is not running"
|
||||||
|
log_warn "Some backup operations may fail"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Backup functions
|
||||||
|
# ============================================================================
|
||||||
backup_minecraft() {
|
backup_minecraft() {
|
||||||
log_info "Backing up Minecraft server..."
|
log_info "Backing up Minecraft server..."
|
||||||
|
|
||||||
local backup_dir="$BACKUP_ROOT/minecraft/$TIMESTAMP"
|
local backup_dir="$BACKUP_ROOT/minecraft/$TIMESTAMP"
|
||||||
ensure_backup_dir "$backup_dir"
|
ensure_dir "$backup_dir"
|
||||||
|
|
||||||
|
# Check if container is running (warning only)
|
||||||
|
check_container_running "$CONTAINER_MINECRAFT" "Minecraft" || true
|
||||||
|
|
||||||
# Backup world data
|
# Backup world data
|
||||||
if [[ -d "minecraft/data" ]]; then
|
if [[ -d "$PROJECT_ROOT/minecraft/data" ]]; then
|
||||||
log_info " Archiving world data..."
|
log_info " Archiving world data..."
|
||||||
tar -czf "$backup_dir/world-data.tar.gz" -C minecraft data 2>/dev/null || {
|
tar -czf "$backup_dir/world-data.tar.gz" -C "$PROJECT_ROOT/minecraft" data 2>/dev/null || {
|
||||||
log_error " Failed to backup world data"
|
log_error " Failed to backup world data"
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
log_info " ✓ World data backed up"
|
log_info " ✓ World data backed up"
|
||||||
|
else
|
||||||
|
log_warn " No world data directory found"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Backup configs
|
# Backup configs
|
||||||
if [[ -d "minecraft/configs" ]]; then
|
if [[ -d "$PROJECT_ROOT/minecraft/configs" ]]; then
|
||||||
log_info " Archiving configs..."
|
log_info " Archiving configs..."
|
||||||
tar -czf "$backup_dir/configs.tar.gz" -C minecraft configs 2>/dev/null || {
|
tar -czf "$backup_dir/configs.tar.gz" -C "$PROJECT_ROOT/minecraft" configs 2>/dev/null || {
|
||||||
log_warn " Failed to backup configs"
|
log_warn " Failed to backup configs"
|
||||||
}
|
}
|
||||||
fi
|
fi
|
||||||
|
|
@ -50,6 +71,7 @@ backup_minecraft() {
|
||||||
Minecraft Backup
|
Minecraft Backup
|
||||||
Created: $(date)
|
Created: $(date)
|
||||||
Location: $backup_dir
|
Location: $backup_dir
|
||||||
|
Container: $CONTAINER_MINECRAFT
|
||||||
Contents:
|
Contents:
|
||||||
- World data
|
- World data
|
||||||
- Configuration files
|
- Configuration files
|
||||||
|
|
@ -62,7 +84,10 @@ backup_teamspeak() {
|
||||||
log_info "Backing up TeamSpeak server..."
|
log_info "Backing up TeamSpeak server..."
|
||||||
|
|
||||||
local backup_dir="$BACKUP_ROOT/teamspeak/$TIMESTAMP"
|
local backup_dir="$BACKUP_ROOT/teamspeak/$TIMESTAMP"
|
||||||
ensure_backup_dir "$backup_dir"
|
ensure_dir "$backup_dir"
|
||||||
|
|
||||||
|
# Check if container is running
|
||||||
|
check_container_running "$CONTAINER_TEAMSPEAK" "TeamSpeak" || true
|
||||||
|
|
||||||
# Export Docker volume
|
# Export Docker volume
|
||||||
if docker volume ls | grep -q teamspeak_data; then
|
if docker volume ls | grep -q teamspeak_data; then
|
||||||
|
|
@ -73,6 +98,8 @@ backup_teamspeak() {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
log_info " ✓ Volume data backed up"
|
log_info " ✓ Volume data backed up"
|
||||||
|
else
|
||||||
|
log_warn " No TeamSpeak volume found"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
log_info " ✓ Backup complete: $backup_dir"
|
log_info " ✓ Backup complete: $backup_dir"
|
||||||
|
|
@ -82,14 +109,42 @@ backup_nextcloud() {
|
||||||
log_info "Backing up Nextcloud..."
|
log_info "Backing up Nextcloud..."
|
||||||
|
|
||||||
local backup_dir="$BACKUP_ROOT/nextcloud/$TIMESTAMP"
|
local backup_dir="$BACKUP_ROOT/nextcloud/$TIMESTAMP"
|
||||||
ensure_backup_dir "$backup_dir"
|
ensure_dir "$backup_dir"
|
||||||
|
|
||||||
# Backup database
|
# Load Nextcloud environment if available
|
||||||
|
local nextcloud_env="$PROJECT_ROOT/nextcloud/.env"
|
||||||
|
if [[ -f "$nextcloud_env" ]]; then
|
||||||
|
log_info " Loading Nextcloud environment..."
|
||||||
|
load_env "$nextcloud_env"
|
||||||
|
else
|
||||||
|
log_warn " No .env file found at $nextcloud_env"
|
||||||
|
log_warn " Using default credentials (not recommended)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validate required environment variables
|
||||||
|
if [[ -z "${MYSQL_PASSWORD:-}" ]]; then
|
||||||
|
log_warn " MYSQL_PASSWORD not set, database backup may fail"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if database container is running
|
||||||
|
if ! check_container_running "$CONTAINER_NEXTCLOUD_DB" "Nextcloud DB"; then
|
||||||
|
log_error " Database container must be running for backup"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Backup database (use environment variable, no default password)
|
||||||
log_info " Backing up database..."
|
log_info " Backing up database..."
|
||||||
docker exec nextcloud-db mariadb-dump -unextcloud -p"${MYSQL_PASSWORD:-ChangeDb123!}" nextcloud \
|
if [[ -n "${MYSQL_PASSWORD:-}" ]]; then
|
||||||
> "$backup_dir/database.sql" 2>/dev/null || {
|
docker exec "$CONTAINER_NEXTCLOUD_DB" mariadb-dump \
|
||||||
log_error " Database backup failed"
|
-u"${MYSQL_USER:-nextcloud}" \
|
||||||
}
|
-p"$MYSQL_PASSWORD" \
|
||||||
|
--single-transaction \
|
||||||
|
"${MYSQL_DATABASE:-nextcloud}" > "$backup_dir/database.sql" 2>/dev/null || {
|
||||||
|
log_error " Database backup failed"
|
||||||
|
}
|
||||||
|
else
|
||||||
|
log_error " Skipping database backup: MYSQL_PASSWORD not set"
|
||||||
|
fi
|
||||||
|
|
||||||
# Export volumes
|
# Export volumes
|
||||||
for vol in nextcloud_html nextcloud_data nextcloud_config nextcloud_apps; do
|
for vol in nextcloud_html nextcloud_data nextcloud_config nextcloud_apps; do
|
||||||
|
|
@ -107,6 +162,7 @@ backup_nextcloud() {
|
||||||
Nextcloud Backup
|
Nextcloud Backup
|
||||||
Created: $(date)
|
Created: $(date)
|
||||||
Location: $backup_dir
|
Location: $backup_dir
|
||||||
|
Containers: $CONTAINER_NEXTCLOUD, $CONTAINER_NEXTCLOUD_DB, $CONTAINER_NEXTCLOUD_REDIS
|
||||||
Contents:
|
Contents:
|
||||||
- MariaDB database dump
|
- MariaDB database dump
|
||||||
- Application volumes
|
- Application volumes
|
||||||
|
|
@ -116,31 +172,84 @@ EOF
|
||||||
log_info " ✓ Backup complete: $backup_dir"
|
log_info " ✓ Backup complete: $backup_dir"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Utility functions
|
||||||
|
# ============================================================================
|
||||||
list_backups() {
|
list_backups() {
|
||||||
log_info "Available backups:"
|
log_info "Available backups:"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
|
local found=0
|
||||||
for service in minecraft teamspeak nextcloud; do
|
for service in minecraft teamspeak nextcloud; do
|
||||||
if [[ -d "$BACKUP_ROOT/$service" ]]; then
|
if [[ -d "$BACKUP_ROOT/$service" ]]; then
|
||||||
|
found=1
|
||||||
echo "=== $service ==="
|
echo "=== $service ==="
|
||||||
ls -lh "$BACKUP_ROOT/$service" | tail -n +2
|
ls -lh "$BACKUP_ROOT/$service" 2>/dev/null | tail -n +2 || echo " (empty)"
|
||||||
echo
|
echo
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
if [[ $found -eq 0 ]]; then
|
||||||
|
log_info "No backups found in $BACKUP_ROOT"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup_old_backups() {
|
cleanup_old_backups() {
|
||||||
local keep_days="${1:-7}"
|
local keep_days="${1:-$BACKUP_RETENTION_DAYS}"
|
||||||
|
|
||||||
|
if [[ ! -d "$BACKUP_ROOT" ]]; then
|
||||||
|
log_info "No backup directory found"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
log_info "Cleaning up backups older than $keep_days days..."
|
log_info "Cleaning up backups older than $keep_days days..."
|
||||||
|
|
||||||
find "$BACKUP_ROOT" -type f -name "*.tar.gz" -mtime +"$keep_days" -delete
|
local count_before
|
||||||
find "$BACKUP_ROOT" -type d -empty -delete
|
count_before=$(find "$BACKUP_ROOT" -type f -name "*.tar.gz" 2>/dev/null | wc -l)
|
||||||
|
|
||||||
log_info " ✓ Cleanup complete"
|
find "$BACKUP_ROOT" -type f -name "*.tar.gz" -mtime +"$keep_days" -delete 2>/dev/null || true
|
||||||
|
find "$BACKUP_ROOT" -type f -name "*.sql" -mtime +"$keep_days" -delete 2>/dev/null || true
|
||||||
|
find "$BACKUP_ROOT" -type f -name "manifest.txt" -mtime +"$keep_days" -delete 2>/dev/null || true
|
||||||
|
find "$BACKUP_ROOT" -type d -empty -delete 2>/dev/null || true
|
||||||
|
|
||||||
|
local count_after
|
||||||
|
count_after=$(find "$BACKUP_ROOT" -type f -name "*.tar.gz" 2>/dev/null | wc -l)
|
||||||
|
|
||||||
|
local removed=$((count_before - count_after))
|
||||||
|
log_info " ✓ Cleanup complete (removed $removed archive(s))"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Main
|
||||||
|
# ============================================================================
|
||||||
|
show_usage() {
|
||||||
|
cat <<EOF
|
||||||
|
Usage: $0 <command> [options]
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
backup [service] Create backup (default: all)
|
||||||
|
list List available backups
|
||||||
|
cleanup [days] Remove backups older than N days (default: $BACKUP_RETENTION_DAYS)
|
||||||
|
|
||||||
|
Services:
|
||||||
|
minecraft, teamspeak, nextcloud, all
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
$0 backup minecraft
|
||||||
|
$0 backup all
|
||||||
|
$0 list
|
||||||
|
$0 cleanup 30
|
||||||
|
|
||||||
|
Environment:
|
||||||
|
BACKUP_ROOT Backup directory (default: ./backups)
|
||||||
|
BACKUP_RETENTION_DAYS Days to keep backups (default: 7)
|
||||||
|
EOF
|
||||||
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
|
check_prerequisites
|
||||||
|
|
||||||
local action="${1:-backup}"
|
local action="${1:-backup}"
|
||||||
local service="${2:-all}"
|
local service="${2:-all}"
|
||||||
|
|
||||||
|
|
@ -162,8 +271,8 @@ main() {
|
||||||
backup_nextcloud || true
|
backup_nextcloud || true
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Usage: $0 backup [minecraft|teamspeak|nextcloud|all]"
|
log_error "Unknown service: $service"
|
||||||
exit 1
|
show_usage
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
;;
|
;;
|
||||||
|
|
@ -171,26 +280,14 @@ main() {
|
||||||
list_backups
|
list_backups
|
||||||
;;
|
;;
|
||||||
cleanup)
|
cleanup)
|
||||||
cleanup_old_backups "${service:-7}"
|
cleanup_old_backups "${service:-$BACKUP_RETENTION_DAYS}"
|
||||||
|
;;
|
||||||
|
-h|--help|help)
|
||||||
|
show_usage
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
cat <<EOF
|
log_error "Unknown command: $action"
|
||||||
Usage: $0 <command> [options]
|
show_usage
|
||||||
|
|
||||||
Commands:
|
|
||||||
backup [service] Create backup (default: all)
|
|
||||||
list List available backups
|
|
||||||
cleanup [days] Remove backups older than N days (default: 7)
|
|
||||||
|
|
||||||
Services:
|
|
||||||
minecraft, teamspeak, nextcloud, all
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
$0 backup minecraft
|
|
||||||
$0 list
|
|
||||||
$0 cleanup 30
|
|
||||||
EOF
|
|
||||||
exit 1
|
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,109 +4,78 @@
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
readonly RED='\033[0;31m'
|
# Source shared library and config
|
||||||
readonly GREEN='\033[0;32m'
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
readonly YELLOW='\033[1;33m'
|
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||||
readonly NC='\033[0m'
|
source "$SCRIPT_DIR/lib/common.sh"
|
||||||
|
source "$PROJECT_ROOT/config.sh"
|
||||||
log_info() { echo -e "${GREEN}[INFO]${NC} $*"; }
|
|
||||||
log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
|
||||||
log_error() { echo -e "${RED}[ERROR]${NC} $*"; }
|
|
||||||
|
|
||||||
check_container_health() {
|
|
||||||
local container_name="$1"
|
|
||||||
|
|
||||||
if ! docker ps --filter "name=$container_name" --format '{{.Names}}' | grep -q "$container_name"; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
local status
|
|
||||||
status=$(docker inspect --format='{{.State.Status}}' "$container_name" 2>/dev/null)
|
|
||||||
|
|
||||||
if [[ "$status" == "running" ]]; then
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
check_port() {
|
|
||||||
local host="${1:-localhost}"
|
|
||||||
local port="$2"
|
|
||||||
|
|
||||||
if timeout 2 bash -c "cat < /dev/null > /dev/tcp/$host/$port" 2>/dev/null; then
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
check_minecraft() {
|
check_minecraft() {
|
||||||
log_info "Checking Minecraft server..."
|
log_info "Checking Minecraft server..."
|
||||||
|
|
||||||
if check_container_health "mc-fabric-1.21.1"; then
|
if check_container_health "$CONTAINER_MINECRAFT"; then
|
||||||
log_info " ✓ Container is running"
|
log_info " ✓ Container is running"
|
||||||
else
|
else
|
||||||
log_error " ✗ Container is not running"
|
log_error " ✗ Container is not running"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if check_port "localhost" 25565; then
|
if check_port "localhost" "$PORT_MINECRAFT"; then
|
||||||
log_info " ✓ Server port 25565 is accessible"
|
log_info " ✓ Server port $PORT_MINECRAFT is accessible"
|
||||||
else
|
else
|
||||||
log_warn " ⚠ Server port 25565 is not accessible"
|
log_warn " ⚠ Server port $PORT_MINECRAFT is not accessible"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if check_port "localhost" 25575; then
|
if check_port "localhost" "$PORT_MINECRAFT_RCON"; then
|
||||||
log_info " ✓ RCON port 25575 is accessible"
|
log_info " ✓ RCON port $PORT_MINECRAFT_RCON is accessible"
|
||||||
else
|
else
|
||||||
log_warn " ⚠ RCON port 25575 is not accessible"
|
log_warn " ⚠ RCON port $PORT_MINECRAFT_RCON is not accessible"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
check_teamspeak() {
|
check_teamspeak() {
|
||||||
log_info "Checking TeamSpeak server..."
|
log_info "Checking TeamSpeak server..."
|
||||||
|
|
||||||
if check_container_health "teamspeak-server"; then
|
if check_container_health "$CONTAINER_TEAMSPEAK"; then
|
||||||
log_info " ✓ Container is running"
|
log_info " ✓ Container is running"
|
||||||
else
|
else
|
||||||
log_error " ✗ Container is not running"
|
log_error " ✗ Container is not running"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if check_port "localhost" 10011; then
|
if check_port "localhost" "$PORT_TEAMSPEAK_QUERY"; then
|
||||||
log_info " ✓ File transfer port 10011 is accessible"
|
log_info " ✓ Query port $PORT_TEAMSPEAK_QUERY is accessible"
|
||||||
else
|
else
|
||||||
log_warn " ⚠ Port 10011 is not accessible"
|
log_warn " ⚠ Port $PORT_TEAMSPEAK_QUERY is not accessible"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
check_nextcloud() {
|
check_nextcloud() {
|
||||||
log_info "Checking Nextcloud..."
|
log_info "Checking Nextcloud..."
|
||||||
|
|
||||||
if check_container_health "nextcloud"; then
|
if check_container_health "$CONTAINER_NEXTCLOUD"; then
|
||||||
log_info " ✓ Nextcloud container is running"
|
log_info " ✓ Nextcloud container is running"
|
||||||
else
|
else
|
||||||
log_error " ✗ Nextcloud container is not running"
|
log_error " ✗ Nextcloud container is not running"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if check_container_health "nextcloud-db"; then
|
if check_container_health "$CONTAINER_NEXTCLOUD_DB"; then
|
||||||
log_info " ✓ Database container is running"
|
log_info " ✓ Database container is running"
|
||||||
else
|
else
|
||||||
log_error " ✗ Database container is not running"
|
log_error " ✗ Database container is not running"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if check_container_health "nextcloud-redis"; then
|
if check_container_health "$CONTAINER_NEXTCLOUD_REDIS"; then
|
||||||
log_info " ✓ Redis container is running"
|
log_info " ✓ Redis container is running"
|
||||||
else
|
else
|
||||||
log_warn " ⚠ Redis container is not running"
|
log_warn " ⚠ Redis container is not running"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if check_port "localhost" 8080; then
|
if check_port "localhost" "$PORT_NEXTCLOUD_WEB"; then
|
||||||
log_info " ✓ Web interface port 8080 is accessible"
|
log_info " ✓ Web interface port $PORT_NEXTCLOUD_WEB is accessible"
|
||||||
else
|
else
|
||||||
log_warn " ⚠ Port 8080 is not accessible"
|
log_warn " ⚠ Port $PORT_NEXTCLOUD_WEB is not accessible"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
119
bin/lib/common.sh
Normal file
119
bin/lib/common.sh
Normal file
|
|
@ -0,0 +1,119 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Shared utility library for all scripts
|
||||||
|
# Source this file: source "$(dirname "$0")/lib/common.sh"
|
||||||
|
|
||||||
|
# Prevent multiple sourcing
|
||||||
|
[[ -n "${_COMMON_SH_LOADED:-}" ]] && return
|
||||||
|
readonly _COMMON_SH_LOADED=1
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Color definitions
|
||||||
|
# ============================================================================
|
||||||
|
readonly RED='\033[0;31m'
|
||||||
|
readonly GREEN='\033[0;32m'
|
||||||
|
readonly YELLOW='\033[1;33m'
|
||||||
|
readonly BLUE='\033[0;34m'
|
||||||
|
readonly NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Logging functions
|
||||||
|
# ============================================================================
|
||||||
|
log_info() { echo -e "${GREEN}[INFO]${NC} $*"; }
|
||||||
|
log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||||||
|
log_error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
|
||||||
|
log_debug() { [[ "${DEBUG:-}" == "1" ]] && echo -e "${BLUE}[DEBUG]${NC} $*"; }
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Container utilities
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# Check if a container is running
|
||||||
|
# Usage: check_container_health "container_name"
|
||||||
|
# Returns: 0 if running, 1 otherwise
|
||||||
|
check_container_health() {
|
||||||
|
local container_name="$1"
|
||||||
|
|
||||||
|
if ! docker ps --filter "name=$container_name" --format '{{.Names}}' | grep -q "^${container_name}$"; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local status
|
||||||
|
status=$(docker inspect --format='{{.State.Status}}' "$container_name" 2>/dev/null)
|
||||||
|
|
||||||
|
[[ "$status" == "running" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if a port is accessible
|
||||||
|
# Usage: check_port "host" "port"
|
||||||
|
# Returns: 0 if accessible, 1 otherwise
|
||||||
|
check_port() {
|
||||||
|
local host="${1:-localhost}"
|
||||||
|
local port="$2"
|
||||||
|
|
||||||
|
if timeout 2 bash -c "cat < /dev/null > /dev/tcp/$host/$port" 2>/dev/null; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# File utilities
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# Ensure a directory exists
|
||||||
|
# Usage: ensure_dir "/path/to/dir"
|
||||||
|
ensure_dir() {
|
||||||
|
local dir="$1"
|
||||||
|
[[ -d "$dir" ]] || mkdir -p "$dir"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if a command exists
|
||||||
|
# Usage: require_command "docker" "https://docs.docker.com/get-docker/"
|
||||||
|
require_command() {
|
||||||
|
local cmd="$1"
|
||||||
|
local install_url="${2:-}"
|
||||||
|
|
||||||
|
if ! command -v "$cmd" &>/dev/null; then
|
||||||
|
log_error "$cmd is not installed"
|
||||||
|
[[ -n "$install_url" ]] && log_info "Install from: $install_url"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Environment utilities
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# Load .env file if it exists
|
||||||
|
# Usage: load_env "/path/to/.env"
|
||||||
|
load_env() {
|
||||||
|
local env_file="${1:-.env}"
|
||||||
|
|
||||||
|
if [[ -f "$env_file" ]]; then
|
||||||
|
set -a
|
||||||
|
# shellcheck source=/dev/null
|
||||||
|
source "$env_file"
|
||||||
|
set +a
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Validate that required environment variables are set
|
||||||
|
# Usage: require_env "VAR1" "VAR2" "VAR3"
|
||||||
|
require_env() {
|
||||||
|
local missing=()
|
||||||
|
for var in "$@"; do
|
||||||
|
if [[ -z "${!var:-}" ]]; then
|
||||||
|
missing+=("$var")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ ${#missing[@]} -gt 0 ]]; then
|
||||||
|
log_error "Missing required environment variables: ${missing[*]}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
@ -7,16 +7,9 @@
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
# Colors for output
|
# Source shared library
|
||||||
readonly RED='\033[0;31m'
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
readonly GREEN='\033[0;32m'
|
source "$SCRIPT_DIR/lib/common.sh"
|
||||||
readonly YELLOW='\033[1;33m'
|
|
||||||
readonly NC='\033[0m' # No Color
|
|
||||||
|
|
||||||
# Logging functions
|
|
||||||
log_info() { echo -e "${GREEN}[INFO]${NC} $*"; }
|
|
||||||
log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
|
||||||
log_error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
|
|
||||||
|
|
||||||
# Check prerequisites
|
# Check prerequisites
|
||||||
check_prerequisites() {
|
check_prerequisites() {
|
||||||
|
|
|
||||||
43
config.sh
Normal file
43
config.sh
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Centralized configuration for all services
|
||||||
|
# Source this file to get consistent container names and settings
|
||||||
|
|
||||||
|
# Prevent multiple sourcing
|
||||||
|
[[ -n "${_CONFIG_SH_LOADED:-}" ]] && return
|
||||||
|
readonly _CONFIG_SH_LOADED=1
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Container Names
|
||||||
|
# ============================================================================
|
||||||
|
# These are the canonical container names used across all scripts.
|
||||||
|
# Update here if container names change in docker-compose.yml files.
|
||||||
|
|
||||||
|
readonly CONTAINER_MINECRAFT="${CONTAINER_MINECRAFT:-mc-fabric-1.21.1}"
|
||||||
|
readonly CONTAINER_TEAMSPEAK="${CONTAINER_TEAMSPEAK:-teamspeak-server}"
|
||||||
|
readonly CONTAINER_NEXTCLOUD="${CONTAINER_NEXTCLOUD:-nextcloud}"
|
||||||
|
readonly CONTAINER_NEXTCLOUD_DB="${CONTAINER_NEXTCLOUD_DB:-nextcloud-db}"
|
||||||
|
readonly CONTAINER_NEXTCLOUD_REDIS="${CONTAINER_NEXTCLOUD_REDIS:-nextcloud-redis}"
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Service Ports
|
||||||
|
# ============================================================================
|
||||||
|
readonly PORT_MINECRAFT=25565
|
||||||
|
readonly PORT_MINECRAFT_RCON=25575
|
||||||
|
readonly PORT_TEAMSPEAK_VOICE=9987
|
||||||
|
readonly PORT_TEAMSPEAK_FILETRANSFER=30033
|
||||||
|
readonly PORT_TEAMSPEAK_QUERY=10011
|
||||||
|
readonly PORT_NEXTCLOUD_WEB=8080
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Backup Configuration
|
||||||
|
# ============================================================================
|
||||||
|
readonly BACKUP_ROOT="${BACKUP_ROOT:-./backups}"
|
||||||
|
readonly BACKUP_RETENTION_DAYS="${BACKUP_RETENTION_DAYS:-7}"
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Helper function to get project root
|
||||||
|
# ============================================================================
|
||||||
|
get_project_root() {
|
||||||
|
local script_path="${BASH_SOURCE[1]:-$0}"
|
||||||
|
cd "$(dirname "$script_path")" && pwd
|
||||||
|
}
|
||||||
19
minecraft/.env.example
Normal file
19
minecraft/.env.example
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Minecraft Server Environment Configuration
|
||||||
|
# Copy this file to .env and modify the values
|
||||||
|
# Usage: cp .env.example .env && chmod 600 .env
|
||||||
|
|
||||||
|
# User permissions (avoid container file permission issues)
|
||||||
|
# Replace with your host user UID/GID, use 'id' command to check
|
||||||
|
UID=1000
|
||||||
|
GID=1000
|
||||||
|
|
||||||
|
# RCON password (remote control, must be complex and secure)
|
||||||
|
# Generate a strong password: openssl rand -base64 32
|
||||||
|
RCON_PASSWORD=your_secure_rcon_password_here
|
||||||
|
|
||||||
|
# Timezone (adjust based on server location)
|
||||||
|
# Examples: America/New_York, Europe/London, Asia/Shanghai
|
||||||
|
TZ=Asia/Shanghai
|
||||||
|
|
||||||
|
# Container name (used by scripts for health checks)
|
||||||
|
CONTAINER_NAME=mc-fabric-1.21.1
|
||||||
Loading…
Reference in a new issue