github.com/pingcap/tidb-lightning@v5.0.0-rc.0.20210428090220-84b649866577+incompatible/lightning/config/global.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 config 15 16 import ( 17 "flag" 18 "fmt" 19 "io/ioutil" 20 "os" 21 "path/filepath" 22 "time" 23 24 "github.com/BurntSushi/toml" 25 "github.com/carlmjohnson/flagext" 26 "github.com/pingcap/errors" 27 28 "github.com/pingcap/tidb-lightning/lightning/common" 29 "github.com/pingcap/tidb-lightning/lightning/log" 30 ) 31 32 type GlobalLightning struct { 33 log.Config 34 StatusAddr string `toml:"status-addr" json:"status-addr"` 35 ServerMode bool `toml:"server-mode" json:"server-mode"` 36 CheckRequirements bool `toml:"check-requirements" json:"check-requirements"` 37 38 // The legacy alias for setting "status-addr". The value should always the 39 // same as StatusAddr, and will not be published in the JSON encoding. 40 PProfPort int `toml:"pprof-port" json:"-"` 41 } 42 43 type GlobalTiDB struct { 44 Host string `toml:"host" json:"host"` 45 Port int `toml:"port" json:"port"` 46 User string `toml:"user" json:"user"` 47 Psw string `toml:"password" json:"-"` 48 StatusPort int `toml:"status-port" json:"status-port"` 49 PdAddr string `toml:"pd-addr" json:"pd-addr"` 50 LogLevel string `toml:"log-level" json:"log-level"` 51 } 52 53 type GlobalMydumper struct { 54 SourceDir string `toml:"data-source-dir" json:"data-source-dir"` 55 NoSchema bool `toml:"no-schema" json:"no-schema"` 56 Filter []string `toml:"filter" json:"filter"` 57 } 58 59 type GlobalImporter struct { 60 Addr string `toml:"addr" json:"addr"` 61 Backend string `toml:"backend" json:"backend"` 62 SortedKVDir string `toml:"sorted-kv-dir" json:"sorted-kv-dir"` 63 } 64 65 type GlobalConfig struct { 66 App GlobalLightning `toml:"lightning" json:"lightning"` 67 Checkpoint GlobalCheckpoint `toml:"checkpoint" json:"checkpoint"` 68 TiDB GlobalTiDB `toml:"tidb" json:"tidb"` 69 Mydumper GlobalMydumper `toml:"mydumper" json:"mydumper"` 70 TikvImporter GlobalImporter `toml:"tikv-importer" json:"tikv-importer"` 71 PostRestore GlobalPostRestore `toml:"post-restore" json:"post-restore"` 72 Security Security `toml:"security" json:"security"` 73 74 ConfigFileContent []byte 75 } 76 77 type GlobalCheckpoint struct { 78 Enable bool `toml:"enable" json:"enable"` 79 } 80 81 type GlobalPostRestore struct { 82 Checksum PostOpLevel `toml:"checksum" json:"checksum"` 83 Analyze PostOpLevel `toml:"analyze" json:"analyze"` 84 } 85 86 func NewGlobalConfig() *GlobalConfig { 87 return &GlobalConfig{ 88 App: GlobalLightning{ 89 ServerMode: false, 90 CheckRequirements: true, 91 }, 92 Checkpoint: GlobalCheckpoint{ 93 Enable: true, 94 }, 95 TiDB: GlobalTiDB{ 96 Host: "127.0.0.1", 97 User: "root", 98 StatusPort: 10080, 99 LogLevel: "error", 100 }, 101 Mydumper: GlobalMydumper{ 102 Filter: DefaultFilter, 103 }, 104 TikvImporter: GlobalImporter{ 105 Backend: "importer", 106 }, 107 PostRestore: GlobalPostRestore{ 108 Checksum: OpLevelRequired, 109 Analyze: OpLevelOptional, 110 }, 111 } 112 } 113 114 // Must should be called after LoadGlobalConfig(). If LoadGlobalConfig() returns 115 // any error, this function will exit the program with an appropriate exit code. 116 func Must(cfg *GlobalConfig, err error) *GlobalConfig { 117 switch errors.Cause(err) { 118 case nil: 119 case flag.ErrHelp: 120 os.Exit(0) 121 default: 122 fmt.Println("Failed to parse command flags: ", err) 123 os.Exit(2) 124 } 125 return cfg 126 } 127 128 func timestampLogFileName() string { 129 return filepath.Join(os.TempDir(), time.Now().Format("lightning.log.2006-01-02T15.04.05Z0700")) 130 } 131 132 // LoadGlobalConfig reads the arguments and fills in the GlobalConfig. 133 func LoadGlobalConfig(args []string, extraFlags func(*flag.FlagSet)) (*GlobalConfig, error) { 134 cfg := NewGlobalConfig() 135 fs := flag.NewFlagSet("", flag.ContinueOnError) 136 137 // if both `-c` and `-config` are specified, the last one in the command line will take effect. 138 // the default value is assigned immediately after the StringVar() call, 139 // so it is fine to not give any default value for `-c`, to keep the `-h` page clean. 140 var configFilePath string 141 fs.StringVar(&configFilePath, "c", "", "(deprecated alias of -config)") 142 fs.StringVar(&configFilePath, "config", "", "tidb-lightning configuration file") 143 printVersion := fs.Bool("V", false, "print version of lightning") 144 145 logLevel := flagext.ChoiceVar(fs, "L", "", `log level: info, debug, warn, error, fatal (default info)`, "", "info", "debug", "warn", "warning", "error", "fatal") 146 logFilePath := fs.String("log-file", "", "log file path") 147 tidbHost := fs.String("tidb-host", "", "TiDB server host") 148 tidbPort := fs.Int("tidb-port", 0, "TiDB server port (default 4000)") 149 tidbUser := fs.String("tidb-user", "", "TiDB user name to connect") 150 tidbPsw := fs.String("tidb-password", "", "TiDB password to connect") 151 tidbStatusPort := fs.Int("tidb-status", 0, "TiDB server status port (default 10080)") 152 pdAddr := fs.String("pd-urls", "", "PD endpoint address") 153 dataSrcPath := fs.String("d", "", "Directory of the dump to import") 154 importerAddr := fs.String("importer", "", "address (host:port) to connect to tikv-importer") 155 backend := flagext.ChoiceVar(fs, "backend", "", `delivery backend: importer, tidb, local (default importer)`, "", "importer", "tidb", "local") 156 sortedKVDir := fs.String("sorted-kv-dir", "", "path for KV pairs when local backend enabled") 157 enableCheckpoint := fs.Bool("enable-checkpoint", true, "whether to enable checkpoints") 158 noSchema := fs.Bool("no-schema", false, "ignore schema files, get schema directly from TiDB instead") 159 checksum := flagext.ChoiceVar(fs, "checksum", "", "compare checksum after importing.", "", "required", "optional", "off", "true", "false") 160 analyze := flagext.ChoiceVar(fs, "analyze", "", "analyze table after importing", "", "required", "optional", "off", "true", "false") 161 checkRequirements := fs.Bool("check-requirements", true, "check cluster version before starting") 162 tlsCAPath := fs.String("ca", "", "CA certificate path for TLS connection") 163 tlsCertPath := fs.String("cert", "", "certificate path for TLS connection") 164 tlsKeyPath := fs.String("key", "", "private key path for TLS connection") 165 redactInfoLog := fs.Bool("redact-info-log", false, "whether to redact sensitive info in log") 166 167 statusAddr := fs.String("status-addr", "", "the Lightning server address") 168 serverMode := fs.Bool("server-mode", false, "start Lightning in server mode, wait for multiple tasks instead of starting immediately") 169 170 var filter []string 171 flagext.StringsVar(fs, &filter, "f", "select tables to import") 172 173 if extraFlags != nil { 174 extraFlags(fs) 175 } 176 177 if err := fs.Parse(args); err != nil { 178 return nil, errors.Trace(err) 179 } 180 if *printVersion { 181 fmt.Println(common.GetRawInfo()) 182 return nil, flag.ErrHelp 183 } 184 185 if len(configFilePath) > 0 { 186 data, err := ioutil.ReadFile(configFilePath) 187 if err != nil { 188 return nil, errors.Annotatef(err, "Cannot read config file `%s`", configFilePath) 189 } 190 if err = toml.Unmarshal(data, cfg); err != nil { 191 return nil, errors.Annotatef(err, "Cannot parse config file `%s`", configFilePath) 192 } 193 cfg.ConfigFileContent = data 194 } 195 196 if *logLevel != "" { 197 cfg.App.Config.Level = *logLevel 198 } 199 if *logFilePath != "" { 200 cfg.App.Config.File = *logFilePath 201 } 202 // "-" is a special config for log to stdout 203 if cfg.App.Config.File == "-" { 204 cfg.App.Config.File = "" 205 } else if cfg.App.Config.File == "" { 206 cfg.App.Config.File = timestampLogFileName() 207 } 208 if *tidbHost != "" { 209 cfg.TiDB.Host = *tidbHost 210 } 211 if *tidbPort != 0 { 212 cfg.TiDB.Port = *tidbPort 213 } 214 if *tidbStatusPort != 0 { 215 cfg.TiDB.StatusPort = *tidbStatusPort 216 } 217 if *tidbUser != "" { 218 cfg.TiDB.User = *tidbUser 219 } 220 if *tidbPsw != "" { 221 cfg.TiDB.Psw = *tidbPsw 222 } 223 if *pdAddr != "" { 224 cfg.TiDB.PdAddr = *pdAddr 225 } 226 if *dataSrcPath != "" { 227 cfg.Mydumper.SourceDir = *dataSrcPath 228 } 229 if *importerAddr != "" { 230 cfg.TikvImporter.Addr = *importerAddr 231 } 232 if *serverMode { 233 cfg.App.ServerMode = true 234 } 235 if *statusAddr != "" { 236 cfg.App.StatusAddr = *statusAddr 237 } 238 if *backend != "" { 239 cfg.TikvImporter.Backend = *backend 240 } 241 if *sortedKVDir != "" { 242 cfg.TikvImporter.SortedKVDir = *sortedKVDir 243 } 244 if !*enableCheckpoint { 245 cfg.Checkpoint.Enable = false 246 } 247 if *noSchema { 248 cfg.Mydumper.NoSchema = true 249 } 250 if *checksum != "" { 251 _ = cfg.PostRestore.Checksum.FromStringValue(*checksum) 252 } 253 if *analyze != "" { 254 _ = cfg.PostRestore.Analyze.FromStringValue(*analyze) 255 } 256 if cfg.App.StatusAddr == "" && cfg.App.PProfPort != 0 { 257 cfg.App.StatusAddr = fmt.Sprintf(":%d", cfg.App.PProfPort) 258 } 259 if !*checkRequirements { 260 cfg.App.CheckRequirements = false 261 } 262 if *tlsCAPath != "" { 263 cfg.Security.CAPath = *tlsCAPath 264 } 265 if *tlsCertPath != "" { 266 cfg.Security.CertPath = *tlsCertPath 267 } 268 if *tlsKeyPath != "" { 269 cfg.Security.KeyPath = *tlsKeyPath 270 } 271 if *redactInfoLog { 272 cfg.Security.RedactInfoLog = *redactInfoLog 273 } 274 if len(filter) > 0 { 275 cfg.Mydumper.Filter = filter 276 } 277 278 if cfg.App.StatusAddr == "" && cfg.App.ServerMode { 279 return nil, errors.New("If server-mode is enabled, the status-addr must be a valid listen address") 280 } 281 282 cfg.App.Config.Adjust() 283 return cfg, nil 284 }