Add cronjob functionality.

This commit is contained in:
Aterfax 2024-03-26 00:15:09 +00:00
parent 33ef7afc93
commit cf3abb37d7
No known key found for this signature in database
GPG Key ID: 51E7ED3290C121FE
16 changed files with 157 additions and 68 deletions

View File

@ -12,7 +12,9 @@
## Longer summary
This container is still a work in progress and backups are not currently cron jobbed (a backup is only taken on re/start). Reading and using the ``docker-compose\docker-compose.yml`` and example ``.env.example`` file should be illustrative on how to use this container. See also: [Using-the-DockerHub-provided-image](#Using-the-DockerHub-provided-image)
This container is still a work in progress but the main feature (cronjob'd backups) now works.
Reading and using the ``docker-compose\docker-compose.yml`` and example ``.env.example`` file should be illustrative on how to use this container. See also: [Using-the-DockerHub-provided-image](#Using-the-DockerHub-provided-image)
## Table of Contents

View File

@ -1,7 +1,8 @@
# The 3 variables below are required.
# The 4 variables below are required.
PBS_ENCRYPTION_PASSWORD="123456789abcdefghijklmn"
PBS_ENDPOINT="pbs.mydomain.com"
PBS_DATASTORE="test-datastore"
CRON_SCHEDULE="0 */4 * * *"
# Use of the PBS_API_KEY_NAME and PBS_API_KEY_SECRET is recommended!
# If unset, ensure PBS_USER and PBS_PASSWORD are set.

View File

@ -13,4 +13,4 @@ services:
- ./pbsconfig/:/root/.config/proxmox-backup/
- ./backups/test1:/backups/test1:ro
- ./backups/test2:/backups/test2:ro
- ./backups/test3:/backups/test3:ro
- ./backups/test3:/backups/test3:ro

View File

@ -7,7 +7,7 @@ FROM ghcr.io/linuxserver/baseimage-debian:bookworm
LABEL maintainer="Aterfax"
# Get initial required packages
RUN apt-get update && apt-get install -y wget nano procps less expect
RUN apt-get update && apt-get install -y wget cron expect
# Get the Proxmox signing keys and add to trust store
RUN curl -o /etc/apt/trusted.gpg.d/proxmox-release-bookworm.gpg https://enterprise.proxmox.com/debian/proxmox-release-bookworm.gpg && \
@ -38,3 +38,6 @@ RUN touch etc/s6-overlay/s6-rc.d/user/contents.d/setup_check
COPY ./src/s6-services/backup /etc/s6-overlay/s6-rc.d/backup
RUN touch etc/s6-overlay/s6-rc.d/user/contents.d/backup
COPY ./src/s6-services/cron-backup /etc/s6-overlay/s6-rc.d/cron-backup
RUN touch etc/s6-overlay/s6-rc.d/user/contents.d/cron-backup

View File

@ -1,9 +1,12 @@
#!/usr/bin/with-contenv bash
# shellcheck shell=bash
# This script runs once as the container starts to get an immediate backup.
# Define a logging function to prefix output to the docker logs.
output_to_log() {
sed 's/^/[backup] /'
while IFS= read -r line; do
echo "[backup] $(date +"%Y-%m-%d %H:%M:%S") $line"
done
}
# Redirect all subsequent command outputs to output_to_log
exec > >(output_to_log)
@ -16,63 +19,4 @@ handle_error() {
}
trap handle_error ERR
path_to_filename() {
local path="$1"
local path_no_trailing_slash="${path%/}" # Remove the trailing slash, if any
local path_no_first_slash="${path_no_trailing_slash#\/}" # Remove the first slash
local filename="${path_no_first_slash//\//-}" # Replace slashes with dashes
echo "${filename}"
}
BACKUP_DIRECTORIES=()
# Iterate over each subdirectory under /backup and add its full path to the array
for dir in /backups/*; do
if [[ -d "$dir" ]]; then
BACKUP_DIRECTORIES+=("$dir/")
fi
done
# Print the contents of the array
echo "## Detected backup directories:"
echo -e "#"
if [ ${#BACKUP_DIRECTORIES[@]} -eq 0 ]; then
echo "# Nothing to backup."
else
for path in "${BACKUP_DIRECTORIES[@]}"; do
echo -e "# $path"
done
echo -e "#\n"
fi
# Construct the directory target list with the proxmox-backup-client syntax.
# This makes 1 .pxar file per path.
TARGETS=""
for dir in "${BACKUP_DIRECTORIES[@]}"; do
TARGET=$(path_to_filename "$dir").pxar:$dir
TARGETS="${TARGETS} ${TARGET}"
done
# Build the backup command we want to execute.
BACKUPCMD="proxmox-backup-client backup ${TARGETS}"
if [ -n "$PBS_DATASTORE_NS" ]; then
BACKUPCMD+=" --ns ${PBS_DATASTORE_NS}"
fi
# Source the variables from the setup_check scripting include file.
source /etc/s6-overlay/s6-rc.d/setup_check/run_include
echo -e "## Backing up to repository: \n# ${PBS_REPOSITORY}\n"
echo -e "## Executing backup command: \n# ${BACKUPCMD}\n"
if [ -n "$HEALTHCHECKSURL" ]; then
curl -fsS -m 10 --retry 5 $HEALTHCHECKSURL/start
fi
${BACKUPCMD} 2>&1
BACKUP_EXIT_CODE=$?
if [ -n "$HEALTHCHECKSURL" ]; then
curl -fsS -m 10 --retry 5 ${HEALTHCHECKSURL}/${BACKUP_EXIT_CODE}
fi
/etc/s6-overlay/s6-rc.d/backup/run_include

View File

@ -0,0 +1,62 @@
#!/usr/bin/with-contenv bash
# shellcheck shell=bash
path_to_filename() {
local path="$1"
local path_no_trailing_slash="${path%/}" # Remove the trailing slash, if any
local path_no_first_slash="${path_no_trailing_slash#\/}" # Remove the first slash
local filename="${path_no_first_slash//\//-}" # Replace slashes with dashes
echo "${filename}"
}
BACKUP_DIRECTORIES=()
# Iterate over each subdirectory under /backup and add its full path to the array
for dir in /backups/*; do
if [[ -d "$dir" ]]; then
BACKUP_DIRECTORIES+=("$dir/")
fi
done
# Print the contents of the array
echo "## Detected backup directories:"
echo -e "#"
if [ ${#BACKUP_DIRECTORIES[@]} -eq 0 ]; then
echo "# Nothing to backup."
else
for path in "${BACKUP_DIRECTORIES[@]}"; do
echo -e "# $path"
done
echo -e "#\n"
fi
# Construct the directory target list with the proxmox-backup-client syntax.
# This makes 1 .pxar file per path.
TARGETS=""
for dir in "${BACKUP_DIRECTORIES[@]}"; do
TARGET=$(path_to_filename "$dir").pxar:$dir
TARGETS="${TARGETS} ${TARGET}"
done
# Build the backup command we want to execute.
BACKUPCMD="proxmox-backup-client backup ${TARGETS}"
if [ -n "$PBS_DATASTORE_NS" ]; then
BACKUPCMD+=" --ns ${PBS_DATASTORE_NS}"
fi
# Source the variables from the setup_check scripting include file.
source /etc/s6-overlay/s6-rc.d/setup_check/run_include
echo -e "## Backing up to repository: \n# ${PBS_REPOSITORY}\n"
echo -e "## Executing backup command: \n# ${BACKUPCMD}\n"
if [ -n "$HEALTHCHECKSURL" ]; then
curl -fsS -m 10 --retry 5 $HEALTHCHECKSURL/start
fi
${BACKUPCMD} 2>&1
BACKUP_EXIT_CODE=$?
if [ -n "$HEALTHCHECKSURL" ]; then
curl -fsS -m 10 --retry 5 ${HEALTHCHECKSURL}/${BACKUP_EXIT_CODE}
fi

View File

@ -0,0 +1,64 @@
#!/usr/bin/with-contenv bash
# shellcheck shell=bash
# This script instates the cron job to take regular backups.
# Define a logging function to prefix output to the docker logs.
output_to_log() {
while IFS= read -r line; do
echo "[cron-backup] $(date +"%Y-%m-%d %H:%M:%S") $line"
done
}
# Redirect all subsequent command outputs to output_to_log
exec > >(output_to_log)
# Set up error handling
handle_error() {
local exit_code="$?"
echo -e "Error occurred (Exit code: $exit_code)"
exit "$exit_code"
}
trap handle_error ERR
validate_cron_expression() {
local cron_expression="$1"
# https://stackoverflow.com/a/57639657
local regex='(@(annually|yearly|monthly|weekly|daily|hourly|reboot))|(@every (\d+(ns|us|µs|ms|s|m|h))+)|((((\d+,)*\d+|(\d+(/|-)\d+)|\d+|\*) ?){5,7})'
if echo "$cron_expression" | grep -Pq "$regex"; then
return 0 # Valid cron expression
else
return 1 # Invalid cron expression
fi
}
if ! validate_cron_expression "$CRON_SCHEDULE"; then
echo -e "Invalid cron expression: $CRON_SCHEDULE \n"
echo "Please define a valid cron time expression for CRON_SCHEDULE, e.g. \"*/5 * * * *\" "
sleep 60
exit 1
fi
CRONLOG_FILE="/root/.config/proxmox-backup/cron.log"
CRON_FILE="/etc/cron.d/cron-backup"
CRON_LINE="${CRON_SCHEDULE} root bash -c '/etc/s6-overlay/s6-rc.d/backup/run_include' >> $CRONLOG_FILE 2>&1 "
TIMEOUT=60
touch "${CRONLOG_FILE}"
echo "${CRON_LINE}" > "${CRON_FILE}"
chmod +x "${CRON_FILE}"
service cron start
echo "Cron service is now running with: \"${CRON_LINE}\" "
# We only want new lines added, not existing log content on startup.
tail -n 0 -f "${CRONLOG_FILE}" &
# Check if cron service is running
while :; do
if ! service cron status > /dev/null; then
echo "Error: Cron service is not running. Restarting cron."
exit 1
fi
sleep ${TIMEOUT}
done

View File

@ -0,0 +1 @@
longrun

View File

@ -0,0 +1 @@
/etc/s6-overlay/s6-rc.d/cron-backup/run

View File

@ -1,9 +1,12 @@
#!/usr/bin/with-contenv bash
# shellcheck shell=bash
# This script runs once as the container starts to get a snapshot of the environment variables.
# Define a logging function to prefix output to the docker logs.
output_to_log() {
sed 's/^/[env-test] /'
while IFS= read -r line; do
echo "[env-test] $(date +"%Y-%m-%d %H:%M:%S") $line"
done
}
# Redirect all subsequent command outputs to output_to_log
exec > >(output_to_log)

View File

@ -1,9 +1,13 @@
#!/usr/bin/with-contenv bash
# shellcheck shell=bash
# This script runs once as the container starts to ensure key setup is functional
# for backups. (Either checking keys or generating new ones).
# Define a logging function to prefix output to the docker logs.
output_to_log() {
sed 's/^/[key_setup] /'
while IFS= read -r line; do
echo "[key_setup] $(date +"%Y-%m-%d %H:%M:%S") $line"
done
}
# Redirect all subsequent command outputs to output_to_log
exec > >(output_to_log)

View File

@ -1,9 +1,13 @@
#!/usr/bin/with-contenv bash
# shellcheck shell=bash
# This script runs once as the container starts to ensure variables are set
# correctly and any dependent variables also get set.
# Define a logging function to prefix output to the docker logs.
output_to_log() {
sed 's/^/[setup_check] /'
while IFS= read -r line; do
echo "[setup_check] $(date +"%Y-%m-%d %H:%M:%S") $line"
done
}
# Redirect all subsequent command outputs to output_to_log
exec > >(output_to_log)