From a627f5e65f2f6dcbb043143ca67e12d8de7efbb5 Mon Sep 17 00:00:00 2001 From: Nikolay Kiryanov Date: Tue, 27 Feb 2024 02:10:06 +0300 Subject: [PATCH 1/5] Fix shellcheck linter errors and warnings --- .github/workflows/ci.yml | 16 +++++++++++++++ Dockerfile | 1 + backup.sh | 42 +++++++++++++++++++++------------------- entrypoint.sh | 6 +++--- 4 files changed, 42 insertions(+), 23 deletions(-) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..eb6c9ed --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,16 @@ +name: Release +on: + push: + branches: + - master + pull_request: + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Lint + run: shellcheck *.sh diff --git a/Dockerfile b/Dockerfile index d78749e..e33e166 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,6 +19,7 @@ ENV S3_PATH 'backup' ENV S3_ENDPOINT **None** ENV S3_S3V4 no ENV SCHEDULE **None** +ENV SUCCESS_WEBHOOK **None** ADD entrypoint.sh . ADD backup.sh . diff --git a/backup.sh b/backup.sh index 4928409..5ec7415 100644 --- a/backup.sh +++ b/backup.sh @@ -1,75 +1,77 @@ #! /bin/sh +# shellcheck disable=SC3040 # expecting 'pipefail' derrictive is availabe in the shell + set -e set -o pipefail -if [ "${S3_ACCESS_KEY_ID}" = "**None**" ]; then +if [ "$S3_ACCESS_KEY_ID" = "**None**" ]; then echo "You need to set the S3_ACCESS_KEY_ID environment variable." exit 1 fi -if [ "${S3_SECRET_ACCESS_KEY}" = "**None**" ]; then +if [ "$S3_SECRET_ACCESS_KEY" = "**None**" ]; then echo "You need to set the S3_SECRET_ACCESS_KEY environment variable." exit 1 fi -if [ "${S3_BUCKET}" = "**None**" ]; then +if [ "$S3_BUCKET" = "**None**" ]; then echo "You need to set the S3_BUCKET environment variable." exit 1 fi -if [ "${POSTGRES_DATABASE}" = "**None**" ]; then +if [ "$POSTGRES_DATABASE" = "**None**" ]; then echo "You need to set the POSTGRES_DATABASE environment variable." exit 1 fi -if [ "${POSTGRES_HOST}" = "**None**" ]; then +if [ "$POSTGRES_HOST" = "**None**" ]; then if [ -n "${POSTGRES_PORT_5432_TCP_ADDR}" ]; then - POSTGRES_HOST=$POSTGRES_PORT_5432_TCP_ADDR - POSTGRES_PORT=$POSTGRES_PORT_5432_TCP_PORT + POSTGRES_HOST="$POSTGRES_PORT_5432_TCP_ADDR" + POSTGRES_PORT="$POSTGRES_PORT_5432_TCP_PORT" else echo "You need to set the POSTGRES_HOST environment variable." exit 1 fi fi -if [ "${POSTGRES_USER}" = "**None**" ]; then +if [ "$POSTGRES_USER" = "**None**" ]; then echo "You need to set the POSTGRES_USER environment variable." exit 1 fi -if [ "${POSTGRES_PASSWORD}" = "**None**" ]; then +if [ "$POSTGRES_PASSWORD" = "**None**" ]; then echo "You need to set the POSTGRES_PASSWORD environment variable or link to a container named POSTGRES." exit 1 fi -if [ "${S3_ENDPOINT}" == "**None**" ]; then +if [ "$S3_ENDPOINT" = "**None**" ]; then AWS_ARGS="" else - AWS_ARGS="--endpoint-url ${S3_ENDPOINT}" + AWS_ARGS="--endpoint-url $S3_ENDPOINT" fi # env vars needed for aws tools -export AWS_ACCESS_KEY_ID=$S3_ACCESS_KEY_ID -export AWS_SECRET_ACCESS_KEY=$S3_SECRET_ACCESS_KEY -export AWS_DEFAULT_REGION=$S3_REGION +export AWS_ACCESS_KEY_ID="$S3_ACCESS_KEY_ID" +export AWS_SECRET_ACCESS_KEY="$S3_SECRET_ACCESS_KEY" +export AWS_DEFAULT_REGION="$S3_REGION" -export PGPASSWORD=$POSTGRES_PASSWORD +export PGPASSWORD="$POSTGRES_PASSWORD" POSTGRES_HOST_OPTS="-h $POSTGRES_HOST -p $POSTGRES_PORT -U $POSTGRES_USER $POSTGRES_EXTRA_OPTS" -echo "Creating dump of ${POSTGRES_DATABASE} database from ${POSTGRES_HOST}..." +echo "Creating dump of $POSTGRES_DATABASE database from $POSTGRES_HOST..." -pg_dump -Fc $POSTGRES_HOST_OPTS $POSTGRES_DATABASE > db.dump +pg_dump -Fc "$POSTGRES_HOST_OPTS" "$POSTGRES_DATABASE" > db.dump echo "Uploading dump to $S3_BUCKET" -cat db.dump | aws $AWS_ARGS s3 cp - s3://$S3_BUCKET/$S3_PREFIX/${POSTGRES_DATABASE}_$(date +"%Y-%m-%dT%H:%M:%SZ").dump || exit 2 +aws "$AWS_ARGS" s3 cp db.dump "s3://$S3_BUCKET/$S3_PREFIX/$POSTGRES_DATABASE_$(date +"%Y-%m-%dT%H:%M:%SZ").dump" || exit 2 echo "DB backup uploaded successfully" rm db.dump -if [ -n $SUCCESS_WEBHOOK ]; then +if [ ! "$SUCCESS_WEBHOOK" = "**None**" ]; then echo "Notifying $SUCCESS_WEBHOOK" - curl -m 10 --retry 5 $SUCCESS_WEBHOOK + curl -m 10 --retry 5 "$SUCCESS_WEBHOOK" fi diff --git a/entrypoint.sh b/entrypoint.sh index bbb32cb..3c7df9a 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -2,14 +2,14 @@ set -e -if [ "${S3_S3V4}" = "yes" ]; then +if [ "$S3_S3V4" = "yes" ]; then aws configure set default.s3.signature_version s3v4 fi -if [ "${SCHEDULE}" = "**None**" ]; then +if [ "$SCHEDULE" = "**None**" ]; then echo You need to set up SCHEDULE env var exit 127 else - echo "${SCHEDULE} /bin/sh /backup.sh" > /etc/crontab.backup + echo "$SCHEDULE /bin/sh /backup.sh" > /etc/crontab.backup exec supercronic -debug -prometheus-listen-address 0.0.0.0 /etc/crontab.backup fi From ddba151d40ba00cd8f1bf8adf74b62c8bc910b43 Mon Sep 17 00:00:00 2001 From: Nikolay Kiryanov Date: Tue, 27 Feb 2024 02:22:57 +0300 Subject: [PATCH 2/5] Update readme to reflect the latest changes --- README.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b0ea5a0..57f7d1f 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ This is a fork of [karser/postgres-backup-s3](https://github.com/karser/docker-i Docker: ```sh -$ docker run -e S3_ACCESS_KEY_ID=key -e S3_SECRET_ACCESS_KEY=secret -e S3_BUCKET=my-bucket -e S3_PREFIX=backup -e POSTGRES_DATABASE=dbname -e POSTGRES_USER=user -e POSTGRES_PASSWORD=password -e POSTGRES_HOST=localhost f213/postgres-backup-s3 +$ docker run -e S3_ACCESS_KEY_ID=key -e S3_SECRET_ACCESS_KEY=secret -e S3_BUCKET=my-bucket -e S3_PREFIX=backup -e POSTGRES_DATABASE=dbname -e POSTGRES_USER=user -e POSTGRES_PASSWORD=password -e POSTGRES_HOST=localhost -e SCHEDULE="@daily" f213/postgres-backup-s3 ``` Docker Compose: @@ -28,7 +28,7 @@ postgres-backup: test: curl http://localhost:1880 environment: - SCHEDULE: 0 30 */2 * * * # every 2 hours at HH:30 + SCHEDULE: 0 30 */2 * * * * # every 2 hours at HH:30 S3_REGION: region S3_ACCESS_KEY_ID: key S3_SECRET_ACCESS_KEY: secret @@ -42,8 +42,6 @@ postgres-backup: SUCCESS_WEBHOOK: https://sb-ping.ru/8pp9RGwDDPzTL2R8MRb8Ae ``` -### Automatic Periodic Backups +### Crontab format -You can additionally set the `SCHEDULE` environment variable like `-e SCHEDULE="@daily"` to run the backup automatically. - -More information about the scheduling can be found [here](http://godoc.org/github.com/robfig/cron#hdr-Predefined_schedules). +Schedule format with years support. More information about the scheduling can be found [here](https://github.com/aptible/supercronic/tree/master?tab=readme-ov-file#crontab-format) From 1fc3533399452f45ced0dba16dc06b803b0e0b5b Mon Sep 17 00:00:00 2001 From: Nikolay Kiryanov Date: Tue, 27 Feb 2024 05:27:35 +0300 Subject: [PATCH 3/5] Fix variables unpack errors --- backup.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/backup.sh b/backup.sh index 5ec7415..fcb9a8c 100644 --- a/backup.sh +++ b/backup.sh @@ -1,6 +1,7 @@ #! /bin/sh # shellcheck disable=SC3040 # expecting 'pipefail' derrictive is availabe in the shell +# shellcheck disable=SC2086 # POSTGRES_HOST_OPTS and AWS_ARGS should be splitted by spaces intentionally set -e set -o pipefail @@ -61,11 +62,11 @@ POSTGRES_HOST_OPTS="-h $POSTGRES_HOST -p $POSTGRES_PORT -U $POSTGRES_USER $POSTG echo "Creating dump of $POSTGRES_DATABASE database from $POSTGRES_HOST..." -pg_dump -Fc "$POSTGRES_HOST_OPTS" "$POSTGRES_DATABASE" > db.dump +pg_dump -Fc $POSTGRES_HOST_OPTS "$POSTGRES_DATABASE" > db.dump echo "Uploading dump to $S3_BUCKET" -aws "$AWS_ARGS" s3 cp db.dump "s3://$S3_BUCKET/$S3_PREFIX/$POSTGRES_DATABASE_$(date +"%Y-%m-%dT%H:%M:%SZ").dump" || exit 2 +aws $AWS_ARGS s3 cp db.dump "s3://$S3_BUCKET/$S3_PREFIX/${POSTGRES_DATABASE}_$(date +"%Y-%m-%dT%H:%M:%SZ").dump" || exit 2 echo "DB backup uploaded successfully" From 2dbb08d7a897533097a0ddb00d09df81ea356e8c Mon Sep 17 00:00:00 2001 From: Nikolay Kiryanov Date: Wed, 28 Feb 2024 00:41:04 +0300 Subject: [PATCH 4/5] Linting: require braces around variables --- .github/workflows/ci.yml | 2 +- Makefile | 4 ++++ backup.sh | 46 ++++++++++++++++++++-------------------- entrypoint.sh | 6 +++--- 4 files changed, 31 insertions(+), 27 deletions(-) create mode 100644 Makefile diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eb6c9ed..7298ad2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,4 +13,4 @@ jobs: uses: actions/checkout@v4 - name: Lint - run: shellcheck *.sh + run: make lint diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d0d204d --- /dev/null +++ b/Makefile @@ -0,0 +1,4 @@ +SHELL_FILES := $(wildcard *.sh) + +lint: + @shellcheck --enable=require-variable-braces $(SHELL_FILES) && echo "ShellCheck passed" diff --git a/backup.sh b/backup.sh index fcb9a8c..6b05931 100644 --- a/backup.sh +++ b/backup.sh @@ -6,73 +6,73 @@ set -e set -o pipefail -if [ "$S3_ACCESS_KEY_ID" = "**None**" ]; then +if [ "${S3_ACCESS_KEY_ID}" = "**None**" ]; then echo "You need to set the S3_ACCESS_KEY_ID environment variable." exit 1 fi -if [ "$S3_SECRET_ACCESS_KEY" = "**None**" ]; then +if [ "${S3_SECRET_ACCESS_KEY}" = "**None**" ]; then echo "You need to set the S3_SECRET_ACCESS_KEY environment variable." exit 1 fi -if [ "$S3_BUCKET" = "**None**" ]; then +if [ "${S3_BUCKET}" = "**None**" ]; then echo "You need to set the S3_BUCKET environment variable." exit 1 fi -if [ "$POSTGRES_DATABASE" = "**None**" ]; then +if [ "${POSTGRES_DATABASE}" = "**None**" ]; then echo "You need to set the POSTGRES_DATABASE environment variable." exit 1 fi -if [ "$POSTGRES_HOST" = "**None**" ]; then +if [ "${POSTGRES_HOST}" = "**None**" ]; then if [ -n "${POSTGRES_PORT_5432_TCP_ADDR}" ]; then - POSTGRES_HOST="$POSTGRES_PORT_5432_TCP_ADDR" - POSTGRES_PORT="$POSTGRES_PORT_5432_TCP_PORT" + POSTGRES_HOST="${POSTGRES_PORT_5432_TCP_ADDR}" + POSTGRES_PORT="${POSTGRES_PORT_5432_TCP_PORT}" else echo "You need to set the POSTGRES_HOST environment variable." exit 1 fi fi -if [ "$POSTGRES_USER" = "**None**" ]; then +if [ "${POSTGRES_USER}" = "**None**" ]; then echo "You need to set the POSTGRES_USER environment variable." exit 1 fi -if [ "$POSTGRES_PASSWORD" = "**None**" ]; then +if [ "${POSTGRES_PASSWORD}" = "**None**" ]; then echo "You need to set the POSTGRES_PASSWORD environment variable or link to a container named POSTGRES." exit 1 fi -if [ "$S3_ENDPOINT" = "**None**" ]; then +if [ "${S3_ENDPOINT}" = "**None**" ]; then AWS_ARGS="" else - AWS_ARGS="--endpoint-url $S3_ENDPOINT" + AWS_ARGS="--endpoint-url ${S3_ENDPOINT}" fi # env vars needed for aws tools -export AWS_ACCESS_KEY_ID="$S3_ACCESS_KEY_ID" -export AWS_SECRET_ACCESS_KEY="$S3_SECRET_ACCESS_KEY" -export AWS_DEFAULT_REGION="$S3_REGION" +export AWS_ACCESS_KEY_ID="${S3_ACCESS_KEY_ID}" +export AWS_SECRET_ACCESS_KEY="${S3_SECRET_ACCESS_KEY}" +export AWS_DEFAULT_REGION="${S3_REGION}" -export PGPASSWORD="$POSTGRES_PASSWORD" -POSTGRES_HOST_OPTS="-h $POSTGRES_HOST -p $POSTGRES_PORT -U $POSTGRES_USER $POSTGRES_EXTRA_OPTS" +export PGPASSWORD="${POSTGRES_PASSWORD}" +POSTGRES_HOST_OPTS="-h ${POSTGRES_HOST} -p ${POSTGRES_PORT} -U ${POSTGRES_USER} ${POSTGRES_EXTRA_OPTS}" -echo "Creating dump of $POSTGRES_DATABASE database from $POSTGRES_HOST..." +echo "Creating dump of ${POSTGRES_DATABASE} database from ${POSTGRES_HOST}..." -pg_dump -Fc $POSTGRES_HOST_OPTS "$POSTGRES_DATABASE" > db.dump +pg_dump -Fc ${POSTGRES_HOST_OPTS} "${POSTGRES_DATABASE}" > db.dump -echo "Uploading dump to $S3_BUCKET" +echo "Uploading dump to ${S3_BUCKET}" -aws $AWS_ARGS s3 cp db.dump "s3://$S3_BUCKET/$S3_PREFIX/${POSTGRES_DATABASE}_$(date +"%Y-%m-%dT%H:%M:%SZ").dump" || exit 2 +aws ${AWS_ARGS} s3 cp db.dump "s3://${S3_BUCKET}/${S3_PREFIX}/${POSTGRES_DATABASE}_$(date +"%Y-%m-%dT%H:%M:%SZ").dump" || exit 2 echo "DB backup uploaded successfully" rm db.dump -if [ ! "$SUCCESS_WEBHOOK" = "**None**" ]; then - echo "Notifying $SUCCESS_WEBHOOK" - curl -m 10 --retry 5 "$SUCCESS_WEBHOOK" +if [ ! "${SUCCESS_WEBHOOK}" = "**None**" ]; then + echo "Notifying ${SUCCESS_WEBHOOK}" + curl -m 10 --retry 5 "${SUCCESS_WEBHOOK}" fi diff --git a/entrypoint.sh b/entrypoint.sh index 3c7df9a..bbb32cb 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -2,14 +2,14 @@ set -e -if [ "$S3_S3V4" = "yes" ]; then +if [ "${S3_S3V4}" = "yes" ]; then aws configure set default.s3.signature_version s3v4 fi -if [ "$SCHEDULE" = "**None**" ]; then +if [ "${SCHEDULE}" = "**None**" ]; then echo You need to set up SCHEDULE env var exit 127 else - echo "$SCHEDULE /bin/sh /backup.sh" > /etc/crontab.backup + echo "${SCHEDULE} /bin/sh /backup.sh" > /etc/crontab.backup exec supercronic -debug -prometheus-listen-address 0.0.0.0 /etc/crontab.backup fi From b90b975c9d3cfefe8779e4d74a748cc83c8bed08 Mon Sep 17 00:00:00 2001 From: Nikolay Kiryanov Date: Thu, 29 Feb 2024 12:34:46 +0300 Subject: [PATCH 5/5] Fix lint github workflow naming --- .github/workflows/{ci.yml => lint.yml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename .github/workflows/{ci.yml => lint.yml} (93%) diff --git a/.github/workflows/ci.yml b/.github/workflows/lint.yml similarity index 93% rename from .github/workflows/ci.yml rename to .github/workflows/lint.yml index 7298ad2..759e41b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/lint.yml @@ -1,4 +1,4 @@ -name: Release +name: Lint on: push: branches: