From 6560ec19704014bf2bf96af70c76df45e6981bf4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Finw=C3=AB?= <finwe@finwe.tf>
Date: Tue, 30 Apr 2024 15:03:22 +0800
Subject: [PATCH] Allow for custom options to pg_dumpall and custom formats

---
 postgres-backup-s3/Dockerfile |  1 +
 postgres-backup-s3/README.md  |  7 ++++---
 postgres-backup-s3/backup.sh  | 38 +++++++++++++++++++++++++++--------
 postgres-backup-s3/install.sh |  2 +-
 4 files changed, 36 insertions(+), 12 deletions(-)

diff --git a/postgres-backup-s3/Dockerfile b/postgres-backup-s3/Dockerfile
index 747f90c..80c8fa6 100644
--- a/postgres-backup-s3/Dockerfile
+++ b/postgres-backup-s3/Dockerfile
@@ -11,6 +11,7 @@ ENV POSTGRES_PORT 5432
 ENV POSTGRES_USER **None**
 ENV POSTGRES_PASSWORD **None**
 ENV POSTGRES_EXTRA_OPTS ''
+ENV POSTGRES_FORMAT **None**
 ENV S3_ACCESS_KEY_ID **None**
 ENV S3_SECRET_ACCESS_KEY **None**
 ENV S3_BUCKET **None**
diff --git a/postgres-backup-s3/README.md b/postgres-backup-s3/README.md
index 0e73f69..38fbd4c 100644
--- a/postgres-backup-s3/README.md
+++ b/postgres-backup-s3/README.md
@@ -36,6 +36,7 @@ pgbackups3:
     POSTGRES_USER: user
     POSTGRES_PASSWORD: password
     POSTGRES_EXTRA_OPTS: '--schema=public --blobs'
