read all configuration in init

This commit is contained in:
Frederik Ring 2021-08-22 22:02:19 +02:00
parent 4c80494433
commit 07b06cf0ba

View File

@ -44,16 +44,22 @@ func main() {
} }
type script struct { type script struct {
ctx context.Context ctx context.Context
cli *client.Client cli *client.Client
mc *minio.Client mc *minio.Client
logger *logrus.Logger logger *logrus.Logger
file string
bucket string start time.Time
archive string
sources string file string
passphrase string bucket string
now time.Time archive string
sources string
passphrase []byte
retentionDays *int
leeway *time.Duration
containerLabel string
pruningPrefix string
} }
// lock opens a lockfile at the given location, keeping it locked until the // lock opens a lockfile at the given location, keeping it locked until the
@ -118,9 +124,27 @@ func (s *script) init() error {
s.file = path.Join("/tmp", file) s.file = path.Join("/tmp", file)
s.archive = os.Getenv("BACKUP_ARCHIVE") s.archive = os.Getenv("BACKUP_ARCHIVE")
s.sources = os.Getenv("BACKUP_SOURCES") s.sources = os.Getenv("BACKUP_SOURCES")
s.passphrase = os.Getenv("GPG_PASSPHRASE") if v := os.Getenv("GPG_PASSPHRASE"); v != "" {
s.passphrase = []byte(v)
}
if v := os.Getenv("BACKUP_RETENTION_DAYS"); v != "" {
i, err := strconv.Atoi(v)
if err != nil {
return fmt.Errorf("init: error parsing BACKUP_RETENTION_DAYS as int: %w", err)
}
s.retentionDays = &i
}
if v := os.Getenv("BACKUP_PRUNING_LEEWAY"); v != "" {
d, err := time.ParseDuration(v)
if err != nil {
return fmt.Errorf("init: error parsing BACKUP_PRUNING_LEEWAY as duration: %w", err)
}
s.leeway = &d
}
s.containerLabel = os.Getenv("BACKUP_STOP_CONTAINER_LABEL")
s.pruningPrefix = os.Getenv("BACKUP_PRUNING_PREFIX")
s.start = time.Now()
s.now = time.Now()
return nil return nil
} }
@ -140,7 +164,7 @@ func (s *script) stopContainersAndRun(thunk func() error) error {
containerLabel := fmt.Sprintf( containerLabel := fmt.Sprintf(
"docker-volume-backup.stop-during-backup=%s", "docker-volume-backup.stop-during-backup=%s",
os.Getenv("BACKUP_STOP_CONTAINER_LABEL"), s.containerLabel,
) )
containersToStop, err := s.cli.ContainerList(s.ctx, types.ContainerListOptions{ containersToStop, err := s.cli.ContainerList(s.ctx, types.ContainerListOptions{
Quiet: true, Quiet: true,
@ -154,7 +178,7 @@ func (s *script) stopContainersAndRun(thunk func() error) error {
return fmt.Errorf("stopContainersAndRun: error querying for containers to stop: %w", err) return fmt.Errorf("stopContainersAndRun: error querying for containers to stop: %w", err)
} }
s.logger.Infof( s.logger.Infof(
"Stopping %d containers labeled `%s` out of %d running containers.", "Stopping %d containers labeled `%s` out of %d running container(s).",
len(containersToStop), len(containersToStop),
containerLabel, containerLabel,
len(allContainers), len(allContainers),
@ -217,7 +241,7 @@ func (s *script) stopContainersAndRun(thunk func() error) error {
err, err,
) )
} }
s.logger.Infof("Successfully restarted %d containers.", len(stoppedContainers)) s.logger.Infof("Successfully restarted %d container(s) and the matching service(s).", len(stoppedContainers))
return nil return nil
}() }()
@ -239,7 +263,7 @@ func (s *script) stopContainersAndRun(thunk func() error) error {
// takeBackup creates a tar archive of the configured backup location and // takeBackup creates a tar archive of the configured backup location and
// saves it to disk. // saves it to disk.
func (s *script) takeBackup() error { func (s *script) takeBackup() error {
s.file = timeutil.Strftime(&s.now, s.file) s.file = timeutil.Strftime(&s.start, s.file)
if err := targz.Compress(s.sources, s.file); err != nil { if err := targz.Compress(s.sources, s.file); err != nil {
return fmt.Errorf("takeBackup: error compressing backup folder: %w", err) return fmt.Errorf("takeBackup: error compressing backup folder: %w", err)
} }
@ -251,7 +275,7 @@ func (s *script) takeBackup() error {
// In case no passphrase is given it returns early, leaving the backup file // In case no passphrase is given it returns early, leaving the backup file
// untouched. // untouched.
func (s *script) encryptBackup() error { func (s *script) encryptBackup() error {
if s.passphrase == "" { if s.passphrase == nil {
return nil return nil
} }
@ -285,6 +309,7 @@ func (s *script) encryptBackup() error {
if err := os.Remove(s.file); err != nil { if err := os.Remove(s.file); err != nil {
return fmt.Errorf("encryptBackup: error removing unencrpyted backup: %w", err) return fmt.Errorf("encryptBackup: error removing unencrpyted backup: %w", err)
} }
s.file = gpgFile s.file = gpgFile
s.logger.Infof("Successfully encrypted backup using given passphrase, saving as `%s`.", s.file) s.logger.Infof("Successfully encrypted backup using given passphrase, saving as `%s`.", s.file)
return nil return nil
@ -326,29 +351,22 @@ func (s *script) cleanBackup() error {
// the given configuration. In case the given configuration would delete all // the given configuration. In case the given configuration would delete all
// backups, it does nothing instead. // backups, it does nothing instead.
func (s *script) pruneOldBackups() error { func (s *script) pruneOldBackups() error {
retention := os.Getenv("BACKUP_RETENTION_DAYS") if s.retentionDays == nil {
if retention == "" {
return nil return nil
} }
retentionDays, err := strconv.Atoi(retention)
if err != nil {
return fmt.Errorf("pruneOldBackups: error parsing BACKUP_RETENTION_DAYS as int: %w", err)
}
leeway := os.Getenv("BACKUP_PRUNING_LEEWAY")
sleepFor, err := time.ParseDuration(leeway)
if err != nil {
return fmt.Errorf("pruneBackups: error parsing given leeway value: %w", err)
}
s.logger.Infof("Sleeping for %s before pruning backups.", leeway)
time.Sleep(sleepFor)
s.logger.Infof("Trying to prune backups older than %d days now.", retentionDays) if s.leeway != nil {
deadline := s.now.AddDate(0, 0, -retentionDays) s.logger.Infof("Sleeping for %s before pruning backups.", s.leeway)
time.Sleep(*s.leeway)
}
s.logger.Infof("Trying to prune backups older than %d day(s) now.", *s.retentionDays)
deadline := s.start.AddDate(0, 0, -*s.retentionDays)
if s.bucket != "" { if s.bucket != "" {
candidates := s.mc.ListObjects(s.ctx, s.bucket, minio.ListObjectsOptions{ candidates := s.mc.ListObjects(s.ctx, s.bucket, minio.ListObjectsOptions{
WithMetadata: true, WithMetadata: true,
Prefix: os.Getenv("BACKUP_PRUNING_PREFIX"), Prefix: s.pruningPrefix,
}) })
var matches []minio.ObjectInfo var matches []minio.ObjectInfo
@ -381,13 +399,13 @@ func (s *script) pruneOldBackups() error {
if len(errors) != 0 { if len(errors) != 0 {
return fmt.Errorf( return fmt.Errorf(
"pruneOldBackups: %d errors removing files from remote storage: %w", "pruneOldBackups: %d error(s) removing files from remote storage: %w",
len(errors), len(errors),
errors[0], errors[0],
) )
} }
s.logger.Infof( s.logger.Infof(
"Successfully pruned %d out of %d remote backups as their age exceeded the configured retention period.", "Successfully pruned %d out of %d remote backup(s) as their age exceeded the configured retention period.",
len(matches), len(matches),
lenCandidates, lenCandidates,
) )
@ -397,13 +415,13 @@ func (s *script) pruneOldBackups() error {
len(matches), len(matches),
) )
} else { } else {
s.logger.Infof("None of %d remote backups were pruned.", lenCandidates) s.logger.Infof("None of %d remote backup(s) were pruned.", lenCandidates)
} }
} }
if _, err := os.Stat(s.archive); !os.IsNotExist(err) { if _, err := os.Stat(s.archive); !os.IsNotExist(err) {
candidates, err := filepath.Glob( candidates, err := filepath.Glob(
path.Join(s.archive, fmt.Sprintf("%s*", os.Getenv("BACKUP_PRUNING_PREFIX"))), path.Join(s.archive, fmt.Sprintf("%s*", s.pruningPrefix)),
) )
if err != nil { if err != nil {
return fmt.Errorf( return fmt.Errorf(
@ -436,13 +454,13 @@ func (s *script) pruneOldBackups() error {
} }
if len(errors) != 0 { if len(errors) != 0 {
return fmt.Errorf( return fmt.Errorf(
"pruneOldBackups: %d errors deleting local files, starting with: %w", "pruneOldBackups: %d error(s) deleting local files, starting with: %w",
len(errors), len(errors),
errors[0], errors[0],
) )
} }
s.logger.Infof( s.logger.Infof(
"Successfully pruned %d out of %d local backups as their age exceeded the configured retention period.", "Successfully pruned %d out of %d local backup(s) as their age exceeded the configured retention period.",
len(matches), len(matches),
len(candidates), len(candidates),
) )
@ -452,7 +470,7 @@ func (s *script) pruneOldBackups() error {
len(matches), len(matches),
) )
} else { } else {
s.logger.Infof("None of %d local backups were pruned.", len(candidates)) s.logger.Infof("None of %d local backup(s) were pruned.", len(candidates))
} }
} }
return nil return nil