13647: Suppress "exit status 1" after config-check diff output.
[arvados.git] / lib / config / load.go
index ec5ce636a0eb520115be4d8301f7ea4adfd95ebd..a0c769537487cce179ff74d65035144ef647b561 100644 (file)
@@ -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+".")
+               }
+       }
+}