X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/f7c4c3fa0d3d177982a7ff665325ea082a872c99..3d98f9b1196260dbc7b9963dfd295d7e330e23d6:/lib/config/load.go diff --git a/lib/config/load.go b/lib/config/load.go index ec5ce636a0..a0c7695374 100644 --- a/lib/config/load.go +++ b/lib/config/load.go @@ -23,6 +23,14 @@ type logger interface { Warnf(string, ...interface{}) } +func loadFileOrStdin(path string, stdin io.Reader, log logger) (*arvados.Config, error) { + if path == "-" { + return load(stdin, log, true) + } else { + return LoadFile(path, log) + } +} + func LoadFile(path string, log logger) (*arvados.Config, error) { f, err := os.Open(path) if err != nil { @@ -33,6 +41,10 @@ func LoadFile(path string, log logger) (*arvados.Config, error) { } func Load(rdr io.Reader, log logger) (*arvados.Config, error) { + return load(rdr, log, true) +} + +func load(rdr io.Reader, log logger, useDeprecated bool) (*arvados.Config, error) { buf, err := ioutil.ReadAll(rdr) if err != nil { return nil, err @@ -74,6 +86,8 @@ func Load(rdr io.Reader, log logger) (*arvados.Config, error) { if err != nil { return nil, fmt.Errorf("loading config data: %s", err) } + logExtraKeys(log, merged, src, "") + removeSampleKeys(merged) err = mergo.Merge(&merged, src, mergo.WithOverride) if err != nil { return nil, fmt.Errorf("merging config data: %s", err) @@ -95,10 +109,14 @@ func Load(rdr io.Reader, log logger) (*arvados.Config, error) { return nil, fmt.Errorf("transcoding config data: %s", err) } - err = applyDeprecatedConfig(&cfg, buf, log) - if err != nil { - return nil, err + if useDeprecated { + err = applyDeprecatedConfig(&cfg, buf, log) + if err != nil { + return nil, err + } } + + // Check for known mistakes for id, cc := range cfg.Clusters { err = checkKeyConflict(fmt.Sprintf("Clusters.%s.PostgreSQL.Connection", id), cc.PostgreSQL.Connection) if err != nil { @@ -113,9 +131,46 @@ func checkKeyConflict(label string, m map[string]string) error { for k := range m { k = strings.ToLower(k) if saw[k] { - return fmt.Errorf("%s: multiple keys with tolower(key)==%q (use same case as defaults)", label, k) + return fmt.Errorf("%s: multiple entries for %q (fix by using same capitalization as default/example file)", label, k) } saw[k] = true } return nil } + +func removeSampleKeys(m map[string]interface{}) { + delete(m, "SAMPLE") + for _, v := range m { + if v, _ := v.(map[string]interface{}); v != nil { + removeSampleKeys(v) + } + } +} + +func logExtraKeys(log logger, expected, supplied map[string]interface{}, prefix string) { + if log == nil { + return + } + allowed := map[string]interface{}{} + for k, v := range expected { + allowed[strings.ToLower(k)] = v + } + for k, vsupp := range supplied { + vexp, ok := allowed[strings.ToLower(k)] + if !ok && expected["SAMPLE"] != nil { + vexp = expected["SAMPLE"] + } else if !ok { + log.Warnf("deprecated or unknown config entry: %s%s", prefix, k) + continue + } + if vsupp, ok := vsupp.(map[string]interface{}); !ok { + // if vsupp is a map but vexp isn't map, this + // will be caught elsewhere; see TestBadType. + continue + } else if vexp, ok := vexp.(map[string]interface{}); !ok { + log.Warnf("unexpected object in config entry: %s%s", prefix, k) + } else { + logExtraKeys(log, vexp, vsupp, prefix+k+".") + } + } +}