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

     1  // Copyright 2019 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  	"fmt"
    20  	"os"
    21  
    22  	"github.com/pingcap/tiflow/dm/config"
    23  	"github.com/pingcap/tiflow/dm/ctl/common"
    24  	"github.com/pingcap/tiflow/dm/pb"
    25  	"github.com/pingcap/tiflow/dm/pkg/log"
    26  	"github.com/pingcap/tiflow/dm/pkg/terror"
    27  	"github.com/spf13/cobra"
    28  	"go.uber.org/zap"
    29  )
    30  
    31  // NewOperateSourceCmd creates a OperateSource command.
    32  func NewOperateSourceCmd() *cobra.Command {
    33  	cmd := &cobra.Command{
    34  		Use:   "operate-source <operate-type> [config-file ...] [-w worker] [--print-sample-config]",
    35  		Short: "`create`/`stop`/`show` upstream MySQL/MariaDB source",
    36  		RunE:  operateSourceFunc,
    37  	}
    38  	cmd.Flags().BoolP("print-sample-config", "p", false, "print sample config file of source")
    39  	cmd.Flags().StringP("worker", "w", "", "specify bound worker for created source")
    40  	return cmd
    41  }
    42  
    43  func convertCmdType(t string) pb.SourceOp {
    44  	switch t {
    45  	case "create":
    46  		return pb.SourceOp_StartSource
    47  	case "update":
    48  		return pb.SourceOp_UpdateSource
    49  	case "stop":
    50  		return pb.SourceOp_StopSource
    51  	case "show":
    52  		return pb.SourceOp_ShowSource
    53  	default:
    54  		return pb.SourceOp_InvalidSourceOp
    55  	}
    56  }
    57  
    58  // operateMysqlFunc does migrate relay request.
    59  func operateSourceFunc(cmd *cobra.Command, _ []string) error {
    60  	printSampleConfig, err := cmd.Flags().GetBool("print-sample-config")
    61  	if err != nil {
    62  		common.PrintLinesf("error in parse `--print-sample-config`")
    63  		return err
    64  	}
    65  
    66  	if printSampleConfig {
    67  		fmt.Println(config.SampleSourceConfig)
    68  		return nil
    69  	}
    70  
    71  	if len(cmd.Flags().Args()) < 1 {
    72  		cmd.SetOut(os.Stdout)
    73  		common.PrintCmdUsage(cmd)
    74  		return errors.New("please check output to see error")
    75  	}
    76  
    77  	cmdType := cmd.Flags().Arg(0)
    78  	op := convertCmdType(cmdType)
    79  	if op == pb.SourceOp_InvalidSourceOp {
    80  		common.PrintLinesf("invalid operate '%s' on worker", cmdType)
    81  		return errors.New("please check output to see error")
    82  	}
    83  	if op != pb.SourceOp_ShowSource && len(cmd.Flags().Args()) == 1 {
    84  		common.PrintLinesf("operate-source create/stop should specify config-file(s)")
    85  		return errors.New("please check output to see error")
    86  	}
    87  
    88  	var specifyWorker string
    89  	if op == pb.SourceOp_StartSource {
    90  		specifyWorker, err = cmd.Flags().GetString("worker")
    91  		if err != nil {
    92  			common.PrintLinesf("error in parse `--worker`")
    93  			return err
    94  		}
    95  		if specifyWorker != "" {
    96  			if len(cmd.Flags().Args()) > 2 {
    97  				common.PrintLinesf("operate-source create can't create multiple sources when specify worker")
    98  			}
    99  		}
   100  	}
   101  
   102  	contents := make([]string, 0, len(cmd.Flags().Args())-1)
   103  	sourceID := make([]string, 0, len(cmd.Flags().Args())-1)
   104  	sources, err := common.GetSourceArgs(cmd)
   105  	if err != nil {
   106  		return err
   107  	}
   108  	sourceID = append(sourceID, sources...)
   109  
   110  	for i := 1; i < len(cmd.Flags().Args()); i++ {
   111  		arg := cmd.Flags().Arg(i)
   112  		var content []byte
   113  		content, err = common.GetFileContent(arg)
   114  		if err != nil {
   115  			if op == pb.SourceOp_StopSource {
   116  				sourceID = append(sourceID, arg)
   117  				continue
   118  			}
   119  			return err
   120  		}
   121  		// If source is configured with tls certificate related content
   122  		// the contents of the certificate need to be read and transferred to the dm-master
   123  		cfg, yamlErr := config.SourceCfgFromYaml(string(content))
   124  		if yamlErr != nil {
   125  			return yamlErr
   126  		}
   127  		if cfg.From.Security != nil {
   128  			loadErr := cfg.From.Security.LoadTLSContent()
   129  			if loadErr != nil {
   130  				log.L().Warn("load tls content failed", zap.Error(terror.ErrCtlLoadTLSCfg.Generate(loadErr)))
   131  			}
   132  			yamlStr, yamlErr := cfg.Yaml()
   133  			if yamlErr != nil {
   134  				return yamlErr
   135  			}
   136  			content = []byte(yamlStr)
   137  		}
   138  		if cfg.RelayDir != "" {
   139  			common.PrintLinesf("`relay-dir` in source config will be deprecated soon, please use `relay-dir` in worker config instead")
   140  		}
   141  		contents = append(contents, string(content))
   142  	}
   143  
   144  	ctx, cancel := context.WithCancel(context.Background())
   145  	defer cancel()
   146  
   147  	resp := &pb.OperateSourceResponse{}
   148  	err = common.SendRequest(
   149  		ctx,
   150  		"OperateSource",
   151  		&pb.OperateSourceRequest{
   152  			Config:     contents,
   153  			Op:         op,
   154  			SourceID:   sourceID,
   155  			WorkerName: specifyWorker,
   156  		},
   157  		&resp,
   158  	)
   159  
   160  	if err != nil {
   161  		return err
   162  	}
   163  
   164  	common.PrettyPrintResponse(resp)
   165  	return nil
   166  }