Skip to content

Commit 9f7ad36

Browse files
authored
Update restore_logs.sh: add interactive mode to select the file from the stage
1 parent 938c51a commit 9f7ad36

File tree

1 file changed

+257
-18
lines changed

1 file changed

+257
-18
lines changed

โ€Žscripts/selfhost/restore_logs.sh

Lines changed: 257 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,190 @@ log_step() {
1313
echo "[$(date '+%H:%M:%S')] [$1/$2] $3"
1414
}
1515

16+
# Show help information
17+
show_help() {
18+
cat <<EOF
19+
Usage: $0 --stage STAGE [YYYYMMDD]
20+
21+
Restore Databend system data from backup archive in stage.
22+
23+
RECOMMENDED USAGE:
24+
# Interactive file selection (recommended)
25+
$0 --stage backup_stage
26+
27+
# Restore specific date
28+
$0 --stage backup_stage 20250109
29+
30+
OPTIONS:
31+
--dsn DSN Database connection string (overrides BENDSQL_DSN env var)
32+
--stage STAGE Source stage name (required)
33+
--file FILENAME Specific file name in stage
34+
--interactive Force interactive mode
35+
-h, --help Show this help message
36+
37+
ENVIRONMENT VARIABLES:
38+
BENDSQL_DSN Default database connection string
39+
40+
INTERACTIVE CONTROLS:
41+
โ†‘/โ†“ or k/j Navigate files
42+
Enter Select file
43+
q Quit
44+
45+
EXAMPLES:
46+
export BENDSQL_DSN="http://username:password@localhost:8000/database"
47+
48+
# Best: Browse and select interactively
49+
$0 --stage my_backup_stage
50+
51+
# Quick: Restore specific date
52+
$0 --stage my_backup_stage 20250109
53+
EOF
54+
}
55+
56+
# Interactive file selector
57+
interactive_file_selector() {
58+
local stage="$1"
59+
local dsn="$2"
60+
61+
echo "Fetching file list from stage @${stage}..."
62+
63+
# Get file list
64+
local file_list
65+
file_list=$(bendsql --dsn "${dsn}" --query="list @${stage};" 2>/dev/null | awk '{print $1}' | grep -E '\.(tar\.gz|tgz)$' | sort)
66+
67+
if [[ -z "$file_list" ]]; then
68+
log_error "No .tar.gz files found in stage @${stage}"
69+
return 1
70+
fi
71+
72+
# Convert to array
73+
local files=()
74+
while IFS= read -r line; do
75+
[[ -n "$line" ]] && files+=("$line")
76+
done <<< "$file_list"
77+
78+
if [[ ${#files[@]} -eq 0 ]]; then
79+
log_error "No .tar.gz files found in stage @${stage}"
80+
return 1
81+
fi
82+
83+
# Default to last file
84+
local selected=$((${#files[@]} - 1))
85+
local total=${#files[@]}
86+
87+
echo ""
88+
echo "Found $total backup files in stage @${stage}:"
89+
echo "Use โ†‘/โ†“ or k/j to navigate, Enter to select, q to quit"
90+
echo ""
91+
92+
# Display function
93+
display_files() {
94+
# Clear screen and move to top
95+
echo -ne "\033[2J\033[H"
96+
echo "Stage: @${stage} ($total files)"
97+
echo "Use โ†‘/โ†“ or k/j to navigate, Enter to select, q to quit"
98+
echo ""
99+
100+
for i in "${!files[@]}"; do
101+
if [[ $i -eq $selected ]]; then
102+
echo -e "\033[7m> ${files[$i]}\033[0m" # Highlighted
103+
else
104+
echo " ${files[$i]}"
105+
fi
106+
done
107+
108+
echo ""
109+
echo "Selected: ${files[$selected]}"
110+
}
111+
112+
# Initial display
113+
display_files
114+
115+
# Input loop
116+
while true; do
117+
# Read single character
118+
read -rsn1 key
119+
120+
case "$key" in
121+
$'\033') # Escape sequence
122+
read -rsn2 key
123+
case "$key" in
124+
'[A') # Up arrow
125+
((selected > 0)) && ((selected--))
126+
display_files
127+
;;
128+
'[B') # Down arrow
129+
((selected < total - 1)) && ((selected++))
130+
display_files
131+
;;
132+
esac
133+
;;
134+
'k'|'K') # Up (vim-style)
135+
((selected > 0)) && ((selected--))
136+
display_files
137+
;;
138+
'j'|'J') # Down (vim-style)
139+
((selected < total - 1)) && ((selected++))
140+
display_files
141+
;;
142+
'') # Enter
143+
echo ""
144+
echo "Selected: ${files[$selected]}"
145+
SELECTED_FILE="${files[$selected]}"
146+
return 0
147+
;;
148+
'q'|'Q') # Quit
149+
echo ""
150+
echo "Selection cancelled."
151+
return 1
152+
;;
153+
esac
154+
done
155+
}
156+
157+
# Parse date from filename
158+
parse_date_from_filename() {
159+
local filename="$1"
160+
local basename=$(basename "$filename" .tar.gz)
161+
162+
# Try different patterns
163+
if [[ "$basename" =~ data_([0-9]{4})-([0-9]{2})-([0-9]{2}) ]]; then
164+
# Pattern: data_YYYY-MM-DD
165+
YEAR="${BASH_REMATCH[1]}"
166+
MONTH="${BASH_REMATCH[2]}"
167+
DAY="${BASH_REMATCH[3]}"
168+
elif [[ "$basename" =~ ([0-9]{4})([0-9]{2})([0-9]{2}) ]]; then
169+
# Pattern: YYYYMMDD anywhere in filename
170+
YEAR="${BASH_REMATCH[1]}"
171+
MONTH="${BASH_REMATCH[2]}"
172+
DAY="${BASH_REMATCH[3]}"
173+
else
174+
# Fallback to current date
175+
log "Could not extract date from filename: $filename, using current date"
176+
YEAR=$(date '+%Y')
177+
MONTH=$(date '+%m')
178+
DAY=$(date '+%d')
179+
fi
180+
181+
FORMATTED_DATE="${YEAR}-${MONTH}-${DAY}"
182+
DATE_ARG="${YEAR}${MONTH}${DAY}"
183+
}
184+
16185
# Parse arguments
186+
FILE_MODE=false
187+
INTERACTIVE_MODE=false
188+
STAGE=""
189+
DSN=""
190+
DATE_ARG=""
191+
TAR_FILE=""
192+
STAGE_FILE=""
193+
17194
while [[ $# -gt 0 ]]; do
18195
case "$1" in
196+
-h | --help)
197+
show_help
198+
exit 0
199+
;;
19200
--dsn)
20201
DSN="$2"
21202
shift 2
@@ -24,41 +205,98 @@ while [[ $# -gt 0 ]]; do
24205
STAGE="$2"
25206
shift 2
26207
;;
208+
--file)
209+
STAGE_FILE="$2"
210+
FILE_MODE=true
211+
shift 2
212+
;;
213+
--interactive)
214+
INTERACTIVE_MODE=true
215+
shift
216+
;;
27217
*)
28218
if [[ "$1" =~ ^[0-9]{8}$ ]]; then
219+
if [[ "$FILE_MODE" = true || "$INTERACTIVE_MODE" = true ]]; then
220+
log_error "Cannot specify date with --file or --interactive"
221+
echo "Use -h or --help for usage information." >&2
222+
exit 1
223+
fi
29224
DATE_ARG="$1"
30225
shift
31226
else
32227
log_error "Unknown parameter: $1"
228+
echo "Use -h or --help for usage information." >&2
33229
exit 1
34230
fi
35231
;;
36232
esac
37233
done
38234

