1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
17 "git.curoverse.com/arvados.git/sdk/go/arvados"
18 "github.com/ghodss/yaml"
19 "github.com/imdario/mergo"
22 type logger interface {
23 Warnf(string, ...interface{})
26 type deprRequestLimits struct {
27 MaxItemsPerResponse *int
28 MultiClusterRequestConcurrency *int
31 type deprCluster struct {
32 RequestLimits deprRequestLimits
33 NodeProfiles map[string]arvados.NodeProfile
36 type deprecatedConfig struct {
37 Clusters map[string]deprCluster
40 func LoadFile(path string, log logger) (*arvados.Config, error) {
41 f, err := os.Open(path)
49 func Load(rdr io.Reader, log logger) (*arvados.Config, error) {
50 var cfg arvados.Config
51 buf, err := ioutil.ReadAll(rdr)
56 // Load the config into a dummy map to get the cluster ID
57 // keys, discarding the values; then set up defaults for each
58 // cluster ID; then load the real config on top of the
61 Clusters map[string]struct{}
63 err = yaml.Unmarshal(buf, &dummy)
67 if len(dummy.Clusters) == 0 {
68 return nil, errors.New("config does not define any clusters")
71 // We can't merge deep structs here; instead, we unmarshal the
72 // default & loaded config files into generic maps, merge
73 // those, and then json-encode+decode the result into the
74 // config struct type.
75 var merged map[string]interface{}
76 for id := range dummy.Clusters {
77 var src map[string]interface{}
78 err = yaml.Unmarshal(bytes.Replace(DefaultYAML, []byte(" xxxxx:"), []byte(" "+id+":"), -1), &src)
80 return nil, fmt.Errorf("loading defaults for %s: %s", id, err)
82 mergo.Merge(&merged, src, mergo.WithOverride)
84 var src map[string]interface{}
85 err = yaml.Unmarshal(buf, &src)
87 return nil, fmt.Errorf("loading config data: %s", err)
89 mergo.Merge(&merged, src, mergo.WithOverride)
94 errEnc = json.NewEncoder(pw).Encode(merged)
97 err = json.NewDecoder(pr).Decode(&cfg)
102 return nil, fmt.Errorf("transcoding config data: %s", err)
105 var dc deprecatedConfig
106 err = yaml.Unmarshal(buf, &dc)
110 err = applyDeprecatedConfig(&cfg, &dc, log)
117 func applyDeprecatedConfig(cfg *arvados.Config, dc *deprecatedConfig, log logger) error {
118 hostname, err := os.Hostname()
122 for id, dcluster := range dc.Clusters {
123 cluster, ok := cfg.Clusters[id]
125 return fmt.Errorf("can't load legacy config %q that is not present in current config", id)
127 for name, np := range dcluster.NodeProfiles {
128 if name == "*" || name == os.Getenv("ARVADOS_NODE_PROFILE") || name == hostname {
129 applyDeprecatedNodeProfile(hostname, np.RailsAPI, &cluster.Services.RailsAPI)
130 applyDeprecatedNodeProfile(hostname, np.Controller, &cluster.Services.Controller)
131 applyDeprecatedNodeProfile(hostname, np.DispatchCloud, &cluster.Services.DispatchCloud)
134 if dst, n := &cluster.API.MaxItemsPerResponse, dcluster.RequestLimits.MaxItemsPerResponse; n != nil && *n != *dst {
135 log.Warnf("overriding Clusters.%s.API.MaxItemsPerResponse with deprecated config RequestLimits.MultiClusterRequestConcurrency = %d", id, *n)
138 if dst, n := &cluster.API.MaxRequestAmplification, dcluster.RequestLimits.MultiClusterRequestConcurrency; n != nil && *n != *dst {
139 log.Warnf("overriding Clusters.%s.API.MaxRequestAmplification with deprecated config RequestLimits.MultiClusterRequestConcurrency = %d", id, *n)
142 cfg.Clusters[id] = cluster
147 func applyDeprecatedNodeProfile(hostname string, ssi arvados.SystemServiceInstance, svc *arvados.Service) {
152 if svc.InternalURLs == nil {
153 svc.InternalURLs = map[arvados.URL]arvados.ServiceInstance{}
159 if strings.HasPrefix(host, ":") {
160 host = hostname + host
162 svc.InternalURLs[arvados.URL{Scheme: scheme, Host: host}] = arvados.ServiceInstance{}