github.com/pingcap/tiup@v1.15.1/components/playground/instance/tiproxy.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 instance 15 16 import ( 17 "context" 18 "encoding/pem" 19 "fmt" 20 "os" 21 "path/filepath" 22 "strings" 23 24 "github.com/BurntSushi/toml" 25 "github.com/pingcap/tiup/pkg/cluster/spec" 26 "github.com/pingcap/tiup/pkg/crypto" 27 tiupexec "github.com/pingcap/tiup/pkg/exec" 28 "github.com/pingcap/tiup/pkg/utils" 29 ) 30 31 // TiProxy represent a ticdc instance. 32 type TiProxy struct { 33 instance 34 pds []*PDInstance 35 Process 36 } 37 38 var _ Instance = &TiProxy{} 39 40 // GenTiProxySessionCerts will create a self-signed certs for TiProxy session migration. NOTE that this cert is directly used by TiDB. 41 func GenTiProxySessionCerts(dir string) error { 42 if _, err := os.Stat(filepath.Join(dir, "tiproxy.crt")); err == nil { 43 return nil 44 } 45 46 ca, err := crypto.NewCA("tiproxy") 47 if err != nil { 48 return err 49 } 50 privKey, err := crypto.NewKeyPair(crypto.KeyTypeRSA, crypto.KeySchemeRSASSAPSSSHA256) 51 if err != nil { 52 return err 53 } 54 csr, err := privKey.CSR("tiproxy", "tiproxy", nil, nil) 55 if err != nil { 56 return err 57 } 58 cert, err := ca.Sign(csr) 59 if err != nil { 60 return err 61 } 62 if err := utils.SaveFileWithBackup(filepath.Join(dir, "tiproxy.key"), privKey.Pem(), ""); err != nil { 63 return err 64 } 65 return utils.SaveFileWithBackup(filepath.Join(dir, "tiproxy.crt"), pem.EncodeToMemory(&pem.Block{ 66 Type: "CERTIFICATE", 67 Bytes: cert, 68 }), "") 69 } 70 71 // NewTiProxy create a TiProxy instance. 72 func NewTiProxy(binPath string, dir, host, configPath string, id int, port int, pds []*PDInstance) *TiProxy { 73 if port <= 0 { 74 port = 6000 75 } 76 tiproxy := &TiProxy{ 77 instance: instance{ 78 BinPath: binPath, 79 ID: id, 80 Dir: dir, 81 Host: host, 82 Port: utils.MustGetFreePort(host, port), 83 StatusPort: utils.MustGetFreePort(host, 3080), 84 ConfigPath: configPath, 85 }, 86 pds: pds, 87 } 88 return tiproxy 89 } 90 91 // MetricAddr implements Instance interface. 92 func (c *TiProxy) MetricAddr() (r MetricAddr) { 93 r.Targets = append(r.Targets, utils.JoinHostPort(c.Host, c.StatusPort)) 94 r.Labels = map[string]string{ 95 "__metrics_path__": "/api/metrics", 96 } 97 return 98 } 99 100 // Start implements Instance interface. 101 func (c *TiProxy) Start(ctx context.Context, version utils.Version) error { 102 endpoints := pdEndpoints(c.pds, false) 103 104 configPath := filepath.Join(c.Dir, "config", "proxy.toml") 105 dir := filepath.Dir(configPath) 106 if err := utils.MkdirAll(dir, 0755); err != nil { 107 return err 108 } 109 110 userConfig, err := unmarshalConfig(c.ConfigPath) 111 if err != nil { 112 return err 113 } 114 if userConfig == nil { 115 userConfig = make(map[string]any) 116 } 117 118 cf, err := os.Create(configPath) 119 if err != nil { 120 return err 121 } 122 123 enc := toml.NewEncoder(cf) 124 enc.Indent = "" 125 if err := enc.Encode(spec.MergeConfig(userConfig, map[string]any{ 126 "proxy.pd-addrs": strings.Join(endpoints, ","), 127 "proxy.addr": utils.JoinHostPort(c.Host, c.Port), 128 "proxy.advertise-addr": AdvertiseHost(c.Host), 129 "api.addr": utils.JoinHostPort(c.Host, c.StatusPort), 130 "log.log-file.filename": c.LogFile(), 131 })); err != nil { 132 return err 133 } 134 135 args := []string{ 136 fmt.Sprintf("--config=%s", configPath), 137 } 138 139 if c.BinPath, err = tiupexec.PrepareBinary("tiproxy", version, c.BinPath); err != nil { 140 return err 141 } 142 143 c.Process = &process{cmd: PrepareCommand(ctx, c.BinPath, args, nil, c.Dir)} 144 145 logIfErr(c.Process.SetOutputFile(c.LogFile())) 146 return c.Process.Start() 147 } 148 149 // Addr return addresses that can be connected by MySQL clients. 150 func (c *TiProxy) Addr() string { 151 return utils.JoinHostPort(AdvertiseHost(c.Host), c.Port) 152 } 153 154 // Component return component name. 155 func (c *TiProxy) Component() string { 156 return "tiproxy" 157 } 158 159 // LogFile return the log file. 160 func (c *TiProxy) LogFile() string { 161 return filepath.Join(c.Dir, "tiproxy.log") 162 }