update xds-server package in docker
[src/xds/xds-server.git] / lib / xdsconfig / fileconfig.go
1 /*
2  * Copyright (C) 2017-2018 "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         "os/user"
24         "path"
25         "path/filepath"
26         "strings"
27
28         common "gerrit.automotivelinux.org/gerrit/src/xds/xds-common.git/golib"
29 )
30
31 const (
32         // GlobalConfigFilename Global config filename
33         GlobalConfigFilename = "server-config.json"
34         // ServerDataFilename Server data filename
35         ServerDataFilename = "server-data.xml"
36         // FoldersConfigFilename Folders config filename
37         FoldersConfigFilename = "server-config_folders.xml"
38         // TargetsConfigFilename Targets config filename
39         TargetsConfigFilename = "server-config_targets.xml"
40 )
41
42 // SyncThingConf definition
43 type SyncThingConf struct {
44         BinDir          string `json:"binDir"`
45         Home            string `json:"home"`
46         GuiAddress      string `json:"gui-address"`
47         GuiAPIKey       string `json:"gui-apikey"`
48         RescanIntervalS int    `json:"rescanIntervalS"`
49 }
50
51 // FileConfig is the JSON structure of xds-server config file (server-config.json)
52 type FileConfig struct {
53         WebAppDir              string         `json:"webAppDir"`
54         ShareRootDir           string         `json:"shareRootDir"`
55         SdkScriptsDir          string         `json:"sdkScriptsDir"`
56         XdsSrvUpdateScriptsDir string         `json:"xdsSrvUpdateScriptsDir"`
57         SdkDbUpdate            string         `json:"sdkDbUpdate"`
58         HTTPPort               string         `json:"httpPort"`
59         SThgConf               *SyncThingConf `json:"syncthing"`
60         LogsDir                string         `json:"logsDir"`
61         XdsSrvUpdateTime       string         `json:"xdsSrvUpdateTime"`
62 }
63
64 // readGlobalConfig reads configuration from a config file.
65 // Order to determine which config file is used:
66 //  1/ from command line option: "--config myConfig.json"
67 //  2/ $HOME/.xds/server/server-config.json file
68 //  3/ /etc/xds/server/server-config.json file
69 //  4/ <xds-server executable dir>/server-config.json file
70 func readGlobalConfig(c *Config, confFile string) error {
71
72         searchIn := make([]string, 0, 3)
73         if confFile != "" {
74                 searchIn = append(searchIn, confFile)
75         }
76         if _, err := user.Current(); err == nil {
77                 searchIn = append(searchIn, path.Join(ConfigRootDir(), GlobalConfigFilename))
78         }
79
80         searchIn = append(searchIn, "/etc/xds/server/server-config.json")
81
82         exePath := os.Args[0]
83         ee, _ := os.Executable()
84         exeAbsPath, err := filepath.Abs(ee)
85         if err == nil {
86                 exePath, err = filepath.EvalSymlinks(exeAbsPath)
87                 if err == nil {
88                         exePath = filepath.Dir(ee)
89                 } else {
90                         exePath = filepath.Dir(exeAbsPath)
91                 }
92         }
93         searchIn = append(searchIn, path.Join(exePath, "server-config.json"))
94
95         var cFile *string
96         for _, p := range searchIn {
97                 if _, err := os.Stat(p); err == nil {
98                         cFile = &p
99                         break
100                 }
101         }
102         if cFile == nil {
103                 // No config file found
104                 return nil
105         }
106         c.Log.Infof("Use config file:       %s", *cFile)
107
108         // TODO move on viper package to support comments in JSON and also
109         // bind with flags (command line options)
110         // see https://github.com/spf13/viper#working-with-flags
111         fd, _ := os.Open(*cFile)
112         defer fd.Close()
113         fCfg := FileConfig{}
114         if err := json.NewDecoder(fd).Decode(&fCfg); err != nil {
115                 return err
116         }
117
118         // Support environment variables (IOW ${MY_ENV_VAR} syntax) in server-config.json
119         vars := []*string{
120                 &fCfg.WebAppDir,
121                 &fCfg.ShareRootDir,
122                 &fCfg.SdkScriptsDir,
123                 &fCfg.XdsSrvUpdateScriptsDir,
124                 &fCfg.LogsDir,
125                 &fCfg.XdsSrvUpdateTime}
126         if fCfg.SThgConf != nil {
127                 vars = append(vars, &fCfg.SThgConf.Home, &fCfg.SThgConf.BinDir)
128         }
129         for _, field := range vars {
130                 var err error
131                 if *field, err = common.ResolveEnvVar(*field); err != nil {
132                         return err
133                 }
134         }
135
136         // Use config file settings else use default config
137         if fCfg.WebAppDir == "" {
138                 fCfg.WebAppDir = c.FileConf.WebAppDir
139         }
140         if fCfg.ShareRootDir == "" {
141                 fCfg.ShareRootDir = c.FileConf.ShareRootDir
142         }
143         if fCfg.SdkScriptsDir == "" {
144                 fCfg.SdkScriptsDir = c.FileConf.SdkScriptsDir
145         }
146         if fCfg.XdsSrvUpdateScriptsDir == "" {
147                 fCfg.XdsSrvUpdateScriptsDir = c.FileConf.XdsSrvUpdateScriptsDir
148         }
149         if fCfg.SdkDbUpdate == "" {
150                 fCfg.SdkDbUpdate = c.FileConf.SdkDbUpdate
151         }
152         if fCfg.HTTPPort == "" {
153                 fCfg.HTTPPort = c.FileConf.HTTPPort
154         }
155         if fCfg.LogsDir == "" {
156                 fCfg.LogsDir = c.FileConf.LogsDir
157         }
158         if fCfg.XdsSrvUpdateTime == "" {
159                 fCfg.XdsSrvUpdateTime = c.FileConf.XdsSrvUpdateTime
160         }
161
162         // Resolve webapp dir (support relative or full path)
163         fCfg.WebAppDir = strings.Trim(fCfg.WebAppDir, " ")
164         if !strings.HasPrefix(fCfg.WebAppDir, "/") && exePath != "" {
165                 cwd, _ := os.Getwd()
166
167                 // Check first from current directory
168                 for _, rootD := range []string{exePath, cwd} {
169                         ff := path.Join(rootD, fCfg.WebAppDir, "index.html")
170                         if common.Exists(ff) {
171                                 fCfg.WebAppDir = path.Join(rootD, fCfg.WebAppDir)
172                                 break
173                         }
174                 }
175         }
176
177         c.FileConf = fCfg
178         return nil
179 }
180
181 func configFilenameGet(cfgFile string) (string, error) {
182         return path.Join(ConfigRootDir(), cfgFile), nil
183 }
184
185 // FoldersConfigFilenameGet Return the FoldersConfig filename
186 func FoldersConfigFilenameGet() (string, error) {
187         return configFilenameGet(FoldersConfigFilename)
188 }
189
190 // TargetsConfigFilenameGet Return the TargetsConfig filename
191 func TargetsConfigFilenameGet() (string, error) {
192         return configFilenameGet(TargetsConfigFilename)
193 }
194
195 // ServerDataFilenameGet Return the ServerData filename
196 func ServerDataFilenameGet() (string, error) {
197         return configFilenameGet(ServerDataFilename)
198 }