fix(deploy): repair backup directory permissions
This commit is contained in:
+1
-1
@@ -147,7 +147,7 @@ means "stop and tell me".
|
|||||||
`deploy/deploy.sh` takes a backup **before** it builds, stops or replaces anything, and **aborts the
|
`deploy/deploy.sh` takes a backup **before** it builds, stops or replaces anything, and **aborts the
|
||||||
deploy if the backup fails**. Nothing else in the deploy runs without a restore point.
|
deploy if the backup fails**. Nothing else in the deploy runs without a restore point.
|
||||||
|
|
||||||
- **Location:** `/opt/job-tracker/backups` — override with `BACKUP_DIR`.
|
- **Location:** `/opt/job-tracker/backups` — override with `BACKUP_DIR`. If an earlier root-run deploy owns the directory, the deploy script repairs its ownership through Docker before writing.
|
||||||
- **Selection:** driven solely by `DATABASE_PROVIDER`, which must be set.
|
- **Selection:** driven solely by `DATABASE_PROVIDER`, which must be set.
|
||||||
- `mariadb` / `mysql` → SQL dump, `jobtracker-<database>-<UTC timestamp>.sql.gz`, e.g.
|
- `mariadb` / `mysql` → SQL dump, `jobtracker-<database>-<UTC timestamp>.sql.gz`, e.g.
|
||||||
`jobtracker-jobtracker-20260719T153759Z.sql.gz`
|
`jobtracker-jobtracker-20260719T153759Z.sql.gz`
|
||||||
|
|||||||
+17
-6
@@ -161,6 +161,15 @@ backup_database() {
|
|||||||
local stamp
|
local stamp
|
||||||
stamp="$(date -u +%Y%m%dT%H%M%SZ)"
|
stamp="$(date -u +%Y%m%dT%H%M%SZ)"
|
||||||
mkdir -p "$BACKUP_DIR"
|
mkdir -p "$BACKUP_DIR"
|
||||||
|
if [ ! -w "$BACKUP_DIR" ]; then
|
||||||
|
echo "Backup directory ${BACKUP_DIR} is not writable; repairing ownership via Docker."
|
||||||
|
docker run --rm -v "$BACKUP_DIR":/backup mariadb:11 \
|
||||||
|
chown "$(id -u):$(id -g)" /backup
|
||||||
|
fi
|
||||||
|
if [ ! -w "$BACKUP_DIR" ]; then
|
||||||
|
echo "Backup directory ${BACKUP_DIR} is still not writable. Aborting deploy."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$provider" = "sqlite" ]; then
|
if [ "$provider" = "sqlite" ]; then
|
||||||
# SQLite lives in the jobtracker_data volume. Tar it from a throwaway container
|
# SQLite lives in the jobtracker_data volume. Tar it from a throwaway container
|
||||||
@@ -219,33 +228,35 @@ backup_database() {
|
|||||||
|
|
||||||
# The password goes via MYSQL_PWD, never on the command line, so it cannot leak
|
# The password goes via MYSQL_PWD, never on the command line, so it cannot leak
|
||||||
# into the process list or the deploy log.
|
# into the process list or the deploy log.
|
||||||
local dump_status=0
|
local dump_status=0 error_file
|
||||||
|
error_file="$(mktemp "${TMPDIR:-/tmp}/jobtracker-backup.XXXXXX.err")"
|
||||||
if command -v mariadb-dump >/dev/null 2>&1; then
|
if command -v mariadb-dump >/dev/null 2>&1; then
|
||||||
MYSQL_PWD="$db_pass" mariadb-dump \
|
MYSQL_PWD="$db_pass" mariadb-dump \
|
||||||
--host="$db_host" --port="$db_port" --user="$db_user" \
|
--host="$db_host" --port="$db_port" --user="$db_user" \
|
||||||
--single-transaction --routines --events --quick \
|
--single-transaction --routines --events --quick \
|
||||||
"$db_name" 2>/tmp/jobtracker-backup.err | gzip -c > "$target" || dump_status=$?
|
"$db_name" 2>"$error_file" | gzip -c > "$target" || dump_status=$?
|
||||||
elif command -v mysqldump >/dev/null 2>&1; then
|
elif command -v mysqldump >/dev/null 2>&1; then
|
||||||
MYSQL_PWD="$db_pass" mysqldump \
|
MYSQL_PWD="$db_pass" mysqldump \
|
||||||
--host="$db_host" --port="$db_port" --user="$db_user" \
|
--host="$db_host" --port="$db_port" --user="$db_user" \
|
||||||
--single-transaction --routines --events --quick \
|
--single-transaction --routines --events --quick \
|
||||||
"$db_name" 2>/tmp/jobtracker-backup.err | gzip -c > "$target" || dump_status=$?
|
"$db_name" 2>"$error_file" | gzip -c > "$target" || dump_status=$?
|
||||||
else
|
else
|
||||||
# No client on the host: run one in a container. --network host so the same
|
# No client on the host: run one in a container. --network host so the same
|
||||||
# host/port from the connection string resolves identically.
|
# host/port from the connection string resolves identically.
|
||||||
docker run --rm --network host -e MYSQL_PWD="$db_pass" mariadb:11 \
|
docker run --rm --network host -e MYSQL_PWD="$db_pass" mariadb:11 \
|
||||||
mariadb-dump --host="$db_host" --port="$db_port" --user="$db_user" \
|
mariadb-dump --host="$db_host" --port="$db_port" --user="$db_user" \
|
||||||
--single-transaction --routines --events --quick \
|
--single-transaction --routines --events --quick \
|
||||||
"$db_name" 2>/tmp/jobtracker-backup.err | gzip -c > "$target" || dump_status=$?
|
"$db_name" 2>"$error_file" | gzip -c > "$target" || dump_status=$?
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$dump_status" -ne 0 ]; then
|
if [ "$dump_status" -ne 0 ]; then
|
||||||
echo "Database dump FAILED (exit ${dump_status}). Aborting deploy."
|
echo "Database dump FAILED (exit ${dump_status}). Aborting deploy."
|
||||||
sed -e 's/password=[^ ]*/password=***/gI' /tmp/jobtracker-backup.err >&2 || true
|
sed -e 's/password=[^ ]*/password=***/gI' "$error_file" >&2 || true
|
||||||
rm -f "$target"
|
rm -f "$error_file" "$target"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
rm -f "$error_file"
|
||||||
verify_sql_backup "$target"
|
verify_sql_backup "$target"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user