diff --git a/cmd/manager/manager.go b/cmd/manager/manager.go index 00b5a11e..fa7cd1b9 100644 --- a/cmd/manager/manager.go +++ b/cmd/manager/manager.go @@ -35,6 +35,7 @@ var ( parallelCount int refreshRate string backupInterval string + backupTimeSpec string ) var envs = make(map[string]string) @@ -59,7 +60,7 @@ var managerCmd = &cobra.Command{ agentImage = fmt.Sprintf("ghcr.io/camptocamp/bivac:%s", utils.ComputeDockerAgentImage(managerVersion)) } - err = manager.Start(bivacCmd.BuildInfo, o, server, volumesFilters, providersFile, targetURL, logServer, agentImage, retryCount, parallelCount, refreshRate, backupInterval) + err = manager.Start(bivacCmd.BuildInfo, o, server, volumesFilters, providersFile, targetURL, logServer, agentImage, retryCount, parallelCount, refreshRate, backupInterval, backupTimeSpec) if err != nil { log.Errorf("failed to start manager: %s", err) return @@ -139,6 +140,9 @@ func init() { managerCmd.Flags().StringVarP(&backupInterval, "backup.interval", "", "23h", "Interval between two backups of a volume.") envs["BIVAC_BACKUP_INTERVAL"] = "backup.interval" + managerCmd.Flags().StringVarP(&backupTimeSpec, "backup.time", "", "00h", "Prefer time to do the backup.") + envs["BIVAC_BACKUP_TIME"] = "backup.time" + bivacCmd.SetValuesFromEnv(envs, managerCmd.Flags()) bivacCmd.RootCmd.AddCommand(managerCmd) } diff --git a/internal/manager/manager.go b/internal/manager/manager.go index 27c5bba5..ea4edf15 100644 --- a/internal/manager/manager.go +++ b/internal/manager/manager.go @@ -34,7 +34,7 @@ type Manager struct { } // Start starts a Bivac manager which handle backups management -func Start(buildInfo utils.BuildInfo, o orchestrators.Orchestrator, s Server, volumeFilters volume.Filters, providersFile, targetURL, logServer, agentImage string, retryCount, parallelCount int, refreshRate, backupInterval string) (err error) { +func Start(buildInfo utils.BuildInfo, o orchestrators.Orchestrator, s Server, volumeFilters volume.Filters, providersFile, targetURL, logServer, agentImage string, retryCount, parallelCount int, refreshRate, backupInterval string, backupTimeSpec string) (err error) { p, err := LoadProviders(providersFile) if err != nil { err = fmt.Errorf("failed to read providers file: %s", err) @@ -47,6 +47,18 @@ func Start(buildInfo utils.BuildInfo, o orchestrators.Orchestrator, s Server, vo return } + //check backupTimeSpec format and constraint 00h < xxh < 23h e.g: 23h59m does not respect constraint + backupTime, err := time.ParseDuration(backupTimeSpec) + if err != nil { + err = fmt.Errorf("failed to parse backup prefered time: %s", err) + return + } + + if backupTime.Hours() >= 23 && backupTime.Hours() >= 0 { + err = fmt.Errorf("backup prefered time does not respect constraint (00h < x < 23h): %s", err) + return + } + backupInt, err := time.ParseDuration(backupInterval) if err != nil { err = fmt.Errorf("failed to parse backup interval: %s", err) @@ -90,7 +102,7 @@ func Start(buildInfo utils.BuildInfo, o orchestrators.Orchestrator, s Server, vo delete(orphanAgents, val) } - if !isBackupNeeded(v, backupInt) { + if !isBackupNeeded(v, backupInt, backupTime) { continue } @@ -179,7 +191,7 @@ func Start(buildInfo utils.BuildInfo, o orchestrators.Orchestrator, s Server, vo return } -func isBackupNeeded(v *volume.Volume, backupInt time.Duration) bool { +func isBackupNeeded(v *volume.Volume, backupInt time.Duration,backupTime time.Duration) bool { if v.BackingUp { return false } @@ -204,11 +216,17 @@ func isBackupNeeded(v *volume.Volume, backupInt time.Duration) bool { return false } + // retry if last backup status is Failed if lbd.Add(time.Hour).Before(time.Now().UTC()) && v.LastBackupStatus == "Failed" { return true } - if lbd.Add(backupInt).Before(time.Now().UTC()) { + // Convertir targetBackupTime en une date avec le jour courant + now := time.Now() + targetBackupTime := time.Date(now.Year(), now.Month(), now.Day(),0,0,0,0,now.Location()).Add(backupTime) + + // check backup interval and backup prefered time + if lbd.Add(backupInt).Before(time.Now().UTC()) && targetBackupTime.Before(now) { return true } return false