+    POSTGRES_FORMAT: 'c'
 ```
 
 ### Automatic Periodic Backups
@@ -45,9 +46,9 @@ You can additionally set the `SCHEDULE` environment variable like `-e SCHEDULE="
 More information about the scheduling can be found [here](http://godoc.org/github.com/robfig/cron#hdr-Predefined_schedules).
 
 ### Backup File Name / Path
-By default, if `POSTGRES_BACKUP_ALL` is true, the dump file will be put at `<S3_PREFIX=''>/all_<timestamp>.sql.gz`. When using `POSTGRES_DATABASE`, each database listed will be backed up to the object path `<S3_PREFIX=''>/<database>_<timestamp>.sql.gz`.
+By default, if `POSTGRES_BACKUP_ALL` is true, the dump file will be put at `<S3_PREFIX=''>/all_<timestamp>.sql.gz`. When using `POSTGRES_DATABASE`, each database listed will be backed up to the object path `<S3_PREFIX=''>/<database>_<timestamp>.<extension>`.
 
-If you wish to make these filenames static, you can use the `S3_FILE_NAME` variable, which will change these formats to `<S3_PREFIX=''>/<S3_FILE_NAME>.sql.gz` or `<S3_PREFIX=''>/<S3_FILE_NAME>_<database>.sql.gz` accordingly.
+If you wish to make these filenames static, you can use the `S3_FILE_NAME` variable, which will change these formats to `<S3_PREFIX=''>/<S3_FILE_NAME>.<extension>` or `<S3_PREFIX=''>/<S3_FILE_NAME>_<database>.<extension>` accordingly.
 
 ### Backup All Databases
 
@@ -65,4 +66,4 @@ You can specify an alternate endpoint by setting `S3_ENDPOINT` environment varia
 
 ### Encryption
 
-You can additionally set the `ENCRYPTION_PASSWORD` environment variable like `-e ENCRYPTION_PASSWORD="superstrongpassword"` to encrypt the backup. It can be decrypted using `openssl aes-256-cbc -d -in backup.sql.gz.enc -out backup.sql.gz`.
\ No newline at end of file
+You can additionally set the `ENCRYPTION_PASSWORD` environment variable like `-e ENCRYPTION_PASSWORD="superstrongpassword"` to encrypt the backup. It can be decrypted using `openssl aes-256-cbc -d -in backup.sql.gz.enc -out backup.sql.gz`.
diff --git a/postgres-backup-s3/backup.sh b/postgres-backup-s3/backup.sh
index 4ae6cff..37edec7 100644
--- a/postgres-backup-s3/backup.sh
+++ b/postgres-backup-s3/backup.sh
@@ -65,13 +65,13 @@ fi
 if [ "${POSTGRES_BACKUP_ALL}" == "true" ]; then
   SRC_FILE=dump.sql.gz
   DEST_FILE=all_$(date +"%Y-%m-%dT%H:%M:%SZ").sql.gz
-  
+
   if [ "${S3_FILE_NAME}" != "**None**" ]; then
     DEST_FILE=${S3_FILE_NAME}.sql.gz
   fi
 
   echo "Creating dump of all databases from ${POSTGRES_HOST}..."
-  pg_dumpall -h $POSTGRES_HOST -p $POSTGRES_PORT -U $POSTGRES_USER | gzip > $SRC_FILE
+  pg_dumpall $POSTGRES_HOST_OPTS | gzip > $SRC_FILE
 
   if [ "${ENCRYPTION_PASSWORD}" != "**None**" ]; then
     echo "Encrypting ${SRC_FILE}"
@@ -90,22 +90,44 @@ if [ "${POSTGRES_BACKUP_ALL}" == "true" ]; then
   echo "SQL backup uploaded successfully"
   rm -rf $SRC_FILE
 else
+  if [ "${POSTGRES_FORMAT}" = "**None**"]; then
+    POSTGRES_FORMAT="p"
+  fi
+
+  case "$POSTGRES_FORMAT" in
+      (p|c|t) ;;
+      (d) echo "Directory format not supported, only single-file formats are supported: p, c, t" >&2; exit 1 ;;
+      (*) echo "Unknown pg_dump format '$POSTGRES_FORMAT'. Please use one within: p, c, d, t" >&2; exit 1 ;;
+  esac
+
+  POSTGRES_HOST_OPTS+=" -F${POSTGRES_FORMAT}"
+
+  FILE_EXT="sql.gz"
+  case "$POSTGRES_FORMAT" in
+      (c) FILE_EXT="dump";;
+      (t) FILE_EXT="tar";;
+  esac
+
   OIFS="$IFS"
   IFS=','
   for DB in $POSTGRES_DATABASE
   do
     IFS="$OIFS"
 
-    SRC_FILE=dump.sql.gz
-    DEST_FILE=${DB}_$(date +"%Y-%m-%dT%H:%M:%SZ").sql.gz
+    SRC_FILE="dump.${FILE_EXT}"
+    DEST_FILE="${DB}_$(date +"%Y-%m-%dT%H:%M:%SZ").${FILE_EXT}"
 
     if [ "${S3_FILE_NAME}" != "**None**" ]; then
-      DEST_FILE=${S3_FILE_NAME}_${DB}.sql.gz
+      DEST_FILE="${S3_FILE_NAME}_${DB}.${FILE_EXT}"
     fi
-    
+
     echo "Creating dump of ${DB} database from ${POSTGRES_HOST}..."
-    pg_dump $POSTGRES_HOST_OPTS $DB | gzip > $SRC_FILE
-    
+    if [ "$POSTGRES_FORMAT" = "p" ]; then
+      pg_dump $POSTGRES_HOST_OPTS $DB | gzip > ${SRC_FILE}
+    else
+      pg_dump $POSTGRES_HOST_OPTS $DB > ${SRC_FILE}
+    fi
+
     if [ "${ENCRYPTION_PASSWORD}" != "**None**" ]; then
       echo "Encrypting ${SRC_FILE}"
       openssl enc -aes-256-cbc -in $SRC_FILE -out ${SRC_FILE}.enc -k $ENCRYPTION_PASSWORD
diff --git a/postgres-backup-s3/install.sh b/postgres-backup-s3/install.sh
index 5e63e1a..d993d53 100644
--- a/postgres-backup-s3/install.sh
+++ b/postgres-backup-s3/install.sh
@@ -4,7 +4,7 @@
 set -eo pipefail
 
 apk update
-apk add openssl aws-cli 
+apk add openssl aws-cli
 apk add postgresql-client --repository=https://dl-cdn.alpinelinux.org/alpine/v3.18/main
 
 # cleanup