|
|
#!/bin/bash |
|
|
|
|
|
set -e |
|
|
|
|
|
|
|
|
log() { |
|
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [MAIN] $*" |
|
|
} |
|
|
|
|
|
|
|
|
declare -a SERVICE_PIDS=() |
|
|
|
|
|
|
|
|
get_service_name() { |
|
|
local script_name="$1" |
|
|
|
|
|
echo "$script_name" | sed 's/-start\.sh$//' | tr '[:lower:]' '[:upper:]' | tr '-' '_' |
|
|
} |
|
|
|
|
|
|
|
|
start_dir="script/start" |
|
|
|
|
|
|
|
|
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 |
|
|
} |
|
|
|
|
|
|
|
|
perform_restic_restore() { |
|
|
log "=== CHECKING FOR RESTIC AUTO-RESTORE ===" |
|
|
|
|
|
|
|
|
local user_home="${HOME:-/home/user}" |
|
|
local config_file="$user_home/config/restic.conf" |
|
|
|
|
|
|
|
|
if [[ -f "$config_file" ]]; then |
|
|
log "Loading restic config from: $config_file" |
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
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" |
|
|
|
|
|
|
|
|
export RESTIC_REPOSITORY="${RESTIC_REPOSITORY_PATH:-}" |
|
|
export RESTIC_PASSWORD="${RESTIC_PASSWORD:-}" |
|
|
export RESTIC_CACHE_DIR="${RESTIC_CACHE_DIR:-$user_home/.cache/restic}" |
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
local restore_script="script/utils/restic-restore.sh" |
|
|
if [[ -x "$restore_script" ]]; then |
|
|
log "Using restic restore script for data restoration with latest snapshot" |
|
|
|
|
|
|
|
|
local args=("--mode" "${RESTIC_RESTORE_MODE:-safe}" "--force") |
|
|
|
|
|
|
|
|
local restore_target |
|
|
if [[ "${RESTIC_RESTORE_MODE:-safe}" == "safe" ]]; then |
|
|
restore_target="${RESTIC_RESTORE_TARGET:-/tmp/restic_restore_$(date +%s)}" |
|
|
else |
|
|
|
|
|
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") |
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
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" |
|
|
|
|
|
|
|
|
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 |
|
|
} |
|
|
|
|
|
|
|
|
start_optional_services() { |
|
|
log "Auto-discovering and starting optional services..." |
|
|
|
|
|
|
|
|
for script in "$start_dir"/*-start.sh; do |
|
|
if [[ -f "$script" ]]; then |
|
|
local script_name=$(basename "$script") |
|
|
|
|
|
|
|
|
if [[ "$script_name" == "core-service-start.sh" || "$script_name" == "persistence-start.sh" ]]; then |
|
|
continue |
|
|
fi |
|
|
|
|
|
|
|
|
local service_name=$(echo "$script_name" | sed 's/-start\.sh$//') |
|
|
local env_var_name=$(get_service_name "$script_name")_ENABLED |
|
|
|
|
|
|
|
|
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_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_configs() { |
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
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_configs |
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
log "Checking for backup service conflicts..." |
|
|
check_backup_service_conflicts |
|
|
|
|
|
|
|
|
log "=== PHASE 1: PERSISTENCE AND DATA RESTORATION (SYNCHRONOUS) ===" |
|
|
start_persistence_service |
|
|
|
|
|
|
|
|
perform_restic_restore || { |
|
|
log "ERROR: Data restoration failed - cannot proceed with service startup" |
|
|
exit 1 |
|
|
} |
|
|
|
|
|
|
|
|
log "=== PHASE 2: OPTIONAL SERVICES ===" |
|
|
log "Starting optional services (persistence completed)..." |
|
|
start_optional_services |
|
|
|
|
|
|
|
|
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 |
|
|
|