Enhance backup and restore scripts: update database name and add support for multi-tenant configurations
This commit is contained in:
@@ -33,11 +33,12 @@ LOG_FILE="${LOG_FILE:-$LOG_DIR/backup.log}"
|
||||
COMPRESSION_LEVEL="${COMPRESSION_LEVEL:-9}"
|
||||
KEEP_DAYS="${KEEP_DAYS:-7}"
|
||||
MIN_KEEP="${MIN_KEEP:-7}"
|
||||
DB_NAME="${DB_NAME:-Inventarsystem}"
|
||||
DB_NAME="${DB_NAME:-inventar_default}"
|
||||
MONGO_URI="${MONGO_URI:-mongodb://localhost:27017/}"
|
||||
INVOICE_KEEP_DAYS="${INVOICE_KEEP_DAYS:-3650}"
|
||||
INVOICE_ARCHIVE_DIR="${INVOICE_ARCHIVE_DIR:-$BACKUP_BASE_DIR/invoice-archive}"
|
||||
BACKUP_MODE="${BACKUP_MODE:-auto}"
|
||||
COMPOSE_FILE="${COMPOSE_FILE:-docker-compose-multitenant.yml}"
|
||||
DOCKER_AVAILABLE=0
|
||||
DOCKER_COMPOSE_CMD=()
|
||||
USE_NULL_OUTPUT=false
|
||||
@@ -58,6 +59,8 @@ Options:
|
||||
--keep-days <N> Age-based retention in days (default: $KEEP_DAYS; 0 disables age filter)
|
||||
--min-keep <N> Always keep at least this many backups (default: $MIN_KEEP)
|
||||
--mode <auto|host|docker> Backup mode (default: $BACKUP_MODE)
|
||||
--multitenant Use docker-compose-multitenant.yml (default)
|
||||
--singletenant Use docker-compose.yml
|
||||
-h|--help Show this help and exit
|
||||
EOF
|
||||
}
|
||||
@@ -87,6 +90,10 @@ while [[ $# -gt 0 ]]; do
|
||||
MIN_KEEP="$2"; shift 2;;
|
||||
--mode)
|
||||
BACKUP_MODE="$2"; shift 2;;
|
||||
--multitenant)
|
||||
COMPOSE_FILE="docker-compose-multitenant.yml"; shift;;
|
||||
--singletenant)
|
||||
COMPOSE_FILE="docker-compose.yml"; shift;;
|
||||
-h|--help)
|
||||
usage; exit 0;;
|
||||
*)
|
||||
@@ -102,12 +109,12 @@ log_message() {
|
||||
init_docker_compose() {
|
||||
if docker compose version >/dev/null 2>&1; then
|
||||
DOCKER_AVAILABLE=1
|
||||
DOCKER_COMPOSE_CMD=(docker compose -f "$PROJECT_DIR/docker-compose.yml")
|
||||
DOCKER_COMPOSE_CMD=(docker compose -f "$PROJECT_DIR/$COMPOSE_FILE")
|
||||
return 0
|
||||
fi
|
||||
if sudo docker compose version >/dev/null 2>&1; then
|
||||
DOCKER_AVAILABLE=1
|
||||
DOCKER_COMPOSE_CMD=(sudo docker compose -f "$PROJECT_DIR/docker-compose.yml")
|
||||
DOCKER_COMPOSE_CMD=(sudo docker compose -f "$PROJECT_DIR/$COMPOSE_FILE")
|
||||
return 0
|
||||
fi
|
||||
|
||||
|
||||
+27
-8
@@ -22,6 +22,7 @@ LEGACY_BACKUP_ARCHIVE=""
|
||||
CLEANUP_OLD_SERVICES=true
|
||||
CLEANUP_OLD_REMOVE_CRON=false
|
||||
TMP_DIR=""
|
||||
COMPOSE_FILE="docker-compose-multitenant.yml"
|
||||
|
||||
cleanup_tmp_dir() {
|
||||
if [ -n "${TMP_DIR:-}" ] && [ -d "$TMP_DIR" ]; then
|
||||
@@ -50,14 +51,13 @@ refresh_start_script_from_main() {
|
||||
pin_compose_app_image() {
|
||||
local tag="$1"
|
||||
local compose_file
|
||||
compose_file="$PROJECT_DIR/docker-compose.yml"
|
||||
|
||||
if [ ! -f "$compose_file" ]; then
|
||||
echo "Warning: $compose_file not found; cannot pin app image"
|
||||
return 0
|
||||
fi
|
||||
for compose_file in "$PROJECT_DIR/docker-compose-multitenant.yml" "$PROJECT_DIR/docker-compose.yml"; do
|
||||
if [ ! -f "$compose_file" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
python3 - <<'PY' "$compose_file" "$tag"
|
||||
python3 - <<'PY' "$compose_file" "$tag"
|
||||
import re
|
||||
import sys
|
||||
|
||||
@@ -151,6 +151,8 @@ if in_app_service and build_found and app_service_indent is not None:
|
||||
with open(compose_file, "w", encoding="utf-8") as f:
|
||||
f.writelines(out)
|
||||
PY
|
||||
|
||||
done
|
||||
}
|
||||
|
||||
install_docker_if_missing() {
|
||||
@@ -173,6 +175,8 @@ Options:
|
||||
--remove-legacy-system Remove old host MongoDB/system after successful import
|
||||
--skip-cleanup-old Do not run cleanup-old.sh after install
|
||||
--cleanup-old-remove-cron Also remove matching cron entries during old-system cleanup
|
||||
--multitenant Use docker-compose-multitenant.yml (default)
|
||||
--singletenant Use docker-compose.yml
|
||||
--legacy-db-name <name> Legacy database name (default: $LEGACY_DB_NAME)
|
||||
--legacy-mongo-uri <uri> Legacy Mongo URI (default: $LEGACY_MONGO_URI)
|
||||
--legacy-system-dir <path> Optional old system directory to remove after migration
|
||||
@@ -199,6 +203,14 @@ parse_args() {
|
||||
CLEANUP_OLD_REMOVE_CRON=true
|
||||
shift
|
||||
;;
|
||||
--multitenant)
|
||||
COMPOSE_FILE="docker-compose-multitenant.yml"
|
||||
shift
|
||||
;;
|
||||
--singletenant)
|
||||
COMPOSE_FILE="docker-compose.yml"
|
||||
shift
|
||||
;;
|
||||
--legacy-db-name)
|
||||
LEGACY_DB_NAME="$2"
|
||||
shift 2
|
||||
@@ -280,14 +292,21 @@ backup_legacy_database() {
|
||||
|
||||
restore_legacy_backup_into_docker() {
|
||||
local i
|
||||
local compose_path
|
||||
|
||||
if [ "$MIGRATE_LEGACY_DB" != "true" ] || [ -z "$LEGACY_BACKUP_ARCHIVE" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
compose_path="$PROJECT_DIR/$COMPOSE_FILE"
|
||||
if [ ! -f "$compose_path" ]; then
|
||||
echo "Error: compose file not found: $compose_path"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Waiting for Docker MongoDB to become ready..."
|
||||
for i in $(seq 1 60); do
|
||||
if sudo docker compose -f "$PROJECT_DIR/docker-compose.yml" exec -T mongodb mongosh --quiet --eval "db.adminCommand({ping:1}).ok" >/dev/null 2>&1; then
|
||||
if sudo docker compose -f "$compose_path" exec -T mongodb mongosh --quiet --eval "db.adminCommand({ping:1}).ok" >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
@@ -299,7 +318,7 @@ restore_legacy_backup_into_docker() {
|
||||
fi
|
||||
|
||||
echo "Importing legacy backup into Docker MongoDB..."
|
||||
sudo docker compose -f "$PROJECT_DIR/docker-compose.yml" exec -T mongodb mongorestore --archive --gzip --drop --nsInclude "${LEGACY_DB_NAME}.*" < "$LEGACY_BACKUP_ARCHIVE"
|
||||
sudo docker compose -f "$compose_path" exec -T mongodb mongorestore --archive --gzip --drop --nsInclude "${LEGACY_DB_NAME}.*" < "$LEGACY_BACKUP_ARCHIVE"
|
||||
echo "Legacy DB import completed."
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -4,5 +4,4 @@ set -euo pipefail
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
|
||||
"$SCRIPT_DIR/stop.sh" "$@"
|
||||
"$SCRIPT_DIR/start.sh" "$@"
|
||||
"$SCRIPT_DIR/start.sh"
|
||||
"$SCRIPT_DIR/start.sh" "$@"
|
||||
+14
-3
@@ -6,12 +6,13 @@ LOG_DIR="$SCRIPT_DIR/logs"
|
||||
LOG_FILE="$LOG_DIR/restore.log"
|
||||
WORK_DIR="$(mktemp -d /tmp/inventarsystem-restore-XXXXXX)"
|
||||
|
||||
DB_NAME="${INVENTAR_MONGODB_DB:-Inventarsystem}"
|
||||
DB_NAME="${INVENTAR_MONGODB_DB:-inventar_default}"
|
||||
SOURCE_PATH=""
|
||||
BACKUP_DATE=""
|
||||
DROP_DATABASE=false
|
||||
RESTART_SERVICES=false
|
||||
STAGED_PATH=""
|
||||
COMPOSE_FILE="docker-compose-multitenant.yml"
|
||||
|
||||
BACKUP_ROOT_LOCAL="$SCRIPT_DIR/backups"
|
||||
BACKUP_ROOT_SYSTEM="/var/backups"
|
||||
@@ -56,6 +57,8 @@ Options:
|
||||
- latest: newest from local/system backup roots
|
||||
--drop-database Drop target DB before import (recommended for full restore)
|
||||
--restart-services Restart stack after restore
|
||||
--multitenant Use docker-compose-multitenant.yml (default)
|
||||
--singletenant Use docker-compose.yml
|
||||
--list List detected backup candidates
|
||||
--help Show this help
|
||||
|
||||
@@ -68,12 +71,12 @@ EOF
|
||||
|
||||
setup_compose() {
|
||||
if docker compose version >/dev/null 2>&1 && docker info >/dev/null 2>&1; then
|
||||
DOCKER_COMPOSE=(docker compose)
|
||||
DOCKER_COMPOSE=(docker compose -f "$SCRIPT_DIR/$COMPOSE_FILE")
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ -n "$SUDO" ] && $SUDO docker compose version >/dev/null 2>&1 && $SUDO docker info >/dev/null 2>&1; then
|
||||
DOCKER_COMPOSE=($SUDO docker compose)
|
||||
DOCKER_COMPOSE=($SUDO docker compose -f "$SCRIPT_DIR/$COMPOSE_FILE")
|
||||
return 0
|
||||
fi
|
||||
|
||||
@@ -459,6 +462,14 @@ parse_args() {
|
||||
RESTART_SERVICES=true
|
||||
shift
|
||||
;;
|
||||
--multitenant)
|
||||
COMPOSE_FILE="docker-compose-multitenant.yml"
|
||||
shift
|
||||
;;
|
||||
--singletenant)
|
||||
COMPOSE_FILE="docker-compose.yml"
|
||||
shift
|
||||
;;
|
||||
--list)
|
||||
list_backups
|
||||
exit 0
|
||||
|
||||
@@ -7,6 +7,7 @@ cd "$SCRIPT_DIR"
|
||||
ENV_FILE="$SCRIPT_DIR/.docker-build.env"
|
||||
APP_IMAGE_REPO="ghcr.io/aiirondev/legendary-octo-garbanzo"
|
||||
DIST_DIR="$SCRIPT_DIR/dist"
|
||||
RUNTIME_COMPOSE_OVERRIDE_FILE="$SCRIPT_DIR/.docker-compose.runtime.override.yml"
|
||||
|
||||
SUDO=""
|
||||
if [ "$(id -u)" -ne 0 ] && command -v sudo >/dev/null 2>&1; then
|
||||
@@ -18,7 +19,7 @@ HTTP_PORT_VALUE="8001"
|
||||
HTTPS_PORT_VALUE="8443"
|
||||
CRON_SETUP_VALUE="${INVENTAR_SETUP_CRON:-1}"
|
||||
APP_IMAGE_VALUE="${INVENTAR_APP_IMAGE:-$APP_IMAGE_REPO:latest}"
|
||||
COMPOSE_FILE="docker-compose.yml"
|
||||
COMPOSE_FILE="docker-compose-multitenant.yml"
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
@@ -28,6 +29,7 @@ Options:
|
||||
--no-cron Do not create or update cron jobs
|
||||
--with-cron Create/update cron jobs (default)
|
||||
--multitenant Use the multi-tenant architecture deployment
|
||||
--singletenant Use the legacy single-tenant compose deployment
|
||||
-h, --help Show this help message
|
||||
EOF
|
||||
}
|
||||
@@ -47,6 +49,10 @@ parse_args() {
|
||||
COMPOSE_FILE="docker-compose-multitenant.yml"
|
||||
shift
|
||||
;;
|
||||
--singletenant)
|
||||
COMPOSE_FILE="docker-compose.yml"
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
@@ -554,9 +560,22 @@ INVENTAR_APP_IMAGE=$APP_IMAGE_VALUE
|
||||
EOF
|
||||
}
|
||||
|
||||
write_runtime_compose_override() {
|
||||
cat > "$RUNTIME_COMPOSE_OVERRIDE_FILE" <<EOF
|
||||
services:
|
||||
app:
|
||||
image: ${APP_IMAGE_VALUE}
|
||||
build: null
|
||||
EOF
|
||||
}
|
||||
|
||||
verify_stack_health() {
|
||||
local compose_args running_services retry_count=0
|
||||
compose_args=(-f "$COMPOSE_FILE" --env-file "$ENV_FILE")
|
||||
compose_args=(-f "$COMPOSE_FILE")
|
||||
if [ -f "$RUNTIME_COMPOSE_OVERRIDE_FILE" ]; then
|
||||
compose_args+=(-f "$RUNTIME_COMPOSE_OVERRIDE_FILE")
|
||||
fi
|
||||
compose_args+=(--env-file "$ENV_FILE")
|
||||
|
||||
# Try health check with optional restart on first failure
|
||||
while [[ $retry_count -lt 2 ]]; do
|
||||
@@ -609,9 +628,15 @@ resolve_app_image
|
||||
configure_host_ports
|
||||
ensure_app_image_loaded
|
||||
write_env_file
|
||||
write_runtime_compose_override
|
||||
|
||||
echo "Starting Inventarsystem Docker stack (app + mongodb)..."
|
||||
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" up -d --remove-orphans
|
||||
compose_up_args=(-f "$COMPOSE_FILE")
|
||||
if [ -f "$RUNTIME_COMPOSE_OVERRIDE_FILE" ]; then
|
||||
compose_up_args+=(-f "$RUNTIME_COMPOSE_OVERRIDE_FILE")
|
||||
fi
|
||||
compose_up_args+=(--env-file "$ENV_FILE")
|
||||
docker compose "${compose_up_args[@]}" up -d --remove-orphans
|
||||
|
||||
verify_stack_health
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cd "$SCRIPT_DIR"
|
||||
|
||||
COMPOSE_FILE="docker-compose.yml"
|
||||
COMPOSE_FILE="docker-compose-multitenant.yml"
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
@@ -12,6 +12,10 @@ while [[ $# -gt 0 ]]; do
|
||||
COMPOSE_FILE="docker-compose-multitenant.yml"
|
||||
shift
|
||||
;;
|
||||
--singletenant)
|
||||
COMPOSE_FILE="docker-compose.yml"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
shift
|
||||
;;
|
||||
|
||||
@@ -15,6 +15,7 @@ APP_IMAGE_ASSET_PREFIX="inventarsystem-image-"
|
||||
ENV_FILE="$PROJECT_DIR/.docker-build.env"
|
||||
APP_IMAGE_REPO="ghcr.io/aiirondev/legendary-octo-garbanzo"
|
||||
DIST_DIR="$PROJECT_DIR/dist"
|
||||
COMPOSE_FILE="docker-compose-multitenant.yml"
|
||||
|
||||
mkdir -p "$LOG_DIR"
|
||||
chmod 777 "$LOG_DIR" 2>/dev/null || true
|
||||
@@ -118,6 +119,41 @@ server {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: $0 [options]
|
||||
|
||||
Options:
|
||||
--multitenant Use docker-compose-multitenant.yml (default)
|
||||
--singletenant Use docker-compose.yml
|
||||
-h, --help Show this help message
|
||||
EOF
|
||||
}
|
||||
|
||||
parse_args() {
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--multitenant)
|
||||
COMPOSE_FILE="docker-compose-multitenant.yml"
|
||||
shift
|
||||
;;
|
||||
--singletenant)
|
||||
COMPOSE_FILE="docker-compose.yml"
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
log_message "ERROR: Unknown option: $1"
|
||||
usage
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name _;
|
||||
@@ -360,6 +396,13 @@ deploy() {
|
||||
local tag="$1"
|
||||
local meta_file="$2"
|
||||
local app_image="${APP_IMAGE_REPO}:${tag}"
|
||||
local compose_path
|
||||
|
||||
compose_path="$PROJECT_DIR/$COMPOSE_FILE"
|
||||
if [ ! -f "$compose_path" ]; then
|
||||
log_message "ERROR: compose file not found: $compose_path"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
@@ -385,15 +428,15 @@ EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
docker compose --env-file "$ENV_FILE" pull nginx mongodb >> "$LOG_FILE" 2>&1
|
||||
docker compose --env-file "$ENV_FILE" up -d --remove-orphans >> "$LOG_FILE" 2>&1
|
||||
docker compose -f "$compose_path" --env-file "$ENV_FILE" pull nginx mongodb >> "$LOG_FILE" 2>&1
|
||||
docker compose -f "$compose_path" --env-file "$ENV_FILE" up -d --remove-orphans >> "$LOG_FILE" 2>&1
|
||||
docker tag "$app_image" "$APP_IMAGE_REPO:latest" >> "$LOG_FILE" 2>&1 || true
|
||||
}
|
||||
|
||||
verify_stack_health() {
|
||||
local compose_args running_services
|
||||
local https_port
|
||||
compose_args=(--env-file "$ENV_FILE")
|
||||
compose_args=(-f "$PROJECT_DIR/$COMPOSE_FILE" --env-file "$ENV_FILE")
|
||||
https_port="$(awk -F= '/^INVENTAR_HTTPS_PORT=/{print $2}' "$ENV_FILE" | tr -d ' ')"
|
||||
if [ -z "$https_port" ]; then
|
||||
https_port="443"
|
||||
@@ -418,6 +461,8 @@ verify_stack_health() {
|
||||
}
|
||||
|
||||
main() {
|
||||
parse_args "$@"
|
||||
|
||||
ensure_runtime_dependencies
|
||||
ensure_tls_certificates
|
||||
ensure_nginx_config_mount_source
|
||||
|
||||
Reference in New Issue
Block a user