15003: Add 'arvados-server dump-config' command.
[arvados.git] / lib / config / load.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 package config
6
7 import (
8         "bytes"
9         "errors"
10         "fmt"
11         "io"
12         "io/ioutil"
13         "os"
14         "strings"
15
16         "git.curoverse.com/arvados.git/sdk/go/arvados"
17         "github.com/ghodss/yaml"
18 )
19
20 type logger interface {
21         Warnf(string, ...interface{})
22 }
23
24 type deprecatedConfig struct {
25         Clusters map[string]struct {
26                 NodeProfiles map[string]arvados.NodeProfile
27         }
28 }
29
30 func Load(rdr io.Reader, log logger) (*arvados.Config, error) {
31         var cfg arvados.Config
32         buf, err := ioutil.ReadAll(rdr)
33         if err != nil {
34                 return nil, err
35         }
36
37         // Load the config into a dummy map to get the cluster ID
38         // keys, discarding the values; then set up defaults for each
39         // cluster ID; then load the real config on top of the
40         // defaults.
41         var dummy struct {
42                 Clusters map[string]struct{}
43         }
44         err = yaml.Unmarshal(buf, &dummy)
45         if err != nil {
46                 return nil, err
47         }
48         if len(dummy.Clusters) == 0 {
49                 return nil, errors.New("config does not define any clusters")
50         }
51         for id := range dummy.Clusters {
52                 err = yaml.Unmarshal(bytes.Replace(DefaultYAML, []byte("xxxxx"), []byte(id), -1), &cfg)
53                 if err != nil {
54                         return nil, fmt.Errorf("loading defaults for %s: %s", id, err)
55                 }
56         }
57         err = yaml.Unmarshal(buf, &cfg)
58         if err != nil {
59                 return nil, err
60         }
61
62         // Check for deprecated config values, and apply them to cfg.
63         var dc deprecatedConfig
64         err = yaml.Unmarshal(buf, &dc)
65         if err != nil {
66                 return nil, err
67         }
68         err = applyDeprecatedConfig(&cfg, &dc, log)
69         if err != nil {
70                 return nil, err
71         }
72         return &cfg, nil
73 }
74
75 func applyDeprecatedConfig(cfg *arvados.Config, dc *deprecatedConfig, log logger) error {
76         hostname, err := os.Hostname()
77         if err != nil {
78                 return err
79         }
80         for id, dcluster := range dc.Clusters {
81                 cluster, ok := cfg.Clusters[id]
82                 if !ok {
83                         return fmt.Errorf("can't load legacy config %q that is not present in current config", id)
84                 }
85                 for name, np := range dcluster.NodeProfiles {
86                         if name == "*" || name == os.Getenv("ARVADOS_NODE_PROFILE") || name == hostname {
87                                 applyDeprecatedNodeProfile(hostname, np.RailsAPI, &cluster.Services.RailsAPI)
88                                 applyDeprecatedNodeProfile(hostname, np.Controller, &cluster.Services.Controller)
89                                 applyDeprecatedNodeProfile(hostname, np.DispatchCloud, &cluster.Services.DispatchCloud)
90                         }
91                 }
92                 cfg.Clusters[id] = cluster
93         }
94         return nil
95 }
96
97 func applyDeprecatedNodeProfile(hostname string, ssi arvados.SystemServiceInstance, svc *arvados.Service) {
98         scheme := "https"
99         if !ssi.TLS {
100                 scheme = "http"
101         }
102         if svc.InternalURLs == nil {
103                 svc.InternalURLs = map[arvados.URL]arvados.ServiceInstance{}
104         }
105         host := ssi.Listen
106         if host == "" {
107                 return
108         }
109         if strings.HasPrefix(host, ":") {
110                 host = hostname + host
111         }
112         svc.InternalURLs[arvados.URL{Scheme: scheme, Host: host}] = arvados.ServiceInstance{}
113 }