mirror of
https://github.com/offen/docker-volume-backup.git
synced 2026-04-10 19:45:35 +02:00
Consolidate config value resolution at top level (#705)
* Consolidate env expansion at top level * Move handling of deprecated config into resolve method * Handle template interpolation in resolve method * Clean up and document resolve function
This commit is contained in:
@@ -4,12 +4,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/offen/docker-volume-backup/internal/errwrap"
|
||||
@@ -225,3 +228,92 @@ func (c *Config) applyEnv() (func() error, error) {
|
||||
}
|
||||
return unset, nil
|
||||
}
|
||||
|
||||
// resolve is responsible for performing all implicit logic that transforms a configuration object
|
||||
// into what is actually being used at runtime. E.g. environment variables are expanded or
|
||||
// deprecated config options are transposed into their up to date successors. The caller is
|
||||
// responsible for calling the returned reset function after usage of the config is done.
|
||||
func (c *Config) resolve() (reset func() error, warnings []string, err error) {
|
||||
reset, aErr := c.applyEnv()
|
||||
if aErr != nil {
|
||||
err = errwrap.Wrap(aErr, "error applying env")
|
||||
return
|
||||
}
|
||||
|
||||
if c.BackupFilenameExpand {
|
||||
c.BackupFilename = os.ExpandEnv(c.BackupFilename)
|
||||
c.BackupLatestSymlink = os.ExpandEnv(c.BackupLatestSymlink)
|
||||
c.BackupPruningPrefix = os.ExpandEnv(c.BackupPruningPrefix)
|
||||
}
|
||||
|
||||
if c.EmailNotificationRecipient != "" {
|
||||
emailURL := fmt.Sprintf(
|
||||
"smtp://%s:%s@%s:%d/?from=%s&to=%s",
|
||||
c.EmailSMTPUsername,
|
||||
c.EmailSMTPPassword,
|
||||
c.EmailSMTPHost,
|
||||
c.EmailSMTPPort,
|
||||
c.EmailNotificationSender,
|
||||
c.EmailNotificationRecipient,
|
||||
)
|
||||
c.NotificationURLs = append(c.NotificationURLs, emailURL)
|
||||
warnings = append(warnings,
|
||||
"Using EMAIL_* keys for providing notification configuration has been deprecated and will be removed in the next major version.",
|
||||
"Please use NOTIFICATION_URLS instead. Refer to the README for an upgrade guide.",
|
||||
)
|
||||
}
|
||||
|
||||
if c.BackupFromSnapshot {
|
||||
warnings = append(warnings,
|
||||
"Using BACKUP_FROM_SNAPSHOT has been deprecated and will be removed in the next major version.",
|
||||
"Please use `archive-pre` and `archive-post` commands to prepare your backup sources. Refer to the documentation for an upgrade guide.",
|
||||
)
|
||||
}
|
||||
|
||||
if c.BackupStopDuringBackupLabel != "" && c.BackupStopContainerLabel != "" {
|
||||
err = errwrap.Wrap(nil, "both BACKUP_STOP_DURING_BACKUP_LABEL and BACKUP_STOP_CONTAINER_LABEL have been set, cannot continue")
|
||||
return
|
||||
}
|
||||
if c.BackupStopContainerLabel != "" {
|
||||
warnings = append(warnings,
|
||||
"Using BACKUP_STOP_CONTAINER_LABEL has been deprecated and will be removed in the next major version.",
|
||||
"Please use BACKUP_STOP_DURING_BACKUP_LABEL instead. Refer to the docs for an upgrade guide.",
|
||||
)
|
||||
c.BackupStopDuringBackupLabel = c.BackupStopContainerLabel
|
||||
}
|
||||
|
||||
tmplFileName, tErr := template.New("extension").Parse(c.BackupFilename)
|
||||
if tErr != nil {
|
||||
err = errwrap.Wrap(tErr, "unable to parse backup file extension template")
|
||||
return
|
||||
}
|
||||
|
||||
var bf bytes.Buffer
|
||||
if tErr := tmplFileName.Execute(&bf, map[string]string{
|
||||
"Extension": func() string {
|
||||
if c.BackupCompression == "none" {
|
||||
return "tar"
|
||||
}
|
||||
return fmt.Sprintf("tar.%s", c.BackupCompression)
|
||||
}(),
|
||||
}); tErr != nil {
|
||||
err = errwrap.Wrap(tErr, "error executing backup file extension template")
|
||||
return
|
||||
}
|
||||
c.BackupFilename = bf.String()
|
||||
|
||||
if c.AzureStorageEndpoint != "" {
|
||||
endpointTemplate, tErr := template.New("endpoint").Parse(c.AzureStorageEndpoint)
|
||||
if tErr != nil {
|
||||
err = errwrap.Wrap(tErr, "error parsing endpoint template")
|
||||
return
|
||||
}
|
||||
var ep bytes.Buffer
|
||||
if tErr := endpointTemplate.Execute(&ep, map[string]string{"AccountName": c.AzureStorageAccountName}); tErr != nil {
|
||||
err = errwrap.Wrap(tErr, "error executing endpoint template")
|
||||
return
|
||||
}
|
||||
c.AzureStorageEndpoint = fmt.Sprintf("%s/", strings.TrimSuffix(ep.String(), "/"))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -18,12 +18,6 @@ func (s *script) createArchive() error {
|
||||
backupSources := s.c.BackupSources
|
||||
|
||||
if s.c.BackupFromSnapshot {
|
||||
s.logger.Warn(
|
||||
"Using BACKUP_FROM_SNAPSHOT has been deprecated and will be removed in the next major version.",
|
||||
)
|
||||
s.logger.Warn(
|
||||
"Please use `archive-pre` and `archive-post` commands to prepare your backup sources. Refer to the documentation 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.
|
||||
s.registerHook(hookLevelPlumbing, func(error) error {
|
||||
|
||||
@@ -43,7 +43,7 @@ func runScript(c *Config) (err error) {
|
||||
}
|
||||
}()
|
||||
|
||||
unset, err := s.c.applyEnv()
|
||||
unset, warnings, err := s.c.resolve()
|
||||
if err != nil {
|
||||
return errwrap.Wrap(err, "error applying env")
|
||||
}
|
||||
@@ -52,6 +52,9 @@ func runScript(c *Config) (err error) {
|
||||
err = errors.Join(err, errwrap.Wrap(derr, "error unsetting environment variables"))
|
||||
}
|
||||
}()
|
||||
for _, w := range warnings {
|
||||
s.logger.Warn(w)
|
||||
}
|
||||
|
||||
if s.c != nil && s.c.BackupJitter > 0 {
|
||||
max := s.c.BackupJitter
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
@@ -79,24 +78,6 @@ func (s *script) init() error {
|
||||
return nil
|
||||
})
|
||||
// Register notifications first so they can fire in case of other init errors.
|
||||
if s.c.EmailNotificationRecipient != "" {
|
||||
emailURL := fmt.Sprintf(
|
||||
"smtp://%s:%s@%s:%d/?from=%s&to=%s",
|
||||
s.c.EmailSMTPUsername,
|
||||
s.c.EmailSMTPPassword,
|
||||
s.c.EmailSMTPHost,
|
||||
s.c.EmailSMTPPort,
|
||||
s.c.EmailNotificationSender,
|
||||
s.c.EmailNotificationRecipient,
|
||||
)
|
||||
s.c.NotificationURLs = append(s.c.NotificationURLs, emailURL)
|
||||
s.logger.Warn(
|
||||
"Using EMAIL_* keys for providing notification configuration has been deprecated and will be removed in the next major version.",
|
||||
)
|
||||
s.logger.Warn(
|
||||
"Please use NOTIFICATION_URLS instead. Refer to the README for an upgrade guide.",
|
||||
)
|
||||
}
|
||||
|
||||
hookLevel, ok := hookLevels[s.c.NotificationLevel]
|
||||
if !ok {
|
||||
@@ -143,30 +124,6 @@ func (s *script) init() error {
|
||||
}
|
||||
|
||||
s.file = path.Join("/tmp", s.c.BackupFilename)
|
||||
|
||||
tmplFileName, tErr := template.New("extension").Parse(s.file)
|
||||
if tErr != nil {
|
||||
return errwrap.Wrap(tErr, "unable to parse backup file extension template")
|
||||
}
|
||||
|
||||
var bf bytes.Buffer
|
||||
if tErr := tmplFileName.Execute(&bf, map[string]string{
|
||||
"Extension": func() string {
|
||||
if s.c.BackupCompression == "none" {
|
||||
return "tar"
|
||||
}
|
||||
return fmt.Sprintf("tar.%s", s.c.BackupCompression)
|
||||
}(),
|
||||
}); tErr != nil {
|
||||
return errwrap.Wrap(tErr, "error executing backup file extension template")
|
||||
}
|
||||
s.file = bf.String()
|
||||
|
||||
if s.c.BackupFilenameExpand {
|
||||
s.file = os.ExpandEnv(s.file)
|
||||
s.c.BackupLatestSymlink = os.ExpandEnv(s.c.BackupLatestSymlink)
|
||||
s.c.BackupPruningPrefix = os.ExpandEnv(s.c.BackupPruningPrefix)
|
||||
}
|
||||
s.file = timeutil.Strftime(&s.stats.StartTime, s.file)
|
||||
|
||||
_, err := os.Stat("/var/run/docker.sock")
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -113,23 +112,9 @@ func (s *script) stopContainersAndServices() (func() error, error) {
|
||||
return noop, errwrap.Wrap(err, "error determining swarm state")
|
||||
}
|
||||
|
||||
labelValue := s.c.BackupStopDuringBackupLabel
|
||||
if s.c.BackupStopContainerLabel != "" {
|
||||
s.logger.Warn(
|
||||
"Using BACKUP_STOP_CONTAINER_LABEL has been deprecated and will be removed in the next major version.",
|
||||
)
|
||||
s.logger.Warn(
|
||||
"Please use BACKUP_STOP_DURING_BACKUP_LABEL instead. Refer to the docs for an upgrade guide.",
|
||||
)
|
||||
if _, ok := os.LookupEnv("BACKUP_STOP_DURING_BACKUP_LABEL"); ok {
|
||||
return noop, errwrap.Wrap(nil, "both BACKUP_STOP_DURING_BACKUP_LABEL and BACKUP_STOP_CONTAINER_LABEL have been set, cannot continue")
|
||||
}
|
||||
labelValue = s.c.BackupStopContainerLabel
|
||||
}
|
||||
|
||||
stopDuringBackupLabel := fmt.Sprintf(
|
||||
"docker-volume-backup.stop-during-backup=%s",
|
||||
labelValue,
|
||||
s.c.BackupStopDuringBackupLabel,
|
||||
)
|
||||
|
||||
stopDuringBackupNoRestartLabel := fmt.Sprintf(
|
||||
@@ -144,7 +129,7 @@ func (s *script) stopContainersAndServices() (func() error, error) {
|
||||
|
||||
var containersToStop []handledContainer
|
||||
for _, c := range allContainers.Items {
|
||||
hasStopDuringBackupLabel, hasStopDuringBackupNoRestartLabel, err := checkStopLabels(c.Labels, labelValue, s.c.BackupStopDuringBackupNoRestartLabel)
|
||||
hasStopDuringBackupLabel, hasStopDuringBackupNoRestartLabel, err := checkStopLabels(c.Labels, s.c.BackupStopDuringBackupLabel, s.c.BackupStopDuringBackupNoRestartLabel)
|
||||
if err != nil {
|
||||
return noop, errwrap.Wrap(err, "error querying for containers to stop")
|
||||
}
|
||||
@@ -169,7 +154,7 @@ func (s *script) stopContainersAndServices() (func() error, error) {
|
||||
}
|
||||
|
||||
for _, service := range allServices {
|
||||
hasStopDuringBackupLabel, hasStopDuringBackupNoRestartLabel, err := checkStopLabels(service.Spec.Labels, labelValue, s.c.BackupStopDuringBackupNoRestartLabel)
|
||||
hasStopDuringBackupLabel, hasStopDuringBackupNoRestartLabel, err := checkStopLabels(service.Spec.Labels, s.c.BackupStopDuringBackupLabel, s.c.BackupStopDuringBackupNoRestartLabel)
|
||||
if err != nil {
|
||||
return noop, errwrap.Wrap(err, "error querying for services to scale down")
|
||||
}
|
||||
|
||||
@@ -4,16 +4,13 @@
|
||||
package azure
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
|
||||
@@ -49,16 +46,6 @@ func NewStorageBackend(opts Config, logFunc storage.Log) (storage.Backend, error
|
||||
return nil, errwrap.Wrap(nil, "using primary account key and connection string are mutually exclusive")
|
||||
}
|
||||
|
||||
endpointTemplate, err := template.New("endpoint").Parse(opts.Endpoint)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrap(err, "error parsing endpoint template")
|
||||
}
|
||||
var ep bytes.Buffer
|
||||
if err := endpointTemplate.Execute(&ep, opts); err != nil {
|
||||
return nil, errwrap.Wrap(err, "error executing endpoint template")
|
||||
}
|
||||
normalizedEndpoint := fmt.Sprintf("%s/", strings.TrimSuffix(ep.String(), "/"))
|
||||
|
||||
var client *azblob.Client
|
||||
if opts.PrimaryAccountKey != "" {
|
||||
cred, err := azblob.NewSharedKeyCredential(opts.AccountName, opts.PrimaryAccountKey)
|
||||
@@ -66,11 +53,12 @@ func NewStorageBackend(opts Config, logFunc storage.Log) (storage.Backend, error
|
||||
return nil, errwrap.Wrap(err, "error creating shared key Azure credential")
|
||||
}
|
||||
|
||||
client, err = azblob.NewClientWithSharedKeyCredential(normalizedEndpoint, cred, nil)
|
||||
client, err = azblob.NewClientWithSharedKeyCredential(opts.Endpoint, cred, nil)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrap(err, "error creating azure client from primary account key")
|
||||
}
|
||||
} else if opts.ConnectionString != "" {
|
||||
var err error
|
||||
client, err = azblob.NewClientFromConnectionString(opts.ConnectionString, nil)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrap(err, "error creating azure client from connection string")
|
||||
@@ -80,7 +68,7 @@ func NewStorageBackend(opts Config, logFunc storage.Log) (storage.Backend, error
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrap(err, "error creating managed identity credential")
|
||||
}
|
||||
client, err = azblob.NewClient(normalizedEndpoint, cred, nil)
|
||||
client, err = azblob.NewClient(opts.Endpoint, cred, nil)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrap(err, "error creating azure client from managed identity")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user