From dc7e6752bd70a0d732e8b8ead47bb7b84c4e08ce Mon Sep 17 00:00:00 2001 From: wangyelei Date: Wed, 22 Jan 2025 20:18:09 +0800 Subject: [PATCH 1/5] chore: support to specify the continuous backup method for cluster.spec --- apis/apps/v1alpha1/cluster_types.go | 5 ++ .../bases/apps.kubeblocks.io_clusters.yaml | 4 ++ controllers/apps/cluster_controller_test.go | 64 +++++++++++++++---- controllers/apps/component_controller_test.go | 27 ++++---- .../apps/opsrequest_controller_test.go | 2 +- .../apps/transformer_cluster_backup_policy.go | 25 +++++--- .../crds/apps.kubeblocks.io_clusters.yaml | 4 ++ docs/developer_docs/api-reference/cluster.md | 12 ++++ pkg/dataprotection/backup/scheduler.go | 39 ++++++++++- pkg/dataprotection/types/constant.go | 2 + 10 files changed, 147 insertions(+), 37 deletions(-) diff --git a/apis/apps/v1alpha1/cluster_types.go b/apis/apps/v1alpha1/cluster_types.go index 9eab7918c01..62af838c03c 100644 --- a/apis/apps/v1alpha1/cluster_types.go +++ b/apis/apps/v1alpha1/cluster_types.go @@ -298,6 +298,11 @@ type ClusterBackup struct { // +optional PITREnabled *bool `json:"pitrEnabled,omitempty"` + // Specifies the backup method to use, if not set, use the first continuous method. + // + // +optional + ContinuousMethod string `json:"continuousMethod,omitempty"` + // Specifies whether to enable incremental backup. // // +kubebuilder:default=false diff --git a/config/crd/bases/apps.kubeblocks.io_clusters.yaml b/config/crd/bases/apps.kubeblocks.io_clusters.yaml index 7ee4c7e8aee..e54380038ef 100644 --- a/config/crd/bases/apps.kubeblocks.io_clusters.yaml +++ b/config/crd/bases/apps.kubeblocks.io_clusters.yaml @@ -200,6 +200,10 @@ spec: backup: description: Specifies the backup configuration of the Cluster. properties: + continuousMethod: + description: Specifies the backup method to use, if not set, use + the first continuous method. + type: string cronExpression: description: The cron expression for the schedule. The timezone is in UTC. See https://en.wikipedia.org/wiki/Cron. diff --git a/controllers/apps/cluster_controller_test.go b/controllers/apps/cluster_controller_test.go index faa20ae54af..2a9a5b1e81c 100644 --- a/controllers/apps/cluster_controller_test.go +++ b/controllers/apps/cluster_controller_test.go @@ -40,6 +40,7 @@ import ( "github.com/apecloud/kubeblocks/pkg/controller/builder" "github.com/apecloud/kubeblocks/pkg/controller/component" "github.com/apecloud/kubeblocks/pkg/controller/scheduling" + "github.com/apecloud/kubeblocks/pkg/dataprotection/utils/boolptr" "github.com/apecloud/kubeblocks/pkg/generics" testapps "github.com/apecloud/kubeblocks/pkg/testutil/apps" testdp "github.com/apecloud/kubeblocks/pkg/testutil/dataprotection" @@ -161,7 +162,7 @@ var _ = Describe("Cluster Controller", func() { GetObject() By("Create a bpt obj") - createBackupPolicyTpl(clusterDefObj, compDefObj.Name, clusterVersionName) + createBackupPolicyTpl(clusterDefObj, compDefObj.Name, false, clusterVersionName) By("Create a componentVersion obj") compVersionObj = testapps.NewComponentVersionFactory(compVersionName). @@ -1368,6 +1369,19 @@ var _ = Describe("Cluster Controller", func() { RepoName: backupRepoName, }, }, + { + desc: "backup with snapshot method and specified continuous method", + backup: &appsv1alpha1.ClusterBackup{ + Enabled: &boolTrue, + RetentionPeriod: retention("1d"), + Method: vsBackupMethodName, + CronExpression: "*/1 * * * *", + StartingDeadlineMinutes: int64Ptr(int64(10)), + ContinuousMethod: continuousMethodName1, + PITREnabled: &boolTrue, + RepoName: backupRepoName, + }, + }, { desc: "disable backup", backup: &appsv1alpha1.ClusterBackup{ @@ -1405,19 +1419,36 @@ var _ = Describe("Cluster Controller", func() { checkSchedule := func(g Gomega, schedule *dpv1alpha1.BackupSchedule) { var policy *dpv1alpha1.SchedulePolicy - enableOtherFullMethod := false - for i, s := range schedule.Spec.Schedules { + hasCheckPITRMethod := false + for i := range schedule.Spec.Schedules { + s := &schedule.Spec.Schedules[i] if s.BackupMethod == backup.Method { Expect(*s.Enabled).Should(BeEquivalentTo(*backup.Enabled)) - policy = &schedule.Spec.Schedules[i] - if *backup.Enabled { - enableOtherFullMethod = true + policy = s + continue + } + if !slices.Contains([]string{continuousMethodName, continuousMethodName1}, s.BackupMethod) { + if boolptr.IsSetToTrue(backup.Enabled) { + // another full backup method should be disabled. + Expect(*s.Enabled).Should(BeFalse()) } continue } - if enableOtherFullMethod { - // another full backup method should be disabled. - Expect(*s.Enabled).Should(BeFalse()) + if len(backup.ContinuousMethod) == 0 { + // first continuous backup method should be equal to "PITREnabled", another is disabled. + if !hasCheckPITRMethod { + Expect(*s.Enabled).Should(BeEquivalentTo(*backup.PITREnabled)) + hasCheckPITRMethod = true + } else { + Expect(*s.Enabled).Should(BeFalse()) + } + } else { + // specified continuous backup method should be equal to "PITREnabled", another is disabled. + if backup.ContinuousMethod == s.BackupMethod { + Expect(*s.Enabled).Should(BeEquivalentTo(*backup.PITREnabled)) + } else { + Expect(*s.Enabled).Should(BeFalse()) + } } } if backup.Enabled != nil && *backup.Enabled { @@ -1593,9 +1624,10 @@ var _ = Describe("Cluster Controller", func() { }) }) -func createBackupPolicyTpl(clusterDefObj *appsv1alpha1.ClusterDefinition, compDef string, mappingClusterVersions ...string) { +func createBackupPolicyTpl(clusterDefObj *appsv1alpha1.ClusterDefinition, compDef string, forHScale bool, mappingClusterVersions ...string) { By("create actionSet") - fakeActionSet(clusterDefObj.Name) + fakeActionSet(actionSetName, clusterDefObj.Name, dpv1alpha1.BackupTypeFull) + fakeActionSet(continuousActionSetName, clusterDefObj.Name, dpv1alpha1.BackupTypeContinuous) By("Creating a BackupPolicyTemplate") bpt := testapps.NewBackupPolicyTemplateFactory(backupPolicyTPLName). @@ -1618,6 +1650,16 @@ func createBackupPolicyTpl(clusterDefObj *appsv1alpha1.ClusterDefinition, compDe case appsv1alpha1.Replication: bpt.SetTargetRole("primary") } + if !forHScale { + bpt.AddBackupMethod(continuousMethodName, false, continuousActionSetName). + SetComponentDef(compDef). + SetBackupMethodVolumeMounts("data", "/data"). + AddBackupMethod(continuousMethodName1, false, continuousActionSetName). + SetComponentDef(compDef). + SetBackupMethodVolumeMounts("data", "/data"). + AddSchedule(continuousMethodName, "0 0 * * *", ttl, false). + AddSchedule(continuousMethodName1, "0 0 * * *", ttl, false) + } } bpt.Create(&testCtx) } diff --git a/controllers/apps/component_controller_test.go b/controllers/apps/component_controller_test.go index a227b7d68ee..07725439de3 100644 --- a/controllers/apps/component_controller_test.go +++ b/controllers/apps/component_controller_test.go @@ -66,10 +66,13 @@ import ( ) const ( - backupPolicyTPLName = "test-backup-policy-template-mysql" - backupMethodName = "test-backup-method" - vsBackupMethodName = "test-vs-backup-method" - actionSetName = "test-action-set" + backupPolicyTPLName = "test-backup-policy-template-mysql" + backupMethodName = "test-backup-method" + continuousMethodName = "continuous-backup-method" + continuousMethodName1 = "continuous-backup-method1" + vsBackupMethodName = "test-vs-backup-method" + actionSetName = "test-action-set" + continuousActionSetName = "test-continuous-action-set" ) var ( @@ -700,7 +703,7 @@ var _ = Describe("Component Controller", func() { if policyType == appsv1alpha1.HScaleDataClonePolicyCloneVolume { By("creating actionSet if backup policy is backup") - fakeActionSet(clusterDef.Name) + fakeActionSet(actionSetName, clusterDef.Name, dpv1alpha1.BackupTypeFull) } } })()).ShouldNot(HaveOccurred()) @@ -2052,7 +2055,7 @@ var _ = Describe("Component Controller", func() { Context("provisioning", func() { BeforeEach(func() { createAllWorkloadTypesClusterDef() - createBackupPolicyTpl(clusterDefObj, compDefName) + createBackupPolicyTpl(clusterDefObj, compDefName, true) }) AfterEach(func() { @@ -2123,7 +2126,7 @@ var _ = Describe("Component Controller", func() { BeforeEach(func() { createAllWorkloadTypesClusterDef() - createBackupPolicyTpl(clusterDefObj, compDefName) + createBackupPolicyTpl(clusterDefObj, compDefName, true) }) AfterEach(func() { @@ -2143,7 +2146,7 @@ var _ = Describe("Component Controller", func() { BeforeEach(func() { cleanEnv() createAllWorkloadTypesClusterDef() - createBackupPolicyTpl(clusterDefObj, compDefName) + createBackupPolicyTpl(clusterDefObj, compDefName, true) }) createNWaitClusterObj := func(components map[string]string, @@ -2220,7 +2223,7 @@ var _ = Describe("Component Controller", func() { BeforeEach(func() { createAllWorkloadTypesClusterDef() - createBackupPolicyTpl(clusterDefObj, compDefName) + createBackupPolicyTpl(clusterDefObj, compDefName, true) mockStorageClass = testk8s.CreateMockStorageClass(&testCtx, testk8s.DefaultStorageClassName) }) @@ -2289,7 +2292,7 @@ var _ = Describe("Component Controller", func() { When("creating cluster with workloadType=consensus component", func() { BeforeEach(func() { createAllWorkloadTypesClusterDef() - createBackupPolicyTpl(clusterDefObj, compDefName) + createBackupPolicyTpl(clusterDefObj, compDefName, true) }) AfterEach(func() { @@ -2544,7 +2547,7 @@ func checkRestoreAndSetCompleted(clusterKey types.NamespacedName, compName strin mockRestoreCompleted(ml) } -func fakeActionSet(clusterDefName string) *dpv1alpha1.ActionSet { +func fakeActionSet(actionSetName, clusterDefName string, backupType dpv1alpha1.BackupType) *dpv1alpha1.ActionSet { actionSet := &dpv1alpha1.ActionSet{ ObjectMeta: metav1.ObjectMeta{ Name: actionSetName, @@ -2559,7 +2562,7 @@ func fakeActionSet(clusterDefName string) *dpv1alpha1.ActionSet { Value: "test-value", }, }, - BackupType: dpv1alpha1.BackupTypeFull, + BackupType: backupType, Backup: &dpv1alpha1.BackupActionSpec{ BackupData: &dpv1alpha1.BackupDataActionSpec{ JobActionSpec: dpv1alpha1.JobActionSpec{ diff --git a/controllers/apps/opsrequest_controller_test.go b/controllers/apps/opsrequest_controller_test.go index 1f15988251a..1919e618be7 100644 --- a/controllers/apps/opsrequest_controller_test.go +++ b/controllers/apps/opsrequest_controller_test.go @@ -319,7 +319,7 @@ var _ = Describe("OpsRequest Controller", func() { } createMysqlCluster := func(replicas int32) { - createBackupPolicyTpl(clusterDefObj, mysqlCompDefName) + createBackupPolicyTpl(clusterDefObj, mysqlCompDefName, true) By("set component to horizontal with snapshot policy and create a cluster") testk8s.MockEnableVolumeSnapshot(&testCtx, testk8s.DefaultStorageClassName) diff --git a/controllers/apps/transformer_cluster_backup_policy.go b/controllers/apps/transformer_cluster_backup_policy.go index 875b72513fb..5ad1881c24c 100644 --- a/controllers/apps/transformer_cluster_backup_policy.go +++ b/controllers/apps/transformer_cluster_backup_policy.go @@ -647,7 +647,8 @@ func (r *clusterBackupPolicyTransformer) mergeClusterBackup( hasSyncPITRMethod := false hasSyncIncMethod := false enableAutoBackup := boolptr.IsSetToTrue(backup.Enabled) - for i, s := range backupSchedule.Spec.Schedules { + for i := range backupSchedule.Spec.Schedules { + s := &backupSchedule.Spec.Schedules[i] if s.BackupMethod == backup.Method { mergeSchedulePolicy(sp, &backupSchedule.Spec.Schedules[i]) exist = true @@ -671,15 +672,20 @@ func (r *clusterBackupPolicyTransformer) mergeClusterBackup( r.Error(err, "failed to get ActionSet for backup.", "ActionSet", as.Name) continue } - if as.Spec.BackupType == dpv1alpha1.BackupTypeContinuous && backup.PITREnabled != nil && !hasSyncPITRMethod { - // auto-sync the first continuous backup for the 'pirtEnable' option. - backupSchedule.Spec.Schedules[i].Enabled = backup.PITREnabled + switch { + case as.Spec.BackupType == dpv1alpha1.BackupTypeContinuous && backup.PITREnabled != nil: + if boolptr.IsSetToFalse(backup.PITREnabled) || hasSyncPITRMethod || + (len(backup.ContinuousMethod) > 0 && backup.ContinuousMethod != s.BackupMethod) { + s.Enabled = boolptr.False() + continue + } + // auto-sync the first or specified continuous backup for the 'pirtEnable' option. + s.Enabled = backup.PITREnabled if backup.RetentionPeriod.String() != "" { - backupSchedule.Spec.Schedules[i].RetentionPeriod = backup.RetentionPeriod + s.RetentionPeriod = backup.RetentionPeriod } hasSyncPITRMethod = true - } - if as.Spec.BackupType == dpv1alpha1.BackupTypeIncremental { + case as.Spec.BackupType == dpv1alpha1.BackupTypeIncremental: if len(backup.Method) == 0 || m.CompatibleMethod != backup.Method { // disable other incremental backup schedules backupSchedule.Spec.Schedules[i].Enabled = boolptr.False() @@ -692,10 +698,9 @@ func (r *clusterBackupPolicyTransformer) mergeClusterBackup( }, &backupSchedule.Spec.Schedules[i]) hasSyncIncMethod = true } - } - if as.Spec.BackupType == dpv1alpha1.BackupTypeFull && enableAutoBackup { + case as.Spec.BackupType == dpv1alpha1.BackupTypeFull && enableAutoBackup: // disable the automatic backup for other full backup method - backupSchedule.Spec.Schedules[i].Enabled = boolptr.False() + s.Enabled = boolptr.False() } } if !exist { diff --git a/deploy/helm/crds/apps.kubeblocks.io_clusters.yaml b/deploy/helm/crds/apps.kubeblocks.io_clusters.yaml index 7ee4c7e8aee..e54380038ef 100644 --- a/deploy/helm/crds/apps.kubeblocks.io_clusters.yaml +++ b/deploy/helm/crds/apps.kubeblocks.io_clusters.yaml @@ -200,6 +200,10 @@ spec: backup: description: Specifies the backup configuration of the Cluster. properties: + continuousMethod: + description: Specifies the backup method to use, if not set, use + the first continuous method. + type: string cronExpression: description: The cron expression for the schedule. The timezone is in UTC. See https://en.wikipedia.org/wiki/Cron. diff --git a/docs/developer_docs/api-reference/cluster.md b/docs/developer_docs/api-reference/cluster.md index a2427b52e03..1017c0750e0 100644 --- a/docs/developer_docs/api-reference/cluster.md +++ b/docs/developer_docs/api-reference/cluster.md @@ -4548,6 +4548,18 @@ bool +continuousMethod
+ +string + + + +(Optional) +

Specifies the backup method to use, if not set, use the first continuous method.

+ + + + incrementalBackupEnabled
bool diff --git a/pkg/dataprotection/backup/scheduler.go b/pkg/dataprotection/backup/scheduler.go index a4eea041847..7f4bbf2dcdc 100644 --- a/pkg/dataprotection/backup/scheduler.go +++ b/pkg/dataprotection/backup/scheduler.go @@ -365,18 +365,42 @@ type backupReconfigureRef struct { type parameterPairs map[string][]appsv1alpha1.ParameterPair +func (s *Scheduler) convertLastAppliedConfigs(continuousMethod string) { + if _, ok := s.BackupSchedule.Annotations[dptypes.LastAppliedConfigsAnnotationKey]; ok { + return + } + lastAppliedConfig := s.BackupSchedule.Annotations[constant.LastAppliedConfigAnnotationKey] + if lastAppliedConfig == "" { + return + } + lastAppliedConfigMap := map[string]string{} + lastAppliedConfigMap[continuousMethod] = lastAppliedConfig + str, _ := json.Marshal(lastAppliedConfigMap) + s.BackupSchedule.Annotations[dptypes.LastAppliedConfigsAnnotationKey] = string(str) +} + +func (s *Scheduler) getLastAppliedConfigsMap() (map[string]string, error) { + resMap := map[string]string{} + if err := json.Unmarshal([]byte(s.BackupSchedule.Annotations[dptypes.LastAppliedConfigsAnnotationKey]), &resMap); err != nil { + return nil, err + } + return resMap, nil +} + func (s *Scheduler) reconfigure(schedulePolicy *dpv1alpha1.SchedulePolicy) error { reCfgRef := s.BackupSchedule.Annotations[dptypes.ReconfigureRefAnnotationKey] if reCfgRef == "" { return nil } + // convert deprecated "lastAppliedConfig "to "lastAppliedConfigs" + s.convertLastAppliedConfigs(schedulePolicy.BackupMethod) configRef := backupReconfigureRef{} if err := json.Unmarshal([]byte(reCfgRef), &configRef); err != nil { return err } enable := boolptr.IsSetToTrue(schedulePolicy.Enabled) - if s.BackupSchedule.Annotations[constant.LastAppliedConfigAnnotationKey] == "" && !enable { + if s.BackupSchedule.Annotations[dptypes.LastAppliedConfigsAnnotationKey] == "" && !enable { // disable in the first policy created, no need reconfigure because default configs had been set. return nil } @@ -392,9 +416,13 @@ func (s *Scheduler) reconfigure(schedulePolicy *dpv1alpha1.SchedulePolicy) error // skip reconfigure if not found parameters. return nil } + lastAppliedConfigsMap, err := s.getLastAppliedConfigsMap() + if err != nil { + return err + } updateParameterPairsBytes, _ := json.Marshal(parameters) updateParameterPairs := string(updateParameterPairsBytes) - if updateParameterPairs == s.BackupSchedule.Annotations[constant.LastAppliedConfigAnnotationKey] { + if updateParameterPairs == lastAppliedConfigsMap[schedulePolicy.BackupMethod] { // reconcile the config job if finished return s.reconcileReconfigure(s.BackupSchedule) } @@ -450,7 +478,12 @@ func (s *Scheduler) reconfigure(schedulePolicy *dpv1alpha1.SchedulePolicy) error if s.BackupSchedule.Annotations == nil { s.BackupSchedule.Annotations = map[string]string{} } - s.BackupSchedule.Annotations[constant.LastAppliedConfigAnnotationKey] = updateParameterPairs + lastAppliedConfigsMap[schedulePolicy.BackupMethod] = updateParameterPairs + updateParameterPairsBytes, _ = json.Marshal(lastAppliedConfigsMap) + s.BackupSchedule.Annotations[dptypes.LastAppliedConfigsAnnotationKey] = string(updateParameterPairsBytes) + if _, ok := s.BackupSchedule.Annotations[constant.LastAppliedConfigAnnotationKey]; ok { + delete(s.BackupSchedule.Annotations, constant.LastAppliedConfigAnnotationKey) + } if err := s.Client.Patch(s.Ctx, s.BackupSchedule, patch); err != nil { return err } diff --git a/pkg/dataprotection/types/constant.go b/pkg/dataprotection/types/constant.go index 558bba53a84..1b74f18bda6 100644 --- a/pkg/dataprotection/types/constant.go +++ b/pkg/dataprotection/types/constant.go @@ -62,6 +62,8 @@ const ( ConnectionPasswordAnnotationKey = "dataprotection.kubeblocks.io/connection-password" // GeminiAcknowledgedAnnotationKey indicates whether Gemini has acknowledged the backup. GeminiAcknowledgedAnnotationKey = "dataprotection.kubeblocks.io/gemini-acknowledged" + // LastAppliedConfigsAnnotationKey specifies last applied reconfigurations. + LastAppliedConfigsAnnotationKey = "dataprotection.kubeblocks.io/last-applied-configurations" ) // label keys From d38145c0ebf4d7e8675360f47b1ef7d4836ea95e Mon Sep 17 00:00:00 2001 From: wangyelei Date: Thu, 23 Jan 2025 14:40:22 +0800 Subject: [PATCH 2/5] tidy up code --- .../apps/transformer_cluster_backup_policy.go | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/controllers/apps/transformer_cluster_backup_policy.go b/controllers/apps/transformer_cluster_backup_policy.go index 5ad1881c24c..57f07f6ddaa 100644 --- a/controllers/apps/transformer_cluster_backup_policy.go +++ b/controllers/apps/transformer_cluster_backup_policy.go @@ -672,8 +672,11 @@ func (r *clusterBackupPolicyTransformer) mergeClusterBackup( r.Error(err, "failed to get ActionSet for backup.", "ActionSet", as.Name) continue } - switch { - case as.Spec.BackupType == dpv1alpha1.BackupTypeContinuous && backup.PITREnabled != nil: + switch as.Spec.BackupType { + case dpv1alpha1.BackupTypeContinuous: + if backup.PITREnabled == nil { + continue + } if boolptr.IsSetToFalse(backup.PITREnabled) || hasSyncPITRMethod || (len(backup.ContinuousMethod) > 0 && backup.ContinuousMethod != s.BackupMethod) { s.Enabled = boolptr.False() @@ -685,7 +688,7 @@ func (r *clusterBackupPolicyTransformer) mergeClusterBackup( s.RetentionPeriod = backup.RetentionPeriod } hasSyncPITRMethod = true - case as.Spec.BackupType == dpv1alpha1.BackupTypeIncremental: + case dpv1alpha1.BackupTypeIncremental: if len(backup.Method) == 0 || m.CompatibleMethod != backup.Method { // disable other incremental backup schedules backupSchedule.Spec.Schedules[i].Enabled = boolptr.False() @@ -698,9 +701,11 @@ func (r *clusterBackupPolicyTransformer) mergeClusterBackup( }, &backupSchedule.Spec.Schedules[i]) hasSyncIncMethod = true } - case as.Spec.BackupType == dpv1alpha1.BackupTypeFull && enableAutoBackup: - // disable the automatic backup for other full backup method - s.Enabled = boolptr.False() + case dpv1alpha1.BackupTypeFull: + if enableAutoBackup { + // disable the automatic backup for other full backup method + s.Enabled = boolptr.False() + } } } if !exist { From 6190e3ed9151bc1cc5151d67d26b1f37af768d23 Mon Sep 17 00:00:00 2001 From: wangyelei Date: Thu, 23 Jan 2025 14:55:58 +0800 Subject: [PATCH 3/5] fix bug --- pkg/dataprotection/backup/scheduler.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pkg/dataprotection/backup/scheduler.go b/pkg/dataprotection/backup/scheduler.go index 7f4bbf2dcdc..c9f426178d1 100644 --- a/pkg/dataprotection/backup/scheduler.go +++ b/pkg/dataprotection/backup/scheduler.go @@ -481,9 +481,7 @@ func (s *Scheduler) reconfigure(schedulePolicy *dpv1alpha1.SchedulePolicy) error lastAppliedConfigsMap[schedulePolicy.BackupMethod] = updateParameterPairs updateParameterPairsBytes, _ = json.Marshal(lastAppliedConfigsMap) s.BackupSchedule.Annotations[dptypes.LastAppliedConfigsAnnotationKey] = string(updateParameterPairsBytes) - if _, ok := s.BackupSchedule.Annotations[constant.LastAppliedConfigAnnotationKey]; ok { - delete(s.BackupSchedule.Annotations, constant.LastAppliedConfigAnnotationKey) - } + delete(s.BackupSchedule.Annotations, constant.LastAppliedConfigAnnotationKey) if err := s.Client.Patch(s.Ctx, s.BackupSchedule, patch); err != nil { return err } From 0f05bdaaddd52e86011aea2dcf30da96e13e65c1 Mon Sep 17 00:00:00 2001 From: wangyelei Date: Thu, 23 Jan 2025 15:02:36 +0800 Subject: [PATCH 4/5] fix --- controllers/apps/transformer_cluster_backup_policy.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/apps/transformer_cluster_backup_policy.go b/controllers/apps/transformer_cluster_backup_policy.go index 57f07f6ddaa..a59f11ed177 100644 --- a/controllers/apps/transformer_cluster_backup_policy.go +++ b/controllers/apps/transformer_cluster_backup_policy.go @@ -688,7 +688,7 @@ func (r *clusterBackupPolicyTransformer) mergeClusterBackup( s.RetentionPeriod = backup.RetentionPeriod } hasSyncPITRMethod = true - case dpv1alpha1.BackupTypeIncremental: + case dpv1alpha1.BackupTypeIncremental: if len(backup.Method) == 0 || m.CompatibleMethod != backup.Method { // disable other incremental backup schedules backupSchedule.Spec.Schedules[i].Enabled = boolptr.False() From 40ba2adc5cbcaf44c702738bcd8d47cec9d45198 Mon Sep 17 00:00:00 2001 From: wangyelei Date: Thu, 23 Jan 2025 16:32:16 +0800 Subject: [PATCH 5/5] fix restore bug --- pkg/dataprotection/restore/utils.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/dataprotection/restore/utils.go b/pkg/dataprotection/restore/utils.go index bea8d944095..7cb74ffd43a 100644 --- a/pkg/dataprotection/restore/utils.go +++ b/pkg/dataprotection/restore/utils.go @@ -293,10 +293,10 @@ func FormatRestoreTimeAndValidate(restoreTimeStr string, continuousBackup *dpv1a restoreTimeStr = restoreTime.UTC().Format(time.RFC3339) // TODO: check with Recoverable time - if continuousBackup.Status.TimeRange == nil || continuousBackup.Status.TimeRange.Start.IsZero() || continuousBackup.Status.TimeRange.End.IsZero() { + if continuousBackup.Status.TimeRange == nil || continuousBackup.GetStartTime().IsZero() || continuousBackup.GetEndTime().IsZero() { return restoreTimeStr, fmt.Errorf("invalid timeRange of the backup") } - if !isTimeInRange(restoreTime, continuousBackup.Status.TimeRange.Start.Time, continuousBackup.Status.TimeRange.End.Time) { + if !isTimeInRange(restoreTime, continuousBackup.GetStartTime().Time, continuousBackup.GetEndTime().Time) { return restoreTimeStr, fmt.Errorf("restore-to-time is out of time range, you can view the recoverable time: \n"+ "\tkbcli cluster describe %s -n %s", continuousBackup.Labels[constant.AppInstanceLabelKey], continuousBackup.Namespace) }