Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(manager): add prefered time for backup #394

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ docker-images: clean
docker manifest push $(IMAGE_NAME):$(IMAGE_VERSION)

lint:
@GO111MODULE=off go get -u -v golang.org/x/lint/golint
@GO111MODULE=auto go get -u -v golang.org/x/lint/golint
@for file in $$(go list ./... | grep -v '_workspace/' | grep -v 'vendor'); do \
export output="$$(golint $${file} | grep -v 'type name will be used as docker.DockerInfo')"; \
[ -n "$${output}" ] && echo "$${output}" && export status=1; \
Expand Down
8 changes: 7 additions & 1 deletion cmd/manager/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ var (
parallelCount int
refreshRate string
backupInterval string
backupTimeSpec string
)
var envs = make(map[string]string)

Expand All @@ -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
Expand Down Expand Up @@ -92,6 +93,8 @@ func init() {
envs["KUBERNETES_NAMESPACE"] = "kubernetes.namespace"
managerCmd.Flags().BoolVarP(&Orchestrators.Kubernetes.AllNamespaces, "kubernetes.all-namespaces", "", false, "Backup volumes of all namespaces.")
envs["KUBERNETES_ALL_NAMESPACES"] = "kubernetes.all-namespaces"
managerCmd.Flags().StringVarP(&Orchestrators.Kubernetes.CustomNamespaces, "kubernetes.custom-namespaces", "", "", "Backup volumes from a custom namespaces list.")
envs["KUBERNETES_CUSTOM_NAMESPACES"] = "kubernetes.custom-namespaces"
managerCmd.Flags().StringVarP(&Orchestrators.Kubernetes.KubeConfig, "kubernetes.kubeconfig", "", "", "Path to your kuberconfig file.")
envs["KUBERNETES_KUBECONFIG"] = "kubernetes.kubeconfig"
managerCmd.Flags().StringVarP(&Orchestrators.Kubernetes.AgentServiceAccount, "kubernetes.agent-service-account", "", "", "Specify service account for agents.")
Expand Down Expand Up @@ -139,6 +142,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)
}
34 changes: 30 additions & 4 deletions internal/manager/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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
}
Expand All @@ -204,11 +216,25 @@ 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()) {
// convert targetBackupTime in date with today time
now := time.Now().UTC()
targetBackupTime := time.Date(now.Year(), now.Month(), now.Day(),0,0,0,0,now.Location()).Add(backupTime)

// set backup interval to 23h if backupTime is not set to default value
if backupTime.Seconds() > 0 && targetBackupTime.Before(now) {
fixInterval, _ := time.ParseDuration("23h")
if lbd.Add(fixInterval).Before(now) {
return true
}
}

// if backupTime is set to default value
if lbd.Add(backupInt).Before(now) && backupTime.Seconds() == 0 {
return true
}
return false
Expand Down
10 changes: 6 additions & 4 deletions internal/manager/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ func TestIsBackupNeededBackupIntervalStatusSuccess(t *testing.T) {
}

h, _ := time.ParseDuration("30m")
assert.Equal(t, isBackupNeeded(givenVolume, h), true)
d, _ := time.ParseDuration("0s") // default prefered time
assert.Equal(t, isBackupNeeded(givenVolume, h,d), true)
h, _ = time.ParseDuration("12h")
assert.Equal(t, isBackupNeeded(givenVolume, h), false)
assert.Equal(t, isBackupNeeded(givenVolume, h,d), false)
}

func TestIsBackupNeededBackupIntervalStatusFailed(t *testing.T) {
Expand All @@ -35,7 +36,8 @@ func TestIsBackupNeededBackupIntervalStatusFailed(t *testing.T) {
}

h, _ := time.ParseDuration("30m")
assert.Equal(t, isBackupNeeded(givenVolume, h), true)
d, _ := time.ParseDuration("0s") // default prefered time
assert.Equal(t, isBackupNeeded(givenVolume, h,d), true)
h, _ = time.ParseDuration("12h")
assert.Equal(t, isBackupNeeded(givenVolume, h), true)
assert.Equal(t, isBackupNeeded(givenVolume, h,d), true)
}
15 changes: 15 additions & 0 deletions pkg/orchestrators/kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
type KubernetesConfig struct {
Namespace string
AllNamespaces bool
CustomNamespaces string
KubeConfig string
AgentServiceAccount string
AgentLabelsInline string
Expand Down Expand Up @@ -556,6 +557,20 @@ func (o *KubernetesOrchestrator) getNamespaces() (namespaces []string, err error
for _, namespace := range nms.Items {
namespaces = append(namespaces, namespace.Name)
}
} else if o.config.CustomNamespaces != "" {
nms, err := o.client.CoreV1().Namespaces().List(metav1.ListOptions{})
if err != nil {
err = fmt.Errorf("failed to retrieve the list of namespaces: %s", err)
return []string{}, err
}
customNamespaces := strings.Split(o.config.CustomNamespaces, ",")
for _, namespace := range nms.Items {
for _, ns := range customNamespaces {
if ns == namespace.Name {
namespaces = append(namespaces, namespace.Name)
}
}
}
} else {
namespaces = append(namespaces, o.config.Namespace)
}
Expand Down
Loading