github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/ctl/master/handle_error.go (about)

     1  // Copyright 2020 PingCAP, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package master
    15  
    16  import (
    17  	"context"
    18  	"errors"
    19  	"os"
    20  
    21  	"github.com/pingcap/tiflow/dm/ctl/common"
    22  	"github.com/pingcap/tiflow/dm/pb"
    23  	"github.com/pingcap/tiflow/dm/pkg/binlog"
    24  	"github.com/spf13/cobra"
    25  )
    26  
    27  // NewHandleErrorCmd creates a HandleError command.
    28  // deprecated, replaced by binlog command.
    29  func NewHandleErrorCmd() *cobra.Command {
    30  	cmd := &cobra.Command{
    31  		Use:    "handle-error <task-name | task-file> [-s source ...] [-b binlog-pos] <skip/replace/revert> [replace-sql1;replace-sql2;]",
    32  		Short:  "`skip`/`replace`/`revert` the current error event or a specific binlog position (binlog-pos) event",
    33  		Hidden: true,
    34  		RunE:   handleErrorFunc,
    35  	}
    36  	cmd.Flags().StringP("binlog-pos", "b", "", "position used to match binlog event if matched the handler-error operation will be applied. The format like \"mysql-bin|000001.000003:3270\"")
    37  	return cmd
    38  }
    39  
    40  func convertOp(t string) pb.ErrorOp {
    41  	switch t {
    42  	case "skip":
    43  		return pb.ErrorOp_Skip
    44  	case "replace":
    45  		return pb.ErrorOp_Replace
    46  	case "revert":
    47  		return pb.ErrorOp_Revert
    48  	default:
    49  		return pb.ErrorOp_InvalidErrorOp
    50  	}
    51  }
    52  
    53  // handleErrorFunc does handle error request.
    54  func handleErrorFunc(cmd *cobra.Command, _ []string) error {
    55  	if len(cmd.Flags().Args()) < 2 {
    56  		cmd.SetOut(os.Stdout)
    57  		common.PrintCmdUsage(cmd)
    58  		return errors.New("please check output to see error")
    59  	}
    60  
    61  	taskName := common.GetTaskNameFromArgOrFile(cmd.Flags().Arg(0))
    62  	operation := cmd.Flags().Arg(1)
    63  	var sqls []string
    64  	var err error
    65  
    66  	op := convertOp(operation)
    67  	switch op {
    68  	case pb.ErrorOp_Skip, pb.ErrorOp_Revert:
    69  		if len(cmd.Flags().Args()) > 2 {
    70  			common.PrintLinesf("replace-sqls can not be used for 'skip/revert' operation")
    71  			return errors.New("please check output to see error")
    72  		}
    73  	case pb.ErrorOp_Replace:
    74  		if len(cmd.Flags().Args()) <= 2 {
    75  			common.PrintLinesf("must specify the replace-sqls for replace operation")
    76  			return errors.New("please check output to see error")
    77  		}
    78  
    79  		sqls, err = common.ExtractSQLsFromArgs(cmd.Flags().Args()[2:])
    80  		if err != nil {
    81  			return err
    82  		}
    83  	default:
    84  		common.PrintLinesf("invalid operation '%s', please use `skip`, `replace` or `revert`", operation)
    85  		return errors.New("please check output to see error")
    86  	}
    87  	request := &pb.HandleErrorRequest{
    88  		Op:   op,
    89  		Task: taskName,
    90  		Sqls: sqls,
    91  	}
    92  	return sendHandleErrorRequest(cmd, request)
    93  }
    94  
    95  func sendHandleErrorRequest(cmd *cobra.Command, request *pb.HandleErrorRequest) error {
    96  	binlogPos, err := cmd.Flags().GetString("binlog-pos")
    97  	if err != nil {
    98  		return err
    99  	}
   100  	if len(binlogPos) != 0 {
   101  		_, err = binlog.VerifyBinlogPos(binlogPos)
   102  		if err != nil {
   103  			return err
   104  		}
   105  	}
   106  
   107  	sources, err := common.GetSourceArgs(cmd)
   108  	if err != nil {
   109  		return err
   110  	}
   111  
   112  	ctx, cancel := context.WithCancel(context.Background())
   113  	defer cancel()
   114  
   115  	request.BinlogPos = binlogPos
   116  	request.Sources = sources
   117  
   118  	resp := &pb.HandleErrorResponse{}
   119  	err = common.SendRequest(
   120  		ctx,
   121  		"HandleError",
   122  		request,
   123  		&resp,
   124  	)
   125  
   126  	if err != nil {
   127  		return err
   128  	}
   129  
   130  	common.PrettyPrintResponse(resp)
   131  	return nil
   132  }