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 }