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