From 9240101c7ea41828496108dbe9a07e9812a8729f Mon Sep 17 00:00:00 2001 From: RidRisR <79858083+RidRisR@users.noreply.github.com> Date: Mon, 28 Oct 2024 04:35:01 +0100 Subject: [PATCH 01/49] new types --- docs/api-references/docs.md | 225 +++- manifests/crd.yaml | 992 ++++++++++++++++++ .../crd/v1/pingcap.com_compactbackups.yaml | 992 ++++++++++++++++++ .../pingcap/v1alpha1/openapi_generated.go | 109 ++ pkg/apis/pingcap/v1alpha1/types.go | 28 + .../pingcap/v1alpha1/zz_generated.deepcopy.go | 62 ++ .../typed/pingcap/v1alpha1/compactbackup.go | 175 +++ .../v1alpha1/fake/fake_compactbackup.go | 126 +++ .../v1alpha1/fake/fake_pingcap_client.go | 4 + .../pingcap/v1alpha1/generated_expansion.go | 2 + .../typed/pingcap/v1alpha1/pingcap_client.go | 5 + .../informers/externalversions/generic.go | 2 + .../pingcap/v1alpha1/compactbackup.go | 87 ++ .../pingcap/v1alpha1/interface.go | 7 + .../listers/pingcap/v1alpha1/compactbackup.go | 96 ++ .../pingcap/v1alpha1/expansion_generated.go | 8 + 16 files changed, 2919 insertions(+), 1 deletion(-) create mode 100644 manifests/crd/v1/pingcap.com_compactbackups.yaml create mode 100644 pkg/client/clientset/versioned/typed/pingcap/v1alpha1/compactbackup.go create mode 100644 pkg/client/clientset/versioned/typed/pingcap/v1alpha1/fake/fake_compactbackup.go create mode 100644 pkg/client/informers/externalversions/pingcap/v1alpha1/compactbackup.go create mode 100644 pkg/client/listers/pingcap/v1alpha1/compactbackup.go diff --git a/docs/api-references/docs.md b/docs/api-references/docs.md index 8367f02c8c..45249bf48a 100644 --- a/docs/api-references/docs.md +++ b/docs/api-references/docs.md @@ -3447,6 +3447,7 @@ string
(Appears on: BackupSpec, +CompactSpec, RestoreSpec)
@@ -3867,7 +3868,8 @@ string
(Appears on: -BackupSpec) +BackupSpec, +CompactSpec)
BackupType represents the backup mode, such as snapshot backup or log backup.
@@ -5335,6 +5337,225 @@ FlashSecurity ++
+Field | +Description | +||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
+metadata
+
+
+Kubernetes meta/v1.ObjectMeta
+
+
+ |
+
+Refer to the Kubernetes API documentation for the fields of the
+metadata field.
+ |
+||||||||||||
+spec
+
+
+CompactSpec
+
+
+ |
+
+ + +
|
+
+(Appears on: +CompactBackup) +
++
BackupSpec contains the backup specification for a tidb cluster.
+ +Field | +Description | +
---|---|
+resources
+
+
+Kubernetes core/v1.ResourceRequirements
+
+
+ |
++ | +
+env
+
+
+[]Kubernetes core/v1.EnvVar
+
+
+ |
++(Optional) + | +
+from
+
+
+TiDBAccessConfig
+
+
+ |
+
+ From is the tidb cluster that needs to backup. + |
+
+backupMode
+
+
+BackupMode
+
+
+ |
++ | +
+StorageProvider
+
+
+StorageProvider
+
+
+ |
+
+
+(Members of StorageProvider configures where and how backups should be stored. + |
+
+br
+
+
+BRConfig
+
+
+ |
+
+ BRConfig is the configs for BR + |
+
ComponentAccessor is the interface to access component details, which respects the cluster-level properties @@ -15861,6 +16082,7 @@ More info: BackupSpec, +CompactSpec, RestoreSpec)
@@ -16750,6 +16972,7 @@ map[github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.StorageVolumeName
(Appears on: BackupSpec, +CompactSpec, RestoreSpec)
diff --git a/manifests/crd.yaml b/manifests/crd.yaml index 063308006f..4d0c3000d0 100644 --- a/manifests/crd.yaml +++ b/manifests/crd.yaml @@ -7051,6 +7051,998 @@ spec: --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + name: compactbackups.pingcap.com +spec: + group: pingcap.com + names: + kind: CompactBackup + listKind: CompactBackupList + plural: compactbackups + shortNames: + - bk + singular: compactbackup + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + azblob: + properties: + accessTier: + type: string + container: + type: string + path: + type: string + prefix: + type: string + sasToken: + type: string + secretName: + type: string + storageAccount: + type: string + type: object + backupMode: + default: snapshot + type: string + br: + properties: + checkRequirements: + type: boolean + checksum: + type: boolean + cluster: + type: string + clusterNamespace: + type: string + concurrency: + format: int32 + type: integer + db: + type: string + logLevel: + type: string + onLine: + type: boolean + options: + items: + type: string + type: array + rateLimit: + type: integer + sendCredToTikv: + type: boolean + statusAddr: + type: string + table: + type: string + timeAgo: + type: string + required: + - cluster + type: object + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + from: + properties: + host: + type: string + port: + format: int32 + type: integer + secretName: + type: string + tlsClientSecretName: + type: string + user: + type: string + required: + - host + - secretName + type: object + gcs: + properties: + bucket: + type: string + bucketAcl: + type: string + location: + type: string + objectAcl: + type: string + path: + type: string + prefix: + type: string + projectId: + type: string + secretName: + type: string + storageClass: + type: string + required: + - projectId + type: object + local: + properties: + prefix: + type: string + volume: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + type: string + kind: + type: string + readOnly: + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + wwids: + items: + type: string + type: array + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + type: string + monitors: + items: + type: string + type: array + pool: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + volumeMount: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + required: + - volume + - volumeMount + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + s3: + properties: + acl: + type: string + bucket: + type: string + endpoint: + type: string + options: + items: + type: string + type: array + path: + type: string + prefix: + type: string + provider: + type: string + region: + type: string + secretName: + type: string + sse: + type: string + storageClass: + type: string + required: + - provider + type: object + type: object + required: + - metadata + - spec + type: object + served: true + storage: true +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.15.0 diff --git a/manifests/crd/v1/pingcap.com_compactbackups.yaml b/manifests/crd/v1/pingcap.com_compactbackups.yaml new file mode 100644 index 0000000000..1421cffcdb --- /dev/null +++ b/manifests/crd/v1/pingcap.com_compactbackups.yaml @@ -0,0 +1,992 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + name: compactbackups.pingcap.com +spec: + group: pingcap.com + names: + kind: CompactBackup + listKind: CompactBackupList + plural: compactbackups + shortNames: + - bk + singular: compactbackup + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + azblob: + properties: + accessTier: + type: string + container: + type: string + path: + type: string + prefix: + type: string + sasToken: + type: string + secretName: + type: string + storageAccount: + type: string + type: object + backupMode: + default: snapshot + type: string + br: + properties: + checkRequirements: + type: boolean + checksum: + type: boolean + cluster: + type: string + clusterNamespace: + type: string + concurrency: + format: int32 + type: integer + db: + type: string + logLevel: + type: string + onLine: + type: boolean + options: + items: + type: string + type: array + rateLimit: + type: integer + sendCredToTikv: + type: boolean + statusAddr: + type: string + table: + type: string + timeAgo: + type: string + required: + - cluster + type: object + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + from: + properties: + host: + type: string + port: + format: int32 + type: integer + secretName: + type: string + tlsClientSecretName: + type: string + user: + type: string + required: + - host + - secretName + type: object + gcs: + properties: + bucket: + type: string + bucketAcl: + type: string + location: + type: string + objectAcl: + type: string + path: + type: string + prefix: + type: string + projectId: + type: string + secretName: + type: string + storageClass: + type: string + required: + - projectId + type: object + local: + properties: + prefix: + type: string + volume: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + type: string + kind: + type: string + readOnly: + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + wwids: + items: + type: string + type: array + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + type: string + monitors: + items: + type: string + type: array + pool: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + volumeMount: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + required: + - volume + - volumeMount + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + s3: + properties: + acl: + type: string + bucket: + type: string + endpoint: + type: string + options: + items: + type: string + type: array + path: + type: string + prefix: + type: string + provider: + type: string + region: + type: string + secretName: + type: string + sse: + type: string + storageClass: + type: string + required: + - provider + type: object + type: object + required: + - metadata + - spec + type: object + served: true + storage: true diff --git a/pkg/apis/pingcap/v1alpha1/openapi_generated.go b/pkg/apis/pingcap/v1alpha1/openapi_generated.go index 4f789a1a7e..ecb4d3e23b 100644 --- a/pkg/apis/pingcap/v1alpha1/openapi_generated.go +++ b/pkg/apis/pingcap/v1alpha1/openapi_generated.go @@ -46,6 +46,8 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.CleanOption": schema_pkg_apis_pingcap_v1alpha1_CleanOption(ref), "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.ClusterRef": schema_pkg_apis_pingcap_v1alpha1_ClusterRef(ref), "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.CommonConfig": schema_pkg_apis_pingcap_v1alpha1_CommonConfig(ref), + "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.CompactBackup": schema_pkg_apis_pingcap_v1alpha1_CompactBackup(ref), + "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.CompactSpec": schema_pkg_apis_pingcap_v1alpha1_CompactSpec(ref), "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.ComponentSpec": schema_pkg_apis_pingcap_v1alpha1_ComponentSpec(ref), "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.ConfigMapRef": schema_pkg_apis_pingcap_v1alpha1_ConfigMapRef(ref), "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.DMCluster": schema_pkg_apis_pingcap_v1alpha1_DMCluster(ref), @@ -1621,6 +1623,113 @@ func schema_pkg_apis_pingcap_v1alpha1_CommonConfig(ref common.ReferenceCallback) } } +func schema_pkg_apis_pingcap_v1alpha1_CompactBackup(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "spec": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.CompactSpec"), + }, + }, + }, + Required: []string{"spec"}, + }, + }, + Dependencies: []string{ + "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.CompactSpec"}, + } +} + +func schema_pkg_apis_pingcap_v1alpha1_CompactSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "BackupSpec contains the backup specification for a tidb cluster.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "resources": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/api/core/v1.ResourceRequirements"), + }, + }, + "env": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/api/core/v1.EnvVar"), + }, + }, + }, + }, + }, + "from": { + SchemaProps: spec.SchemaProps{ + Description: "From is the tidb cluster that needs to backup.", + Ref: ref("github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.TiDBAccessConfig"), + }, + }, + "backupMode": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + "s3": { + SchemaProps: spec.SchemaProps{ + Ref: ref("github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.S3StorageProvider"), + }, + }, + "gcs": { + SchemaProps: spec.SchemaProps{ + Ref: ref("github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.GcsStorageProvider"), + }, + }, + "azblob": { + SchemaProps: spec.SchemaProps{ + Ref: ref("github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.AzblobStorageProvider"), + }, + }, + "local": { + SchemaProps: spec.SchemaProps{ + Ref: ref("github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.LocalStorageProvider"), + }, + }, + "br": { + SchemaProps: spec.SchemaProps{ + Description: "BRConfig is the configs for BR", + Ref: ref("github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.BRConfig"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.AzblobStorageProvider", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.BRConfig", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.GcsStorageProvider", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.LocalStorageProvider", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.S3StorageProvider", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.TiDBAccessConfig", "k8s.io/api/core/v1.EnvVar", "k8s.io/api/core/v1.ResourceRequirements"}, + } +} + func schema_pkg_apis_pingcap_v1alpha1_ComponentSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/pkg/apis/pingcap/v1alpha1/types.go b/pkg/apis/pingcap/v1alpha1/types.go index 5532fc5660..b52008fb7a 100644 --- a/pkg/apis/pingcap/v1alpha1/types.go +++ b/pkg/apis/pingcap/v1alpha1/types.go @@ -3431,3 +3431,31 @@ type ScalePolicy struct { // +optional ScaleOutParallelism *int32 `json:"scaleOutParallelism,omitempty"` } + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +k8s:openapi-gen=true +// +kubebuilder:resource:shortName="bk" +type CompactBackup struct { + metav1.TypeMeta `json:",inline"` + // +k8s:openapi-gen=false + metav1.ObjectMeta `json:"metadata"` + + Spec CompactSpec `json:"spec"` +} + +// BackupSpec contains the backup specification for a tidb cluster. +// +k8s:openapi-gen=true +type CompactSpec struct { + corev1.ResourceRequirements `json:"resources,omitempty"` + // +optional + Env []corev1.EnvVar `json:"env,omitempty"` + // From is the tidb cluster that needs to backup. + From *TiDBAccessConfig `json:"from,omitempty"` + // +kubebuilder:default=snapshot + Mode BackupMode `json:"backupMode,omitempty"` + // StorageProvider configures where and how backups should be stored. + StorageProvider `json:",inline"` + // BRConfig is the configs for BR + BR *BRConfig `json:"br,omitempty"` +} diff --git a/pkg/apis/pingcap/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/pingcap/v1alpha1/zz_generated.deepcopy.go index b65b9dca1d..e9e5f29518 100644 --- a/pkg/apis/pingcap/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/pingcap/v1alpha1/zz_generated.deepcopy.go @@ -865,6 +865,68 @@ func (in *CommonConfig) DeepCopy() *CommonConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CompactBackup) DeepCopyInto(out *CompactBackup) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CompactBackup. +func (in *CompactBackup) DeepCopy() *CompactBackup { + if in == nil { + return nil + } + out := new(CompactBackup) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CompactBackup) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CompactSpec) DeepCopyInto(out *CompactSpec) { + *out = *in + in.ResourceRequirements.DeepCopyInto(&out.ResourceRequirements) + if in.Env != nil { + in, out := &in.Env, &out.Env + *out = make([]v1.EnvVar, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.From != nil { + in, out := &in.From, &out.From + *out = new(TiDBAccessConfig) + (*in).DeepCopyInto(*out) + } + in.StorageProvider.DeepCopyInto(&out.StorageProvider) + if in.BR != nil { + in, out := &in.BR, &out.BR + *out = new(BRConfig) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CompactSpec. +func (in *CompactSpec) DeepCopy() *CompactSpec { + if in == nil { + return nil + } + out := new(CompactSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ComponentSpec) DeepCopyInto(out *ComponentSpec) { *out = *in diff --git a/pkg/client/clientset/versioned/typed/pingcap/v1alpha1/compactbackup.go b/pkg/client/clientset/versioned/typed/pingcap/v1alpha1/compactbackup.go new file mode 100644 index 0000000000..de71c963d9 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/pingcap/v1alpha1/compactbackup.go @@ -0,0 +1,175 @@ +// Copyright 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. + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + "time" + + v1alpha1 "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1" + scheme "github.com/pingcap/tidb-operator/pkg/client/clientset/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// CompactBackupsGetter has a method to return a CompactBackupInterface. +// A group's client should implement this interface. +type CompactBackupsGetter interface { + CompactBackups(namespace string) CompactBackupInterface +} + +// CompactBackupInterface has methods to work with CompactBackup resources. +type CompactBackupInterface interface { + Create(ctx context.Context, compactBackup *v1alpha1.CompactBackup, opts v1.CreateOptions) (*v1alpha1.CompactBackup, error) + Update(ctx context.Context, compactBackup *v1alpha1.CompactBackup, opts v1.UpdateOptions) (*v1alpha1.CompactBackup, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.CompactBackup, error) + List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.CompactBackupList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.CompactBackup, err error) + CompactBackupExpansion +} + +// compactBackups implements CompactBackupInterface +type compactBackups struct { + client rest.Interface + ns string +} + +// newCompactBackups returns a CompactBackups +func newCompactBackups(c *PingcapV1alpha1Client, namespace string) *compactBackups { + return &compactBackups{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the compactBackup, and returns the corresponding compactBackup object, and an error if there is any. +func (c *compactBackups) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.CompactBackup, err error) { + result = &v1alpha1.CompactBackup{} + err = c.client.Get(). + Namespace(c.ns). + Resource("compactbackups"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of CompactBackups that match those selectors. +func (c *compactBackups) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.CompactBackupList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.CompactBackupList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("compactbackups"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested compactBackups. +func (c *compactBackups) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("compactbackups"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a compactBackup and creates it. Returns the server's representation of the compactBackup, and an error, if there is any. +func (c *compactBackups) Create(ctx context.Context, compactBackup *v1alpha1.CompactBackup, opts v1.CreateOptions) (result *v1alpha1.CompactBackup, err error) { + result = &v1alpha1.CompactBackup{} + err = c.client.Post(). + Namespace(c.ns). + Resource("compactbackups"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(compactBackup). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a compactBackup and updates it. Returns the server's representation of the compactBackup, and an error, if there is any. +func (c *compactBackups) Update(ctx context.Context, compactBackup *v1alpha1.CompactBackup, opts v1.UpdateOptions) (result *v1alpha1.CompactBackup, err error) { + result = &v1alpha1.CompactBackup{} + err = c.client.Put(). + Namespace(c.ns). + Resource("compactbackups"). + Name(compactBackup.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(compactBackup). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the compactBackup and deletes it. Returns an error if one occurs. +func (c *compactBackups) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("compactbackups"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *compactBackups) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("compactbackups"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched compactBackup. +func (c *compactBackups) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.CompactBackup, err error) { + result = &v1alpha1.CompactBackup{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("compactbackups"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/pingcap/v1alpha1/fake/fake_compactbackup.go b/pkg/client/clientset/versioned/typed/pingcap/v1alpha1/fake/fake_compactbackup.go new file mode 100644 index 0000000000..725757a8ae --- /dev/null +++ b/pkg/client/clientset/versioned/typed/pingcap/v1alpha1/fake/fake_compactbackup.go @@ -0,0 +1,126 @@ +// Copyright 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. + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1alpha1 "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeCompactBackups implements CompactBackupInterface +type FakeCompactBackups struct { + Fake *FakePingcapV1alpha1 + ns string +} + +var compactbackupsResource = v1alpha1.SchemeGroupVersion.WithResource("compactbackups") + +var compactbackupsKind = v1alpha1.SchemeGroupVersion.WithKind("CompactBackup") + +// Get takes name of the compactBackup, and returns the corresponding compactBackup object, and an error if there is any. +func (c *FakeCompactBackups) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.CompactBackup, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(compactbackupsResource, c.ns, name), &v1alpha1.CompactBackup{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.CompactBackup), err +} + +// List takes label and field selectors, and returns the list of CompactBackups that match those selectors. +func (c *FakeCompactBackups) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.CompactBackupList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(compactbackupsResource, compactbackupsKind, c.ns, opts), &v1alpha1.CompactBackupList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.CompactBackupList{ListMeta: obj.(*v1alpha1.CompactBackupList).ListMeta} + for _, item := range obj.(*v1alpha1.CompactBackupList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested compactBackups. +func (c *FakeCompactBackups) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(compactbackupsResource, c.ns, opts)) + +} + +// Create takes the representation of a compactBackup and creates it. Returns the server's representation of the compactBackup, and an error, if there is any. +func (c *FakeCompactBackups) Create(ctx context.Context, compactBackup *v1alpha1.CompactBackup, opts v1.CreateOptions) (result *v1alpha1.CompactBackup, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(compactbackupsResource, c.ns, compactBackup), &v1alpha1.CompactBackup{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.CompactBackup), err +} + +// Update takes the representation of a compactBackup and updates it. Returns the server's representation of the compactBackup, and an error, if there is any. +func (c *FakeCompactBackups) Update(ctx context.Context, compactBackup *v1alpha1.CompactBackup, opts v1.UpdateOptions) (result *v1alpha1.CompactBackup, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(compactbackupsResource, c.ns, compactBackup), &v1alpha1.CompactBackup{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.CompactBackup), err +} + +// Delete takes name of the compactBackup and deletes it. Returns an error if one occurs. +func (c *FakeCompactBackups) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(compactbackupsResource, c.ns, name, opts), &v1alpha1.CompactBackup{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeCompactBackups) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(compactbackupsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.CompactBackupList{}) + return err +} + +// Patch applies the patch and returns the patched compactBackup. +func (c *FakeCompactBackups) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.CompactBackup, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(compactbackupsResource, c.ns, name, pt, data, subresources...), &v1alpha1.CompactBackup{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.CompactBackup), err +} diff --git a/pkg/client/clientset/versioned/typed/pingcap/v1alpha1/fake/fake_pingcap_client.go b/pkg/client/clientset/versioned/typed/pingcap/v1alpha1/fake/fake_pingcap_client.go index 80dcf44250..94f1896e3e 100644 --- a/pkg/client/clientset/versioned/typed/pingcap/v1alpha1/fake/fake_pingcap_client.go +++ b/pkg/client/clientset/versioned/typed/pingcap/v1alpha1/fake/fake_pingcap_client.go @@ -33,6 +33,10 @@ func (c *FakePingcapV1alpha1) BackupSchedules(namespace string) v1alpha1.BackupS return &FakeBackupSchedules{c, namespace} } +func (c *FakePingcapV1alpha1) CompactBackups(namespace string) v1alpha1.CompactBackupInterface { + return &FakeCompactBackups{c, namespace} +} + func (c *FakePingcapV1alpha1) DMClusters(namespace string) v1alpha1.DMClusterInterface { return &FakeDMClusters{c, namespace} } diff --git a/pkg/client/clientset/versioned/typed/pingcap/v1alpha1/generated_expansion.go b/pkg/client/clientset/versioned/typed/pingcap/v1alpha1/generated_expansion.go index 6799967ce4..d5d8f8681e 100644 --- a/pkg/client/clientset/versioned/typed/pingcap/v1alpha1/generated_expansion.go +++ b/pkg/client/clientset/versioned/typed/pingcap/v1alpha1/generated_expansion.go @@ -19,6 +19,8 @@ type BackupExpansion interface{} type BackupScheduleExpansion interface{} +type CompactBackupExpansion interface{} + type DMClusterExpansion interface{} type DataResourceExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/pingcap/v1alpha1/pingcap_client.go b/pkg/client/clientset/versioned/typed/pingcap/v1alpha1/pingcap_client.go index 126a8b75a6..cb570a8b87 100644 --- a/pkg/client/clientset/versioned/typed/pingcap/v1alpha1/pingcap_client.go +++ b/pkg/client/clientset/versioned/typed/pingcap/v1alpha1/pingcap_client.go @@ -27,6 +27,7 @@ type PingcapV1alpha1Interface interface { RESTClient() rest.Interface BackupsGetter BackupSchedulesGetter + CompactBackupsGetter DMClustersGetter DataResourcesGetter RestoresGetter @@ -51,6 +52,10 @@ func (c *PingcapV1alpha1Client) BackupSchedules(namespace string) BackupSchedule return newBackupSchedules(c, namespace) } +func (c *PingcapV1alpha1Client) CompactBackups(namespace string) CompactBackupInterface { + return newCompactBackups(c, namespace) +} + func (c *PingcapV1alpha1Client) DMClusters(namespace string) DMClusterInterface { return newDMClusters(c, namespace) } diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index a5ccab2deb..6b07e7efe1 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -54,6 +54,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource return &genericInformer{resource: resource.GroupResource(), informer: f.Pingcap().V1alpha1().Backups().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("backupschedules"): return &genericInformer{resource: resource.GroupResource(), informer: f.Pingcap().V1alpha1().BackupSchedules().Informer()}, nil + case v1alpha1.SchemeGroupVersion.WithResource("compactbackups"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Pingcap().V1alpha1().CompactBackups().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("dmclusters"): return &genericInformer{resource: resource.GroupResource(), informer: f.Pingcap().V1alpha1().DMClusters().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("dataresources"): diff --git a/pkg/client/informers/externalversions/pingcap/v1alpha1/compactbackup.go b/pkg/client/informers/externalversions/pingcap/v1alpha1/compactbackup.go new file mode 100644 index 0000000000..47083cb76a --- /dev/null +++ b/pkg/client/informers/externalversions/pingcap/v1alpha1/compactbackup.go @@ -0,0 +1,87 @@ +// Copyright 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. + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + time "time" + + pingcapv1alpha1 "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1" + versioned "github.com/pingcap/tidb-operator/pkg/client/clientset/versioned" + internalinterfaces "github.com/pingcap/tidb-operator/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "github.com/pingcap/tidb-operator/pkg/client/listers/pingcap/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// CompactBackupInformer provides access to a shared informer and lister for +// CompactBackups. +type CompactBackupInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.CompactBackupLister +} + +type compactBackupInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewCompactBackupInformer constructs a new informer for CompactBackup type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewCompactBackupInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredCompactBackupInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredCompactBackupInformer constructs a new informer for CompactBackup type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredCompactBackupInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.PingcapV1alpha1().CompactBackups(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.PingcapV1alpha1().CompactBackups(namespace).Watch(context.TODO(), options) + }, + }, + &pingcapv1alpha1.CompactBackup{}, + resyncPeriod, + indexers, + ) +} + +func (f *compactBackupInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredCompactBackupInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *compactBackupInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&pingcapv1alpha1.CompactBackup{}, f.defaultInformer) +} + +func (f *compactBackupInformer) Lister() v1alpha1.CompactBackupLister { + return v1alpha1.NewCompactBackupLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/pingcap/v1alpha1/interface.go b/pkg/client/informers/externalversions/pingcap/v1alpha1/interface.go index 7ea63ea74a..2e5e23b7a6 100644 --- a/pkg/client/informers/externalversions/pingcap/v1alpha1/interface.go +++ b/pkg/client/informers/externalversions/pingcap/v1alpha1/interface.go @@ -25,6 +25,8 @@ type Interface interface { Backups() BackupInformer // BackupSchedules returns a BackupScheduleInformer. BackupSchedules() BackupScheduleInformer + // CompactBackups returns a CompactBackupInformer. + CompactBackups() CompactBackupInformer // DMClusters returns a DMClusterInformer. DMClusters() DMClusterInformer // DataResources returns a DataResourceInformer. @@ -66,6 +68,11 @@ func (v *version) BackupSchedules() BackupScheduleInformer { return &backupScheduleInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} } +// CompactBackups returns a CompactBackupInformer. +func (v *version) CompactBackups() CompactBackupInformer { + return &compactBackupInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + // DMClusters returns a DMClusterInformer. func (v *version) DMClusters() DMClusterInformer { return &dMClusterInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} diff --git a/pkg/client/listers/pingcap/v1alpha1/compactbackup.go b/pkg/client/listers/pingcap/v1alpha1/compactbackup.go new file mode 100644 index 0000000000..0e4f26d86f --- /dev/null +++ b/pkg/client/listers/pingcap/v1alpha1/compactbackup.go @@ -0,0 +1,96 @@ +// Copyright 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. + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// CompactBackupLister helps list CompactBackups. +// All objects returned here must be treated as read-only. +type CompactBackupLister interface { + // List lists all CompactBackups in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.CompactBackup, err error) + // CompactBackups returns an object that can list and get CompactBackups. + CompactBackups(namespace string) CompactBackupNamespaceLister + CompactBackupListerExpansion +} + +// compactBackupLister implements the CompactBackupLister interface. +type compactBackupLister struct { + indexer cache.Indexer +} + +// NewCompactBackupLister returns a new CompactBackupLister. +func NewCompactBackupLister(indexer cache.Indexer) CompactBackupLister { + return &compactBackupLister{indexer: indexer} +} + +// List lists all CompactBackups in the indexer. +func (s *compactBackupLister) List(selector labels.Selector) (ret []*v1alpha1.CompactBackup, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.CompactBackup)) + }) + return ret, err +} + +// CompactBackups returns an object that can list and get CompactBackups. +func (s *compactBackupLister) CompactBackups(namespace string) CompactBackupNamespaceLister { + return compactBackupNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// CompactBackupNamespaceLister helps list and get CompactBackups. +// All objects returned here must be treated as read-only. +type CompactBackupNamespaceLister interface { + // List lists all CompactBackups in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.CompactBackup, err error) + // Get retrieves the CompactBackup from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*v1alpha1.CompactBackup, error) + CompactBackupNamespaceListerExpansion +} + +// compactBackupNamespaceLister implements the CompactBackupNamespaceLister +// interface. +type compactBackupNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all CompactBackups in the indexer for a given namespace. +func (s compactBackupNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.CompactBackup, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.CompactBackup)) + }) + return ret, err +} + +// Get retrieves the CompactBackup from the indexer for a given namespace and name. +func (s compactBackupNamespaceLister) Get(name string) (*v1alpha1.CompactBackup, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("compactbackup"), name) + } + return obj.(*v1alpha1.CompactBackup), nil +} diff --git a/pkg/client/listers/pingcap/v1alpha1/expansion_generated.go b/pkg/client/listers/pingcap/v1alpha1/expansion_generated.go index 5b0bb67412..f2cb82902b 100644 --- a/pkg/client/listers/pingcap/v1alpha1/expansion_generated.go +++ b/pkg/client/listers/pingcap/v1alpha1/expansion_generated.go @@ -31,6 +31,14 @@ type BackupScheduleListerExpansion interface{} // BackupScheduleNamespaceLister. type BackupScheduleNamespaceListerExpansion interface{} +// CompactBackupListerExpansion allows custom methods to be added to +// CompactBackupLister. +type CompactBackupListerExpansion interface{} + +// CompactBackupNamespaceListerExpansion allows custom methods to be added to +// CompactBackupNamespaceLister. +type CompactBackupNamespaceListerExpansion interface{} + // DMClusterListerExpansion allows custom methods to be added to // DMClusterLister. type DMClusterListerExpansion interface{} From df3c1917f0a41c27e0ffb0cf9fa8dda6a204b7a1 Mon Sep 17 00:00:00 2001 From: RidRisR <79858083+RidRisR@users.noreply.github.com> Date: Mon, 28 Oct 2024 06:53:49 +0100 Subject: [PATCH 02/49] add new crd --- cmd/controller-manager/main.go | 2 + docs/api-references/docs.md | 39 ++++++ go.mod | 1 + go.sum | 2 + manifests/crd.yaml | 15 ++- .../crd/v1/pingcap.com_compactbackups.yaml | 15 ++- .../pingcap/v1alpha1/openapi_generated.go | 44 ++++++ pkg/apis/pingcap/v1alpha1/types.go | 21 ++- .../pingcap/v1alpha1/zz_generated.deepcopy.go | 50 +++++++ .../typed/pingcap/v1alpha1/compactbackup.go | 17 +++ .../v1alpha1/fake/fake_compactbackup.go | 12 ++ .../compact_backup_controller.go | 126 ++++++++++++++++++ 12 files changed, 339 insertions(+), 5 deletions(-) create mode 100644 pkg/controller/compactbackup/compact_backup_controller.go diff --git a/cmd/controller-manager/main.go b/cmd/controller-manager/main.go index 991de3e2eb..283de5583c 100644 --- a/cmd/controller-manager/main.go +++ b/cmd/controller-manager/main.go @@ -31,6 +31,7 @@ import ( "github.com/pingcap/tidb-operator/pkg/controller/autoscaler" "github.com/pingcap/tidb-operator/pkg/controller/backup" "github.com/pingcap/tidb-operator/pkg/controller/backupschedule" + compact "github.com/pingcap/tidb-operator/pkg/controller/compactbackup" "github.com/pingcap/tidb-operator/pkg/controller/dmcluster" "github.com/pingcap/tidb-operator/pkg/controller/restore" "github.com/pingcap/tidb-operator/pkg/controller/tidbcluster" @@ -182,6 +183,7 @@ func main() { tidbcluster.NewPodController(deps), dmcluster.NewController(deps), backup.NewController(deps), + compact.NewController(deps), restore.NewController(deps), backupschedule.NewController(deps), tidbinitializer.NewController(deps), diff --git a/docs/api-references/docs.md b/docs/api-references/docs.md index 45249bf48a..9273c83cc9 100644 --- a/docs/api-references/docs.md +++ b/docs/api-references/docs.md @@ -5457,6 +5457,18 @@ BRConfig +
status
+
+
+CompactStatus
+
+
++(Appears on: +CompactBackup) +
++
+Field | +Description | +
---|---|
+state
+
+string
+
+ |
++ | +
ComponentAccessor is the interface to access component details, which respects the cluster-level properties diff --git a/go.mod b/go.mod index c9ad495768..dcd301c2a8 100644 --- a/go.mod +++ b/go.mod @@ -214,6 +214,7 @@ require ( gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/klog v1.0.0 k8s.io/kms v0.28.14 // indirect k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.1.2 // indirect diff --git a/go.sum b/go.sum index 317846741e..0ce9d0a1c7 100644 --- a/go.sum +++ b/go.sum @@ -1155,6 +1155,8 @@ k8s.io/component-base v0.28.14 h1:sJowHyRY166hBfBQ4cOKjkSvUo4bUdeuePtEOQfSNRY= k8s.io/component-base v0.28.14/go.mod h1:DgYlfHNvP1yeBb4L+UIzMsWNtOl0yqTk+4dGGc79H0w= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= diff --git a/manifests/crd.yaml b/manifests/crd.yaml index 4d0c3000d0..f774305743 100644 --- a/manifests/crd.yaml +++ b/manifests/crd.yaml @@ -7062,11 +7062,16 @@ spec: listKind: CompactBackupList plural: compactbackups shortNames: - - bk + - cpbk singular: compactbackup scope: Namespaced versions: - - name: v1alpha1 + - additionalPrinterColumns: + - description: The current status of the compact backup + jsonPath: .status.state + name: Status + type: string + name: v1alpha1 schema: openAPIV3Schema: properties: @@ -8034,12 +8039,18 @@ spec: - provider type: object type: object + status: + properties: + state: + type: string + type: object required: - metadata - spec type: object served: true storage: true + subresources: {} --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/manifests/crd/v1/pingcap.com_compactbackups.yaml b/manifests/crd/v1/pingcap.com_compactbackups.yaml index 1421cffcdb..e9f4194e1f 100644 --- a/manifests/crd/v1/pingcap.com_compactbackups.yaml +++ b/manifests/crd/v1/pingcap.com_compactbackups.yaml @@ -12,11 +12,16 @@ spec: listKind: CompactBackupList plural: compactbackups shortNames: - - bk + - cpbk singular: compactbackup scope: Namespaced versions: - - name: v1alpha1 + - additionalPrinterColumns: + - description: The current status of the compact backup + jsonPath: .status.state + name: Status + type: string + name: v1alpha1 schema: openAPIV3Schema: properties: @@ -984,9 +989,15 @@ spec: - provider type: object type: object + status: + properties: + state: + type: string + type: object required: - metadata - spec type: object served: true storage: true + subresources: {} diff --git a/pkg/apis/pingcap/v1alpha1/openapi_generated.go b/pkg/apis/pingcap/v1alpha1/openapi_generated.go index ecb4d3e23b..7a8e44f238 100644 --- a/pkg/apis/pingcap/v1alpha1/openapi_generated.go +++ b/pkg/apis/pingcap/v1alpha1/openapi_generated.go @@ -47,6 +47,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.ClusterRef": schema_pkg_apis_pingcap_v1alpha1_ClusterRef(ref), "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.CommonConfig": schema_pkg_apis_pingcap_v1alpha1_CommonConfig(ref), "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.CompactBackup": schema_pkg_apis_pingcap_v1alpha1_CompactBackup(ref), + "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.CompactBackupList": schema_pkg_apis_pingcap_v1alpha1_CompactBackupList(ref), "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.CompactSpec": schema_pkg_apis_pingcap_v1alpha1_CompactSpec(ref), "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.ComponentSpec": schema_pkg_apis_pingcap_v1alpha1_ComponentSpec(ref), "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.ConfigMapRef": schema_pkg_apis_pingcap_v1alpha1_ConfigMapRef(ref), @@ -1658,6 +1659,49 @@ func schema_pkg_apis_pingcap_v1alpha1_CompactBackup(ref common.ReferenceCallback } } +func schema_pkg_apis_pingcap_v1alpha1_CompactBackupList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "CompactList contains a list of Compact Backup.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.CompactBackup"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.CompactBackup"}, + } +} + func schema_pkg_apis_pingcap_v1alpha1_CompactSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/pkg/apis/pingcap/v1alpha1/types.go b/pkg/apis/pingcap/v1alpha1/types.go index b52008fb7a..0a8fe7b8ce 100644 --- a/pkg/apis/pingcap/v1alpha1/types.go +++ b/pkg/apis/pingcap/v1alpha1/types.go @@ -3435,13 +3435,16 @@ type ScalePolicy struct { // +genclient // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // +k8s:openapi-gen=true -// +kubebuilder:resource:shortName="bk" +// +kubebuilder:resource:shortName="cpbk" +// +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.state`,description="The current status of the compact backup" type CompactBackup struct { metav1.TypeMeta `json:",inline"` // +k8s:openapi-gen=false metav1.ObjectMeta `json:"metadata"` Spec CompactSpec `json:"spec"` + // +k8s:openapi-gen=false + Status CompactStatus `json:"status,omitempty"` } // BackupSpec contains the backup specification for a tidb cluster. @@ -3459,3 +3462,19 @@ type CompactSpec struct { // BRConfig is the configs for BR BR *BRConfig `json:"br,omitempty"` } + +type CompactStatus struct { + State string `json:"state,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// +k8s:openapi-gen=true +// CompactList contains a list of Compact Backup. +type CompactBackupList struct { + metav1.TypeMeta `json:",inline"` + // +k8s:openapi-gen=false + metav1.ListMeta `json:"metadata"` + + Items []CompactBackup `json:"items"` +} diff --git a/pkg/apis/pingcap/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/pingcap/v1alpha1/zz_generated.deepcopy.go index e9e5f29518..fc0b823152 100644 --- a/pkg/apis/pingcap/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/pingcap/v1alpha1/zz_generated.deepcopy.go @@ -871,6 +871,7 @@ func (in *CompactBackup) DeepCopyInto(out *CompactBackup) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) + out.Status = in.Status return } @@ -892,6 +893,39 @@ func (in *CompactBackup) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CompactBackupList) DeepCopyInto(out *CompactBackupList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]CompactBackup, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CompactBackupList. +func (in *CompactBackupList) DeepCopy() *CompactBackupList { + if in == nil { + return nil + } + out := new(CompactBackupList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CompactBackupList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CompactSpec) DeepCopyInto(out *CompactSpec) { *out = *in @@ -927,6 +961,22 @@ func (in *CompactSpec) DeepCopy() *CompactSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CompactStatus) DeepCopyInto(out *CompactStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CompactStatus. +func (in *CompactStatus) DeepCopy() *CompactStatus { + if in == nil { + return nil + } + out := new(CompactStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ComponentSpec) DeepCopyInto(out *ComponentSpec) { *out = *in diff --git a/pkg/client/clientset/versioned/typed/pingcap/v1alpha1/compactbackup.go b/pkg/client/clientset/versioned/typed/pingcap/v1alpha1/compactbackup.go index de71c963d9..a42c9972de 100644 --- a/pkg/client/clientset/versioned/typed/pingcap/v1alpha1/compactbackup.go +++ b/pkg/client/clientset/versioned/typed/pingcap/v1alpha1/compactbackup.go @@ -37,6 +37,7 @@ type CompactBackupsGetter interface { type CompactBackupInterface interface { Create(ctx context.Context, compactBackup *v1alpha1.CompactBackup, opts v1.CreateOptions) (*v1alpha1.CompactBackup, error) Update(ctx context.Context, compactBackup *v1alpha1.CompactBackup, opts v1.UpdateOptions) (*v1alpha1.CompactBackup, error) + UpdateStatus(ctx context.Context, compactBackup *v1alpha1.CompactBackup, opts v1.UpdateOptions) (*v1alpha1.CompactBackup, error) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.CompactBackup, error) @@ -132,6 +133,22 @@ func (c *compactBackups) Update(ctx context.Context, compactBackup *v1alpha1.Com return } +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *compactBackups) UpdateStatus(ctx context.Context, compactBackup *v1alpha1.CompactBackup, opts v1.UpdateOptions) (result *v1alpha1.CompactBackup, err error) { + result = &v1alpha1.CompactBackup{} + err = c.client.Put(). + Namespace(c.ns). + Resource("compactbackups"). + Name(compactBackup.Name). + SubResource("status"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(compactBackup). + Do(ctx). + Into(result) + return +} + // Delete takes name of the compactBackup and deletes it. Returns an error if one occurs. func (c *compactBackups) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { return c.client.Delete(). diff --git a/pkg/client/clientset/versioned/typed/pingcap/v1alpha1/fake/fake_compactbackup.go b/pkg/client/clientset/versioned/typed/pingcap/v1alpha1/fake/fake_compactbackup.go index 725757a8ae..2a7e2d387c 100644 --- a/pkg/client/clientset/versioned/typed/pingcap/v1alpha1/fake/fake_compactbackup.go +++ b/pkg/client/clientset/versioned/typed/pingcap/v1alpha1/fake/fake_compactbackup.go @@ -98,6 +98,18 @@ func (c *FakeCompactBackups) Update(ctx context.Context, compactBackup *v1alpha1 return obj.(*v1alpha1.CompactBackup), err } +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeCompactBackups) UpdateStatus(ctx context.Context, compactBackup *v1alpha1.CompactBackup, opts v1.UpdateOptions) (*v1alpha1.CompactBackup, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(compactbackupsResource, "status", c.ns, compactBackup), &v1alpha1.CompactBackup{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.CompactBackup), err +} + // Delete takes name of the compactBackup and deletes it. Returns an error if one occurs. func (c *FakeCompactBackups) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. diff --git a/pkg/controller/compactbackup/compact_backup_controller.go b/pkg/controller/compactbackup/compact_backup_controller.go new file mode 100644 index 0000000000..83bed8c0ef --- /dev/null +++ b/pkg/controller/compactbackup/compact_backup_controller.go @@ -0,0 +1,126 @@ +package compact + +import ( + "fmt" + "time" + + perrors "github.com/pingcap/errors" + "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1" + "github.com/pingcap/tidb-operator/pkg/controller" + "github.com/pingcap/tidb-operator/pkg/metrics" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/tools/cache" + "k8s.io/client-go/util/workqueue" + "k8s.io/klog" +) + +// Controller controls backup. +type Controller struct { + deps *controller.Dependencies + // backups that need to be synced. + queue workqueue.RateLimitingInterface +} + +// NewController creates a backup controller. +func NewController(deps *controller.Dependencies) *Controller { + c := &Controller{ + deps: deps, + queue: workqueue.NewNamedRateLimitingQueue( + controller.NewControllerRateLimiter(1*time.Second, 100*time.Second), + "backup", + ), + } + + backupInformer := deps.InformerFactory.Pingcap().V1alpha1().Backups() + jobInformer := deps.KubeInformerFactory.Batch().V1().Jobs() + backupInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ + AddFunc: c.updateBackup, + UpdateFunc: func(old, cur interface{}) { + c.updateBackup(cur) + }, + DeleteFunc: c.updateBackup, + }) + jobInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ + DeleteFunc: c.updateBackup, + }) + + return c +} + +// Name returns backup controller name. +func (c *Controller) Name() string { + return "compactBackup" +} + +// Run runs the backup controller. +func (c *Controller) Run(workers int, stopCh <-chan struct{}) { + defer utilruntime.HandleCrash() + defer c.queue.ShutDown() + + klog.Info("Starting backup controller") + defer klog.Info("Shutting down backup controller") + + for i := 0; i < workers; i++ { + go wait.Until(c.worker, time.Second, stopCh) + } + + <-stopCh +} + +// worker runs a worker goroutine that invokes processNextWorkItem until the the controller's queue is closed +func (c *Controller) worker() { + for c.processNextWorkItem() { + } +} + +func (c *Controller) updateBackup(cur interface{}) { + newBackup := cur.(*v1alpha1.CompactBackup) + ns := newBackup.GetNamespace() + name := newBackup.GetName() + + klog.Infof("backup object %s/%s enqueue", ns, name) + c.enqueueBackup(newBackup) +} + +// enqueueBackup enqueues the given backup in the work queue. +func (c *Controller) enqueueBackup(obj interface{}) { + key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj) + if err != nil { + utilruntime.HandleError(fmt.Errorf("cound't get key for object %+v: %v", obj, err)) + return + } + c.queue.Add(key) +} + +// processNextWorkItem dequeues items, processes them, and marks them done. It enforces that the syncHandler is never +// invoked concurrently with the same key. +func (c *Controller) processNextWorkItem() bool { + metrics.ActiveWorkers.WithLabelValues(c.Name()).Add(1) + defer metrics.ActiveWorkers.WithLabelValues(c.Name()).Add(-1) + + key, quit := c.queue.Get() + if quit { + return false + } + defer c.queue.Done(key) + if err := c.sync(key.(string)); err != nil { + if perrors.Find(err, controller.IsRequeueError) != nil { + klog.Infof("Backup: %v, still need sync: %v, requeuing", key.(string), err) + c.queue.AddRateLimited(key) + } else if perrors.Find(err, controller.IsIgnoreError) != nil { + klog.Infof("Backup: %v, ignore err: %v", key.(string), err) + } else { + utilruntime.HandleError(fmt.Errorf("Backup: %v, sync failed, err: %v, requeuing", key.(string), err)) + c.queue.AddRateLimited(key) + } + } else { + c.queue.Forget(key) + } + return true +} + +func (c *Controller) sync(key string) (err error) { + klog.Infof("do nothing, skip") + return nil +} From 92c981990481a44ffaac2fa32820cdf009dd67b3 Mon Sep 17 00:00:00 2001 From: RidRisR <79858083+RidRisR@users.noreply.github.com> Date: Mon, 28 Oct 2024 08:53:55 +0100 Subject: [PATCH 03/49] trry --- pkg/apis/pingcap/v1alpha1/types.go | 104 +++++++++ .../compact_backup_controller.go | 206 +++++++++++++++++- pkg/controller/controller_utils.go | 17 ++ pkg/controller/dependences.go | 1 + 4 files changed, 327 insertions(+), 1 deletion(-) diff --git a/pkg/apis/pingcap/v1alpha1/types.go b/pkg/apis/pingcap/v1alpha1/types.go index 0a8fe7b8ce..667bc960f0 100644 --- a/pkg/apis/pingcap/v1alpha1/types.go +++ b/pkg/apis/pingcap/v1alpha1/types.go @@ -3451,16 +3451,120 @@ type CompactBackup struct { // +k8s:openapi-gen=true type CompactSpec struct { corev1.ResourceRequirements `json:"resources,omitempty"` + // List of environment variables to set in the container, like v1.Container.Env. + // Note that the following builtin env vars will be overwritten by values set here + // - S3_PROVIDER + // - S3_ENDPOINT + // - AWS_REGION + // - AWS_ACL + // - AWS_STORAGE_CLASS + // - AWS_DEFAULT_REGION + // - AWS_ACCESS_KEY_ID + // - AWS_SECRET_ACCESS_KEY + // - GCS_PROJECT_ID + // - GCS_OBJECT_ACL + // - GCS_BUCKET_ACL + // - GCS_LOCATION + // - GCS_STORAGE_CLASS + // - GCS_SERVICE_ACCOUNT_JSON_KEY + // - BR_LOG_TO_TERM // +optional Env []corev1.EnvVar `json:"env,omitempty"` // From is the tidb cluster that needs to backup. From *TiDBAccessConfig `json:"from,omitempty"` + // Type is the backup type for tidb cluster and only used when Mode = snapshot, such as full, db, table. + Type BackupType `json:"backupType,omitempty"` + // 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. StorageProvider `json:",inline"` + // 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 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. + // +optional + 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" + 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'. + // +optional + LogTruncateUntil string `json:"logTruncateUntil,omitempty"` + // LogStop indicates that will stop the log backup. + // +optional + LogStop bool `json:"logStop,omitempty"` + // CalcSizeLevel determines how to size calculation of snapshots for EBS volume snapshot backup + // +optional + // +kubebuilder:default="all" + CalcSizeLevel string `json:"calcSizeLevel,omitempty"` + // FederalVolumeBackupPhase indicates which phase to execute in federal volume backup + // +optional + FederalVolumeBackupPhase FederalVolumeBackupPhase `json:"federalVolumeBackupPhase,omitempty"` + // ResumeGcSchedule indicates whether resume gc and pd scheduler for EBS volume snapshot backup + // +optional + ResumeGcSchedule bool `json:"resumeGcSchedule,omitempty"` + // DumplingConfig is the configs for dumpling + Dumpling *DumplingConfig `json:"dumpling,omitempty"` + // Base tolerations of backup Pods, components may add more tolerations upon this respectively + // +optional + Tolerations []corev1.Toleration `json:"tolerations,omitempty"` + // ToolImage specifies the tool image used in `Backup`, which supports BR and Dumpling images. + // For examples `spec.toolImage: pingcap/br:v4.0.8` or `spec.toolImage: pingcap/dumpling:v4.0.8` + // For BR image, if it does not contain tag, Pod will use image 'ToolImage:${TiKV_Version}'. + // +optional + ToolImage string `json:"toolImage,omitempty"` + // ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images. + // +optional + ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"` + // TableFilter means Table filter expression for 'db.table' matching. BR supports this from v4.0.3. + TableFilter []string `json:"tableFilter,omitempty"` + // Affinity of backup Pods + // +optional + Affinity *corev1.Affinity `json:"affinity,omitempty"` + // Use KMS to decrypt the secrets + 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 + CleanPolicy CleanPolicyType `json:"cleanPolicy,omitempty"` + // CleanOption controls the behavior of clean. + CleanOption *CleanOption `json:"cleanOption,omitempty"` + + // PodSecurityContext of the component + // +optional + PodSecurityContext *corev1.PodSecurityContext `json:"podSecurityContext,omitempty"` + + // PriorityClassName of Backup Job Pods + PriorityClassName string `json:"priorityClassName,omitempty"` + + // BackoffRetryPolicy the backoff retry policy, currently only valid for snapshot backup + BackoffRetryPolicy BackoffRetryPolicy `json:"backoffRetryPolicy,omitempty"` + + // Additional volumes of component pod. + // +optional + AdditionalVolumes []corev1.Volume `json:"additionalVolumes,omitempty"` + // Additional volume mounts of component pod. + // +optional + AdditionalVolumeMounts []corev1.VolumeMount `json:"additionalVolumeMounts,omitempty"` + // VolumeBackupInitJobMaxActiveSeconds represents the deadline (in seconds) of the vbk init job + // +kubebuilder:default=600 + VolumeBackupInitJobMaxActiveSeconds int `json:"volumeBackupInitJobMaxActiveSeconds,omitempty"` } type CompactStatus struct { diff --git a/pkg/controller/compactbackup/compact_backup_controller.go b/pkg/controller/compactbackup/compact_backup_controller.go index 83bed8c0ef..8b604996f6 100644 --- a/pkg/controller/compactbackup/compact_backup_controller.go +++ b/pkg/controller/compactbackup/compact_backup_controller.go @@ -4,15 +4,24 @@ import ( "fmt" "time" + "github.com/pingcap/errors" perrors "github.com/pingcap/errors" + "github.com/pingcap/tidb-operator/pkg/apis/label" "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1" + "github.com/pingcap/tidb-operator/pkg/backup/constants" + backuputil "github.com/pingcap/tidb-operator/pkg/backup/util" "github.com/pingcap/tidb-operator/pkg/controller" "github.com/pingcap/tidb-operator/pkg/metrics" + "github.com/pingcap/tidb-operator/pkg/util" + batchv1 "k8s.io/api/batch/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/tools/cache" "k8s.io/client-go/util/workqueue" "k8s.io/klog" + "k8s.io/utils/pointer" ) // Controller controls backup. @@ -80,6 +89,7 @@ func (c *Controller) updateBackup(cur interface{}) { name := newBackup.GetName() klog.Infof("backup object %s/%s enqueue", ns, name) + newBackup.Status.State = "Prepare" c.enqueueBackup(newBackup) } @@ -121,6 +131,200 @@ func (c *Controller) processNextWorkItem() bool { } func (c *Controller) sync(key string) (err error) { - klog.Infof("do nothing, skip") + startTime := time.Now() + defer func() { + duration := time.Since(startTime) + metrics.ReconcileTime.WithLabelValues(c.Name()).Observe(duration.Seconds()) + + if err == nil { + metrics.ReconcileTotal.WithLabelValues(c.Name(), metrics.LabelSuccess).Inc() + } else if perrors.Find(err, controller.IsRequeueError) != nil { + metrics.ReconcileTotal.WithLabelValues(c.Name(), metrics.LabelRequeue).Inc() + } else { + metrics.ReconcileTotal.WithLabelValues(c.Name(), metrics.LabelError).Inc() + metrics.ReconcileErrors.WithLabelValues(c.Name()).Inc() + } + + klog.V(4).Infof("Finished syncing Backup %q (%v)", key, duration) + }() + + ns, name, err := cache.SplitMetaNamespaceKey(key) + if err != nil { + return err + } + backup, err := c.deps.CompactBackupLister.CompactBackups(ns).Get(name) + if errors.IsNotFound(err) { + klog.Infof("Backup has been deleted %v", key) + return nil + } + if err != nil { + return err + } + + return c.syncCompact(backup.DeepCopy()) +} + +func (c *Controller) syncCompact(backup *v1alpha1.CompactBackup) error { + ns := backup.GetNamespace() + name := backup.GetName() + backupJobName := backup.GetName() + + // make backup job + var err error + var job *batchv1.Job + var reason string + if job, reason, err = c.makeBackupJob(backup); err != nil { + klog.Errorf("backup %s/%s create job %s failed, reason is %s, error %v.", ns, name, backupJobName, reason, err) + return err + } + + // create k8s job + klog.Infof("backup %s/%s creating job %s.", ns, name, backupJobName) + if err := c.deps.JobControl.CreateJob(backup, job); err != nil { + errMsg := fmt.Errorf("create backup %s/%s job %s failed, err: %v", ns, name, backupJobName, err) + return errMsg + } return nil } + +func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job, string, error) { + ns := backup.GetNamespace() + name := backup.GetName() + jobName := backup.GetName() + backupNamespace := ns + if backup.Spec.BR.ClusterNamespace != "" { + backupNamespace = backup.Spec.BR.ClusterNamespace + } + + tc, err := c.deps.TiDBClusterLister.TidbClusters(backupNamespace).Get(backup.Spec.BR.Cluster) + if err != nil { + return nil, fmt.Sprintf("failed to fetch tidbcluster %s/%s", backupNamespace, backup.Spec.BR.Cluster), err + } + + var ( + envVars []corev1.EnvVar + reason string + ) + if backup.Spec.From != nil { + envVars, reason, err = backuputil.GenerateTidbPasswordEnv(ns, name, backup.Spec.From.SecretName, backup.Spec.UseKMS, c.deps.SecretLister) + if err != nil { + return nil, reason, err + } + } + + storageEnv, reason, err := backuputil.GenerateStorageCertEnv(ns, backup.Spec.UseKMS, backup.Spec.StorageProvider, c.deps.SecretLister) + if err != nil { + return nil, reason, fmt.Errorf("backup %s/%s, %v", ns, name, err) + } + + envVars = append(envVars, storageEnv...) + envVars = append(envVars, corev1.EnvVar{ + Name: "BR_LOG_TO_TERM", + Value: string(rune(1)), + }) + + // set env vars specified in backup.Spec.Env + envVars = util.AppendOverwriteEnv(envVars, backup.Spec.Env) + + args := []string{ + "backup", + fmt.Sprintf("--namespace=%s", ns), + fmt.Sprintf("--backupName=%s", name), + } + tikvImage := tc.TiKVImage() + _, tikvVersion := backuputil.ParseImage(tikvImage) + if tikvVersion != "" { + args = append(args, fmt.Sprintf("--tikvVersion=%s", tikvVersion)) + } + + volumeMounts := []corev1.VolumeMount{} + volumes := []corev1.Volume{} + + brVolumeMount := corev1.VolumeMount{ + Name: "br-bin", + ReadOnly: false, + MountPath: util.BRBinPath, + } + volumeMounts = append(volumeMounts, brVolumeMount) + + volumes = append(volumes, corev1.Volume{ + Name: "br-bin", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }) + + // mount volumes if specified + if backup.Spec.Local != nil { + volumes = append(volumes, backup.Spec.Local.Volume) + volumeMounts = append(volumeMounts, backup.Spec.Local.VolumeMount) + } + + serviceAccount := constants.DefaultServiceAccountName + if backup.Spec.ServiceAccount != "" { + serviceAccount = backup.Spec.ServiceAccount + } + + brImage := "pingcap/br:" + tikvVersion + jobLabels := util.CombineStringMap(label.NewBackup().Instance("Compact-test").BackupJob().Backup(name), backup.Labels) + podLabels := jobLabels + jobAnnotations := backup.Annotations + podAnnotations := backup.Annotations + + podSpec := &corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: podLabels, + Annotations: podAnnotations, + }, + Spec: corev1.PodSpec{ + SecurityContext: backup.Spec.PodSecurityContext, + ServiceAccountName: serviceAccount, + InitContainers: []corev1.Container{ + { + Name: "br", + Image: brImage, + Command: []string{"/bin/sh", "-c"}, + Args: []string{fmt.Sprintf("cp /br %s/br; echo 'BR copy finished'", util.BRBinPath)}, + ImagePullPolicy: corev1.PullIfNotPresent, + VolumeMounts: []corev1.VolumeMount{brVolumeMount}, + Resources: backup.Spec.ResourceRequirements, + }, + }, + Containers: []corev1.Container{ + { + Name: label.BackupJobLabelVal, + Image: c.deps.CLIConfig.TiDBBackupManagerImage, + Args: args, + ImagePullPolicy: corev1.PullIfNotPresent, + VolumeMounts: volumeMounts, + Env: util.AppendEnvIfPresent(envVars, "TZ"), + Resources: backup.Spec.ResourceRequirements, + }, + }, + RestartPolicy: corev1.RestartPolicyNever, + Tolerations: backup.Spec.Tolerations, + ImagePullSecrets: backup.Spec.ImagePullSecrets, + Affinity: backup.Spec.Affinity, + Volumes: volumes, + PriorityClassName: backup.Spec.PriorityClassName, + }, + } + + job := &batchv1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: jobName, + Namespace: ns, + Labels: jobLabels, + Annotations: jobAnnotations, + OwnerReferences: []metav1.OwnerReference{ + controller.GetCompactBackupOwnerRef(backup), + }, + }, + Spec: batchv1.JobSpec{ + BackoffLimit: pointer.Int32Ptr(0), + Template: *podSpec, + }, + } + + return job, "", nil +} diff --git a/pkg/controller/controller_utils.go b/pkg/controller/controller_utils.go index e432802be8..c321d0fc67 100644 --- a/pkg/controller/controller_utils.go +++ b/pkg/controller/controller_utils.go @@ -49,6 +49,9 @@ var ( // BackupControllerKind contains the schema.GroupVersionKind for backup controller type. BackupControllerKind = v1alpha1.SchemeGroupVersion.WithKind("Backup") + // CompactBackupControllerKind contains the schema.GroupVersionKind for backup controller type. + CompactBackupControllerKind = v1alpha1.SchemeGroupVersion.WithKind("CompactBackup") + // RestoreControllerKind contains the schema.GroupVersionKind for restore controller type. RestoreControllerKind = v1alpha1.SchemeGroupVersion.WithKind("Restore") @@ -159,6 +162,20 @@ func GetBackupOwnerRef(backup *v1alpha1.Backup) metav1.OwnerReference { } } +// GetCompactBackupOwnerRef returns Backup's OwnerReference +func GetCompactBackupOwnerRef(backup *v1alpha1.CompactBackup) metav1.OwnerReference { + controller := true + blockOwnerDeletion := true + return metav1.OwnerReference{ + APIVersion: CompactBackupControllerKind.GroupVersion().String(), + Kind: CompactBackupControllerKind.Kind, + Name: backup.GetName(), + UID: backup.GetUID(), + Controller: &controller, + BlockOwnerDeletion: &blockOwnerDeletion, + } +} + // GetRestoreOwnerRef returns Restore's OwnerReference func GetRestoreOwnerRef(restore *v1alpha1.Restore) metav1.OwnerReference { controller := true diff --git a/pkg/controller/dependences.go b/pkg/controller/dependences.go index 6c22b8e658..3ed7c4d6ee 100644 --- a/pkg/controller/dependences.go +++ b/pkg/controller/dependences.go @@ -233,6 +233,7 @@ type Dependencies struct { TiDBClusterAutoScalerLister listers.TidbClusterAutoScalerLister DMClusterLister listers.DMClusterLister BackupLister listers.BackupLister + CompactBackupLister listers.CompactBackupLister RestoreLister listers.RestoreLister BackupScheduleLister listers.BackupScheduleLister TiDBInitializerLister listers.TidbInitializerLister From a420fdbbca897f0d3c0f8af915ecf9d67ec40494 Mon Sep 17 00:00:00 2001 From: RidRisR <79858083+RidRisR@users.noreply.github.com> Date: Mon, 28 Oct 2024 10:35:03 +0100 Subject: [PATCH 04/49] adapt controller --- docs/api-references/docs.md | 1045 ++++++++++++-- manifests/crd.yaml | 1278 +++++++++++++++++ .../crd/v1/pingcap.com_compactbackups.yaml | 1278 +++++++++++++++++ .../pingcap/v1alpha1/openapi_generated.go | 231 ++- .../pingcap/v1alpha1/zz_generated.deepcopy.go | 62 + .../compact_backup_controller.go | 82 +- pkg/controller/dependences.go | 1 + 7 files changed, 3777 insertions(+), 200 deletions(-) diff --git a/docs/api-references/docs.md b/docs/api-references/docs.md index 9273c83cc9..f48ec8c628 100644 --- a/docs/api-references/docs.md +++ b/docs/api-references/docs.md @@ -3620,7 +3620,8 @@ bool
(Appears on: -BackupSpec) +BackupSpec, +CompactSpec)
BackoffRetryPolicy is the backoff retry policy, currently only valid for snapshot backup. @@ -4751,6 +4752,7 @@ map[github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.LogSubCommandType
(Appears on: BackupSpec, +CompactSpec, RestoreSpec)
@@ -5091,7 +5093,8 @@ github.com/pingcap/tidb-operator/pkg/apis/util/config.GenericConfig
(Appears on: -BackupSpec) +BackupSpec, +CompactSpec)
CleanOption defines the configuration for cleanup backup
@@ -5170,7 +5173,8 @@ float64(Appears on: -BackupSpec) +BackupSpec, +CompactSpec)
CleanPolicyType represents the clean policy of backup data in remote storage
@@ -5209,361 +5213,1089 @@ default to the same namespace as TidbMonitor/TidbCluster/TidbNGMonitoring/TidbDaname
+name
+
+string
+
+Name is the name of TidbCluster object
+clusterDomain
+
+string
+
+ClusterDomain is the domain of TidbCluster object
++(Appears on: +TiFlashConfig) +
++
CommonConfig is the configuration of TiFlash process.
+ +Field | +Description | +
---|---|
+tmp_path
+
+string
+
+ |
+
+(Optional)
+ Optional: Defaults to “/data0/tmp” + |
+
+path_realtime_mode
+
+bool
+
+ |
+
+(Optional)
+ Optional: Defaults to false + |
+
+mark_cache_size
+
+int64
+
+ |
+
+(Optional)
+ Optional: Defaults to 5368709120 + |
+
+minmax_index_cache_size
+
+int64
+
+ |
+
+(Optional)
+ Optional: Defaults to 5368709120 + |
+
+flash
+
+
+Flash
+
+
+ |
++(Optional) + | +
+logger
+
+
+FlashLogger
+
+
+ |
++(Optional) + | +
+security
+
+
+FlashSecurity
+
+
+ |
++(Optional) + | +
+
+Field | +Description | +||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
+metadata
+
+
+Kubernetes meta/v1.ObjectMeta
+
+
+ |
+
+Refer to the Kubernetes API documentation for the fields of the
+metadata field.
+ |
+||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+spec
+
+
+CompactSpec
+
+
+ |
+
+ + +
|
+||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+status
+
+
+CompactStatus
+
+
+ |
++ | +
+(Appears on: +CompactBackup) +
++
BackupSpec contains the backup specification for a tidb cluster.
+ +Field | +Description | +
---|---|
+resources
+
+
+Kubernetes core/v1.ResourceRequirements
+
+
+ |
++ | +
+env
+
+
+[]Kubernetes core/v1.EnvVar
+
+
+ |
+
+(Optional)
+ List of environment variables to set in the container, like v1.Container.Env. +Note that the following builtin env vars will be overwritten by values set here +- S3_PROVIDER +- S3_ENDPOINT +- AWS_REGION +- AWS_ACL +- AWS_STORAGE_CLASS +- AWS_DEFAULT_REGION +- AWS_ACCESS_KEY_ID +- AWS_SECRET_ACCESS_KEY +- GCS_PROJECT_ID +- GCS_OBJECT_ACL +- GCS_BUCKET_ACL +- GCS_LOCATION +- GCS_STORAGE_CLASS +- GCS_SERVICE_ACCOUNT_JSON_KEY +- BR_LOG_TO_TERM + |
+
+from
+
+
+TiDBAccessConfig
+
+
+ |
+
+ From is the tidb cluster that needs to backup. + |
+
+backupType
+
+
+BackupType
+
+
+ |
+
+ Type is the backup type for tidb cluster and only used when Mode = snapshot, such as full, db, table. + |
+
+backupMode
+
+
+BackupMode
+
+
+ |
+
+ Mode is the backup mode, such as snapshot backup or log backup. + |
+
+tikvGCLifeTime
+
+string
+
+ |
+
+ 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. + |
+
+StorageProvider
+
+
+StorageProvider
+
+
+ |
+
+
+(Members of StorageProvider configures where and how backups should be stored. + |
+
+storageClassName
+
+string
+
+ |
+
+(Optional)
+ The storageClassName of the persistent volume for Backup data storage. +Defaults to Kubernetes default storage class. + |
+
+storageSize
+
+string
+
+ |
+
+ StorageSize is the request storage size for backup job + |
+
+br
-string
+
+BRConfig
+
|
- Name is the name of TidbCluster object +BRConfig is the configs for BR |
-clusterDomain
+commitTs
string
|
(Optional)
- ClusterDomain is the domain of TidbCluster object +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. |
-(Appears on: -TiFlashConfig) -
--
CommonConfig is the configuration of TiFlash process.
- -Field | -Description | -
---|---|
-tmp_path
+logSubcommand
-string
+
+LogSubCommandType
+
|
(Optional)
- Optional: Defaults to “/data0/tmp” +Subcommand is the subcommand for BR, such as start, stop, pause etc. |
-path_realtime_mode
+logTruncateUntil
-bool
+string
|
(Optional)
- Optional: Defaults to false +LogTruncateUntil is log backup truncate until timestamp. +Format supports TSO or datetime, e.g. ‘400036290571534337’, ‘2018-05-11 01:42:23’. |
-mark_cache_size
+logStop
-int64
+bool
|
(Optional)
- Optional: Defaults to 5368709120 +LogStop indicates that will stop the log backup. |
-minmax_index_cache_size
+calcSizeLevel
-int64
+string
|
(Optional)
- Optional: Defaults to 5368709120 +CalcSizeLevel determines how to size calculation of snapshots for EBS volume snapshot backup |
-flash
+federalVolumeBackupPhase
-
-Flash
+
+FederalVolumeBackupPhase
|
(Optional)
+ FederalVolumeBackupPhase indicates which phase to execute in federal volume backup |
-logger
+resumeGcSchedule
-
-FlashLogger
-
+bool
|
(Optional)
+ ResumeGcSchedule indicates whether resume gc and pd scheduler for EBS volume snapshot backup |
-security
+dumpling
-
-FlashSecurity
+
+DumplingConfig
|
-(Optional)
+ DumplingConfig is the configs for dumpling |
-
-Field | -Description | -||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
-metadata
+tolerations
-
-Kubernetes meta/v1.ObjectMeta
+
+[]Kubernetes core/v1.Toleration
|
-Refer to the Kubernetes API documentation for the fields of the
-metadata field.
+(Optional)
+Base tolerations of backup Pods, components may add more tolerations upon this respectively |
||||||||||||
-spec
+toolImage
-
-CompactSpec
-
+string
|
- - -
CleanPolicy denotes whether to clean backup data when the object is deleted from the cluster, if not set, the backup data will be retained |
||||||||||||
-status
+cleanOption
-
-CompactStatus
+
+CleanOption
|
+ CleanOption controls the behavior of clean. |
-(Appears on: -CompactBackup) -
--
BackupSpec contains the backup specification for a tidb cluster.
- -Field | -Description | -||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
-resources
+podSecurityContext
-
-Kubernetes core/v1.ResourceRequirements
+
+Kubernetes core/v1.PodSecurityContext
|
+(Optional)
+ PodSecurityContext of the component |
||||||||||
-env
+priorityClassName
-
-[]Kubernetes core/v1.EnvVar
-
+string
|
-(Optional)
+ PriorityClassName of Backup Job Pods |
||||||||||
-from
+backoffRetryPolicy
-
-TiDBAccessConfig
+
+BackoffRetryPolicy
|
- From is the tidb cluster that needs to backup. +BackoffRetryPolicy the backoff retry policy, currently only valid for snapshot backup |
||||||||||
-backupMode
+additionalVolumes
-
-BackupMode
+
+[]Kubernetes core/v1.Volume
|
+(Optional)
+ Additional volumes of component pod. |
||||||||||
-StorageProvider
+additionalVolumeMounts
-
-StorageProvider
+
+[]Kubernetes core/v1.VolumeMount
|
-
-(Members of StorageProvider configures where and how backups should be stored. +(Optional) +Additional volume mounts of component pod. |
||||||||||
-br
+volumeBackupInitJobMaxActiveSeconds
-
-BRConfig
-
+int
|
- BRConfig is the configs for BR +VolumeBackupInitJobMaxActiveSeconds represents the deadline (in seconds) of the vbk init job |
||||||||||
-backupType
-
-
-BackupType
-
-
- |
-
- Type is the backup type for tidb cluster and only used when Mode = snapshot, such as full, db, table. - |
-||||||||||
-backupMode
-
-
-BackupMode
-
-
- |
-
- Mode is the backup mode, such as snapshot backup or log backup. - |
-||||||||||
tikvGCLifeTime
string
|
- 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. |
||||||||||
-(Optional)
- 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. - |
-|||||||||||
-logSubcommand
-
-
-LogSubCommandType
-
-
- |
-
-(Optional)
- Subcommand is the subcommand for BR, such as start, stop, pause etc. - |
-||||||||||
-logTruncateUntil
-
-string
-
- |
-
-(Optional)
- LogTruncateUntil is log backup truncate until timestamp. + StartTs is the start ts of the compact backup. Format supports TSO or datetime, e.g. ‘400036290571534337’, ‘2018-05-11 01:42:23’. |
||||||||||
-logStop
-
-bool
-
- |
-
-(Optional)
- LogStop indicates that will stop the log backup. - |
-||||||||||
-calcSizeLevel
+endTs
string
|
(Optional)
- CalcSizeLevel determines how to size calculation of snapshots for EBS volume snapshot backup +EndTs is the end ts of the compact backup. +Format supports TSO or datetime, e.g. ‘400036290571534337’, ‘2018-05-11 01:42:23’. +Default is current timestamp. |
||||||||||
-federalVolumeBackupPhase
+concurrency
-
-FederalVolumeBackupPhase
-
+int
|
(Optional)
- FederalVolumeBackupPhase indicates which phase to execute in federal volume backup +ResumeGcSchedule indicates whether resume gc and pd scheduler for EBS volume snapshot backup +Concurrency is the concurrency of compact backup job |
||||||||||
-(Optional)
- ResumeGcSchedule indicates whether resume gc and pd scheduler for EBS volume snapshot backup - |
-|||||||||||
-dumpling
-
-
-DumplingConfig
-
-
- |
-
- DumplingConfig is the configs for dumpling |
||||||||||
-toolImage
+brImage
string
|
(Optional)
- ToolImage specifies the tool image used in BrImage specifies the br image used in compact |
||||||||||
-tableFilter
-
-[]string
-
- |
-
- TableFilter means Table filter expression for ‘db.table’ matching. BR supports this from v4.0.3. - |
-||||||||||
affinity
@@ -5721,32 +5622,6 @@ string
| |||||||||||
-cleanPolicy
-
-
-CleanPolicyType
-
-
- |
-
- CleanPolicy denotes whether to clean backup data when the object is deleted from the cluster, if not set, the backup data will be retained - |
-||||||||||
-cleanOption
-
-
-CleanOption
-
-
- |
-
- CleanOption controls the behavior of clean. - |
-||||||||||
podSecurityContext
@@ -5912,41 +5787,12 @@ TiDBAccessConfig
| |||||||||||
-backupType
-
-
-BackupType
-
-
- |
-
- Type is the backup type for tidb cluster and only used when Mode = snapshot, such as full, db, table. - |
-||||||||||
-backupMode
-
-
-BackupMode
-
-
- |
-
- Mode is the backup mode, such as snapshot backup or log backup. - |
-||||||||||
tikvGCLifeTime
string
|
- 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. |
||||||||||
-(Optional)
- 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. - |
-|||||||||||
-logSubcommand
-
-
-LogSubCommandType
-
-
- |
-
-(Optional)
- Subcommand is the subcommand for BR, such as start, stop, pause etc. - |
-||||||||||
-logTruncateUntil
-
-string
-
- |
-
-(Optional)
- LogTruncateUntil is log backup truncate until timestamp. + StartTs is the start ts of the compact backup. Format supports TSO or datetime, e.g. ‘400036290571534337’, ‘2018-05-11 01:42:23’. |
||||||||||
-logStop
-
-bool
-
- |
-
-(Optional)
- LogStop indicates that will stop the log backup. - |
-||||||||||
-calcSizeLevel
+endTs
string
|
(Optional)
- CalcSizeLevel determines how to size calculation of snapshots for EBS volume snapshot backup +EndTs is the end ts of the compact backup. +Format supports TSO or datetime, e.g. ‘400036290571534337’, ‘2018-05-11 01:42:23’. +Default is current timestamp. |
||||||||||
-federalVolumeBackupPhase
+concurrency
-
-FederalVolumeBackupPhase
-
+int
|
(Optional)
- FederalVolumeBackupPhase indicates which phase to execute in federal volume backup +ResumeGcSchedule indicates whether resume gc and pd scheduler for EBS volume snapshot backup +Concurrency is the concurrency of compact backup job |
||||||||||
-(Optional)
- ResumeGcSchedule indicates whether resume gc and pd scheduler for EBS volume snapshot backup - |
-|||||||||||
-dumpling
-
-
-DumplingConfig
-
-
- |
-
- DumplingConfig is the configs for dumpling |
||||||||||
-toolImage
+brImage
string
|
(Optional)
- ToolImage specifies the tool image used in BrImage specifies the br image used in compact |
||||||||||
-tableFilter
-
-[]string
-
- |
-
- TableFilter means Table filter expression for ‘db.table’ matching. BR supports this from v4.0.3. - |
-||||||||||
affinity
@@ -6197,32 +5977,6 @@ string
| |||||||||||
-cleanPolicy
-
-
-CleanPolicyType
-
-
- |
-
- CleanPolicy denotes whether to clean backup data when the object is deleted from the cluster, if not set, the backup data will be retained - |
-||||||||||
-cleanOption
-
-
-CleanOption
-
-
- |
-
- CleanOption controls the behavior of clean. - |
-||||||||||
podSecurityContext
@@ -8208,8 +7962,7 @@ for other components, the auto failover feature may be used instead.
DumplingConfig(Appears on: -BackupSpec, -CompactSpec) +BackupSpec)
DumplingConfig contains config for dumpling @@ -8500,8 +8253,7 @@ it takes effect only when setspec.recoverFailover=false
FederalVolumeBackupPhase(Appears on: -BackupSpec, -CompactSpec) +BackupSpec)
FederalVolumeBackupPhase represents a phase to execute in federal volume backup @@ -9913,7 +9665,6 @@ BackupConditionType (Appears on: BackupCondition, BackupSpec, -CompactSpec, LogSubCommandStatus)diff --git a/manifests/crd.yaml b/manifests/crd.yaml index 21e5419639..fe1f2320e3 100644 --- a/manifests/crd.yaml +++ b/manifests/crd.yaml @@ -8208,11 +8208,6 @@ spec: default: 30m type: string type: object - backupMode: - default: snapshot - type: string - backupType: - type: string br: properties: checkRequirements: @@ -8249,51 +8244,14 @@ spec: required: - cluster type: object - calcSizeLevel: - default: all - type: string - cleanOption: - properties: - backoffEnabled: - type: boolean - batchConcurrency: - format: int32 - type: integer - disableBatchConcurrency: - type: boolean - pageSize: - format: int64 - type: integer - retryCount: - default: 5 - type: integer - routineConcurrency: - format: int32 - type: integer - snapshotsDeleteRatio: - default: 1 - type: number - type: object - cleanPolicy: - default: Retain - enum: - - Retain - - OnFailure - - Delete + brImage: type: string commitTs: type: string - dumpling: - properties: - options: - items: - type: string - type: array - tableFilter: - items: - type: string - type: array - type: object + concurrency: + type: integer + endTs: + type: string env: items: properties: @@ -8358,8 +8316,6 @@ spec: - name type: object type: array - federalVolumeBackupPhase: - type: string from: properties: host: @@ -9143,16 +9099,6 @@ spec: - volume - volumeMount type: object - logStop: - type: boolean - logSubcommand: - enum: - - log-start - - log-stop - - log-pause - type: string - logTruncateUntil: - type: string podSecurityContext: properties: fsGroup: @@ -9287,10 +9233,6 @@ spec: type: string storageSize: type: string - tableFilter: - items: - type: string - type: array tikvGCLifeTime: type: string tolerations: @@ -9309,8 +9251,6 @@ spec: type: string type: object type: array - toolImage: - type: string useKMS: type: boolean volumeBackupInitJobMaxActiveSeconds: diff --git a/manifests/crd/v1/pingcap.com_compactbackups.yaml b/manifests/crd/v1/pingcap.com_compactbackups.yaml index dee3552d38..feb7984243 100644 --- a/manifests/crd/v1/pingcap.com_compactbackups.yaml +++ b/manifests/crd/v1/pingcap.com_compactbackups.yaml @@ -1158,11 +1158,6 @@ spec: default: 30m type: string type: object - backupMode: - default: snapshot - type: string - backupType: - type: string br: properties: checkRequirements: @@ -1199,51 +1194,14 @@ spec: required: - cluster type: object - calcSizeLevel: - default: all - type: string - cleanOption: - properties: - backoffEnabled: - type: boolean - batchConcurrency: - format: int32 - type: integer - disableBatchConcurrency: - type: boolean - pageSize: - format: int64 - type: integer - retryCount: - default: 5 - type: integer - routineConcurrency: - format: int32 - type: integer - snapshotsDeleteRatio: - default: 1 - type: number - type: object - cleanPolicy: - default: Retain - enum: - - Retain - - OnFailure - - Delete + brImage: type: string commitTs: type: string - dumpling: - properties: - options: - items: - type: string - type: array - tableFilter: - items: - type: string - type: array - type: object + concurrency: + type: integer + endTs: + type: string env: items: properties: @@ -1308,8 +1266,6 @@ spec: - name type: object type: array - federalVolumeBackupPhase: - type: string from: properties: host: @@ -2093,16 +2049,6 @@ spec: - volume - volumeMount type: object - logStop: - type: boolean - logSubcommand: - enum: - - log-start - - log-stop - - log-pause - type: string - logTruncateUntil: - type: string podSecurityContext: properties: fsGroup: @@ -2237,10 +2183,6 @@ spec: type: string storageSize: type: string - tableFilter: - items: - type: string - type: array tikvGCLifeTime: type: string tolerations: @@ -2259,8 +2201,6 @@ spec: type: string type: object type: array - toolImage: - type: string useKMS: type: boolean volumeBackupInitJobMaxActiveSeconds: diff --git a/pkg/apis/pingcap/v1alpha1/openapi_generated.go b/pkg/apis/pingcap/v1alpha1/openapi_generated.go index 6d510d42f8..8716911d4d 100644 --- a/pkg/apis/pingcap/v1alpha1/openapi_generated.go +++ b/pkg/apis/pingcap/v1alpha1/openapi_generated.go @@ -1735,25 +1735,10 @@ func schema_pkg_apis_pingcap_v1alpha1_CompactSpec(ref common.ReferenceCallback) Ref: ref("github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.TiDBAccessConfig"), }, }, - "backupType": { - SchemaProps: spec.SchemaProps{ - Description: "Type is the backup type for tidb cluster and only used when Mode = snapshot, such as full, db, table.", - Type: []string{"string"}, - Format: "", - }, - }, - "backupMode": { - SchemaProps: spec.SchemaProps{ - Description: "Mode is the backup mode, such as snapshot backup or log backup.", - Type: []string{"string"}, - Format: "", - }, - }, "tikvGCLifeTime": { SchemaProps: spec.SchemaProps{ - 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{"string"}, - Format: "", + Type: []string{"string"}, + Format: "", }, }, "s3": { @@ -1798,57 +1783,30 @@ func schema_pkg_apis_pingcap_v1alpha1_CompactSpec(ref common.ReferenceCallback) }, "commitTs": { SchemaProps: spec.SchemaProps{ - Description: "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.", - Type: []string{"string"}, - Format: "", - }, - }, - "logSubcommand": { - SchemaProps: spec.SchemaProps{ - Description: "Subcommand is the subcommand for BR, such as start, stop, pause etc.", + Description: "StartTs is the start ts of the compact backup. Format supports TSO or datetime, e.g. '400036290571534337', '2018-05-11 01:42:23'.", Type: []string{"string"}, Format: "", }, }, - "logTruncateUntil": { + "endTs": { SchemaProps: spec.SchemaProps{ - Description: "LogTruncateUntil is log backup truncate until timestamp. Format supports TSO or datetime, e.g. '400036290571534337', '2018-05-11 01:42:23'.", + Description: "EndTs is the end ts of the compact backup. Format supports TSO or datetime, e.g. '400036290571534337', '2018-05-11 01:42:23'. Default is current timestamp.", Type: []string{"string"}, Format: "", }, }, - "logStop": { - SchemaProps: spec.SchemaProps{ - Description: "LogStop indicates that will stop the log backup.", - Type: []string{"boolean"}, - Format: "", - }, - }, - "calcSizeLevel": { - SchemaProps: spec.SchemaProps{ - Description: "CalcSizeLevel determines how to size calculation of snapshots for EBS volume snapshot backup", - Type: []string{"string"}, - Format: "", - }, - }, - "federalVolumeBackupPhase": { + "concurrency": { SchemaProps: spec.SchemaProps{ - Description: "FederalVolumeBackupPhase indicates which phase to execute in federal volume backup", - Type: []string{"string"}, - Format: "", + Description: "ResumeGcSchedule indicates whether resume gc and pd scheduler for EBS volume snapshot backup Concurrency is the concurrency of compact backup job", + Default: 4, + Type: []string{"integer"}, + Format: "int32", }, }, "resumeGcSchedule": { SchemaProps: spec.SchemaProps{ - Description: "ResumeGcSchedule indicates whether resume gc and pd scheduler for EBS volume snapshot backup", - Type: []string{"boolean"}, - Format: "", - }, - }, - "dumpling": { - SchemaProps: spec.SchemaProps{ - Description: "DumplingConfig is the configs for dumpling", - Ref: ref("github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.DumplingConfig"), + Type: []string{"boolean"}, + Format: "", }, }, "tolerations": { @@ -1865,9 +1823,9 @@ func schema_pkg_apis_pingcap_v1alpha1_CompactSpec(ref common.ReferenceCallback) }, }, }, - "toolImage": { + "brImage": { SchemaProps: spec.SchemaProps{ - Description: "ToolImage specifies the tool image used in `Backup`, which supports BR and Dumpling images. For examples `spec.toolImage: pingcap/br:v4.0.8` or `spec.toolImage: pingcap/dumpling:v4.0.8` For BR image, if it does not contain tag, Pod will use image 'ToolImage:${TiKV_Version}'.", + Description: "BrImage specifies the br image used in compact `Backup`. For examples `spec.brImage: pingcap/br:v4.0.8` For BR image, if it does not contain tag, Pod will use image 'BrImage:${TiKV_Version}'.", Type: []string{"string"}, Format: "", }, @@ -1886,21 +1844,6 @@ func schema_pkg_apis_pingcap_v1alpha1_CompactSpec(ref common.ReferenceCallback) }, }, }, - "tableFilter": { - SchemaProps: spec.SchemaProps{ - Description: "TableFilter means Table filter expression for 'db.table' matching. BR supports this from v4.0.3.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, "affinity": { SchemaProps: spec.SchemaProps{ Description: "Affinity of backup Pods", @@ -1921,19 +1864,6 @@ func schema_pkg_apis_pingcap_v1alpha1_CompactSpec(ref common.ReferenceCallback) Format: "", }, }, - "cleanPolicy": { - SchemaProps: spec.SchemaProps{ - Description: "CleanPolicy denotes whether to clean backup data when the object is deleted from the cluster, if not set, the backup data will be retained", - Type: []string{"string"}, - Format: "", - }, - }, - "cleanOption": { - SchemaProps: spec.SchemaProps{ - Description: "CleanOption controls the behavior of clean.", - Ref: ref("github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.CleanOption"), - }, - }, "podSecurityContext": { SchemaProps: spec.SchemaProps{ Description: "PodSecurityContext of the component", @@ -1993,7 +1923,7 @@ func schema_pkg_apis_pingcap_v1alpha1_CompactSpec(ref common.ReferenceCallback) }, }, Dependencies: []string{ - "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.AzblobStorageProvider", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.BRConfig", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.BackoffRetryPolicy", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.CleanOption", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.DumplingConfig", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.GcsStorageProvider", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.LocalStorageProvider", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.S3StorageProvider", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.TiDBAccessConfig", "k8s.io/api/core/v1.Affinity", "k8s.io/api/core/v1.EnvVar", "k8s.io/api/core/v1.LocalObjectReference", "k8s.io/api/core/v1.PodSecurityContext", "k8s.io/api/core/v1.ResourceRequirements", "k8s.io/api/core/v1.Toleration", "k8s.io/api/core/v1.Volume", "k8s.io/api/core/v1.VolumeMount"}, + "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.AzblobStorageProvider", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.BRConfig", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.BackoffRetryPolicy", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.GcsStorageProvider", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.LocalStorageProvider", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.S3StorageProvider", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.TiDBAccessConfig", "k8s.io/api/core/v1.Affinity", "k8s.io/api/core/v1.EnvVar", "k8s.io/api/core/v1.LocalObjectReference", "k8s.io/api/core/v1.PodSecurityContext", "k8s.io/api/core/v1.ResourceRequirements", "k8s.io/api/core/v1.Toleration", "k8s.io/api/core/v1.Volume", "k8s.io/api/core/v1.VolumeMount"}, } } diff --git a/pkg/apis/pingcap/v1alpha1/types.go b/pkg/apis/pingcap/v1alpha1/types.go index 667bc960f0..bd3a913121 100644 --- a/pkg/apis/pingcap/v1alpha1/types.go +++ b/pkg/apis/pingcap/v1alpha1/types.go @@ -3471,16 +3471,8 @@ type CompactSpec struct { // +optional Env []corev1.EnvVar `json:"env,omitempty"` // From is the tidb cluster that needs to backup. - From *TiDBAccessConfig `json:"from,omitempty"` - // Type is the backup type for tidb cluster and only used when Mode = snapshot, such as full, db, table. - Type BackupType `json:"backupType,omitempty"` - // 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"` + From *TiDBAccessConfig `json:"from,omitempty"` + TikvGCLifeTime *string `json:"tikvGCLifeTime,omitempty"` // StorageProvider configures where and how backups should be stored. StorageProvider `json:",inline"` // The storageClassName of the persistent volume for Backup data storage. @@ -3491,47 +3483,31 @@ type CompactSpec struct { StorageSize string `json:"storageSize,omitempty"` // BRConfig is the configs for BR BR *BRConfig `json:"br,omitempty"` - // CommitTs is the commit ts of the backup, snapshot ts for full backup or start ts for log backup. + // StartTs is the start ts of the compact backup. // Format supports TSO or datetime, e.g. '400036290571534337', '2018-05-11 01:42:23'. - // Default is current timestamp. - // +optional - 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" - LogSubcommand LogSubCommandType `json:"logSubcommand,omitempty"` - // LogTruncateUntil is log backup truncate until timestamp. + StartTs string `json:"commitTs,omitempty"` + // EndTs is the end ts of the compact backup. // Format supports TSO or datetime, e.g. '400036290571534337', '2018-05-11 01:42:23'. + // Default is current timestamp. // +optional - LogTruncateUntil string `json:"logTruncateUntil,omitempty"` - // LogStop indicates that will stop the log backup. - // +optional - LogStop bool `json:"logStop,omitempty"` - // CalcSizeLevel determines how to size calculation of snapshots for EBS volume snapshot backup - // +optional - // +kubebuilder:default="all" - CalcSizeLevel string `json:"calcSizeLevel,omitempty"` - // FederalVolumeBackupPhase indicates which phase to execute in federal volume backup - // +optional - FederalVolumeBackupPhase FederalVolumeBackupPhase `json:"federalVolumeBackupPhase,omitempty"` + EndTs string `json:"endTs,omitempty"` // ResumeGcSchedule indicates whether resume gc and pd scheduler for EBS volume snapshot backup // +optional + // Concurrency is the concurrency of compact backup job + // +default=4 + Concurrency int `json:"concurrency,omitempty"` ResumeGcSchedule bool `json:"resumeGcSchedule,omitempty"` - // DumplingConfig is the configs for dumpling - Dumpling *DumplingConfig `json:"dumpling,omitempty"` // Base tolerations of backup Pods, components may add more tolerations upon this respectively // +optional Tolerations []corev1.Toleration `json:"tolerations,omitempty"` - // ToolImage specifies the tool image used in `Backup`, which supports BR and Dumpling images. - // For examples `spec.toolImage: pingcap/br:v4.0.8` or `spec.toolImage: pingcap/dumpling:v4.0.8` - // For BR image, if it does not contain tag, Pod will use image 'ToolImage:${TiKV_Version}'. + // BrImage specifies the br image used in compact `Backup`. + // For examples `spec.brImage: pingcap/br:v4.0.8` + // For BR image, if it does not contain tag, Pod will use image 'BrImage:${TiKV_Version}'. // +optional - ToolImage string `json:"toolImage,omitempty"` + BrImage string `json:"brImage,omitempty"` // ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images. // +optional ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"` - // TableFilter means Table filter expression for 'db.table' matching. BR supports this from v4.0.3. - TableFilter []string `json:"tableFilter,omitempty"` // Affinity of backup Pods // +optional Affinity *corev1.Affinity `json:"affinity,omitempty"` @@ -3539,12 +3515,6 @@ type CompactSpec 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 - CleanPolicy CleanPolicyType `json:"cleanPolicy,omitempty"` - // CleanOption controls the behavior of clean. - CleanOption *CleanOption `json:"cleanOption,omitempty"` // PodSecurityContext of the component // +optional diff --git a/pkg/apis/pingcap/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/pingcap/v1alpha1/zz_generated.deepcopy.go index c75e387d4f..9da323d29c 100644 --- a/pkg/apis/pingcap/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/pingcap/v1alpha1/zz_generated.deepcopy.go @@ -958,11 +958,6 @@ func (in *CompactSpec) DeepCopyInto(out *CompactSpec) { *out = new(BRConfig) (*in).DeepCopyInto(*out) } - if in.Dumpling != nil { - in, out := &in.Dumpling, &out.Dumpling - *out = new(DumplingConfig) - (*in).DeepCopyInto(*out) - } if in.Tolerations != nil { in, out := &in.Tolerations, &out.Tolerations *out = make([]v1.Toleration, len(*in)) @@ -975,21 +970,11 @@ func (in *CompactSpec) DeepCopyInto(out *CompactSpec) { *out = make([]v1.LocalObjectReference, len(*in)) copy(*out, *in) } - if in.TableFilter != nil { - in, out := &in.TableFilter, &out.TableFilter - *out = make([]string, len(*in)) - copy(*out, *in) - } if in.Affinity != nil { in, out := &in.Affinity, &out.Affinity *out = new(v1.Affinity) (*in).DeepCopyInto(*out) } - if in.CleanOption != nil { - in, out := &in.CleanOption, &out.CleanOption - *out = new(CleanOption) - **out = **in - } if in.PodSecurityContext != nil { in, out := &in.PodSecurityContext, &out.PodSecurityContext *out = new(v1.PodSecurityContext) diff --git a/pkg/controller/compactbackup/compact_backup_controller.go b/pkg/controller/compactbackup/compact_backup_controller.go index 27a6efe1d5..fd9fa1a44b 100644 --- a/pkg/controller/compactbackup/compact_backup_controller.go +++ b/pkg/controller/compactbackup/compact_backup_controller.go @@ -3,6 +3,7 @@ package compact import ( "context" "fmt" + "strings" "time" "github.com/pingcap/errors" @@ -261,6 +262,16 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job args = append(args, fmt.Sprintf("--tikvVersion=%s", tikvVersion)) } + brImage := "pingcap/br:" + tikvVersion + if backup.Spec.BrImage != "" { + image := backup.Spec.BrImage + if !strings.ContainsRune(backup.Spec.BrImage, ':') { + image = fmt.Sprintf("%s:%s", image, tikvVersion) + } + + brImage = image + } + volumeMounts := []corev1.VolumeMount{} volumes := []corev1.Volume{} @@ -284,22 +295,37 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job volumeMounts = append(volumeMounts, backup.Spec.Local.VolumeMount) } - // serviceAccount := constants.DefaultServiceAccountName - // if backup.Spec.ServiceAccount != "" { - // serviceAccount = backup.Spec.ServiceAccount - // } - jobLabels := util.CombineStringMap(label.NewBackup().Instance("Compact-test").BackupJob().Backup(name), backup.Labels) - // podLabels := jobLabels + podLabels := jobLabels jobAnnotations := backup.Annotations // Create a basic PodSpec with a single container that just prints "Hello World" podSpec := &corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{"app": "backup"}, - Annotations: map[string]string{"description": "A simple backup job"}, + Labels: podLabels, + Annotations: jobAnnotations, }, Spec: corev1.PodSpec{ + InitContainers: []corev1.Container{ + { + Name: "br", + Image: brImage, + Command: []string{"/bin/sh", "-c"}, + Args: []string{fmt.Sprintf("cp /br %s/br; echo 'BR copy finished'", util.BRBinPath)}, + ImagePullPolicy: corev1.PullIfNotPresent, + VolumeMounts: []corev1.VolumeMount{brVolumeMount}, + Resources: backup.Spec.ResourceRequirements, + }, + { + Name: "tikv-ctl", + Image: tikvImage, + Command: []string{"/bin/sh", "-c"}, + Args: []string{fmt.Sprintf("cp /tikv-ctl %s/tikv-ctl; echo 'KVCTL copy finished'", util.KVCTLBinPath)}, + ImagePullPolicy: corev1.PullIfNotPresent, + VolumeMounts: []corev1.VolumeMount{brVolumeMount}, + Resources: backup.Spec.ResourceRequirements, + }, + }, Containers: []corev1.Container{ { Name: "simple-backup", diff --git a/pkg/util/util.go b/pkg/util/util.go index 3df326f809..909224a7be 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -48,6 +48,7 @@ var ( ClusterAssetsTLSPath = "/var/lib/cluster-assets-tls" TiDBClientTLSPath = "/var/lib/tidb-client-tls" BRBinPath = "/var/lib/br-bin" + KVCTLBinPath = "/var/lib/kvctl-bin" DumplingBinPath = "/var/lib/dumpling-bin" LightningBinPath = "/var/lib/lightning-bin" ClusterClientVolName = "cluster-client-tls" From 24b88b88d028bf844fe1decfd84bf0e3d15d98f8 Mon Sep 17 00:00:00 2001 From: RidRisR <79858083+RidRisR@users.noreply.github.com> Date: Tue, 29 Oct 2024 09:42:55 +0100 Subject: [PATCH 07/49] upload state --- .../compact_backup_controller.go | 180 ++++++++++++++---- 1 file changed, 142 insertions(+), 38 deletions(-) diff --git a/pkg/controller/compactbackup/compact_backup_controller.go b/pkg/controller/compactbackup/compact_backup_controller.go index fd9fa1a44b..0cf5d788a1 100644 --- a/pkg/controller/compactbackup/compact_backup_controller.go +++ b/pkg/controller/compactbackup/compact_backup_controller.go @@ -10,6 +10,7 @@ import ( perrors "github.com/pingcap/errors" "github.com/pingcap/tidb-operator/pkg/apis/label" "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1" + "github.com/pingcap/tidb-operator/pkg/backup/constants" backuputil "github.com/pingcap/tidb-operator/pkg/backup/util" "github.com/pingcap/tidb-operator/pkg/client/clientset/versioned" "github.com/pingcap/tidb-operator/pkg/controller" @@ -21,6 +22,7 @@ import ( utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/tools/cache" + "k8s.io/client-go/util/retry" "k8s.io/client-go/util/workqueue" "k8s.io/klog" "k8s.io/utils/pointer" @@ -87,19 +89,40 @@ func (c *Controller) worker() { } } +func (c *Controller) UpdateStatus(backup *v1alpha1.CompactBackup, newState string) error { + ns := backup.GetNamespace() + backupName := backup.GetName() + // try best effort to guarantee backup is updated. + err := retry.OnError(retry.DefaultRetry, func(e error) bool { return e != nil }, func() error { + // Always get the latest backup before update. + if updated, err := c.deps.CompactBackupLister.CompactBackups(ns).Get(backupName); err == nil { + // make a copy so we don't mutate the shared cache + *backup = *(updated.DeepCopy()) + } else { + utilruntime.HandleError(fmt.Errorf("error getting updated backup %s/%s from lister: %v", ns, backupName, err)) + return err + } + if backup.Status.State != newState { + backup.Status.State = newState + _, updateErr := c.cli.PingcapV1alpha1().CompactBackups(ns).Update(context.TODO(), backup, metav1.UpdateOptions{}) + if updateErr == nil { + klog.Infof("Backup: [%s/%s] updated successfully", ns, backupName) + return nil + } + klog.Errorf("Failed to update backup [%s/%s], error: %v", ns, backupName, updateErr) + return updateErr + } + return nil + }) + return err +} + func (c *Controller) updateBackup(cur interface{}) { newBackup := cur.(*v1alpha1.CompactBackup) ns := newBackup.GetNamespace() name := newBackup.GetName() klog.Infof("backup object %s/%s enqueue", ns, name) - newBackup.Status.State = "Prepare" - _, updateErr := c.cli.PingcapV1alpha1().CompactBackups(ns).Update(context.TODO(), newBackup, metav1.UpdateOptions{}) - if updateErr == nil { - klog.Infof("Backup: [%s/%s] updated successfully", ns, newBackup.GetName()) - } else { - klog.Errorf("Backup: [%s/%s] updated failed", ns, newBackup.GetName()) - } c.enqueueBackup(newBackup) } @@ -174,22 +197,25 @@ func (c *Controller) sync(key string) (err error) { } //Skip - if backup.Status.State == "Complete" { + if backup.Status.State != "" { return nil } - err = c.syncCompact(backup.DeepCopy()) - backup.Status.State = "Complete" - _, updateErr := c.cli.PingcapV1alpha1().CompactBackups(ns).Update(context.TODO(), backup, metav1.UpdateOptions{}) - if updateErr == nil { - klog.Infof("Backup: [%s/%s] updated successfully", ns, backup.GetName()) + c.UpdateStatus(backup, "Preparing") + + err = c.doCompact(backup.DeepCopy()) + + var newState string + if err != nil { + newState = "Failed" } else { - klog.Errorf("Backup: [%s/%s] updated failed", ns, backup.GetName()) + newState = "Running" } + c.UpdateStatus(backup, newState) return err } -func (c *Controller) syncCompact(backup *v1alpha1.CompactBackup) error { +func (c *Controller) doCompact(backup *v1alpha1.CompactBackup) error { ns := backup.GetNamespace() name := backup.GetName() backupJobName := backup.GetName() @@ -215,7 +241,7 @@ func (c *Controller) syncCompact(backup *v1alpha1.CompactBackup) error { func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job, string, error) { ns := backup.GetNamespace() name := backup.GetName() - jobName := backup.GetName() + jobName := backup.GetName() + "-compact-backup" backupNamespace := ns if backup.Spec.BR.ClusterNamespace != "" { backupNamespace = backup.Spec.BR.ClusterNamespace @@ -262,50 +288,103 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job args = append(args, fmt.Sprintf("--tikvVersion=%s", tikvVersion)) } - brImage := "pingcap/br:" + tikvVersion - if backup.Spec.BrImage != "" { - image := backup.Spec.BrImage - if !strings.ContainsRune(backup.Spec.BrImage, ':') { - image = fmt.Sprintf("%s:%s", image, tikvVersion) - } - - brImage = image - } + //TODO: (Ris)What is the instance here? + jobLabels := util.CombineStringMap(label.NewBackup().Instance("Compact-test").BackupJob().Backup(name), backup.Labels) + podLabels := jobLabels + jobAnnotations := backup.Annotations + podAnnotations := jobAnnotations volumeMounts := []corev1.VolumeMount{} volumes := []corev1.Volume{} + if tc.IsTLSClusterEnabled() { + args = append(args, "--cluster-tls=true") + volumeMounts = append(volumeMounts, corev1.VolumeMount{ + Name: util.ClusterClientVolName, + ReadOnly: true, + MountPath: util.ClusterClientTLSPath, + }) + volumes = append(volumes, corev1.Volume{ + Name: util.ClusterClientVolName, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: util.ClusterClientTLSSecretName(backup.Spec.BR.Cluster), + }, + }, + }) + } + + 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", + Name: "tool-bin", ReadOnly: false, MountPath: util.BRBinPath, } volumeMounts = append(volumeMounts, brVolumeMount) volumes = append(volumes, corev1.Volume{ - Name: "br-bin", + Name: "tool-bin", VolumeSource: corev1.VolumeSource{ EmptyDir: &corev1.EmptyDirVolumeSource{}, }, }) + if len(backup.Spec.AdditionalVolumes) > 0 { + volumes = append(volumes, backup.Spec.AdditionalVolumes...) + } + if len(backup.Spec.AdditionalVolumeMounts) > 0 { + volumeMounts = append(volumeMounts, backup.Spec.AdditionalVolumeMounts...) + } + // mount volumes if specified if backup.Spec.Local != nil { volumes = append(volumes, backup.Spec.Local.Volume) volumeMounts = append(volumeMounts, backup.Spec.Local.VolumeMount) } - jobLabels := util.CombineStringMap(label.NewBackup().Instance("Compact-test").BackupJob().Backup(name), backup.Labels) - podLabels := jobLabels - jobAnnotations := backup.Annotations + serviceAccount := constants.DefaultServiceAccountName + if backup.Spec.ServiceAccount != "" { + serviceAccount = backup.Spec.ServiceAccount + } + + brImage := "pingcap/br:" + tikvVersion + if backup.Spec.BrImage != "" { + image := backup.Spec.BrImage + if !strings.ContainsRune(backup.Spec.BrImage, ':') { + image = fmt.Sprintf("%s:%s", image, tikvVersion) + } + + brImage = image + } - // Create a basic PodSpec with a single container that just prints "Hello World" podSpec := &corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Labels: podLabels, - Annotations: jobAnnotations, + Annotations: podAnnotations, }, Spec: corev1.PodSpec{ + SecurityContext: backup.Spec.PodSecurityContext, + ServiceAccountName: serviceAccount, InitContainers: []corev1.Container{ { Name: "br", @@ -313,17 +392,27 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job Command: []string{"/bin/sh", "-c"}, Args: []string{fmt.Sprintf("cp /br %s/br; echo 'BR copy finished'", util.BRBinPath)}, ImagePullPolicy: corev1.PullIfNotPresent, - VolumeMounts: []corev1.VolumeMount{brVolumeMount}, - Resources: backup.Spec.ResourceRequirements, + VolumeMounts: []corev1.VolumeMount{ + { + Name: "tool-bin", + MountPath: util.BRBinPath, + }, + }, + Resources: backup.Spec.ResourceRequirements, }, { Name: "tikv-ctl", Image: tikvImage, Command: []string{"/bin/sh", "-c"}, - Args: []string{fmt.Sprintf("cp /tikv-ctl %s/tikv-ctl; echo 'KVCTL copy finished'", util.KVCTLBinPath)}, + Args: []string{fmt.Sprintf("cp /tikv-ctl %s/tikv-ctl; echo 'tikv-ctl copy finished'", util.KVCTLBinPath)}, ImagePullPolicy: corev1.PullIfNotPresent, - VolumeMounts: []corev1.VolumeMount{brVolumeMount}, - Resources: backup.Spec.ResourceRequirements, + VolumeMounts: []corev1.VolumeMount{ + { + Name: "tool-bin", + MountPath: util.KVCTLBinPath, + }, + }, + Resources: backup.Spec.ResourceRequirements, }, }, Containers: []corev1.Container{ @@ -336,9 +425,24 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job Args: []string{ "echo 'Backup job running successfully'; sleep 30", }, + VolumeMounts: []corev1.VolumeMount{ + { + Name: "tool-bin", + MountPath: util.BRBinPath, + }, + { + Name: "tool-bin", + MountPath: util.KVCTLBinPath, + }, + }, }, }, - RestartPolicy: corev1.RestartPolicyNever, + RestartPolicy: corev1.RestartPolicyNever, + Tolerations: backup.Spec.Tolerations, + ImagePullSecrets: backup.Spec.ImagePullSecrets, + Affinity: backup.Spec.Affinity, + Volumes: volumes, + PriorityClassName: backup.Spec.PriorityClassName, }, } From 50b0bb2ca8c398e7440aa73bd7007d6493984697 Mon Sep 17 00:00:00 2001 From: RidRisR <79858083+RidRisR@users.noreply.github.com> Date: Tue, 29 Oct 2024 09:49:08 +0100 Subject: [PATCH 08/49] fix --- pkg/controller/compactbackup/compact_backup_controller.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/pkg/controller/compactbackup/compact_backup_controller.go b/pkg/controller/compactbackup/compact_backup_controller.go index 0cf5d788a1..1ca367011e 100644 --- a/pkg/controller/compactbackup/compact_backup_controller.go +++ b/pkg/controller/compactbackup/compact_backup_controller.go @@ -335,13 +335,6 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job }) } - brVolumeMount := corev1.VolumeMount{ - Name: "tool-bin", - ReadOnly: false, - MountPath: util.BRBinPath, - } - volumeMounts = append(volumeMounts, brVolumeMount) - volumes = append(volumes, corev1.Volume{ Name: "tool-bin", VolumeSource: corev1.VolumeSource{ From 28a38e4c1b1754fc6df59507e8489b2c25c6f576 Mon Sep 17 00:00:00 2001 From: RidRisR <79858083+RidRisR@users.noreply.github.com> Date: Wed, 30 Oct 2024 08:30:31 +0100 Subject: [PATCH 09/49] remove cluster dependency --- docs/api-references/docs.md | 75 +++++++++------ manifests/crd.yaml | 40 +------- .../crd/v1/pingcap.com_compactbackups.yaml | 40 +------- .../pingcap/v1alpha1/openapi_generated.go | 22 +++-- pkg/apis/pingcap/v1alpha1/types.go | 8 +- .../pingcap/v1alpha1/zz_generated.deepcopy.go | 5 - .../compact_backup_controller.go | 93 ++++++------------- 7 files changed, 104 insertions(+), 179 deletions(-) diff --git a/docs/api-references/docs.md b/docs/api-references/docs.md index 394222e8dd..c83464c988 100644 --- a/docs/api-references/docs.md +++ b/docs/api-references/docs.md @@ -3447,7 +3447,6 @@ string (Appears on: BackupSpec, -CompactSpec, RestoreSpec) @@ -5482,19 +5481,6 @@ string | |||||||||||
-br
-
-
-BRConfig
-
-
- |
-
- BRConfig is the configs for BR - |
-||||||||||
commitTs
string
@@ -5558,6 +5544,17 @@ bool
| |||||||||||
+version
+
+string
+
+ |
+
+ Version specifies the tool image version used in compact |
+||||||||||
brImage
string
@@ -5572,6 +5569,19 @@ For BR image, if it does not contain tag, Pod will use image ‘BrImage:${Ti
| |||||||||||
+tikvImage
+
+string
+
+ |
+
+(Optional)
+ TiKVImage specifies the tikv image used in compact |
+||||||||||
imagePullSecrets
@@ -5837,19 +5847,6 @@ string
| |||||||||||
-br
-
-
-BRConfig
-
-
- |
-
- BRConfig is the configs for BR - |
-||||||||||
commitTs
string
@@ -5913,6 +5910,17 @@ bool
| |||||||||||
+version
+
+string
+
+ |
+
+ Version specifies the tool image version used in compact |
+||||||||||
brImage
string
@@ -5927,6 +5935,19 @@ For BR image, if it does not contain tag, Pod will use image ‘BrImage:${Ti
| |||||||||||
+tikvImage
+
+string
+
+ |
+
+(Optional)
+ TiKVImage specifies the tikv image used in compact |
+||||||||||
imagePullSecrets
diff --git a/manifests/crd.yaml b/manifests/crd.yaml
index fe1f2320e3..336e5e1171 100644
--- a/manifests/crd.yaml
+++ b/manifests/crd.yaml
@@ -8208,42 +8208,6 @@ spec:
default: 30m
type: string
type: object
- br:
- properties:
- checkRequirements:
- type: boolean
- checksum:
- type: boolean
- cluster:
- type: string
- clusterNamespace:
- type: string
- concurrency:
- format: int32
- type: integer
- db:
- type: string
- logLevel:
- type: string
- onLine:
- type: boolean
- options:
- items:
- type: string
- type: array
- rateLimit:
- type: integer
- sendCredToTikv:
- type: boolean
- statusAddr:
- type: string
- table:
- type: string
- timeAgo:
- type: string
- required:
- - cluster
- type: object
brImage:
type: string
commitTs:
@@ -9235,6 +9199,8 @@ spec:
type: string
tikvGCLifeTime:
type: string
+ tikvImage:
+ type: string
tolerations:
items:
properties:
@@ -9253,6 +9219,8 @@ spec:
type: array
useKMS:
type: boolean
+ version:
+ type: string
volumeBackupInitJobMaxActiveSeconds:
default: 600
type: integer
diff --git a/manifests/crd/v1/pingcap.com_compactbackups.yaml b/manifests/crd/v1/pingcap.com_compactbackups.yaml
index feb7984243..c58dbfe4ae 100644
--- a/manifests/crd/v1/pingcap.com_compactbackups.yaml
+++ b/manifests/crd/v1/pingcap.com_compactbackups.yaml
@@ -1158,42 +1158,6 @@ spec:
default: 30m
type: string
type: object
- br:
- properties:
- checkRequirements:
- type: boolean
- checksum:
- type: boolean
- cluster:
- type: string
- clusterNamespace:
- type: string
- concurrency:
- format: int32
- type: integer
- db:
- type: string
- logLevel:
- type: string
- onLine:
- type: boolean
- options:
- items:
- type: string
- type: array
- rateLimit:
- type: integer
- sendCredToTikv:
- type: boolean
- statusAddr:
- type: string
- table:
- type: string
- timeAgo:
- type: string
- required:
- - cluster
- type: object
brImage:
type: string
commitTs:
@@ -2185,6 +2149,8 @@ spec:
type: string
tikvGCLifeTime:
type: string
+ tikvImage:
+ type: string
tolerations:
items:
properties:
@@ -2203,6 +2169,8 @@ spec:
type: array
useKMS:
type: boolean
+ version:
+ type: string
volumeBackupInitJobMaxActiveSeconds:
default: 600
type: integer
diff --git a/pkg/apis/pingcap/v1alpha1/openapi_generated.go b/pkg/apis/pingcap/v1alpha1/openapi_generated.go
index 8716911d4d..bb6adb867a 100644
--- a/pkg/apis/pingcap/v1alpha1/openapi_generated.go
+++ b/pkg/apis/pingcap/v1alpha1/openapi_generated.go
@@ -1775,12 +1775,6 @@ func schema_pkg_apis_pingcap_v1alpha1_CompactSpec(ref common.ReferenceCallback)
Format: "",
},
},
- "br": {
- SchemaProps: spec.SchemaProps{
- Description: "BRConfig is the configs for BR",
- Ref: ref("github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.BRConfig"),
- },
- },
"commitTs": {
SchemaProps: spec.SchemaProps{
Description: "StartTs is the start ts of the compact backup. Format supports TSO or datetime, e.g. '400036290571534337', '2018-05-11 01:42:23'.",
@@ -1823,6 +1817,13 @@ func schema_pkg_apis_pingcap_v1alpha1_CompactSpec(ref common.ReferenceCallback)
},
},
},
+ "version": {
+ SchemaProps: spec.SchemaProps{
+ Description: "Version specifies the tool image version used in compact `Backup`.",
+ Type: []string{"string"},
+ Format: "",
+ },
+ },
"brImage": {
SchemaProps: spec.SchemaProps{
Description: "BrImage specifies the br image used in compact `Backup`. For examples `spec.brImage: pingcap/br:v4.0.8` For BR image, if it does not contain tag, Pod will use image 'BrImage:${TiKV_Version}'.",
@@ -1830,6 +1831,13 @@ func schema_pkg_apis_pingcap_v1alpha1_CompactSpec(ref common.ReferenceCallback)
Format: "",
},
},
+ "tikvImage": {
+ SchemaProps: spec.SchemaProps{
+ Description: "TiKVImage specifies the tikv image used in compact `Backup`. For examples `spec.tikvImage: pingcap/tikv:v4.0.8`",
+ Type: []string{"string"},
+ Format: "",
+ },
+ },
"imagePullSecrets": {
SchemaProps: spec.SchemaProps{
Description: "ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images.",
@@ -1923,7 +1931,7 @@ func schema_pkg_apis_pingcap_v1alpha1_CompactSpec(ref common.ReferenceCallback)
},
},
Dependencies: []string{
- "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.AzblobStorageProvider", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.BRConfig", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.BackoffRetryPolicy", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.GcsStorageProvider", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.LocalStorageProvider", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.S3StorageProvider", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.TiDBAccessConfig", "k8s.io/api/core/v1.Affinity", "k8s.io/api/core/v1.EnvVar", "k8s.io/api/core/v1.LocalObjectReference", "k8s.io/api/core/v1.PodSecurityContext", "k8s.io/api/core/v1.ResourceRequirements", "k8s.io/api/core/v1.Toleration", "k8s.io/api/core/v1.Volume", "k8s.io/api/core/v1.VolumeMount"},
+ "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.AzblobStorageProvider", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.BackoffRetryPolicy", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.GcsStorageProvider", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.LocalStorageProvider", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.S3StorageProvider", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.TiDBAccessConfig", "k8s.io/api/core/v1.Affinity", "k8s.io/api/core/v1.EnvVar", "k8s.io/api/core/v1.LocalObjectReference", "k8s.io/api/core/v1.PodSecurityContext", "k8s.io/api/core/v1.ResourceRequirements", "k8s.io/api/core/v1.Toleration", "k8s.io/api/core/v1.Volume", "k8s.io/api/core/v1.VolumeMount"},
}
}
diff --git a/pkg/apis/pingcap/v1alpha1/types.go b/pkg/apis/pingcap/v1alpha1/types.go
index bd3a913121..c5f536be1d 100644
--- a/pkg/apis/pingcap/v1alpha1/types.go
+++ b/pkg/apis/pingcap/v1alpha1/types.go
@@ -3481,8 +3481,6 @@ type CompactSpec struct {
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
- BR *BRConfig `json:"br,omitempty"`
// StartTs is the start ts of the compact backup.
// Format supports TSO or datetime, e.g. '400036290571534337', '2018-05-11 01:42:23'.
StartTs string `json:"commitTs,omitempty"`
@@ -3500,11 +3498,17 @@ type CompactSpec struct {
// Base tolerations of backup Pods, components may add more tolerations upon this respectively
// +optional
Tolerations []corev1.Toleration `json:"tolerations,omitempty"`
+ // Version specifies the tool image version used in compact `Backup`.
+ Version string `json:"version,omitempty"`
// BrImage specifies the br image used in compact `Backup`.
// For examples `spec.brImage: pingcap/br:v4.0.8`
// For BR image, if it does not contain tag, Pod will use image 'BrImage:${TiKV_Version}'.
// +optional
BrImage string `json:"brImage,omitempty"`
+ // TiKVImage specifies the tikv image used in compact `Backup`.
+ // For examples `spec.tikvImage: pingcap/tikv:v4.0.8`
+ // +optional
+ TiKVImage string `json:"tikvImage,omitempty"`
// ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images.
// +optional
ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"`
diff --git a/pkg/apis/pingcap/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/pingcap/v1alpha1/zz_generated.deepcopy.go
index 9da323d29c..51b722ada7 100644
--- a/pkg/apis/pingcap/v1alpha1/zz_generated.deepcopy.go
+++ b/pkg/apis/pingcap/v1alpha1/zz_generated.deepcopy.go
@@ -953,11 +953,6 @@ func (in *CompactSpec) DeepCopyInto(out *CompactSpec) {
*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))
diff --git a/pkg/controller/compactbackup/compact_backup_controller.go b/pkg/controller/compactbackup/compact_backup_controller.go
index 1ca367011e..2592bfc057 100644
--- a/pkg/controller/compactbackup/compact_backup_controller.go
+++ b/pkg/controller/compactbackup/compact_backup_controller.go
@@ -242,26 +242,12 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job
ns := backup.GetNamespace()
name := backup.GetName()
jobName := backup.GetName() + "-compact-backup"
- backupNamespace := ns
- if backup.Spec.BR.ClusterNamespace != "" {
- backupNamespace = backup.Spec.BR.ClusterNamespace
- }
-
- tc, err := c.deps.TiDBClusterLister.TidbClusters(backupNamespace).Get(backup.Spec.BR.Cluster)
- if err != nil {
- return nil, fmt.Sprintf("failed to fetch tidbcluster %s/%s", backupNamespace, backup.Spec.BR.Cluster), err
- }
var (
envVars []corev1.EnvVar
reason string
+ err error
)
- if backup.Spec.From != nil {
- envVars, reason, err = backuputil.GenerateTidbPasswordEnv(ns, name, backup.Spec.From.SecretName, backup.Spec.UseKMS, c.deps.SecretLister)
- if err != nil {
- return nil, reason, err
- }
- }
storageEnv, reason, err := backuputil.GenerateStorageCertEnv(ns, backup.Spec.UseKMS, backup.Spec.StorageProvider, c.deps.SecretLister)
if err != nil {
@@ -282,10 +268,30 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job
fmt.Sprintf("--namespace=%s", ns),
fmt.Sprintf("--backupName=%s", name),
}
- tikvImage := tc.TiKVImage()
- _, tikvVersion := backuputil.ParseImage(tikvImage)
+
+ tikvImage := "pingcap/tikv"
+ if backup.Spec.TiKVImage != "" {
+ tikvImage = backup.Spec.TiKVImage
+ }
+
+ tikvVersion := backup.Spec.Version
+ _, imageVersion := backuputil.ParseImage(tikvImage)
+ if imageVersion != "" {
+ tikvVersion = imageVersion
+ }
+
if tikvVersion != "" {
args = append(args, fmt.Sprintf("--tikvVersion=%s", tikvVersion))
+ } else {
+ return nil, "tikv version is empty", fmt.Errorf("tikv version is empty")
+ }
+
+ brImage := fmt.Sprintf("pingcap/br:%s", tikvVersion)
+ if backup.Spec.BrImage != "" {
+ brImage = backup.Spec.BrImage
+ if !strings.ContainsRune(brImage, ':') {
+ brImage = fmt.Sprintf("%s:%s", brImage, tikvVersion)
+ }
}
//TODO: (Ris)What is the instance here?
@@ -297,44 +303,6 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job
volumeMounts := []corev1.VolumeMount{}
volumes := []corev1.Volume{}
- if tc.IsTLSClusterEnabled() {
- args = append(args, "--cluster-tls=true")
- volumeMounts = append(volumeMounts, corev1.VolumeMount{
- Name: util.ClusterClientVolName,
- ReadOnly: true,
- MountPath: util.ClusterClientTLSPath,
- })
- volumes = append(volumes, corev1.Volume{
- Name: util.ClusterClientVolName,
- VolumeSource: corev1.VolumeSource{
- Secret: &corev1.SecretVolumeSource{
- SecretName: util.ClusterClientTLSSecretName(backup.Spec.BR.Cluster),
- },
- },
- })
- }
-
- 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),
- },
- },
- })
- }
-
volumes = append(volumes, corev1.Volume{
Name: "tool-bin",
VolumeSource: corev1.VolumeSource{
@@ -360,16 +328,6 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job
serviceAccount = backup.Spec.ServiceAccount
}
- brImage := "pingcap/br:" + tikvVersion
- if backup.Spec.BrImage != "" {
- image := backup.Spec.BrImage
- if !strings.ContainsRune(backup.Spec.BrImage, ':') {
- image = fmt.Sprintf("%s:%s", image, tikvVersion)
- }
-
- brImage = image
- }
-
podSpec := &corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: podLabels,
@@ -416,7 +374,10 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job
"/bin/sh", "-c",
},
Args: []string{
- "echo 'Backup job running successfully'; sleep 30",
+ // Check if the binaries exist; if both checks pass, proceed with the backup job
+ "if [ -x " + util.BRBinPath + " ] && [ -x " + util.KVCTLBinPath + " ]; then " +
+ "echo 'Both binaries exist. Backup job running successfully'; " +
+ "else echo 'Required binaries missing! Exiting...'; exit 1; fi; sleep 30",
},
VolumeMounts: []corev1.VolumeMount{
{
From f54633324ecf84147823a771424f14d6b064428e Mon Sep 17 00:00:00 2001
From: RidRisR <79858083+RidRisR@users.noreply.github.com>
Date: Wed, 30 Oct 2024 09:35:07 +0100
Subject: [PATCH 10/49] refactor getStoragePath
---
cmd/backup-manager/app/backup/manager.go | 4 ++--
cmd/backup-manager/app/util/util.go | 20 ++++++++++----------
cmd/backup-manager/app/util/util_test.go | 2 +-
3 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/cmd/backup-manager/app/backup/manager.go b/cmd/backup-manager/app/backup/manager.go
index 3678f3a0bd..8a49ca1b25 100644
--- a/cmd/backup-manager/app/backup/manager.go
+++ b/cmd/backup-manager/app/backup/manager.go
@@ -198,7 +198,7 @@ func (bm *Manager) performBackup(ctx context.Context, backup *v1alpha1.Backup, d
var errs []error
- backupFullPath, err := util.GetStoragePath(backup)
+ backupFullPath, err := util.GetStoragePath(&backup.Spec.StorageProvider)
if err != nil {
errs = append(errs, err)
uerr := bm.StatusUpdater.Update(backup, &v1alpha1.BackupCondition{
@@ -506,7 +506,7 @@ func (bm *Manager) performLogBackup(ctx context.Context, backup *v1alpha1.Backup
// startLogBackup starts log backup.
func (bm *Manager) startLogBackup(ctx context.Context, backup *v1alpha1.Backup) (*controller.BackupUpdateStatus, string, error) {
started := time.Now()
- backupFullPath, err := util.GetStoragePath(backup)
+ backupFullPath, err := util.GetStoragePath(&backup.Spec.StorageProvider)
if err != nil {
klog.Errorf("Get backup full path of cluster %s failed, err: %s", bm, err)
return nil, "GetBackupRemotePathFailed", err
diff --git a/cmd/backup-manager/app/util/util.go b/cmd/backup-manager/app/util/util.go
index b00b1eaa0c..877972fb27 100644
--- a/cmd/backup-manager/app/util/util.go
+++ b/cmd/backup-manager/app/util/util.go
@@ -103,28 +103,28 @@ func EnsureDirectoryExist(dirName string) error {
}
// GetStoragePath generate the path of a specific storage
-func GetStoragePath(backup *v1alpha1.Backup) (string, error) {
+func GetStoragePath(StorageProvider *v1alpha1.StorageProvider) (string, error) {
var url, bucket, prefix string
- st := util.GetStorageType(backup.Spec.StorageProvider)
+ st := util.GetStorageType(*StorageProvider)
switch st {
case v1alpha1.BackupStorageTypeS3:
- prefix = backup.Spec.StorageProvider.S3.Prefix
- bucket = backup.Spec.StorageProvider.S3.Bucket
+ prefix = StorageProvider.S3.Prefix
+ bucket = StorageProvider.S3.Bucket
url = fmt.Sprintf("s3://%s", path.Join(bucket, prefix))
return url, nil
case v1alpha1.BackupStorageTypeGcs:
- prefix = backup.Spec.StorageProvider.Gcs.Prefix
- bucket = backup.Spec.StorageProvider.Gcs.Bucket
+ prefix = StorageProvider.Gcs.Prefix
+ bucket = StorageProvider.Gcs.Bucket
url = fmt.Sprintf("gcs://%s/", path.Join(bucket, prefix))
return url, nil
case v1alpha1.BackupStorageTypeAzblob:
- prefix = backup.Spec.StorageProvider.Azblob.Prefix
- bucket = backup.Spec.StorageProvider.Azblob.Container
+ prefix = StorageProvider.Azblob.Prefix
+ bucket = StorageProvider.Azblob.Container
url = fmt.Sprintf("azure://%s/", path.Join(bucket, prefix))
return url, nil
case v1alpha1.BackupStorageTypeLocal:
- prefix = backup.Spec.StorageProvider.Local.Prefix
- mountPath := backup.Spec.StorageProvider.Local.VolumeMount.MountPath
+ prefix = StorageProvider.Local.Prefix
+ mountPath := StorageProvider.Local.VolumeMount.MountPath
url = fmt.Sprintf("local://%s", path.Join(mountPath, prefix))
return url, nil
default:
diff --git a/cmd/backup-manager/app/util/util_test.go b/cmd/backup-manager/app/util/util_test.go
index 0a25c93876..0848efaf20 100644
--- a/cmd/backup-manager/app/util/util_test.go
+++ b/cmd/backup-manager/app/util/util_test.go
@@ -260,7 +260,7 @@ func TestGetRemotePath(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- p, err := GetStoragePath(tt.backup)
+ p, err := GetStoragePath(&tt.backup.Spec.StorageProvider)
if tt.err {
g.Expect(err).To(HaveOccurred())
return
From de989f86137a7c3a993ec580d795741702a29132 Mon Sep 17 00:00:00 2001
From: RidRisR <79858083+RidRisR@users.noreply.github.com>
Date: Thu, 31 Oct 2024 06:20:12 +0100
Subject: [PATCH 11/49] add env vars
---
.../compact_backup_controller.go | 76 +++++++++++++------
1 file changed, 52 insertions(+), 24 deletions(-)
diff --git a/pkg/controller/compactbackup/compact_backup_controller.go b/pkg/controller/compactbackup/compact_backup_controller.go
index 2592bfc057..2dd20325c9 100644
--- a/pkg/controller/compactbackup/compact_backup_controller.go
+++ b/pkg/controller/compactbackup/compact_backup_controller.go
@@ -57,7 +57,7 @@ func NewController(deps *controller.Dependencies) *Controller {
DeleteFunc: c.updateBackup,
})
jobInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
- DeleteFunc: c.updateBackup,
+ DeleteFunc: c.deleteJob,
})
return c
@@ -117,6 +117,42 @@ func (c *Controller) UpdateStatus(backup *v1alpha1.CompactBackup, newState strin
return err
}
+func (c *Controller) resolveCompactBackupFromJob(namespace string, job *batchv1.Job) *v1alpha1.CompactBackup {
+ owner := metav1.GetControllerOf(job)
+ if owner == nil {
+ return nil
+ }
+
+ if owner.Kind != controller.CompactBackupControllerKind.Kind {
+ return nil
+ }
+
+ backup, err := c.deps.CompactBackupLister.CompactBackups(namespace).Get(owner.Name)
+ if err != nil {
+ return nil
+ }
+ if owner.UID != backup.UID {
+ return nil
+ }
+ return backup
+}
+
+func (c *Controller) deleteJob(obj interface{}) {
+ job, ok := obj.(*batchv1.Job)
+ if !ok {
+ return
+ }
+
+ ns := job.GetNamespace()
+ jobName := job.GetName()
+ backup := c.resolveCompactBackupFromJob(ns, job)
+ if backup == nil {
+ return
+ }
+ klog.V(4).Infof("Job %s/%s deleted through %v.", ns, jobName, utilruntime.GetCaller())
+ c.updateBackup(backup)
+}
+
func (c *Controller) updateBackup(cur interface{}) {
newBackup := cur.(*v1alpha1.CompactBackup)
ns := newBackup.GetNamespace()
@@ -241,7 +277,7 @@ func (c *Controller) doCompact(backup *v1alpha1.CompactBackup) error {
func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job, string, error) {
ns := backup.GetNamespace()
name := backup.GetName()
- jobName := backup.GetName() + "-compact-backup"
+ jobName := backup.GetName()
var (
envVars []corev1.EnvVar
@@ -310,6 +346,17 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job
},
})
+ volumeMounts = append(volumeMounts,
+ corev1.VolumeMount{
+ Name: "tool-bin",
+ MountPath: util.BRBinPath,
+ },
+ corev1.VolumeMount{
+ Name: "tool-bin",
+ MountPath: util.KVCTLBinPath,
+ },
+ )
+
if len(backup.Spec.AdditionalVolumes) > 0 {
volumes = append(volumes, backup.Spec.AdditionalVolumes...)
}
@@ -343,12 +390,7 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job
Command: []string{"/bin/sh", "-c"},
Args: []string{fmt.Sprintf("cp /br %s/br; echo 'BR copy finished'", util.BRBinPath)},
ImagePullPolicy: corev1.PullIfNotPresent,
- VolumeMounts: []corev1.VolumeMount{
- {
- Name: "tool-bin",
- MountPath: util.BRBinPath,
- },
- },
+ VolumeMounts: volumeMounts,
Resources: backup.Spec.ResourceRequirements,
},
{
@@ -357,12 +399,7 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job
Command: []string{"/bin/sh", "-c"},
Args: []string{fmt.Sprintf("cp /tikv-ctl %s/tikv-ctl; echo 'tikv-ctl copy finished'", util.KVCTLBinPath)},
ImagePullPolicy: corev1.PullIfNotPresent,
- VolumeMounts: []corev1.VolumeMount{
- {
- Name: "tool-bin",
- MountPath: util.KVCTLBinPath,
- },
- },
+ VolumeMounts: volumeMounts,
Resources: backup.Spec.ResourceRequirements,
},
},
@@ -379,16 +416,7 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job
"echo 'Both binaries exist. Backup job running successfully'; " +
"else echo 'Required binaries missing! Exiting...'; exit 1; fi; sleep 30",
},
- VolumeMounts: []corev1.VolumeMount{
- {
- Name: "tool-bin",
- MountPath: util.BRBinPath,
- },
- {
- Name: "tool-bin",
- MountPath: util.KVCTLBinPath,
- },
- },
+ VolumeMounts: volumeMounts,
},
},
RestartPolicy: corev1.RestartPolicyNever,
From a744d6b9c31344a8c305ec1452bd81a129b74df9 Mon Sep 17 00:00:00 2001
From: RidRisR <79858083+RidRisR@users.noreply.github.com>
Date: Thu, 31 Oct 2024 07:31:10 +0100
Subject: [PATCH 12/49] use backup-manager
---
.../compact_backup_controller.go | 44 ++++++++++++-------
1 file changed, 27 insertions(+), 17 deletions(-)
diff --git a/pkg/controller/compactbackup/compact_backup_controller.go b/pkg/controller/compactbackup/compact_backup_controller.go
index 2dd20325c9..10710f539b 100644
--- a/pkg/controller/compactbackup/compact_backup_controller.go
+++ b/pkg/controller/compactbackup/compact_backup_controller.go
@@ -3,6 +3,7 @@ package compact
import (
"context"
"fmt"
+ "strconv"
"strings"
"time"
@@ -10,6 +11,7 @@ import (
perrors "github.com/pingcap/errors"
"github.com/pingcap/tidb-operator/pkg/apis/label"
"github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1"
+ "github.com/pingcap/tidb-operator/pkg/apis/util/config"
"github.com/pingcap/tidb-operator/pkg/backup/constants"
backuputil "github.com/pingcap/tidb-operator/pkg/backup/util"
"github.com/pingcap/tidb-operator/pkg/client/clientset/versioned"
@@ -291,31 +293,43 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job
}
envVars = append(envVars, storageEnv...)
- envVars = append(envVars, corev1.EnvVar{
- Name: "BR_LOG_TO_TERM",
- Value: string(rune(1)),
- })
// set env vars specified in backup.Spec.Env
envVars = util.AppendOverwriteEnv(envVars, backup.Spec.Env)
args := []string{
- "backup",
+ "compact",
fmt.Sprintf("--namespace=%s", ns),
- fmt.Sprintf("--backupName=%s", name),
+ fmt.Sprintf("--resourceName=%s", name),
+ }
+ startTS, err := config.ParseTSString(backup.Spec.StartTs)
+ if err != nil {
+ return nil, fmt.Sprintf("failed to parse startTs(%v)", backup.Spec.StartTs), err
+ }
+ args = append(args, "--from-ts", strconv.FormatUint(startTS, 10))
+ endTS, err := config.ParseTSString(backup.Spec.EndTs)
+ if err != nil {
+ return nil, fmt.Sprintf("failed to parse endTs(%v)", backup.Spec.EndTs), err
}
+ args = append(args, "--until-ts", strconv.FormatUint(endTS, 10))
+ args = append(args, "--concurrency", backup.Spec.EndTs)
+ args = append(args, "--name", backup.GetObjectMeta().GetName())
+ strg, err := backuputil.GetStoragePath(backup.Spec.StorageProvider)
+ if err != nil {
+ return nil, fmt.Sprintf("failed to get storage path: %v", err), err
+ }
+ args = append(args, "--storage-string", strg)
tikvImage := "pingcap/tikv"
if backup.Spec.TiKVImage != "" {
tikvImage = backup.Spec.TiKVImage
}
-
+
tikvVersion := backup.Spec.Version
_, imageVersion := backuputil.ParseImage(tikvImage)
if imageVersion != "" {
tikvVersion = imageVersion
}
-
if tikvVersion != "" {
args = append(args, fmt.Sprintf("--tikvVersion=%s", tikvVersion))
} else {
@@ -331,7 +345,7 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job
}
//TODO: (Ris)What is the instance here?
- jobLabels := util.CombineStringMap(label.NewBackup().Instance("Compact-test").BackupJob().Backup(name), backup.Labels)
+ jobLabels := util.CombineStringMap(label.NewBackup().Instance("Compact-Backup").BackupJob().Backup(name), backup.Labels)
podLabels := jobLabels
jobAnnotations := backup.Annotations
podAnnotations := jobAnnotations
@@ -405,17 +419,13 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job
},
Containers: []corev1.Container{
{
- Name: "simple-backup",
- Image: "busybox", // Using a simple image for demonstration
+ Name: "backup-manager",
+ Image: c.deps.CLIConfig.TiDBBackupManagerImage,
Command: []string{
"/bin/sh", "-c",
},
- Args: []string{
- // Check if the binaries exist; if both checks pass, proceed with the backup job
- "if [ -x " + util.BRBinPath + " ] && [ -x " + util.KVCTLBinPath + " ]; then " +
- "echo 'Both binaries exist. Backup job running successfully'; " +
- "else echo 'Required binaries missing! Exiting...'; exit 1; fi; sleep 30",
- },
+ Args: args,
+ Env: envVars,
VolumeMounts: volumeMounts,
},
},
From e042927159b86100e7ae6115c81616f7e14e8a46 Mon Sep 17 00:00:00 2001
From: ideascf | |||||||||||
+clusterTLSSecretName
+
+string
+
+ |
+
+(Optional)
+ ClusterTLSSecretName is used for overwriting the default mTLS cert secret name (see also: pkg/util/util.go:ClusterTLSSecretName) +This field is useful for sharing the same mTLS cert secret for multiple ticdc clusters connecting to the same upstream tidb cluster. + |
+||||||||||
+clusterClientTLSSecretName
+
+string
+
+ |
+
+(Optional)
+ ClusterTLSSecretName is used for overwriting the default cluster client cert secret name (see also: pkg/util/util.go:ClusterClientTLSSecretName)
+This field is useful for sharing the same cluster client cert secret for multiple ticdc clusters connecting to the same upstream tidb cluster.
+The ClusterClientTLSSecret is actually not directly used by ticdc, but it is useful for executing some commands via |
+||||||||||
baseImage
string
diff --git a/manifests/crd/v1/pingcap.com_tidbclusters.yaml b/manifests/crd/v1/pingcap.com_tidbclusters.yaml
index bd231fd88b..b658c82317 100644
--- a/manifests/crd/v1/pingcap.com_tidbclusters.yaml
+++ b/manifests/crd/v1/pingcap.com_tidbclusters.yaml
@@ -13152,6 +13152,10 @@ spec:
x-kubernetes-list-map-keys:
- name
x-kubernetes-list-type: map
+ clusterClientTLSSecretName:
+ type: string
+ clusterTLSSecretName:
+ type: string
config:
x-kubernetes-preserve-unknown-fields: true
configUpdateStrategy:
diff --git a/pkg/apis/pingcap/v1alpha1/openapi_generated.go b/pkg/apis/pingcap/v1alpha1/openapi_generated.go
index bb6adb867a..22ceb9820c 100644
--- a/pkg/apis/pingcap/v1alpha1/openapi_generated.go
+++ b/pkg/apis/pingcap/v1alpha1/openapi_generated.go
@@ -9723,6 +9723,20 @@ func schema_pkg_apis_pingcap_v1alpha1_TiCDCSpec(ref common.ReferenceCallback) co
},
},
},
+ "clusterTLSSecretName": {
+ SchemaProps: spec.SchemaProps{
+ Description: "ClusterTLSSecretName is used for overwriting the default mTLS cert secret name (see also: pkg/util/util.go:ClusterTLSSecretName) This field is useful for sharing the same mTLS cert secret for multiple ticdc clusters connecting to the same upstream tidb cluster.",
+ Type: []string{"string"},
+ Format: "",
+ },
+ },
+ "clusterClientTLSSecretName": {
+ SchemaProps: spec.SchemaProps{
+ Description: "ClusterTLSSecretName is used for overwriting the default **cluster client** cert secret name (see also: pkg/util/util.go:ClusterClientTLSSecretName) This field is useful for sharing the same cluster client cert secret for multiple ticdc clusters connecting to the same upstream tidb cluster. The ClusterClientTLSSecret is actually not directly used by ticdc, but it is useful for executing some commands via `ticdc-ctl`\n by `kubectl exec -it ticdc-0 -- /cdc cli --ca /var/lib/cluster-client-tls/ca.crt --cert /var/lib/cluster-client-tls/tls.crt --key /var/lib/cluster-client-tls/tls.key ...`.",
+ Type: []string{"string"},
+ Format: "",
+ },
+ },
"baseImage": {
SchemaProps: spec.SchemaProps{
Description: "Base image of the component, image tag is now allowed during validation",
diff --git a/pkg/apis/pingcap/v1alpha1/types.go b/pkg/apis/pingcap/v1alpha1/types.go
index c5f536be1d..f2944a08ea 100644
--- a/pkg/apis/pingcap/v1alpha1/types.go
+++ b/pkg/apis/pingcap/v1alpha1/types.go
@@ -859,6 +859,18 @@ type TiCDCSpec struct {
// +optional
TLSClientSecretNames []string `json:"tlsClientSecretNames,omitempty"`
+ // ClusterTLSSecretName is used for overwriting the default mTLS cert secret name (see also: pkg/util/util.go:ClusterTLSSecretName)
+ // This field is useful for sharing the same mTLS cert secret for multiple ticdc clusters connecting to the same upstream tidb cluster.
+ // +optional
+ ClusterTLSSecretName string `json:"clusterTLSSecretName,omitempty"`
+
+ // ClusterTLSSecretName is used for overwriting the default **cluster client** cert secret name (see also: pkg/util/util.go:ClusterClientTLSSecretName)
+ // This field is useful for sharing the same cluster client cert secret for multiple ticdc clusters connecting to the same upstream tidb cluster.
+ // The ClusterClientTLSSecret is actually not directly used by ticdc, but it is useful for executing some commands via `ticdc-ctl`
+ // by `kubectl exec -it ticdc-0 -- /cdc cli --ca /var/lib/cluster-client-tls/ca.crt --cert /var/lib/cluster-client-tls/tls.crt --key /var/lib/cluster-client-tls/tls.key ...`.
+ // +optional
+ ClusterClientTLSSecretName string `json:"clusterClientTLSSecretName,omitempty"`
+
// Base image of the component, image tag is now allowed during validation
// +kubebuilder:default=pingcap/ticdc
// +optional
diff --git a/pkg/manager/member/ticdc_member_manager.go b/pkg/manager/member/ticdc_member_manager.go
index 3c29259fed..5d66cf5d84 100644
--- a/pkg/manager/member/ticdc_member_manager.go
+++ b/pkg/manager/member/ticdc_member_manager.go
@@ -405,13 +405,13 @@ func getNewTiCDCStatefulSet(tc *v1alpha1.TidbCluster, cm *corev1.ConfigMap) (*ap
vols = append(vols, corev1.Volume{
Name: ticdcCertVolumeMount, VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
- SecretName: util.ClusterTLSSecretName(tc.Name, label.TiCDCLabelVal),
+ SecretName: getTiCDCClusterTLSCertSecretName(tc),
},
},
}, corev1.Volume{
Name: util.ClusterClientVolName, VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
- SecretName: util.ClusterClientTLSSecretName(tc.Name),
+ SecretName: getTiCDCClusterClientTLSCertSecretName(tc),
},
},
})
@@ -566,6 +566,24 @@ func getNewTiCDCStatefulSet(tc *v1alpha1.TidbCluster, cm *corev1.ConfigMap) (*ap
return ticdcSts, nil
}
+func getTiCDCClusterTLSCertSecretName(tc *v1alpha1.TidbCluster) string {
+ clusterTLSSecretName := util.ClusterTLSSecretName(tc.Name, label.TiCDCLabelVal)
+ if tc.Spec.TiCDC.ClusterTLSSecretName != "" {
+ clusterTLSSecretName = tc.Spec.TiCDC.ClusterTLSSecretName
+ }
+
+ return clusterTLSSecretName
+}
+
+func getTiCDCClusterClientTLSCertSecretName(tc *v1alpha1.TidbCluster) string {
+ clusterClientTLSSecretName := util.ClusterClientTLSSecretName(tc.Name)
+ if tc.Spec.TiCDC.ClusterClientTLSSecretName != "" {
+ clusterClientTLSSecretName = tc.Spec.TiCDC.ClusterClientTLSSecretName
+ }
+
+ return clusterClientTLSSecretName
+}
+
func labelTiCDC(tc *v1alpha1.TidbCluster) label.Label {
instanceName := tc.GetInstanceName()
return label.New().Instance(instanceName).TiCDC()
From ced6412e66ef2757696990e39a8599bb51368526 Mon Sep 17 00:00:00 2001
From: ideascf | |||||||||||
-clusterTLSSecretName
-
-string
-
- |
-
-(Optional)
- ClusterTLSSecretName is used for overwriting the default mTLS cert secret name (see also: pkg/util/util.go:ClusterTLSSecretName) -This field is useful for sharing the same mTLS cert secret for multiple ticdc clusters connecting to the same upstream tidb cluster. - |
-||||||||||
-clusterClientTLSSecretName
-
-string
-
- |
-
-(Optional)
- ClusterTLSSecretName is used for overwriting the default cluster client cert secret name (see also: pkg/util/util.go:ClusterClientTLSSecretName)
-This field is useful for sharing the same cluster client cert secret for multiple ticdc clusters connecting to the same upstream tidb cluster.
-The ClusterClientTLSSecret is actually not directly used by ticdc, but it is useful for executing some commands via |
-||||||||||
baseImage
string
diff --git a/manifests/crd/v1/pingcap.com_tidbclusters.yaml b/manifests/crd/v1/pingcap.com_tidbclusters.yaml
index b658c82317..bd231fd88b 100644
--- a/manifests/crd/v1/pingcap.com_tidbclusters.yaml
+++ b/manifests/crd/v1/pingcap.com_tidbclusters.yaml
@@ -13152,10 +13152,6 @@ spec:
x-kubernetes-list-map-keys:
- name
x-kubernetes-list-type: map
- clusterClientTLSSecretName:
- type: string
- clusterTLSSecretName:
- type: string
config:
x-kubernetes-preserve-unknown-fields: true
configUpdateStrategy:
diff --git a/pkg/apis/pingcap/v1alpha1/openapi_generated.go b/pkg/apis/pingcap/v1alpha1/openapi_generated.go
index 22ceb9820c..bb6adb867a 100644
--- a/pkg/apis/pingcap/v1alpha1/openapi_generated.go
+++ b/pkg/apis/pingcap/v1alpha1/openapi_generated.go
@@ -9723,20 +9723,6 @@ func schema_pkg_apis_pingcap_v1alpha1_TiCDCSpec(ref common.ReferenceCallback) co
},
},
},
- "clusterTLSSecretName": {
- SchemaProps: spec.SchemaProps{
- Description: "ClusterTLSSecretName is used for overwriting the default mTLS cert secret name (see also: pkg/util/util.go:ClusterTLSSecretName) This field is useful for sharing the same mTLS cert secret for multiple ticdc clusters connecting to the same upstream tidb cluster.",
- Type: []string{"string"},
- Format: "",
- },
- },
- "clusterClientTLSSecretName": {
- SchemaProps: spec.SchemaProps{
- Description: "ClusterTLSSecretName is used for overwriting the default **cluster client** cert secret name (see also: pkg/util/util.go:ClusterClientTLSSecretName) This field is useful for sharing the same cluster client cert secret for multiple ticdc clusters connecting to the same upstream tidb cluster. The ClusterClientTLSSecret is actually not directly used by ticdc, but it is useful for executing some commands via `ticdc-ctl`\n by `kubectl exec -it ticdc-0 -- /cdc cli --ca /var/lib/cluster-client-tls/ca.crt --cert /var/lib/cluster-client-tls/tls.crt --key /var/lib/cluster-client-tls/tls.key ...`.",
- Type: []string{"string"},
- Format: "",
- },
- },
"baseImage": {
SchemaProps: spec.SchemaProps{
Description: "Base image of the component, image tag is now allowed during validation",
diff --git a/pkg/apis/pingcap/v1alpha1/types.go b/pkg/apis/pingcap/v1alpha1/types.go
index f2944a08ea..c5f536be1d 100644
--- a/pkg/apis/pingcap/v1alpha1/types.go
+++ b/pkg/apis/pingcap/v1alpha1/types.go
@@ -859,18 +859,6 @@ type TiCDCSpec struct {
// +optional
TLSClientSecretNames []string `json:"tlsClientSecretNames,omitempty"`
- // ClusterTLSSecretName is used for overwriting the default mTLS cert secret name (see also: pkg/util/util.go:ClusterTLSSecretName)
- // This field is useful for sharing the same mTLS cert secret for multiple ticdc clusters connecting to the same upstream tidb cluster.
- // +optional
- ClusterTLSSecretName string `json:"clusterTLSSecretName,omitempty"`
-
- // ClusterTLSSecretName is used for overwriting the default **cluster client** cert secret name (see also: pkg/util/util.go:ClusterClientTLSSecretName)
- // This field is useful for sharing the same cluster client cert secret for multiple ticdc clusters connecting to the same upstream tidb cluster.
- // The ClusterClientTLSSecret is actually not directly used by ticdc, but it is useful for executing some commands via `ticdc-ctl`
- // by `kubectl exec -it ticdc-0 -- /cdc cli --ca /var/lib/cluster-client-tls/ca.crt --cert /var/lib/cluster-client-tls/tls.crt --key /var/lib/cluster-client-tls/tls.key ...`.
- // +optional
- ClusterClientTLSSecretName string `json:"clusterClientTLSSecretName,omitempty"`
-
// Base image of the component, image tag is now allowed during validation
// +kubebuilder:default=pingcap/ticdc
// +optional
diff --git a/pkg/manager/member/ticdc_member_manager.go b/pkg/manager/member/ticdc_member_manager.go
index 5d66cf5d84..3c29259fed 100644
--- a/pkg/manager/member/ticdc_member_manager.go
+++ b/pkg/manager/member/ticdc_member_manager.go
@@ -405,13 +405,13 @@ func getNewTiCDCStatefulSet(tc *v1alpha1.TidbCluster, cm *corev1.ConfigMap) (*ap
vols = append(vols, corev1.Volume{
Name: ticdcCertVolumeMount, VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
- SecretName: getTiCDCClusterTLSCertSecretName(tc),
+ SecretName: util.ClusterTLSSecretName(tc.Name, label.TiCDCLabelVal),
},
},
}, corev1.Volume{
Name: util.ClusterClientVolName, VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
- SecretName: getTiCDCClusterClientTLSCertSecretName(tc),
+ SecretName: util.ClusterClientTLSSecretName(tc.Name),
},
},
})
@@ -566,24 +566,6 @@ func getNewTiCDCStatefulSet(tc *v1alpha1.TidbCluster, cm *corev1.ConfigMap) (*ap
return ticdcSts, nil
}
-func getTiCDCClusterTLSCertSecretName(tc *v1alpha1.TidbCluster) string {
- clusterTLSSecretName := util.ClusterTLSSecretName(tc.Name, label.TiCDCLabelVal)
- if tc.Spec.TiCDC.ClusterTLSSecretName != "" {
- clusterTLSSecretName = tc.Spec.TiCDC.ClusterTLSSecretName
- }
-
- return clusterTLSSecretName
-}
-
-func getTiCDCClusterClientTLSCertSecretName(tc *v1alpha1.TidbCluster) string {
- clusterClientTLSSecretName := util.ClusterClientTLSSecretName(tc.Name)
- if tc.Spec.TiCDC.ClusterClientTLSSecretName != "" {
- clusterClientTLSSecretName = tc.Spec.TiCDC.ClusterClientTLSSecretName
- }
-
- return clusterClientTLSSecretName
-}
-
func labelTiCDC(tc *v1alpha1.TidbCluster) label.Label {
instanceName := tc.GetInstanceName()
return label.New().Instance(instanceName).TiCDC()
From b6faebdacf6c3ba32e74cf4423ec89f0415125c1 Mon Sep 17 00:00:00 2001
From: hillium | |||||||||||
-commitTs
+startTs
string
@@ -5847,7 +5847,7 @@ string
| |||||||||||
-commitTs
+startTs
string
diff --git a/manifests/crd.yaml b/manifests/crd.yaml
index 336e5e1171..2394657360 100644
--- a/manifests/crd.yaml
+++ b/manifests/crd.yaml
@@ -8210,8 +8210,6 @@ spec:
type: object
brImage:
type: string
- commitTs:
- type: string
concurrency:
type: integer
endTs:
@@ -9193,6 +9191,8 @@ spec:
type: object
serviceAccount:
type: string
+ startTs:
+ type: string
storageClassName:
type: string
storageSize:
diff --git a/manifests/crd/v1/pingcap.com_compactbackups.yaml b/manifests/crd/v1/pingcap.com_compactbackups.yaml
index c58dbfe4ae..e3b434ae2d 100644
--- a/manifests/crd/v1/pingcap.com_compactbackups.yaml
+++ b/manifests/crd/v1/pingcap.com_compactbackups.yaml
@@ -1160,8 +1160,6 @@ spec:
type: object
brImage:
type: string
- commitTs:
- type: string
concurrency:
type: integer
endTs:
@@ -2143,6 +2141,8 @@ spec:
type: object
serviceAccount:
type: string
+ startTs:
+ type: string
storageClassName:
type: string
storageSize:
diff --git a/pkg/apis/pingcap/v1alpha1/openapi_generated.go b/pkg/apis/pingcap/v1alpha1/openapi_generated.go
index bb6adb867a..9c2de35e06 100644
--- a/pkg/apis/pingcap/v1alpha1/openapi_generated.go
+++ b/pkg/apis/pingcap/v1alpha1/openapi_generated.go
@@ -1775,7 +1775,7 @@ func schema_pkg_apis_pingcap_v1alpha1_CompactSpec(ref common.ReferenceCallback)
Format: "",
},
},
- "commitTs": {
+ "startTs": {
SchemaProps: spec.SchemaProps{
Description: "StartTs is the start ts of the compact backup. Format supports TSO or datetime, e.g. '400036290571534337', '2018-05-11 01:42:23'.",
Type: []string{"string"},
diff --git a/pkg/apis/pingcap/v1alpha1/types.go b/pkg/apis/pingcap/v1alpha1/types.go
index c5f536be1d..8f7fa95280 100644
--- a/pkg/apis/pingcap/v1alpha1/types.go
+++ b/pkg/apis/pingcap/v1alpha1/types.go
@@ -3483,7 +3483,7 @@ type CompactSpec struct {
StorageSize string `json:"storageSize,omitempty"`
// StartTs is the start ts of the compact backup.
// Format supports TSO or datetime, e.g. '400036290571534337', '2018-05-11 01:42:23'.
- StartTs string `json:"commitTs,omitempty"`
+ StartTs string `json:"startTs,omitempty"`
// EndTs is the end ts of the compact backup.
// Format supports TSO or datetime, e.g. '400036290571534337', '2018-05-11 01:42:23'.
// Default is current timestamp.
diff --git a/pkg/controller/compactbackup/compact_backup_controller.go b/pkg/controller/compactbackup/compact_backup_controller.go
index 10710f539b..e7ee80e2f3 100644
--- a/pkg/controller/compactbackup/compact_backup_controller.go
+++ b/pkg/controller/compactbackup/compact_backup_controller.go
@@ -3,7 +3,6 @@ package compact
import (
"context"
"fmt"
- "strconv"
"strings"
"time"
@@ -11,7 +10,6 @@ import (
perrors "github.com/pingcap/errors"
"github.com/pingcap/tidb-operator/pkg/apis/label"
"github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1"
- "github.com/pingcap/tidb-operator/pkg/apis/util/config"
"github.com/pingcap/tidb-operator/pkg/backup/constants"
backuputil "github.com/pingcap/tidb-operator/pkg/backup/util"
"github.com/pingcap/tidb-operator/pkg/client/clientset/versioned"
@@ -302,29 +300,12 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job
fmt.Sprintf("--namespace=%s", ns),
fmt.Sprintf("--resourceName=%s", name),
}
- startTS, err := config.ParseTSString(backup.Spec.StartTs)
- if err != nil {
- return nil, fmt.Sprintf("failed to parse startTs(%v)", backup.Spec.StartTs), err
- }
- args = append(args, "--from-ts", strconv.FormatUint(startTS, 10))
- endTS, err := config.ParseTSString(backup.Spec.EndTs)
- if err != nil {
- return nil, fmt.Sprintf("failed to parse endTs(%v)", backup.Spec.EndTs), err
- }
- args = append(args, "--until-ts", strconv.FormatUint(endTS, 10))
- args = append(args, "--concurrency", backup.Spec.EndTs)
- args = append(args, "--name", backup.GetObjectMeta().GetName())
- strg, err := backuputil.GetStoragePath(backup.Spec.StorageProvider)
- if err != nil {
- return nil, fmt.Sprintf("failed to get storage path: %v", err), err
- }
- args = append(args, "--storage-string", strg)
tikvImage := "pingcap/tikv"
if backup.Spec.TiKVImage != "" {
tikvImage = backup.Spec.TiKVImage
}
-
+
tikvVersion := backup.Spec.Version
_, imageVersion := backuputil.ParseImage(tikvImage)
if imageVersion != "" {
@@ -404,8 +385,8 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job
Command: []string{"/bin/sh", "-c"},
Args: []string{fmt.Sprintf("cp /br %s/br; echo 'BR copy finished'", util.BRBinPath)},
ImagePullPolicy: corev1.PullIfNotPresent,
- VolumeMounts: volumeMounts,
- Resources: backup.Spec.ResourceRequirements,
+ VolumeMounts: volumeMounts,
+ Resources: backup.Spec.ResourceRequirements,
},
{
Name: "tikv-ctl",
@@ -413,20 +394,18 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job
Command: []string{"/bin/sh", "-c"},
Args: []string{fmt.Sprintf("cp /tikv-ctl %s/tikv-ctl; echo 'tikv-ctl copy finished'", util.KVCTLBinPath)},
ImagePullPolicy: corev1.PullIfNotPresent,
- VolumeMounts: volumeMounts,
- Resources: backup.Spec.ResourceRequirements,
+ VolumeMounts: volumeMounts,
+ Resources: backup.Spec.ResourceRequirements,
},
},
Containers: []corev1.Container{
{
Name: "backup-manager",
- Image: c.deps.CLIConfig.TiDBBackupManagerImage,
- Command: []string{
- "/bin/sh", "-c",
- },
- Args: args,
- Env: envVars,
- VolumeMounts: volumeMounts,
+ Image: c.deps.CLIConfig.TiDBBackupManagerImage,
+ Args: args,
+ Env: envVars,
+ VolumeMounts: volumeMounts,
+ ImagePullPolicy: corev1.PullAlways,
},
},
RestartPolicy: corev1.RestartPolicyNever,
From bf9b18519496204f13803a6a5c8d2965b0c758ed Mon Sep 17 00:00:00 2001
From: RidRisR <79858083+RidRisR@users.noreply.github.com>
Date: Wed, 4 Dec 2024 07:31:07 +0100
Subject: [PATCH 17/49] attach to tc
---
pkg/apis/pingcap/v1alpha1/types.go | 12 +++-----
.../compact_backup_controller.go | 29 ++++++++-----------
2 files changed, 16 insertions(+), 25 deletions(-)
diff --git a/pkg/apis/pingcap/v1alpha1/types.go b/pkg/apis/pingcap/v1alpha1/types.go
index 8f7fa95280..5f1f2f6902 100644
--- a/pkg/apis/pingcap/v1alpha1/types.go
+++ b/pkg/apis/pingcap/v1alpha1/types.go
@@ -3447,7 +3447,7 @@ type CompactBackup struct {
Status CompactStatus `json:"status,omitempty"`
}
-// BackupSpec contains the backup specification for a tidb cluster.
+// CompactSpec contains the backup specification for a tidb cluster.
// +k8s:openapi-gen=true
type CompactSpec struct {
corev1.ResourceRequirements `json:"resources,omitempty"`
@@ -3498,17 +3498,13 @@ type CompactSpec struct {
// Base tolerations of backup Pods, components may add more tolerations upon this respectively
// +optional
Tolerations []corev1.Toleration `json:"tolerations,omitempty"`
- // Version specifies the tool image version used in compact `Backup`.
- Version string `json:"version,omitempty"`
// BrImage specifies the br image used in compact `Backup`.
// For examples `spec.brImage: pingcap/br:v4.0.8`
// For BR image, if it does not contain tag, Pod will use image 'BrImage:${TiKV_Version}'.
// +optional
- BrImage string `json:"brImage,omitempty"`
- // TiKVImage specifies the tikv image used in compact `Backup`.
- // For examples `spec.tikvImage: pingcap/tikv:v4.0.8`
- // +optional
- TiKVImage string `json:"tikvImage,omitempty"`
+ ToolImage string `json:"brImage,omitempty"`
+ // BRConfig is the configs for BR
+ BR *BRConfig `json:"br,omitempty"`
// ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images.
// +optional
ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"`
diff --git a/pkg/controller/compactbackup/compact_backup_controller.go b/pkg/controller/compactbackup/compact_backup_controller.go
index e7ee80e2f3..0c6964a2fd 100644
--- a/pkg/controller/compactbackup/compact_backup_controller.go
+++ b/pkg/controller/compactbackup/compact_backup_controller.go
@@ -301,28 +301,23 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job
fmt.Sprintf("--resourceName=%s", name),
}
- tikvImage := "pingcap/tikv"
- if backup.Spec.TiKVImage != "" {
- tikvImage = backup.Spec.TiKVImage
- }
-
- tikvVersion := backup.Spec.Version
- _, imageVersion := backuputil.ParseImage(tikvImage)
- if imageVersion != "" {
- tikvVersion = imageVersion
+ tc, err := c.deps.TiDBClusterLister.TidbClusters(ns).Get(backup.Spec.BR.Cluster)
+ if err != nil {
+ return nil, fmt.Sprintf("failed to fetch tidbcluster %s/%s", ns, backup.Spec.BR.Cluster), err
}
+ tikvImage := tc.TiKVImage()
+ _, tikvVersion := backuputil.ParseImage(tikvImage)
if tikvVersion != "" {
args = append(args, fmt.Sprintf("--tikvVersion=%s", tikvVersion))
- } else {
- return nil, "tikv version is empty", fmt.Errorf("tikv version is empty")
}
-
- brImage := fmt.Sprintf("pingcap/br:%s", tikvVersion)
- if backup.Spec.BrImage != "" {
- brImage = backup.Spec.BrImage
- if !strings.ContainsRune(brImage, ':') {
- brImage = fmt.Sprintf("%s:%s", brImage, tikvVersion)
+ brImage := "pingcap/br:" + tikvVersion
+ if backup.Spec.ToolImage != "" {
+ toolImage := backup.Spec.ToolImage
+ if !strings.ContainsRune(backup.Spec.ToolImage, ':') {
+ toolImage = fmt.Sprintf("%s:%s", toolImage, tikvVersion)
}
+
+ brImage = toolImage
}
//TODO: (Ris)What is the instance here?
From f9aafcbe52e2ef0149192164dc1695f5d7f53827 Mon Sep 17 00:00:00 2001
From: RidRisR <79858083+RidRisR@users.noreply.github.com>
Date: Wed, 4 Dec 2024 07:34:33 +0100
Subject: [PATCH 18/49] lint
---
docs/api-references/docs.md | 45 +++++--------------
manifests/crd.yaml | 40 +++++++++++++++--
.../crd/v1/pingcap.com_compactbackups.yaml | 40 +++++++++++++++--
.../pingcap/v1alpha1/openapi_generated.go | 18 +++-----
.../pingcap/v1alpha1/zz_generated.deepcopy.go | 5 +++
.../compact_backup_controller.go | 4 +-
6 files changed, 96 insertions(+), 56 deletions(-)
diff --git a/docs/api-references/docs.md b/docs/api-references/docs.md
index 57abb8805a..0755f48c1a 100644
--- a/docs/api-references/docs.md
+++ b/docs/api-references/docs.md
@@ -3447,6 +3447,7 @@ string
(Appears on: BackupSpec, +CompactSpec, RestoreSpec) @@ -5544,17 +5545,6 @@ bool | |||||||||||
-version
-
-string
-
- |
-
- Version specifies the tool image version used in compact |
-||||||||||
brImage
string
@@ -5569,15 +5559,15 @@ For BR image, if it does not contain tag, Pod will use image ‘BrImage:${Ti
| |||||||||||
-tikvImage
+br
-string
+
+BRConfig
+
|
-(Optional)
- TiKVImage specifies the tikv image used in compact BRConfig is the configs for BR |
||||||||||
-version
-
-string
-
- |
-
- Version specifies the tool image version used in compact |
-
brImage
string
@@ -5935,15 +5914,15 @@ For BR image, if it does not contain tag, Pod will use image ‘BrImage:${Ti
| |
-tikvImage
+br
-string
+
+BRConfig
+
|
-(Optional)
- TiKVImage specifies the tikv image used in compact BRConfig is the configs for BR |
-brImage
+toolImage
string
@@ -5900,7 +5900,7 @@ bool
| |
-brImage
+toolImage
string
diff --git a/manifests/crd.yaml b/manifests/crd.yaml
index 7079fab07f..c73a2e42ee 100644
--- a/manifests/crd.yaml
+++ b/manifests/crd.yaml
@@ -8244,8 +8244,6 @@ spec:
required:
- cluster
type: object
- brImage:
- type: string
concurrency:
type: integer
endTs:
@@ -9251,6 +9249,8 @@ spec:
type: string
type: object
type: array
+ toolImage:
+ type: string
useKMS:
type: boolean
volumeBackupInitJobMaxActiveSeconds:
diff --git a/manifests/crd/v1/pingcap.com_compactbackups.yaml b/manifests/crd/v1/pingcap.com_compactbackups.yaml
index 19ee6b2a4a..a837d98f18 100644
--- a/manifests/crd/v1/pingcap.com_compactbackups.yaml
+++ b/manifests/crd/v1/pingcap.com_compactbackups.yaml
@@ -1194,8 +1194,6 @@ spec:
required:
- cluster
type: object
- brImage:
- type: string
concurrency:
type: integer
endTs:
@@ -2201,6 +2199,8 @@ spec:
type: string
type: object
type: array
+ toolImage:
+ type: string
useKMS:
type: boolean
volumeBackupInitJobMaxActiveSeconds:
diff --git a/pkg/apis/pingcap/v1alpha1/openapi_generated.go b/pkg/apis/pingcap/v1alpha1/openapi_generated.go
index 4906ef9a5f..030f7dc7ce 100644
--- a/pkg/apis/pingcap/v1alpha1/openapi_generated.go
+++ b/pkg/apis/pingcap/v1alpha1/openapi_generated.go
@@ -1817,7 +1817,7 @@ func schema_pkg_apis_pingcap_v1alpha1_CompactSpec(ref common.ReferenceCallback)
},
},
},
- "brImage": {
+ "toolImage": {
SchemaProps: spec.SchemaProps{
Description: "BrImage specifies the br image used in compact `Backup`. For examples `spec.brImage: pingcap/br:v4.0.8` For BR image, if it does not contain tag, Pod will use image 'BrImage:${TiKV_Version}'.",
Type: []string{"string"},
diff --git a/pkg/backup/backup/backup_cleaner.go b/pkg/backup/backup/backup_cleaner.go
index d80967dd2c..8f859f6fe6 100644
--- a/pkg/backup/backup/backup_cleaner.go
+++ b/pkg/backup/backup/backup_cleaner.go
@@ -73,7 +73,11 @@ func (bc *backupCleaner) StopLogBackup(backup *v1alpha1.Backup) error {
return fmt.Errorf("backup %s/%s spec.BR shouldn't be nil", backup.GetNamespace(), backup.GetName())
}
if !v1alpha1.IsLogBackupAlreadyStart(backup) {
- return nil
+ return bc.statusUpdater.Update(backup, &v1alpha1.BackupCondition{
+ Command: v1alpha1.LogStopCommand,
+ Type: v1alpha1.BackupComplete,
+ Status: corev1.ConditionTrue,
+ }, nil)
}
if v1alpha1.IsLogBackupAlreadyStop(backup) {
return nil
diff --git a/pkg/controller/compactbackup/compact_backup_controller.go b/pkg/controller/compactbackup/compact_backup_controller.go
index 8c554edf33..a84cca4f26 100644
--- a/pkg/controller/compactbackup/compact_backup_controller.go
+++ b/pkg/controller/compactbackup/compact_backup_controller.go
@@ -321,9 +321,6 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job
}
tikvImage := tc.TiKVImage()
_, tikvVersion := backuputil.ParseImage(tikvImage)
- if tikvVersion != "" {
- args = append(args, fmt.Sprintf("--tikvVersion=%s", tikvVersion))
- }
brImage := "pingcap/br:" + tikvVersion
if backup.Spec.ToolImage != "" {
toolImage := backup.Spec.ToolImage
@@ -333,6 +330,7 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job
brImage = toolImage
}
+ klog.Infof("backup %s/%s use br image %s and tikv image %s", ns, name, brImage, tikvImage)
//TODO: (Ris)What is the instance here?
jobLabels := util.CombineStringMap(label.NewBackup().Instance("Compact-Backup").BackupJob().Backup(name), backup.Labels)
From 53a443ce4f8bae06ea21ef03b2c3e34e1e852d0a Mon Sep 17 00:00:00 2001
From: RidRisR <79858083+RidRisR@users.noreply.github.com>
Date: Wed, 11 Dec 2024 09:11:12 +0100
Subject: [PATCH 23/49] delete unused
---
cmd/backup-manager/app/compact/options/options.go | 9 ---------
1 file changed, 9 deletions(-)
diff --git a/cmd/backup-manager/app/compact/options/options.go b/cmd/backup-manager/app/compact/options/options.go
index 8ef0c32dff..56e2afe930 100644
--- a/cmd/backup-manager/app/compact/options/options.go
+++ b/cmd/backup-manager/app/compact/options/options.go
@@ -24,15 +24,6 @@ import (
const (
fromTSUnset = math.MaxUint64
untilTSUnset = 0
-
- namespaceFlag = "namespace"
- resourceNameFlag = "resourceName"
- tiKVVersionFlag = "tikvVersion"
- storageStringFlag = "storage-string"
- fromTSFlag = "from-ts"
- untilTSFlag = "until-ts"
- nameFlag = "name"
- concurrencyFlag = "concurrency"
)
type CompactOpts struct {
From ce4005a60ec5400030836fc040dbbd6334b9f7d3 Mon Sep 17 00:00:00 2001
From: RidRisR <79858083+RidRisR@users.noreply.github.com>
Date: Thu, 12 Dec 2024 07:41:05 +0100
Subject: [PATCH 24/49] more detailed status
---
cmd/backup-manager/app/compact/manager.go | 27 +++++----
.../app/compact/status_updater.go | 60 +++++++++++++++----
docs/api-references/docs.md | 20 +++++++
manifests/crd.yaml | 12 ++++
.../crd/v1/pingcap.com_compactbackups.yaml | 12 ++++
pkg/apis/pingcap/v1alpha1/types.go | 6 +-
.../compact_backup_controller.go | 16 +++--
7 files changed, 123 insertions(+), 30 deletions(-)
diff --git a/cmd/backup-manager/app/compact/manager.go b/cmd/backup-manager/app/compact/manager.go
index 58e6494c59..28ba18dcf7 100644
--- a/cmd/backup-manager/app/compact/manager.go
+++ b/cmd/backup-manager/app/compact/manager.go
@@ -44,10 +44,8 @@ type Progress struct {
// It just extracted the message from the JSON and keeps the origin json bytes.
// So you may extract fields from it by `json.Unmarshal(l.Raw, ...)`.
type logLine struct {
- Message string
-
- // Raw is the original log JSON.
- Raw []byte
+ Message string `json:"Message"`
+ Raw json.RawMessage `json:"-"`
}
// Manager mainly used to manage backup related work
@@ -178,16 +176,24 @@ func (cm *Manager) compactCmd(ctx context.Context, base64Storage string) *exec.C
func (cm *Manager) processCompactionLogs(ctx context.Context, logStream io.Reader) error {
dec := json.NewDecoder(logStream)
- var line logLine
for dec.More() {
if ctx.Err() != nil {
return ctx.Err()
}
- if err := dec.Decode(&line); err != nil {
+
+ var raw json.RawMessage
+ if err := dec.Decode(&raw); err != nil {
+ return errors.Annotate(err, "failed to decode raw log line")
+ }
+
+ var line logLine
+ if err := json.Unmarshal(raw, &line); err != nil {
return errors.Annotate(err, "failed to decode the line of log")
}
+ line.Raw = raw
+
if err := cm.processLogLine(ctx, line); err != nil {
- return errors.Annotate(err, "error during processing log line")
+ return err
}
}
@@ -204,7 +210,7 @@ func (cm *Manager) processLogLine(ctx context.Context, l logLine) error {
case messageCompactionDone:
var prog Progress
if err := json.Unmarshal(l.Raw, &prog); err != nil {
- return errors.Annotate(err, "failed to decode progress")
+ return errors.Annotatef(err, "failed to decode progress message: %s", string(l.Raw))
}
cm.statusUpdater.OnProgress(ctx, prog, cm.compact)
return nil
@@ -213,10 +219,11 @@ func (cm *Manager) processLogLine(ctx context.Context, l logLine) error {
Err string `json:"err"`
}{}
if err := json.Unmarshal(l.Raw, &errContainer); err != nil {
- return errors.Annotate(err, "failed to decode error message")
+ return errors.Annotatef(err, "failed to decode error message: %s", string(l.Raw))
}
- return errors.Errorf("compaction aborted: %s", errContainer.Err)
+ return errors.New(errContainer.Err)
default:
+ klog.Infof("progress log: %s", l.Message)
return nil
}
}
diff --git a/cmd/backup-manager/app/compact/status_updater.go b/cmd/backup-manager/app/compact/status_updater.go
index 6a1f353299..0dd5d5f9d5 100644
--- a/cmd/backup-manager/app/compact/status_updater.go
+++ b/cmd/backup-manager/app/compact/status_updater.go
@@ -16,6 +16,7 @@ package compact
import (
"context"
"fmt"
+ "time"
"github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1"
"github.com/pingcap/tidb-operator/pkg/client/clientset/versioned"
@@ -28,10 +29,16 @@ import (
"k8s.io/klog"
)
+const (
+ // progressDebounceDuration is the minimum time interval between two progress updates for a backup
+ progressDebounceDuration = 3 * time.Second
+)
+
type CompactStatusUpdater struct {
- recorder record.EventRecorder
- lister listers.CompactBackupLister
- cli versioned.Interface
+ recorder record.EventRecorder
+ lister listers.CompactBackupLister
+ cli versioned.Interface
+ progressLastUpdate time.Time
}
func NewCompactStatusUpdater(recorder record.EventRecorder, lister listers.CompactBackupLister, cli versioned.Interface) *CompactStatusUpdater {
@@ -46,21 +53,48 @@ func (r *CompactStatusUpdater) Event(compact *v1alpha1.CompactBackup, ty, reason
r.recorder.Event(compact, ty, reason, msg)
}
-func (r *CompactStatusUpdater) UpdateStatus(compact *v1alpha1.CompactBackup, newState string) error {
+func (r *CompactStatusUpdater) UpdateStatus(compact *v1alpha1.CompactBackup, newState string, progress string, message string) error {
ns := compact.GetNamespace()
backupName := compact.GetName()
- // try best effort to guarantee backup is updated.
+ key := fmt.Sprintf("%s/%s", ns, backupName) // Unique key for the backup
+
+ now := time.Now()
+ updateProgress := true
+ if progress != "" {
+ if now.Sub(r.progressLastUpdate) < progressDebounceDuration {
+ klog.Infof("Skipping progress update for [%s] due to debounce interval", key)
+ updateProgress = false
+ }
+ }
+
+ // Update the status
err := retry.OnError(retry.DefaultRetry, func(e error) bool { return e != nil }, func() error {
- // Always get the latest backup before update.
+ // Always get the latest CompactBackup before updating
if updated, err := r.lister.CompactBackups(ns).Get(backupName); err == nil {
- // make a copy so we don't mutate the shared cache
*compact = *(updated.DeepCopy())
} else {
utilruntime.HandleError(fmt.Errorf("error getting updated backup %s/%s from lister: %v", ns, backupName, err))
return err
}
- if compact.Status.State != newState {
+
+ updated := false
+ if newState !="" && compact.Status.State != newState {
compact.Status.State = newState
+ updated = true
+ updateProgress = true
+ }
+ if message != "" && compact.Status.Message != message {
+ compact.Status.Message = message
+ updated = true
+ }
+ if updateProgress && progress != "" && compact.Status.Progress != progress {
+ compact.Status.Progress = progress
+ updated = true
+ r.progressLastUpdate = now
+ }
+
+ // Apply the update if any field changed
+ if updated {
_, updateErr := r.cli.PingcapV1alpha1().CompactBackups(ns).Update(context.TODO(), compact, metav1.UpdateOptions{})
if updateErr == nil {
klog.Infof("Backup: [%s/%s] updated successfully", ns, backupName)
@@ -75,22 +109,22 @@ func (r *CompactStatusUpdater) UpdateStatus(compact *v1alpha1.CompactBackup, new
}
func (r *CompactStatusUpdater) OnStart(ctx context.Context, compact *v1alpha1.CompactBackup) {
- r.UpdateStatus(compact, "RUNNING")
+ r.UpdateStatus(compact, string(v1alpha1.BackupRunning), "", "")
r.Event(compact, corev1.EventTypeNormal, "Started", "The compaction process has started successfully.")
}
func (r *CompactStatusUpdater) OnProgress(ctx context.Context, p Progress, compact *v1alpha1.CompactBackup) {
- message := fmt.Sprintf("RUNNING[READ_META(%d/%d),COMPACT_WORK(%d/%d)]",
+ progress := fmt.Sprintf("[READ_META(%d/%d),COMPACT_WORK(%d/%d)]",
p.MetaCompleted, p.MetaTotal, p.BytesCompacted, p.BytesToCompact)
- r.UpdateStatus(compact, message)
+ r.UpdateStatus(compact, "", progress, "")
}
func (r *CompactStatusUpdater) OnFinish(ctx context.Context, err error, compact *v1alpha1.CompactBackup) {
if err != nil {
r.Event(compact, corev1.EventTypeWarning, "Failed", err.Error())
- r.UpdateStatus(compact, "FAILED")
+ r.UpdateStatus(compact, string(v1alpha1.BackupFailed), "", err.Error())
} else {
r.Event(compact, corev1.EventTypeNormal, "Finished", "The compaction process has finished successfully.")
- r.UpdateStatus(compact, "FINISHED")
+ r.UpdateStatus(compact, string(v1alpha1.BackupComplete), "", "")
}
}
diff --git a/docs/api-references/docs.md b/docs/api-references/docs.md
index 193f96923c..e56d99ecd0 100644
--- a/docs/api-references/docs.md
+++ b/docs/api-references/docs.md
@@ -6079,6 +6079,26 @@ string
| |
+progress
+
+string
+
+ |
++ | +
+message
+
+string
+
+ |
++ | +
from
-
-
-TiDBAccessConfig
-
-
-From is the tidb cluster that needs to backup.
-tikvGCLifeTime
-
-string
-
-StorageProvider
@@ -5458,30 +5435,6 @@ StorageProvider
storageClassName
-
-string
-
-The storageClassName of the persistent volume for Backup data storage. -Defaults to Kubernetes default storage class.
-storageSize
-
-string
-
-StorageSize is the request storage size for backup job
-startTs
string
@@ -5514,19 +5467,7 @@ int
ResumeGcSchedule indicates whether resume gc and pd scheduler for EBS volume snapshot backup -Concurrency is the concurrency of compact backup job
-resumeGcSchedule
-
-bool
-
-Concurrency is the concurrency of compact backup job
Additional volume mounts of component pod.
volumeBackupInitJobMaxActiveSeconds
-
-int
-
-VolumeBackupInitJobMaxActiveSeconds represents the deadline (in seconds) of the vbk init job
-from
-
-
-TiDBAccessConfig
-
-
-From is the tidb cluster that needs to backup.
-tikvGCLifeTime
-
-string
-
-StorageProvider
@@ -5813,30 +5720,6 @@ StorageProvider
storageClassName
-
-string
-
-The storageClassName of the persistent volume for Backup data storage. -Defaults to Kubernetes default storage class.
-storageSize
-
-string
-
-StorageSize is the request storage size for backup job
-startTs
string
@@ -5869,19 +5752,7 @@ int
ResumeGcSchedule indicates whether resume gc and pd scheduler for EBS volume snapshot backup -Concurrency is the concurrency of compact backup job
-resumeGcSchedule
-
-bool
-
-Concurrency is the concurrency of compact backup job
Additional volume mounts of component pod.
volumeBackupInitJobMaxActiveSeconds
-
-int
-
-VolumeBackupInitJobMaxActiveSeconds represents the deadline (in seconds) of the vbk init job
-(Appears on: BackupSpec, -CompactSpec, RestoreSpec)
diff --git a/manifests/crd.yaml b/manifests/crd.yaml index 5b2865926a..883a6351fd 100644 --- a/manifests/crd.yaml +++ b/manifests/crd.yaml @@ -8320,23 +8320,6 @@ spec: - name type: object type: array - from: - properties: - host: - type: string - port: - format: int32 - type: integer - secretName: - type: string - tlsClientSecretName: - type: string - user: - type: string - required: - - host - - secretName - type: object gcs: properties: bucket: @@ -9200,8 +9183,6 @@ spec: x-kubernetes-int-or-string: true type: object type: object - resumeGcSchedule: - type: boolean s3: properties: acl: @@ -9235,12 +9216,6 @@ spec: type: string startTs: type: string - storageClassName: - type: string - storageSize: - type: string - tikvGCLifeTime: - type: string tolerations: items: properties: @@ -9261,9 +9236,6 @@ spec: type: string useKMS: type: boolean - volumeBackupInitJobMaxActiveSeconds: - default: 600 - type: integer type: object status: properties: diff --git a/manifests/crd/v1/pingcap.com_compactbackups.yaml b/manifests/crd/v1/pingcap.com_compactbackups.yaml index d852d4659f..f280e97dd9 100644 --- a/manifests/crd/v1/pingcap.com_compactbackups.yaml +++ b/manifests/crd/v1/pingcap.com_compactbackups.yaml @@ -1270,23 +1270,6 @@ spec: - name type: object type: array - from: - properties: - host: - type: string - port: - format: int32 - type: integer - secretName: - type: string - tlsClientSecretName: - type: string - user: - type: string - required: - - host - - secretName - type: object gcs: properties: bucket: @@ -2150,8 +2133,6 @@ spec: x-kubernetes-int-or-string: true type: object type: object - resumeGcSchedule: - type: boolean s3: properties: acl: @@ -2185,12 +2166,6 @@ spec: type: string startTs: type: string - storageClassName: - type: string - storageSize: - type: string - tikvGCLifeTime: - type: string tolerations: items: properties: @@ -2211,9 +2186,6 @@ spec: type: string useKMS: type: boolean - volumeBackupInitJobMaxActiveSeconds: - default: 600 - type: integer type: object status: properties: diff --git a/pkg/apis/pingcap/v1alpha1/openapi_generated.go b/pkg/apis/pingcap/v1alpha1/openapi_generated.go index 030f7dc7ce..14d4952415 100644 --- a/pkg/apis/pingcap/v1alpha1/openapi_generated.go +++ b/pkg/apis/pingcap/v1alpha1/openapi_generated.go @@ -1729,18 +1729,6 @@ func schema_pkg_apis_pingcap_v1alpha1_CompactSpec(ref common.ReferenceCallback) }, }, }, - "from": { - SchemaProps: spec.SchemaProps{ - Description: "From is the tidb cluster that needs to backup.", - Ref: ref("github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.TiDBAccessConfig"), - }, - }, - "tikvGCLifeTime": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, "s3": { SchemaProps: spec.SchemaProps{ Ref: ref("github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.S3StorageProvider"), @@ -1761,20 +1749,6 @@ func schema_pkg_apis_pingcap_v1alpha1_CompactSpec(ref common.ReferenceCallback) Ref: ref("github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.LocalStorageProvider"), }, }, - "storageClassName": { - SchemaProps: spec.SchemaProps{ - Description: "The storageClassName of the persistent volume for Backup data storage. Defaults to Kubernetes default storage class.", - Type: []string{"string"}, - Format: "", - }, - }, - "storageSize": { - SchemaProps: spec.SchemaProps{ - Description: "StorageSize is the request storage size for backup job", - Type: []string{"string"}, - Format: "", - }, - }, "startTs": { SchemaProps: spec.SchemaProps{ Description: "StartTs is the start ts of the compact backup. Format supports TSO or datetime, e.g. '400036290571534337', '2018-05-11 01:42:23'.", @@ -1791,18 +1765,12 @@ func schema_pkg_apis_pingcap_v1alpha1_CompactSpec(ref common.ReferenceCallback) }, "concurrency": { SchemaProps: spec.SchemaProps{ - Description: "ResumeGcSchedule indicates whether resume gc and pd scheduler for EBS volume snapshot backup Concurrency is the concurrency of compact backup job", + Description: "Concurrency is the concurrency of compact backup job", Default: 4, Type: []string{"integer"}, Format: "int32", }, }, - "resumeGcSchedule": { - SchemaProps: spec.SchemaProps{ - Type: []string{"boolean"}, - Format: "", - }, - }, "tolerations": { SchemaProps: spec.SchemaProps{ Description: "Base tolerations of backup Pods, components may add more tolerations upon this respectively", @@ -1912,18 +1880,11 @@ func schema_pkg_apis_pingcap_v1alpha1_CompactSpec(ref common.ReferenceCallback) }, }, }, - "volumeBackupInitJobMaxActiveSeconds": { - SchemaProps: spec.SchemaProps{ - Description: "VolumeBackupInitJobMaxActiveSeconds represents the deadline (in seconds) of the vbk init job", - Type: []string{"integer"}, - Format: "int32", - }, - }, }, }, }, Dependencies: []string{ - "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.AzblobStorageProvider", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.BRConfig", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.BackoffRetryPolicy", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.GcsStorageProvider", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.LocalStorageProvider", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.S3StorageProvider", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.TiDBAccessConfig", "k8s.io/api/core/v1.Affinity", "k8s.io/api/core/v1.EnvVar", "k8s.io/api/core/v1.LocalObjectReference", "k8s.io/api/core/v1.PodSecurityContext", "k8s.io/api/core/v1.ResourceRequirements", "k8s.io/api/core/v1.Toleration", "k8s.io/api/core/v1.Volume", "k8s.io/api/core/v1.VolumeMount"}, + "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.AzblobStorageProvider", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.BRConfig", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.BackoffRetryPolicy", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.GcsStorageProvider", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.LocalStorageProvider", "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1.S3StorageProvider", "k8s.io/api/core/v1.Affinity", "k8s.io/api/core/v1.EnvVar", "k8s.io/api/core/v1.LocalObjectReference", "k8s.io/api/core/v1.PodSecurityContext", "k8s.io/api/core/v1.ResourceRequirements", "k8s.io/api/core/v1.Toleration", "k8s.io/api/core/v1.Volume", "k8s.io/api/core/v1.VolumeMount"}, } } diff --git a/pkg/apis/pingcap/v1alpha1/types.go b/pkg/apis/pingcap/v1alpha1/types.go index e08be21f19..5a1fb5053f 100644 --- a/pkg/apis/pingcap/v1alpha1/types.go +++ b/pkg/apis/pingcap/v1alpha1/types.go @@ -3497,7 +3497,7 @@ type CompactSpec struct { EndTs string `json:"endTs,omitempty"` // Concurrency is the concurrency of compact backup job // +default=4 - Concurrency int `json:"concurrency,omitempty"` + Concurrency int `json:"concurrency,omitempty"` // Base tolerations of backup Pods, components may add more tolerations upon this respectively // +optional Tolerations []corev1.Toleration `json:"tolerations,omitempty"` diff --git a/pkg/apis/pingcap/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/pingcap/v1alpha1/zz_generated.deepcopy.go index fbb1d8acf1..5653f71a37 100644 --- a/pkg/apis/pingcap/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/pingcap/v1alpha1/zz_generated.deepcopy.go @@ -937,22 +937,7 @@ func (in *CompactSpec) DeepCopyInto(out *CompactSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - if in.From != nil { - in, out := &in.From, &out.From - *out = new(TiDBAccessConfig) - (*in).DeepCopyInto(*out) - } - 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 - *out = new(string) - **out = **in - } if in.Tolerations != nil { in, out := &in.Tolerations, &out.Tolerations *out = make([]v1.Toleration, len(*in)) From 6594acf3a9059770bacf53cb1fc0fa8ed78252e3 Mon Sep 17 00:00:00 2001 From: RidRisR <79858083+RidRisR@users.noreply.github.com> Date: Wed, 18 Dec 2024 08:02:34 +0100 Subject: [PATCH 34/49] handle error --- pkg/controller/compactbackup/compact_backup_controller.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/controller/compactbackup/compact_backup_controller.go b/pkg/controller/compactbackup/compact_backup_controller.go index d98ba4b986..ed2fcf1a54 100644 --- a/pkg/controller/compactbackup/compact_backup_controller.go +++ b/pkg/controller/compactbackup/compact_backup_controller.go @@ -248,12 +248,16 @@ func (c *Controller) sync(key string) (err error) { return err } + if backup.Status.State == string(v1alpha1.BackupFailed) { + return nil + } + //Skip if backup.Status.State != "" { return nil } - c.UpdateStatus(backup, string(v1alpha1.BackupPrepare)) + c.UpdateStatus(backup, string(v1alpha1.BackupScheduled)) err = c.doCompact(backup.DeepCopy()) From 74d00156e02dbd8b045121e1caa675071acb0b98 Mon Sep 17 00:00:00 2001 From: RidRisR <79858083+RidRisR@users.noreply.github.com> Date: Mon, 23 Dec 2024 09:14:44 +0100 Subject: [PATCH 35/49] add necessary interface for retry --- pkg/apis/pingcap/v1alpha1/types.go | 5 ++ .../compactbackup/compact_backup_control.go | 41 +++++++++++++ .../compact_backup_controller.go | 57 ++++++++++++++++--- .../controller}/status_updater.go | 8 ++- 4 files changed, 102 insertions(+), 9 deletions(-) create mode 100644 pkg/controller/compactbackup/compact_backup_control.go rename {cmd/backup-manager/app/compact => pkg/controller}/status_updater.go (94%) diff --git a/pkg/apis/pingcap/v1alpha1/types.go b/pkg/apis/pingcap/v1alpha1/types.go index 5a1fb5053f..55de09367c 100644 --- a/pkg/apis/pingcap/v1alpha1/types.go +++ b/pkg/apis/pingcap/v1alpha1/types.go @@ -3538,9 +3538,14 @@ type CompactSpec struct { } type CompactStatus struct { + // State is the current state of the backup State string `json:"state,omitempty"` + // Progress is the progress of the backup Progress string `json:"progress,omitempty"` + // Message is the message of the backup Message string `json:"message,omitempty"` + // BackoffRetryStatus is status of the backoff retry, it will be used when backup pod or job exited unexpectedly + BackoffRetryStatus []BackoffRetryRecord `json:"backoffRetryStatus,omitempty"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/controller/compactbackup/compact_backup_control.go b/pkg/controller/compactbackup/compact_backup_control.go new file mode 100644 index 0000000000..eab668f25a --- /dev/null +++ b/pkg/controller/compactbackup/compact_backup_control.go @@ -0,0 +1,41 @@ +// 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, +// See the License for the specific language governing permissions and +// limitations under the License. + +package compact + +import ( + "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1" + "github.com/pingcap/tidb-operator/pkg/backup" + "github.com/pingcap/tidb-operator/pkg/client/clientset/versioned" + "github.com/pingcap/tidb-operator/pkg/controller" +) + +// ControlInterface implements the control logic for updating Compact Backup +// It is implemented as an interface to allow for extensions that provide different semantics. +// Currently, there is only one implementation. +type ControlInterface interface { + // UpdateStatus updates the status for a Compact Backup, include condition and status info + UpdateStatus(backup *v1alpha1.Backup, condition *v1alpha1.BackupCondition, newStatus *controller.BackupUpdateStatus) error +} + +type defaultCompactControl struct { + cli versioned.Interface + backupManager backup.BackupManager +} + +// NewDefaultCompactControl returns a new instance of the default implementation ControlInterface for Compact Backup +func NewDefaultCompactControl( + cli versioned.Interface, + deps *controller.Dependencies) ControlInterface { + +} \ No newline at end of file diff --git a/pkg/controller/compactbackup/compact_backup_controller.go b/pkg/controller/compactbackup/compact_backup_controller.go index ed2fcf1a54..4421ae39a2 100644 --- a/pkg/controller/compactbackup/compact_backup_controller.go +++ b/pkg/controller/compactbackup/compact_backup_controller.go @@ -238,7 +238,7 @@ func (c *Controller) sync(key string) (err error) { return err } klog.Infof("Backup: [%s/%s] start to sync", ns, name) - backup, err := c.deps.CompactBackupLister.CompactBackups(ns).Get(name) + compact, err := c.deps.CompactBackupLister.CompactBackups(ns).Get(name) if err != nil { if errors.IsNotFound(err) { klog.Infof("Backup has been deleted %v", key) @@ -248,18 +248,29 @@ func (c *Controller) sync(key string) (err error) { return err } - if backup.Status.State == string(v1alpha1.BackupFailed) { + if compact.Status.State == string(v1alpha1.BackupFailed) || compact.Status.State == string(v1alpha1.BackupScheduled) { return nil } - //Skip - if backup.Status.State != "" { - return nil + if compact.Status.State == string(v1alpha1.BackupRunning) { + jobFailed, reason, originalReason, err := c.detectBackupJobFailure(compact) + if err != nil { + klog.Errorf("Fail to detect backup %s/%s running status, error %v", ns, name, err) + return nil + } + + if jobFailed { + // retry backup after detect failure + if err := c.retryAfterFailureDetected(compact, reason, originalReason); err != nil { + klog.Errorf("Fail to restart snapshot backup %s/%s, error %v", ns, name, err) + } + return nil + } } - c.UpdateStatus(backup, string(v1alpha1.BackupScheduled)) + c.UpdateStatus(compact, string(v1alpha1.BackupScheduled)) - err = c.doCompact(backup.DeepCopy()) + err = c.doCompact(compact.DeepCopy()) var newState, message string if err != nil { @@ -269,7 +280,7 @@ func (c *Controller) sync(key string) (err error) { } else { newState = string(v1alpha1.BackupRunning) } - c.UpdateStatus(backup, newState, message) + c.UpdateStatus(compact, newState, message) return err } @@ -450,3 +461,33 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job return job, "", nil } + +func (c *Controller) detectBackupJobFailure(compact *v1alpha1.CompactBackup) ( + jobFailed bool, reason string, originalReason string, err error) { + var ( + ns = compact.GetNamespace() + name = compact.GetName() + ) + job, err := c.deps.JobLister.Jobs(ns).Get(name) + if err != nil && !errors.IsNotFound(err) { + klog.Errorf("Fail to get job %s for backup %s/%s, error %v ", name, ns, name, err) + return false, "", "", err + } + if job != nil { + for _, condition := range job.Status.Conditions { + if condition.Type == batchv1.JobFailed && condition.Status == corev1.ConditionTrue { + reason = fmt.Sprintf("Job %s has failed", name) + originalReason = condition.Reason + return true, reason, originalReason, nil + } + } + } + + klog.Infof("Detect backup %s/%s job failed, will retry, reason %s, original reason %s ", ns, name, reason, originalReason) + // record failure when detect failure + err = c.recordDetectedFailure(backup, reason, originalReason) + if err != nil { + klog.Errorf("failed to record detected failed %s for backup %s/%s", reason, ns, name) + } + return jobFailed, reason, originalReason, nil +} diff --git a/cmd/backup-manager/app/compact/status_updater.go b/pkg/controller/status_updater.go similarity index 94% rename from cmd/backup-manager/app/compact/status_updater.go rename to pkg/controller/status_updater.go index d3e9a1c286..322880ffe1 100644 --- a/cmd/backup-manager/app/compact/status_updater.go +++ b/pkg/controller/status_updater.go @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package compact +package controller import ( "context" @@ -34,6 +34,12 @@ const ( progressDebounceDuration = 3 * time.Second ) +type CompactStatusUpdaterInterface interface { + OnStart(ctx context.Context, compact *v1alpha1.CompactBackup) + OnProgress(ctx context.Context, p Progress, compact *v1alpha1.CompactBackup) + OnFinish(ctx context.Context, compact *v1alpha1.CompactBackup) +} + type CompactStatusUpdater struct { recorder record.EventRecorder lister listers.CompactBackupLister From 09873ae0fa40b4efcf6c4f94571706b013007856 Mon Sep 17 00:00:00 2001 From: RidRisR <79858083+RidRisR@users.noreply.github.com> Date: Mon, 23 Dec 2024 09:16:03 +0100 Subject: [PATCH 36/49] add control interface --- pkg/controller/compact_backup_control.go | 67 ++++++++++++++++++++++++ pkg/controller/dependences.go | 1 + 2 files changed, 68 insertions(+) create mode 100644 pkg/controller/compact_backup_control.go diff --git a/pkg/controller/compact_backup_control.go b/pkg/controller/compact_backup_control.go new file mode 100644 index 0000000000..2b79a7c701 --- /dev/null +++ b/pkg/controller/compact_backup_control.go @@ -0,0 +1,67 @@ +// Copyright 2019 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. + +// Copyright 2019 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.i + +package controller + +import ( + "context" + + "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1" + "github.com/pingcap/tidb-operator/pkg/client/clientset/versioned" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/tools/record" +) + +// BackupControlInterface manages Backups used in BackupSchedule +type CompactBackupControlInterface interface { + CreateCompactBackup(compact *v1alpha1.CompactBackup) (*v1alpha1.CompactBackup, error) + DeleteCompactBackup(compact *v1alpha1.CompactBackup) error +} + +type realCompactControl struct { + cli versioned.Interface + recorder record.EventRecorder +} + +func NewRealCompactControl(cli versioned.Interface, recorder record.EventRecorder) CompactBackupControlInterface { + return &realCompactControl{ + cli: cli, + recorder: recorder, + } +} + +func (c *realCompactControl) CreateCompactBackup(compact *v1alpha1.CompactBackup) (*v1alpha1.CompactBackup, error) { + ns := compact.GetNamespace() + + return c.cli.PingcapV1alpha1().CompactBackups(ns).Create(context.TODO(), compact, metav1.CreateOptions{}) +} + +func (c *realCompactControl) DeleteCompactBackup(compact *v1alpha1.CompactBackup) error { + ns := compact.GetNamespace() + compactName := compact.GetName() + + return c.cli.PingcapV1alpha1().CompactBackups(ns).Delete(context.TODO(), compactName, metav1.DeleteOptions{}) +} \ No newline at end of file diff --git a/pkg/controller/dependences.go b/pkg/controller/dependences.go index 34878c0c44..52f8d50ce2 100644 --- a/pkg/controller/dependences.go +++ b/pkg/controller/dependences.go @@ -195,6 +195,7 @@ type Controls struct { ProxyControl TiProxyControlInterface TiDBControl TiDBControlInterface BackupControl BackupControlInterface + CompactControl CompactBackupControlInterface RestoreControl RestoreControlInterface SecretControl SecretControlInterface } From c9e78c834408c98a9c51a72ced1afed46b276884 Mon Sep 17 00:00:00 2001 From: RidRisR <79858083+RidRisR@users.noreply.github.com> Date: Mon, 23 Dec 2024 09:23:52 +0100 Subject: [PATCH 37/49] fix updater usage --- cmd/backup-manager/app/compact/manager.go | 18 ++++++------------ pkg/controller/status_updater.go | 13 ++++++++++--- tests/e2e/br/framework/br/data.go | 6 ------ 3 files changed, 16 insertions(+), 21 deletions(-) diff --git a/cmd/backup-manager/app/compact/manager.go b/cmd/backup-manager/app/compact/manager.go index aab8e0dd90..edd49e7752 100644 --- a/cmd/backup-manager/app/compact/manager.go +++ b/cmd/backup-manager/app/compact/manager.go @@ -29,6 +29,7 @@ import ( "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1" pkgutil "github.com/pingcap/tidb-operator/pkg/backup/util" listers "github.com/pingcap/tidb-operator/pkg/client/listers/pingcap/v1alpha1" + "github.com/pingcap/tidb-operator/pkg/controller" "github.com/pingcap/tidb-operator/pkg/util" "k8s.io/klog/v2" ) @@ -38,13 +39,6 @@ const ( messageCompactAborted = "Compaction aborted." ) -type Progress struct { - MetaCompleted uint64 `json:"meta_completed"` - MetaTotal uint64 `json:"meta_total"` - BytesToCompact uint64 `json:"bytes_to_compact"` - BytesCompacted uint64 `json:"bytes_compacted"` -} - // logLine is line of JSON log. // It just extracted the message from the JSON and keeps the origin json bytes. // So you may extract fields from it by `json.Unmarshal(l.Raw, ...)`. @@ -57,14 +51,14 @@ type logLine struct { type Manager struct { compact *v1alpha1.CompactBackup resourceLister listers.CompactBackupLister - statusUpdater *CompactStatusUpdater + statusUpdater controller.CompactStatusUpdaterInterface options options.CompactOpts } // NewManager return a Manager func NewManager( lister listers.CompactBackupLister, - statusUpdater *CompactStatusUpdater, + statusUpdater controller.CompactStatusUpdaterInterface, compactOpts options.CompactOpts) *Manager { compact, err := lister.CompactBackups(compactOpts.Namespace).Get(compactOpts.ResourceName) if err != nil { @@ -93,7 +87,7 @@ func (cm *Manager) ProcessCompact() error { defer cancel() compact, err := cm.resourceLister.CompactBackups(cm.options.Namespace).Get(cm.options.ResourceName) - defer func() { cm.statusUpdater.OnFinish(ctx, err, cm.compact) }() + defer func() { cm.statusUpdater.OnFinish(ctx, cm.compact, err) }() if err != nil { return errors.New("backup not found") } @@ -208,11 +202,11 @@ func (cm *Manager) processCompactionLogs(ctx context.Context, logStream io.Reade func (cm *Manager) processLogLine(ctx context.Context, l logLine) error { switch l.Message { case messageCompactionDone: - var prog Progress + var prog controller.Progress if err := json.Unmarshal(l.Raw, &prog); err != nil { return errors.Annotatef(err, "failed to decode progress message: %s", string(l.Raw)) } - cm.statusUpdater.OnProgress(ctx, prog, cm.compact) + cm.statusUpdater.OnProgress(ctx, cm.compact, prog) return nil case messageCompactAborted: errContainer := struct { diff --git a/pkg/controller/status_updater.go b/pkg/controller/status_updater.go index 322880ffe1..0efe59cb72 100644 --- a/pkg/controller/status_updater.go +++ b/pkg/controller/status_updater.go @@ -34,10 +34,17 @@ const ( progressDebounceDuration = 3 * time.Second ) +type Progress struct { + MetaCompleted uint64 `json:"meta_completed"` + MetaTotal uint64 `json:"meta_total"` + BytesToCompact uint64 `json:"bytes_to_compact"` + BytesCompacted uint64 `json:"bytes_compacted"` +} + type CompactStatusUpdaterInterface interface { OnStart(ctx context.Context, compact *v1alpha1.CompactBackup) - OnProgress(ctx context.Context, p Progress, compact *v1alpha1.CompactBackup) - OnFinish(ctx context.Context, compact *v1alpha1.CompactBackup) + OnProgress(ctx context.Context, compact *v1alpha1.CompactBackup, p Progress) + OnFinish(ctx context.Context, compact *v1alpha1.CompactBackup, err error) } type CompactStatusUpdater struct { @@ -123,7 +130,7 @@ func (r *CompactStatusUpdater) OnProgress(ctx context.Context, p Progress, compa r.UpdateStatus(compact, "", progress, "") } -func (r *CompactStatusUpdater) OnFinish(ctx context.Context, err error, compact *v1alpha1.CompactBackup) { +func (r *CompactStatusUpdater) OnFinish(ctx context.Context, compact *v1alpha1.CompactBackup, err error) { if err != nil { r.Event(compact, corev1.EventTypeWarning, "Failed", err.Error()) r.UpdateStatus(compact, string(v1alpha1.BackupFailed), "", err.Error()) diff --git a/tests/e2e/br/framework/br/data.go b/tests/e2e/br/framework/br/data.go index 4e68c99b8c..1b1ece903f 100644 --- a/tests/e2e/br/framework/br/data.go +++ b/tests/e2e/br/framework/br/data.go @@ -190,12 +190,6 @@ func GetCompactBackup(ns, name, tcName string, s3Config *v1alpha1.S3StorageProvi StorageProvider: v1alpha1.StorageProvider{ S3: s3Config, }, - From: &v1alpha1.TiDBAccessConfig{ - Host: controller.TiDBMemberName(tcName), - SecretName: name, - Port: v1alpha1.DefaultTiDBServerPort, - User: "root", - }, BR: &v1alpha1.BRConfig{ Cluster: tcName, ClusterNamespace: ns, From 13d51a105692ff74f27868829c82840c76ab4043 Mon Sep 17 00:00:00 2001 From: RidRisR <79858083+RidRisR@users.noreply.github.com> Date: Mon, 23 Dec 2024 09:27:40 +0100 Subject: [PATCH 38/49] status_updater formally done --- cmd/backup-manager/app/cmd/compact.go | 3 ++- .../{status_updater.go => compact_status_updater.go} | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) rename pkg/controller/{status_updater.go => compact_status_updater.go} (97%) diff --git a/cmd/backup-manager/app/cmd/compact.go b/cmd/backup-manager/app/cmd/compact.go index 5f8796ed75..f4fab17ed7 100644 --- a/cmd/backup-manager/app/cmd/compact.go +++ b/cmd/backup-manager/app/cmd/compact.go @@ -21,6 +21,7 @@ import ( "github.com/pingcap/tidb-operator/cmd/backup-manager/app/constants" "github.com/pingcap/tidb-operator/cmd/backup-manager/app/util" informers "github.com/pingcap/tidb-operator/pkg/client/informers/externalversions" + "github.com/pingcap/tidb-operator/pkg/controller" "github.com/spf13/cobra" "k8s.io/client-go/tools/cache" cmdutil "k8s.io/kubectl/pkg/cmd/util" @@ -54,7 +55,7 @@ func runCompact(compactOpts options.CompactOpts, kubecfg string) error { informerFactory := informers.NewSharedInformerFactoryWithOptions(cli, constants.ResyncDuration, options...) recorder := util.NewEventRecorder(kubeCli, "compact-manager") compactInformer := informerFactory.Pingcap().V1alpha1().CompactBackups() - statusUpdater := compact.NewCompactStatusUpdater(recorder, compactInformer.Lister(), cli) + statusUpdater := controller.NewCompactStatusUpdater(recorder, compactInformer.Lister(), cli) ctx, cancel := context.WithCancel(context.Background()) defer cancel() diff --git a/pkg/controller/status_updater.go b/pkg/controller/compact_status_updater.go similarity index 97% rename from pkg/controller/status_updater.go rename to pkg/controller/compact_status_updater.go index 0efe59cb72..823b889199 100644 --- a/pkg/controller/status_updater.go +++ b/pkg/controller/compact_status_updater.go @@ -124,7 +124,7 @@ func (r *CompactStatusUpdater) OnStart(ctx context.Context, compact *v1alpha1.Co r.Event(compact, corev1.EventTypeNormal, "Started", "The compaction process has started successfully.") } -func (r *CompactStatusUpdater) OnProgress(ctx context.Context, p Progress, compact *v1alpha1.CompactBackup) { +func (r *CompactStatusUpdater) OnProgress(ctx context.Context, compact *v1alpha1.CompactBackup, p Progress) { progress := fmt.Sprintf("[READ_META(%d/%d),COMPACT_WORK(%d/%d)]", p.MetaCompleted, p.MetaTotal, p.BytesCompacted, p.BytesToCompact) r.UpdateStatus(compact, "", progress, "") From 8fb8ae8700c3783635dae0bdeca12b27987b424c Mon Sep 17 00:00:00 2001 From: RidRisR <79858083+RidRisR@users.noreply.github.com> Date: Mon, 23 Dec 2024 10:12:39 +0100 Subject: [PATCH 39/49] simplify codes --- pkg/controller/compact_status_updater.go | 14 +++++++ .../compactbackup/compact_backup_control.go | 41 ------------------- .../compact_backup_controller.go | 15 +++---- 3 files changed, 19 insertions(+), 51 deletions(-) delete mode 100644 pkg/controller/compactbackup/compact_backup_control.go diff --git a/pkg/controller/compact_status_updater.go b/pkg/controller/compact_status_updater.go index 823b889199..f06a9668ab 100644 --- a/pkg/controller/compact_status_updater.go +++ b/pkg/controller/compact_status_updater.go @@ -42,6 +42,8 @@ type Progress struct { } type CompactStatusUpdaterInterface interface { + OnSchedule(ctx context.Context, compact *v1alpha1.CompactBackup) + OnCreateJob(ctx context.Context, compact *v1alpha1.CompactBackup, err error) OnStart(ctx context.Context, compact *v1alpha1.CompactBackup) OnProgress(ctx context.Context, compact *v1alpha1.CompactBackup, p Progress) OnFinish(ctx context.Context, compact *v1alpha1.CompactBackup, err error) @@ -119,6 +121,18 @@ func (r *CompactStatusUpdater) UpdateStatus(compact *v1alpha1.CompactBackup, new return err } +func (r *CompactStatusUpdater) OnSchedule(ctx context.Context, compact *v1alpha1.CompactBackup) { + r.UpdateStatus(compact, string(v1alpha1.BackupScheduled), "", "") +} + +func (r *CompactStatusUpdater) OnCreateJob(ctx context.Context, compact *v1alpha1.CompactBackup, err error) { + if err != nil { + r.UpdateStatus(compact, string(v1alpha1.BackupFailed), "", err.Error()) + } else { + r.UpdateStatus(compact, string(v1alpha1.BackupPrepare), "", "") + } +} + func (r *CompactStatusUpdater) OnStart(ctx context.Context, compact *v1alpha1.CompactBackup) { r.UpdateStatus(compact, string(v1alpha1.BackupRunning), "", "") r.Event(compact, corev1.EventTypeNormal, "Started", "The compaction process has started successfully.") diff --git a/pkg/controller/compactbackup/compact_backup_control.go b/pkg/controller/compactbackup/compact_backup_control.go deleted file mode 100644 index eab668f25a..0000000000 --- a/pkg/controller/compactbackup/compact_backup_control.go +++ /dev/null @@ -1,41 +0,0 @@ -// 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, -// See the License for the specific language governing permissions and -// limitations under the License. - -package compact - -import ( - "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1" - "github.com/pingcap/tidb-operator/pkg/backup" - "github.com/pingcap/tidb-operator/pkg/client/clientset/versioned" - "github.com/pingcap/tidb-operator/pkg/controller" -) - -// ControlInterface implements the control logic for updating Compact Backup -// It is implemented as an interface to allow for extensions that provide different semantics. -// Currently, there is only one implementation. -type ControlInterface interface { - // UpdateStatus updates the status for a Compact Backup, include condition and status info - UpdateStatus(backup *v1alpha1.Backup, condition *v1alpha1.BackupCondition, newStatus *controller.BackupUpdateStatus) error -} - -type defaultCompactControl struct { - cli versioned.Interface - backupManager backup.BackupManager -} - -// NewDefaultCompactControl returns a new instance of the default implementation ControlInterface for Compact Backup -func NewDefaultCompactControl( - cli versioned.Interface, - deps *controller.Dependencies) ControlInterface { - -} \ No newline at end of file diff --git a/pkg/controller/compactbackup/compact_backup_controller.go b/pkg/controller/compactbackup/compact_backup_controller.go index 4421ae39a2..04f5852dae 100644 --- a/pkg/controller/compactbackup/compact_backup_controller.go +++ b/pkg/controller/compactbackup/compact_backup_controller.go @@ -47,6 +47,7 @@ type Controller struct { // backups that need to be synced. queue workqueue.RateLimitingInterface cli versioned.Interface + statusUpdater controller.CompactStatusUpdaterInterface } // NewController creates a backup controller. @@ -268,19 +269,12 @@ func (c *Controller) sync(key string) (err error) { } } - c.UpdateStatus(compact, string(v1alpha1.BackupScheduled)) + c.statusUpdater.OnSchedule(context.TODO(), compact) err = c.doCompact(compact.DeepCopy()) + klog.Errorf("Backup: [%s/%s] sync failed, error: %v", ns, name, err) - var newState, message string - if err != nil { - newState = string(v1alpha1.BackupFailed) - message = err.Error() - klog.Errorf("Backup: [%s/%s] sync failed, error: %v", ns, name, err) - } else { - newState = string(v1alpha1.BackupRunning) - } - c.UpdateStatus(compact, newState, message) + c.statusUpdater.OnCreateJob(context.TODO(), compact, err) return err } @@ -310,6 +304,7 @@ func (c *Controller) doCompact(backup *v1alpha1.CompactBackup) error { func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job, string, error) { ns := backup.GetNamespace() name := backup.GetName() + // Do we need a unique name for the job? jobName := backup.GetName() var ( From ed3e4ba9b05fee71f51390ef9264837ffcabfaa0 Mon Sep 17 00:00:00 2001 From: RidRisR <79858083+RidRisR@users.noreply.github.com> Date: Mon, 23 Dec 2024 11:29:30 +0100 Subject: [PATCH 40/49] caller side --- pkg/apis/pingcap/v1alpha1/types.go | 2 +- pkg/controller/compact_status_updater.go | 94 +++++++++++++++---- .../compact_backup_controller.go | 43 ++++++++- 3 files changed, 119 insertions(+), 20 deletions(-) diff --git a/pkg/apis/pingcap/v1alpha1/types.go b/pkg/apis/pingcap/v1alpha1/types.go index 55de09367c..2a264ea18b 100644 --- a/pkg/apis/pingcap/v1alpha1/types.go +++ b/pkg/apis/pingcap/v1alpha1/types.go @@ -3542,7 +3542,7 @@ type CompactStatus struct { State string `json:"state,omitempty"` // Progress is the progress of the backup Progress string `json:"progress,omitempty"` - // Message is the message of the backup + // Message is the error message of the backup Message string `json:"message,omitempty"` // BackoffRetryStatus is status of the backoff retry, it will be used when backup pod or job exited unexpectedly BackoffRetryStatus []BackoffRetryRecord `json:"backoffRetryStatus,omitempty"` diff --git a/pkg/controller/compact_status_updater.go b/pkg/controller/compact_status_updater.go index f06a9668ab..8576a883b8 100644 --- a/pkg/controller/compact_status_updater.go +++ b/pkg/controller/compact_status_updater.go @@ -34,19 +34,39 @@ const ( progressDebounceDuration = 3 * time.Second ) +type RetryStatus struct { + // RetryNum is the number of retry + RetryNum *int + // DetectFailedAt is the time when detect failure + DetectFailedAt *metav1.Time + // ExpectedRetryAt is the time we calculate and expect retry after it + ExpectedRetryAt *metav1.Time + // RealRetryAt is the time when the retry was actually initiated + RealRetryAt *metav1.Time + // Reason is the reason of retry + RetryReason *string + // OriginalReason is the original reason of backup job or pod failed + OriginalReason *string +} + type Progress struct { + // MetaCompleted is the number of meta files compacted MetaCompleted uint64 `json:"meta_completed"` + // MetaTotal is the total number of meta files MetaTotal uint64 `json:"meta_total"` + // BytesToCompact is the number of bytes to compact BytesToCompact uint64 `json:"bytes_to_compact"` + // BytesCompacted is the number of bytes compacted BytesCompacted uint64 `json:"bytes_compacted"` } type CompactStatusUpdaterInterface interface { - OnSchedule(ctx context.Context, compact *v1alpha1.CompactBackup) - OnCreateJob(ctx context.Context, compact *v1alpha1.CompactBackup, err error) - OnStart(ctx context.Context, compact *v1alpha1.CompactBackup) - OnProgress(ctx context.Context, compact *v1alpha1.CompactBackup, p Progress) - OnFinish(ctx context.Context, compact *v1alpha1.CompactBackup, err error) + OnSchedule(ctx context.Context, compact *v1alpha1.CompactBackup) error + OnCreateJob(ctx context.Context, compact *v1alpha1.CompactBackup, err error) error + OnStart(ctx context.Context, compact *v1alpha1.CompactBackup) error + OnProgress(ctx context.Context, compact *v1alpha1.CompactBackup, p Progress) error + OnFinish(ctx context.Context, compact *v1alpha1.CompactBackup, err error) error + OnRetriableFailed(ctx context.Context, compact *v1alpha1.CompactBackup, retry *RetryStatus) error } type CompactStatusUpdater struct { @@ -121,35 +141,75 @@ func (r *CompactStatusUpdater) UpdateStatus(compact *v1alpha1.CompactBackup, new return err } -func (r *CompactStatusUpdater) OnSchedule(ctx context.Context, compact *v1alpha1.CompactBackup) { - r.UpdateStatus(compact, string(v1alpha1.BackupScheduled), "", "") +func (r *CompactStatusUpdater) UpdateRetryStatus(compact *v1alpha1.CompactBackup, newState string, status *RetryStatus) error { + ns := compact.GetNamespace() + backupName := compact.GetName() + + // Update the status + err := retry.OnError(retry.DefaultRetry, func(e error) bool { return e != nil }, func() error { + // Always get the latest CompactBackup before updating + if updated, err := r.lister.CompactBackups(ns).Get(backupName); err == nil { + *compact = *(updated.DeepCopy()) + } else { + utilruntime.HandleError(fmt.Errorf("error getting updated backup %s/%s from lister: %v", ns, backupName, err)) + return err + } + + updated := false + if newState != "" && compact.Status.State != newState { + compact.Status.State = newState + updated = true + } + //TODO: (Ris) update the retry status here + + // Apply the update if any field changed + if updated { + _, updateErr := r.cli.PingcapV1alpha1().CompactBackups(ns).Update(context.TODO(), compact, metav1.UpdateOptions{}) + if updateErr == nil { + klog.Infof("Backup: [%s/%s] updated successfully", ns, backupName) + return nil + } + klog.Errorf("Failed to update backup [%s/%s], error: %v", ns, backupName, updateErr) + return updateErr + } + return nil + }) + return err +} + +func (r *CompactStatusUpdater) OnSchedule(ctx context.Context, compact *v1alpha1.CompactBackup) error { + return r.UpdateStatus(compact, string(v1alpha1.BackupScheduled), "", "") } -func (r *CompactStatusUpdater) OnCreateJob(ctx context.Context, compact *v1alpha1.CompactBackup, err error) { +func (r *CompactStatusUpdater) OnCreateJob(ctx context.Context, compact *v1alpha1.CompactBackup, err error) error { if err != nil { - r.UpdateStatus(compact, string(v1alpha1.BackupFailed), "", err.Error()) + return r.UpdateStatus(compact, string(v1alpha1.BackupFailed), "", err.Error()) } else { - r.UpdateStatus(compact, string(v1alpha1.BackupPrepare), "", "") + return r.UpdateStatus(compact, string(v1alpha1.BackupPrepare), "", "") } } -func (r *CompactStatusUpdater) OnStart(ctx context.Context, compact *v1alpha1.CompactBackup) { - r.UpdateStatus(compact, string(v1alpha1.BackupRunning), "", "") +func (r *CompactStatusUpdater) OnStart(ctx context.Context, compact *v1alpha1.CompactBackup) error { r.Event(compact, corev1.EventTypeNormal, "Started", "The compaction process has started successfully.") + return r.UpdateStatus(compact, string(v1alpha1.BackupRunning), "", "") } -func (r *CompactStatusUpdater) OnProgress(ctx context.Context, compact *v1alpha1.CompactBackup, p Progress) { +func (r *CompactStatusUpdater) OnProgress(ctx context.Context, compact *v1alpha1.CompactBackup, p Progress) error { progress := fmt.Sprintf("[READ_META(%d/%d),COMPACT_WORK(%d/%d)]", p.MetaCompleted, p.MetaTotal, p.BytesCompacted, p.BytesToCompact) - r.UpdateStatus(compact, "", progress, "") + return r.UpdateStatus(compact, "", progress, "") } -func (r *CompactStatusUpdater) OnFinish(ctx context.Context, compact *v1alpha1.CompactBackup, err error) { +func (r *CompactStatusUpdater) OnFinish(ctx context.Context, compact *v1alpha1.CompactBackup, err error) error { if err != nil { r.Event(compact, corev1.EventTypeWarning, "Failed", err.Error()) - r.UpdateStatus(compact, string(v1alpha1.BackupFailed), "", err.Error()) + return r.UpdateStatus(compact, string(v1alpha1.BackupFailed), "", err.Error()) } else { r.Event(compact, corev1.EventTypeNormal, "Finished", "The compaction process has finished successfully.") - r.UpdateStatus(compact, string(v1alpha1.BackupComplete), "", "") + return r.UpdateStatus(compact, string(v1alpha1.BackupComplete), "", "") } } + +func (r *CompactStatusUpdater) OnRetriableFailed(ctx context.Context, compact *v1alpha1.CompactBackup, retry *RetryStatus) error { + return r.UpdateRetryStatus(compact, string(v1alpha1.BackupRetryTheFailed), retry) +} diff --git a/pkg/controller/compactbackup/compact_backup_controller.go b/pkg/controller/compactbackup/compact_backup_controller.go index 04f5852dae..7181cca5c9 100644 --- a/pkg/controller/compactbackup/compact_backup_controller.go +++ b/pkg/controller/compactbackup/compact_backup_controller.go @@ -249,7 +249,13 @@ func (c *Controller) sync(key string) (err error) { return err } - if compact.Status.State == string(v1alpha1.BackupFailed) || compact.Status.State == string(v1alpha1.BackupScheduled) { + if compact.Status.State == string(v1alpha1.BackupFailed){ + klog.Errorf("Backup %s/%s is failed, skip", ns, name) + return nil + } + + if compact.Status.State == string(v1alpha1.BackupScheduled) { + klog.Infof("Backup %s/%s is scheduled, skip", ns, name) return nil } @@ -262,6 +268,7 @@ func (c *Controller) sync(key string) (err error) { if jobFailed { // retry backup after detect failure + //TODO: (Ris)impl this if err := c.retryAfterFailureDetected(compact, reason, originalReason); err != nil { klog.Errorf("Fail to restart snapshot backup %s/%s, error %v", ns, name, err) } @@ -457,6 +464,38 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job return job, "", nil } +func (c *Controller) recordDetectedFailure(compact *v1alpha1.CompactBackup, reason, originalReason string) error { + ns := compact.GetNamespace() + name := compact.GetName() + + retryNum := len(compact.Status.BackoffRetryStatus) + 1 + detectFailedAt := metav1.Now() + minDuration, err := time.ParseDuration(compact.Spec.BackoffRetryPolicy.MinRetryDuration) + if err != nil { + klog.Errorf("fail to parse minRetryDuration %s of compact backup %s/%s, %v", compact.Spec.BackoffRetryPolicy.MinRetryDuration, ns, name, err) + return err + } + duration := time.Duration(minDuration.Nanoseconds() << (retryNum - 1)) + expectedRetryAt := metav1.NewTime(detectFailedAt.Add(duration)) + + // update + newStatus := &controller.RetryStatus{ + RetryNum: &retryNum, + DetectFailedAt: &detectFailedAt, + ExpectedRetryAt: &expectedRetryAt, + RetryReason: &reason, + OriginalReason: &originalReason, + } + + klog.Infof("Record backup %s/%s retry status, %v", ns, name, newStatus) + if err := c.statusUpdater.OnRetriableFailed(context.TODO(), compact, newStatus); err != nil { + klog.Errorf("Fail to update the retry status of backup %s/%s, %v", ns, name, err) + return err + } + + return nil +} + func (c *Controller) detectBackupJobFailure(compact *v1alpha1.CompactBackup) ( jobFailed bool, reason string, originalReason string, err error) { var ( @@ -480,7 +519,7 @@ func (c *Controller) detectBackupJobFailure(compact *v1alpha1.CompactBackup) ( klog.Infof("Detect backup %s/%s job failed, will retry, reason %s, original reason %s ", ns, name, reason, originalReason) // record failure when detect failure - err = c.recordDetectedFailure(backup, reason, originalReason) + err = c.recordDetectedFailure(compact, reason, originalReason) if err != nil { klog.Errorf("failed to record detected failed %s for backup %s/%s", reason, ns, name) } From b6e88317cdfd7283e251054045f48d0d19cc60b7 Mon Sep 17 00:00:00 2001 From: RidRisR <79858083+RidRisR@users.noreply.github.com> Date: Wed, 25 Dec 2024 08:56:18 +0100 Subject: [PATCH 41/49] add retry impl --- pkg/controller/compact_status_updater.go | 117 ++++++------- .../compact_backup_controller.go | 154 ++++++++++++++++-- 2 files changed, 184 insertions(+), 87 deletions(-) diff --git a/pkg/controller/compact_status_updater.go b/pkg/controller/compact_status_updater.go index 8576a883b8..5496ae63cd 100644 --- a/pkg/controller/compact_status_updater.go +++ b/pkg/controller/compact_status_updater.go @@ -16,6 +16,7 @@ package controller import ( "context" "fmt" + "reflect" "time" "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1" @@ -34,21 +35,6 @@ const ( progressDebounceDuration = 3 * time.Second ) -type RetryStatus struct { - // RetryNum is the number of retry - RetryNum *int - // DetectFailedAt is the time when detect failure - DetectFailedAt *metav1.Time - // ExpectedRetryAt is the time we calculate and expect retry after it - ExpectedRetryAt *metav1.Time - // RealRetryAt is the time when the retry was actually initiated - RealRetryAt *metav1.Time - // Reason is the reason of retry - RetryReason *string - // OriginalReason is the original reason of backup job or pod failed - OriginalReason *string -} - type Progress struct { // MetaCompleted is the number of meta files compacted MetaCompleted uint64 `json:"meta_completed"` @@ -66,7 +52,7 @@ type CompactStatusUpdaterInterface interface { OnStart(ctx context.Context, compact *v1alpha1.CompactBackup) error OnProgress(ctx context.Context, compact *v1alpha1.CompactBackup, p Progress) error OnFinish(ctx context.Context, compact *v1alpha1.CompactBackup, err error) error - OnRetriableFailed(ctx context.Context, compact *v1alpha1.CompactBackup, retry *RetryStatus) error + OnRetriableFailed(ctx context.Context, compact *v1alpha1.CompactBackup, retry *v1alpha1.BackoffRetryRecord) error } type CompactStatusUpdater struct { @@ -88,15 +74,15 @@ func (r *CompactStatusUpdater) Event(compact *v1alpha1.CompactBackup, ty, reason r.recorder.Event(compact, ty, reason, msg) } -func (r *CompactStatusUpdater) UpdateStatus(compact *v1alpha1.CompactBackup, newState string, progress string, message string) error { +func (r *CompactStatusUpdater) UpdateStatus(compact *v1alpha1.CompactBackup, newStatus v1alpha1.CompactStatus) error { ns := compact.GetNamespace() backupName := compact.GetName() now := time.Now() - updateProgress := true - if progress != "" { + canUpdateProgress := true + if newStatus.Progress != "" { if now.Sub(r.progressLastUpdate) < progressDebounceDuration { - updateProgress = false + canUpdateProgress = false } } @@ -111,56 +97,24 @@ func (r *CompactStatusUpdater) UpdateStatus(compact *v1alpha1.CompactBackup, new } updated := false - if newState != "" && compact.Status.State != newState { - compact.Status.State = newState + if newStatus.State != "" && compact.Status.State != newStatus.State { + compact.Status.State = newStatus.State updated = true - updateProgress = true + canUpdateProgress = true } - if message != "" && compact.Status.Message != message { - compact.Status.Message = message + if newStatus.Message != "" && compact.Status.Message != newStatus.Message { + compact.Status.Message = newStatus.Message updated = true } - if updateProgress && progress != "" && compact.Status.Progress != progress { - compact.Status.Progress = progress + if canUpdateProgress && newStatus.Progress != "" && compact.Status.Progress != newStatus.Progress { + compact.Status.Progress = newStatus.Progress updated = true r.progressLastUpdate = now } - - // Apply the update if any field changed - if updated { - _, updateErr := r.cli.PingcapV1alpha1().CompactBackups(ns).Update(context.TODO(), compact, metav1.UpdateOptions{}) - if updateErr == nil { - klog.Infof("Backup: [%s/%s] updated successfully", ns, backupName) - return nil - } - klog.Errorf("Failed to update backup [%s/%s], error: %v", ns, backupName, updateErr) - return updateErr - } - return nil - }) - return err -} - -func (r *CompactStatusUpdater) UpdateRetryStatus(compact *v1alpha1.CompactBackup, newState string, status *RetryStatus) error { - ns := compact.GetNamespace() - backupName := compact.GetName() - - // Update the status - err := retry.OnError(retry.DefaultRetry, func(e error) bool { return e != nil }, func() error { - // Always get the latest CompactBackup before updating - if updated, err := r.lister.CompactBackups(ns).Get(backupName); err == nil { - *compact = *(updated.DeepCopy()) - } else { - utilruntime.HandleError(fmt.Errorf("error getting updated backup %s/%s from lister: %v", ns, backupName, err)) - return err - } - - updated := false - if newState != "" && compact.Status.State != newState { - compact.Status.State = newState + if newStatus.BackoffRetryStatus != nil && !reflect.DeepEqual(newStatus.BackoffRetryStatus, compact.Status.BackoffRetryStatus) { + compact.Status.BackoffRetryStatus = newStatus.BackoffRetryStatus updated = true } - //TODO: (Ris) update the retry status here // Apply the update if any field changed if updated { @@ -178,38 +132,61 @@ func (r *CompactStatusUpdater) UpdateRetryStatus(compact *v1alpha1.CompactBackup } func (r *CompactStatusUpdater) OnSchedule(ctx context.Context, compact *v1alpha1.CompactBackup) error { - return r.UpdateStatus(compact, string(v1alpha1.BackupScheduled), "", "") + newStatus := v1alpha1.CompactStatus{ + State: string(v1alpha1.BackupScheduled), + } + return r.UpdateStatus(compact, newStatus) } func (r *CompactStatusUpdater) OnCreateJob(ctx context.Context, compact *v1alpha1.CompactBackup, err error) error { + newStatus := v1alpha1.CompactStatus{ + } if err != nil { - return r.UpdateStatus(compact, string(v1alpha1.BackupFailed), "", err.Error()) + newStatus.State = string(v1alpha1.BackupFailed) + newStatus.Message = err.Error() } else { - return r.UpdateStatus(compact, string(v1alpha1.BackupPrepare), "", "") + newStatus.State = string(v1alpha1.BackupRunning) } + return r.UpdateStatus(compact, newStatus) } func (r *CompactStatusUpdater) OnStart(ctx context.Context, compact *v1alpha1.CompactBackup) error { r.Event(compact, corev1.EventTypeNormal, "Started", "The compaction process has started successfully.") - return r.UpdateStatus(compact, string(v1alpha1.BackupRunning), "", "") + + newStauts := v1alpha1.CompactStatus{ + State: string(v1alpha1.BackupRunning), + } + return r.UpdateStatus(compact, newStauts) } func (r *CompactStatusUpdater) OnProgress(ctx context.Context, compact *v1alpha1.CompactBackup, p Progress) error { progress := fmt.Sprintf("[READ_META(%d/%d),COMPACT_WORK(%d/%d)]", p.MetaCompleted, p.MetaTotal, p.BytesCompacted, p.BytesToCompact) - return r.UpdateStatus(compact, "", progress, "") + + newStatus := v1alpha1.CompactStatus{ + Progress: progress, + } + return r.UpdateStatus(compact, newStatus) } func (r *CompactStatusUpdater) OnFinish(ctx context.Context, compact *v1alpha1.CompactBackup, err error) error { + newStatus := v1alpha1.CompactStatus{ + } if err != nil { + newStatus.State = string(v1alpha1.BackupFailed) + newStatus.Message = err.Error() r.Event(compact, corev1.EventTypeWarning, "Failed", err.Error()) - return r.UpdateStatus(compact, string(v1alpha1.BackupFailed), "", err.Error()) } else { + newStatus.State = string(v1alpha1.BackupComplete) r.Event(compact, corev1.EventTypeNormal, "Finished", "The compaction process has finished successfully.") - return r.UpdateStatus(compact, string(v1alpha1.BackupComplete), "", "") } + return r.UpdateStatus(compact, newStatus) } -func (r *CompactStatusUpdater) OnRetriableFailed(ctx context.Context, compact *v1alpha1.CompactBackup, retry *RetryStatus) error { - return r.UpdateRetryStatus(compact, string(v1alpha1.BackupRetryTheFailed), retry) +func (r *CompactStatusUpdater) OnRetriableFailed(ctx context.Context, compact *v1alpha1.CompactBackup, retry *v1alpha1.BackoffRetryRecord) error { + newStatus := v1alpha1.CompactStatus{ + BackoffRetryStatus: append(compact.Status.BackoffRetryStatus, *retry), + } + r.Event(compact, corev1.EventTypeWarning, "RetryableFailed", retry.OriginalReason) + return r.UpdateStatus(compact, newStatus) } diff --git a/pkg/controller/compactbackup/compact_backup_controller.go b/pkg/controller/compactbackup/compact_backup_controller.go index 7181cca5c9..f7a82e8597 100644 --- a/pkg/controller/compactbackup/compact_backup_controller.go +++ b/pkg/controller/compactbackup/compact_backup_controller.go @@ -259,21 +259,18 @@ func (c *Controller) sync(key string) (err error) { return nil } - if compact.Status.State == string(v1alpha1.BackupRunning) { - jobFailed, reason, originalReason, err := c.detectBackupJobFailure(compact) - if err != nil { - klog.Errorf("Fail to detect backup %s/%s running status, error %v", ns, name, err) - return nil - } + jobFailed, reason, originalReason, err := c.detectBackupJobFailure(compact) + if err != nil { + klog.Errorf("Fail to detect backup %s/%s running status, error %v", ns, name, err) + return nil + } - if jobFailed { - // retry backup after detect failure - //TODO: (Ris)impl this - if err := c.retryAfterFailureDetected(compact, reason, originalReason); err != nil { - klog.Errorf("Fail to restart snapshot backup %s/%s, error %v", ns, name, err) - } - return nil + if jobFailed { + // retry backup after detect failure + if err := c.retryAfterFailureDetected(compact, reason, originalReason); err != nil { + klog.Errorf("Fail to restart snapshot backup %s/%s, error %v", ns, name, err) } + return nil } c.statusUpdater.OnSchedule(context.TODO(), compact) @@ -479,12 +476,12 @@ func (c *Controller) recordDetectedFailure(compact *v1alpha1.CompactBackup, reas expectedRetryAt := metav1.NewTime(detectFailedAt.Add(duration)) // update - newStatus := &controller.RetryStatus{ - RetryNum: &retryNum, + newStatus := &v1alpha1.BackoffRetryRecord{ + RetryNum: retryNum, DetectFailedAt: &detectFailedAt, ExpectedRetryAt: &expectedRetryAt, - RetryReason: &reason, - OriginalReason: &originalReason, + RetryReason: reason, + OriginalReason: originalReason, } klog.Infof("Record backup %s/%s retry status, %v", ns, name, newStatus) @@ -525,3 +522,126 @@ func (c *Controller) detectBackupJobFailure(compact *v1alpha1.CompactBackup) ( } return jobFailed, reason, originalReason, nil } + +func (c *Controller) retryAfterFailureDetected(compact *v1alpha1.CompactBackup, reason, originalReason string) error { + var ( + ns = compact.GetNamespace() + name = compact.GetName() + err error + ) + + // retry snapshot backup according to backoff policy + err = c.retrySnapshotBackupAccordingToBackoffPolicy(compact) + if err != nil { + klog.Errorf("Fail to retry compact job %s/%s according to backoff policy , %v", ns, name, err) + return err + } + klog.Infof("Retry compact job %s/%s according to backoff policy", ns, name) + return nil +} + +// retrySnapshotBackupAccordingToBackoffPolicy retry snapshot backup according to spec.backoffRetryPolicy. +// the main logic is reentrant: +// 1. check whether is retrying which is marked as BackupRetryFailed, +// if true, clean job and mark RealRetryAt which means current retry is done. +// 2. check whether is retry done, skip. +// 3. check whether exceed retry limit, if true, mark as failed. +// 4. check whether exceed the retry interval which is recorded as ExpectedRetryAt, +// the value is the time detect failure + MinRetryDuration << (retry num -1), +// if true, mark as BackupRetryFailed, if not, wait to next loop. +// 5. after mark as BackupRetryFailed, the logic will back to 1 in next loop. +func (c *Controller) retrySnapshotBackupAccordingToBackoffPolicy(compact *v1alpha1.CompactBackup) error { + if len(compact.Status.BackoffRetryStatus) == 0 { + return nil + } + var ( + ns = compact.GetNamespace() + name = compact.GetName() + now = time.Now() + err error + failedReason string + retryRecord = compact.Status.BackoffRetryStatus[len(compact.Status.BackoffRetryStatus)-1] + ) + klog.V(4).Infof("retry backup %s/%s, retry reason %s, original reason %s", ns, name, retryRecord.RetryReason, retryRecord.OriginalReason) + + // check retrying + if isBackoffRetrying(compact) { + return c.doRetryFailedBackup(compact) + } + + // check retry done + if isCurrentBackoffRetryDone(compact) { + return nil + } + + // check is exceed retry limit + isExceedRetryTimes := isExceedRetryTimes(compact) + if isExceedRetryTimes { + failedReason = fmt.Sprintf("exceed retry times, max is %d, failed reason %s, original reason %s", backup.Spec.BackoffRetryPolicy.MaxRetryTimes, retryRecord.RetryReason, retryRecord.OriginalReason) + } + isRetryTimeout, err := isRetryTimeout(compact, &now) + if err != nil { + klog.Errorf("fail to check whether the retry is timeout, backup is %s/%s, %v", ns, name, err) + return err + } + if isRetryTimeout { + failedReason = fmt.Sprintf("retry timeout, max is %s, failed reason %s, original reason %s", backup.Spec.BackoffRetryPolicy.RetryTimeout, retryRecord.RetryReason, retryRecord.OriginalReason) + } + + if isExceedRetryTimes || isRetryTimeout { + klog.Infof("backup %s/%s exceed retry limit, failed reason %s", ns, name, failedReason) + err = c.control.UpdateStatus(backup, &v1alpha1.BackupCondition{ + Type: v1alpha1.BackupFailed, + Status: corev1.ConditionTrue, + Reason: "AlreadyFailed", + Message: failedReason, + }, nil) + if err != nil { + klog.Errorf("Fail to update the condition of backup %s/%s, %v", ns, name, err) + return err + } + return nil + } + + // check is time to retry + if !isTimeToRetry(backup, &now) { + klog.V(4).Infof("backup %s/%s is not the time to retry, expected retry time is %s, now is %s", ns, name, retryRecord.ExpectedRetryAt, now) + return nil + } + + klog.V(4).Infof("backup %s/%s is the time to retry, expected retry time is %s, now is %s", ns, name, retryRecord.ExpectedRetryAt, now) + + // update retry status + err = c.control.UpdateStatus(backup, &v1alpha1.BackupCondition{ + Type: v1alpha1.BackupRetryTheFailed, + Status: corev1.ConditionTrue, + Reason: "RetryFailedBackup", + Message: fmt.Sprintf("reason %s, original reason %s", retryRecord.RetryReason, retryRecord.OriginalReason), + }, nil) + if err != nil { + klog.Errorf("Fail to update the retry status of backup %s/%s, %v", ns, name, err) + return err + } + + return nil +} + +func isBackoffRetrying(backup *v1alpha1.Backup) bool { + if backup.Spec.Mode != v1alpha1.BackupModeSnapshot { + return false + } + if len(backup.Status.BackoffRetryStatus) == 0 { + return false + } + return backup.Status.Phase == v1alpha1.BackupRetryTheFailed +} + +func isCurrentBackoffRetryDone(backup *v1alpha1.Backup) bool { + if backup.Spec.Mode != v1alpha1.BackupModeSnapshot { + return false + } + if len(backup.Status.BackoffRetryStatus) == 0 { + return false + } + return backup.Status.BackoffRetryStatus[len(backup.Status.BackoffRetryStatus)-1].RealRetryAt != nil +} From d4d8a86a4abdf0c051019c7f467e79ef9cedf14e Mon Sep 17 00:00:00 2001 From: RidRisR <79858083+RidRisR@users.noreply.github.com> Date: Wed, 25 Dec 2024 09:57:00 +0100 Subject: [PATCH 42/49] add helper functions --- .../compact_backup_controller.go | 84 +++++++++++++++++-- 1 file changed, 75 insertions(+), 9 deletions(-) diff --git a/pkg/controller/compactbackup/compact_backup_controller.go b/pkg/controller/compactbackup/compact_backup_controller.go index f7a82e8597..f3c3b13c83 100644 --- a/pkg/controller/compactbackup/compact_backup_controller.go +++ b/pkg/controller/compactbackup/compact_backup_controller.go @@ -577,7 +577,7 @@ func (c *Controller) retrySnapshotBackupAccordingToBackoffPolicy(compact *v1alph // check is exceed retry limit isExceedRetryTimes := isExceedRetryTimes(compact) if isExceedRetryTimes { - failedReason = fmt.Sprintf("exceed retry times, max is %d, failed reason %s, original reason %s", backup.Spec.BackoffRetryPolicy.MaxRetryTimes, retryRecord.RetryReason, retryRecord.OriginalReason) + failedReason = fmt.Sprintf("exceed retry times, max is %d, failed reason %s, original reason %s", compact.Spec.BackoffRetryPolicy.MaxRetryTimes, retryRecord.RetryReason, retryRecord.OriginalReason) } isRetryTimeout, err := isRetryTimeout(compact, &now) if err != nil { @@ -626,22 +626,88 @@ func (c *Controller) retrySnapshotBackupAccordingToBackoffPolicy(compact *v1alph return nil } -func isBackoffRetrying(backup *v1alpha1.Backup) bool { - if backup.Spec.Mode != v1alpha1.BackupModeSnapshot { +func (c *Controller) doRetryFailedBackup(compact *v1alpha1.CompactBackup) error { + ns := compact.GetNamespace() + name := compact.GetName() + klog.V(4).Infof("backup %s/%s is retrying after it has been scheduled", ns, name) + + // retry done + if isCurrentBackoffRetryDone(compact) { + // clean job is asynchronous, we need enqueue again, + // the backup status will be scheduled after create new job, and then this reconcile is really done. + c.enqueueBackup(compact) + return nil + } + + // clean job + err := c.cleanBackupOldJobIfExist(backup) + if err != nil { + klog.Errorf("Fail to clean job of backup %s/%s, error is %v", ns, name, err) + return err + } + + // retry done, mark RealRetryAt + RealRetryStatus := &controller.BackupUpdateStatus{ + RealRetryAt: &metav1.Time{Time: time.Now()}, + } + + // add restart condition to clean data before run br command + err = c.control.UpdateStatus(backup, &v1alpha1.BackupCondition{ + Type: v1alpha1.BackupRestart, + Status: corev1.ConditionTrue, + }, RealRetryStatus) + if err != nil { + klog.Errorf("Fail to update the condition of backup %s/%s, %v", ns, name, err) + return err + } + + c.enqueueBackup(compact) + return nil +} + +func isBackoffRetrying(compact *v1alpha1.CompactBackup) bool { + if len(compact.Status.BackoffRetryStatus) == 0 { return false } - if len(backup.Status.BackoffRetryStatus) == 0 { + return compact.Status.State == string(v1alpha1.BackupRetryTheFailed) +} + +func isCurrentBackoffRetryDone(compact *v1alpha1.CompactBackup) bool { + if len(compact.Status.BackoffRetryStatus) == 0 { return false } - return backup.Status.Phase == v1alpha1.BackupRetryTheFailed + return compact.Status.BackoffRetryStatus[len(compact.Status.BackoffRetryStatus)-1].RealRetryAt != nil } -func isCurrentBackoffRetryDone(backup *v1alpha1.Backup) bool { - if backup.Spec.Mode != v1alpha1.BackupModeSnapshot { +func isExceedRetryTimes(compact *v1alpha1.CompactBackup) bool { + records := compact.Status.BackoffRetryStatus + if len(records) == 0 { return false } - if len(backup.Status.BackoffRetryStatus) == 0 { + + currentRetryNum := records[len(records)-1].RetryNum + return currentRetryNum > compact.Spec.BackoffRetryPolicy.MaxRetryTimes +} + +func isRetryTimeout(compact *v1alpha1.CompactBackup, now *time.Time) (bool, error) { + records := compact.Status.BackoffRetryStatus + if len(records) == 0 { + return false, nil + } + firstDetectAt := records[0].DetectFailedAt + retryTimeout, err := time.ParseDuration(compact.Spec.BackoffRetryPolicy.RetryTimeout) + if err != nil { + klog.Errorf("fail to parse retryTimeout %s of backup %s/%s, %v", compact.Spec.BackoffRetryPolicy.RetryTimeout, compact.Namespace, compact.Name, err) + return false, err + } + return now.Unix()-firstDetectAt.Unix() > int64(retryTimeout)/int64(time.Second), nil +} + +func isTimeToRetry(compact *v1alpha1.CompactBackup, now *time.Time) bool { + if len(compact.Status.BackoffRetryStatus) == 0 { return false } - return backup.Status.BackoffRetryStatus[len(backup.Status.BackoffRetryStatus)-1].RealRetryAt != nil + retryRecord := compact.Status.BackoffRetryStatus[len(compact.Status.BackoffRetryStatus)-1] + return time.Now().Unix() > retryRecord.ExpectedRetryAt.Unix() + } From 26bf6ed122c5bba0b9e0a1c496f5fc75a4fdd845 Mon Sep 17 00:00:00 2001 From: RidRisR <79858083+RidRisR@users.noreply.github.com> Date: Wed, 25 Dec 2024 10:41:19 +0100 Subject: [PATCH 43/49] revert backoff logic --- .../compact_backup_controller.go | 265 +----------------- 1 file changed, 1 insertion(+), 264 deletions(-) diff --git a/pkg/controller/compactbackup/compact_backup_controller.go b/pkg/controller/compactbackup/compact_backup_controller.go index f3c3b13c83..2523656869 100644 --- a/pkg/controller/compactbackup/compact_backup_controller.go +++ b/pkg/controller/compactbackup/compact_backup_controller.go @@ -259,19 +259,7 @@ func (c *Controller) sync(key string) (err error) { return nil } - jobFailed, reason, originalReason, err := c.detectBackupJobFailure(compact) - if err != nil { - klog.Errorf("Fail to detect backup %s/%s running status, error %v", ns, name, err) - return nil - } - - if jobFailed { - // retry backup after detect failure - if err := c.retryAfterFailureDetected(compact, reason, originalReason); err != nil { - klog.Errorf("Fail to restart snapshot backup %s/%s, error %v", ns, name, err) - } - return nil - } + //TODO:(ris)add retry logic c.statusUpdater.OnSchedule(context.TODO(), compact) @@ -460,254 +448,3 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job return job, "", nil } - -func (c *Controller) recordDetectedFailure(compact *v1alpha1.CompactBackup, reason, originalReason string) error { - ns := compact.GetNamespace() - name := compact.GetName() - - retryNum := len(compact.Status.BackoffRetryStatus) + 1 - detectFailedAt := metav1.Now() - minDuration, err := time.ParseDuration(compact.Spec.BackoffRetryPolicy.MinRetryDuration) - if err != nil { - klog.Errorf("fail to parse minRetryDuration %s of compact backup %s/%s, %v", compact.Spec.BackoffRetryPolicy.MinRetryDuration, ns, name, err) - return err - } - duration := time.Duration(minDuration.Nanoseconds() << (retryNum - 1)) - expectedRetryAt := metav1.NewTime(detectFailedAt.Add(duration)) - - // update - newStatus := &v1alpha1.BackoffRetryRecord{ - RetryNum: retryNum, - DetectFailedAt: &detectFailedAt, - ExpectedRetryAt: &expectedRetryAt, - RetryReason: reason, - OriginalReason: originalReason, - } - - klog.Infof("Record backup %s/%s retry status, %v", ns, name, newStatus) - if err := c.statusUpdater.OnRetriableFailed(context.TODO(), compact, newStatus); err != nil { - klog.Errorf("Fail to update the retry status of backup %s/%s, %v", ns, name, err) - return err - } - - return nil -} - -func (c *Controller) detectBackupJobFailure(compact *v1alpha1.CompactBackup) ( - jobFailed bool, reason string, originalReason string, err error) { - var ( - ns = compact.GetNamespace() - name = compact.GetName() - ) - job, err := c.deps.JobLister.Jobs(ns).Get(name) - if err != nil && !errors.IsNotFound(err) { - klog.Errorf("Fail to get job %s for backup %s/%s, error %v ", name, ns, name, err) - return false, "", "", err - } - if job != nil { - for _, condition := range job.Status.Conditions { - if condition.Type == batchv1.JobFailed && condition.Status == corev1.ConditionTrue { - reason = fmt.Sprintf("Job %s has failed", name) - originalReason = condition.Reason - return true, reason, originalReason, nil - } - } - } - - klog.Infof("Detect backup %s/%s job failed, will retry, reason %s, original reason %s ", ns, name, reason, originalReason) - // record failure when detect failure - err = c.recordDetectedFailure(compact, reason, originalReason) - if err != nil { - klog.Errorf("failed to record detected failed %s for backup %s/%s", reason, ns, name) - } - return jobFailed, reason, originalReason, nil -} - -func (c *Controller) retryAfterFailureDetected(compact *v1alpha1.CompactBackup, reason, originalReason string) error { - var ( - ns = compact.GetNamespace() - name = compact.GetName() - err error - ) - - // retry snapshot backup according to backoff policy - err = c.retrySnapshotBackupAccordingToBackoffPolicy(compact) - if err != nil { - klog.Errorf("Fail to retry compact job %s/%s according to backoff policy , %v", ns, name, err) - return err - } - klog.Infof("Retry compact job %s/%s according to backoff policy", ns, name) - return nil -} - -// retrySnapshotBackupAccordingToBackoffPolicy retry snapshot backup according to spec.backoffRetryPolicy. -// the main logic is reentrant: -// 1. check whether is retrying which is marked as BackupRetryFailed, -// if true, clean job and mark RealRetryAt which means current retry is done. -// 2. check whether is retry done, skip. -// 3. check whether exceed retry limit, if true, mark as failed. -// 4. check whether exceed the retry interval which is recorded as ExpectedRetryAt, -// the value is the time detect failure + MinRetryDuration << (retry num -1), -// if true, mark as BackupRetryFailed, if not, wait to next loop. -// 5. after mark as BackupRetryFailed, the logic will back to 1 in next loop. -func (c *Controller) retrySnapshotBackupAccordingToBackoffPolicy(compact *v1alpha1.CompactBackup) error { - if len(compact.Status.BackoffRetryStatus) == 0 { - return nil - } - var ( - ns = compact.GetNamespace() - name = compact.GetName() - now = time.Now() - err error - failedReason string - retryRecord = compact.Status.BackoffRetryStatus[len(compact.Status.BackoffRetryStatus)-1] - ) - klog.V(4).Infof("retry backup %s/%s, retry reason %s, original reason %s", ns, name, retryRecord.RetryReason, retryRecord.OriginalReason) - - // check retrying - if isBackoffRetrying(compact) { - return c.doRetryFailedBackup(compact) - } - - // check retry done - if isCurrentBackoffRetryDone(compact) { - return nil - } - - // check is exceed retry limit - isExceedRetryTimes := isExceedRetryTimes(compact) - if isExceedRetryTimes { - failedReason = fmt.Sprintf("exceed retry times, max is %d, failed reason %s, original reason %s", compact.Spec.BackoffRetryPolicy.MaxRetryTimes, retryRecord.RetryReason, retryRecord.OriginalReason) - } - isRetryTimeout, err := isRetryTimeout(compact, &now) - if err != nil { - klog.Errorf("fail to check whether the retry is timeout, backup is %s/%s, %v", ns, name, err) - return err - } - if isRetryTimeout { - failedReason = fmt.Sprintf("retry timeout, max is %s, failed reason %s, original reason %s", backup.Spec.BackoffRetryPolicy.RetryTimeout, retryRecord.RetryReason, retryRecord.OriginalReason) - } - - if isExceedRetryTimes || isRetryTimeout { - klog.Infof("backup %s/%s exceed retry limit, failed reason %s", ns, name, failedReason) - err = c.control.UpdateStatus(backup, &v1alpha1.BackupCondition{ - Type: v1alpha1.BackupFailed, - Status: corev1.ConditionTrue, - Reason: "AlreadyFailed", - Message: failedReason, - }, nil) - if err != nil { - klog.Errorf("Fail to update the condition of backup %s/%s, %v", ns, name, err) - return err - } - return nil - } - - // check is time to retry - if !isTimeToRetry(backup, &now) { - klog.V(4).Infof("backup %s/%s is not the time to retry, expected retry time is %s, now is %s", ns, name, retryRecord.ExpectedRetryAt, now) - return nil - } - - klog.V(4).Infof("backup %s/%s is the time to retry, expected retry time is %s, now is %s", ns, name, retryRecord.ExpectedRetryAt, now) - - // update retry status - err = c.control.UpdateStatus(backup, &v1alpha1.BackupCondition{ - Type: v1alpha1.BackupRetryTheFailed, - Status: corev1.ConditionTrue, - Reason: "RetryFailedBackup", - Message: fmt.Sprintf("reason %s, original reason %s", retryRecord.RetryReason, retryRecord.OriginalReason), - }, nil) - if err != nil { - klog.Errorf("Fail to update the retry status of backup %s/%s, %v", ns, name, err) - return err - } - - return nil -} - -func (c *Controller) doRetryFailedBackup(compact *v1alpha1.CompactBackup) error { - ns := compact.GetNamespace() - name := compact.GetName() - klog.V(4).Infof("backup %s/%s is retrying after it has been scheduled", ns, name) - - // retry done - if isCurrentBackoffRetryDone(compact) { - // clean job is asynchronous, we need enqueue again, - // the backup status will be scheduled after create new job, and then this reconcile is really done. - c.enqueueBackup(compact) - return nil - } - - // clean job - err := c.cleanBackupOldJobIfExist(backup) - if err != nil { - klog.Errorf("Fail to clean job of backup %s/%s, error is %v", ns, name, err) - return err - } - - // retry done, mark RealRetryAt - RealRetryStatus := &controller.BackupUpdateStatus{ - RealRetryAt: &metav1.Time{Time: time.Now()}, - } - - // add restart condition to clean data before run br command - err = c.control.UpdateStatus(backup, &v1alpha1.BackupCondition{ - Type: v1alpha1.BackupRestart, - Status: corev1.ConditionTrue, - }, RealRetryStatus) - if err != nil { - klog.Errorf("Fail to update the condition of backup %s/%s, %v", ns, name, err) - return err - } - - c.enqueueBackup(compact) - return nil -} - -func isBackoffRetrying(compact *v1alpha1.CompactBackup) bool { - if len(compact.Status.BackoffRetryStatus) == 0 { - return false - } - return compact.Status.State == string(v1alpha1.BackupRetryTheFailed) -} - -func isCurrentBackoffRetryDone(compact *v1alpha1.CompactBackup) bool { - if len(compact.Status.BackoffRetryStatus) == 0 { - return false - } - return compact.Status.BackoffRetryStatus[len(compact.Status.BackoffRetryStatus)-1].RealRetryAt != nil -} - -func isExceedRetryTimes(compact *v1alpha1.CompactBackup) bool { - records := compact.Status.BackoffRetryStatus - if len(records) == 0 { - return false - } - - currentRetryNum := records[len(records)-1].RetryNum - return currentRetryNum > compact.Spec.BackoffRetryPolicy.MaxRetryTimes -} - -func isRetryTimeout(compact *v1alpha1.CompactBackup, now *time.Time) (bool, error) { - records := compact.Status.BackoffRetryStatus - if len(records) == 0 { - return false, nil - } - firstDetectAt := records[0].DetectFailedAt - retryTimeout, err := time.ParseDuration(compact.Spec.BackoffRetryPolicy.RetryTimeout) - if err != nil { - klog.Errorf("fail to parse retryTimeout %s of backup %s/%s, %v", compact.Spec.BackoffRetryPolicy.RetryTimeout, compact.Namespace, compact.Name, err) - return false, err - } - return now.Unix()-firstDetectAt.Unix() > int64(retryTimeout)/int64(time.Second), nil -} - -func isTimeToRetry(compact *v1alpha1.CompactBackup, now *time.Time) bool { - if len(compact.Status.BackoffRetryStatus) == 0 { - return false - } - retryRecord := compact.Status.BackoffRetryStatus[len(compact.Status.BackoffRetryStatus)-1] - return time.Now().Unix() > retryRecord.ExpectedRetryAt.Unix() - -} From 482609331a9db3d7db678b75016ed62e636fdc13 Mon Sep 17 00:00:00 2001 From: RidRisR <79858083+RidRisR@users.noreply.github.com> Date: Thu, 26 Dec 2024 08:59:49 +0100 Subject: [PATCH 44/49] add skip for already running job --- pkg/apis/pingcap/v1alpha1/types.go | 5 +- pkg/controller/compact_status_updater.go | 13 +- .../compact_backup_controller.go | 151 ++++++++++++------ 3 files changed, 105 insertions(+), 64 deletions(-) diff --git a/pkg/apis/pingcap/v1alpha1/types.go b/pkg/apis/pingcap/v1alpha1/types.go index 2a264ea18b..48b91a5e35 100644 --- a/pkg/apis/pingcap/v1alpha1/types.go +++ b/pkg/apis/pingcap/v1alpha1/types.go @@ -3527,7 +3527,8 @@ type CompactSpec struct { PriorityClassName string `json:"priorityClassName,omitempty"` // BackoffRetryPolicy the backoff retry policy, currently only valid for snapshot backup - BackoffRetryPolicy BackoffRetryPolicy `json:"backoffRetryPolicy,omitempty"` + // +default=2 + MaxRetryTimes int32 `json:"maxRetryTimes,omitempty"` // Additional volumes of component pod. // +optional @@ -3544,8 +3545,6 @@ type CompactStatus struct { Progress string `json:"progress,omitempty"` // Message is the error message of the backup Message string `json:"message,omitempty"` - // BackoffRetryStatus is status of the backoff retry, it will be used when backup pod or job exited unexpectedly - BackoffRetryStatus []BackoffRetryRecord `json:"backoffRetryStatus,omitempty"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/controller/compact_status_updater.go b/pkg/controller/compact_status_updater.go index 5496ae63cd..bd7b6d2d39 100644 --- a/pkg/controller/compact_status_updater.go +++ b/pkg/controller/compact_status_updater.go @@ -16,7 +16,6 @@ package controller import ( "context" "fmt" - "reflect" "time" "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1" @@ -52,7 +51,7 @@ type CompactStatusUpdaterInterface interface { OnStart(ctx context.Context, compact *v1alpha1.CompactBackup) error OnProgress(ctx context.Context, compact *v1alpha1.CompactBackup, p Progress) error OnFinish(ctx context.Context, compact *v1alpha1.CompactBackup, err error) error - OnRetriableFailed(ctx context.Context, compact *v1alpha1.CompactBackup, retry *v1alpha1.BackoffRetryRecord) error + OnJobFailed(ctx context.Context, compact *v1alpha1.CompactBackup, reason string) error } type CompactStatusUpdater struct { @@ -111,10 +110,6 @@ func (r *CompactStatusUpdater) UpdateStatus(compact *v1alpha1.CompactBackup, new updated = true r.progressLastUpdate = now } - if newStatus.BackoffRetryStatus != nil && !reflect.DeepEqual(newStatus.BackoffRetryStatus, compact.Status.BackoffRetryStatus) { - compact.Status.BackoffRetryStatus = newStatus.BackoffRetryStatus - updated = true - } // Apply the update if any field changed if updated { @@ -183,10 +178,10 @@ func (r *CompactStatusUpdater) OnFinish(ctx context.Context, compact *v1alpha1.C return r.UpdateStatus(compact, newStatus) } -func (r *CompactStatusUpdater) OnRetriableFailed(ctx context.Context, compact *v1alpha1.CompactBackup, retry *v1alpha1.BackoffRetryRecord) error { +func (r *CompactStatusUpdater) OnJobFailed(ctx context.Context, compact *v1alpha1.CompactBackup, reason string) error { newStatus := v1alpha1.CompactStatus{ - BackoffRetryStatus: append(compact.Status.BackoffRetryStatus, *retry), + State: string(v1alpha1.BackupFailed), } - r.Event(compact, corev1.EventTypeWarning, "RetryableFailed", retry.OriginalReason) + r.Event(compact, corev1.EventTypeWarning, "The compact job is failed.", reason) return r.UpdateStatus(compact, newStatus) } diff --git a/pkg/controller/compactbackup/compact_backup_controller.go b/pkg/controller/compactbackup/compact_backup_controller.go index 2523656869..0d44be9949 100644 --- a/pkg/controller/compactbackup/compact_backup_controller.go +++ b/pkg/controller/compactbackup/compact_backup_controller.go @@ -38,7 +38,7 @@ import ( "k8s.io/client-go/util/retry" "k8s.io/client-go/util/workqueue" "k8s.io/klog" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" ) // Controller controls backup. @@ -64,11 +64,11 @@ func NewController(deps *controller.Dependencies) *Controller { backupInformer := deps.InformerFactory.Pingcap().V1alpha1().CompactBackups() jobInformer := deps.KubeInformerFactory.Batch().V1().Jobs() backupInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ - AddFunc: c.updateBackup, + AddFunc: c.updateCompact, UpdateFunc: func(old, cur interface{}) { - c.updateBackup(cur) + c.updateCompact(cur) }, - DeleteFunc: c.updateBackup, + DeleteFunc: c.updateCompact, }) jobInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ DeleteFunc: c.deleteJob, @@ -167,14 +167,24 @@ func (c *Controller) deleteJob(obj interface{}) { return } klog.V(4).Infof("Job %s/%s deleted through %v.", ns, jobName, utilruntime.GetCaller()) - c.updateBackup(backup) + c.updateCompact(backup) } -func (c *Controller) updateBackup(cur interface{}) { +func (c *Controller) updateCompact(cur interface{}) { newBackup := cur.(*v1alpha1.CompactBackup) ns := newBackup.GetNamespace() name := newBackup.GetName() + if newBackup.Status.State == string(v1alpha1.BackupFailed){ + klog.Errorf("Backup %s/%s is failed, skip", ns, name) + return + } + + if newBackup.Status.State == string(v1alpha1.BackupComplete){ + klog.Errorf("Backup %s/%s is complete, skip", ns, name) + return + } + klog.Infof("backup object %s/%s enqueue", ns, name) c.enqueueBackup(newBackup) } @@ -249,18 +259,15 @@ func (c *Controller) sync(key string) (err error) { return err } - if compact.Status.State == string(v1alpha1.BackupFailed){ - klog.Errorf("Backup %s/%s is failed, skip", ns, name) - return nil + running,err := c.isCompactJobAlreadyRunning(compact) + if err != nil { + return err } - - if compact.Status.State == string(v1alpha1.BackupScheduled) { - klog.Infof("Backup %s/%s is scheduled, skip", ns, name) + if running { + klog.Infof("Backup %s/%s is running, skip", ns, name) return nil } - //TODO:(ris)add retry logic - c.statusUpdater.OnSchedule(context.TODO(), compact) err = c.doCompact(compact.DeepCopy()) @@ -270,34 +277,34 @@ func (c *Controller) sync(key string) (err error) { return err } -func (c *Controller) doCompact(backup *v1alpha1.CompactBackup) error { - ns := backup.GetNamespace() - name := backup.GetName() - backupJobName := backup.GetName() +func (c *Controller) doCompact(compact *v1alpha1.CompactBackup) error { + ns := compact.GetNamespace() + name := compact.GetName() + backupJobName := compact.GetName() // make backup job var err error var job *batchv1.Job var reason string - if job, reason, err = c.makeBackupJob(backup); err != nil { + if job, reason, err = c.makeCompactJob(compact); err != nil { klog.Errorf("backup %s/%s create job %s failed, reason is %s, error %v.", ns, name, backupJobName, reason, err) return err } // create k8s job klog.Infof("backup %s/%s creating job %s.", ns, name, backupJobName) - if err := c.deps.JobControl.CreateJob(backup, job); err != nil { + if err := c.deps.JobControl.CreateJob(compact, job); err != nil { errMsg := fmt.Errorf("create backup %s/%s job %s failed, err: %v", ns, name, backupJobName, err) return errMsg } return nil } -func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job, string, error) { - ns := backup.GetNamespace() - name := backup.GetName() +func (c *Controller) makeCompactJob(compact *v1alpha1.CompactBackup) (*batchv1.Job, string, error) { + ns := compact.GetNamespace() + name := compact.GetName() // Do we need a unique name for the job? - jobName := backup.GetName() + jobName := compact.GetName() var ( envVars []corev1.EnvVar @@ -305,7 +312,7 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job err error ) - storageEnv, reason, err := backuputil.GenerateStorageCertEnv(ns, backup.Spec.UseKMS, backup.Spec.StorageProvider, c.deps.SecretLister) + storageEnv, reason, err := backuputil.GenerateStorageCertEnv(ns, compact.Spec.UseKMS, compact.Spec.StorageProvider, c.deps.SecretLister) if err != nil { return nil, reason, fmt.Errorf("backup %s/%s, %v", ns, name, err) } @@ -313,7 +320,7 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job envVars = append(envVars, storageEnv...) // set env vars specified in backup.Spec.Env - envVars = util.AppendOverwriteEnv(envVars, backup.Spec.Env) + envVars = util.AppendOverwriteEnv(envVars, compact.Spec.Env) args := []string{ "compact", @@ -321,16 +328,16 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job fmt.Sprintf("--resourceName=%s", name), } - tc, err := c.deps.TiDBClusterLister.TidbClusters(backup.Spec.BR.ClusterNamespace).Get(backup.Spec.BR.Cluster) + tc, err := c.deps.TiDBClusterLister.TidbClusters(compact.Spec.BR.ClusterNamespace).Get(compact.Spec.BR.Cluster) if err != nil { - return nil, fmt.Sprintf("failed to fetch tidbcluster %s/%s", ns, backup.Spec.BR.Cluster), err + return nil, fmt.Sprintf("failed to fetch tidbcluster %s/%s", ns, compact.Spec.BR.Cluster), err } tikvImage := tc.TiKVImage() _, tikvVersion := backuputil.ParseImage(tikvImage) brImage := "pingcap/br:" + tikvVersion - if backup.Spec.ToolImage != "" { - toolImage := backup.Spec.ToolImage - if !strings.ContainsRune(backup.Spec.ToolImage, ':') { + if compact.Spec.ToolImage != "" { + toolImage := compact.Spec.ToolImage + if !strings.ContainsRune(compact.Spec.ToolImage, ':') { toolImage = fmt.Sprintf("%s:%s", toolImage, tikvVersion) } @@ -339,9 +346,9 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job klog.Infof("backup %s/%s use br image %s and tikv image %s", ns, name, brImage, tikvImage) //TODO: (Ris)What is the instance here? - jobLabels := util.CombineStringMap(label.NewBackup().Instance("Compact-Backup").BackupJob().Backup(name), backup.Labels) + jobLabels := util.CombineStringMap(label.NewBackup().Instance("Compact-Backup").BackupJob().Backup(name), compact.Labels) podLabels := jobLabels - jobAnnotations := backup.Annotations + jobAnnotations := compact.Annotations podAnnotations := jobAnnotations volumeMounts := []corev1.VolumeMount{} @@ -365,22 +372,22 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job }, ) - if len(backup.Spec.AdditionalVolumes) > 0 { - volumes = append(volumes, backup.Spec.AdditionalVolumes...) + if len(compact.Spec.AdditionalVolumes) > 0 { + volumes = append(volumes, compact.Spec.AdditionalVolumes...) } - if len(backup.Spec.AdditionalVolumeMounts) > 0 { - volumeMounts = append(volumeMounts, backup.Spec.AdditionalVolumeMounts...) + if len(compact.Spec.AdditionalVolumeMounts) > 0 { + volumeMounts = append(volumeMounts, compact.Spec.AdditionalVolumeMounts...) } // mount volumes if specified - if backup.Spec.Local != nil { - volumes = append(volumes, backup.Spec.Local.Volume) - volumeMounts = append(volumeMounts, backup.Spec.Local.VolumeMount) + if compact.Spec.Local != nil { + volumes = append(volumes, compact.Spec.Local.Volume) + volumeMounts = append(volumeMounts, compact.Spec.Local.VolumeMount) } serviceAccount := constants.DefaultServiceAccountName - if backup.Spec.ServiceAccount != "" { - serviceAccount = backup.Spec.ServiceAccount + if compact.Spec.ServiceAccount != "" { + serviceAccount = compact.Spec.ServiceAccount } podSpec := &corev1.PodTemplateSpec{ @@ -389,7 +396,7 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job Annotations: podAnnotations, }, Spec: corev1.PodSpec{ - SecurityContext: backup.Spec.PodSecurityContext, + SecurityContext: compact.Spec.PodSecurityContext, ServiceAccountName: serviceAccount, InitContainers: []corev1.Container{ { @@ -399,7 +406,7 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job Args: []string{fmt.Sprintf("cp /br %s/br; echo 'BR copy finished'", util.BRBinPath)}, ImagePullPolicy: corev1.PullIfNotPresent, VolumeMounts: volumeMounts, - Resources: backup.Spec.ResourceRequirements, + Resources: compact.Spec.ResourceRequirements, }, { Name: "tikv-ctl", @@ -408,7 +415,7 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job Args: []string{fmt.Sprintf("cp /tikv-ctl %s/tikv-ctl; echo 'tikv-ctl copy finished'", util.KVCTLBinPath)}, ImagePullPolicy: corev1.PullIfNotPresent, VolumeMounts: volumeMounts, - Resources: backup.Spec.ResourceRequirements, + Resources: compact.Spec.ResourceRequirements, }, }, Containers: []corev1.Container{ @@ -421,12 +428,12 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job ImagePullPolicy: corev1.PullIfNotPresent, }, }, - RestartPolicy: corev1.RestartPolicyNever, - Tolerations: backup.Spec.Tolerations, - ImagePullSecrets: backup.Spec.ImagePullSecrets, - Affinity: backup.Spec.Affinity, + RestartPolicy: corev1.RestartPolicyOnFailure, + Tolerations: compact.Spec.Tolerations, + ImagePullSecrets: compact.Spec.ImagePullSecrets, + Affinity: compact.Spec.Affinity, Volumes: volumes, - PriorityClassName: backup.Spec.PriorityClassName, + PriorityClassName: compact.Spec.PriorityClassName, }, } @@ -437,14 +444,54 @@ func (c *Controller) makeBackupJob(backup *v1alpha1.CompactBackup) (*batchv1.Job Labels: jobLabels, Annotations: jobAnnotations, OwnerReferences: []metav1.OwnerReference{ - controller.GetCompactBackupOwnerRef(backup), + controller.GetCompactBackupOwnerRef(compact), }, }, Spec: batchv1.JobSpec{ - BackoffLimit: pointer.Int32Ptr(0), Template: *podSpec, + BackoffLimit: ptr.To(compact.Spec.MaxRetryTimes), }, } return job, "", nil } + +func (c *Controller) isCompactJobAlreadyRunning(compact *v1alpha1.CompactBackup) (bool, error) { + ns := compact.GetNamespace() + name := compact.GetName() + + job, err := c.deps.KubeClientset.BatchV1().Jobs(ns).Get(context.TODO(), name, metav1.GetOptions{}) + if err != nil { + if errors.IsNotFound(err) { + return false, nil + } + klog.Errorf("Failed to get job %s for compact %s/%s, error %v", name, ns, name, err) + return false, err + } + + for _, condition := range job.Status.Conditions { + if condition.Type == batchv1.JobFailed && condition.Status == corev1.ConditionTrue { + // Check events if job failed + events, err := c.deps.KubeClientset.CoreV1().Events(ns).List(context.TODO(), metav1.ListOptions{ + FieldSelector: fmt.Sprintf("involvedObject.kind=Job,involvedObject.name=%s", name), + }) + if err != nil { + if errors.IsNotFound(err) { + return true, nil // No events found, treat as "running" + } + klog.Errorf("Failed to get events for job %s/%s, error %v", ns, name, err) + return true, err + } + + for _, event := range events.Items { + if event.Reason == "BackoffLimitExceeded" { + klog.Warningf("Job %s has exceeded the backoff limit, no further retries will be attempted.", name) + c.statusUpdater.OnJobFailed(context.TODO(), compact, event.Message) + } + } + return true, nil + } + } + + return true, nil +} From 129ff36e82b3e6dd2f92cc9cb4380bd0988466ff Mon Sep 17 00:00:00 2001 From: RidRisR <79858083+RidRisR@users.noreply.github.com> Date: Thu, 26 Dec 2024 09:02:10 +0100 Subject: [PATCH 45/49] make generate --- docs/api-references/docs.md | 18 ++++++++---------- manifests/crd.yaml | 15 +++------------ .../crd/v1/pingcap.com_compactbackups.yaml | 15 +++------------ pkg/apis/pingcap/v1alpha1/openapi_generated.go | 9 +++++---- pkg/apis/pingcap/v1alpha1/types.go | 4 ++-- .../pingcap/v1alpha1/zz_generated.deepcopy.go | 1 - pkg/controller/compact_backup_control.go | 2 +- pkg/controller/compact_status_updater.go | 12 +++++------- .../compactbackup/compact_backup_controller.go | 10 +++++----- 9 files changed, 32 insertions(+), 54 deletions(-) diff --git a/docs/api-references/docs.md b/docs/api-references/docs.md index fe726a0266..b4a9a79bcd 100644 --- a/docs/api-references/docs.md +++ b/docs/api-references/docs.md @@ -3620,8 +3620,7 @@ bool
(Appears on: -BackupSpec, -CompactSpec) +BackupSpec)
BackoffRetryPolicy is the backoff retry policy, currently only valid for snapshot backup. @@ -5588,11 +5587,9 @@ string
backoffRetryPolicy
+maxRetryTimes
-
-BackoffRetryPolicy
-
+int32
backoffRetryPolicy
+maxRetryTimes
-
-BackoffRetryPolicy
-
+int32
State is the current state of the backup
Progress is the progress of the backup
Message is the error message of the backup