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