Skip to content

Commit

Permalink
chore: support to rebuild instance from backup for sharding cluster
Browse files Browse the repository at this point in the history
  • Loading branch information
wangyelei committed Jan 9, 2025
1 parent 17a521d commit fc3db69
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 38 deletions.
4 changes: 4 additions & 0 deletions apis/apps/v1alpha1/opsrequest_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,10 @@ type RebuildInstance struct {
// +optional
BackupName string `json:"backupName,omitempty"`

// When multiple source targets exist of the backup, you must specify the source target to restore.
// +optional
SourceBackupTargetName string `json:"sourceBackupTargetName,omitempty"`

// Defines container environment variables for the restore process.
// merged with the ones specified in the Backup and ActionSet resources.
//
Expand Down
4 changes: 4 additions & 0 deletions config/crd/bases/apps.kubeblocks.io_opsrequests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3982,6 +3982,10 @@ spec:
type: object
type: array
x-kubernetes-preserve-unknown-fields: true
sourceBackupTargetName:
description: When multiple source targets exist of the backup,
you must specify the source target to restore.
type: string
required:
- componentName
- instances
Expand Down
58 changes: 31 additions & 27 deletions controllers/apps/operations/rebuild_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ func (r rebuildInstanceOpsHandler) Action(reqCtx intctrlutil.RequestCtx, cli cli
if err := cli.Get(reqCtx.Ctx, client.ObjectKey{Name: ins.Name, Namespace: opsRes.Cluster.Namespace}, targetPod); err != nil {
return err
}
synthesizedComp, err = r.buildSynthesizedComponent(reqCtx, cli, opsRes.Cluster, targetPod.Labels[constant.KBAppComponentLabelKey])

synthesizedComp, err = r.buildSynthesizedComponent(reqCtx, cli, opsRes.Cluster, targetPod, v.ComponentName)
if err != nil {
return err
}
Expand Down Expand Up @@ -274,8 +275,7 @@ func (r rebuildInstanceOpsHandler) rebuildInstanceInPlace(reqCtx intctrlutil.Req
rebuildFrom appsv1alpha1.RebuildInstance,
instance appsv1alpha1.Instance,
index int) (bool, error) {
inPlaceHelper, err := r.prepareInplaceRebuildHelper(reqCtx, cli, opsRes, rebuildFrom.RestoreEnv,
instance, rebuildFrom.BackupName, index)
inPlaceHelper, err := r.prepareInplaceRebuildHelper(reqCtx, cli, opsRes, rebuildFrom, instance, index)
if err != nil {
return false, err
}
Expand Down Expand Up @@ -443,10 +443,6 @@ func (r rebuildInstanceOpsHandler) checkProgressForScalingOutPods(reqCtx intctrl
failedCount int
completedCount int
)
synthesizedComp, err := r.buildSynthesizedComponent(reqCtx, cli, opsRes.Cluster, rebuildInstance.ComponentName)
if err != nil {
return 0, 0, nil, err
}
currPodSet, _ := component.GenerateAllPodNamesToSet(compSpec.Replicas, compSpec.Instances, compSpec.OfflineInstances,
opsRes.Cluster.Name, compSpec.Name)
for _, instance := range rebuildInstance.Instances {
Expand All @@ -463,6 +459,10 @@ func (r rebuildInstanceOpsHandler) checkProgressForScalingOutPods(reqCtx intctrl
reqCtx.Log.Info(fmt.Sprintf("waiting to create the pod %s", scalingOutPodName))
continue
}
synthesizedComp, err := r.buildSynthesizedComponent(reqCtx, cli, opsRes.Cluster, pod, rebuildInstance.ComponentName)
if err != nil {
return 0, 0, nil, err
}
isAvailable, err := instanceIsAvailable(synthesizedComp, pod, opsRes.OpsRequest.Annotations[ignoreRoleCheckAnnotationKey])
if err != nil {
// set progress status to failed when new pod is failed
Expand Down Expand Up @@ -539,13 +539,17 @@ func (r rebuildInstanceOpsHandler) getScalingOutPodNameFromMessage(progressMsg s
func (r rebuildInstanceOpsHandler) buildSynthesizedComponent(reqCtx intctrlutil.RequestCtx,
cli client.Client,
cluster *appsv1alpha1.Cluster,
pod *corev1.Pod,
componentName string) (*component.SynthesizedComponent, error) {
compSpec := getComponentSpecOrShardingTemplate(cluster, componentName)
if compSpec == nil {
return nil, intctrlutil.NewFatalError(fmt.Sprintf(`the component "%s" is not found`, componentName))
}
if compSpec.ComponentDef == "" {
// TODO: remove after 0.9
return component.BuildSynthesizedComponentWrapper(reqCtx, cli, cluster, compSpec)
}
comp, compDef, err := component.GetCompNCompDefByName(reqCtx.Ctx, cli, cluster.Namespace, constant.GenerateClusterComponentName(cluster.Name, componentName))
comp, compDef, err := component.GetCompNCompDefByName(reqCtx.Ctx, cli, cluster.Namespace, constant.GenerateClusterComponentName(cluster.Name, pod.Labels[constant.KBAppComponentLabelKey]))
if err != nil {
return nil, err
}
Expand All @@ -555,30 +559,29 @@ func (r rebuildInstanceOpsHandler) buildSynthesizedComponent(reqCtx intctrlutil.
func (r rebuildInstanceOpsHandler) prepareInplaceRebuildHelper(reqCtx intctrlutil.RequestCtx,
cli client.Client,
opsRes *OpsResource,
envForRestore []corev1.EnvVar,
rebuildInstance appsv1alpha1.RebuildInstance,
instance appsv1alpha1.Instance,
backupName string,
index int) (*inplaceRebuildHelper, error) {
var (
backup *dpv1alpha1.Backup
actionSet *dpv1alpha1.ActionSet
synthesizedComp *component.SynthesizedComponent
err error
)
if backupName != "" {
if rebuildInstance.BackupName != "" {
// prepare backup infos
backup = &dpv1alpha1.Backup{}
if err = cli.Get(reqCtx.Ctx, client.ObjectKey{Name: backupName, Namespace: opsRes.Cluster.Namespace}, backup); err != nil {
if err = cli.Get(reqCtx.Ctx, client.ObjectKey{Name: rebuildInstance.BackupName, Namespace: opsRes.Cluster.Namespace}, backup); err != nil {
return nil, err
}
if backup.Labels[dptypes.BackupTypeLabelKey] != string(dpv1alpha1.BackupTypeFull) {
return nil, intctrlutil.NewFatalError(fmt.Sprintf(`the backup "%s" is not a Full backup`, backupName))
return nil, intctrlutil.NewFatalError(fmt.Sprintf(`the backup "%s" is not a Full backup`, rebuildInstance.BackupName))
}
if backup.Status.Phase != dpv1alpha1.BackupPhaseCompleted {
return nil, intctrlutil.NewFatalError(fmt.Sprintf(`the backup "%s" phase is not Completed`, backupName))
return nil, intctrlutil.NewFatalError(fmt.Sprintf(`the backup "%s" phase is not Completed`, rebuildInstance.BackupName))
}
if backup.Status.BackupMethod == nil {
return nil, intctrlutil.NewFatalError(fmt.Sprintf(`the backupMethod of the backup "%s" can not be empty`, backupName))
return nil, intctrlutil.NewFatalError(fmt.Sprintf(`the backupMethod of the backup "%s" can not be empty`, rebuildInstance.BackupName))
}
actionSet, err = dputils.GetActionSetByName(reqCtx, cli, backup.Status.BackupMethod.ActionSetName)
if err != nil {
Expand All @@ -589,7 +592,7 @@ func (r rebuildInstanceOpsHandler) prepareInplaceRebuildHelper(reqCtx intctrluti
if err = cli.Get(reqCtx.Ctx, client.ObjectKey{Name: instance.Name, Namespace: opsRes.Cluster.Namespace}, targetPod); err != nil {
return nil, err
}
synthesizedComp, err = r.buildSynthesizedComponent(reqCtx, cli, opsRes.Cluster, targetPod.Labels[constant.KBAppComponentLabelKey])
synthesizedComp, err = r.buildSynthesizedComponent(reqCtx, cli, opsRes.Cluster, targetPod, rebuildInstance.ComponentName)
if err != nil {
return nil, err
}
Expand All @@ -599,17 +602,18 @@ func (r rebuildInstanceOpsHandler) prepareInplaceRebuildHelper(reqCtx intctrluti
return nil, err
}
return &inplaceRebuildHelper{
index: index,
backup: backup,
instance: instance,
actionSet: actionSet,
synthesizedComp: synthesizedComp,
pvcMap: pvcMap,
volumes: volumes,
targetPod: targetPod,
volumeMounts: volumeMounts,
rebuildPrefix: rebuildPrefix,
envForRestore: envForRestore,
index: index,
backup: backup,
instance: instance,
actionSet: actionSet,
synthesizedComp: synthesizedComp,
sourceBackupTargetName: rebuildInstance.SourceBackupTargetName,
pvcMap: pvcMap,
volumes: volumes,
targetPod: targetPod,
volumeMounts: volumeMounts,
rebuildPrefix: rebuildPrefix,
envForRestore: rebuildInstance.RestoreEnv,
}, nil
}

Expand Down
25 changes: 14 additions & 11 deletions controllers/apps/operations/rebuild_instance_inplace.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,14 @@ type inplaceRebuildHelper struct {
instance appsv1alpha1.Instance
actionSet *dpv1alpha1.ActionSet
// key: source pvc name, value: the tmp pvc which using to rebuild
pvcMap map[string]*corev1.PersistentVolumeClaim
synthesizedComp *component.SynthesizedComponent
volumes []corev1.Volume
volumeMounts []corev1.VolumeMount
envForRestore []corev1.EnvVar
rebuildPrefix string
index int
pvcMap map[string]*corev1.PersistentVolumeClaim
synthesizedComp *component.SynthesizedComponent
volumes []corev1.Volume
volumeMounts []corev1.VolumeMount
envForRestore []corev1.EnvVar
rebuildPrefix string
sourceBackupTargetName string
index int
}

// rebuildPodWithNoBackup rebuilds the instance with no backup.
Expand Down Expand Up @@ -219,8 +220,9 @@ func (inPlaceHelper *inplaceRebuildHelper) createPrepareDataRestore(reqCtx intct
ObjectMeta: inPlaceHelper.buildRestoreMetaObject(opsRequest, restoreName),
Spec: dpv1alpha1.RestoreSpec{
Backup: dpv1alpha1.BackupRef{
Name: inPlaceHelper.backup.Name,
Namespace: opsRequest.Namespace,
Name: inPlaceHelper.backup.Name,
Namespace: opsRequest.Namespace,
SourceTargetName: inPlaceHelper.sourceBackupTargetName,
},
Env: inPlaceHelper.envForRestore,
PrepareDataConfig: &dpv1alpha1.PrepareDataConfig{
Expand Down Expand Up @@ -262,8 +264,9 @@ func (inPlaceHelper *inplaceRebuildHelper) createPostReadyRestore(reqCtx intctrl
ObjectMeta: inPlaceHelper.buildRestoreMetaObject(opsRequest, restoreName),
Spec: dpv1alpha1.RestoreSpec{
Backup: dpv1alpha1.BackupRef{
Name: inPlaceHelper.backup.Name,
Namespace: inPlaceHelper.backup.Namespace,
Name: inPlaceHelper.backup.Name,
Namespace: inPlaceHelper.backup.Namespace,
SourceTargetName: inPlaceHelper.sourceBackupTargetName,
},
Env: inPlaceHelper.envForRestore,
ReadyConfig: &dpv1alpha1.ReadyConfig{
Expand Down
4 changes: 4 additions & 0 deletions deploy/helm/crds/apps.kubeblocks.io_opsrequests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3982,6 +3982,10 @@ spec:
type: object
type: array
x-kubernetes-preserve-unknown-fields: true
sourceBackupTargetName:
description: When multiple source targets exist of the backup,
you must specify the source target to restore.
type: string
required:
- componentName
- instances
Expand Down
12 changes: 12 additions & 0 deletions docs/developer_docs/api-reference/cluster.md
Original file line number Diff line number Diff line change
Expand Up @@ -17683,6 +17683,18 @@ Defaults to an empty PersistentVolume if unspecified.</p>
</tr>
<tr>
<td>
<code>sourceBackupTargetName</code><br/>
<em>
string
</em>
</td>
<td>
<em>(Optional)</em>
<p>When multiple source targets exist of the backup, you must specify the source target to restore.</p>
</td>
</tr>
<tr>
<td>
<code>restoreEnv</code><br/>
<em>
<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#envvar-v1-core">
Expand Down

0 comments on commit fc3db69

Please sign in to comment.