github.com/pingcap/tiup@v1.15.1/components/playground/instance/instance.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 "fmt" 19 "net" 20 "os" 21 "path/filepath" 22 23 "github.com/BurntSushi/toml" 24 "github.com/pingcap/errors" 25 "github.com/pingcap/tiup/pkg/cluster/spec" 26 "github.com/pingcap/tiup/pkg/utils" 27 ) 28 29 // Config of the instance. 30 type Config struct { 31 ConfigPath string `yaml:"config_path"` 32 BinPath string `yaml:"bin_path"` 33 Num int `yaml:"num"` 34 Host string `yaml:"host"` 35 Port int `yaml:"port"` 36 UpTimeout int `yaml:"up_timeout"` 37 Version string `yaml:"version"` 38 } 39 40 // CSEOptions contains configs to run TiDB cluster in CSE mode. 41 type CSEOptions struct { 42 S3Endpoint string `yaml:"s3_endpoint"` 43 Bucket string `yaml:"bucket"` 44 AccessKey string `yaml:"access_key"` 45 SecretKey string `yaml:"secret_key"` 46 } 47 48 type instance struct { 49 ID int 50 Dir string 51 Host string 52 Port int 53 StatusPort int // client port for PD 54 ConfigPath string 55 BinPath string 56 } 57 58 // MetricAddr will be used by prometheus scrape_configs. 59 type MetricAddr struct { 60 Targets []string `json:"targets"` 61 Labels map[string]string `json:"labels"` 62 } 63 64 // Instance represent running component 65 type Instance interface { 66 Pid() int 67 // Start the instance process. 68 // Will kill the process once the context is done. 69 Start(ctx context.Context, version utils.Version) error 70 // Component Return the component name. 71 Component() string 72 // LogFile return the log file name 73 LogFile() string 74 // Uptime show uptime. 75 Uptime() string 76 // MetricAddr return the address to pull metrics. 77 MetricAddr() MetricAddr 78 // Wait Should only call this if the instance is started successfully. 79 // The implementation should be safe to call Wait multi times. 80 Wait() error 81 } 82 83 func (inst *instance) MetricAddr() (r MetricAddr) { 84 if inst.Host != "" && inst.StatusPort != 0 { 85 r.Targets = append(r.Targets, utils.JoinHostPort(inst.Host, inst.StatusPort)) 86 } 87 return 88 } 89 90 // CompVersion return the format to run specified version of a component. 91 func CompVersion(comp string, version utils.Version) string { 92 if version.IsEmpty() { 93 return comp 94 } 95 return fmt.Sprintf("%v:%v", comp, version) 96 } 97 98 // AdvertiseHost returns the interface's ip addr if listen host is 0.0.0.0 99 func AdvertiseHost(listen string) string { 100 if listen == "0.0.0.0" { 101 addrs, err := net.InterfaceAddrs() 102 if err != nil || len(addrs) == 0 { 103 return "localhost" 104 } 105 106 for _, addr := range addrs { 107 if ip, ok := addr.(*net.IPNet); ok && !ip.IP.IsLoopback() && ip.IP.To4() != nil { 108 return ip.IP.To4().String() 109 } 110 } 111 return "localhost" 112 } 113 114 return listen 115 } 116 117 func logIfErr(err error) { 118 if err != nil { 119 fmt.Println(err) 120 } 121 } 122 123 func pdEndpoints(pds []*PDInstance, isHTTP bool) []string { 124 var endpoints []string 125 for _, pd := range pds { 126 if pd.Role == PDRoleTSO || pd.Role == PDRoleScheduling { 127 continue 128 } 129 if isHTTP { 130 endpoints = append(endpoints, "http://"+utils.JoinHostPort(AdvertiseHost(pd.Host), pd.StatusPort)) 131 } else { 132 endpoints = append(endpoints, utils.JoinHostPort(AdvertiseHost(pd.Host), pd.StatusPort)) 133 } 134 } 135 return endpoints 136 } 137 138 // prepareConfig accepts a user specified config and merge user config with a 139 // pre-defined one. 140 func prepareConfig(outputConfigPath string, userConfigPath string, preDefinedConfig map[string]any) error { 141 dir := filepath.Dir(outputConfigPath) 142 if err := utils.MkdirAll(dir, 0755); err != nil { 143 return err 144 } 145 146 userConfig, err := unmarshalConfig(userConfigPath) 147 if err != nil { 148 return errors.Trace(err) 149 } 150 if userConfig == nil { 151 userConfig = make(map[string]any) 152 } 153 154 cf, err := os.Create(outputConfigPath) 155 if err != nil { 156 return errors.Trace(err) 157 } 158 159 enc := toml.NewEncoder(cf) 160 enc.Indent = "" 161 return enc.Encode(spec.MergeConfig(preDefinedConfig, userConfig)) 162 } 163 164 func unmarshalConfig(path string) (map[string]any, error) { 165 if path == "" { 166 return nil, nil 167 } 168 data, err := os.ReadFile(path) 169 if err != nil { 170 return nil, err 171 } 172 c := make(map[string]any) 173 err = toml.Unmarshal(data, &c) 174 if err != nil { 175 return nil, err 176 } 177 return c, nil 178 }