From 05497fb18351c2b205da09ff53ce3e50f0561a0f Mon Sep 17 00:00:00 2001 From: James Tufarelli Date: Mon, 9 Oct 2023 18:33:59 -0700 Subject: [PATCH] Add SKIP_STOPPING and BACKUP_ON_START variables --- Dockerfile | 3 + docs/arguments.md | 45 ++++++++++++--- docs/installation.md | 2 +- docs/todo.md | 2 - mkdocs.yml | 2 +- pkg/backup.sh | 88 ++++++++++++++++------------- pkg/entry.sh | 48 ++++++++++++---- snippets/docker-compose-example.yml | 2 +- snippets/docker-run-example.sh | 2 +- 9 files changed, 129 insertions(+), 65 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8fb78ad8..f0a49e24 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,5 +22,8 @@ ENV CRON_SCHEDULE="0 4 * * *" # Default enable the report file ENV REPORT_FILE="true" +# Run the backup immediately on start +ENV BACKUP_ON_START="false" + # Run the entry script and pass all variables to it ENTRYPOINT [ "bash", "-c", "exec ./entry.sh \"${@}\"", "--"] diff --git a/docs/arguments.md b/docs/arguments.md index 25b8be36..060f6ef6 100644 --- a/docs/arguments.md +++ b/docs/arguments.md @@ -23,7 +23,7 @@ CRON_SCHEDULE=* 4 * * * ``` ## Skip Containers -Tell Nautical to skip backup in containers in this list. +Tell Nautical to skip backup of containers in this list. This list can either be the container `name` or full `id`. @@ -31,10 +31,16 @@ This list can either be the container `name` or full `id`. ```properties SKIP_CONTAINERS=container-name1,container-name2,container-name3 -# Or +``` +```properties SKIP_CONTAINERS=container-name1,056bd2e970c1338782733fdbf1009c6e158c715d0d105b11de88bd549430e7f5 ``` -**TIP**: You can get the full container ID using the `docker inspect ` command +!!! tip "Getting the full container ID" + Usally, it's easier to just use the `container-name`, but if you need to use the full ID, these commands will help: + + * `docker ps --no-trunc` + * `docker inspect ` + ## Override Source Directory > **Default**: *empty* @@ -46,8 +52,8 @@ OVERRIDE_SOURCE_DIR=example1:example1-new-source-data,ctr2:ctr2-new-source | Container Name | Old Source Directory | New Source Directory | | -------------- | -------------------- | ---------------------------- | -| example1 | `src/example1` | `src/example1-new-dest-data` | -| ctr2 | `src/ctr2` | `src/newdest` | +| example1 | `src/example1` | `src/example1-new-dest-data` | +| ctr2 | `src/ctr2` | `src/newdest` | ## Override Destination Directory @@ -59,10 +65,10 @@ OVERRIDE_DEST_DIR=example1:example1-new-dest-data,ctr2:newdest The example above would yield the following results: -| Container Name | Old Destination Directory | New Destination Directory | -| -------------- | -------------------- | ---------------------------- | -| example1 | `dest/example1` | `dest/example1-new-dest-data` | -| ctr2 | `dest/ctr2` | `dest/newdest` | +| Container Name | Old Destination Directory | New Destination Directory | +| -------------- | ------------------------- | ----------------------------- | +| example1 | `dest/example1` | `dest/example1-new-dest-data` | +| ctr2 | `dest/ctr2` | `dest/newdest` | ## Report file @@ -74,5 +80,26 @@ Enable or Disable the automatically generated report file. REPORT_FILE=true ``` +## Skip Stopping Containers +Bypass stopping the container before performing a backup. This can be useful for containers with minimal configuration. + +> **Default**: *empty* + +```properties +SKIP_STOPPING=example1,example2 +``` +!!! warning "Not stoppping containers can produce *corrupt* backups." + Containers with databases--particularly SQL--need to be shutdown before backup. + + Only do this on containers you know for certain do not need to be shutdown before backup. + +## Backup on Start +Will immediatly perform a backup when the container is started in addition to the CRON sheduled backup. + +> **Default**: false + +```properties +BACKUP_ON_START=true +```

