Compare commits
2 Commits
8b636b38c5
...
a8161f04e5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8161f04e5 | ||
|
|
4ce0340ef8 |
@ -2,4 +2,3 @@
|
||||
# Backup General - Scheduling
|
||||
# ================================================================================
|
||||
CFG_BACKUP_CRONTAB_APP="0 5 * * *" # App Backup Schedule - Crontab schedule for application backups
|
||||
CFG_BACKUP_CRONTAB_APP_INTERVAL=3 # App Backup Interval - Minutes between app backup checks
|
||||
|
||||
@ -650,13 +650,6 @@ class ConfigShared {
|
||||
fieldHTML += `
|
||||
<input type="url" id="${fieldId}" name="${key}" value="${value}" class="form-control" placeholder="${placeholder}">
|
||||
`;
|
||||
} else if (key === 'CFG_BACKUP_CRONTAB_APP_INTERVAL') {
|
||||
fieldHTML += `
|
||||
<div class="input-group">
|
||||
<input type="number" id="${fieldId}" name="${key}" value="${value}" class="form-control" min="1" max="1440" placeholder="3">
|
||||
<span class="input-group-text">minutes</span>
|
||||
</div>
|
||||
`;
|
||||
} else if (/^CFG_BACKUP(_LOC_[0-9]+)?_KEEP_(LAST|DAILY|WEEKLY|MONTHLY|YEARLY)$/.test(key)) {
|
||||
const unitLabel = key.endsWith('_KEEP_LAST') ? 'snapshots' :
|
||||
key.endsWith('_KEEP_DAILY') ? 'days' :
|
||||
|
||||
32
scripts/backup/app/backup_schedule_all.sh
Normal file
32
scripts/backup/app/backup_schedule_all.sh
Normal file
@ -0,0 +1,32 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Enqueue a backup for every installed app that has backups enabled. Invoked
|
||||
# once daily by the backup scheduler crontab entry. Each app is handed to
|
||||
# backupAppSchedule, which queues a task for the processor (WebUI installs) or
|
||||
# runs the backup inline (terminal-only installs).
|
||||
backupScheduleEnabledApps()
|
||||
{
|
||||
isHeader "Scheduling backups for enabled applications"
|
||||
|
||||
if [ ! -f "$docker_dir/$db_file" ]; then
|
||||
isError "Database not found: $docker_dir/$db_file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local app_names=()
|
||||
while IFS= read -r name; do
|
||||
[[ -z "$name" ]] && continue
|
||||
app_names+=("$name")
|
||||
done < <(sudo sqlite3 "$docker_dir/$db_file" "SELECT name FROM apps WHERE status = 1;")
|
||||
|
||||
local queued=0
|
||||
for name in "${app_names[@]}"; do
|
||||
local backup_flag="CFG_${name^^}_BACKUP"
|
||||
if [[ "${!backup_flag}" == "true" ]]; then
|
||||
backupAppSchedule "$name"
|
||||
((queued++))
|
||||
fi
|
||||
done
|
||||
|
||||
isSuccessful "Backup scheduling complete — $queued app(s) queued"
|
||||
}
|
||||
@ -54,6 +54,9 @@ cliHandleBackupCommands()
|
||||
all)
|
||||
backupAllApps
|
||||
;;
|
||||
scheduled)
|
||||
backupScheduleEnabledApps
|
||||
;;
|
||||
location)
|
||||
case "$action" in
|
||||
add)
|
||||
|
||||
@ -21,6 +21,9 @@ cliShowBackupHelp()
|
||||
echo "backup all"
|
||||
echo " Snapshot every installed app."
|
||||
echo ""
|
||||
echo "backup scheduled"
|
||||
echo " Queue a backup for every app with backups enabled (daily cron entry)."
|
||||
echo ""
|
||||
echo "backup location add <name> [type]"
|
||||
echo " Add a new backup location. Type defaults to 'local'."
|
||||
echo " Types: local, sftp, rest, s3, b2, gs, azure, rclone"
|
||||
|
||||
@ -40,7 +40,7 @@ viewAppConfigs()
|
||||
isNotice "Exiting..."
|
||||
echo ""
|
||||
checkConfigFilesMissingVariables true
|
||||
crontabSetupAllAppBackups true
|
||||
crontabSetupBackupScheduler
|
||||
fi
|
||||
elif [[ "$selected_app_number" =~ ^[0-9]+$ ]] && [ "$selected_app_number" -ge 1 ] && [ "$selected_app_number" -le ${#installed_apps[@]} ]; then
|
||||
local index=$((selected_app_number - 1))
|
||||
|
||||
@ -102,7 +102,7 @@ viewLibrePortalConfigs()
|
||||
isNotice "Exiting..."
|
||||
echo ""
|
||||
checkConfigFilesMissingVariables true;
|
||||
crontabSetupAllAppBackups true;
|
||||
crontabSetupBackupScheduler;
|
||||
fi
|
||||
elif [[ "$selected_number" =~ ^[0-9]+$ ]] && [ "$selected_number" -ge 1 ] && [ "$selected_number" -le ${#config_files[@]} ]; then
|
||||
local index=$((selected_number - 1))
|
||||
|
||||
@ -1,54 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
crontabSetupAllAppBackups()
|
||||
{
|
||||
local show_header=$1
|
||||
local ISCRON=$( (sudo -u $sudo_user_name crontab -l) 2>/dev/null )
|
||||
|
||||
# Check to see if installed
|
||||
if [[ "$ISCRON" == *"command not found"* ]]; then
|
||||
isNotice "Crontab is not found. Unable to set up backups."
|
||||
fi
|
||||
|
||||
# Check to see if crontab is not installed
|
||||
if ! sudo -u $sudo_user_name crontab -l 2>/dev/null | grep -q "cron is set up for $sudo_user_name" > /dev/null 2>&1; then
|
||||
isNotice "Crontab is not set up, skipping until it's found."
|
||||
fi
|
||||
|
||||
# Check if the database file exists
|
||||
if [ ! -f "$docker_dir/$db_file" ]; then
|
||||
isNotice "Database file not found: $docker_dir/$db_file"
|
||||
fi
|
||||
|
||||
if [[ $show_header != "false" ]]; then
|
||||
isHeader "Backup Crontab Install"
|
||||
fi
|
||||
|
||||
local app_names=()
|
||||
while IFS= read -r name; do
|
||||
local app_names+=("$name")
|
||||
done < <(sudo sqlite3 "$docker_dir/$db_file" "SELECT name FROM apps WHERE status = 1;")
|
||||
|
||||
# Check if sqlite3 is available
|
||||
if ! command -v sudo sqlite3 &> /dev/null; then
|
||||
isNotice "sqlite3 command not found. Make sure it's installed."
|
||||
fi
|
||||
|
||||
# Remove crontab entries for applications with status = 0 (uninstalled)
|
||||
while IFS= read -r name; do
|
||||
local uninstalled_apps+=("$name")
|
||||
done < <(sudo sqlite3 "$docker_dir/$db_file" "SELECT name FROM apps WHERE status = 0;")
|
||||
|
||||
for name in "${uninstalled_apps[@]}"; do
|
||||
removeBackupCrontabAppFolderRemoved $name
|
||||
done
|
||||
|
||||
# Setup crontab entries for installed applications
|
||||
for name in "${app_names[@]}"; do
|
||||
checkBackupCrontabApp $name
|
||||
done
|
||||
|
||||
crontabClean;
|
||||
isSuccessful "Setting up Crontab backups for application(s) completed."
|
||||
}
|
||||
|
||||
31
scripts/crontab/app/crontab_backup_scheduler.sh
Normal file
31
scripts/crontab/app/crontab_backup_scheduler.sh
Normal file
@ -0,0 +1,31 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Install (or refresh) the single daily crontab entry that drives application
|
||||
# backups. The entry runs `libreportal backup scheduled`, which enqueues a
|
||||
# backup task per enabled app for the processor to drain serially.
|
||||
crontabSetupBackupScheduler()
|
||||
{
|
||||
local ISCRON=$( (sudo -u $sudo_user_name crontab -l) 2>/dev/null )
|
||||
|
||||
if [[ "$ISCRON" == *"command not found"* ]]; then
|
||||
isNotice "Crontab is not found. Unable to set up the backup scheduler."
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! sudo -u $sudo_user_name crontab -l 2>/dev/null | grep -q "cron is set up for $sudo_user_name"; then
|
||||
isNotice "Crontab is not set up, skipping backup scheduler until it's found."
|
||||
return 0
|
||||
fi
|
||||
|
||||
local marker="# CRONTAB BACKUP SCHEDULER"
|
||||
local scheduler_entry="$CFG_BACKUP_CRONTAB_APP libreportal backup scheduled $marker"
|
||||
|
||||
# Drop any previous scheduler entry, then re-add the current one so a
|
||||
# changed schedule (CFG_BACKUP_CRONTAB_APP) always takes effect.
|
||||
local result=$(sudo -u $sudo_user_name crontab -l 2>/dev/null | grep -v "$marker" | sudo -u $sudo_user_name crontab -)
|
||||
local result=$( (sudo -u $sudo_user_name crontab -l 2>/dev/null; echo "$scheduler_entry") | sudo -u $sudo_user_name crontab - )
|
||||
checkSuccess "Installing the daily backup scheduler entry"
|
||||
|
||||
local schedule_time=$(echo "$CFG_BACKUP_CRONTAB_APP" | cut -d' ' -f2)
|
||||
isSuccessful "Enabled apps will be queued for backup daily at ${schedule_time}:00"
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
checkBackupCrontabApp()
|
||||
{
|
||||
local name="$1"
|
||||
local config_variable="CFG_${name^^}_BACKUP"
|
||||
local desired="${!config_variable}"
|
||||
local has_cron=0
|
||||
if sudo -u $sudo_user_name crontab -l 2>/dev/null | grep -q "$name"; then
|
||||
has_cron=1
|
||||
fi
|
||||
|
||||
if [[ "$desired" == "true" && $has_cron -eq 0 ]]; then
|
||||
installSetupCrontab "$name"
|
||||
databaseCronJobsInsert "$name"
|
||||
isSuccessful "Backup crontab enabled for $name."
|
||||
elif [[ "$desired" == "false" && $has_cron -eq 1 ]]; then
|
||||
removeBackupCrontabApp "$name"
|
||||
isSuccessful "Backup crontab removed for $name (disabled in config)."
|
||||
fi
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
removeBackupCrontabApp()
|
||||
{
|
||||
local name="$1"
|
||||
# Remove the crontab entry for the specified application
|
||||
sudo -u $sudo_user_name crontab -l 2>/dev/null | grep -v "$name" | sudo -u $sudo_user_name crontab -
|
||||
isSuccessful "Automatic backups for $name have been removed."
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
removeBackupCrontabAppFolderRemoved()
|
||||
{
|
||||
local name="$1"
|
||||
|
||||
# Check if the crontab entry exists for the specified application
|
||||
if sudo -u $sudo_user_name crontab -l 2>/dev/null | grep -q "$name"; then
|
||||
echo ""
|
||||
isNotice "Application $name is no longer installed."
|
||||
while true; do
|
||||
isQuestion "Do you want to remove automatic backups for $name (y/n): "
|
||||
read -rp "" removecrontab
|
||||
if [[ "$removecrontab" =~ ^[yYnN]$ ]]; then
|
||||
break
|
||||
fi
|
||||
isNotice "Please provide a valid input (y/n)."
|
||||
done
|
||||
if [[ "$removecrontab" =~ ^[yY]$ ]]; then
|
||||
removeBackupCrontabApp $name;
|
||||
fi
|
||||
fi
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Function to set up the backup entry in crontab
|
||||
installSetupCrontab()
|
||||
{
|
||||
local entry_name="$1"
|
||||
|
||||
isHeader "Adding $entry_name to Crontab"
|
||||
|
||||
# Check to see if already instealled
|
||||
if ! sudo -u $sudo_user_name crontab -l 2>/dev/null | grep -q "cron is set up for $sudo_user_name"; then
|
||||
isError "Crontab is not setup"
|
||||
fi
|
||||
|
||||
local crontab_entry="$CFG_BACKUP_CRONTAB_APP libreportal backup app schedule $entry_name"
|
||||
local apps_comment="# CRONTAB BACKUP APPS"
|
||||
local existing_crontab=$(sudo -u $sudo_user_name crontab -l 2>/dev/null)
|
||||
|
||||
# Check if the apps comment exists in the crontab
|
||||
if ! echo "$existing_crontab" | grep -q "$apps_comment"; then
|
||||
existing_crontab=$(echo -e "$existing_crontab\n$apps_comment")
|
||||
checkSuccess "Insert the apps comment header"
|
||||
fi
|
||||
existing_crontab=$(echo "$existing_crontab" | sed "/$apps_comment/a\\
|
||||
$crontab_entry")
|
||||
checkSuccess "Insert the backup entry after the apps comment"
|
||||
|
||||
local result=$(echo "$existing_crontab" | sudo -u $sudo_user_name crontab -)
|
||||
checkSuccess "Set the updated crontab"
|
||||
|
||||
crontab_full_value=$(echo "$CFG_BACKUP_CRONTAB_APP" | cut -d' ' -f2)
|
||||
isSuccessful "$entry_name will be backed up every day at $crontab_full_value:am"
|
||||
}
|
||||
@ -1,65 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Function to update a specific line in the crontab
|
||||
installSetupCrontabTiming()
|
||||
{
|
||||
local entry_name=$1
|
||||
ISCRON=$( (sudo -u $sudo_user_name crontab -l) 2>/dev/null )
|
||||
|
||||
# Check to see if installed
|
||||
if [[ "$ISCRON" == *"command not found"* ]]; then
|
||||
isError "Cron is not installed."
|
||||
fi
|
||||
|
||||
# Check to see if already setup
|
||||
if ! sudo -u $sudo_user_name crontab -l 2>/dev/null | grep -q "cron is set up for $sudo_user_name"; then
|
||||
isError "Crontab is not setup"
|
||||
fi
|
||||
|
||||
# Check if sqlite3 is available
|
||||
if ! command -v sqlite3 &> /dev/null; then
|
||||
isNotice "sqlite3 command not found. Make sure it's installed."
|
||||
fi
|
||||
|
||||
# Ensure the database file exists
|
||||
if [ ! -f "$docker_dir/$db_file" ]; then
|
||||
isNotice "Database file not found: $docker_dir/$db_file"
|
||||
fi
|
||||
|
||||
# Step 1: Retrieve the necessary information from the database
|
||||
db_entry=$(sqlite3 "$docker_dir/$db_file" "SELECT id, name FROM cron_jobs WHERE name='$entry_name';")
|
||||
IFS='|' read -r id name <<< "$db_entry"
|
||||
|
||||
# Check if the entry exists in the database
|
||||
if [[ -z "$id" ]]; then
|
||||
isNotice "Entry '$entry_name' not found in the database."
|
||||
fi
|
||||
|
||||
# Calculate the new minute value based on the ID
|
||||
new_minute_value=$((id * $CFG_BACKUP_CRONTAB_APP_INTERVAL))
|
||||
|
||||
# Step 2: Locate the existing crontab entry in the crontab file
|
||||
crontab_entry_to_update=$(sudo -u $sudo_user_name crontab -l 2>/dev/null | grep "$entry_name")
|
||||
|
||||
# Check if the entry exists in the crontab
|
||||
if [[ -z "$crontab_entry_to_update" ]]; then
|
||||
isError "Entry '$entry_name' not found in the crontab."
|
||||
fi
|
||||
|
||||
# Extract the existing minute value from the current crontab entry
|
||||
current_minute_value=$(echo "$crontab_entry_to_update" | awk '{print $1}')
|
||||
|
||||
# Step 3: Update the minute value in the identified crontab entry
|
||||
updated_crontab_entry="${crontab_entry_to_update/$current_minute_value/$new_minute_value}"
|
||||
|
||||
# Assuming CFG_BACKUP_CRONTAB_APP is set to "0 5 * * *"
|
||||
crontab_app_value=$(echo "$CFG_BACKUP_CRONTAB_APP" | cut -d' ' -f2)
|
||||
|
||||
local result=$(sudo -u $sudo_user_name crontab -l 2>/dev/null | grep -v "$entry_name" | sudo -u $sudo_user_name crontab - )
|
||||
checkSuccess "Remove the existing crontab entry"
|
||||
local result=$( (sudo -u $sudo_user_name crontab -l 2>/dev/null; echo "$updated_crontab_entry") | sudo -u $sudo_user_name crontab - )
|
||||
checkSuccess "Add the updated crontab entry"
|
||||
|
||||
isSuccessful "Crontab entry for '$entry_name' updated successfully."
|
||||
isSuccessful "$entry_name will be backed up every day at $crontab_app_value:${new_minute_value}am"
|
||||
}
|
||||
@ -9,7 +9,7 @@ crontabRefresh()
|
||||
crontabSetup;
|
||||
|
||||
# Rebuild from scratch
|
||||
crontabSetupAllAppBackups "false";
|
||||
crontabSetupBackupScheduler;
|
||||
|
||||
#crontabSetupTaskProcessor # Switched to Systemd
|
||||
crontabSetupSystemInfoUpdater;
|
||||
|
||||
@ -1,19 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
databaseCronJobsInsert()
|
||||
{
|
||||
local app_name="$1"
|
||||
local table_name=cron_jobs
|
||||
local key_in_db=$(sudo sqlite3 "$docker_dir/$db_file" "SELECT COUNT(*) FROM $table_name WHERE name = '$app_name';")
|
||||
|
||||
if [ "$key_in_db" != "" ]; then
|
||||
if [ "$key_in_db" -eq 0 ]; then
|
||||
local result=$(sudo sqlite3 "$docker_dir/$db_file" "INSERT INTO $table_name (name, date, time) VALUES ('$app_name', '$current_date', '$current_time');")
|
||||
checkSuccess "Adding $app_name to the $table_name table."
|
||||
else
|
||||
local result=$(sudo sqlite3 "$docker_dir/$db_file" "UPDATE $table_name SET name = '$app_name', date = '$current_date', time = '$current_time' WHERE name = '$app_name';")
|
||||
checkSuccess "$app_name already added to the $table_name table. Updating date/time."
|
||||
fi
|
||||
#isNotice "app_name is empty, unable to insert"
|
||||
fi
|
||||
}
|
||||
@ -67,13 +67,6 @@ databaseCreateTables()
|
||||
checkSuccess "Creating $setup_table_name table"
|
||||
fi
|
||||
|
||||
setup_table_name=cron_jobs
|
||||
if ! sqlite3 "$docker_dir/$db_file" ".tables" | grep -q "\b$setup_table_name\b"; then
|
||||
# Table info here
|
||||
local result=$(sqlite3 $docker_dir/$db_file "CREATE TABLE IF NOT EXISTS $setup_table_name (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE, date DATE, time TIME);")
|
||||
checkSuccess "Creating $setup_table_name table"
|
||||
fi
|
||||
|
||||
setup_table_name=network_resources
|
||||
if ! sqlite3 "$docker_dir/$db_file" ".tables" | grep -q "\b$setup_table_name\b"; then
|
||||
# Simple unified network resources table - replaces all complex network tables
|
||||
|
||||
@ -7,7 +7,7 @@ crontabToolsMenu()
|
||||
|
||||
while true; do
|
||||
isHeader "Crontab Menu"
|
||||
isOption "1. Scan apps for Crontab Backup"
|
||||
isOption "1. Set up Backup Scheduler"
|
||||
isOption "2. Force Crontab Reinstall"
|
||||
isOption "x. Exit to Main Menu"
|
||||
echo ""
|
||||
|
||||
@ -9,6 +9,7 @@ backup_scripts=(
|
||||
"backup/app/backup_app_hooks.sh"
|
||||
"backup/app/backup_app_schedule.sh"
|
||||
"backup/app/backup_app_start.sh"
|
||||
"backup/app/backup_schedule_all.sh"
|
||||
"backup/engine/backup_ssh.sh"
|
||||
"backup/engine/borg_backup.sh"
|
||||
"backup/engine/borg_check.sh"
|
||||
|
||||
@ -4,12 +4,7 @@
|
||||
# Do not edit manually - run './scripts/source/files/generate_arrays.sh run' to regenerate
|
||||
|
||||
crontab_scripts=(
|
||||
"crontab/app/crontab_backup_all_apps.sh"
|
||||
"crontab/app/crontab_check_backup_app.sh"
|
||||
"crontab/app/crontab_remove_backup_app.sh"
|
||||
"crontab/app/crontab_remove_folder.sh"
|
||||
"crontab/app/install/crontab_setup.sh"
|
||||
"crontab/app/install/crontab_timing.sh"
|
||||
"crontab/app/crontab_backup_scheduler.sh"
|
||||
"crontab/crontab_clean.sh"
|
||||
"crontab/crontab_clear.sh"
|
||||
"crontab/crontab_install.sh"
|
||||
|
||||
@ -14,7 +14,6 @@ database_scripts=(
|
||||
"database/check_os_update.sh"
|
||||
"database/delete_db_file.sh"
|
||||
"database/insert/db_insert_backups.sh"
|
||||
"database/insert/db_insert_cron_jobs.sh"
|
||||
"database/insert/db_insert_option.sh"
|
||||
"database/insert/db_insert_port_open.sh"
|
||||
"database/insert/db_insert_port_used.sh"
|
||||
|
||||
@ -33,7 +33,7 @@ startOther()
|
||||
fi
|
||||
|
||||
if [[ "$toolsstartcrontabsetup" == [yY] ]]; then
|
||||
crontabSetupAllAppBackups
|
||||
crontabSetupBackupScheduler
|
||||
fi
|
||||
|
||||
if [[ "$toolinstallcrontab" == [yY] ]]; then
|
||||
|
||||
@ -72,7 +72,7 @@ webuiValidateConfigValue() {
|
||||
isError " Invalid crontab format for $var_name"
|
||||
fi
|
||||
;;
|
||||
CFG_BACKUP_KEEP_LAST|CFG_BACKUP_KEEP_DAILY|CFG_BACKUP_KEEP_WEEKLY|CFG_BACKUP_KEEP_MONTHLY|CFG_BACKUP_KEEP_YEARLY|CFG_BACKUP_VERIFY_DATA_PERCENT|CFG_BACKUP_CRONTAB_APP_INTERVAL|CFG_UPDATER_CHECK|CFG_SWAPFILE_SIZE|CFG_GENERATED_PASS_LENGTH|CFG_WEBUI_LOG_STREAM_IDLE_TIMEOUT_MINUTES|CFG_WEBUI_LOG_STREAM_MAX_DURATION_MINUTES|CFG_WEBUI_LOG_STREAM_MAX_LINES_PER_SEC)
|
||||
CFG_BACKUP_KEEP_LAST|CFG_BACKUP_KEEP_DAILY|CFG_BACKUP_KEEP_WEEKLY|CFG_BACKUP_KEEP_MONTHLY|CFG_BACKUP_KEEP_YEARLY|CFG_BACKUP_VERIFY_DATA_PERCENT|CFG_UPDATER_CHECK|CFG_SWAPFILE_SIZE|CFG_GENERATED_PASS_LENGTH|CFG_WEBUI_LOG_STREAM_IDLE_TIMEOUT_MINUTES|CFG_WEBUI_LOG_STREAM_MAX_DURATION_MINUTES|CFG_WEBUI_LOG_STREAM_MAX_LINES_PER_SEC)
|
||||
# Validate numeric values
|
||||
if ! echo "$var_value" | grep -qE '^[0-9]+$'; then
|
||||
isError " $var_name must be a positive integer"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user