Skip to content

Commit

Permalink
config: Stop server startup if an unrecognized option is found in a c…
Browse files Browse the repository at this point in the history
…onfig file (#9855)
  • Loading branch information
kolbe authored and winkyao committed Apr 8, 2019
1 parent f063e78 commit f514a32
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 9 deletions.
30 changes: 28 additions & 2 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ package config
import (
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"strings"
"time"

"github.com/BurntSushi/toml"
Expand Down Expand Up @@ -108,6 +110,18 @@ type Security struct {
ClusterSSLKey string `toml:"cluster-ssl-key" json:"cluster-ssl-key"`
}

// The ErrConfigValidationFailed error is used so that external callers can do a type assertion
// to defer handling of this specific error when someone does not want strict type checking.
// This is needed only because logging hasn't been set up at the time we parse the config file.
// This should all be ripped out once strict config checking is made the default behavior.
type ErrConfigValidationFailed struct {
err string
}

func (e *ErrConfigValidationFailed) Error() string {
return e.err
}

// ToTLSConfig generates tls's config based on security section of the config.
func (s *Security) ToTLSConfig() (*tls.Config, error) {
var tlsConfig *tls.Config
Expand Down Expand Up @@ -373,11 +387,23 @@ func GetGlobalConfig() *Config {

// Load loads config options from a toml file.
func (c *Config) Load(confFile string) error {
_, err := toml.DecodeFile(confFile, c)
metaData, err := toml.DecodeFile(confFile, c)
if c.TokenLimit <= 0 {
c.TokenLimit = 1000
}
return errors.Trace(err)

// If any items in confFile file are not mapped into the Config struct, issue
// an error and stop the server from starting.
undecoded := metaData.Undecoded()
if len(undecoded) > 0 && err == nil {
var undecodedItems []string
for _, item := range undecoded {
undecodedItems = append(undecodedItems, item.String())
}
err = &ErrConfigValidationFailed{fmt.Sprintf("config file %s contained unknown configuration options: %s", confFile, strings.Join(undecodedItems, ", "))}
}

return err
}

// ToLogConfig converts *Log to *logutil.LogConfig.
Expand Down
20 changes: 17 additions & 3 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,27 @@ func (s *testConfigSuite) TestConfig(c *C) {

f, err := os.Create(configFile)
c.Assert(err, IsNil)
_, err = f.WriteString(`[performance]

// Make sure the server refuses to start if there's an unrecognized configuration option
_, err = f.WriteString(`
unrecognized-option-test = true
`)
c.Assert(err, IsNil)
c.Assert(f.Sync(), IsNil)

c.Assert(conf.Load(configFile), ErrorMatches, "(?:.|\n)*unknown configuration option(?:.|\n)*")

f.Truncate(0)
f.Seek(0, 0)

_, err = f.WriteString(`
token-limit = 0
[performance]
[tikv-client]
commit-timeout="41s"
max-batch-size=128
token-limit = -1
`)

c.Assert(err, IsNil)
c.Assert(f.Sync(), IsNil)

Expand Down
30 changes: 26 additions & 4 deletions tidb-server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ import (
const (
nmVersion = "V"
nmConfig = "config"
nmConfigCheck = "config-check"
nmConfigStrict = "config-strict"
nmStore = "store"
nmStorePath = "path"
nmHost = "host"
Expand Down Expand Up @@ -90,8 +92,10 @@ const (
)

var (
version = flagBoolean(nmVersion, false, "print version information and exit")
configPath = flag.String(nmConfig, "", "config file path")
version = flagBoolean(nmVersion, false, "print version information and exit")
configPath = flag.String(nmConfig, "", "config file path")
configCheck = flagBoolean(nmConfigCheck, false, "check config file validity and exit")
configStrict = flagBoolean(nmConfigStrict, false, "enforce config file validity")

// Base
store = flag.String(nmStore, "mocktikv", "registered store name, [tikv, mocktikv]")
Expand Down Expand Up @@ -141,11 +145,21 @@ func main() {
}
registerStores()
registerMetrics()
loadConfig()
configWarning := loadConfig()
overrideConfig()
validateConfig()
if *configCheck {
fmt.Println("config check successful")
os.Exit(0)
}
setGlobalVars()
setupLog()
// If configStrict had been specified, and there had been an error, the server would already
// have exited by now. If configWarning is not an empty string, write it to the log now that
// it's been properly set up.
if configWarning != "" {
log.Warn(configWarning)
}
setupTracing() // Should before createServer and after setup config.
printInfo()
setupBinlogClient()
Expand Down Expand Up @@ -287,12 +301,20 @@ func flagBoolean(name string, defaultVal bool, usage string) *bool {
return flag.Bool(name, defaultVal, usage)
}

func loadConfig() {
func loadConfig() string {
cfg = config.GetGlobalConfig()
if *configPath != "" {
err := cfg.Load(*configPath)
// This block is to accommodate an interim situation where strict config checking
// is not the default behavior of TiDB. The warning message must be deferred until
// logging has been set up. After strict config checking is the default behavior,
// This should all be removed.
if _, ok := err.(*config.ErrConfigValidationFailed); ok && !*configCheck && !*configStrict {
return err.Error()
}
terror.MustNil(err)
}
return ""
}

func overrideConfig() {
Expand Down

0 comments on commit f514a32

Please sign in to comment.