From 600f8d79dffc643d152b9320c4c667b934e0bae7 Mon Sep 17 00:00:00 2001 From: SantoshKumarGajawada Date: Mon, 2 Dec 2024 11:03:54 +0000 Subject: [PATCH] PB-8609: Modify shouldStartApplicationBackup to support parallel schedule backup --- .../v1alpha1/applicationbackupschedule.go | 1 + .../stork/v1alpha1/zz_generated.deepcopy.go | 239 +++++++++++++++++- .../controllers/applicationbackupschedule.go | 61 +++-- 3 files changed, 284 insertions(+), 17 deletions(-) diff --git a/pkg/apis/stork/v1alpha1/applicationbackupschedule.go b/pkg/apis/stork/v1alpha1/applicationbackupschedule.go index fc6ca44a9a..fa4180b4b6 100644 --- a/pkg/apis/stork/v1alpha1/applicationbackupschedule.go +++ b/pkg/apis/stork/v1alpha1/applicationbackupschedule.go @@ -18,6 +18,7 @@ type ApplicationBackupScheduleSpec struct { Suspend *bool `json:"suspend"` ReclaimPolicy ReclaimPolicyType `json:"reclaimPolicy"` BackupType string `json:"backupType"` + ParallelBackup *bool `json:"parallelBackup"` } // ApplicationBackupTemplateSpec describes the data a ApplicationBackup should have when created diff --git a/pkg/apis/stork/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/stork/v1alpha1/zz_generated.deepcopy.go index ce39c0923a..93ef12476a 100644 --- a/pkg/apis/stork/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/stork/v1alpha1/zz_generated.deepcopy.go @@ -32,7 +32,8 @@ func (in *Action) DeepCopyInto(out *Action) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) return } @@ -87,9 +88,46 @@ func (in *ActionList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ActionParameter) DeepCopyInto(out *ActionParameter) { + *out = *in + in.FailoverParameter.DeepCopyInto(&out.FailoverParameter) + in.FailbackParameter.DeepCopyInto(&out.FailbackParameter) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ActionParameter. +func (in *ActionParameter) DeepCopy() *ActionParameter { + if in == nil { + return nil + } + out := new(ActionParameter) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ActionParameterItem) DeepCopyInto(out *ActionParameterItem) { + *out = *in + in.FailoverParameter.DeepCopyInto(&out.FailoverParameter) + in.FailbackParameter.DeepCopyInto(&out.FailbackParameter) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ActionParameterItem. +func (in *ActionParameterItem) DeepCopy() *ActionParameterItem { + if in == nil { + return nil + } + out := new(ActionParameterItem) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ActionSpec) DeepCopyInto(out *ActionSpec) { *out = *in + in.ActionParameter.DeepCopyInto(&out.ActionParameter) return } @@ -103,6 +141,104 @@ func (in *ActionSpec) DeepCopy() *ActionSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ActionStatus) DeepCopyInto(out *ActionStatus) { + *out = *in + in.FinishTimestamp.DeepCopyInto(&out.FinishTimestamp) + if in.Summary != nil { + in, out := &in.Summary, &out.Summary + *out = new(ActionSummary) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ActionStatus. +func (in *ActionStatus) DeepCopy() *ActionStatus { + if in == nil { + return nil + } + out := new(ActionStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ActionSummary) DeepCopyInto(out *ActionSummary) { + *out = *in + if in.FailoverSummaryItem != nil { + in, out := &in.FailoverSummaryItem, &out.FailoverSummaryItem + *out = make([]*FailoverSummary, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(FailoverSummary) + **out = **in + } + } + } + if in.FailbackSummaryItem != nil { + in, out := &in.FailbackSummaryItem, &out.FailbackSummaryItem + *out = make([]*FailbackSummary, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(FailbackSummary) + **out = **in + } + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ActionSummary. +func (in *ActionSummary) DeepCopy() *ActionSummary { + if in == nil { + return nil + } + out := new(ActionSummary) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ActionSummaryItem) DeepCopyInto(out *ActionSummaryItem) { + *out = *in + if in.FailoverSummaryItem != nil { + in, out := &in.FailoverSummaryItem, &out.FailoverSummaryItem + *out = make([]*FailoverSummary, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(FailoverSummary) + **out = **in + } + } + } + if in.FailbackSummaryItem != nil { + in, out := &in.FailbackSummaryItem, &out.FailbackSummaryItem + *out = make([]*FailbackSummary, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(FailbackSummary) + **out = **in + } + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ActionSummaryItem. +func (in *ActionSummaryItem) DeepCopy() *ActionSummaryItem { + if in == nil { + return nil + } + out := new(ActionSummaryItem) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ApplicationBackup) DeepCopyInto(out *ApplicationBackup) { *out = *in @@ -251,6 +387,11 @@ func (in *ApplicationBackupScheduleSpec) DeepCopyInto(out *ApplicationBackupSche *out = new(bool) **out = **in } + if in.ParallelBackup != nil { + in, out := &in.ParallelBackup, &out.ParallelBackup + *out = new(bool) + **out = **in + } return } @@ -433,6 +574,7 @@ func (in *ApplicationBackupVolumeInfo) DeepCopyInto(out *ApplicationBackupVolume (*out)[key] = val } } + out.JobSecurityContext = in.JobSecurityContext return } @@ -1486,6 +1628,85 @@ func (in *ExportStatus) DeepCopy() *ExportStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FailbackParameter) DeepCopyInto(out *FailbackParameter) { + *out = *in + if in.FailbackNamespaces != nil { + in, out := &in.FailbackNamespaces, &out.FailbackNamespaces + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FailbackParameter. +func (in *FailbackParameter) DeepCopy() *FailbackParameter { + if in == nil { + return nil + } + out := new(FailbackParameter) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FailbackSummary) DeepCopyInto(out *FailbackSummary) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FailbackSummary. +func (in *FailbackSummary) DeepCopy() *FailbackSummary { + if in == nil { + return nil + } + out := new(FailbackSummary) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FailoverParameter) DeepCopyInto(out *FailoverParameter) { + *out = *in + if in.FailoverNamespaces != nil { + in, out := &in.FailoverNamespaces, &out.FailoverNamespaces + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.SkipSourceOperations != nil { + in, out := &in.SkipSourceOperations, &out.SkipSourceOperations + *out = new(bool) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FailoverParameter. +func (in *FailoverParameter) DeepCopy() *FailoverParameter { + if in == nil { + return nil + } + out := new(FailoverParameter) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FailoverSummary) DeepCopyInto(out *FailoverSummary) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FailoverSummary. +func (in *FailoverSummary) DeepCopy() *FailoverSummary { + if in == nil { + return nil + } + out := new(FailoverSummary) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GoogleConfig) DeepCopyInto(out *GoogleConfig) { *out = *in @@ -1642,6 +1863,22 @@ func (in *IntervalPolicy) DeepCopy() *IntervalPolicy { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JobSecurityContext) DeepCopyInto(out *JobSecurityContext) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JobSecurityContext. +func (in *JobSecurityContext) DeepCopy() *JobSecurityContext { + if in == nil { + return nil + } + out := new(JobSecurityContext) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in KindResourceTransform) DeepCopyInto(out *KindResourceTransform) { { diff --git a/pkg/applicationmanager/controllers/applicationbackupschedule.go b/pkg/applicationmanager/controllers/applicationbackupschedule.go index 8ba129e4ee..fa637e8dc7 100644 --- a/pkg/applicationmanager/controllers/applicationbackupschedule.go +++ b/pkg/applicationmanager/controllers/applicationbackupschedule.go @@ -8,6 +8,7 @@ import ( "strings" "time" + "github.com/libopenstorage/stork/drivers/volume" stork_api "github.com/libopenstorage/stork/pkg/apis/stork/v1alpha1" "github.com/libopenstorage/stork/pkg/controllers" storkops "github.com/libopenstorage/stork/pkg/crud/stork" @@ -244,29 +245,27 @@ func (s *ApplicationBackupScheduleController) isApplicationBackupComplete(status } func (s *ApplicationBackupScheduleController) shouldStartApplicationBackup(backupSchedule *stork_api.ApplicationBackupSchedule) (stork_api.SchedulePolicyType, bool, error) { - // Don't trigger a new backup if one is already in progress + isParallelBackupEnabled := *backupSchedule.Spec.ParallelBackup for _, policyType := range stork_api.GetValidSchedulePolicyTypes() { + var latestScheduledApplicationBackupStatus *stork_api.ScheduledApplicationBackupStatus + var latestApplicationBackupTimestamp meta.Time policyApplicationBackup, present := backupSchedule.Status.Items[policyType] if present { for _, backup := range policyApplicationBackup { - if !s.isApplicationBackupComplete(backup.Status) { + if (!isParallelBackupEnabled && backup.Status == stork_api.ApplicationBackupStatusInProgress) || + backup.Status == stork_api.ApplicationBackupStatusInitial || + backup.Status == stork_api.ApplicationBackupStatusPending { return stork_api.SchedulePolicyTypeInvalid, false, nil } - } - } - } - - for _, policyType := range stork_api.GetValidSchedulePolicyTypes() { - var latestApplicationBackupTimestamp meta.Time - policyApplicationBackup, present := backupSchedule.Status.Items[policyType] - if present { - for _, backup := range policyApplicationBackup { - if latestApplicationBackupTimestamp.Before(&backup.CreationTimestamp) { - latestApplicationBackupTimestamp = backup.CreationTimestamp + if latestScheduledApplicationBackupStatus == nil || latestScheduledApplicationBackupStatus.CreationTimestamp.Before(&backup.CreationTimestamp) { + latestScheduledApplicationBackupStatus = backup } } } - trigger, err := schedule.TriggerRequired( + if latestScheduledApplicationBackupStatus != nil { + latestApplicationBackupTimestamp = latestScheduledApplicationBackupStatus.CreationTimestamp + } + isTriggerRequired, err := schedule.TriggerRequired( backupSchedule.Spec.SchedulePolicyName, backupSchedule.Namespace, policyType, @@ -275,13 +274,43 @@ func (s *ApplicationBackupScheduleController) shouldStartApplicationBackup(backu if err != nil { return stork_api.SchedulePolicyTypeInvalid, false, err } - if trigger { - return policyType, true, nil + if !isTriggerRequired { + continue } + if latestScheduledApplicationBackupStatus != nil { + isLatestScheduleBackupInProgress := latestScheduledApplicationBackupStatus.Status == stork_api.ApplicationBackupStatusInProgress + if isLatestScheduleBackupInProgress { + isScheduleBackupAllowed, err := verifyAllPXDVolumesSnapshotCompleted(latestScheduledApplicationBackupStatus.Name, backupSchedule.Namespace) + if err != nil { + logrus.Errorf("Error while verifyAllPXDVolumesSnapshotCompleted: %v", err) + return stork_api.SchedulePolicyTypeInvalid, false, err + } + if !isScheduleBackupAllowed { + continue + } + } + } + return policyType, true, nil } return stork_api.SchedulePolicyTypeInvalid, false, nil } +func verifyAllPXDVolumesSnapshotCompleted(backupName, backupNamespace string) (bool, error) { + fn := "verifyAllPXDVolumesSnapshotCompleted" + backup, err := storkops.Instance().GetApplicationBackup(backupName, backupNamespace) + if err != nil { + return false, err + } + // verify all the volumes driver are PXD and BackupID is non-empty(Snapshot for that volume is completed) + for _, volumeInfo := range backup.Status.Volumes { + if !(volumeInfo.DriverName == volume.PortworxDriverName && volumeInfo.BackupID != "") { + logrus.Errorf("%s: pvcName: %v, driverName: %v, backupID: %v", fn, volumeInfo.PersistentVolumeClaim, volumeInfo.DriverName, volumeInfo.BackupID) + return false, nil + } + } + return true, nil +} + func (s *ApplicationBackupScheduleController) formatApplicationBackupName(backupSchedule *stork_api.ApplicationBackupSchedule, policyType stork_api.SchedulePolicyType) string { return strings.Join([]string{backupSchedule.Name, strings.ToLower(string(policyType)), time.Now().Format(nameTimeSuffixFormat)}, "-") }