Skip to content

Commit

Permalink
remove check role in switchover opsrequest
Browse files Browse the repository at this point in the history
  • Loading branch information
cjc7373 committed Dec 13, 2024
1 parent ae0a8d6 commit 52e760a
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 310 deletions.
1 change: 1 addition & 0 deletions apis/operations/v1alpha1/opsrequest_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ type Switchover struct {
// If CandidateName is specified, the role will be transferred to this instance.
// The name must match one of the pods in the component.
// Refer to ComponentDefinition's Swtichover lifecycle action for more details.
//
// +optional
CandidateName string `json:"candidateName,omitempty"`
}
Expand Down
93 changes: 11 additions & 82 deletions apis/operations/v1alpha1/opsrequest_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ func (r *OpsRequest) ValidateOps(ctx context.Context,
case ReconfiguringType:
return r.validateReconfigure(ctx, k8sClient, cluster)
case SwitchoverType:
return r.validateSwitchover(ctx, k8sClient, cluster)
return r.validateSwitchover(cluster)
case ExposeType:
return r.validateExpose(ctx, cluster)
case RebuildInstanceType:
Expand Down Expand Up @@ -493,7 +493,8 @@ func (r *OpsRequest) validateVolumeExpansion(ctx context.Context, cli client.Cli
}

// validateSwitchover validates switchover api when spec.type is Switchover.
func (r *OpsRequest) validateSwitchover(ctx context.Context, cli client.Client, cluster *appsv1.Cluster) error {
// more time consuming checks will be done in handler's Action() function.
func (r *OpsRequest) validateSwitchover(cluster *appsv1.Cluster) error {
switchoverList := r.Spec.SwitchoverList
if len(switchoverList) == 0 {
return notEmptyError("spec.switchover")
Expand All @@ -506,7 +507,14 @@ func (r *OpsRequest) validateSwitchover(ctx context.Context, cli client.Client,
if err := r.checkComponentExistence(cluster, compOpsList); err != nil {
return err
}
return validateSwitchoverResourceList(ctx, cli, cluster, switchoverList)

for _, switchover := range switchoverList {
if switchover.InstanceName == "" {
return notEmptyError("switchover.instanceName")
}
}

return nil
}

func (r *OpsRequest) checkInstanceTemplate(cluster *appsv1.Cluster, componentOps ComponentOps, inputInstances []string) error {
Expand Down Expand Up @@ -791,85 +799,6 @@ func GetRunningOpsByOpsType(ctx context.Context, cli client.Client,
return runningOpsList, nil
}

// validateSwitchoverResourceList checks if switchover resourceList is legal.
func validateSwitchoverResourceList(ctx context.Context, cli client.Client, cluster *appsv1.Cluster, switchoverList []Switchover) error {
for _, switchover := range switchoverList {
if switchover.InstanceName == "" {
return notEmptyError("switchover.instanceName")
}

validateBaseOnCompDef := func(compDef string) error {
compDefObj, err := getComponentDefByName(ctx, cli, compDef)
if err != nil {
return err
}
if compDefObj == nil {
return fmt.Errorf("this component %s referenced componentDefinition is invalid", switchover.ComponentName)
}
if compDefObj.Spec.LifecycleActions == nil || compDefObj.Spec.LifecycleActions.Switchover == nil {
return fmt.Errorf("this cluster component %s does not support switchover", switchover.ComponentName)
}
// check switchover.InstanceName whether exist and role label is correct
if switchover.InstanceName == KBSwitchoverCandidateInstanceForAnyPod {
return nil
}
if len(compDefObj.Spec.Roles) == 0 {
return errors.New("component has no roles definition, does not support switchover")
}

getPod := func(name string) (*corev1.Pod, error) {
pod := &corev1.Pod{}
if err := cli.Get(ctx, types.NamespacedName{Namespace: cluster.Namespace, Name: name}, pod); err != nil {
return nil, fmt.Errorf("get instanceName %s failed, err: %s, and check the validity of the instanceName using \"kbcli cluster list-instances\"", name, err.Error())
}
return pod, nil
}

checkOwnership := func(pod *corev1.Pod) error {
if !strings.HasPrefix(pod.Name, fmt.Sprintf("%s-%s", cluster.Name, switchover.ComponentName)) {
return fmt.Errorf("instanceName %s does not belong to the current component, please check the validity of the instance using \"kbcli cluster list-instances\"", switchover.InstanceName)
}
return nil
}

pod, err := getPod(switchover.InstanceName)
if err != nil {
return err
}
if err := checkOwnership(pod); err != nil {
return err
}
roleName, ok := pod.Labels[constant.RoleLabelKey]
if !ok || roleName == "" {
return fmt.Errorf("instanceName %s cannot be promoted because it had a invalid role label", switchover.InstanceName)
}

if switchover.CandidateName != "" {
candidatePod, err := getPod(switchover.InstanceName)
if err != nil {
return err
}
if err := checkOwnership(candidatePod); err != nil {
return err
}
}

return nil
}

compSpec := cluster.Spec.GetComponentByName(switchover.ComponentName)
if compSpec == nil {
return fmt.Errorf("component %s not found", switchover.ComponentName)
}
if compSpec.ComponentDef != "" {
return validateBaseOnCompDef(compSpec.ComponentDef)
} else {
return fmt.Errorf("not-supported")
}
}
return nil
}

// getComponentDefByName gets ComponentDefinition with compDefName
func getComponentDefByName(ctx context.Context, cli client.Client, compDefName string) (*appsv1.ComponentDefinition, error) {
compDef := &appsv1.ComponentDefinition{}
Expand Down
54 changes: 27 additions & 27 deletions controllers/apps/transformer_component_workload.go
Original file line number Diff line number Diff line change
Expand Up @@ -680,34 +680,37 @@ func (r *componentWorkloadOps) leaveMember4ScaleIn(deleteReplicas, joinedReplica
}

func (r *componentWorkloadOps) leaveMemberForPod(pod *corev1.Pod, pods []*corev1.Pod) error {
isLeader := func(pod *corev1.Pod) bool {
trySwitchover := func(lfa lifecycle.Lifecycle, pod *corev1.Pod) error {
// if pod does not have role, no need to call switchover
if pod == nil || len(pod.Labels) == 0 {
return false
return nil
}
_, ok := pod.Labels[constant.RoleLabelKey]

return ok
}

tryToSwitchover := func(lfa lifecycle.Lifecycle, pod *corev1.Pod) error {
// if pod is not leader/primary, no need to switchover
if !isLeader(pod) {
if !ok {
return nil
}
// if HA functionality is not enabled, no need to switchover

err := lfa.Switchover(r.reqCtx.Ctx, r.cli, nil, "")
if err != nil && errors.Is(err, lifecycle.ErrActionNotDefined) {
return nil
}
if err == nil {
// FIXME: compare role labels after switchover succeeds
return fmt.Errorf("switchover succeed, wait role label to be updated")
if err != nil {
if errors.Is(err, lifecycle.ErrActionNotDefined) {
return nil
}
return err
}
return err
r.reqCtx.Recorder.Eventf(r.component, corev1.EventTypeNormal, "Switchover", "successfully call switchover action for pod %v", pod.Name)
return nil
}

if !(isLeader(pod) || // if the pod is leader, it needs to call switchover
(r.synthesizeComp.LifecycleActions != nil && r.synthesizeComp.LifecycleActions.MemberLeave != nil)) { // if the memberLeave action is defined, it needs to call it
tryMemberLeave := func(lfa lifecycle.Lifecycle) error {
err := lfa.MemberLeave(r.reqCtx.Ctx, r.cli, nil)
if err != nil {
if errors.Is(err, lifecycle.ErrActionNotDefined) {
return nil
}
return err
}

r.reqCtx.Recorder.Eventf(r.component, corev1.EventTypeNormal, "MemberLeave", "successfully leave member for pod %v", pod.Name)
return nil
}

Expand All @@ -716,17 +719,14 @@ func (r *componentWorkloadOps) leaveMemberForPod(pod *corev1.Pod, pods []*corev1
return err
}

// switchover if the leaving pod is leader
if switchoverErr := tryToSwitchover(lfa, pod); switchoverErr != nil {
return switchoverErr
if err := trySwitchover(lfa, pod); err != nil {
return err
}

if err = lfa.MemberLeave(r.reqCtx.Ctx, r.cli, nil); err != nil {
if !errors.Is(err, lifecycle.ErrActionNotDefined) {
return err
}
if err := tryMemberLeave(lfa); err != nil {
return err
}
r.reqCtx.Log.Info("succeed to leave member for pod", "pod", pod.Name)

return nil
}

Expand Down
Loading

0 comments on commit 52e760a

Please sign in to comment.