From 95002a753dc5e418b9dc7e7faadd70066ff898cb Mon Sep 17 00:00:00 2001 From: Frederik Ring Date: Wed, 29 Jun 2022 21:39:39 +0200 Subject: [PATCH 01/11] Refactor label command mechanism to be more flexible --- cmd/backup/exec.go | 15 +++++++++++++++ cmd/backup/main.go | 12 +++--------- cmd/backup/script.go | 18 ++---------------- 3 files changed, 20 insertions(+), 25 deletions(-) diff --git a/cmd/backup/exec.go b/cmd/backup/exec.go index 9499396c..bacd2859 100644 --- a/cmd/backup/exec.go +++ b/cmd/backup/exec.go @@ -121,3 +121,18 @@ func (s *script) runLabeledCommands(label string) error { } return nil } + +func (s *script) withLabeledCommands(label string, cb func() error) func() error { + if s.cli == nil { + return cb + } + return func() error { + if err := s.runLabeledCommands(fmt.Sprintf("docker-volume-backup.%s-pre", label)); err != nil { + return fmt.Errorf("withLabeledCommands: %s: error running pre commands: %w", label, err) + } + defer func() { + s.runLabeledCommands(fmt.Sprintf("docker-volume-backup.%s-post", label)) + }() + return cb() + } +} diff --git a/cmd/backup/main.go b/cmd/backup/main.go index 9da34109..0f1a8f32 100644 --- a/cmd/backup/main.go +++ b/cmd/backup/main.go @@ -38,14 +38,7 @@ func main() { s.logger.Info("Finished running backup tasks.") }() - s.must(func() error { - runPostCommands, err := s.runCommands() - defer func() { - s.must(runPostCommands()) - }() - if err != nil { - return err - } + doArchive := s.withLabeledCommands("exec", func() error { restartContainers, err := s.stopContainers() // The mechanism for restarting containers is not using hooks as it // should happen as soon as possible (i.e. before uploading backups or @@ -57,7 +50,8 @@ func main() { return err } return s.takeBackup() - }()) + }) + s.must(doArchive()) s.must(s.encryptBackup()) s.must(s.copyBackup()) diff --git a/cmd/backup/script.go b/cmd/backup/script.go index 99657be7..9a295934 100644 --- a/cmd/backup/script.go +++ b/cmd/backup/script.go @@ -32,9 +32,11 @@ import ( "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" "github.com/otiai10/copy" + "github.com/pkg/sftp" "github.com/sirupsen/logrus" "github.com/studio-b12/gowebdav" "golang.org/x/crypto/openpgp" + "golang.org/x/crypto/ssh" ) // script holds all the stateful information required to orchestrate a @@ -282,22 +284,6 @@ func newScript() (*script, error) { return s, nil } -func (s *script) runCommands() (func() error, error) { - if s.cli == nil { - return noop, nil - } - - if err := s.runLabeledCommands("docker-volume-backup.exec-pre"); err != nil { - return noop, fmt.Errorf("runCommands: error running pre commands: %w", err) - } - return func() error { - if err := s.runLabeledCommands("docker-volume-backup.exec-post"); err != nil { - return fmt.Errorf("runCommands: error running post commands: %w", err) - } - return nil - }, nil -} - // stopContainers stops all Docker containers that are marked as to being // stopped during the backup and returns a function that can be called to // restart everything that has been stopped. From 3597be03454acf939a2bf76162d7d08254ab3c69 Mon Sep 17 00:00:00 2001 From: Frederik Ring Date: Wed, 29 Jun 2022 21:52:50 +0200 Subject: [PATCH 02/11] Run all steps wrapped in labeled commands --- cmd/backup/exec.go | 8 ++++---- cmd/backup/main.go | 11 +++++------ test/commands/docker-compose.yml | 4 ++-- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/cmd/backup/exec.go b/cmd/backup/exec.go index bacd2859..ea38ed51 100644 --- a/cmd/backup/exec.go +++ b/cmd/backup/exec.go @@ -122,16 +122,16 @@ func (s *script) runLabeledCommands(label string) error { return nil } -func (s *script) withLabeledCommands(label string, cb func() error) func() error { +func (s *script) withLabeledCommands(step string, cb func() error) func() error { if s.cli == nil { return cb } return func() error { - if err := s.runLabeledCommands(fmt.Sprintf("docker-volume-backup.%s-pre", label)); err != nil { - return fmt.Errorf("withLabeledCommands: %s: error running pre commands: %w", label, err) + if err := s.runLabeledCommands(fmt.Sprintf("docker-volume-backup.%s-pre", step)); err != nil { + return fmt.Errorf("withLabeledCommands: %s: error running pre commands: %w", step, err) } defer func() { - s.runLabeledCommands(fmt.Sprintf("docker-volume-backup.%s-post", label)) + s.runLabeledCommands(fmt.Sprintf("docker-volume-backup.%s-post", step)) }() return cb() } diff --git a/cmd/backup/main.go b/cmd/backup/main.go index 0f1a8f32..e2991b3a 100644 --- a/cmd/backup/main.go +++ b/cmd/backup/main.go @@ -38,7 +38,7 @@ func main() { s.logger.Info("Finished running backup tasks.") }() - doArchive := s.withLabeledCommands("exec", func() error { + s.must(s.withLabeledCommands("archive", func() error { restartContainers, err := s.stopContainers() // The mechanism for restarting containers is not using hooks as it // should happen as soon as possible (i.e. before uploading backups or @@ -50,10 +50,9 @@ func main() { return err } return s.takeBackup() - }) - s.must(doArchive()) + })()) - s.must(s.encryptBackup()) - s.must(s.copyBackup()) - s.must(s.pruneBackups()) + s.must(s.withLabeledCommands("encrypt", s.encryptBackup)()) + s.must(s.withLabeledCommands("copy", s.copyBackup)()) + s.must(s.withLabeledCommands("prune", s.pruneBackups)()) } diff --git a/test/commands/docker-compose.yml b/test/commands/docker-compose.yml index 0119fcc9..627c3c5b 100644 --- a/test/commands/docker-compose.yml +++ b/test/commands/docker-compose.yml @@ -10,8 +10,8 @@ services: MARIADB_ROOT_PASSWORD: test MARIADB_DATABASE: backup labels: - - docker-volume-backup.exec-pre=/bin/sh -c 'mysqldump -ptest --all-databases > /tmp/volume/dump.sql' - - docker-volume-backup.exec-post=/bin/sh -c 'echo "post" > /tmp/volume/post.txt' + - docker-volume-backup.archive-pre=/bin/sh -c 'mysqldump -ptest --all-databases > /tmp/volume/dump.sql' + - docker-volume-backup.copy-post=/bin/sh -c 'echo "post" > /tmp/volume/post.txt' - docker-volume-backup.exec-label=test volumes: - app_data:/tmp/volume From 140681169d554e8b6b0e5760ab20a5f51fd91d21 Mon Sep 17 00:00:00 2001 From: Frederik Ring Date: Thu, 30 Jun 2022 13:46:39 +0200 Subject: [PATCH 03/11] Rename methods to be in line with lifecycle --- cmd/backup/main.go | 6 +++--- cmd/backup/script.go | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cmd/backup/main.go b/cmd/backup/main.go index e2991b3a..f0c0cfda 100644 --- a/cmd/backup/main.go +++ b/cmd/backup/main.go @@ -49,10 +49,10 @@ func main() { if err != nil { return err } - return s.takeBackup() + return s.createArchive() })()) - s.must(s.withLabeledCommands("encrypt", s.encryptBackup)()) - s.must(s.withLabeledCommands("copy", s.copyBackup)()) + s.must(s.withLabeledCommands("encrypt", s.encryptArchive)()) + s.must(s.withLabeledCommands("copy", s.copyArchive)()) s.must(s.withLabeledCommands("prune", s.pruneBackups)()) } diff --git a/cmd/backup/script.go b/cmd/backup/script.go index 9a295934..b00d6b6c 100644 --- a/cmd/backup/script.go +++ b/cmd/backup/script.go @@ -403,9 +403,9 @@ func (s *script) stopContainers() (func() error, error) { }, stopError } -// takeBackup creates a tar archive of the configured backup location and +// createArchive creates a tar archive of the configured backup location and // saves it to disk. -func (s *script) takeBackup() error { +func (s *script) createArchive() error { backupSources := s.c.BackupSources if s.c.BackupFromSnapshot { @@ -470,10 +470,10 @@ func (s *script) takeBackup() error { return nil } -// encryptBackup encrypts the backup file using PGP and the configured passphrase. +// encryptArchive encrypts the backup file using PGP and the configured passphrase. // In case no passphrase is given it returns early, leaving the backup file // untouched. -func (s *script) encryptBackup() error { +func (s *script) encryptArchive() error { if s.c.GpgPassphrase == "" { return nil } @@ -517,9 +517,9 @@ func (s *script) encryptBackup() error { return nil } -// copyBackup makes sure the backup file is copied to both local and remote locations +// copyArchive makes sure the backup file is copied to both local and remote locations // as per the given configuration. -func (s *script) copyBackup() error { +func (s *script) copyArchive() error { _, name := path.Split(s.file) if stat, err := os.Stat(s.file); err != nil { return fmt.Errorf("copyBackup: unable to stat backup file: %w", err) From 47011312e0888ed817393da97bf715ded08ad7a4 Mon Sep 17 00:00:00 2001 From: Frederik Ring Date: Thu, 30 Jun 2022 14:00:20 +0200 Subject: [PATCH 04/11] Deprecate exec-pre and exec-post labels --- cmd/backup/exec.go | 46 ++++++++++++++++++++++++++++++++++++++++++++ cmd/backup/script.go | 2 +- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/cmd/backup/exec.go b/cmd/backup/exec.go index ea38ed51..d8a117a5 100644 --- a/cmd/backup/exec.go +++ b/cmd/backup/exec.go @@ -93,10 +93,56 @@ func (s *script) runLabeledCommands(label string) error { return fmt.Errorf("runLabeledCommands: error querying for containers: %w", err) } + var hasDeprecatedContainers bool + if label == "docker-volume-backup.archive-pre" { + f[0] = filters.KeyValuePair{ + Key: "label", + Value: "docker-volume-backup.exec-pre", + } + deprecatedContainers, err := s.cli.ContainerList(context.Background(), types.ContainerListOptions{ + Quiet: true, + Filters: filters.NewArgs(f...), + }) + if err != nil { + return fmt.Errorf("runLabeledCommands: error querying for containers: %w", err) + } + if len(deprecatedContainers) != 0 { + hasDeprecatedContainers = true + containersWithCommand = append(containersWithCommand, deprecatedContainers...) + } + } + + if label == "docker-volume-backup.archive-post" { + f[0] = filters.KeyValuePair{ + Key: "label", + Value: "docker-volume-backup.exec-post", + } + deprecatedContainers, err := s.cli.ContainerList(context.Background(), types.ContainerListOptions{ + Quiet: true, + Filters: filters.NewArgs(f...), + }) + if err != nil { + return fmt.Errorf("runLabeledCommands: error querying for containers: %w", err) + } + if len(deprecatedContainers) != 0 { + hasDeprecatedContainers = true + containersWithCommand = append(containersWithCommand, deprecatedContainers...) + } + } + if len(containersWithCommand) == 0 { return nil } + if hasDeprecatedContainers { + s.logger.Warn( + "Using `docker-volume-backup.exec-pre` and `docker-volume-backup.exec-post` labels has been deprecated and will be removed in the next major version.", + ) + s.logger.Warn( + "Please use other `-pre` and `-post` labels instead. Refer to the README for an upgrade guide.", + ) + } + g := new(errgroup.Group) for _, container := range containersWithCommand { diff --git a/cmd/backup/script.go b/cmd/backup/script.go index b00d6b6c..810f8b42 100644 --- a/cmd/backup/script.go +++ b/cmd/backup/script.go @@ -413,7 +413,7 @@ func (s *script) createArchive() error { "Using BACKUP_FROM_SNAPSHOT has been deprecated and will be removed in the next major version.", ) s.logger.Warn( - "Please use `exec-pre` and `exec-post` commands to prepare your backup sources. Refer to the README for an upgrade guide.", + "Please use `archive-pre` and `archive-post` commands to prepare your backup sources. Refer to the README for an upgrade guide.", ) backupSources = filepath.Join("/tmp", s.c.BackupSources) // copy before compressing guard against a situation where backup folder's content are still growing. From b692100e0fee9fea090b2336dff72847bead0bf7 Mon Sep 17 00:00:00 2001 From: Frederik Ring Date: Thu, 30 Jun 2022 14:26:17 +0200 Subject: [PATCH 05/11] Add documentation --- README.md | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 53b482a7..1a0e78dd 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ It handles __recurring or one-off backups of Docker volumes__ to a __local direc - [Automatically pruning old backups](#automatically-pruning-old-backups) - [Send email notifications on failed backup runs](#send-email-notifications-on-failed-backup-runs) - [Customize notifications](#customize-notifications) - - [Run custom commands before / after backup](#run-custom-commands-before--after-backup) + - [Run custom commands during the backup lifecycle](#run-custom-commands-during-the-backup-lifecycle) - [Encrypting your backup using GPG](#encrypting-your-backup-using-gpg) - [Restoring a volume from a backup](#restoring-a-volume-from-a-backup) - [Set the timezone the container runs in](#set-the-timezone-the-container-runs-in) @@ -28,6 +28,7 @@ It handles __recurring or one-off backups of Docker volumes__ to a __local direc - [Manually triggering a backup](#manually-triggering-a-backup) - [Update deprecated email configuration](#update-deprecated-email-configuration) - [Replace deprecated `BACKUP_FROM_SNAPSHOT` usage](#replace-deprecated-backup_from_snapshot-usage) + - [Replace deprecated `exec-pre` and `exec-post` labels](#replace-deprecated-exec-pre-and-exec-post-labels) - [Using a custom Docker host](#using-a-custom-docker-host) - [Run multiple backup schedules in the same container](#run-multiple-backup-schedules-in-the-same-container) - [Define different retention schedules](#define-different-retention-schedules) @@ -351,7 +352,7 @@ You can populate below template according to your requirements and use it as you # It is possible to define commands to be run in any container before and after # a backup is conducted. The commands themselves are defined in labels like -# `docker-volume-backup.exec-pre=/bin/sh -c 'mysqldump [options] > dump.sql'. +# `docker-volume-backup.archive-pre=/bin/sh -c 'mysqldump [options] > dump.sql'. # Several options exist for controlling this feature: # By default, any output of such a command is suppressed. If this value @@ -543,11 +544,16 @@ Overridable template names are: `title_success`, `body_success`, `title_failure` For a full list of available variables and functions, see [this page](https://github.com/offen/docker-volume-backup/blob/master/docs/NOTIFICATION-TEMPLATES.md). -### Run custom commands before / after backup +### Run custom commands during the backup lifecycle In certain scenarios it can be required to run specific commands before and after a backup is taken (e.g. dumping a database). When mounting the Docker socket into the `docker-volume-backup` container, you can define pre- and post-commands that will be run in the context of the target container. -Such commands are defined by specifying the command in a `docker-volume-backup.exec-[pre|post]` label. +Such commands are defined by specifying the command in a `docker-volume-backup.[step]-[pre|post]` label where `step` can be any of the following phases of a backup lifecyle: + +- `archive` (the tar archive is created) +- `encrypt` (the tar archive is encrypted - optional) +- `copy` (the tar archive is copied to all configured storages) +- `prune` (existing backups are pruned based on the defined ruleset - optional) Taking a database dump using `mysqldump` would look like this: @@ -561,7 +567,7 @@ services: volumes: - backup_data:/tmp/backups labels: - - docker-volume-backup.exec-pre=/bin/sh -c 'mysqldump --all-databases > /backups/dump.sql' + - docker-volume-backup.archive-pre=/bin/sh -c 'mysqldump --all-databases > /backups/dump.sql' volumes: backup_data: @@ -723,7 +729,7 @@ NOTIFICATION_URLS=smtp://me:secret@posteo.de:587/?fromAddress=no-reply@example.c ### Replace deprecated `BACKUP_FROM_SNAPSHOT` usage Starting with version 2.15.0, the `BACKUP_FROM_SNAPSHOT` feature has been deprecated. -If you need to prepare your sources before the backup is taken, use `exec-pre`, `exec-post` and an intermediate volume: +If you need to prepare your sources before the backup is taken, use `archive-pre`, `archive-post` and an intermediate volume: ```yml version: '3' @@ -735,8 +741,8 @@ services: - data:/var/my_app - backup:/tmp/backup labels: - - docker-volume-backup.exec-pre=cp -r /var/my_app /tmp/backup/my-app - - docker-volume-backup.exec-post=rm -rf /tmp/backup/my-app + - docker-volume-backup.archive-pre=cp -r /var/my_app /tmp/backup/my-app + - docker-volume-backup.archive-post=rm -rf /tmp/backup/my-app backup: image: offen/docker-volume-backup:latest @@ -751,6 +757,22 @@ volumes: backup: ``` +### Replace deprecated `exec-pre` and `exec-post` labels + +Version 2.19.0 introduced the option to run labeled commands at multiple points in time during the backup lifecycle. +In order to be able to use more obvious terminology in the new labels, the existing `exec-pre` and `exec-post` labels have been deprecated. +If you want to emulate the existing behavior, all you need to do is change `exec-pre` to `archive-pre` and `exec-post` to `archive-post`: + +```diff + labels: +- - docker-volume-backup.exec-pre=cp -r /var/my_app /tmp/backup/my-app ++ - docker-volume-backup.archive-pre=cp -r /var/my_app /tmp/backup/my-app +- - docker-volume-backup.exec-post=rm -rf /tmp/backup/my-app ++ - docker-volume-backup.archive-post=rm -rf /tmp/backup/my-app +``` + +Check the additional documentation on running commands during the backup lifecycle to find out about further possibilities. + ### Using a custom Docker host If you are interfacing with Docker via TCP, set `DOCKER_HOST` to the correct URL. From 12a231edc11e58e2cc831c5a2e081a2d2dee6df7 Mon Sep 17 00:00:00 2001 From: Frederik Ring Date: Thu, 30 Jun 2022 14:44:37 +0200 Subject: [PATCH 06/11] Use type alias for lifecycle phases --- cmd/backup/exec.go | 11 ++++++++++- cmd/backup/main.go | 8 ++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/cmd/backup/exec.go b/cmd/backup/exec.go index d8a117a5..6e0f0a07 100644 --- a/cmd/backup/exec.go +++ b/cmd/backup/exec.go @@ -168,7 +168,16 @@ func (s *script) runLabeledCommands(label string) error { return nil } -func (s *script) withLabeledCommands(step string, cb func() error) func() error { +type lifecyclePhase string + +const ( + lifecyclePhaseArchive lifecyclePhase = "archive" + lifecyclePhaseEncrypt lifecyclePhase = "encrypt" + lifecyclePhaseCopy lifecyclePhase = "copy" + lifecyclePhasePrune lifecyclePhase = "prune" +) + +func (s *script) withLabeledCommands(step lifecyclePhase, cb func() error) func() error { if s.cli == nil { return cb } diff --git a/cmd/backup/main.go b/cmd/backup/main.go index f0c0cfda..f72b3fa9 100644 --- a/cmd/backup/main.go +++ b/cmd/backup/main.go @@ -38,7 +38,7 @@ func main() { s.logger.Info("Finished running backup tasks.") }() - s.must(s.withLabeledCommands("archive", func() error { + s.must(s.withLabeledCommands(lifecyclePhaseArchive, func() error { restartContainers, err := s.stopContainers() // The mechanism for restarting containers is not using hooks as it // should happen as soon as possible (i.e. before uploading backups or @@ -52,7 +52,7 @@ func main() { return s.createArchive() })()) - s.must(s.withLabeledCommands("encrypt", s.encryptArchive)()) - s.must(s.withLabeledCommands("copy", s.copyArchive)()) - s.must(s.withLabeledCommands("prune", s.pruneBackups)()) + s.must(s.withLabeledCommands(lifecyclePhaseEncrypt, s.encryptArchive)()) + s.must(s.withLabeledCommands(lifecyclePhaseCopy, s.copyArchive)()) + s.must(s.withLabeledCommands(lifecyclePhasePrune, s.pruneBackups)()) } From 00b7fba66a4a6c871ef8e81a5172fae51230e5c5 Mon Sep 17 00:00:00 2001 From: Frederik Ring Date: Wed, 6 Jul 2022 13:38:59 +0200 Subject: [PATCH 07/11] Fix bad imports --- cmd/backup/script.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/cmd/backup/script.go b/cmd/backup/script.go index 810f8b42..41e7adec 100644 --- a/cmd/backup/script.go +++ b/cmd/backup/script.go @@ -18,9 +18,6 @@ import ( "text/template" "time" - "github.com/pkg/sftp" - "golang.org/x/crypto/ssh" - "github.com/containrrr/shoutrrr" "github.com/containrrr/shoutrrr/pkg/router" "github.com/docker/docker/api/types" From 4f8e9ea3241fd3412bf325adad72c2de182bf956 Mon Sep 17 00:00:00 2001 From: Frederik Ring Date: Thu, 7 Jul 2022 09:24:20 +0200 Subject: [PATCH 08/11] Fix command lookup for deprecated labels --- cmd/backup/exec.go | 8 +++++++- test/commands/docker-compose.yml | 3 ++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/cmd/backup/exec.go b/cmd/backup/exec.go index 6e0f0a07..b36cdc28 100644 --- a/cmd/backup/exec.go +++ b/cmd/backup/exec.go @@ -148,7 +148,13 @@ func (s *script) runLabeledCommands(label string) error { for _, container := range containersWithCommand { c := container g.Go(func() error { - cmd, _ := c.Labels[label] + cmd, ok := c.Labels[label] + if !ok && label == "docker-volume-backup.archive-pre" { + cmd, _ = c.Labels["docker-volume-backup.exec-pre"] + } else if !ok && label == "docker-volume-backup.archive-post" { + cmd, _ = c.Labels["docker-volume-backup.exec-post"] + } + s.logger.Infof("Running %s command %s for container %s", label, cmd, strings.TrimPrefix(c.Names[0], "/")) stdout, stderr, err := s.exec(c.ID, cmd) if s.c.ExecForwardOutput { diff --git a/test/commands/docker-compose.yml b/test/commands/docker-compose.yml index 627c3c5b..fe0d57fd 100644 --- a/test/commands/docker-compose.yml +++ b/test/commands/docker-compose.yml @@ -10,7 +10,8 @@ services: MARIADB_ROOT_PASSWORD: test MARIADB_DATABASE: backup labels: - - docker-volume-backup.archive-pre=/bin/sh -c 'mysqldump -ptest --all-databases > /tmp/volume/dump.sql' + # this is testing the deprecated label on purpose + - docker-volume-backup.exec-pre=/bin/sh -c 'mysqldump -ptest --all-databases > /tmp/volume/dump.sql' - docker-volume-backup.copy-post=/bin/sh -c 'echo "post" > /tmp/volume/post.txt' - docker-volume-backup.exec-label=test volumes: From 0f7c81bec8ae277ae682db8298b1c66f27f7df04 Mon Sep 17 00:00:00 2001 From: Frederik Ring Date: Thu, 7 Jul 2022 10:25:55 +0200 Subject: [PATCH 09/11] Use more generic naming for lifecycle phase --- README.md | 2 +- cmd/backup/exec.go | 2 +- cmd/backup/main.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1a0e78dd..ae480897 100644 --- a/README.md +++ b/README.md @@ -551,7 +551,7 @@ When mounting the Docker socket into the `docker-volume-backup` container, you c Such commands are defined by specifying the command in a `docker-volume-backup.[step]-[pre|post]` label where `step` can be any of the following phases of a backup lifecyle: - `archive` (the tar archive is created) -- `encrypt` (the tar archive is encrypted - optional) +- `process` (the tar archive is processed, e.g. encrypted - optional) - `copy` (the tar archive is copied to all configured storages) - `prune` (existing backups are pruned based on the defined ruleset - optional) diff --git a/cmd/backup/exec.go b/cmd/backup/exec.go index b36cdc28..cf197879 100644 --- a/cmd/backup/exec.go +++ b/cmd/backup/exec.go @@ -178,7 +178,7 @@ type lifecyclePhase string const ( lifecyclePhaseArchive lifecyclePhase = "archive" - lifecyclePhaseEncrypt lifecyclePhase = "encrypt" + lifecyclePhaseProcess lifecyclePhase = "process" lifecyclePhaseCopy lifecyclePhase = "copy" lifecyclePhasePrune lifecyclePhase = "prune" ) diff --git a/cmd/backup/main.go b/cmd/backup/main.go index f72b3fa9..1a8fe98b 100644 --- a/cmd/backup/main.go +++ b/cmd/backup/main.go @@ -52,7 +52,7 @@ func main() { return s.createArchive() })()) - s.must(s.withLabeledCommands(lifecyclePhaseEncrypt, s.encryptArchive)()) + s.must(s.withLabeledCommands(lifecyclePhaseProcess, s.encryptArchive)()) s.must(s.withLabeledCommands(lifecyclePhaseCopy, s.copyArchive)()) s.must(s.withLabeledCommands(lifecyclePhasePrune, s.pruneBackups)()) } From fd78c15660ae063e3250329b98168170cb642288 Mon Sep 17 00:00:00 2001 From: Frederik Ring Date: Thu, 7 Jul 2022 11:19:04 +0200 Subject: [PATCH 10/11] Fail on erroneous post command --- cmd/backup/exec.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/backup/exec.go b/cmd/backup/exec.go index cf197879..04eee8f2 100644 --- a/cmd/backup/exec.go +++ b/cmd/backup/exec.go @@ -192,7 +192,7 @@ func (s *script) withLabeledCommands(step lifecyclePhase, cb func() error) func( return fmt.Errorf("withLabeledCommands: %s: error running pre commands: %w", step, err) } defer func() { - s.runLabeledCommands(fmt.Sprintf("docker-volume-backup.%s-post", step)) + s.must(s.runLabeledCommands(fmt.Sprintf("docker-volume-backup.%s-post", step))) }() return cb() } From a54b393071de6317f0fbe1099e945864b93b2304 Mon Sep 17 00:00:00 2001 From: Frederik Ring Date: Sun, 10 Jul 2022 10:24:30 +0200 Subject: [PATCH 11/11] Update documentation --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ae480897..8d53b98e 100644 --- a/README.md +++ b/README.md @@ -547,7 +547,7 @@ For a full list of available variables and functions, see [this page](https://gi ### Run custom commands during the backup lifecycle In certain scenarios it can be required to run specific commands before and after a backup is taken (e.g. dumping a database). -When mounting the Docker socket into the `docker-volume-backup` container, you can define pre- and post-commands that will be run in the context of the target container. +When mounting the Docker socket into the `docker-volume-backup` container, you can define pre- and post-commands that will be run in the context of the target container (it is also possible to run commands inside the `docker-volume-backup` container itself using this feature). Such commands are defined by specifying the command in a `docker-volume-backup.[step]-[pre|post]` label where `step` can be any of the following phases of a backup lifecyle: - `archive` (the tar archive is created) @@ -587,7 +587,7 @@ services: volumes: - backup_data:/tmp/backups labels: - - docker-volume-backup.exec-pre=/bin/sh -c 'mysqldump --all-databases > /tmp/volume/dump.sql' + - docker-volume-backup.archive-pre=/bin/sh -c 'mysqldump --all-databases > /tmp/volume/dump.sql' - docker-volume-backup.exec-label=database backup: @@ -603,7 +603,7 @@ volumes: ``` -The backup procedure is guaranteed to wait for all `pre` commands to finish. +The backup procedure is guaranteed to wait for all `pre` or `post` commands to finish before proceeding. However there are no guarantees about the order in which they are run, which could also happen concurrently. ### Encrypting your backup using GPG @@ -771,6 +771,7 @@ If you want to emulate the existing behavior, all you need to do is change `exec + - docker-volume-backup.archive-post=rm -rf /tmp/backup/my-app ``` +The `EXEC_LABEL` setting and the `docker-volume-backup.exec-label` label stay as is. Check the additional documentation on running commands during the backup lifecycle to find out about further possibilities. ### Using a custom Docker host