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

     1  // Copyright 2022 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  	"os"
    19  	"strings"
    20  
    21  	"github.com/pingcap/errors"
    22  	"github.com/pingcap/tiflow/dm/ctl/common"
    23  	"github.com/pingcap/tiflow/dm/pb"
    24  	"github.com/spf13/cobra"
    25  )
    26  
    27  const (
    28  	ValidationAllErr         = "all"
    29  	ValidationIgnoredErr     = "ignored"
    30  	ValidationUnprocessedErr = "unprocessed"
    31  	ValidationResolvedErr    = "resolved"
    32  )
    33  
    34  var mapStr2ErrState = map[string]pb.ValidateErrorState{
    35  	ValidationAllErr:         pb.ValidateErrorState_InvalidErr,
    36  	ValidationIgnoredErr:     pb.ValidateErrorState_IgnoredErr,
    37  	ValidationUnprocessedErr: pb.ValidateErrorState_NewErr,
    38  	ValidationResolvedErr:    pb.ValidateErrorState_ResolvedErr,
    39  }
    40  
    41  func NewQueryValidationErrorCmd() *cobra.Command {
    42  	cmd := &cobra.Command{
    43  		Use:   "show-error [--error error-state] <task-name>",
    44  		Short: "show validation error row change",
    45  		RunE:  queryValidationError,
    46  	}
    47  	cmd.Flags().String("error", ValidationUnprocessedErr, "filtering type of error: all, ignored, or unprocessed")
    48  	return cmd
    49  }
    50  
    51  func queryValidationError(cmd *cobra.Command, _ []string) (err error) {
    52  	var (
    53  		errState   string
    54  		taskName   string
    55  		pbErrState pb.ValidateErrorState
    56  		ok         bool
    57  	)
    58  	if len(cmd.Flags().Args()) != 1 {
    59  		return errors.New("task name should be specified")
    60  	}
    61  	taskName = cmd.Flags().Arg(0)
    62  	errState, err = cmd.Flags().GetString("error")
    63  	if err != nil {
    64  		return err
    65  	}
    66  	if pbErrState, ok = mapStr2ErrState[errState]; !ok || errState == ValidationResolvedErr {
    67  		// todo: support querying resolved error?
    68  		cmd.SetOut(os.Stdout)
    69  		common.PrintCmdUsage(cmd)
    70  		return errors.Errorf("error flag should be either `%s`, `%s`, or `%s`", ValidationAllErr, ValidationIgnoredErr, ValidationUnprocessedErr)
    71  	}
    72  	ctx, cancel := context.WithCancel(context.Background())
    73  	defer cancel()
    74  	resp := &pb.GetValidationErrorResponse{}
    75  	err = common.SendRequest(
    76  		ctx,
    77  		"GetValidationError",
    78  		&pb.GetValidationErrorRequest{
    79  			ErrState: pbErrState, // using InvalidValidateError to represent `all``
    80  			TaskName: taskName,
    81  		},
    82  		&resp,
    83  	)
    84  	if err != nil {
    85  		return err
    86  	}
    87  	common.PrettyPrintResponse(resp)
    88  	return nil
    89  }
    90  
    91  func NewQueryValidationStatusCmd() *cobra.Command {
    92  	cmd := &cobra.Command{
    93  		Use:   "status [--table-stage stage] <task-name>",
    94  		Short: "query validation status of a task",
    95  		RunE:  queryValidationStatus,
    96  	}
    97  	cmd.Flags().String("table-stage", "", "filter validation tables by stage: running/stopped")
    98  	return cmd
    99  }
   100  
   101  func queryValidationStatus(cmd *cobra.Command, _ []string) error {
   102  	var (
   103  		stage    string
   104  		taskName string
   105  		err      error
   106  	)
   107  
   108  	if len(cmd.Flags().Args()) != 1 {
   109  		cmd.SetOut(os.Stdout)
   110  		common.PrintCmdUsage(cmd)
   111  		return errors.New("task name should be specified")
   112  	}
   113  	taskName = cmd.Flags().Arg(0)
   114  	stage, err = cmd.Flags().GetString("table-stage")
   115  	if err != nil {
   116  		return err
   117  	}
   118  	if stage != "" && stage != strings.ToLower(pb.Stage_Running.String()) && stage != strings.ToLower(pb.Stage_Stopped.String()) {
   119  		cmd.SetOut(os.Stdout)
   120  		common.PrintCmdUsage(cmd)
   121  		return errors.Errorf(
   122  			"stage should be either `%s` or `%s`",
   123  			strings.ToLower(pb.Stage_Running.String()),
   124  			strings.ToLower(pb.Stage_Stopped.String()),
   125  		)
   126  	}
   127  	var pbStage pb.Stage
   128  	switch stage {
   129  	case "":
   130  		// use invalid stage to represent `all` stages
   131  		pbStage = pb.Stage_InvalidStage
   132  	case strings.ToLower(pb.Stage_Running.String()):
   133  		pbStage = pb.Stage_Running
   134  	case strings.ToLower(pb.Stage_Stopped.String()):
   135  		pbStage = pb.Stage_Stopped
   136  	}
   137  	ctx, cancel := context.WithCancel(context.Background())
   138  	defer cancel()
   139  
   140  	resp := &pb.GetValidationStatusResponse{}
   141  	err = common.SendRequest(
   142  		ctx,
   143  		"GetValidationStatus",
   144  		&pb.GetValidationStatusRequest{
   145  			TaskName:     taskName,
   146  			FilterStatus: pbStage,
   147  		},
   148  		&resp,
   149  	)
   150  	if err != nil {
   151  		return err
   152  	}
   153  	common.PrettyPrintResponse(resp)
   154  	return nil
   155  }