mirror of
https://github.com/offen/docker-volume-backup.git
synced 2025-12-05 17:18:02 +01:00
Compare commits
2 Commits
v2.16.0
...
header-for
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8caac8724c | ||
|
|
9eda23e512 |
25
README.md
25
README.md
@@ -207,9 +207,9 @@ You can populate below template according to your requirements and use it as you
|
|||||||
# AWS_ENDPOINT_PROTO="https"
|
# AWS_ENDPOINT_PROTO="https"
|
||||||
|
|
||||||
# Setting this variable to `true` will disable verification of
|
# Setting this variable to `true` will disable verification of
|
||||||
# SSL certificates for AWS_ENDPOINT. You shouldn't use this unless you use
|
# SSL certificates. You shouldn't use this unless you use self-signed
|
||||||
# self-signed certificates for your remote storage backend. This can only be
|
# certificates for your remote storage backend. This can only be used
|
||||||
# used when AWS_ENDPOINT_PROTO is set to `https`.
|
# when AWS_ENDPOINT_PROTO is set to `https`.
|
||||||
|
|
||||||
# AWS_ENDPOINT_INSECURE="true"
|
# AWS_ENDPOINT_INSECURE="true"
|
||||||
|
|
||||||
@@ -232,12 +232,6 @@ You can populate below template according to your requirements and use it as you
|
|||||||
|
|
||||||
# WEBDAV_PASSWORD="password"
|
# WEBDAV_PASSWORD="password"
|
||||||
|
|
||||||
# Setting this variable to `true` will disable verification of
|
|
||||||
# SSL certificates for WEBDAV_URL. You shouldn't use this unless you use
|
|
||||||
# self-signed certificates for your remote storage backend.
|
|
||||||
|
|
||||||
# WEBDAV_URL_INSECURE="true"
|
|
||||||
|
|
||||||
# In addition to storing backups remotely, you can also keep local copies.
|
# In addition to storing backups remotely, you can also keep local copies.
|
||||||
# Pass a container-local path to store your backups if needed. You also need to
|
# Pass a container-local path to store your backups if needed. You also need to
|
||||||
# mount a local folder or Docker volume into that location (`/archive`
|
# mount a local folder or Docker volume into that location (`/archive`
|
||||||
@@ -357,6 +351,19 @@ You can populate below template according to your requirements and use it as you
|
|||||||
|
|
||||||
# LOCK_TIMEOUT="60m"
|
# LOCK_TIMEOUT="60m"
|
||||||
|
|
||||||
|
########### HEADER FORMAT USED BY THE TAR ARCHIVE
|
||||||
|
|
||||||
|
# By default, tar archive creation will pick a header format that is appropriate
|
||||||
|
# for the archive's contents. In case you have special requirements or need to
|
||||||
|
# work with tools that do not support all standard header formats, you can use
|
||||||
|
# this option to enforce a certain header format. Valid options are "USTAR",
|
||||||
|
# "PAX" and "GNU". Be aware that setting this value might create situations where
|
||||||
|
# it's not possible to encode the information about a certain file, making the
|
||||||
|
# backup fail.
|
||||||
|
# In case no value is set, an appropriate format will be selected for each file.
|
||||||
|
|
||||||
|
# TAR_ARCHIVE_HEADER_FORMAT="USTAR"
|
||||||
|
|
||||||
########### EMAIL NOTIFICATIONS
|
########### EMAIL NOTIFICATIONS
|
||||||
|
|
||||||
# ************************************************************************
|
# ************************************************************************
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func createArchive(inputFilePath, outputFilePath string) error {
|
func createArchive(inputFilePath, outputFilePath string, options createArchiveOptions) error {
|
||||||
inputFilePath = stripTrailingSlashes(inputFilePath)
|
inputFilePath = stripTrailingSlashes(inputFilePath)
|
||||||
inputFilePath, outputFilePath, err := makeAbsolute(inputFilePath, outputFilePath)
|
inputFilePath, outputFilePath, err := makeAbsolute(inputFilePath, outputFilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -28,7 +28,7 @@ func createArchive(inputFilePath, outputFilePath string) error {
|
|||||||
return fmt.Errorf("createArchive: error creating output file path: %w", err)
|
return fmt.Errorf("createArchive: error creating output file path: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := compress(inputFilePath, outputFilePath, filepath.Dir(inputFilePath)); err != nil {
|
if err := compress(inputFilePath, outputFilePath, filepath.Dir(inputFilePath), options); err != nil {
|
||||||
return fmt.Errorf("createArchive: error creating archive: %w", err)
|
return fmt.Errorf("createArchive: error creating archive: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ func makeAbsolute(inputFilePath, outputFilePath string) (string, string, error)
|
|||||||
return inputFilePath, outputFilePath, err
|
return inputFilePath, outputFilePath, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func compress(inPath, outFilePath, subPath string) error {
|
func compress(inPath, outFilePath, subPath string, options createArchiveOptions) error {
|
||||||
file, err := os.Create(outFilePath)
|
file, err := os.Create(outFilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("compress: error creating out file: %w", err)
|
return fmt.Errorf("compress: error creating out file: %w", err)
|
||||||
@@ -71,7 +71,7 @@ func compress(inPath, outFilePath, subPath string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, p := range paths {
|
for _, p := range paths {
|
||||||
if err := writeTarGz(p, tarWriter, prefix); err != nil {
|
if err := writeTarGz(p, tarWriter, prefix, options.format); err != nil {
|
||||||
return fmt.Errorf("compress error writing %s to archive: %w", p, err)
|
return fmt.Errorf("compress error writing %s to archive: %w", p, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -94,7 +94,7 @@ func compress(inPath, outFilePath, subPath string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeTarGz(path string, tarWriter *tar.Writer, prefix string) error {
|
func writeTarGz(path string, tarWriter *tar.Writer, prefix string, format tar.Format) error {
|
||||||
fileInfo, err := os.Lstat(path)
|
fileInfo, err := os.Lstat(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("writeTarGz: error getting file infor for %s: %w", path, err)
|
return fmt.Errorf("writeTarGz: error getting file infor for %s: %w", path, err)
|
||||||
@@ -113,6 +113,10 @@ func writeTarGz(path string, tarWriter *tar.Writer, prefix string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
header, err := tar.FileInfoHeader(fileInfo, link)
|
header, err := tar.FileInfoHeader(fileInfo, link)
|
||||||
|
if format >= 0 {
|
||||||
|
header.Format = format
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("writeTarGz: error getting file info header: %w", err)
|
return fmt.Errorf("writeTarGz: error getting file info header: %w", err)
|
||||||
}
|
}
|
||||||
@@ -140,3 +144,7 @@ func writeTarGz(path string, tarWriter *tar.Writer, prefix string) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type createArchiveOptions struct {
|
||||||
|
format tar.Format
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,7 +3,11 @@
|
|||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"archive/tar"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
// Config holds all configuration values that are expected to be set
|
// Config holds all configuration values that are expected to be set
|
||||||
// by users.
|
// by users.
|
||||||
@@ -36,11 +40,36 @@ type Config struct {
|
|||||||
EmailSMTPUsername string `envconfig:"EMAIL_SMTP_USERNAME"`
|
EmailSMTPUsername string `envconfig:"EMAIL_SMTP_USERNAME"`
|
||||||
EmailSMTPPassword string `envconfig:"EMAIL_SMTP_PASSWORD"`
|
EmailSMTPPassword string `envconfig:"EMAIL_SMTP_PASSWORD"`
|
||||||
WebdavUrl string `split_words:"true"`
|
WebdavUrl string `split_words:"true"`
|
||||||
WebdavUrlInsecure bool `split_words:"true"`
|
|
||||||
WebdavPath string `split_words:"true" default:"/"`
|
WebdavPath string `split_words:"true" default:"/"`
|
||||||
WebdavUsername string `split_words:"true"`
|
WebdavUsername string `split_words:"true"`
|
||||||
WebdavPassword string `split_words:"true"`
|
WebdavPassword string `split_words:"true"`
|
||||||
ExecLabel string `split_words:"true"`
|
ExecLabel string `split_words:"true"`
|
||||||
ExecForwardOutput bool `split_words:"true"`
|
ExecForwardOutput bool `split_words:"true"`
|
||||||
LockTimeout time.Duration `split_words:"true" default:"60m"`
|
LockTimeout time.Duration `split_words:"true" default:"60m"`
|
||||||
|
TarArchiveHeaderFormat TarFormat `split_words:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TarFormat tar.Format
|
||||||
|
|
||||||
|
func (t *TarFormat) Decode(value string) error {
|
||||||
|
switch value {
|
||||||
|
case "PAX":
|
||||||
|
*t = TarFormat(tar.FormatPAX)
|
||||||
|
return nil
|
||||||
|
case "USTAR":
|
||||||
|
*t = TarFormat(tar.FormatUSTAR)
|
||||||
|
return nil
|
||||||
|
case "GNU":
|
||||||
|
*t = TarFormat(tar.FormatGNU)
|
||||||
|
return nil
|
||||||
|
case "":
|
||||||
|
*t = TarFormat(-1)
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("tarFormat: unknown format %s", value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TarFormat) Format() tar.Format {
|
||||||
|
return tar.Format(*t)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"net/http"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -147,15 +146,6 @@ func newScript() (*script, error) {
|
|||||||
} else {
|
} else {
|
||||||
webdavClient := gowebdav.NewClient(s.c.WebdavUrl, s.c.WebdavUsername, s.c.WebdavPassword)
|
webdavClient := gowebdav.NewClient(s.c.WebdavUrl, s.c.WebdavUsername, s.c.WebdavPassword)
|
||||||
s.webdavClient = webdavClient
|
s.webdavClient = webdavClient
|
||||||
if s.c.WebdavUrlInsecure {
|
|
||||||
defaultTransport, ok := http.DefaultTransport.(*http.Transport)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("newScript: unexpected error when asserting type for http.DefaultTransport")
|
|
||||||
}
|
|
||||||
webdavTransport := defaultTransport.Clone()
|
|
||||||
webdavTransport.TLSClientConfig.InsecureSkipVerify = s.c.WebdavUrlInsecure
|
|
||||||
s.webdavClient.SetTransport(webdavTransport)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -398,7 +388,9 @@ func (s *script) takeBackup() error {
|
|||||||
s.logger.Infof("Removed tar file `%s`.", tarFile)
|
s.logger.Infof("Removed tar file `%s`.", tarFile)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err := createArchive(backupSources, tarFile); err != nil {
|
if err := createArchive(backupSources, tarFile, createArchiveOptions{
|
||||||
|
format: s.c.TarArchiveHeaderFormat.Format(),
|
||||||
|
}); err != nil {
|
||||||
return fmt.Errorf("takeBackup: error compressing backup folder: %w", err)
|
return fmt.Errorf("takeBackup: error compressing backup folder: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -12,7 +12,7 @@ require (
|
|||||||
github.com/minio/minio-go/v7 v7.0.16
|
github.com/minio/minio-go/v7 v7.0.16
|
||||||
github.com/otiai10/copy v1.7.0
|
github.com/otiai10/copy v1.7.0
|
||||||
github.com/sirupsen/logrus v1.8.1
|
github.com/sirupsen/logrus v1.8.1
|
||||||
github.com/studio-b12/gowebdav v0.0.0-20220128162035-c7b1ff8a5e62
|
github.com/studio-b12/gowebdav v0.0.0-20211109083228-3f8721cd4b6f
|
||||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
|
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||||
)
|
)
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -660,8 +660,6 @@ github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd
|
|||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/studio-b12/gowebdav v0.0.0-20211109083228-3f8721cd4b6f h1:L2NE7BXnSlSLoNYZ0lCwZDjdnYjCNYC71k9ClZUTFTs=
|
github.com/studio-b12/gowebdav v0.0.0-20211109083228-3f8721cd4b6f h1:L2NE7BXnSlSLoNYZ0lCwZDjdnYjCNYC71k9ClZUTFTs=
|
||||||
github.com/studio-b12/gowebdav v0.0.0-20211109083228-3f8721cd4b6f/go.mod h1:bHA7t77X/QFExdeAnDzK6vKM34kEZAcE1OX4MfiwjkE=
|
github.com/studio-b12/gowebdav v0.0.0-20211109083228-3f8721cd4b6f/go.mod h1:bHA7t77X/QFExdeAnDzK6vKM34kEZAcE1OX4MfiwjkE=
|
||||||
github.com/studio-b12/gowebdav v0.0.0-20220128162035-c7b1ff8a5e62 h1:b2nJXyPCa9HY7giGM+kYcnQ71m14JnGdQabMPmyt++8=
|
|
||||||
github.com/studio-b12/gowebdav v0.0.0-20220128162035-c7b1ff8a5e62/go.mod h1:bHA7t77X/QFExdeAnDzK6vKM34kEZAcE1OX4MfiwjkE=
|
|
||||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||||
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||||
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ services:
|
|||||||
BACKUP_PRUNING_PREFIX: test
|
BACKUP_PRUNING_PREFIX: test
|
||||||
GPG_PASSPHRASE: 1234secret
|
GPG_PASSPHRASE: 1234secret
|
||||||
WEBDAV_URL: http://webdav/
|
WEBDAV_URL: http://webdav/
|
||||||
WEBDAV_URL_INSECURE: 'true'
|
|
||||||
WEBDAV_PATH: /my/new/path/
|
WEBDAV_PATH: /my/new/path/
|
||||||
WEBDAV_USERNAME: test
|
WEBDAV_USERNAME: test
|
||||||
WEBDAV_PASSWORD: test
|
WEBDAV_PASSWORD: test
|
||||||
|
|||||||
Reference in New Issue
Block a user