Always resolved env vars in path of config structure.
[src/xds/xds-agent.git] / lib / xdsconfig / configfile.go
1 /*
2  * Copyright (C) 2017 "IoT.bzh"
3  * Author Sebastien Douheret <sebastien@iot.bzh>
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 package xdsconfig
19
20 import (
21         "encoding/json"
22         "os"
23         "path"
24
25         common "github.com/iotbzh/xds-common/golib"
26 )
27
28 type SyncThingConf struct {
29         BinDir     string `json:"binDir"`
30         Home       string `json:"home"`
31         GuiAddress string `json:"gui-address"`
32         GuiAPIKey  string `json:"gui-apikey"`
33 }
34
35 type XDSServerConf struct {
36         URL       string `json:"url"`
37         ConnRetry int    `json:"connRetry"`
38
39         // private/not exported fields
40         ID            string `json:"-"`
41         APIBaseURL    string `json:"-"`
42         APIPartialURL string `json:"-"`
43 }
44
45 type FileConfig struct {
46         HTTPPort    string          `json:"httpPort"`
47         WebAppDir   string          `json:"webAppDir"`
48         LogsDir     string          `json:"logsDir"`
49         XDSAPIKey   string          `json:"xds-apikey"`
50         ServersConf []XDSServerConf `json:"xdsServers"`
51         SThgConf    *SyncThingConf  `json:"syncthing"`
52 }
53
54 // readGlobalConfig reads configuration from a config file.
55 // Order to determine which config file is used:
56 //  1/ from command line option: "--config myConfig.json"
57 //  2/ $HOME/.xds/agent/agent-config.json file
58 //  3/ /etc/xds/agent/agent-config.json file
59
60 func readGlobalConfig(c *Config, confFile string) error {
61
62         var fd *os.File
63         var fCfg = FileConfig{}
64
65         searchIn := make([]string, 0, 3)
66         if confFile != "" {
67                 searchIn = append(searchIn, confFile)
68         }
69         if homeDir := common.GetUserHome(); homeDir != "" {
70                 searchIn = append(searchIn, path.Join(homeDir, ".xds", "agent", "agent-config.json"))
71         }
72
73         searchIn = append(searchIn, "/etc/xds/agent/agent-config.json")
74
75         var cFile *string
76         for _, p := range searchIn {
77                 if _, err := os.Stat(p); err == nil {
78                         cFile = &p
79                         break
80                 }
81         }
82         if cFile == nil {
83                 c.Log.Infof("No config file found")
84                 // always resolved env vars even if no config file found!
85                 goto resVars
86         }
87
88         c.Log.Infof("Use config file: %s", *cFile)
89
90         // TODO move on viper package to support comments in JSON and also
91         // bind with flags (command line options)
92         // see https://github.com/spf13/viper#working-with-flags
93
94         fd, _ = os.Open(*cFile)
95         defer func() {
96                 if fd != nil {
97                         fd.Close()
98                 }
99         }()
100
101         // Decode config file content and save it in a first variable
102         if err := json.NewDecoder(fd).Decode(&fCfg); err != nil {
103                 return err
104         }
105
106         // Decode config file content and overwrite default settings
107         fd.Seek(0, 0)
108         json.NewDecoder(fd).Decode(&c.FileConf)
109
110         // Disable Syncthing support when there is no syncthing field in config
111         if fCfg.SThgConf == nil {
112                 c.FileConf.SThgConf = nil
113         }
114
115         // Support environment variables (IOW ${MY_ENV_VAR} syntax) in agent-config.json
116 resVars:
117         vars := []*string{
118                 &c.FileConf.LogsDir,
119                 &c.FileConf.WebAppDir,
120         }
121         if c.FileConf.SThgConf != nil {
122                 vars = append(vars, &c.FileConf.SThgConf.Home,
123                         &c.FileConf.SThgConf.BinDir)
124         }
125         for _, field := range vars {
126                 var err error
127                 *field, err = common.ResolveEnvVar(*field)
128                 if err != nil {
129                         return err
130                 }
131         }
132
133         return nil
134 }