39235
# Validate parameters
40-
if [[ -z "$STAGE" || -z "$DATE_ARG" ]]; then
41-
log_error "Missing required parameters: --stage or yyyymmdd date"
236+
if [[ -z "$STAGE" ]]; then
237+
log_error "Missing required parameter: --stage"
238+
echo "Use -h or --help for usage information." >&2
42239
exit 1
43240
fi
44241

242+
# Validate DSN early for interactive mode
45243
if [[ -z "$DSN" ]]; then
46244
DSN="$BENDSQL_DSN"
47245
if [[ -z "$DSN" ]]; then
48246
log_error "DSN not provided and BENDSQL_DSN not set"
247+
echo "Use -h or --help for usage information." >&2
49248
exit 1
50249
fi
51250
fi
52251

53-
# Format date
54-
YEAR=${DATE_ARG:0:4}
55-
MONTH=${DATE_ARG:4:2}
56-
DAY=${DATE_ARG:6:2}
57-
FORMATTED_DATE="${YEAR}-${MONTH}-${DAY}"
58-
TAR_FILE="data_${FORMATTED_DATE}.tar.gz"
252+
# Determine mode
253+
if [[ "$INTERACTIVE_MODE" = true ]] || [[ -z "$DATE_ARG" && -z "$STAGE_FILE" ]]; then
254+
# Interactive mode
255+
if ! interactive_file_selector "$STAGE" "$DSN"; then
256+
exit 1
257+
fi
258+
259+
STAGE_FILE="$SELECTED_FILE"
260+
FILE_MODE=true
261+
parse_date_from_filename "$SELECTED_FILE"
262+
TAR_FILE="$SELECTED_FILE"
263+
264+
elif [[ "$FILE_MODE" = true ]]; then
265+
# File mode validation
266+
if [[ -z "$STAGE_FILE" ]]; then
267+
log_error "Missing required parameter: --file"
268+
echo "Use -h or --help for usage information." >&2
269+
exit 1
270+
fi
271+
272+
# Parse date from filename
273+
parse_date_from_filename "$STAGE_FILE"
274+
TAR_FILE="$STAGE_FILE"
275+
276+
else
277+
# Date mode validation
278+
if [[ -z "$DATE_ARG" ]]; then
279+
log_error "Missing required parameter: yyyymmdd date"
280+
echo "Use -h or --help for usage information." >&2
281+
exit 1
282+
fi
283+
284+
# Format date
285+
YEAR=${DATE_ARG:0:4}
286+
MONTH=${DATE_ARG:4:2}
287+
DAY=${DATE_ARG:6:2}
288+
FORMATTED_DATE="${YEAR}-${MONTH}-${DAY}"
289+
TAR_FILE="data_${FORMATTED_DATE}.tar.gz"
290+
fi
59291

