File size: 10,876 Bytes
9b205e1 28975d3 9b205e1 cf5db51 2889faa cf5db51 9b205e1 cf5db51 fb4f47d 9b205e1 cf5db51 9b205e1 cf5db51 9b205e1 cf5db51 9b205e1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 | #!/bin/bash
set -e
# Log function
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [MAIN] $*"
}
# Array to store background process PIDs
declare -a SERVICE_PIDS=()
# Function to extract service name from script filename
get_service_name() {
local script_name="$1"
# Remove -start.sh suffix and convert to uppercase for env var
echo "$script_name" | sed 's/-start\.sh$//' | tr '[:lower:]' '[:upper:]' | tr '-' '_'
}
# Define start directory path
start_dir="script/start"
# Function to start persistence service synchronously (BLOCKING)
start_persistence_service() {
local persistence_script="$start_dir/persistence-start.sh"
if [[ -f "$persistence_script" ]] && [[ "${PERSISTENCE_ENABLED:-false}" == "true" ]]; then
log "=== STARTING PERSISTENCE SERVICE (SYNCHRONOUS) ==="
log "This is a BLOCKING operation that must complete before other services start"
if "$persistence_script"; then
log "✓ Persistence service completed successfully"
log "Data restoration and verification completed"
return 0
else
log "✗ Persistence service failed"
log "ERROR: Cannot proceed with other services due to persistence failure"
exit 1
fi
else
if [[ "${PERSISTENCE_ENABLED:-false}" == "true" ]]; then
log "WARNING: Persistence enabled but script not found: $persistence_script"
else
log "Persistence service is disabled"
fi
return 0
fi
}
# Function to perform restic auto-restore BEFORE any services start
perform_restic_restore() {
log "=== CHECKING FOR RESTIC AUTO-RESTORE ==="
# Prepare restic environment first
local user_home="${HOME:-/home/user}"
local config_file="$user_home/config/restic.conf"
# Load restic configuration BEFORE checking RESTIC_AUTO_RESTORE
if [[ -f "$config_file" ]]; then
log "Loading restic config from: $config_file"
# Load config with environment variable precedence
local temp_config="/tmp/restic_config_$$"
sed 's/^\([^#]*\)=\(.*\)$/\1=${\1:-\2}/' "$config_file" > "$temp_config"
source "$temp_config"
rm -f "$temp_config"
log "Configuration loaded successfully"
else
log "No restic configuration file found: $config_file"
fi
# Now check if restic auto-restore is enabled (after loading config)
if [[ "${RESTIC_AUTO_RESTORE:-false}" != "true" ]]; then
log "Restic auto-restore is disabled"
return 0
fi
log "Restic auto-restore is enabled - performing data restoration BEFORE services start"
# Set up restic environment
export RESTIC_REPOSITORY="${RESTIC_REPOSITORY_PATH:-}"
export RESTIC_PASSWORD="${RESTIC_PASSWORD:-}"
export RESTIC_CACHE_DIR="${RESTIC_CACHE_DIR:-$user_home/.cache/restic}"
# Check if restic is available
if ! command -v restic &> /dev/null; then
log "WARNING: Restic command not found, skipping auto-restore"
log "Install restic to enable backup/restore functionality"
return 0
fi
# Check if repository is accessible
if ! restic snapshots > /dev/null 2>&1; then
log "WARNING: Cannot access restic repository, skipping auto-restore"
log "This might be the first startup or repository is not yet initialized"
log "To create a repository, set RESTIC_ENABLED=true and restart the service"
return 0
fi
# Check if we have snapshots available - simplified to just check if any exist
if ! restic snapshots --json | jq -e '. | length > 0' > /dev/null 2>&1; then
log "No snapshots available for restore, skipping auto-restore"
return 0
fi
# Use the restore script for proper restoration with latest snapshot
local restore_script="script/utils/restic-restore.sh"
if [[ -x "$restore_script" ]]; then
log "Using restic restore script for data restoration with latest snapshot"
# Simplified arguments - always use latest snapshot
local args=("--mode" "${RESTIC_RESTORE_MODE:-safe}" "--force")
# Set restore target path
local restore_target
if [[ "${RESTIC_RESTORE_MODE:-safe}" == "safe" ]]; then
restore_target="${RESTIC_RESTORE_TARGET:-/tmp/restic_restore_$(date +%s)}"
else
# For replace/direct mode, use parent directory of backup paths as target
local backup_parent
backup_parent=$(dirname "${RESTIC_BACKUP_PATHS:-/home/user}")
restore_target="${RESTIC_RESTORE_TARGET:-$backup_parent}"
fi
[[ -n "$restore_target" ]] && args+=("--target" "$restore_target")
# Add include paths if specified
if [[ -n "${RESTIC_RESTORE_INCLUDE_PATHS:-}" ]]; then
IFS=':' read -ra paths <<< "$RESTIC_RESTORE_INCLUDE_PATHS"
for path in "${paths[@]}"; do
args+=("--include" "$path")
done
fi
# Always use latest - no need to pass snapshot ID
log "Executing restic restore: $restore_script ${args[*]} (using latest snapshot)"
if "$restore_script" "${args[@]}"; then
log "✓ Restic auto-restore completed successfully"
log "Data restoration finished - services can now start safely"
# For safe mode, provide guidance on next steps
if [[ "${RESTIC_RESTORE_MODE:-safe}" == "safe" ]]; then
log "Safe mode: Data restored to temporary location: $restore_target"
log "Please verify and manually copy data if needed"
fi
return 0
else
log "✗ Restic auto-restore failed"
return 1
fi
else
log "ERROR: Restic restore script not found: $restore_script"
return 1
fi
}
# Function to start optional services automatically (AFTER persistence)
start_optional_services() {
log "Auto-discovering and starting optional services..."
# Process all start scripts except core service and persistence
for script in "$start_dir"/*-start.sh; do
if [[ -f "$script" ]]; then
local script_name=$(basename "$script")
# Skip core service (handled separately) and persistence (handled above)
if [[ "$script_name" == "core-service-start.sh" || "$script_name" == "persistence-start.sh" ]]; then
continue
fi
# Extract service name and construct environment variable name
local service_name=$(echo "$script_name" | sed 's/-start\.sh$//')
local env_var_name=$(get_service_name "$script_name")_ENABLED
# Get the environment variable value (indirect variable expansion)
local is_enabled="${!env_var_name:-false}"
log "Processing service: $service_name (env: $env_var_name, enabled: $is_enabled)"
if [[ "$is_enabled" == "true" ]]; then
log "Starting $service_name..."
"$script" &
local pid=$!
SERVICE_PIDS+=($pid)
log "$service_name started with PID: $pid"
else
log "$service_name is disabled"
fi
fi
done
if [[ ${#SERVICE_PIDS[@]} -gt 0 ]]; then
log "Started ${#SERVICE_PIDS[@]} optional services with PIDs: ${SERVICE_PIDS[*]}"
else
log "No optional services were started"
fi
}
# Check for backup service conflicts (persistence vs restic)
check_backup_service_conflicts() {
if [[ "${PERSISTENCE_ENABLED:-false}" == "true" && "${RESTIC_ENABLED:-false}" == "true" ]]; then
log "ERROR: Cannot enable both persistence and restic services simultaneously!"
log "ERROR: Please choose one backup service:"
log "ERROR: - Use persistence: export PERSISTENCE_ENABLED=true RESTIC_ENABLED=false"
log "ERROR: - Use restic: export PERSISTENCE_ENABLED=false RESTIC_ENABLED=true"
exit 1
fi
}
# Load service configurations to ensure consistency with actual startup behavior
load_service_configs() {
# Load restic config if exists (same logic as in perform_restic_restore)
local user_home="${HOME:-/home/user}"
local restic_config="$user_home/config/restic.conf"
if [[ -f "$restic_config" ]]; then
local temp_config="/tmp/restic_config_display_$$"
sed 's/^\([^#]*\)=\(.*\)$/\1=${\1:-\2}/' "$restic_config" > "$temp_config"
source "$temp_config"
rm -f "$temp_config"
fi
# Load persistence config if exists
local persistence_config="$user_home/config/persistence.conf"
if [[ -f "$persistence_config" ]]; then
local temp_config="/tmp/persistence_config_display_$$"
sed 's/^\([^#]*\)=\(.*\)$/\1=${\1:-\2}/' "$persistence_config" > "$temp_config"
source "$temp_config"
rm -f "$temp_config"
fi
}
# Load service configurations first
load_service_configs
# Display service status summary
log "Service configuration:"
for script in "$start_dir"/*-start.sh; do
if [[ -f "$script" ]]; then
script_name=$(basename "$script")
if [[ "$script_name" != "core-service-start.sh" ]]; then
service_name=$(echo "$script_name" | sed 's/-start\.sh$//')
env_var_name=$(get_service_name "$script_name")_ENABLED
is_enabled="${!env_var_name:-false}"
log " $(echo "$service_name" | sed 's/\b\w/\U&/g'): $is_enabled"
fi
fi
done
# Check for backup service conflicts BEFORE starting any services
log "Checking for backup service conflicts..."
check_backup_service_conflicts
# PHASE 1: Start persistence service SYNCHRONOUSLY (BLOCKING)
log "=== PHASE 1: PERSISTENCE AND DATA RESTORATION (SYNCHRONOUS) ==="
start_persistence_service
# Perform restic auto-restore BEFORE any other services start
perform_restic_restore || {
log "ERROR: Data restoration failed - cannot proceed with service startup"
exit 1
}
# PHASE 2: Start optional services (AFTER persistence completes)
log "=== PHASE 2: OPTIONAL SERVICES ==="
log "Starting optional services (persistence completed)..."
start_optional_services
# PHASE 3: Start core service (required, must be last)
log "=== PHASE 3: CORE SERVICE ==="
log "Starting core service (all dependencies ready)..."
if [[ -f "$start_dir/core-service-start.sh" ]]; then
log "Found core service startup script, executing..."
exec "$start_dir/core-service-start.sh"
else
log "ERROR: Core service startup script not found: $start_dir/core-service-start.sh"
log "Please ensure you have implemented your core service according to the template documentation."
log "See docs/DEVELOPMENT.md for instructions on implementing your core service."
exit 1
fi
|