From 1c1fd3049075519d04adc58f9e91222f80a72eaf Mon Sep 17 00:00:00 2001 From: chenfei Date: Wed, 19 Feb 2025 09:44:02 +0000 Subject: [PATCH 01/15] Resolve TODOs for BR on operator v2 --- api/br/v1alpha1/backup.go | 14 -- api/br/v1alpha1/backup_test.go | 97 ++++++++ api/br/v1alpha1/backup_types.go | 2 +- api/core/v1alpha1/names.go | 1 - api/meta/v1alpha1/label.go | 9 +- cmd/backup-manager/app/backup/backup.go | 9 +- cmd/backup-manager/app/cmd/backup.go | 16 ++ cmd/backup-manager/app/cmd/restore.go | 27 +++ cmd/backup-manager/app/restore/restore.go | 8 +- .../br/manager/backup/backup_cleaner.go | 22 -- .../br/manager/backup/backup_manager.go | 22 -- .../manager/backup/backup_status_updater.go | 51 +---- .../br/manager/backup/backup_tracker.go | 6 +- .../br/manager/restore/restore_manager.go | 3 +- .../manager/restore/restore_status_updater.go | 50 +---- pkg/controllers/br/manager/util/cluster.go | 19 ++ pkg/controllers/br/manager/util/util.go | 47 +++- pkg/controllers/br/manager/util/util2.go | 6 - pkg/controllers/br/manager/util/util2_test.go | 210 ++++++++++++++++++ 19 files changed, 440 insertions(+), 179 deletions(-) create mode 100644 api/br/v1alpha1/backup_test.go create mode 100644 pkg/controllers/br/manager/util/util2_test.go diff --git a/api/br/v1alpha1/backup.go b/api/br/v1alpha1/backup.go index 0ece9f0a19..307d3ce881 100644 --- a/api/br/v1alpha1/backup.go +++ b/api/br/v1alpha1/backup.go @@ -68,19 +68,6 @@ func (bk *Backup) GetAllLogBackupJobName() []string { } } -// TODO(ideascf): do we need these functions? -// // GetTidbEndpointHash return the hash string base on tidb cluster's host and port -// -// func (bk *Backup) GetTidbEndpointHash() string { -// return HashContents([]byte(bk.Spec.From.GetTidbEndpoint())) -// } -// -// // GetBackupPVCName return the backup pvc name -// -// func (bk *Backup) GetBackupPVCName() string { -// return fmt.Sprintf("backup-pvc-%s", bk.GetTidbEndpointHash()) -// } -// // GetInstanceName return the backup instance name func (bk *Backup) GetInstanceName() string { if bk.Labels != nil { @@ -121,7 +108,6 @@ var ( RestoreControllerKind = SchemeGroupVersion.WithKind("Restore") ) -// TODO(ideascf): copy UT // GetBackupOwnerRef returns Backup's OwnerReference func GetBackupOwnerRef(backup *Backup) metav1.OwnerReference { controller := true diff --git a/api/br/v1alpha1/backup_test.go b/api/br/v1alpha1/backup_test.go new file mode 100644 index 0000000000..b6a38fdcc0 --- /dev/null +++ b/api/br/v1alpha1/backup_test.go @@ -0,0 +1,97 @@ +package v1alpha1 + +import ( + "testing" + + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + + metav1alpha1 "github.com/pingcap/tidb-operator/api/v2/meta/v1alpha1" +) + +func TestGetBackupOwnerRef(t *testing.T) { + g := NewGomegaWithT(t) + + b := newBackup() + b.UID = types.UID("demo-uid") + ref := GetBackupOwnerRef(b) + g.Expect(ref.APIVersion).To(Equal(BackupControllerKind.GroupVersion().String())) + g.Expect(ref.Kind).To(Equal(BackupControllerKind.Kind)) + g.Expect(ref.Name).To(Equal(b.GetName())) + g.Expect(ref.UID).To(Equal(types.UID("demo-uid"))) + g.Expect(*ref.Controller).To(BeTrue()) + g.Expect(*ref.BlockOwnerDeletion).To(BeTrue()) +} + +func TestGetRestoreOwnerRef(t *testing.T) { + g := NewGomegaWithT(t) + + r := newRestore() + r.UID = types.UID("demo-uid") + ref := GetRestoreOwnerRef(r) + g.Expect(ref.APIVersion).To(Equal(RestoreControllerKind.GroupVersion().String())) + g.Expect(ref.Kind).To(Equal(RestoreControllerKind.Kind)) + g.Expect(ref.Name).To(Equal(r.GetName())) + g.Expect(ref.UID).To(Equal(types.UID("demo-uid"))) + g.Expect(*ref.Controller).To(BeTrue()) + g.Expect(*ref.BlockOwnerDeletion).To(BeTrue()) +} + +func TestGetBackupScheduleOwnerRef(t *testing.T) { + g := NewGomegaWithT(t) + + b := newBackupSchedule() + b.UID = types.UID("demo-uid") + ref := GetBackupScheduleOwnerRef(b) + g.Expect(ref.APIVersion).To(Equal(backupScheduleControllerKind.GroupVersion().String())) + g.Expect(ref.Kind).To(Equal(backupScheduleControllerKind.Kind)) + g.Expect(ref.Name).To(Equal(b.GetName())) + g.Expect(ref.UID).To(Equal(types.UID("demo-uid"))) + g.Expect(*ref.Controller).To(BeTrue()) + g.Expect(*ref.BlockOwnerDeletion).To(BeTrue()) +} + +func newBackup() *Backup { + backup := &Backup{ + ObjectMeta: metav1.ObjectMeta{ + Name: "demo-backup", + Namespace: metav1.NamespaceDefault, + Labels: map[string]string{ + metav1alpha1.NameLabelKey: metav1alpha1.BackupJobLabelVal, + }, + }, + Spec: BackupSpec{}, + } + return backup +} + +func newRestore() *Restore { + restore := &Restore{ + ObjectMeta: metav1.ObjectMeta{ + Name: "demo-backup", + Namespace: metav1.NamespaceDefault, + Labels: map[string]string{ + metav1alpha1.NameLabelKey: metav1alpha1.RestoreJobLabelVal, + }, + }, + Spec: RestoreSpec{}, + } + return restore +} + +func newBackupSchedule() *BackupSchedule { + backup := &BackupSchedule{ + ObjectMeta: metav1.ObjectMeta{ + Name: "demo-backup", + Namespace: metav1.NamespaceDefault, + Labels: map[string]string{ + metav1alpha1.NameLabelKey: metav1alpha1.BackupScheduleJobLabelVal, + }, + }, + Spec: BackupScheduleSpec{ + BackupTemplate: BackupSpec{}, + }, + } + return backup +} diff --git a/api/br/v1alpha1/backup_types.go b/api/br/v1alpha1/backup_types.go index e3c6daf469..4a9db04a5a 100644 --- a/api/br/v1alpha1/backup_types.go +++ b/api/br/v1alpha1/backup_types.go @@ -259,7 +259,7 @@ type Progress struct { // Step is the step name of progress Step string `json:"step,omitempty"` // Progress is the backup progress value - Progress int `json:"progress,omitempty"` // TODO(ideascf): type changed from float64 to int + Progress int `json:"progress,omitempty"` // LastTransitionTime is the update time // +nullable LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"` diff --git a/api/core/v1alpha1/names.go b/api/core/v1alpha1/names.go index 4ca09cf8cc..c9907a4e70 100644 --- a/api/core/v1alpha1/names.go +++ b/api/core/v1alpha1/names.go @@ -90,7 +90,6 @@ const ( DirPathClusterTLSPD = "/var/lib/pd-tls" DirPathClusterTLSTiKV = "/var/lib/tikv-tls" DirPathClusterTLSTiDB = "/var/lib/tidb-tls" - DirPathTiDBClientTLS = "/var/lib/tidb-client-tls" // FIXME(ideascf): do we need this? DirPathClusterTLSTiFlash = "/var/lib/tiflash-tls" DirPathClusterClientTLS = "/var/lib/cluster-client-tls" DirPathClusterTLSTiCDC = "/var/lib/ticdc-tls" diff --git a/api/meta/v1alpha1/label.go b/api/meta/v1alpha1/label.go index 5f7d40e25e..c52e5143e2 100644 --- a/api/meta/v1alpha1/label.go +++ b/api/meta/v1alpha1/label.go @@ -20,7 +20,8 @@ const ( KeyPrefix = "pingcap.com/" // LabelKeyManagedBy means resources are managed by tidb operator - LabelKeyManagedBy = KeyPrefix + "managed-by" + LabelKeyManagedBy = KeyPrefix + "managed-by" + LabelValueManagedByOperator = "tidb-operator" ) const ( @@ -103,7 +104,7 @@ func (l Label) Restore(val string) Label { func NewBackup() Label { return Label{ NameLabelKey: BackupJobLabelVal, - LabelKeyManagedBy: "backup-operator", // TODO(ideascf): change to tidb-operator?? + LabelKeyManagedBy: LabelValueManagedByOperator, } } @@ -111,7 +112,7 @@ func NewBackup() Label { func NewRestore() Label { return Label{ NameLabelKey: RestoreJobLabelVal, - LabelKeyManagedBy: "restore-operator", + LabelKeyManagedBy: LabelValueManagedByOperator, } } @@ -119,6 +120,6 @@ func NewRestore() Label { func NewBackupSchedule() Label { return Label{ NameLabelKey: BackupScheduleJobLabelVal, - LabelKeyManagedBy: "backup-schedule-operator", + LabelKeyManagedBy: LabelValueManagedByOperator, } } diff --git a/cmd/backup-manager/app/backup/backup.go b/cmd/backup-manager/app/backup/backup.go index 1f22d07949..2a477c111f 100644 --- a/cmd/backup-manager/app/backup/backup.go +++ b/cmd/backup-manager/app/backup/backup.go @@ -36,6 +36,8 @@ import ( // Options contains the input arguments to the backup command type Options struct { backupUtil.GenericOptions + // PDAddress is the address of the PD, for example: db-pd.tidb12345:2379 + PDAddress string } // backupData generates br args and runs br binary to do the real backup work @@ -177,13 +179,8 @@ func (bo *Options) backupCommandTemplate(backup *v1alpha1.Backup, specificArgs [ return nil, fmt.Errorf("backup command is invalid, Args: %v", specificArgs) } - clusterNamespace := backup.Spec.BR.ClusterNamespace - if backup.Spec.BR.ClusterNamespace == "" { - clusterNamespace = backup.Namespace - } args := make([]string, 0) - // TODO(ideascf): use PDGroupClientPort? - args = append(args, fmt.Sprintf("--pd=%s-pd.%s:%d", backup.Spec.BR.Cluster, clusterNamespace, corev1alpha1.DefaultPDPortClient)) + args = append(args, fmt.Sprintf("--pd=%s", bo.PDAddress)) if bo.TLSCluster { args = append(args, fmt.Sprintf("--ca=%s", path.Join(corev1alpha1.DirPathClusterClientTLS, corev1.ServiceAccountRootCAKey))) args = append(args, fmt.Sprintf("--cert=%s", path.Join(corev1alpha1.DirPathClusterClientTLS, corev1.TLSCertKey))) diff --git a/cmd/backup-manager/app/cmd/backup.go b/cmd/backup-manager/app/cmd/backup.go index ec1b8f2fc2..b82add503b 100644 --- a/cmd/backup-manager/app/cmd/backup.go +++ b/cmd/backup-manager/app/cmd/backup.go @@ -88,6 +88,13 @@ func runBackup(backupOpts backup.Options, kubecfg string) error { return err } + // set PD Address + pdAddress, err := getPDAddressForBackup(newcli, backupOpts) + if err != nil { + return err + } + backupOpts.PDAddress = pdAddress + recorder := record.NewBroadcaster().NewRecorder(scheme.Scheme, corev1.EventSource{Component: "backup"}) statusUpdater := backupMgr.NewRealBackupConditionUpdater(newcli, recorder) klog.Infof("start to process backup %s", backupOpts.String()) @@ -143,3 +150,12 @@ func newClient(ctx context.Context, cfg *rest.Config, s *runtime.Scheme, disable return c, nil } + +func getPDAddressForBackup(cli client.Client, bo backup.Options) (string, error) { + b := &v1alpha1.Backup{} + err := cli.Get(context.Background(), client.ObjectKey{Namespace: bo.Namespace, Name: bo.ResourceName}, b) + if err != nil { + return "", err + } + return getPDAddress(cli, b.Spec.BR.ClusterNamespace, b.Spec.BR.Cluster) +} diff --git a/cmd/backup-manager/app/cmd/restore.go b/cmd/backup-manager/app/cmd/restore.go index c3cac0d610..df59a9c814 100644 --- a/cmd/backup-manager/app/cmd/restore.go +++ b/cmd/backup-manager/app/cmd/restore.go @@ -16,6 +16,7 @@ package cmd import ( "context" + "fmt" // registry mysql drive _ "github.com/go-sql-driver/mysql" @@ -31,7 +32,9 @@ import ( "github.com/pingcap/tidb-operator/api/v2/br/v1alpha1" "github.com/pingcap/tidb-operator/cmd/backup-manager/app/restore" "github.com/pingcap/tidb-operator/cmd/backup-manager/app/util" + coreutil "github.com/pingcap/tidb-operator/pkg/apiutil/core/v1alpha1" restoreMgr "github.com/pingcap/tidb-operator/pkg/controllers/br/manager/restore" + brutil "github.com/pingcap/tidb-operator/pkg/controllers/br/manager/util" "github.com/pingcap/tidb-operator/pkg/scheme" ) @@ -81,9 +84,33 @@ func runRestore(restoreOpts restore.Options, kubecfg string) error { return err } + // set PD Address + pdAddress, err := getPDAddressForRestore(newcli, restoreOpts) + if err != nil { + return err + } + restoreOpts.PDAddress = pdAddress + recorder := record.NewBroadcaster().NewRecorder(scheme.Scheme, corev1.EventSource{Component: "restore"}) statusUpdater := restoreMgr.NewRealRestoreConditionUpdater(newcli, recorder) klog.Infof("start to process restore %s", restoreOpts.String()) rm := restore.NewManager(newcli, statusUpdater, restoreOpts) return rm.ProcessRestore() } + +func getPDAddressForRestore(cli client.Client, ro restore.Options) (string, error) { + r := &v1alpha1.Restore{} + err := cli.Get(context.Background(), client.ObjectKey{Namespace: ro.Namespace, Name: ro.ResourceName}, r) + if err != nil { + return "", err + } + return getPDAddress(cli, r.Spec.BR.ClusterNamespace, r.Spec.BR.Cluster) +} + +func getPDAddress(cli client.Client, clusterNs, clusterName string) (string, error) { + pdg, err := brutil.FirstPDGroup(cli, clusterNs, clusterName) + if err != nil { + return "", err + } + return fmt.Sprintf("%s-pd.%s:%d", pdg.Spec.Cluster.Name, pdg.Namespace, coreutil.PDGroupClientPort(pdg)), nil +} diff --git a/cmd/backup-manager/app/restore/restore.go b/cmd/backup-manager/app/restore/restore.go index f7576f6a9c..aeaa30fc0b 100644 --- a/cmd/backup-manager/app/restore/restore.go +++ b/cmd/backup-manager/app/restore/restore.go @@ -50,6 +50,8 @@ type Options struct { TargetAZ string // UseFSR to indicate if use FSR for TiKV data volumes during EBS snapshot restore UseFSR bool + // PDAddress is the address of the PD, for example: db-pd.tidb12345:2379 + PDAddress string } // nolint: gocyclo @@ -58,12 +60,8 @@ func (ro *Options) restoreData( restore *v1alpha1.Restore, statusUpdater restore.RestoreConditionUpdaterInterface, ) error { - clusterNamespace := restore.Spec.BR.ClusterNamespace - if restore.Spec.BR.ClusterNamespace == "" { - clusterNamespace = restore.Namespace - } args := make([]string, 0) - args = append(args, fmt.Sprintf("--pd=%s-pd.%s:%d", restore.Spec.BR.Cluster, clusterNamespace, corev1alpha1.DefaultPDPortClient)) + args = append(args, fmt.Sprintf("--pd=%s", ro.PDAddress)) if ro.TLSCluster { args = append(args, fmt.Sprintf("--ca=%s", path.Join(corev1alpha1.DirPathClusterClientTLS, corev1.ServiceAccountRootCAKey))) args = append(args, fmt.Sprintf("--cert=%s", path.Join(corev1alpha1.DirPathClusterClientTLS, corev1.TLSCertKey))) diff --git a/pkg/controllers/br/manager/backup/backup_cleaner.go b/pkg/controllers/br/manager/backup/backup_cleaner.go index e9a887b7f9..73ff63ed86 100644 --- a/pkg/controllers/br/manager/backup/backup_cleaner.go +++ b/pkg/controllers/br/manager/backup/backup_cleaner.go @@ -400,28 +400,6 @@ func (bc *backupCleaner) makeStopLogBackupJob(backup *v1alpha1.Backup) (*batchv1 }) } - // TODO(ideascf): do we need do client-tls for tidb? - // if backup.Spec.From != nil && tc.Spec.TiDB != nil && tc.Spec.TiDB.TLSClient != nil && tc.Spec.TiDB.TLSClient.Enabled && !tc.SkipTLSWhenConnectTiDB() { - // args = append(args, "--client-tls=true") - // if tc.Spec.TiDB.TLSClient.SkipInternalClientCA { - // args = append(args, "--skipClientCA=true") - // } - - // volumeMounts = append(volumeMounts, corev1.VolumeMount{ - // Name: "tidb-client-tls", - // ReadOnly: true, - // MountPath: corev1alpha1.DirPathClusterTLSTiDB, - // }) - // volumes = append(volumes, corev1.Volume{ - // Name: "tidb-client-tls", - // VolumeSource: corev1.VolumeSource{ - // Secret: &corev1.SecretVolumeSource{ - // SecretName: util.TiDBClientTLSSecretName(backup.Spec.BR.Cluster, backup.Spec.From.TLSClientSecretName), - // }, - // }, - // }) - // } - brVolumeMount := corev1.VolumeMount{ Name: "br-bin", ReadOnly: false, diff --git a/pkg/controllers/br/manager/backup/backup_manager.go b/pkg/controllers/br/manager/backup/backup_manager.go index ee77183a5e..d2bd6a243e 100644 --- a/pkg/controllers/br/manager/backup/backup_manager.go +++ b/pkg/controllers/br/manager/backup/backup_manager.go @@ -467,28 +467,6 @@ func (bm *backupManager) makeBRBackupJob(backup *v1alpha1.Backup) (*batchv1.Job, }) } - // TODO(ideascf): do we need do client-tls for tidb? - // if backup.Spec.From != nil && tc.Spec.TiDB != nil && tc.Spec.TiDB.TLSClient != nil && tc.Spec.TiDB.TLSClient.Enabled && !tc.SkipTLSWhenConnectTiDB() { - // args = append(args, "--client-tls=true") - // if tc.Spec.TiDB.TLSClient.SkipInternalClientCA { - // args = append(args, "--skipClientCA=true") - // } - - // volumeMounts = append(volumeMounts, corev1.VolumeMount{ - // Name: "tidb-client-tls", - // ReadOnly: true, - // MountPath: util.TiDBClientTLSPath, - // }) - // volumes = append(volumes, corev1.Volume{ - // Name: "tidb-client-tls", - // VolumeSource: corev1.VolumeSource{ - // Secret: &corev1.SecretVolumeSource{ - // SecretName: util.TiDBClientTLSSecretName(backup.Spec.BR.Cluster, backup.Spec.From.TLSClientSecretName), - // }, - // }, - // }) - // } - brVolumeMount := corev1.VolumeMount{ Name: "br-bin", ReadOnly: false, diff --git a/pkg/controllers/br/manager/backup/backup_status_updater.go b/pkg/controllers/br/manager/backup/backup_status_updater.go index 5ba5c826e8..a171b08e01 100644 --- a/pkg/controllers/br/manager/backup/backup_status_updater.go +++ b/pkg/controllers/br/manager/backup/backup_status_updater.go @@ -27,6 +27,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "github.com/pingcap/tidb-operator/api/v2/br/v1alpha1" + "github.com/pingcap/tidb-operator/pkg/controllers/br/manager/util" ) // BackupConditionUpdaterInterface enables updating Backup conditions. @@ -51,7 +52,7 @@ func NewRealBackupConditionUpdater( } func (u *realBackupConditionUpdater) Update(backup *v1alpha1.Backup, condition *v1alpha1.BackupCondition, newStatus *BackupUpdateStatus) error { - // TODO(ideascf): set reason for all + // reason is required so that we do set if it's empty if condition != nil { if condition.Reason == "" { condition.Reason = condition.Type @@ -66,7 +67,7 @@ func (u *realBackupConditionUpdater) Update(backup *v1alpha1.Backup, condition * currentBackup := &v1alpha1.Backup{} if err := u.cli.Get(context.TODO(), client.ObjectKey{Namespace: ns, Name: backupName}, currentBackup); err == nil { // make a copy so we don't mutate the shared cache - *backup = *(currentBackup.DeepCopy()) // TODO(ideascf): do we need to deep copy or just assign? + *backup = *(currentBackup.DeepCopy()) } else { utilruntime.HandleError(fmt.Errorf("error getting updated backup %s/%s from lister: %w", ns, backupName, err)) return err @@ -134,7 +135,7 @@ func updateBackupStatus(status *v1alpha1.BackupStatus, newStatus *BackupUpdateSt isUpdate = true } if newStatus.ProgressStep != nil { - progresses, updated := updateBRProgress(status.Progresses, newStatus.ProgressStep, newStatus.Progress, newStatus.ProgressUpdateTime) + progresses, updated := util.UpdateBRProgress(status.Progresses, newStatus.ProgressStep, newStatus.Progress, newStatus.ProgressUpdateTime) if updated { status.Progresses = progresses isUpdate = true @@ -424,50 +425,6 @@ func updateLogSubCommandConditionOnly(status *v1alpha1.LogSubCommandStatus, cond return isUpdate } -// updateBRProgress updates progress for backup/restore. -func updateBRProgress(progresses []v1alpha1.Progress, step *string, progress *int, updateTime *metav1.Time) ([]v1alpha1.Progress, bool) { - var oldProgress *v1alpha1.Progress - for i, p := range progresses { - if p.Step == *step { - oldProgress = &progresses[i] - break - } - } - - makeSureLastProgressOver := func() { - size := len(progresses) - if size == 0 || progresses[size-1].Progress >= 100 { - return - } - progresses[size-1].Progress = 100 - progresses[size-1].LastTransitionTime = metav1.Time{Time: time.Now()} - } - - // no such progress, will new - if oldProgress == nil { - makeSureLastProgressOver() - progresses = append(progresses, v1alpha1.Progress{ - Step: *step, - Progress: *progress, - LastTransitionTime: *updateTime, - }) - return progresses, true - } - - isUpdate := false - if oldProgress.Progress < *progress { - oldProgress.Progress = *progress - isUpdate = true - } - - if oldProgress.LastTransitionTime != *updateTime { - oldProgress.LastTransitionTime = *updateTime - isUpdate = true - } - - return progresses, isUpdate -} - // nolint: gocyclo func updateBackoffRetryStatus(status *v1alpha1.BackupStatus, newStatus *BackupUpdateStatus) bool { isUpdate := false diff --git a/pkg/controllers/br/manager/backup/backup_tracker.go b/pkg/controllers/br/manager/backup/backup_tracker.go index 85ff8c5554..64565cf49d 100644 --- a/pkg/controllers/br/manager/backup/backup_tracker.go +++ b/pkg/controllers/br/manager/backup/backup_tracker.go @@ -24,6 +24,7 @@ import ( "time" "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/util/retry" "k8s.io/klog/v2" @@ -120,9 +121,12 @@ func (bt *backupTracker) StartTrackLogBackupProgress(backup *v1alpha1.Backup) er return nil } klog.Infof("add log backup %s/%s to tracker", ns, name) - // TODO(ideascf): do we need this? _, err := bt.getLogBackupTC(backup) if err != nil { + if apierrors.IsNotFound(err) { + klog.Infof("log backup %s/%s cluster %s/%s not found, will skip", ns, name, backup.Spec.BR.ClusterNamespace, backup.Spec.BR.Cluster) + return nil + } return err } bt.logBackups[logkey] = true diff --git a/pkg/controllers/br/manager/restore/restore_manager.go b/pkg/controllers/br/manager/restore/restore_manager.go index 2e354b7450..1e02db4dc0 100644 --- a/pkg/controllers/br/manager/restore/restore_manager.go +++ b/pkg/controllers/br/manager/restore/restore_manager.go @@ -105,8 +105,7 @@ func (rm *restoreManager) syncRestoreJob(restore *v1alpha1.Restore) error { return fmt.Errorf("failed to get first tikv group: %w", err) } - err = backuputil.ValidateRestore(restore, tikvGroup.Spec.Template.Spec.Version, false) // TODO(ideascf): cluster.Spec.AcrossK8s? - // } + err = backuputil.ValidateRestore(restore, tikvGroup.Spec.Template.Spec.Version) if err != nil { _ = rm.statusUpdater.Update(restore, &metav1.Condition{ Type: string(v1alpha1.RestoreInvalid), diff --git a/pkg/controllers/br/manager/restore/restore_status_updater.go b/pkg/controllers/br/manager/restore/restore_status_updater.go index 9853e6a039..8310c2ec75 100644 --- a/pkg/controllers/br/manager/restore/restore_status_updater.go +++ b/pkg/controllers/br/manager/restore/restore_status_updater.go @@ -27,6 +27,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "github.com/pingcap/tidb-operator/api/v2/br/v1alpha1" + "github.com/pingcap/tidb-operator/pkg/controllers/br/manager/util" ) // RestoreUpdateStatus represents the status of a restore to be updated. @@ -68,7 +69,7 @@ func NewRealRestoreConditionUpdater( } func (u *realRestoreConditionUpdater) Update(restore *v1alpha1.Restore, condition *metav1.Condition, newStatus *RestoreUpdateStatus) error { - // TODO(ideascf): set reason for all + // reason is required so that we do set if it's empty if condition != nil { if condition.Reason == "" { condition.Reason = condition.Type @@ -127,7 +128,7 @@ func updateRestoreStatus(status *v1alpha1.RestoreStatus, newStatus *RestoreUpdat isUpdate = true } if newStatus.ProgressStep != nil { - progresses, updated := updateBRProgress(status.Progresses, newStatus.ProgressStep, newStatus.Progress, newStatus.ProgressUpdateTime) + progresses, updated := util.UpdateBRProgress(status.Progresses, newStatus.ProgressStep, newStatus.Progress, newStatus.ProgressUpdateTime) if updated { status.Progresses = progresses isUpdate = true @@ -137,49 +138,4 @@ func updateRestoreStatus(status *v1alpha1.RestoreStatus, newStatus *RestoreUpdat return isUpdate } -// TODO(ideascf): this function is copied from backup_status_updater.go, we should refactor it. -// updateBRProgress updates progress for backup/restore. -func updateBRProgress(progresses []v1alpha1.Progress, step *string, progress *int, updateTime *metav1.Time) ([]v1alpha1.Progress, bool) { - var oldProgress *v1alpha1.Progress - for i, p := range progresses { - if p.Step == *step { - oldProgress = &progresses[i] - break - } - } - - makeSureLastProgressOver := func() { - size := len(progresses) - if size == 0 || progresses[size-1].Progress >= 100 { - return - } - progresses[size-1].Progress = 100 - progresses[size-1].LastTransitionTime = metav1.Time{Time: time.Now()} - } - - // no such progress, will new - if oldProgress == nil { - makeSureLastProgressOver() - progresses = append(progresses, v1alpha1.Progress{ - Step: *step, - Progress: *progress, - LastTransitionTime: *updateTime, - }) - return progresses, true - } - - isUpdate := false - if oldProgress.Progress < *progress { - oldProgress.Progress = *progress - isUpdate = true - } - - if oldProgress.LastTransitionTime != *updateTime { - oldProgress.LastTransitionTime = *updateTime - isUpdate = true - } - - return progresses, isUpdate -} - var _ RestoreConditionUpdaterInterface = &realRestoreConditionUpdater{} diff --git a/pkg/controllers/br/manager/util/cluster.go b/pkg/controllers/br/manager/util/cluster.go index e030aef7f7..52ca6ad135 100644 --- a/pkg/controllers/br/manager/util/cluster.go +++ b/pkg/controllers/br/manager/util/cluster.go @@ -17,6 +17,7 @@ package util import ( "context" "fmt" + "sort" "sigs.k8s.io/controller-runtime/pkg/client" @@ -33,6 +34,24 @@ func FirstTikvGroup(cli client.Client, ns, cluster string) (*v1alpha1.TiKVGroup, if len(tikvGroups) == 0 { return nil, fmt.Errorf("no tikv groups found in cluster %s", cluster) } + sort.Slice(tikvGroups, func(i, j int) bool { + return tikvGroups[i].CreationTimestamp.Before(&tikvGroups[j].CreationTimestamp) + }) tikvGroup := tikvGroups[0] return tikvGroup, nil } + +func FirstPDGroup(cli client.Client, ns, cluster string) (*v1alpha1.PDGroup, error) { + pdGroups, err := apicall.ListGroups[scope.PDGroup](context.TODO(), cli, ns, cluster) + if err != nil { + return nil, fmt.Errorf("failed to list pd groups: %w", err) + } + if len(pdGroups) == 0 { + return nil, fmt.Errorf("no pd groups found in cluster %s", cluster) + } + sort.Slice(pdGroups, func(i, j int) bool { + return pdGroups[i].CreationTimestamp.Before(&pdGroups[j].CreationTimestamp) + }) + pdGroup := pdGroups[0] + return pdGroup, nil +} diff --git a/pkg/controllers/br/manager/util/util.go b/pkg/controllers/br/manager/util/util.go index b0b873a4cc..977f09273b 100644 --- a/pkg/controllers/br/manager/util/util.go +++ b/pkg/controllers/br/manager/util/util.go @@ -24,6 +24,7 @@ import ( "unsafe" corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" brv1alpha1 "github.com/pingcap/tidb-operator/api/v2/br/v1alpha1" @@ -521,7 +522,7 @@ func ValidateBackup(backup *brv1alpha1.Backup, tikvVersion string, cluster *core // nolint: gocyclo // ValidateRestore checks whether a restore spec is valid. -func ValidateRestore(restore *brv1alpha1.Restore, tikvVersion string, acrossK8s bool) error { +func ValidateRestore(restore *brv1alpha1.Restore, tikvVersion string) error { ns := restore.Namespace name := restore.Name @@ -689,3 +690,47 @@ func GetOptions(provider brv1alpha1.StorageProvider) []string { return nil } } + +// updateBRProgress updates progress for backup/restore. +func UpdateBRProgress(progresses []brv1alpha1.Progress, step *string, progress *int, updateTime *metav1.Time) ([]brv1alpha1.Progress, bool) { + var oldProgress *brv1alpha1.Progress + for i, p := range progresses { + if p.Step == *step { + oldProgress = &progresses[i] + break + } + } + + makeSureLastProgressOver := func() { + size := len(progresses) + if size == 0 || progresses[size-1].Progress >= 100 { + return + } + progresses[size-1].Progress = 100 + progresses[size-1].LastTransitionTime = metav1.Time{Time: time.Now()} + } + + // no such progress, will new + if oldProgress == nil { + makeSureLastProgressOver() + progresses = append(progresses, brv1alpha1.Progress{ + Step: *step, + Progress: *progress, + LastTransitionTime: *updateTime, + }) + return progresses, true + } + + isUpdate := false + if oldProgress.Progress < *progress { + oldProgress.Progress = *progress + isUpdate = true + } + + if oldProgress.LastTransitionTime != *updateTime { + oldProgress.LastTransitionTime = *updateTime + isUpdate = true + } + + return progresses, isUpdate +} diff --git a/pkg/controllers/br/manager/util/util2.go b/pkg/controllers/br/manager/util/util2.go index ad413dd4bc..d1d7a5b594 100644 --- a/pkg/controllers/br/manager/util/util2.go +++ b/pkg/controllers/br/manager/util/util2.go @@ -20,9 +20,6 @@ import ( corev1 "k8s.io/api/core/v1" ) -// NOTE: copy from tidb-operator/pkg/util/ - -// TODO(ideascf): copy UT // AppendOverwriteEnv appends envs b into a and overwrites the envs whose names already exist // in b. // Note that this will not change relative order of envs. @@ -44,7 +41,6 @@ func AppendOverwriteEnv(a []corev1.EnvVar, b []corev1.EnvVar) []corev1.EnvVar { return a } -// TODO(ideascf): copy UT // AppendEnvIfPresent appends the given environment if present func AppendEnvIfPresent(envs []corev1.EnvVar, name string) []corev1.EnvVar { for _, e := range envs { @@ -61,7 +57,6 @@ func AppendEnvIfPresent(envs []corev1.EnvVar, name string) []corev1.EnvVar { return envs } -// TODO(ideascf): copy UT // CombineStringMap merges maps into a new map. // NOTE: if the same key exists in multiple source maps, the value of the first one will be kept. // so we suggest to : @@ -79,7 +74,6 @@ func CombineStringMap(maps ...map[string]string) map[string]string { return r } -// TODO(ideascf): copy UT // CopyStringMap copy annotations to a new string map func CopyStringMap(src map[string]string) map[string]string { if src == nil { diff --git a/pkg/controllers/br/manager/util/util2_test.go b/pkg/controllers/br/manager/util/util2_test.go new file mode 100644 index 0000000000..d2e61745ec --- /dev/null +++ b/pkg/controllers/br/manager/util/util2_test.go @@ -0,0 +1,210 @@ +package util + +import ( + "os" + "testing" + + "github.com/google/go-cmp/cmp" + . "github.com/onsi/gomega" + + corev1 "k8s.io/api/core/v1" +) + +func TestAppendOverwriteEnv(t *testing.T) { + g := NewGomegaWithT(t) + + a := []corev1.EnvVar{ + { + Name: "ak_1", + Value: "ak_1", + }, + { + Name: "ak_2", + Value: "ak_2", + }, + } + b := []corev1.EnvVar{ + { + Name: "bk_1", + Value: "bk_1", + }, + { + Name: "ak_1", + Value: "ak_10", + }, + { + Name: "ak_2", + Value: "ak_20", + }, + { + Name: "bk_2", + Value: "bk_2", + }, + } + + expect := []corev1.EnvVar{ + { + Name: "ak_1", + Value: "ak_10", + }, + { + Name: "ak_2", + Value: "ak_20", + }, + { + Name: "bk_1", + Value: "bk_1", + }, + { + Name: "bk_2", + Value: "bk_2", + }, + } + + get := AppendOverwriteEnv(a, b) + g.Expect(get).Should(Equal(expect)) +} + +func TestAppendEnvIfPresent(t *testing.T) { + tests := []struct { + name string + a []corev1.EnvVar + envs map[string]string + n string + want []corev1.EnvVar + }{ + { + "does not exist", + []corev1.EnvVar{ + { + Name: "foo", + Value: "bar", + }, + }, + nil, + "TEST_ENV", + []corev1.EnvVar{ + { + Name: "foo", + Value: "bar", + }, + }, + }, + { + "does exist", + []corev1.EnvVar{ + { + Name: "foo", + Value: "bar", + }, + }, + map[string]string{ + "TEST_ENV": "TEST_VAL", + }, + "TEST_ENV", + []corev1.EnvVar{ + { + Name: "foo", + Value: "bar", + }, + { + Name: "TEST_ENV", + Value: "TEST_VAL", + }, + }, + }, + { + "already exist", + []corev1.EnvVar{ + { + Name: "foo", + Value: "bar", + }, + { + Name: "TEST_ENV", + Value: "TEST_OLD_VAL", + }, + }, + map[string]string{ + "TEST_ENV": "TEST_VAL", + }, + "TEST_ENV", + []corev1.EnvVar{ + { + Name: "foo", + Value: "bar", + }, + { + Name: "TEST_ENV", + Value: "TEST_OLD_VAL", + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + os.Clearenv() + for k, v := range tt.envs { + os.Setenv(k, v) + } + got := AppendEnvIfPresent(tt.a, tt.n) + if diff := cmp.Diff(tt.want, got); diff != "" { + t.Errorf("unwant (-want, +got): %s", diff) + } + }) + } +} + +func TestCombineStringMap(t *testing.T) { + g := NewGomegaWithT(t) + + a := map[string]string{ + "a": "av", + } + origA := map[string]string{ + "a": "av", + } + b := map[string]string{ + "b": "bv", + } + c := map[string]string{ + "c": "cv", + } + dropped := map[string]string{ + "a": "aov", + } + + expect1 := map[string]string{ + "a": "av", + "b": "bv", + "c": "cv", + } + expect2 := map[string]string{ + "a": "aov", + "b": "bv", + "c": "cv", + } + + res := CombineStringMap(a, b, c, dropped) + g.Expect(res).Should(Equal(expect1)) + g.Expect(a).Should(Equal(origA)) + + res = CombineStringMap(nil, b, c, dropped) + g.Expect(res).Should(Equal(expect2)) + +} + +func TestCopyStringMap(t *testing.T) { + g := NewGomegaWithT(t) + + src := map[string]string{ + "a": "av", + } + + // modify res and check src unchanged + res := CopyStringMap(src) + res["test"] = "v" + res["a"] = "overwrite" + g.Expect(src).Should(Equal(map[string]string{"a": "av"})) +} From 29e0456d3974661126d95e60661430dc2612af84 Mon Sep 17 00:00:00 2001 From: chenfei Date: Wed, 19 Feb 2025 13:46:23 +0000 Subject: [PATCH 02/15] fix BR job command --- pkg/controllers/br/manager/backup/backup_manager.go | 1 + pkg/controllers/br/manager/restore/restore_manager.go | 1 + 2 files changed, 2 insertions(+) diff --git a/pkg/controllers/br/manager/backup/backup_manager.go b/pkg/controllers/br/manager/backup/backup_manager.go index d2bd6a243e..1d988d2511 100644 --- a/pkg/controllers/br/manager/backup/backup_manager.go +++ b/pkg/controllers/br/manager/backup/backup_manager.go @@ -532,6 +532,7 @@ func (bm *backupManager) makeBRBackupJob(backup *v1alpha1.Backup) (*batchv1.Job, { Name: brv1alpha1.LabelValComponentBackup, Image: bm.backupManagerImage, + Command: []string{"/backup-manager"}, Args: args, ImagePullPolicy: corev1.PullIfNotPresent, VolumeMounts: volumeMounts, diff --git a/pkg/controllers/br/manager/restore/restore_manager.go b/pkg/controllers/br/manager/restore/restore_manager.go index 1e02db4dc0..9a557980d1 100644 --- a/pkg/controllers/br/manager/restore/restore_manager.go +++ b/pkg/controllers/br/manager/restore/restore_manager.go @@ -317,6 +317,7 @@ func (rm *restoreManager) makeRestoreJob(restore *v1alpha1.Restore) (*batchv1.Jo { Name: metav1alpha1.RestoreJobLabelVal, Image: rm.backupManagerImage, + Command: []string{"/backup-manager"}, Args: args, ImagePullPolicy: corev1.PullIfNotPresent, VolumeMounts: volumeMounts, From 3eae177ba3b0f7d1c374ba0f1bf864f7f5c6a936 Mon Sep 17 00:00:00 2001 From: chenfei Date: Wed, 19 Feb 2025 14:07:12 +0000 Subject: [PATCH 03/15] opt how to pass pd address to br job --- cmd/backup-manager/app/cmd/backup.go | 17 +---------- cmd/backup-manager/app/cmd/restore.go | 28 +------------------ .../br/manager/backup/backup_manager.go | 8 +++++- .../br/manager/restore/restore_manager.go | 8 +++++- 4 files changed, 16 insertions(+), 45 deletions(-) diff --git a/cmd/backup-manager/app/cmd/backup.go b/cmd/backup-manager/app/cmd/backup.go index b82add503b..3e75c788b8 100644 --- a/cmd/backup-manager/app/cmd/backup.go +++ b/cmd/backup-manager/app/cmd/backup.go @@ -66,6 +66,7 @@ func NewBackupCommand() *cobra.Command { cmd.Flags().StringVar(&bo.CommitTS, "commit-ts", "0", "the log backup start ts") cmd.Flags().StringVar(&bo.TruncateUntil, "truncate-until", "0", "the log backup truncate until") cmd.Flags().BoolVar(&bo.Initialize, "initialize", false, "Whether execute initialize process for volume backup") + cmd.Flags().StringVar(&bo.PDAddress, "pd-addr", "", "PD Address, for example: db-pd.tidb1234:2379") return cmd } @@ -88,13 +89,6 @@ func runBackup(backupOpts backup.Options, kubecfg string) error { return err } - // set PD Address - pdAddress, err := getPDAddressForBackup(newcli, backupOpts) - if err != nil { - return err - } - backupOpts.PDAddress = pdAddress - recorder := record.NewBroadcaster().NewRecorder(scheme.Scheme, corev1.EventSource{Component: "backup"}) statusUpdater := backupMgr.NewRealBackupConditionUpdater(newcli, recorder) klog.Infof("start to process backup %s", backupOpts.String()) @@ -150,12 +144,3 @@ func newClient(ctx context.Context, cfg *rest.Config, s *runtime.Scheme, disable return c, nil } - -func getPDAddressForBackup(cli client.Client, bo backup.Options) (string, error) { - b := &v1alpha1.Backup{} - err := cli.Get(context.Background(), client.ObjectKey{Namespace: bo.Namespace, Name: bo.ResourceName}, b) - if err != nil { - return "", err - } - return getPDAddress(cli, b.Spec.BR.ClusterNamespace, b.Spec.BR.Cluster) -} diff --git a/cmd/backup-manager/app/cmd/restore.go b/cmd/backup-manager/app/cmd/restore.go index df59a9c814..f7e148583d 100644 --- a/cmd/backup-manager/app/cmd/restore.go +++ b/cmd/backup-manager/app/cmd/restore.go @@ -16,7 +16,6 @@ package cmd import ( "context" - "fmt" // registry mysql drive _ "github.com/go-sql-driver/mysql" @@ -32,9 +31,7 @@ import ( "github.com/pingcap/tidb-operator/api/v2/br/v1alpha1" "github.com/pingcap/tidb-operator/cmd/backup-manager/app/restore" "github.com/pingcap/tidb-operator/cmd/backup-manager/app/util" - coreutil "github.com/pingcap/tidb-operator/pkg/apiutil/core/v1alpha1" restoreMgr "github.com/pingcap/tidb-operator/pkg/controllers/br/manager/restore" - brutil "github.com/pingcap/tidb-operator/pkg/controllers/br/manager/util" "github.com/pingcap/tidb-operator/pkg/scheme" ) @@ -62,6 +59,7 @@ func NewRestoreCommand() *cobra.Command { cmd.Flags().BoolVar(&ro.Prepare, "prepare", false, "Whether to prepare for restore") cmd.Flags().StringVar(&ro.TargetAZ, "target-az", "", "For volume-snapshot restore, which az the volume snapshots restore to") cmd.Flags().BoolVar(&ro.UseFSR, "use-fsr", false, "EBS snapshot restore use FSR for TiKV data volumes or not") + cmd.Flags().StringVar(&ro.PDAddress, "pd-addr", "", "PD Address, for example: db-pd.tidb1234:2379") return cmd } @@ -84,33 +82,9 @@ func runRestore(restoreOpts restore.Options, kubecfg string) error { return err } - // set PD Address - pdAddress, err := getPDAddressForRestore(newcli, restoreOpts) - if err != nil { - return err - } - restoreOpts.PDAddress = pdAddress - recorder := record.NewBroadcaster().NewRecorder(scheme.Scheme, corev1.EventSource{Component: "restore"}) statusUpdater := restoreMgr.NewRealRestoreConditionUpdater(newcli, recorder) klog.Infof("start to process restore %s", restoreOpts.String()) rm := restore.NewManager(newcli, statusUpdater, restoreOpts) return rm.ProcessRestore() } - -func getPDAddressForRestore(cli client.Client, ro restore.Options) (string, error) { - r := &v1alpha1.Restore{} - err := cli.Get(context.Background(), client.ObjectKey{Namespace: ro.Namespace, Name: ro.ResourceName}, r) - if err != nil { - return "", err - } - return getPDAddress(cli, r.Spec.BR.ClusterNamespace, r.Spec.BR.Cluster) -} - -func getPDAddress(cli client.Client, clusterNs, clusterName string) (string, error) { - pdg, err := brutil.FirstPDGroup(cli, clusterNs, clusterName) - if err != nil { - return "", err - } - return fmt.Sprintf("%s-pd.%s:%d", pdg.Spec.Cluster.Name, pdg.Namespace, coreutil.PDGroupClientPort(pdg)), nil -} diff --git a/pkg/controllers/br/manager/backup/backup_manager.go b/pkg/controllers/br/manager/backup/backup_manager.go index 1d988d2511..26e99dd1b3 100644 --- a/pkg/controllers/br/manager/backup/backup_manager.go +++ b/pkg/controllers/br/manager/backup/backup_manager.go @@ -23,6 +23,7 @@ import ( batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/tools/record" @@ -184,7 +185,7 @@ func (bm *backupManager) syncBackupJob(backup *v1alpha1.Backup) error { // create k8s job klog.Infof("backup %s/%s creating job %s.", ns, name, backupJobName) - if err := bm.cli.Create(context.TODO(), job); err != nil { + if err := bm.cli.Create(context.TODO(), job); err != nil && !apierrors.IsAlreadyExists(err) { errMsg := fmt.Errorf("create backup %s/%s job %s failed, err: %w", ns, name, backupJobName, err) _ = bm.statusUpdater.Update(backup, &v1alpha1.BackupCondition{ Command: logBackupSubcommand, @@ -393,6 +394,10 @@ func (bm *backupManager) makeBRBackupJob(backup *v1alpha1.Backup) (*batchv1.Job, if err != nil { return nil, fmt.Sprintf("failed to get tikv group %s/%s", ns, backup.Spec.BR.Cluster), err } + pdGroup, err := util.FirstPDGroup(bm.cli, ns, cluster.Name) + if err != nil { + return nil, fmt.Sprintf("failed to get first pd group: %v", err), err + } var ( envVars []corev1.EnvVar @@ -417,6 +422,7 @@ func (bm *backupManager) makeBRBackupJob(backup *v1alpha1.Backup) (*batchv1.Job, "backup", fmt.Sprintf("--namespace=%s", ns), fmt.Sprintf("--backupName=%s", name), + fmt.Sprintf("--pd-addr=%s", fmt.Sprintf("%s-pd.%s:%d", pdGroup.Spec.Cluster.Name, pdGroup.Namespace, coreutil.PDGroupClientPort(pdGroup))), } tikvVersion := tikvGroup.Spec.Template.Spec.Version if tikvVersion != "" { diff --git a/pkg/controllers/br/manager/restore/restore_manager.go b/pkg/controllers/br/manager/restore/restore_manager.go index 9a557980d1..bdb818b325 100644 --- a/pkg/controllers/br/manager/restore/restore_manager.go +++ b/pkg/controllers/br/manager/restore/restore_manager.go @@ -22,6 +22,7 @@ import ( batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/tools/record" "k8s.io/klog/v2" @@ -148,7 +149,7 @@ func (rm *restoreManager) syncRestoreJob(restore *v1alpha1.Restore) error { } klog.Infof("restore %s/%s creating job %s.", ns, name, restoreJobName) - if err := rm.cli.Create(context.TODO(), job); err != nil { + if err := rm.cli.Create(context.TODO(), job); err != nil && !apierrors.IsAlreadyExists(err) { errMsg := fmt.Errorf("create restore %s/%s job %s failed, err: %w", ns, name, restoreJobName, err) _ = rm.statusUpdater.Update(restore, &metav1.Condition{ Type: string(v1alpha1.RestoreRetryFailed), @@ -191,6 +192,10 @@ func (rm *restoreManager) makeRestoreJob(restore *v1alpha1.Restore) (*batchv1.Jo if err != nil { return nil, fmt.Sprintf("failed to get first tikv group: %v", err), err } + pdGroup, err := util.FirstPDGroup(rm.cli, ns, cluster.Name) + if err != nil { + return nil, fmt.Sprintf("failed to get first pd group: %v", err), err + } var ( envVars []corev1.EnvVar @@ -214,6 +219,7 @@ func (rm *restoreManager) makeRestoreJob(restore *v1alpha1.Restore) (*batchv1.Jo "restore", fmt.Sprintf("--namespace=%s", ns), fmt.Sprintf("--restoreName=%s", name), + fmt.Sprintf("--pd-addr=%s", fmt.Sprintf("%s-pd.%s:%d", pdGroup.Spec.Cluster.Name, pdGroup.Namespace, coreutil.PDGroupClientPort(pdGroup))), } tikvVersion := tikvGroup.Spec.Template.Spec.Version if tikvVersion != "" { From b56fa9cdb021d0ae820d5923e9d0c3d98fc0a2bd Mon Sep 17 00:00:00 2001 From: chenfei Date: Wed, 19 Feb 2025 15:26:41 +0000 Subject: [PATCH 04/15] fix task sequence --- pkg/controllers/br/backup/builder.go | 5 +++-- pkg/controllers/br/restore/builder.go | 4 ++-- pkg/controllers/common/cond.go | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/pkg/controllers/br/backup/builder.go b/pkg/controllers/br/backup/builder.go index 285b5da527..0b15b3fc6a 100644 --- a/pkg/controllers/br/backup/builder.go +++ b/pkg/controllers/br/backup/builder.go @@ -27,8 +27,6 @@ func (r *Reconciler) NewRunner(state *tasks.ReconcileContext, reporter task.Task runner := task.NewTaskRunner(reporter, // get backup tasks.TaskContextBackup(state, r.Client), - // if it's gone just return - task.IfBreak(common.CondJobHasBeenDeleted(state)), // finalizer management task.If(task.CondFunc(func() bool { @@ -42,6 +40,9 @@ func (r *Reconciler) NewRunner(state *tasks.ReconcileContext, reporter task.Task common.TaskJobFinalizerDel[*runtime.Backup](state, r.Client), ), + // if it's gone just return + task.IfBreak(common.CondJobHasBeenDeleted(state)), + // get cluster common.TaskContextCluster[scope.Backup](state, r.Client), // if it's paused just return diff --git a/pkg/controllers/br/restore/builder.go b/pkg/controllers/br/restore/builder.go index a67a92e3e4..38c083f710 100644 --- a/pkg/controllers/br/restore/builder.go +++ b/pkg/controllers/br/restore/builder.go @@ -27,8 +27,6 @@ func (r *Reconciler) NewRunner(state *tasks.ReconcileContext, reporter task.Task runner := task.NewTaskRunner(reporter, // get backup tasks.TaskContextRestore(state, r.Client), - // if it's gone just return - task.IfBreak(common.CondJobHasBeenDeleted(state)), // finalizer management task.If(task.CondFunc(func() bool { @@ -41,6 +39,8 @@ func (r *Reconciler) NewRunner(state *tasks.ReconcileContext, reporter task.Task }), common.TaskJobFinalizerDel[*runtime.Restore](state, r.Client), ), + // if it's gone just return + task.IfBreak(common.CondJobHasBeenDeleted(state)), // get cluster common.TaskContextCluster[scope.Restore](state, r.Client), diff --git a/pkg/controllers/common/cond.go b/pkg/controllers/common/cond.go index 27cdb85baa..2144fda1de 100644 --- a/pkg/controllers/common/cond.go +++ b/pkg/controllers/common/cond.go @@ -58,6 +58,6 @@ func CondInstanceHasBeenDeleted[RI runtime.InstanceT[I], I runtime.InstanceSet]( func CondJobHasBeenDeleted[J runtime.Job](state JobState[J]) task.Condition { return task.CondFunc(func() bool { - return state.Job().Object().GetDeletionTimestamp() != nil + return !state.Job().Object().GetDeletionTimestamp().IsZero() }) } From d8bd58297689d53ddb4d3999556f9cf3ea1a048d Mon Sep 17 00:00:00 2001 From: chenfei Date: Thu, 20 Feb 2025 04:00:44 +0000 Subject: [PATCH 05/15] remove backup.spec.from related code --- cmd/backup-manager/app/backup/manager.go | 129 +---------------------- 1 file changed, 2 insertions(+), 127 deletions(-) diff --git a/cmd/backup-manager/app/backup/manager.go b/cmd/backup-manager/app/backup/manager.go index 5579fefc2d..57fba836e4 100644 --- a/cmd/backup-manager/app/backup/manager.go +++ b/cmd/backup-manager/app/backup/manager.go @@ -16,7 +16,6 @@ package backup import ( "context" - "database/sql" "encoding/json" "fmt" "strconv" @@ -28,7 +27,6 @@ import ( "github.com/pingcap/tidb-operator/api/v2/br/v1alpha1" "github.com/pingcap/tidb-operator/cmd/backup-manager/app/clean" - "github.com/pingcap/tidb-operator/cmd/backup-manager/app/constants" "github.com/pingcap/tidb-operator/cmd/backup-manager/app/util" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -117,11 +115,11 @@ func (bm *Manager) ProcessBackup() error { } // skip the DB initialization if spec.from is not specified - return bm.performBackup(ctx, backup.DeepCopy(), nil) + return bm.performBackup(ctx, backup.DeepCopy()) } // nolint: gocyclo -func (bm *Manager) performBackup(ctx context.Context, backup *v1alpha1.Backup, db *sql.DB) error { +func (bm *Manager) performBackup(ctx context.Context, backup *v1alpha1.Backup) error { started := time.Now() var errs []error @@ -153,102 +151,6 @@ func (bm *Manager) performBackup(ctx context.Context, backup *v1alpha1.Backup, d return err } - var ( - oldTikvGCTime, tikvGCLifeTime string - oldTikvGCTimeDuration, tikvGCTimeDuration time.Duration - ) - - // set tikv gc life time to prevent gc when backing up data - if db != nil { - oldTikvGCTime, err = bm.GetTikvGCLifeTime(ctx, db) - if err != nil { - errs = append(errs, err) - klog.Errorf("cluster %s get %s failed, err: %s", bm, constants.TikvGCVariable, err) - uerr := bm.StatusUpdater.Update(backup, &v1alpha1.BackupCondition{ - Condition: metav1.Condition{ - Type: string(v1alpha1.BackupFailed), - Status: metav1.ConditionTrue, - Reason: "GetTikvGCLifeTimeFailed", - Message: err.Error(), - }, - }, nil) - errs = append(errs, uerr) - return errorutils.NewAggregate(errs) - } - klog.Infof("cluster %s %s is %s", bm, constants.TikvGCVariable, oldTikvGCTime) - - oldTikvGCTimeDuration, err = time.ParseDuration(oldTikvGCTime) - if err != nil { - errs = append(errs, err) - klog.Errorf("cluster %s parse old %s failed, err: %s", bm, constants.TikvGCVariable, err) - uerr := bm.StatusUpdater.Update(backup, &v1alpha1.BackupCondition{ - Condition: metav1.Condition{ - Type: string(v1alpha1.BackupFailed), - Status: metav1.ConditionTrue, - Reason: "ParseOldTikvGCLifeTimeFailed", - Message: err.Error(), - }, - }, nil) - errs = append(errs, uerr) - return errorutils.NewAggregate(errs) - } - - if backup.Spec.TikvGCLifeTime != nil { - tikvGCLifeTime = *backup.Spec.TikvGCLifeTime - tikvGCTimeDuration, err = time.ParseDuration(tikvGCLifeTime) - if err != nil { - errs = append(errs, err) - klog.Errorf("cluster %s parse configured %s failed, err: %s", bm, constants.TikvGCVariable, err) - uerr := bm.StatusUpdater.Update(backup, &v1alpha1.BackupCondition{ - Condition: metav1.Condition{ - Type: string(v1alpha1.BackupFailed), - Status: metav1.ConditionTrue, - Reason: "ParseConfiguredTikvGCLifeTimeFailed", - Message: err.Error(), - }, - }, nil) - errs = append(errs, uerr) - return errorutils.NewAggregate(errs) - } - } else { - tikvGCLifeTime = constants.TikvGCLifeTime - tikvGCTimeDuration, err = time.ParseDuration(tikvGCLifeTime) - if err != nil { - errs = append(errs, err) - klog.Errorf("cluster %s parse default %s failed, err: %s", bm, constants.TikvGCVariable, err) - uerr := bm.StatusUpdater.Update(backup, &v1alpha1.BackupCondition{ - Condition: metav1.Condition{ - Type: string(v1alpha1.BackupFailed), - Status: metav1.ConditionTrue, - Reason: "ParseDefaultTikvGCLifeTimeFailed", - Message: err.Error(), - }, - }, nil) - errs = append(errs, uerr) - return errorutils.NewAggregate(errs) - } - } - - if oldTikvGCTimeDuration < tikvGCTimeDuration { - err = bm.SetTikvGCLifeTime(ctx, db, tikvGCLifeTime) - if err != nil { - errs = append(errs, err) - klog.Errorf("cluster %s set tikv GC life time to %s failed, err: %s", bm, tikvGCLifeTime, err) - uerr := bm.StatusUpdater.Update(backup, &v1alpha1.BackupCondition{ - Condition: metav1.Condition{ - Type: string(v1alpha1.BackupFailed), - Status: metav1.ConditionTrue, - Reason: "SetTikvGCLifeTimeFailed", - Message: err.Error(), - }, - }, nil) - errs = append(errs, uerr) - return errorutils.NewAggregate(errs) - } - klog.Infof("set cluster %s %s to %s success", bm, constants.TikvGCVariable, tikvGCLifeTime) - } - } - // clean snapshot backup data if it was restarted if backup.Spec.Mode == v1alpha1.BackupModeSnapshot && v1alpha1.IsBackupRestart(backup) && !bm.isBRCanContinueRunByCheckpoint() { klog.Infof("clean snapshot backup %s data before run br command, backup path is %s", bm, backup.Status.BackupPath) @@ -269,33 +171,6 @@ func (bm *Manager) performBackup(ctx context.Context, backup *v1alpha1.Backup, d // run br binary to do the real job backupErr := bm.backupData(ctx, backup) - - if db != nil && oldTikvGCTimeDuration < tikvGCTimeDuration { - // use another context to revert `tikv_gc_life_time` back. - ctx2, cancel2 := context.WithTimeout(context.Background(), constants.DefaultTikvGCSetTimeout) - defer cancel2() - err = bm.SetTikvGCLifeTime(ctx2, db, oldTikvGCTime) - if err != nil { - if backupErr != nil { - errs = append(errs, backupErr) - } - errs = append(errs, err) - klog.Errorf("cluster %s reset tikv GC life time to %s failed, err: %s", bm, oldTikvGCTime, err) - - uerr := bm.StatusUpdater.Update(backup, &v1alpha1.BackupCondition{ - Condition: metav1.Condition{ - Type: string(v1alpha1.BackupFailed), - Status: metav1.ConditionTrue, - Reason: "ResetTikvGCLifeTimeFailed", - Message: err.Error(), - }, - }, nil) - errs = append(errs, uerr) - return errorutils.NewAggregate(errs) - } - klog.Infof("reset cluster %s %s to %s success", bm, constants.TikvGCVariable, oldTikvGCTime) - } - if backupErr != nil { errs = append(errs, backupErr) klog.Errorf("backup cluster %s data failed, err: %s", bm, backupErr) From 614ecc9b25f79f347749f6c33351e2ae252b0213 Mon Sep 17 00:00:00 2001 From: chenfei Date: Thu, 20 Feb 2025 04:01:00 +0000 Subject: [PATCH 06/15] remove commented code --- cmd/backup-manager/app/util/generic.go | 34 -------------------------- 1 file changed, 34 deletions(-) diff --git a/cmd/backup-manager/app/util/generic.go b/cmd/backup-manager/app/util/generic.go index 253649ff92..6fe3b9d08b 100644 --- a/cmd/backup-manager/app/util/generic.go +++ b/cmd/backup-manager/app/util/generic.go @@ -47,40 +47,6 @@ func (bo *GenericOptions) String() string { return fmt.Sprintf("%s/%s", bo.Namespace, bo.ResourceName) } -/* - func (bo *GenericOptions) GetDSN(enabledTLSClient bool) (string, error) { - if !enabledTLSClient { - return fmt.Sprintf("%s:%s@(%s:%d)/%s?charset=utf8", bo.User, bo.Password, bo.Host, bo.Port, constants.TidbMetaDB), nil - } - rootCertPool := x509.NewCertPool() - if !bo.SkipClientCA { - pem, err := ioutil.ReadFile(path.Join(corev1alpha1.DirPathTiDBClientTLS, corev1.ServiceAccountRootCAKey)) - if err != nil { - return "", err - } - if ok := rootCertPool.AppendCertsFromPEM(pem); !ok { - return "", errors.New("Failed to append PEM") - } - } - - clientCert := make([]tls.Certificate, 0, 1) - certs, err := tls.LoadX509KeyPair( - path.Join(corev1alpha1.DirPathTiDBClientTLS, corev1.TLSCertKey), - path.Join(corev1alpha1.DirPathTiDBClientTLS, corev1.TLSPrivateKeyKey)) - if err != nil { - return "", err - } - clientCert = append(clientCert, certs) - mysql.RegisterTLSConfig("customer", &tls.Config{ - RootCAs: rootCertPool, - Certificates: clientCert, - ServerName: bo.Host, - InsecureSkipVerify: bo.SkipClientCA, - }) - return fmt.Sprintf("%s:%s@(%s:%d)/%s?tls=customer&charset=utf8", bo.User, bo.Password, bo.Host, bo.Port, constants.TidbMetaDB), nil - } -*/ - func (bo *GenericOptions) GetTikvGCLifeTime(ctx context.Context, db *sql.DB) (string, error) { var tikvGCTime string sql := fmt.Sprintf("select variable_value from %s where variable_name= ?", constants.TidbMetaTable) //nolint: gosec From dcb6c14791e45049d2b4284b02ab79665624f108 Mon Sep 17 00:00:00 2001 From: chenfei Date: Thu, 20 Feb 2025 04:04:46 +0000 Subject: [PATCH 07/15] Remove field backup.spec.tikvGCLifeTime --- api/br/v1alpha1/backup_types.go | 4 ---- api/br/v1alpha1/zz_generated.deepcopy.go | 5 ----- manifests/crd/br.pingcap.com_backups.yaml | 6 ------ manifests/crd/br.pingcap.com_backupschedules.yaml | 12 ------------ 4 files changed, 27 deletions(-) diff --git a/api/br/v1alpha1/backup_types.go b/api/br/v1alpha1/backup_types.go index 4a9db04a5a..1c12f4c4f1 100644 --- a/api/br/v1alpha1/backup_types.go +++ b/api/br/v1alpha1/backup_types.go @@ -295,10 +295,6 @@ type BackupSpec struct { // Mode is the backup mode, such as snapshot backup or log backup. // +kubebuilder:default=snapshot Mode BackupMode `json:"backupMode,omitempty"` - // TikvGCLifeTime is to specify the safe gc life time for backup. - // The time limit during which data is retained for each GC, in the format of Go Duration. - // When a GC happens, the current time minus this value is the safe point. - TikvGCLifeTime *string `json:"tikvGCLifeTime,omitempty"` // StorageProvider configures where and how backups should be stored. // *** Note: This field should generally not be left empty, unless you are certain the storage provider // *** can be obtained from another source, such as a schedule CR. diff --git a/api/br/v1alpha1/zz_generated.deepcopy.go b/api/br/v1alpha1/zz_generated.deepcopy.go index 42c7c90734..7259f65046 100644 --- a/api/br/v1alpha1/zz_generated.deepcopy.go +++ b/api/br/v1alpha1/zz_generated.deepcopy.go @@ -385,11 +385,6 @@ func (in *BackupSpec) DeepCopyInto(out *BackupSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - if in.TikvGCLifeTime != nil { - in, out := &in.TikvGCLifeTime, &out.TikvGCLifeTime - *out = new(string) - **out = **in - } in.StorageProvider.DeepCopyInto(&out.StorageProvider) if in.StorageClassName != nil { in, out := &in.StorageClassName, &out.StorageClassName diff --git a/manifests/crd/br.pingcap.com_backups.yaml b/manifests/crd/br.pingcap.com_backups.yaml index cbecb56949..b2168e3bbb 100644 --- a/manifests/crd/br.pingcap.com_backups.yaml +++ b/manifests/crd/br.pingcap.com_backups.yaml @@ -5425,12 +5425,6 @@ spec: items: type: string type: array - tikvGCLifeTime: - description: |- - TikvGCLifeTime is to specify the safe gc life time for backup. - The time limit during which data is retained for each GC, in the format of Go Duration. - When a GC happens, the current time minus this value is the safe point. - type: string tolerations: description: Base tolerations of backup Pods, components may add more tolerations upon this respectively diff --git a/manifests/crd/br.pingcap.com_backupschedules.yaml b/manifests/crd/br.pingcap.com_backupschedules.yaml index cfe56f2017..30511035b5 100644 --- a/manifests/crd/br.pingcap.com_backupschedules.yaml +++ b/manifests/crd/br.pingcap.com_backupschedules.yaml @@ -5476,12 +5476,6 @@ spec: items: type: string type: array - tikvGCLifeTime: - description: |- - TikvGCLifeTime is to specify the safe gc life time for backup. - The time limit during which data is retained for each GC, in the format of Go Duration. - When a GC happens, the current time minus this value is the safe point. - type: string tolerations: description: Base tolerations of backup Pods, components may add more tolerations upon this respectively @@ -18226,12 +18220,6 @@ spec: items: type: string type: array - tikvGCLifeTime: - description: |- - TikvGCLifeTime is to specify the safe gc life time for backup. - The time limit during which data is retained for each GC, in the format of Go Duration. - When a GC happens, the current time minus this value is the safe point. - type: string tolerations: description: Base tolerations of backup Pods, components may add more tolerations upon this respectively From 4f5916f94c9f22b0735877e894c84319584a8a28 Mon Sep 17 00:00:00 2001 From: chenfei Date: Thu, 20 Feb 2025 04:39:05 +0000 Subject: [PATCH 08/15] fix BR status update panic --- cmd/backup-manager/app/backup/manager.go | 2 -- .../br/manager/backup/backup_status_updater.go | 12 ++++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/cmd/backup-manager/app/backup/manager.go b/cmd/backup-manager/app/backup/manager.go index 57fba836e4..05f56548c8 100644 --- a/cmd/backup-manager/app/backup/manager.go +++ b/cmd/backup-manager/app/backup/manager.go @@ -114,7 +114,6 @@ func (bm *Manager) ProcessBackup() error { return bm.performLogBackup(ctx, backup.DeepCopy()) } - // skip the DB initialization if spec.from is not specified return bm.performBackup(ctx, backup.DeepCopy()) } @@ -319,7 +318,6 @@ func (bm *Manager) startLogBackup(ctx context.Context, backup *v1alpha1.Backup) // run br binary to do the real job backupErr := bm.doStartLogBackup(ctx, backup) - if backupErr != nil { klog.Errorf("Start log backup of cluster %s failed, err: %s", bm, backupErr) return nil, "StartLogBackupFailed", backupErr diff --git a/pkg/controllers/br/manager/backup/backup_status_updater.go b/pkg/controllers/br/manager/backup/backup_status_updater.go index a171b08e01..70e98e2b0d 100644 --- a/pkg/controllers/br/manager/backup/backup_status_updater.go +++ b/pkg/controllers/br/manager/backup/backup_status_updater.go @@ -153,7 +153,11 @@ func updateBackupStatus(status *v1alpha1.BackupStatus, newStatus *BackupUpdateSt func updateSnapshotBackupStatus(backup *v1alpha1.Backup, condition *v1alpha1.BackupCondition, newStatus *BackupUpdateStatus) bool { var isStatusUpdate, isConditionUpdate bool isStatusUpdate = updateBackupStatus(&backup.Status, newStatus) - isConditionUpdate = v1alpha1.UpdateBackupCondition(&backup.Status, &condition.Condition) + var metaCondition *metav1.Condition + if condition != nil { + metaCondition = &condition.Condition + } + isConditionUpdate = v1alpha1.UpdateBackupCondition(&backup.Status, metaCondition) return isStatusUpdate || isConditionUpdate } @@ -223,7 +227,11 @@ func updateWholeLogBackupStatus(backup *v1alpha1.Backup, condition *v1alpha1.Bac // call real update interface to update whole status doUpdateStatusAndCondition := func(newCondition *v1alpha1.BackupCondition, newStatus *BackupUpdateStatus) bool { isStatusUpdate := updateBackupStatus(&backup.Status, newStatus) - isConditionUpdate := v1alpha1.UpdateBackupCondition(&backup.Status, &newCondition.Condition) + var metaCondition *metav1.Condition + if newCondition != nil { + metaCondition = &newCondition.Condition + } + isConditionUpdate := v1alpha1.UpdateBackupCondition(&backup.Status, metaCondition) return isStatusUpdate || isConditionUpdate } From 80dc81d2c9824e9b97cf33e5498da6b8e0af85d1 Mon Sep 17 00:00:00 2001 From: chenfei Date: Thu, 20 Feb 2025 07:16:48 +0000 Subject: [PATCH 09/15] optimize CRD definition of Backup --- api/br/v1alpha1/backup_types.go | 7 ++++++- manifests/crd/br.pingcap.com_backups.yaml | 7 ++++++- manifests/crd/br.pingcap.com_backupschedules.yaml | 14 ++++++++++++-- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/api/br/v1alpha1/backup_types.go b/api/br/v1alpha1/backup_types.go index 1c12f4c4f1..c1b4492465 100644 --- a/api/br/v1alpha1/backup_types.go +++ b/api/br/v1alpha1/backup_types.go @@ -309,6 +309,7 @@ type BackupSpec struct { // *** Note: This field should generally not be left empty, unless you are certain the BR config // *** can be obtained from another source, such as a schedule CR. BR *BRConfig `json:"br,omitempty"` + // CommitTs is the commit ts of the backup, snapshot ts for full backup or start ts for log backup. // Format supports TSO or datetime, e.g. '400036290571534337', '2018-05-11 01:42:23'. // Default is current timestamp. @@ -316,15 +317,18 @@ type BackupSpec struct { CommitTs string `json:"commitTs,omitempty"` // Subcommand is the subcommand for BR, such as start, stop, pause etc. // +optional - // +kubebuilder:validation:Enum:="log-start";"log-stop";"log-pause" + // +kubebuilder:validation:Enum:="log-start";"log-stop";"log-pause";"log-resume";"log-truncate" LogSubcommand LogSubCommandType `json:"logSubcommand,omitempty"` // LogTruncateUntil is log backup truncate until timestamp. // Format supports TSO or datetime, e.g. '400036290571534337', '2018-05-11 01:42:23'. + // It's required when LogSubcommand is "log-truncate". // +optional LogTruncateUntil string `json:"logTruncateUntil,omitempty"` + // Deprecated: use LogSubcommand instead. it will be removed later. // LogStop indicates that will stop the log backup. // +optional LogStop bool `json:"logStop,omitempty"` + // Base tolerations of backup Pods, components may add more tolerations upon this respectively // +optional Tolerations []corev1.Toleration `json:"tolerations,omitempty"` @@ -345,6 +349,7 @@ type BackupSpec struct { UseKMS bool `json:"useKMS,omitempty"` // Specify service account of backup ServiceAccount string `json:"serviceAccount,omitempty"` + // CleanPolicy denotes whether to clean backup data when the object is deleted from the cluster, if not set, the backup data will be retained // +kubebuilder:validation:Enum:=Retain;OnFailure;Delete // +kubebuilder:default=Retain diff --git a/manifests/crd/br.pingcap.com_backups.yaml b/manifests/crd/br.pingcap.com_backups.yaml index b2168e3bbb..c9b0e5394c 100644 --- a/manifests/crd/br.pingcap.com_backups.yaml +++ b/manifests/crd/br.pingcap.com_backups.yaml @@ -5076,7 +5076,9 @@ spec: - volumeMount type: object logStop: - description: LogStop indicates that will stop the log backup. + description: |- + Deprecated: use LogSubcommand instead. it will be removed later. + LogStop indicates that will stop the log backup. type: boolean logSubcommand: description: Subcommand is the subcommand for BR, such as start, stop, @@ -5085,11 +5087,14 @@ spec: - log-start - log-stop - log-pause + - log-resume + - log-truncate type: string logTruncateUntil: description: |- LogTruncateUntil is log backup truncate until timestamp. Format supports TSO or datetime, e.g. '400036290571534337', '2018-05-11 01:42:23'. + It's required when LogSubcommand is "log-truncate". type: string podSecurityContext: description: PodSecurityContext of the component diff --git a/manifests/crd/br.pingcap.com_backupschedules.yaml b/manifests/crd/br.pingcap.com_backupschedules.yaml index 30511035b5..e8ac214ad9 100644 --- a/manifests/crd/br.pingcap.com_backupschedules.yaml +++ b/manifests/crd/br.pingcap.com_backupschedules.yaml @@ -5125,7 +5125,9 @@ spec: - volumeMount type: object logStop: - description: LogStop indicates that will stop the log backup. + description: |- + Deprecated: use LogSubcommand instead. it will be removed later. + LogStop indicates that will stop the log backup. type: boolean logSubcommand: description: Subcommand is the subcommand for BR, such as start, @@ -5134,11 +5136,14 @@ spec: - log-start - log-stop - log-pause + - log-resume + - log-truncate type: string logTruncateUntil: description: |- LogTruncateUntil is log backup truncate until timestamp. Format supports TSO or datetime, e.g. '400036290571534337', '2018-05-11 01:42:23'. + It's required when LogSubcommand is "log-truncate". type: string podSecurityContext: description: PodSecurityContext of the component @@ -17869,7 +17874,9 @@ spec: - volumeMount type: object logStop: - description: LogStop indicates that will stop the log backup. + description: |- + Deprecated: use LogSubcommand instead. it will be removed later. + LogStop indicates that will stop the log backup. type: boolean logSubcommand: description: Subcommand is the subcommand for BR, such as start, @@ -17878,11 +17885,14 @@ spec: - log-start - log-stop - log-pause + - log-resume + - log-truncate type: string logTruncateUntil: description: |- LogTruncateUntil is log backup truncate until timestamp. Format supports TSO or datetime, e.g. '400036290571534337', '2018-05-11 01:42:23'. + It's required when LogSubcommand is "log-truncate". type: string podSecurityContext: description: PodSecurityContext of the component From 73e178e3c0dc085a51bc26fa22c0899d7afb1a35 Mon Sep 17 00:00:00 2001 From: chenfei Date: Thu, 20 Feb 2025 07:23:13 +0000 Subject: [PATCH 10/15] Remove EBS volume restore related constant values and funcs --- api/br/v1alpha1/restore.go | 12 ------------ api/br/v1alpha1/restore_types.go | 5 ----- 2 files changed, 17 deletions(-) diff --git a/api/br/v1alpha1/restore.go b/api/br/v1alpha1/restore.go index f2ed49b1b1..05a9e9c9b3 100644 --- a/api/br/v1alpha1/restore.go +++ b/api/br/v1alpha1/restore.go @@ -121,15 +121,3 @@ func IsRestoreFailed(restore *Restore) bool { _, condition := GetRestoreCondition(&restore.Status, RestoreFailed) return condition != nil && condition.Status == metav1.ConditionTrue } - -// IsRestoreTiKVComplete returns true if all TiKVs run successfully during volume restore -func IsRestoreTiKVComplete(restore *Restore) bool { - _, condition := GetRestoreCondition(&restore.Status, RestoreTiKVComplete) - return condition != nil && condition.Status == metav1.ConditionTrue -} - -// IsRestoreDataComplete returns true if a Restore for data consistency has successfully completed -func IsRestoreDataComplete(restore *Restore) bool { - _, condition := GetRestoreCondition(&restore.Status, RestoreDataComplete) - return condition != nil && condition.Status == metav1.ConditionTrue -} diff --git a/api/br/v1alpha1/restore_types.go b/api/br/v1alpha1/restore_types.go index c69a26ccb0..79655d1502 100644 --- a/api/br/v1alpha1/restore_types.go +++ b/api/br/v1alpha1/restore_types.go @@ -76,11 +76,6 @@ const ( RestoreScheduled RestoreConditionType = "Scheduled" // RestoreRunning means the Restore is currently being executed. RestoreRunning RestoreConditionType = "Running" - // RestoreDataComplete means the Restore has successfully executed part-2 and the - // data in restore volumes has been deal with consistency based on min_resolved_ts - RestoreDataComplete RestoreConditionType = "DataComplete" - // RestoreTiKVComplete means in volume restore, all TiKV instances are started and up - RestoreTiKVComplete RestoreConditionType = "TikvComplete" // RestoreComplete means the Restore has successfully executed and the // backup data has been loaded into tidb cluster. RestoreComplete RestoreConditionType = "Complete" From 8289db82aeb89b607f81d0a3b98dbd486e9e3df4 Mon Sep 17 00:00:00 2001 From: chenfei Date: Thu, 20 Feb 2025 07:24:16 +0000 Subject: [PATCH 11/15] Remove store.spec.tikvGCLifeTime --- api/br/v1alpha1/restore_types.go | 4 ---- api/br/v1alpha1/zz_generated.deepcopy.go | 5 ----- manifests/crd/br.pingcap.com_restores.yaml | 6 ------ 3 files changed, 15 deletions(-) diff --git a/api/br/v1alpha1/restore_types.go b/api/br/v1alpha1/restore_types.go index 79655d1502..aa6abe665a 100644 --- a/api/br/v1alpha1/restore_types.go +++ b/api/br/v1alpha1/restore_types.go @@ -131,10 +131,6 @@ type RestoreSpec struct { // LogRestoreStartTs is the start timestamp which log restore from. // +optional LogRestoreStartTs string `json:"logRestoreStartTs,omitempty"` - // TikvGCLifeTime is to specify the safe gc life time for restore. - // The time limit during which data is retained for each GC, in the format of Go Duration. - // When a GC happens, the current time minus this value is the safe point. - TikvGCLifeTime *string `json:"tikvGCLifeTime,omitempty"` // StorageProvider configures where and how backups should be stored. StorageProvider `json:",inline"` // PitrFullBackupStorageProvider configures where and how pitr dependent full backup should be stored. diff --git a/api/br/v1alpha1/zz_generated.deepcopy.go b/api/br/v1alpha1/zz_generated.deepcopy.go index 7259f65046..95b71a1be2 100644 --- a/api/br/v1alpha1/zz_generated.deepcopy.go +++ b/api/br/v1alpha1/zz_generated.deepcopy.go @@ -867,11 +867,6 @@ func (in *RestoreSpec) DeepCopyInto(out *RestoreSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - if in.TikvGCLifeTime != nil { - in, out := &in.TikvGCLifeTime, &out.TikvGCLifeTime - *out = new(string) - **out = **in - } in.StorageProvider.DeepCopyInto(&out.StorageProvider) in.PitrFullBackupStorageProvider.DeepCopyInto(&out.PitrFullBackupStorageProvider) if in.StorageClassName != nil { diff --git a/manifests/crd/br.pingcap.com_restores.yaml b/manifests/crd/br.pingcap.com_restores.yaml index bff0b44be2..a8aff8cb20 100644 --- a/manifests/crd/br.pingcap.com_restores.yaml +++ b/manifests/crd/br.pingcap.com_restores.yaml @@ -7307,12 +7307,6 @@ spec: items: type: string type: array - tikvGCLifeTime: - description: |- - TikvGCLifeTime is to specify the safe gc life time for restore. - The time limit during which data is retained for each GC, in the format of Go Duration. - When a GC happens, the current time minus this value is the safe point. - type: string tolerateSingleTiKVOutage: default: false description: TolerateSingleTiKVOutage indicates whether to tolerate From cbad4558b3095cdd4742493708077156a6728f01 Mon Sep 17 00:00:00 2001 From: chenfei Date: Thu, 20 Feb 2025 07:32:07 +0000 Subject: [PATCH 12/15] Refine API definition --- api/br/v1alpha1/backup_types.go | 9 +++++---- api/br/v1alpha1/restore_types.go | 11 +++++++---- api/br/v1alpha1/zz_generated.deepcopy.go | 20 ++++++++++---------- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/api/br/v1alpha1/backup_types.go b/api/br/v1alpha1/backup_types.go index c1b4492465..dd3d9ed8e9 100644 --- a/api/br/v1alpha1/backup_types.go +++ b/api/br/v1alpha1/backup_types.go @@ -299,16 +299,17 @@ type BackupSpec struct { // *** Note: This field should generally not be left empty, unless you are certain the storage provider // *** can be obtained from another source, such as a schedule CR. StorageProvider `json:",inline"` + // BRConfig is the configs for BR + // *** Note: This field should generally not be left empty, unless you are certain the BR config + // *** can be obtained from another source, such as a schedule CR. + BR *BRConfig `json:"br,omitempty"` + // The storageClassName of the persistent volume for Backup data storage. // Defaults to Kubernetes default storage class. // +optional StorageClassName *string `json:"storageClassName,omitempty"` // StorageSize is the request storage size for backup job StorageSize string `json:"storageSize,omitempty"` - // BRConfig is the configs for BR - // *** Note: This field should generally not be left empty, unless you are certain the BR config - // *** can be obtained from another source, such as a schedule CR. - BR *BRConfig `json:"br,omitempty"` // CommitTs is the commit ts of the backup, snapshot ts for full backup or start ts for log backup. // Format supports TSO or datetime, e.g. '400036290571534337', '2018-05-11 01:42:23'. diff --git a/api/br/v1alpha1/restore_types.go b/api/br/v1alpha1/restore_types.go index aa6abe665a..f0d5c5988d 100644 --- a/api/br/v1alpha1/restore_types.go +++ b/api/br/v1alpha1/restore_types.go @@ -126,24 +126,27 @@ type RestoreSpec struct { // Mode is the restore mode. such as snapshot or pitr. // +kubebuilder:default=snapshot Mode RestoreMode `json:"restoreMode,omitempty"` + // StorageProvider configures where and how backups should be stored. + StorageProvider `json:",inline"` + // BR is the configs for BR. + BR *BRConfig `json:"br,omitempty"` + // PitrRestoredTs is the pitr restored ts. PitrRestoredTs string `json:"pitrRestoredTs,omitempty"` // LogRestoreStartTs is the start timestamp which log restore from. // +optional LogRestoreStartTs string `json:"logRestoreStartTs,omitempty"` - // StorageProvider configures where and how backups should be stored. - StorageProvider `json:",inline"` // PitrFullBackupStorageProvider configures where and how pitr dependent full backup should be stored. // +optional PitrFullBackupStorageProvider StorageProvider `json:"pitrFullBackupStorageProvider,omitempty"` + // The storageClassName of the persistent volume for Restore data storage. // Defaults to Kubernetes default storage class. // +optional StorageClassName *string `json:"storageClassName,omitempty"` // StorageSize is the request storage size for backup job StorageSize string `json:"storageSize,omitempty"` - // BR is the configs for BR. - BR *BRConfig `json:"br,omitempty"` + // Base tolerations of restore Pods, components may add more tolerations upon this respectively // +optional Tolerations []corev1.Toleration `json:"tolerations,omitempty"` diff --git a/api/br/v1alpha1/zz_generated.deepcopy.go b/api/br/v1alpha1/zz_generated.deepcopy.go index 95b71a1be2..9cdf636309 100644 --- a/api/br/v1alpha1/zz_generated.deepcopy.go +++ b/api/br/v1alpha1/zz_generated.deepcopy.go @@ -386,16 +386,16 @@ func (in *BackupSpec) DeepCopyInto(out *BackupSpec) { } } in.StorageProvider.DeepCopyInto(&out.StorageProvider) - if in.StorageClassName != nil { - in, out := &in.StorageClassName, &out.StorageClassName - *out = new(string) - **out = **in - } if in.BR != nil { in, out := &in.BR, &out.BR *out = new(BRConfig) (*in).DeepCopyInto(*out) } + if in.StorageClassName != nil { + in, out := &in.StorageClassName, &out.StorageClassName + *out = new(string) + **out = **in + } if in.Tolerations != nil { in, out := &in.Tolerations, &out.Tolerations *out = make([]v1.Toleration, len(*in)) @@ -868,17 +868,17 @@ func (in *RestoreSpec) DeepCopyInto(out *RestoreSpec) { } } in.StorageProvider.DeepCopyInto(&out.StorageProvider) + if in.BR != nil { + in, out := &in.BR, &out.BR + *out = new(BRConfig) + (*in).DeepCopyInto(*out) + } in.PitrFullBackupStorageProvider.DeepCopyInto(&out.PitrFullBackupStorageProvider) if in.StorageClassName != nil { in, out := &in.StorageClassName, &out.StorageClassName *out = new(string) **out = **in } - if in.BR != nil { - in, out := &in.BR, &out.BR - *out = new(BRConfig) - (*in).DeepCopyInto(*out) - } if in.Tolerations != nil { in, out := &in.Tolerations, &out.Tolerations *out = make([]v1.Toleration, len(*in)) From a08473e07ca2ca6fd2fcd4bbb9b940571b5940b2 Mon Sep 17 00:00:00 2001 From: chenfei Date: Thu, 20 Feb 2025 07:51:21 +0000 Subject: [PATCH 13/15] Address lint --- .golangci.yml | 3 +++ pkg/controllers/br/manager/util/util2_test.go | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.golangci.yml b/.golangci.yml index 062fac9e7e..b70987d4d0 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -126,3 +126,6 @@ issues: run: timeout: 15m + skip-files: + - ".*/br/.*/_test.go" + - ".*/br/.*/testutils/.*" diff --git a/pkg/controllers/br/manager/util/util2_test.go b/pkg/controllers/br/manager/util/util2_test.go index d2e61745ec..dd326f1404 100644 --- a/pkg/controllers/br/manager/util/util2_test.go +++ b/pkg/controllers/br/manager/util/util2_test.go @@ -192,7 +192,6 @@ func TestCombineStringMap(t *testing.T) { res = CombineStringMap(nil, b, c, dropped) g.Expect(res).Should(Equal(expect2)) - } func TestCopyStringMap(t *testing.T) { From 9b0d9a176a2fc853c05ada05e84f4584c767f5d9 Mon Sep 17 00:00:00 2001 From: chenfei Date: Thu, 20 Feb 2025 08:00:35 +0000 Subject: [PATCH 14/15] Add missing test files --- pkg/controllers/br/manager/testutils/br.go | 89 ++++++++ .../br/manager/testutils/helpers.go | 216 ++++++++++++++++++ 2 files changed, 305 insertions(+) create mode 100644 pkg/controllers/br/manager/testutils/br.go create mode 100644 pkg/controllers/br/manager/testutils/helpers.go diff --git a/pkg/controllers/br/manager/testutils/br.go b/pkg/controllers/br/manager/testutils/br.go new file mode 100644 index 0000000000..30f88b6a6e --- /dev/null +++ b/pkg/controllers/br/manager/testutils/br.go @@ -0,0 +1,89 @@ +// Copyright 2024 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright 2020 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// See the License for the specific language governing permissions and +// limitations under the License. + +package testutils + +import ( + corev1 "k8s.io/api/core/v1" + + brv1alpha1 "github.com/pingcap/tidb-operator/api/v2/br/v1alpha1" +) + +// GenValidStorageProviders generates valid storage providers +func GenValidStorageProviders() []brv1alpha1.StorageProvider { + return []brv1alpha1.StorageProvider{ + { + S3: &brv1alpha1.S3StorageProvider{ + Bucket: "s3", + Prefix: "prefix-", + Endpoint: "s3://localhost:80", + }, + }, + { + S3: &brv1alpha1.S3StorageProvider{ + Bucket: "s3", + Prefix: "prefix-", + Endpoint: "s3://localhost:80", + SecretName: "s3", + }, + }, + { + Gcs: &brv1alpha1.GcsStorageProvider{ + ProjectId: "gcs", + Bucket: "gcs", + Prefix: "prefix-", + }, + }, + { + Gcs: &brv1alpha1.GcsStorageProvider{ + ProjectId: "gcs", + Bucket: "gcs", + Prefix: "prefix-", + SecretName: "gcs", + }, + }, + { + Local: &brv1alpha1.LocalStorageProvider{ + Prefix: "prefix-", + Volume: corev1.Volume{ + Name: "nfs", + VolumeSource: corev1.VolumeSource{ + NFS: &corev1.NFSVolumeSource{ + Server: "fake-server", + Path: "/some/path", + ReadOnly: true, + }, + }, + }, + VolumeMount: corev1.VolumeMount{ + Name: "nfs", + MountPath: "/some/path", + }, + }, + }, + } +} diff --git a/pkg/controllers/br/manager/testutils/helpers.go b/pkg/controllers/br/manager/testutils/helpers.go new file mode 100644 index 0000000000..eea7772baa --- /dev/null +++ b/pkg/controllers/br/manager/testutils/helpers.go @@ -0,0 +1,216 @@ +// Copyright 2024 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright 2020 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// See the License for the specific language governing permissions and +// limitations under the License. + +package testutils + +import ( + "context" + "testing" + "time" + + . "github.com/onsi/gomega" + batchv1 "k8s.io/api/batch/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + + "sigs.k8s.io/controller-runtime/pkg/client" + + brv1alpha1 "github.com/pingcap/tidb-operator/api/v2/br/v1alpha1" + corev1alpha1 "github.com/pingcap/tidb-operator/api/v2/core/v1alpha1" + "github.com/pingcap/tidb-operator/pkg/controllers/br/manager/constants" +) + +// Helper is for testing backup related code only +type Helper struct { + T *testing.T + Cli client.Client +} + +// NewHelper returns a helper encapsulation +func NewHelper(t *testing.T, cli client.Client) *Helper { + return &Helper{ + T: t, + Cli: cli, + } +} + +// Close closes the stop channel +func (h *Helper) Close() { +} + +// JobExists checks whether a k8s Job exists +func (h *Helper) JobExists(restore *brv1alpha1.Restore) { + h.T.Helper() + g := NewGomegaWithT(h.T) + job := &batchv1.Job{} + err := h.Cli.Get(context.TODO(), types.NamespacedName{Namespace: restore.Namespace, Name: restore.GetRestoreJobName()}, job) + g.Expect(err).Should(BeNil()) +} + +func (h *Helper) createSecret(namespace, secretName string) { + g := NewGomegaWithT(h.T) + s := &corev1.Secret{} + s.Data = map[string][]byte{ + constants.TidbPasswordKey: []byte("dummy"), + constants.GcsCredentialsKey: []byte("dummy"), + constants.S3AccessKey: []byte("dummy"), + constants.S3SecretKey: []byte("dummy"), + } + s.Namespace = namespace + s.Name = secretName + err := h.Cli.Create(context.TODO(), s) + g.Expect(err).Should(BeNil()) +} + +// CreateSecret creates secrets based on backup/restore spec +func (h *Helper) CreateSecret(obj interface{}) { + h.T.Helper() + g := NewGomegaWithT(h.T) + if obj1, ok := obj.(*brv1alpha1.Backup); ok { + if obj1.Spec.StorageProvider.S3 != nil && obj1.Spec.StorageProvider.S3.SecretName != "" { + h.createSecret(obj1.Namespace, obj1.Spec.StorageProvider.S3.SecretName) + g.Eventually(func() error { + secret := &corev1.Secret{} + err := h.Cli.Get(context.TODO(), types.NamespacedName{Namespace: obj1.Namespace, Name: obj1.Spec.StorageProvider.S3.SecretName}, secret) + return err + }, time.Second*10).Should(BeNil()) + } else if obj1.Spec.StorageProvider.Gcs != nil && obj1.Spec.StorageProvider.Gcs.SecretName != "" { + h.createSecret(obj1.Namespace, obj1.Spec.StorageProvider.Gcs.SecretName) + g.Eventually(func() error { + secret := &corev1.Secret{} + err := h.Cli.Get(context.TODO(), types.NamespacedName{Namespace: obj1.Namespace, Name: obj1.Spec.StorageProvider.Gcs.SecretName}, secret) + return err + }, time.Second*10).Should(BeNil()) + } + } else if obj2, ok := obj.(*brv1alpha1.Restore); ok { + if obj2.Spec.StorageProvider.S3 != nil && obj2.Spec.StorageProvider.S3.SecretName != "" { + h.createSecret(obj2.Namespace, obj2.Spec.StorageProvider.S3.SecretName) + g.Eventually(func() error { + secret := &corev1.Secret{} + err := h.Cli.Get(context.TODO(), types.NamespacedName{Namespace: obj2.Namespace, Name: obj2.Spec.StorageProvider.S3.SecretName}, secret) + return err + }, time.Second*10).Should(BeNil()) + } else if obj2.Spec.StorageProvider.Gcs != nil && obj2.Spec.StorageProvider.Gcs.SecretName != "" { + h.createSecret(obj2.Namespace, obj2.Spec.StorageProvider.Gcs.SecretName) + g.Eventually(func() error { + secret := &corev1.Secret{} + err := h.Cli.Get(context.TODO(), types.NamespacedName{Namespace: obj2.Namespace, Name: obj2.Spec.StorageProvider.Gcs.SecretName}, secret) + return err + }, time.Second*10).Should(BeNil()) + } + } +} + +// CreateTC creates a Cluster with name `clusterName` in ns `namespace` +func (h *Helper) CreateTC(namespace, clusterName string, acrossK8s, recoverMode bool) { + h.T.Helper() + g := NewGomegaWithT(h.T) + var err error + + tc := &corev1alpha1.Cluster{ + Spec: corev1alpha1.ClusterSpec{ + SuspendAction: &corev1alpha1.SuspendAction{}, + TLSCluster: &corev1alpha1.TLSCluster{}, + BootstrapSQL: &corev1.LocalObjectReference{}, + UpgradePolicy: "", + Paused: false, + RevisionHistoryLimit: new(int32), + }, + Status: corev1alpha1.ClusterStatus{}, + } + tc.Namespace = namespace + tc.Name = clusterName + err = h.Cli.Create(context.TODO(), tc) + g.Expect(err).Should(BeNil()) + // make sure can read tc from lister + g.Eventually(func() error { + tc := &corev1alpha1.Cluster{} + err := h.Cli.Get(context.TODO(), types.NamespacedName{Namespace: tc.Namespace, Name: tc.Name}, tc) + return err + }, time.Second*10).Should(BeNil()) + g.Expect(err).Should(BeNil()) +} + +// // CreateTCWithNoTiKV creates a TidbCluster with name `clusterName` in ns `namespace` with no TiKV nodes +// func (h *Helper) CreateTCWithNoTiKV(namespace, clusterName string, acrossK8s, recoverMode bool) { +// h.T.Helper() +// g := NewGomegaWithT(h.T) +// var err error + +// tc := &v1alpha1.TidbCluster{ +// Spec: v1alpha1.TidbClusterSpec{ +// AcrossK8s: acrossK8s, +// RecoveryMode: recoverMode, +// TLSCluster: &v1alpha1.TLSCluster{Enabled: true}, +// TiKV: &v1alpha1.TiKVSpec{ +// BaseImage: "pingcap/tikv", +// Replicas: 3, +// StorageVolumes: []v1alpha1.StorageVolume{ +// {MountPath: "/var/lib/raft", Name: "raft", StorageSize: "50Gi"}, +// {MountPath: "/var/lib/wal", Name: "wal", StorageSize: "50Gi"}, +// }, +// }, +// TiDB: &v1alpha1.TiDBSpec{ +// TLSClient: &v1alpha1.TiDBTLSClient{Enabled: true}, +// }, +// PD: &v1alpha1.PDSpec{ +// Replicas: 1, +// }, +// }, +// Status: v1alpha1.TidbClusterStatus{ +// PD: v1alpha1.PDStatus{ +// Members: map[string]v1alpha1.PDMember{ +// "pd-0": {Name: "pd-0", Health: true}, +// }, +// }, +// }, +// } +// tc.Namespace = namespace +// tc.Name = clusterName +// _, err = h.Deps.Clientset.PingcapV1alpha1().TidbClusters(tc.Namespace).Create(context.TODO(), tc, metav1.CreateOptions{}) +// g.Expect(err).Should(BeNil()) +// // make sure can read tc from lister +// g.Eventually(func() error { +// _, err := h.Deps.TiDBClusterLister.TidbClusters(tc.Namespace).Get(tc.Name) +// return err +// }, time.Second*10).Should(BeNil()) +// g.Expect(err).Should(BeNil()) +// } + +func (h *Helper) CreateRestore(restore *brv1alpha1.Restore) { + h.T.Helper() + g := NewGomegaWithT(h.T) + err := h.Cli.Create(context.TODO(), restore) + g.Expect(err).Should(BeNil()) + // make sure can read tc from lister + g.Eventually(func() error { + restore := &brv1alpha1.Restore{} + err := h.Cli.Get(context.TODO(), types.NamespacedName{Namespace: restore.Namespace, Name: restore.Name}, restore) + return err + }, time.Second).Should(BeNil()) + g.Expect(err).Should(BeNil()) +} From ea3036ff43c2a0bb66e500d3aee015bfa698d6a0 Mon Sep 17 00:00:00 2001 From: chenfei Date: Thu, 20 Feb 2025 08:04:01 +0000 Subject: [PATCH 15/15] Address lint --- api/br/v1alpha1/backup_test.go | 14 +++++++++++++ api/go.mod | 7 +++++-- api/go.sum | 20 +++++++++++++++---- go.mod | 10 +++++----- go.sum | 20 +++++++++---------- pkg/controllers/br/manager/util/util2_test.go | 14 +++++++++++++ 6 files changed, 64 insertions(+), 21 deletions(-) diff --git a/api/br/v1alpha1/backup_test.go b/api/br/v1alpha1/backup_test.go index b6a38fdcc0..50e2449fe7 100644 --- a/api/br/v1alpha1/backup_test.go +++ b/api/br/v1alpha1/backup_test.go @@ -1,3 +1,17 @@ +// Copyright 2024 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package v1alpha1 import ( diff --git a/api/go.mod b/api/go.mod index d26d37f8f9..be3a9c806b 100644 --- a/api/go.mod +++ b/api/go.mod @@ -5,6 +5,7 @@ go 1.22.0 toolchain go1.22.3 require ( + github.com/onsi/gomega v1.36.2 k8s.io/api v0.31.0 k8s.io/apimachinery v0.31.0 ) @@ -13,15 +14,17 @@ require ( github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/x448/float16 v0.8.4 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/text v0.17.0 // indirect + golang.org/x/net v0.33.0 // indirect + golang.org/x/text v0.21.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect diff --git a/api/go.sum b/api/go.sum index d5b938d762..27b81b80b1 100644 --- a/api/go.sum +++ b/api/go.sum @@ -6,6 +6,8 @@ github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -14,6 +16,8 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -27,6 +31,10 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/onsi/ginkgo/v2 v2.22.1 h1:QW7tbJAUDyVDVOM5dFa7qaybo+CRfR7bemlQUN6Z8aM= +github.com/onsi/ginkgo/v2 v2.22.1/go.mod h1:S6aTpoRsSq2cZOd+pssHAlKW/Q/jZt6cPrPlnj4a1xM= +github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= +github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -51,22 +59,26 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8= +golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/go.mod b/go.mod index fab74e8227..68ce7520b1 100644 --- a/go.mod +++ b/go.mod @@ -25,8 +25,8 @@ require ( github.com/google/go-cmp v0.6.0 github.com/mitchellh/mapstructure v1.5.0 github.com/olekukonko/tablewriter v0.0.5 - github.com/onsi/ginkgo/v2 v2.19.0 - github.com/onsi/gomega v1.34.1 + github.com/onsi/ginkgo/v2 v2.22.1 + github.com/onsi/gomega v1.36.2 github.com/pelletier/go-toml/v2 v2.2.2 github.com/pingcap/errors v0.11.4 github.com/pingcap/kvproto v0.0.0-20240403065636-c699538f7aa1 @@ -132,7 +132,7 @@ require ( github.com/golang/protobuf v1.5.4 // indirect github.com/google/btree v1.0.1 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/pprof v0.0.0-20240711041743-f6c9dda6c6da // indirect + github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect github.com/google/s2a-go v0.1.8 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.6.0 // indirect @@ -188,14 +188,14 @@ require ( gocloud.dev v0.18.0 golang.org/x/crypto v0.32.0 // indirect golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect - golang.org/x/mod v0.20.0 // indirect + golang.org/x/mod v0.22.0 // indirect golang.org/x/net v0.34.0 // indirect golang.org/x/oauth2 v0.24.0 // indirect golang.org/x/sys v0.29.0 // indirect golang.org/x/term v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect golang.org/x/time v0.8.0 // indirect - golang.org/x/tools v0.24.0 // indirect + golang.org/x/tools v0.28.0 // indirect golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/api v0.214.0 // indirect diff --git a/go.sum b/go.sum index c9f48ba444..6e6a9f6f9e 100644 --- a/go.sum +++ b/go.sum @@ -288,8 +288,8 @@ github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible/go.m github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20240711041743-f6c9dda6c6da h1:xRmpO92tb8y+Z85iUOMOicpCfaYcv7o3Cg3wKrIpg8g= -github.com/google/pprof v0.0.0-20240711041743-f6c9dda6c6da/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= @@ -389,10 +389,10 @@ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= -github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= -github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= -github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= -github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= +github.com/onsi/ginkgo/v2 v2.22.1 h1:QW7tbJAUDyVDVOM5dFa7qaybo+CRfR7bemlQUN6Z8aM= +github.com/onsi/ginkgo/v2 v2.22.1/go.mod h1:S6aTpoRsSq2cZOd+pssHAlKW/Q/jZt6cPrPlnj4a1xM= +github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= +github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= @@ -529,8 +529,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= -golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= +golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -643,8 +643,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= -golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= -golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8= +golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/pkg/controllers/br/manager/util/util2_test.go b/pkg/controllers/br/manager/util/util2_test.go index dd326f1404..6606de1967 100644 --- a/pkg/controllers/br/manager/util/util2_test.go +++ b/pkg/controllers/br/manager/util/util2_test.go @@ -1,3 +1,17 @@ +// Copyright 2024 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package util import (