60-
log "Starting log restoration for date: ${FORMATTED_DATE}"
61-
log "Source stage: @${STAGE}, Target file: ${TAR_FILE}"
292+
# Show operation mode
293+
if [[ "$FILE_MODE" = true ]]; then
294+
log "Starting log restoration from stage file: ${TAR_FILE}"
295+
log "Source stage: @${STAGE}, Extracted date: ${FORMATTED_DATE}"
296+
else
297+
log "Starting log restoration for date: ${FORMATTED_DATE}"
298+
log "Source stage: @${STAGE}, Target file: ${TAR_FILE}"
299+
fi
62300

63301
# Step 1: Generate download URL
64302
log_step "1" "6" "Generating presigned download URL for @${STAGE}/${TAR_FILE}"
@@ -73,24 +311,25 @@ log "Download URL generated successfully"
73311

74312
# Step 2: Download backup
75313
log_step "2" "6" "Downloading ${TAR_FILE} from stage @${STAGE}"
76-
curl -s -o "${TAR_FILE}" "${DOWNLOAD_URL}"
314+
LOCAL_TAR_FILE=$(basename "$TAR_FILE")
315+
curl -s -o "${LOCAL_TAR_FILE}" "${DOWNLOAD_URL}"
77316

78-
if [[ ! -f "${TAR_FILE}" ]]; then
317+
if [[ ! -f "${LOCAL_TAR_FILE}" ]]; then
79318
log_error "Failed to download ${TAR_FILE}"
80319
exit 1
81320
fi
82321

83-
FILE_SIZE=$(du -h "${TAR_FILE}" | cut -f1)
322+
FILE_SIZE=$(du -h "${LOCAL_TAR_FILE}" | cut -f1)
84323
log "Downloaded ${TAR_FILE} successfully (${FILE_SIZE})"
85324

86325
# Step 3: Extract archive
87-
log_step "3" "6" "Extracting ${TAR_FILE} to temporary directory"
326+
log_step "3" "6" "Extracting ${LOCAL_TAR_FILE} to temporary directory"
88327
TEMP_DIR="temp_extracted_${DATE_ARG}"
89328
mkdir -p "${TEMP_DIR}"
90-
tar -xzf "${TAR_FILE}" -C "${TEMP_DIR}"
329+
tar -xzf "${LOCAL_TAR_FILE}" -C "${TEMP_DIR}"
91330

92331
EXTRACTED_FILES=$(find "${TEMP_DIR}" -type f | wc -l)
93-
log "Extracted ${EXTRACTED_FILES} files from ${TAR_FILE}"
332+
log "Extracted ${EXTRACTED_FILES} files from ${LOCAL_TAR_FILE}"
94333

95334
# Step 4: Detect path prefix
96335
log_step "4" "6" "Analyzing directory structure for path prefix"
@@ -158,8 +397,8 @@ echo # New line after progress
158397
log "Upload completed: ${UPLOAD_SUCCESS} successful, ${UPLOAD_FAILED} failed"
159398

160399
# Cleanup
161-
log "Cleaning up: removing ${TEMP_DIR} and ${TAR_FILE}"
162-
rm -rf "${TEMP_DIR}" "${TAR_FILE}"
400+
log "Cleaning up: removing ${TEMP_DIR} and ${LOCAL_TAR_FILE}"
401+
rm -rf "${TEMP_DIR}" "${LOCAL_TAR_FILE}"
163402

164403
# Step 6: Restore database
165404
RESTORE_DATABASE="${STAGE}_${YEAR}_${MONTH}_${DAY}"

0 commit comments

Comments
ย (0)