X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/6a08de4e6d04ed9706ae5f6502c9ff3d26a8bc0e..f7c4c3fa0d3d177982a7ff665325ea082a872c99:/lib/config/load.go diff --git a/lib/config/load.go b/lib/config/load.go index 159dd65dc0..ec5ce636a0 100644 --- a/lib/config/load.go +++ b/lib/config/load.go @@ -6,6 +6,7 @@ package config import ( "bytes" + "encoding/json" "errors" "fmt" "io" @@ -15,18 +16,13 @@ import ( "git.curoverse.com/arvados.git/sdk/go/arvados" "github.com/ghodss/yaml" + "github.com/imdario/mergo" ) type logger interface { Warnf(string, ...interface{}) } -type deprecatedConfig struct { - Clusters map[string]struct { - NodeProfiles map[string]arvados.NodeProfile - } -} - func LoadFile(path string, log logger) (*arvados.Config, error) { f, err := os.Open(path) if err != nil { @@ -37,7 +33,6 @@ func LoadFile(path string, log logger) (*arvados.Config, error) { } func Load(rdr io.Reader, log logger) (*arvados.Config, error) { - var cfg arvados.Config buf, err := ioutil.ReadAll(rdr) if err != nil { return nil, err @@ -57,66 +52,70 @@ func Load(rdr io.Reader, log logger) (*arvados.Config, error) { if len(dummy.Clusters) == 0 { return nil, errors.New("config does not define any clusters") } + + // We can't merge deep structs here; instead, we unmarshal the + // default & loaded config files into generic maps, merge + // those, and then json-encode+decode the result into the + // config struct type. + var merged map[string]interface{} for id := range dummy.Clusters { - err = yaml.Unmarshal(bytes.Replace(DefaultYAML, []byte("xxxxx"), []byte(id), -1), &cfg) + var src map[string]interface{} + err = yaml.Unmarshal(bytes.Replace(DefaultYAML, []byte(" xxxxx:"), []byte(" "+id+":"), -1), &src) if err != nil { return nil, fmt.Errorf("loading defaults for %s: %s", id, err) } + err = mergo.Merge(&merged, src, mergo.WithOverride) + if err != nil { + return nil, fmt.Errorf("merging defaults for %s: %s", id, err) + } } - err = yaml.Unmarshal(buf, &cfg) + var src map[string]interface{} + err = yaml.Unmarshal(buf, &src) if err != nil { - return nil, err + return nil, fmt.Errorf("loading config data: %s", err) } - - // Check for deprecated config values, and apply them to cfg. - var dc deprecatedConfig - err = yaml.Unmarshal(buf, &dc) + err = mergo.Merge(&merged, src, mergo.WithOverride) if err != nil { - return nil, err + return nil, fmt.Errorf("merging config data: %s", err) + } + + // map[string]interface{} => json => arvados.Config + var cfg arvados.Config + var errEnc error + pr, pw := io.Pipe() + go func() { + errEnc = json.NewEncoder(pw).Encode(merged) + pw.Close() + }() + err = json.NewDecoder(pr).Decode(&cfg) + if errEnc != nil { + err = errEnc } - err = applyDeprecatedConfig(&cfg, &dc, log) if err != nil { - return nil, err + return nil, fmt.Errorf("transcoding config data: %s", err) } - return &cfg, nil -} -func applyDeprecatedConfig(cfg *arvados.Config, dc *deprecatedConfig, log logger) error { - hostname, err := os.Hostname() + err = applyDeprecatedConfig(&cfg, buf, log) if err != nil { - return err + return nil, err } - for id, dcluster := range dc.Clusters { - cluster, ok := cfg.Clusters[id] - if !ok { - return fmt.Errorf("can't load legacy config %q that is not present in current config", id) - } - for name, np := range dcluster.NodeProfiles { - if name == "*" || name == os.Getenv("ARVADOS_NODE_PROFILE") || name == hostname { - applyDeprecatedNodeProfile(hostname, np.RailsAPI, &cluster.Services.RailsAPI) - applyDeprecatedNodeProfile(hostname, np.Controller, &cluster.Services.Controller) - applyDeprecatedNodeProfile(hostname, np.DispatchCloud, &cluster.Services.DispatchCloud) - } + for id, cc := range cfg.Clusters { + err = checkKeyConflict(fmt.Sprintf("Clusters.%s.PostgreSQL.Connection", id), cc.PostgreSQL.Connection) + if err != nil { + return nil, err } - cfg.Clusters[id] = cluster } - return nil + return &cfg, nil } -func applyDeprecatedNodeProfile(hostname string, ssi arvados.SystemServiceInstance, svc *arvados.Service) { - scheme := "https" - if !ssi.TLS { - scheme = "http" - } - if svc.InternalURLs == nil { - svc.InternalURLs = map[arvados.URL]arvados.ServiceInstance{} - } - host := ssi.Listen - if host == "" { - return - } - if strings.HasPrefix(host, ":") { - host = hostname + host +func checkKeyConflict(label string, m map[string]string) error { + saw := map[string]bool{} + 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) + } + saw[k] = true } - svc.InternalURLs[arvados.URL{Scheme: scheme, Host: host}] = arvados.ServiceInstance{} + return nil }