15003: Use config lib for arvados-server.
[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 LoadFile(path string, log logger) (*arvados.Config, error) {
31         f, err := os.Open(path)
32         if err != nil {
33                 return nil, err
34         }
35         defer f.Close()
36         return Load(f, log)
37 }
38
39 func Load(rdr io.Reader, log logger) (*arvados.Config, error) {
40         var cfg arvados.Config
41         buf, err := ioutil.ReadAll(rdr)
42         if err != nil {
43                 return nil, err
44         }
45
46         // Load the config into a dummy map to get the cluster ID
47         // keys, discarding the values; then set up defaults for each
48         // cluster ID; then load the real config on top of the
49         // defaults.
50         var dummy struct {
51                 Clusters map[string]struct{}
52         }
53         err = yaml.Unmarshal(buf, &dummy)
54         if err != nil {
55                 return nil, err
56         }
57         if len(dummy.Clusters) == 0 {
58                 return nil, errors.New("config does not define any clusters")
59         }
60         for id := range dummy.Clusters {
61                 err = yaml.Unmarshal(bytes.Replace(DefaultYAML, []byte("xxxxx"), []byte(id), -1), &cfg)
62                 if err != nil {
63                         return nil, fmt.Errorf("loading defaults for %s: %s", id, err)
64                 }
65         }
66         err = yaml.Unmarshal(buf, &cfg)
67         if err != nil {
68                 return nil, err
69         }
70
71         // Check for deprecated config values, and apply them to cfg.
72         var dc deprecatedConfig
73         err = yaml.Unmarshal(buf, &dc)
74         if err != nil {
75                 return nil, err
76         }
77         err = applyDeprecatedConfig(&cfg, &dc, log)
78         if err != nil {
79                 return nil, err
80         }
81         return &cfg, nil
82 }
83
84 func applyDeprecatedConfig(cfg *arvados.Config, dc *deprecatedConfig, log logger) error {
85         hostname, err := os.Hostname()
86         if err != nil {
87                 return err
88         }
89         for id, dcluster := range dc.Clusters {
90                 cluster, ok := cfg.Clusters[id]
91                 if !ok {
92                         return fmt.Errorf("can't load legacy config %q that is not present in current config", id)
93                 }
94                 for name, np := range dcluster.NodeProfiles {
95                         if name == "*" || name == os.Getenv("ARVADOS_NODE_PROFILE") || name == hostname {
96                                 applyDeprecatedNodeProfile(hostname, np.RailsAPI, &cluster.Services.RailsAPI)
97                                 applyDeprecatedNodeProfile(hostname, np.Controller, &cluster.Services.Controller)
98                                 applyDeprecatedNodeProfile(hostname, np.DispatchCloud, &cluster.Services.DispatchCloud)
99                         }
100                 }
101                 cfg.Clusters[id] = cluster
102         }
103         return nil
104 }
105
106 func applyDeprecatedNodeProfile(hostname string, ssi arvados.SystemServiceInstance, svc *arvados.Service) {
107         scheme := "https"
108         if !ssi.TLS {
109                 scheme = "http"
110         }
111         if svc.InternalURLs == nil {
112                 svc.InternalURLs = map[arvados.URL]arvados.ServiceInstance{}
113         }
114         host := ssi.Listen
115         if host == "" {
116                 return
117         }
118         if strings.HasPrefix(host, ":") {
119                 host = hostname + host
120         }
121         svc.InternalURLs[arvados.URL{Scheme: scheme, Host: host}] = arvados.ServiceInstance{}
122 }