\ No newline at end of file diff --git a/docs/installation.md b/docs/installation.md index 1e406bc1..43a1fa41 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -1,4 +1,4 @@ -For a full list of configuration options, see the [Arugments](./arguments.md) section. +For a full list of configuration options, see the [Variables](./arguments.md) section. ## Docker Compose Example diff --git a/docs/todo.md b/docs/todo.md index 5d5b4364..58cd307d 100644 --- a/docs/todo.md +++ b/docs/todo.md @@ -4,8 +4,6 @@ This project is not complete, and is still under active development. Below are a * Used in addition to enviornment variables to configure Nautical. * [ ] Backup file exclusions * For example, you could exclude `*.log` file from only the Trilium container. -* [ ] Custmizable container directories - * Currently, the container name must match the directory name; this would be nice to change. * [ ] Lifecycle hooks * Allow calling a script in the container that will about to be shutdown. diff --git a/mkdocs.yml b/mkdocs.yml index 1833c811..3afad7f1 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -35,7 +35,7 @@ nav: - Home: index.md - Introduction: introduction.md - Installation: installation.md - - Arguments: arguments.md + - Variables: arguments.md - Q & A: q-and-a.md - To Do: todo.md diff --git a/pkg/backup.sh b/pkg/backup.sh index 2577808b..8a7fa0dc 100644 --- a/pkg/backup.sh +++ b/pkg/backup.sh @@ -7,25 +7,34 @@ if [ ! -z "$CONTAINER_SKIP_LIST_STR" ]; then IFS=',' read -ra SKIP_CONTAINERS <<< "$CONTAINER_SKIP_LIST_STR" fi -declare -A override_source_dirs - -if [ ! -z "$OVERRIDE_SOURCE_DIR" ]; then - IFS=',' read -ra PAIRS <<< "$OVERRIDE_SOURCE_DIR" - for pair in "${PAIRS[@]}"; do - IFS=':' read -ra KV <<< "$pair" - override_source_dirs[${KV[0]}]=${KV[1]} - done +# Convert the string back to an array +if [ ! -z "$SKIP_STOPPING_STR" ]; then + IFS=',' read -ra SKIP_STOPPING <<< "$SKIP_STOPPING_STR" fi + +# Function to populate override directories +populate_override_dirs() { + local -n override_dirs_ref=$1 # Use nameref to update the associative array passed as argument + local override_var=$2 # The environment variable containing the override info + + if [ ! -z "$override_var" ]; then + IFS=',' read -ra PAIRS <<< "$override_var" + for pair in "${PAIRS[@]}"; do + IFS=':' read -ra KV <<< "$pair" + override_dirs_ref[${KV[0]}]=${KV[1]} + done + fi +} + +# Declare associative arrays for source and destination overrides +declare -A override_source_dirs declare -A override_dest_dirs -if [ ! -z "$OVERRIDE_DEST_DIR" ]; then - IFS=',' read -ra PAIRS <<< "$OVERRIDE_DEST_DIR" - for pair in "${PAIRS[@]}"; do - IFS=':' read -ra KV <<< "$pair" - override_dest_dirs[${KV[0]}]=${KV[1]} - done -fi +# Populate the arrays +populate_override_dirs override_source_dirs "$OVERRIDE_SOURCE_DIR" +populate_override_dirs override_dest_dirs "$OVERRIDE_DEST_DIR" + # Fetch both container names and IDs containers=$(docker ps --no-trunc --format="{{.ID}}:{{.Names}}") @@ -75,28 +84,36 @@ log_entry() { BackupContainer() { local container=$1 - - local src_dir="$SOURCE_LOCATION/$container" # Determine the source directory to use for this container - + local skip_stopping=0 + for skip in "${SKIP_STOPPING[@]}"; do + if [ "$skip" == "$container" ]; then + skip_stopping=1 + break + fi + done + + local src_dir="$SOURCE_LOCATION/$container" if [ ! -z "${override_source_dirs[$container]}" ]; then src_dir="$SOURCE_LOCATION/${override_source_dirs[$container]}" - echo "Overriding source directory for $container to ${override_source_dirs[$container]}" + log_entry "Overriding source directory for $container to ${override_source_dirs[$container]}" fi - local dest_dir="$DEST_LOCATION/$container" # Determine the source directory to use for this container - + local dest_dir="$DEST_LOCATION/$container" if [ ! -z "${override_dest_dirs[$container]}" ]; then dest_dir="$DEST_LOCATION/${override_dest_dirs[$container]}" - echo "Overriding destination directory for $container to ${override_dest_dirs[$container]}" + log_entry "Overriding destination directory for $container to ${override_dest_dirs[$container]}" fi if [ -d "$src_dir" ]; then - - log_entry "Stopping $container..." - docker stop $container 2>&1 >/dev/null - if [ $? -ne 0 ]; then - log_entry "Error stopping container $container. Skipping backup for this container." - return + if [ $skip_stopping -eq 0 ]; then + log_entry "Stopping $container..." + docker stop $container 2>&1 >/dev/null + if [ $? -ne 0 ]; then + log_entry "Error stopping container $container. Skipping backup for this container." + return + fi + else + log_entry "Skipping stopping of $container as it's in the SKIP_STOPPING list." fi log_entry "Backing up $container data..." @@ -104,22 +121,15 @@ BackupContainer() { if [ $? -ne 0 ]; then log_entry "Error copying data for container $container. Skipping backup for this container." - + fi + + if [ $skip_stopping -eq 0 ]; then log_entry "Starting $container container..." - docker start $container + docker start $container 2>&1 >/dev/null if [ $? -ne 0 ]; then log_entry "Error restarting container $container. Please check manually!" return fi - - fi - - - log_entry "Starting $container container..." - docker start $container 2>&1 >/dev/null - if [ $? -ne 0 ]; then - log_entry "Error restarting container $container. Please check manually!" - return fi log_entry "$container completed." diff --git a/pkg/entry.sh b/pkg/entry.sh index 8b05f9f2..c5d45369 100644 --- a/pkg/entry.sh +++ b/pkg/entry.sh @@ -44,22 +44,40 @@ fi CONTAINER_SKIP_LIST=() # Containers to skips -# Add any container names specified in the SKIP_CONTAINERS environment variable to the skip list -if [ ! -z "$SKIP_CONTAINERS" ]; then - # Remove quotes and leading/trailing whitespaces - cleaned_skip_containers=$(echo "$SKIP_CONTAINERS" | sed "s/'//g;s/\"//g" | tr -d ' ') - - # Split by commas into an array - IFS=',' read -ra ADDITIONAL_SKIPS <<< "$cleaned_skip_containers" - - # Add to the default skips - CONTAINER_SKIP_LIST=("${CONTAINER_SKIP_LIST[@]}" "${ADDITIONAL_SKIPS[@]}") -fi +# Function to populate the skip list array +process_csv() { + local -n skip_list_ref=$1 # Use nameref to update the array passed as argument + local skip_var=$2 # The environment variable containing the skip list + + if [ ! -z "$skip_var" ]; then + # Remove quotes and leading/trailing whitespaces + local cleaned_skip_var=$(echo "$skip_var" | sed "s/'//g;s/\"//g" | tr -d ' ') + + # Split by commas into an array + IFS=',' read -ra ADDITIONAL_SKIPS <<< "$cleaned_skip_var" + + # Add to the existing skip list + skip_list_ref=("${skip_list_ref[@]}" "${ADDITIONAL_SKIPS[@]}") + fi +} + +# Declare the CONTAINER_SKIP_LIST array +CONTAINER_SKIP_LIST=() +SKIP_STOPPING_LIST=() + +# Populate the skip list +process_csv CONTAINER_SKIP_LIST "$SKIP_CONTAINERS" +process_csv SKIP_STOPPING_LIST "$SKIP_STOPPING" + if [ ! -z "$SKIP_CONTAINERS" ]; then echo "SKIP_CONTAINERS: ${CONTAINER_SKIP_LIST[@]}" fi +if [ ! -z "$SKIP_STOPPING" ]; then + echo "SKIP_STOPPING: ${SKIP_STOPPING_LIST[@]}" +fi + # Get the container ID of the current container export SELF_CONTAINER_ID=$(cat /proc/self/cgroup | grep 'docker' | sed 's/^.*\///' | tail -n1) # Add the self container ID to the default skips @@ -68,6 +86,9 @@ CONTAINER_SKIP_LIST+=("$SELF_CONTAINER_ID") CONTAINER_SKIP_LIST_STR=$(IFS=,; echo "${CONTAINER_SKIP_LIST[*]}") # Convert the array to a string export CONTAINER_SKIP_LIST_STR # Export the string +SKIP_STOPPING_STR=$(IFS=,; echo "${SKIP_STOPPING[*]}") # Convert the array to a string +export SKIP_STOPPING_STR # Export the string + # Assuming OVERRIDE_SOURCE_DIR is passed as an environment variable in the format "container1:dir1,container2:dir2,..." if [ ! -z "$OVERRIDE_SOURCE_DIR" ]; then echo "OVERRIDE_SOURCE_DIR: ${OVERRIDE_SOURCE_DIR}" @@ -84,6 +105,11 @@ if [ "$REPORT_FILE" = "false" ]; then echo "REPORT_FILE: $REPORT_FILE" fi +if [ "$BACKUP_ON_START" = "true" ]; then + echo "BACKUP_ON_START: $BACKUP_ON_START" + bash ./app/backup.sh +fi + echo "Initialization complete. Awaiting CRON schedule: $CRON_SCHEDULE" diff --git a/snippets/docker-compose-example.yml b/snippets/docker-compose-example.yml index 4a47ed20..e8274a04 100644 --- a/snippets/docker-compose-example.yml +++ b/snippets/docker-compose-example.yml @@ -2,7 +2,7 @@ version: '3' services: nautical-backup: - image: minituff/nautical-backup:0.0.3 #(7)! + image: minituff/nautical-backup:0.0.5 #(7)! container_name: nautical-backup hostname: nautical-backup restart: unless-stopped diff --git a/snippets/docker-run-example.sh b/snippets/docker-run-example.sh index 8b9df620..22ae4322 100644 --- a/snippets/docker-run-example.sh +++ b/snippets/docker-run-example.sh @@ -5,4 +5,4 @@ docker run -d \ -v /destination:/app/destination \ #(3)! -e CRON_SCHEDULE="* 4 * * *" \ #(5)! -e SKIP_CONTAINERS="example1,example2,example3" \ #(6)! -minituff/nautical-backup:0.0.3 #(7)! \ No newline at end of file +minituff/nautical-backup:0.0.5 #(7)! \ No newline at end of file