mirror of
https://github.com/offen/docker-volume-backup.git
synced 2025-12-08 02:08:03 +01:00
Compare commits
11 Commits
v2.43.1
...
retention-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8a853a5b03 | ||
|
|
378217e517 | ||
|
|
23756074f9 | ||
|
|
40b12b9d07 | ||
|
|
e628f09122 | ||
|
|
7340e00dab | ||
|
|
958585336a | ||
|
|
68b7e4d678 | ||
|
|
857e4fc605 | ||
|
|
8d26194809 | ||
|
|
3063288d1e |
3
.github/FUNDING.yml
vendored
3
.github/FUNDING.yml
vendored
@@ -1,3 +0,0 @@
|
||||
github: offen
|
||||
patreon: offen
|
||||
|
||||
4
.github/workflows/deploy-docs.yml
vendored
4
.github/workflows/deploy-docs.yml
vendored
@@ -39,7 +39,7 @@ jobs:
|
||||
env:
|
||||
JEKYLL_ENV: production
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v1
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: 'docs/_site/'
|
||||
|
||||
@@ -52,4 +52,4 @@ jobs:
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v1
|
||||
uses: actions/deploy-pages@v4
|
||||
|
||||
@@ -76,7 +76,7 @@ docker run --rm \
|
||||
offen/docker-volume-backup:v2
|
||||
```
|
||||
|
||||
Alternatively, pass a `--env-file` in order to use a full config as described below.
|
||||
Alternatively, pass a `--env-file` in order to use a full config as described [in the docs](https://offen.github.io/docker-volume-backup/reference/).
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ type Config struct {
|
||||
BackupArchive string `split_words:"true" default:"/archive"`
|
||||
BackupCronExpression string `split_words:"true" default:"@daily"`
|
||||
BackupRetentionDays int32 `split_words:"true" default:"-1"`
|
||||
BackupRetentionPeriod time.Duration `split_words:"true"`
|
||||
BackupPruningLeeway time.Duration `split_words:"true" default:"1m"`
|
||||
BackupPruningPrefix string `split_words:"true"`
|
||||
BackupStopContainerLabel string `split_words:"true"`
|
||||
|
||||
@@ -17,11 +17,18 @@ import (
|
||||
// the given configuration. In case the given configuration would delete all
|
||||
// backups, it does nothing instead and logs a warning.
|
||||
func (s *script) pruneBackups() error {
|
||||
if s.c.BackupRetentionDays < 0 {
|
||||
if s.c.BackupRetentionDays < 0 && s.c.BackupRetentionPeriod == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
deadline := time.Now().AddDate(0, 0, -int(s.c.BackupRetentionDays)).Add(s.c.BackupPruningLeeway)
|
||||
var deadline time.Time
|
||||
if s.c.BackupRetentionPeriod != 0 {
|
||||
deadline = time.Now().Add(-s.c.BackupRetentionPeriod)
|
||||
} else {
|
||||
s.logger.Warn("Using BACKUP_RETENTION_DAYS has been deprecated and will be removed in the next major version. Please use BACKUP_RETENTION_PERIOD instead.")
|
||||
deadline = time.Now().AddDate(0, 0, -int(s.c.BackupRetentionDays))
|
||||
}
|
||||
deadline = deadline.Add(s.c.BackupPruningLeeway)
|
||||
|
||||
eg := errgroup.Group{}
|
||||
for _, backend := range s.storages {
|
||||
|
||||
@@ -225,6 +225,10 @@ func (s *script) init() error {
|
||||
s.storages = append(s.storages, dropboxBackend)
|
||||
}
|
||||
|
||||
if s.c.BackupRetentionDays > -1 && s.c.BackupRetentionPeriod > 0 {
|
||||
return errwrap.Wrap(nil, "both BACKUP_RETENTION_DAYS and BACKUP_RETENTION_PERIOD were configured, which are mutually exclusive")
|
||||
}
|
||||
|
||||
if s.c.EmailNotificationRecipient != "" {
|
||||
emailURL := fmt.Sprintf(
|
||||
"smtp://%s:%s@%s:%d/?from=%s&to=%s",
|
||||
|
||||
@@ -7,7 +7,8 @@ nav_order: 3
|
||||
|
||||
# Automatically prune old backups
|
||||
|
||||
When `BACKUP_RETENTION_DAYS` is configured, the command will check if there are any archives in the remote storage backend(s) or local archive that are older than the given retention value and rotate these backups away.
|
||||
When `BACKUP_RETENTION_PERIOD` is configured, the command will check if there are any archives in the remote storage backend(s) or local archive that are older than the given retention value and rotate these backups away.
|
||||
The value is a duration as per Go's [`time.ParseDuration`][duration].
|
||||
|
||||
{: .note }
|
||||
Be aware that this mechanism looks at __all files in the target bucket or archive__, which means that other files that are older than the given deadline are deleted as well.
|
||||
@@ -23,7 +24,7 @@ services:
|
||||
environment:
|
||||
BACKUP_FILENAME: backup-%Y-%m-%dT%H-%M-%S.tar.gz
|
||||
BACKUP_PRUNING_PREFIX: backup-
|
||||
BACKUP_RETENTION_DAYS: '7'
|
||||
BACKUP_RETENTION_PERIOD: '168h'
|
||||
volumes:
|
||||
- ${HOME}/backups:/archive
|
||||
- data:/backup/my-app-backup:ro
|
||||
@@ -32,3 +33,5 @@ services:
|
||||
volumes:
|
||||
data:
|
||||
```
|
||||
|
||||
[duration]: https://pkg.go.dev/time#ParseDuration
|
||||
|
||||
@@ -21,6 +21,10 @@ gpg -o backup.tar.gz -d backup.tar.gz.gpg
|
||||
|
||||
## Using age encryption
|
||||
|
||||
{: .note }
|
||||
Even though the `age` CLI tools supports encryption using SSH keys, this is not supported by this tool.
|
||||
`AGE_PUBLIC_KEYS` currently expects `age` keys to be given.
|
||||
|
||||
age allows backups to be encrypted with either a symmetric key (password) or a public key. One of those options are available for use.
|
||||
|
||||
Given `AGE_PASSPHRASE` being provided, the backup archive will be encrypted with the passphrase and saved as a `.age` file instead. Refer to age documentation for how to properly decrypt.
|
||||
|
||||
@@ -280,7 +280,7 @@ services:
|
||||
AWS_SECRET_ACCESS_KEY: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
|
||||
BACKUP_FILENAME: backup-%Y-%m-%dT%H-%M-%S.tar.gz
|
||||
BACKUP_PRUNING_PREFIX: backup-
|
||||
BACKUP_RETENTION_DAYS: 7
|
||||
BACKUP_RETENTION_PERIOD: 168h
|
||||
volumes:
|
||||
- data:/backup/my-app-backup:ro
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
|
||||
@@ -312,9 +312,10 @@ You can populate below template according to your requirements and use it as you
|
||||
# removal to certain files.
|
||||
|
||||
# Define this value to enable automatic rotation of old backups. The value
|
||||
# declares the number of days for which a backup is kept.
|
||||
# declares the duration for which a backup is kept. It is formatted as per
|
||||
# https://pkg.go.dev/time#ParseDuration, e.g. 1 day turns into `24h`
|
||||
|
||||
# BACKUP_RETENTION_DAYS="7"
|
||||
# BACKUP_RETENTION_PERIOD="168h"
|
||||
|
||||
# In case the duration a backup takes fluctuates noticeably in your setup
|
||||
# you can adjust this setting to make sure there are no race conditions
|
||||
@@ -337,6 +338,9 @@ You can populate below template according to your requirements and use it as you
|
||||
|
||||
########### BACKUP ENCRYPTION
|
||||
|
||||
# All of the encryption options are mutually exclusive. Provide a single option
|
||||
# for the encryption scheme of your choice.
|
||||
|
||||
# Backups can be encrypted symmetrically using gpg in case a passphrase is given.
|
||||
|
||||
# GPG_PASSPHRASE="<xxx>"
|
||||
@@ -350,6 +354,16 @@ You can populate below template according to your requirements and use it as you
|
||||
#...
|
||||
#-----END PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
# Backups can be encrypted symmetrically using age in case a passphrase is given.
|
||||
|
||||
# AGE_PASSPHRASE="<xxx>"
|
||||
|
||||
# Backups can be encrypted asymmetrically using age in case publickeys are given.
|
||||
# Multiple keys need to be provided as a comma separated list. Right now, this only
|
||||
# support passing age keys, with no support for ssh keys.
|
||||
|
||||
# AGE_PUBLIC_KEYS="<xxx>"
|
||||
|
||||
########### STOPPING CONTAINERS AND SERVICES DURING BACKUP
|
||||
|
||||
# Containers or services can be stopped by applying a
|
||||
|
||||
12
go.mod
12
go.mod
@@ -4,17 +4,17 @@ go 1.23
|
||||
|
||||
require (
|
||||
filippo.io/age v1.2.1
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.5.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.1
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.0
|
||||
github.com/containrrr/shoutrrr v0.8.0
|
||||
github.com/cosiner/argv v0.1.0
|
||||
github.com/docker/cli v27.4.1+incompatible
|
||||
github.com/docker/cli v27.5.1+incompatible
|
||||
github.com/docker/docker v27.1.1+incompatible
|
||||
github.com/gofrs/flock v0.12.1
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/klauspost/compress v1.17.11
|
||||
github.com/leekchan/timeutil v0.0.0-20150802142658-28917288c48d
|
||||
github.com/minio/minio-go/v7 v7.0.83
|
||||
github.com/minio/minio-go/v7 v7.0.84
|
||||
github.com/offen/envconfig v1.5.0
|
||||
github.com/otiai10/copy v1.14.1
|
||||
github.com/pkg/sftp v1.13.7
|
||||
@@ -52,9 +52,9 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2 // indirect
|
||||
github.com/Microsoft/go-winio v0.5.2 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.1.0-alpha.1
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
|
||||
36
go.sum
36
go.sum
@@ -35,24 +35,24 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
filippo.io/age v1.2.1 h1:X0TZjehAZylOIj4DubWYU1vWQxv9bJpo+Uu2/LGhi1o=
|
||||
filippo.io/age v1.2.1/go.mod h1:JL9ew2lTN+Pyft4RiNGguFfOpewKwSHm5ayKD/A4004=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 h1:JZg6HRh6W6U4OLl6lk7BZ7BLisIzM9dG1R50zUk9C/M=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0/go.mod h1:YL1xnZ6QejvQHWJrX/AvhFl4WW4rqHVoKspWNVwFk0M=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 h1:B/dfvscEQtew9dVuoxqxrUKKv8Ih2f55PydknDamU+g=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0/go.mod h1:fiPSssYvltE08HJchL04dOy+RD4hgrjph0cwGGMntdI=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0 h1:+m0M/LFxN43KvULkDNfdXOgrjtg6UYJPFBJyuEcRCAw=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0/go.mod h1:PwOyop78lveYMRs6oCxjiVyBdyCgIYH6XHIVZO9/SFQ=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 h1:g0EZJwz7xkXQiZAI5xi9f3WWFYBlX1CPTrR+NDToRkQ=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0/go.mod h1:XCW7KnZet0Opnr7HccfUw1PLc4CjHqpcaxW8DHklNkQ=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.1 h1:1mvYtZfWQAnwNah/C+Z+Jb9rQH95LPE2vlmMuWAHJk8=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.1/go.mod h1:75I/mXtme1JyWFtz8GocPHVFyH421IBoZErnO16dd0k=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.1 h1:Bk5uOhSAenHyR5P61D/NzeQCv+4fEVV8mOkJ82NqpWw=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.1/go.mod h1:QZ4pw3or1WPmRBxf0cHd1tknzrT54WPBOQoGutCPvSU=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0 h1:PiSrjRPpkQNjrM8H0WwKMnZUdu1RGMtd/LdGKUrOo+c=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0/go.mod h1:oDrbWx4ewMylP7xHivfgixbfGBT6APAwsSoHRKotnIc=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.5.0 h1:mlmW46Q0B79I+Aj4azKC6xDMFN9a9SyZWESlGWYXbFs=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.5.0/go.mod h1:PXe2h+LKcWTX9afWdZoHyODqR4fBa5boUM/8uJfZ0Jo=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.0 h1:UXT0o77lXQrikd1kgwIPQOUect7EoR/+sbP4wQKdzxM=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.0/go.mod h1:cTvi54pg19DoT07ekoeMgE/taAwNtCShVeZqA+Iv2xI=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM=
|
||||
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2 h1:kYRSnvJju5gYVyhkij+RTJ/VR6QIUaCfWeaFm2ycsjQ=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
|
||||
@@ -84,8 +84,8 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/docker/cli v27.4.1+incompatible h1:VzPiUlRJ/xh+otB75gva3r05isHMo5wXDfPRi5/b4hI=
|
||||
github.com/docker/cli v27.4.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/cli v27.5.1+incompatible h1:JB9cieUT9YNiMITtIsguaN55PLOHhBSz3LKVc6cqWaY=
|
||||
github.com/docker/cli v27.5.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/docker v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY=
|
||||
github.com/docker/docker v27.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
@@ -222,8 +222,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
|
||||
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
|
||||
github.com/minio/minio-go/v7 v7.0.83 h1:W4Kokksvlz3OKf3OqIlzDNKd4MERlC2oN8YptwJ0+GA=
|
||||
github.com/minio/minio-go/v7 v7.0.83/go.mod h1:57YXpvc5l3rjPdhqNrDsvVlY0qPI6UTk1bflAe+9doY=
|
||||
github.com/minio/minio-go/v7 v7.0.84 h1:D1HVmAF8JF8Bpi6IU4V9vIEj+8pc+xU88EWMs2yed0E=
|
||||
github.com/minio/minio-go/v7 v7.0.84/go.mod h1:57YXpvc5l3rjPdhqNrDsvVlY0qPI6UTk1bflAe+9doY=
|
||||
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||
github.com/moby/term v0.0.0-20200312100748-672ec06f55cd h1:aY7OQNf2XqY/JQ6qREWamhI/81os/agb2BAGpcx5yWI=
|
||||
@@ -254,8 +254,8 @@ github.com/pkg/sftp v1.13.7/go.mod h1:KMKI0t3T6hfA+lTR/ssZdunHo+uwq7ghoN09/FSu3D
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/redis/go-redis/v9 v9.6.1 h1:HHDteefn6ZkTtY5fGUE8tj8uy85AHk6zP7CpzIAM0y4=
|
||||
github.com/redis/go-redis/v9 v9.6.1/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA=
|
||||
github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E=
|
||||
github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw=
|
||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
@@ -276,8 +276,8 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/studio-b12/gowebdav v0.10.0 h1:Yewz8FFiadcGEu4hxS/AAJQlHelndqln1bns3hcJIYc=
|
||||
github.com/studio-b12/gowebdav v0.10.0/go.mod h1:bHA7t77X/QFExdeAnDzK6vKM34kEZAcE1OX4MfiwjkE=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
|
||||
@@ -6,7 +6,7 @@ services:
|
||||
BACKUP_CRON_EXPRESSION: 0 0 5 31 2 ?
|
||||
BACKUP_FILENAME: test.tar.gz
|
||||
BACKUP_LATEST_SYMLINK: test-latest.tar.gz.age
|
||||
BACKUP_RETENTION_DAYS: ${BACKUP_RETENTION_DAYS:-7}
|
||||
BACKUP_RETENTION_PERIOD: ${BACKUP_RETENTION_PERIOD:-168h}
|
||||
AGE_PASSPHRASE: "Dance.0Tonight.Go.Typical"
|
||||
volumes:
|
||||
- ${LOCAL_DIR:-./local}:/archive
|
||||
|
||||
@@ -6,7 +6,7 @@ services:
|
||||
BACKUP_CRON_EXPRESSION: 0 0 5 31 2 ?
|
||||
BACKUP_FILENAME: test.tar.gz
|
||||
BACKUP_LATEST_SYMLINK: test-latest.tar.gz.age
|
||||
BACKUP_RETENTION_DAYS: ${BACKUP_RETENTION_DAYS:-7}
|
||||
BACKUP_RETENTION_PERIOD: ${BACKUP_RETENTION_PERIOD:-168h}
|
||||
AGE_PUBLIC_KEYS: "${BACKUP_AGE_PUBLIC_KEYS}"
|
||||
volumes:
|
||||
- ${LOCAL_DIR:-./local}:/archive
|
||||
|
||||
@@ -37,7 +37,7 @@ services:
|
||||
AZURE_STORAGE_ACCESS_TIER: Hot
|
||||
BACKUP_FILENAME: test.tar.gz
|
||||
BACKUP_CRON_EXPRESSION: 0 0 5 31 2 ?
|
||||
BACKUP_RETENTION_DAYS: ${BACKUP_RETENTION_DAYS:-7}
|
||||
BACKUP_RETENTION_PERIOD: ${BACKUP_RETENTION_PERIOD:-168h}
|
||||
BACKUP_PRUNING_LEEWAY: 5s
|
||||
BACKUP_PRUNING_PREFIX: test
|
||||
volumes:
|
||||
|
||||
@@ -38,7 +38,7 @@ rm "$LOCAL_DIR/test.tar.gz"
|
||||
|
||||
# The second part of this test checks if backups get deleted when the retention
|
||||
# is set to 0 days (which it should not as it would mean all backups get deleted)
|
||||
BACKUP_RETENTION_DAYS="0" docker compose up -d
|
||||
BACKUP_RETENTION_PERIOD="1s" docker compose up -d
|
||||
sleep 5
|
||||
|
||||
docker compose exec backup backup
|
||||
@@ -52,7 +52,7 @@ pass "Remote backups have not been deleted."
|
||||
# The third part of this test checks if old backups get deleted when the retention
|
||||
# is set to 7 days (which it should)
|
||||
|
||||
BACKUP_RETENTION_DAYS="7" docker compose up -d
|
||||
BACKUP_RETENTION_PERIOD="168h" docker compose up -d
|
||||
sleep 5
|
||||
|
||||
info "Create first backup with no prune"
|
||||
|
||||
@@ -26,7 +26,7 @@ services:
|
||||
AWS_ENDPOINT_CA_CERT: /root/minio-rootCA.crt
|
||||
AWS_S3_BUCKET_NAME: backup
|
||||
BACKUP_CRON_EXPRESSION: 0 0 5 31 2 ?
|
||||
BACKUP_RETENTION_DAYS: ${BACKUP_RETENTION_DAYS:-7}
|
||||
BACKUP_RETENTION_PERIOD: ${BACKUP_RETENTION_PERIOD:-168h}
|
||||
BACKUP_PRUNING_LEEWAY: 5s
|
||||
volumes:
|
||||
- app_data:/backup/app_data:ro
|
||||
|
||||
@@ -30,7 +30,7 @@ services:
|
||||
BACKUP_FILENAME_EXPAND: 'true'
|
||||
BACKUP_FILENAME: test-$$HOSTNAME.tar.gz
|
||||
BACKUP_CRON_EXPRESSION: 0 0 5 31 2 ?
|
||||
BACKUP_RETENTION_DAYS: ${BACKUP_RETENTION_DAYS:-7}
|
||||
BACKUP_RETENTION_PERIOD: ${BACKUP_RETENTION_PERIOD:-168h}
|
||||
BACKUP_PRUNING_LEEWAY: 5s
|
||||
BACKUP_PRUNING_PREFIX: test
|
||||
DROPBOX_ENDPOINT: http://openapi_mock:8080
|
||||
|
||||
@@ -29,7 +29,7 @@ fi
|
||||
|
||||
# The second part of this test checks if backups get deleted when the retention
|
||||
# is set to 0 days (which it should not as it would mean all backups get deleted)
|
||||
BACKUP_RETENTION_DAYS="0" docker compose up -d
|
||||
BACKUP_RETENTION_PERIOD="1s" docker compose up -d
|
||||
sleep 5
|
||||
|
||||
logs=$(docker compose exec -T backup backup)
|
||||
@@ -43,7 +43,7 @@ fi
|
||||
|
||||
# The third part of this test checks if old backups get deleted when the retention
|
||||
# is set to 7 days (which it should)
|
||||
BACKUP_RETENTION_DAYS="7" docker compose up -d
|
||||
BACKUP_RETENTION_PERIOD="168h" docker compose up -d
|
||||
sleep 5
|
||||
|
||||
info "Create second backup and prune"
|
||||
|
||||
@@ -6,7 +6,7 @@ services:
|
||||
BACKUP_CRON_EXPRESSION: 0 0 5 31 2 ?
|
||||
BACKUP_FILENAME: test.tar.gz
|
||||
BACKUP_LATEST_SYMLINK: test-latest.tar.gz.gpg
|
||||
BACKUP_RETENTION_DAYS: ${BACKUP_RETENTION_DAYS:-7}
|
||||
BACKUP_RETENTION_PERIOD: ${BACKUP_RETENTION_PERIOD:-168h}
|
||||
GPG_PUBLIC_KEY_RING_FILE: /keys/public_key.asc
|
||||
volumes:
|
||||
- ${KEY_DIR:-.}/public_key.asc:/keys/public_key.asc
|
||||
|
||||
@@ -6,7 +6,7 @@ services:
|
||||
BACKUP_CRON_EXPRESSION: 0 0 5 31 2 ?
|
||||
BACKUP_FILENAME: test.tar.gz
|
||||
BACKUP_LATEST_SYMLINK: test-latest.tar.gz.gpg
|
||||
BACKUP_RETENTION_DAYS: ${BACKUP_RETENTION_DAYS:-7}
|
||||
BACKUP_RETENTION_PERIOD: ${BACKUP_RETENTION_PERIOD:-168h}
|
||||
GPG_PASSPHRASE: 1234#$$ecret
|
||||
volumes:
|
||||
- ${LOCAL_DIR:-./local}:/archive
|
||||
|
||||
@@ -8,7 +8,7 @@ services:
|
||||
BACKUP_FILENAME: test-$$HOSTNAME.tar.gz
|
||||
BACKUP_LATEST_SYMLINK: test-$$HOSTNAME.latest.tar.gz.gpg
|
||||
BACKUP_CRON_EXPRESSION: 0 0 5 31 2 ?
|
||||
BACKUP_RETENTION_DAYS: ${BACKUP_RETENTION_DAYS:-7}
|
||||
BACKUP_RETENTION_PERIOD: ${BACKUP_RETENTION_PERIOD:-168h}
|
||||
BACKUP_PRUNING_LEEWAY: 5s
|
||||
BACKUP_PRUNING_PREFIX: test
|
||||
volumes:
|
||||
|
||||
@@ -41,7 +41,7 @@ pass "Found symlink to latest version in local backup."
|
||||
|
||||
# The second part of this test checks if backups get deleted when the retention
|
||||
# is set to 0 days (which it should not as it would mean all backups get deleted)
|
||||
BACKUP_RETENTION_DAYS="0" docker compose up -d
|
||||
BACKUP_RETENTION_PERIOD="1s" docker compose up -d
|
||||
sleep 5
|
||||
|
||||
docker compose exec backup backup
|
||||
@@ -54,7 +54,7 @@ pass "Local backups have not been deleted."
|
||||
# The third part of this test checks if old backups get deleted when the retention
|
||||
# is set to 7 days (which it should)
|
||||
|
||||
BACKUP_RETENTION_DAYS="7" docker compose up -d
|
||||
BACKUP_RETENTION_PERIOD="168h" docker compose up -d
|
||||
sleep 5
|
||||
|
||||
info "Create first backup with no prune"
|
||||
|
||||
@@ -4,7 +4,7 @@ services:
|
||||
restart: always
|
||||
environment:
|
||||
BACKUP_CRON_EXPRESSION: 0 0 5 31 2 ?
|
||||
BACKUP_RETENTION_DAYS: '7'
|
||||
BACKUP_RETENTION_PERIOD: 168h
|
||||
volumes:
|
||||
- app_data:/backup/app_data:ro
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
|
||||
@@ -13,7 +13,7 @@ sleep 5
|
||||
|
||||
ec=0
|
||||
|
||||
docker compose exec -e BACKUP_RETENTION_DAYS=7 -e BACKUP_FILENAME=test.tar.gz backup backup & \
|
||||
docker compose exec -e BACKUP_RETENTION_PERIOD=168h -e BACKUP_FILENAME=test.tar.gz backup backup & \
|
||||
{ set +e; sleep 0.1; docker compose exec -e BACKUP_FILENAME=test2.tar.gz -e LOCK_TIMEOUT=1s backup backup; ec=$?;}
|
||||
|
||||
if [ "$ec" = "0" ]; then
|
||||
|
||||
@@ -25,7 +25,7 @@ services:
|
||||
BACKUP_FILENAME_EXPAND: 'true'
|
||||
BACKUP_FILENAME: test-$$HOSTNAME.tar.gz
|
||||
BACKUP_CRON_EXPRESSION: 0 0 5 31 2 ?
|
||||
BACKUP_RETENTION_DAYS: 7
|
||||
BACKUP_RETENTION_PERIOD: 168h
|
||||
BACKUP_PRUNING_LEEWAY: 5s
|
||||
BACKUP_PRUNING_PREFIX: test
|
||||
BACKUP_LATEST_SYMLINK: test-$$HOSTNAME.latest.tar.gz
|
||||
|
||||
22
test/retention/docker-compose.yml
Normal file
22
test/retention/docker-compose.yml
Normal file
@@ -0,0 +1,22 @@
|
||||
services:
|
||||
backup:
|
||||
image: offen/docker-volume-backup:${TEST_VERSION:-canary}
|
||||
restart: always
|
||||
environment:
|
||||
BACKUP_CRON_EXPRESSION: 0 0 5 31 2 ?
|
||||
BACKUP_RETENTION_PERIOD: 15s
|
||||
BACKUP_PRUNING_LEEWAY: 1s
|
||||
volumes:
|
||||
- app_data:/backup/app_data:ro
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- ${LOCAL_DIR:-./local}:/archive
|
||||
|
||||
offen:
|
||||
image: offen/offen:latest
|
||||
labels:
|
||||
- docker-volume-backup.stop-during-backup=true
|
||||
volumes:
|
||||
- app_data:/var/opt/offen
|
||||
|
||||
volumes:
|
||||
app_data:
|
||||
28
test/retention/run.sh
Executable file
28
test/retention/run.sh
Executable file
@@ -0,0 +1,28 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
. ../util.sh
|
||||
current_test=$(basename $(pwd))
|
||||
|
||||
export LOCAL_DIR=$(mktemp -d)
|
||||
|
||||
docker compose up -d --quiet-pull
|
||||
sleep 5
|
||||
|
||||
docker compose exec backup backup
|
||||
|
||||
sleep 20
|
||||
|
||||
if [ $(ls -1 $LOCAL_DIR | wc -l) != "1" ]; then
|
||||
fail "Unexpected number of backups after initial run"
|
||||
fi
|
||||
pass "Found 1 backup files."
|
||||
|
||||
docker compose exec backup backup
|
||||
|
||||
if [ $(ls -1 $LOCAL_DIR | wc -l) != "1" ]; then
|
||||
fail "Unexpected number of backups after initial run"
|
||||
fi
|
||||
pass "Found 1 backup files."
|
||||
@@ -25,7 +25,7 @@ services:
|
||||
BACKUP_FILENAME_EXPAND: 'true'
|
||||
BACKUP_FILENAME: test-$$HOSTNAME.tar.gz
|
||||
BACKUP_CRON_EXPRESSION: 0 0 5 31 2 ?
|
||||
BACKUP_RETENTION_DAYS: ${BACKUP_RETENTION_DAYS:-7}
|
||||
BACKUP_RETENTION_PERIOD: ${BACKUP_RETENTION_PERIOD:-168h}
|
||||
BACKUP_PRUNING_LEEWAY: 5s
|
||||
BACKUP_PRUNING_PREFIX: test
|
||||
volumes:
|
||||
|
||||
@@ -22,9 +22,11 @@ docker run --rm \
|
||||
|
||||
pass "Found relevant files in untared remote backups."
|
||||
|
||||
sleep 5
|
||||
|
||||
# The second part of this test checks if backups get deleted when the retention
|
||||
# is set to 0 days (which it should not as it would mean all backups get deleted)
|
||||
BACKUP_RETENTION_DAYS="0" docker compose up -d
|
||||
BACKUP_RETENTION_PERIOD="5s" docker compose up -d
|
||||
sleep 5
|
||||
|
||||
docker compose exec backup backup
|
||||
@@ -39,7 +41,7 @@ pass "Remote backups have not been deleted."
|
||||
# The third part of this test checks if old backups get deleted when the retention
|
||||
# is set to 7 days (which it should)
|
||||
|
||||
BACKUP_RETENTION_DAYS="7" docker compose up -d
|
||||
BACKUP_RETENTION_PERIOD="168h" docker compose up -d
|
||||
sleep 5
|
||||
|
||||
info "Create first backup with no prune"
|
||||
|
||||
@@ -31,7 +31,7 @@ services:
|
||||
AWS_S3_BUCKET_NAME: backup
|
||||
BACKUP_FILENAME: test.tar.gz
|
||||
BACKUP_CRON_EXPRESSION: 0 0 5 31 2 ?
|
||||
BACKUP_RETENTION_DAYS: 7
|
||||
BACKUP_RETENTION_PERIOD: 168h
|
||||
BACKUP_PRUNING_LEEWAY: 5s
|
||||
volumes:
|
||||
- pg_data:/backup/pg_data:ro
|
||||
|
||||
@@ -25,7 +25,7 @@ services:
|
||||
AWS_S3_BUCKET_NAME: backup
|
||||
BACKUP_FILENAME: test.tar.gz
|
||||
BACKUP_CRON_EXPRESSION: 0 0 5 31 2 ?
|
||||
BACKUP_RETENTION_DAYS: 7
|
||||
BACKUP_RETENTION_PERIOD: 168h
|
||||
BACKUP_PRUNING_LEEWAY: 5s
|
||||
volumes:
|
||||
- pg_data:/backup/pg_data:ro
|
||||
|
||||
@@ -19,7 +19,7 @@ services:
|
||||
BACKUP_FILENAME_EXPAND: 'true'
|
||||
BACKUP_FILENAME: test-$$HOSTNAME.tar.gz
|
||||
BACKUP_CRON_EXPRESSION: 0 0 5 31 2 ?
|
||||
BACKUP_RETENTION_DAYS: ${BACKUP_RETENTION_DAYS:-7}
|
||||
BACKUP_RETENTION_PERIOD: ${BACKUP_RETENTION_PERIOD:-168h}
|
||||
BACKUP_PRUNING_LEEWAY: 5s
|
||||
BACKUP_PRUNING_PREFIX: test
|
||||
SSH_HOST_NAME: ssh
|
||||
|
||||
@@ -28,7 +28,7 @@ pass "Found relevant files in decrypted and untared remote backups."
|
||||
|
||||
# The second part of this test checks if backups get deleted when the retention
|
||||
# is set to 0 days (which it should not as it would mean all backups get deleted)
|
||||
BACKUP_RETENTION_DAYS="0" docker compose up -d
|
||||
BACKUP_RETENTION_PERIOD="1s" docker compose up -d
|
||||
sleep 5
|
||||
|
||||
docker compose exec backup backup
|
||||
@@ -43,7 +43,7 @@ pass "Remote backups have not been deleted."
|
||||
# The third part of this test checks if old backups get deleted when the retention
|
||||
# is set to 7 days (which it should)
|
||||
|
||||
BACKUP_RETENTION_DAYS="7" docker compose up -d
|
||||
BACKUP_RETENTION_PERIOD="168h" docker compose up -d
|
||||
sleep 5
|
||||
|
||||
info "Create first backup with no prune"
|
||||
|
||||
@@ -31,7 +31,7 @@ services:
|
||||
AWS_S3_BUCKET_NAME: backup
|
||||
BACKUP_FILENAME: test.tar.gz
|
||||
BACKUP_CRON_EXPRESSION: 0 0 5 31 2 ?
|
||||
BACKUP_RETENTION_DAYS: 7
|
||||
BACKUP_RETENTION_PERIOD: 168h
|
||||
BACKUP_PRUNING_LEEWAY: 5s
|
||||
volumes:
|
||||
- pg_data:/backup/pg_data:ro
|
||||
|
||||
@@ -18,7 +18,7 @@ services:
|
||||
BACKUP_FILENAME_EXPAND: 'true'
|
||||
BACKUP_FILENAME: test-$$HOSTNAME.tar.gz
|
||||
BACKUP_CRON_EXPRESSION: 0 0 5 31 2 ?
|
||||
BACKUP_RETENTION_DAYS: ${BACKUP_RETENTION_DAYS:-7}
|
||||
BACKUP_RETENTION_PERIOD: ${BACKUP_RETENTION_PERIOD:-168h}
|
||||
BACKUP_PRUNING_LEEWAY: 5s
|
||||
BACKUP_PRUNING_PREFIX: test
|
||||
WEBDAV_URL: http://webdav/
|
||||
|
||||
@@ -24,7 +24,7 @@ pass "Found relevant files in untared remote backup."
|
||||
|
||||
# The second part of this test checks if backups get deleted when the retention
|
||||
# is set to 0 days (which it should not as it would mean all backups get deleted)
|
||||
BACKUP_RETENTION_DAYS="0" docker compose up -d
|
||||
BACKUP_RETENTION_PERIOD="1s" docker compose up -d
|
||||
sleep 5
|
||||
|
||||
docker compose exec backup backup
|
||||
@@ -39,7 +39,7 @@ pass "Remote backups have not been deleted."
|
||||
# The third part of this test checks if old backups get deleted when the retention
|
||||
# is set to 7 days (which it should)
|
||||
|
||||
BACKUP_RETENTION_DAYS="7" docker compose up -d
|
||||
BACKUP_RETENTION_PERIOD="168h" docker compose up -d
|
||||
sleep 5
|
||||
|
||||
info "Create first backup with no prune"
|
||||
|
||||
Reference in New Issue
Block a user