+/*
+ * Copyright (C) 2017-2018 "IoT.bzh"
+ * Author Sebastien Douheret <sebastien@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package xdsconfig
import (
"encoding/json"
- "fmt"
"os"
"os/user"
"path"
"path/filepath"
- "regexp"
"strings"
+
+ common "gerrit.automotivelinux.org/gerrit/src/xds/xds-common.git"
)
+const (
+ // GlobalConfigFilename Global config filename
+ GlobalConfigFilename = "server-config.json"
+ // ServerDataFilename Server data filename
+ ServerDataFilename = "server-data.xml"
+ // FoldersConfigFilename Folders config filename
+ FoldersConfigFilename = "server-config_folders.xml"
+ // TargetsConfigFilename Targets config filename
+ TargetsConfigFilename = "server-config_targets.xml"
+)
+
+// SyncThingConf definition
type SyncThingConf struct {
- BinDir string `json:"binDir"`
- Home string `json:"home"`
- GuiAddress string `json:"gui-address"`
- GuiAPIKey string `json:"gui-apikey"`
+ BinDir string `json:"binDir"`
+ Home string `json:"home"`
+ GuiAddress string `json:"gui-address"`
+ GuiAPIKey string `json:"gui-apikey"`
+ RescanIntervalS int `json:"rescanIntervalS"`
}
+// FileConfig is the JSON structure of xds-server config file (server-config.json)
type FileConfig struct {
- WebAppDir string `json:"webAppDir"`
- ShareRootDir string `json:"shareRootDir"`
- HTTPPort string `json:"httpPort"`
- SThgConf *SyncThingConf `json:"syncthing"`
- LogsDir string `json:"logsDir"`
+ WebAppDir string `json:"webAppDir"`
+ ShareRootDir string `json:"shareRootDir"`
+ SdkScriptsDir string `json:"sdkScriptsDir"`
+ XdsUtilsScriptsDir string `json:"xdsUtilsScriptsDir"`
+ SdkDbUpdate string `json:"sdkDbUpdate"`
+ HTTPPort string `json:"httpPort"`
+ SThgConf *SyncThingConf `json:"syncthing"`
+ LogsDir string `json:"logsDir"`
+ XdsSrvUpdateTime string `json:"xdsSrvUpdateTime"`
}
-// getConfigFromFile reads configuration from a config file.
+// readGlobalConfig reads configuration from a config file.
// Order to determine which config file is used:
// 1/ from command line option: "--config myConfig.json"
-// 2/ $HOME/.xds/config.json file
-// 3/ <current_dir>/config.json file
-// 4/ <xds-server executable dir>/config.json file
-
-func updateConfigFromFile(c *Config, confFile string) error {
+// 2/ $HOME/.xds/server/server-config.json file
+// 3/ /etc/xds/server/server-config.json file
+// 4/ <xds-server executable dir>/server-config.json file
+func readGlobalConfig(c *Config, confFile string) error {
searchIn := make([]string, 0, 3)
if confFile != "" {
searchIn = append(searchIn, confFile)
}
- if usr, err := user.Current(); err == nil {
- searchIn = append(searchIn, path.Join(usr.HomeDir, ".xds", "config.json"))
+ if _, err := user.Current(); err == nil {
+ searchIn = append(searchIn, path.Join(ConfigRootDir(), GlobalConfigFilename))
}
- cwd, err := os.Getwd()
- if err == nil {
- searchIn = append(searchIn, path.Join(cwd, "config.json"))
- }
- exePath, err := filepath.Abs(filepath.Dir(os.Args[0]))
+
+ searchIn = append(searchIn, "/etc/xds/server/server-config.json")
+
+ exePath := os.Args[0]
+ ee, _ := os.Executable()
+ exeAbsPath, err := filepath.Abs(ee)
if err == nil {
- searchIn = append(searchIn, path.Join(exePath, "config.json"))
+ exePath, err = filepath.EvalSymlinks(exeAbsPath)
+ if err == nil {
+ exePath = filepath.Dir(ee)
+ } else {
+ exePath = filepath.Dir(exeAbsPath)
+ }
}
+ searchIn = append(searchIn, path.Join(exePath, "server-config.json"))
var cFile *string
for _, p := range searchIn {
// No config file found
return nil
}
-
- c.Log.Infof("Use config file: %s", *cFile)
+ c.Log.Infof("Use config file: %s", *cFile)
// TODO move on viper package to support comments in JSON and also
// bind with flags (command line options)
// see https://github.com/spf13/viper#working-with-flags
-
fd, _ := os.Open(*cFile)
defer fd.Close()
fCfg := FileConfig{}
if err := json.NewDecoder(fd).Decode(&fCfg); err != nil {
return err
}
- c.FileConf = fCfg
- // Support environment variables (IOW ${MY_ENV_VAR} syntax) in config.json
- // TODO: better to use reflect package to iterate on fields and be more generic
- var rep string
- if rep, err = resolveEnvVar(fCfg.WebAppDir); err != nil {
- return err
+ // Support environment variables (IOW ${MY_ENV_VAR} syntax) in server-config.json
+ vars := []*string{
+ &fCfg.WebAppDir,
+ &fCfg.ShareRootDir,
+ &fCfg.SdkScriptsDir,
+ &fCfg.XdsUtilsScriptsDir,
+ &fCfg.LogsDir,
+ &fCfg.XdsSrvUpdateTime}
+ if fCfg.SThgConf != nil {
+ vars = append(vars, &fCfg.SThgConf.Home, &fCfg.SThgConf.BinDir)
}
- fCfg.WebAppDir = path.Clean(rep)
-
- if rep, err = resolveEnvVar(fCfg.ShareRootDir); err != nil {
- return err
+ // Use config file settings else use default config
+ if fCfg.WebAppDir == "" {
+ fCfg.WebAppDir = c.FileConf.WebAppDir
+ }
+ if fCfg.ShareRootDir == "" {
+ fCfg.ShareRootDir = c.FileConf.ShareRootDir
+ }
+ if fCfg.SdkScriptsDir == "" {
+ fCfg.SdkScriptsDir = c.FileConf.SdkScriptsDir
+ }
+ if fCfg.XdsUtilsScriptsDir == "" {
+ fCfg.XdsUtilsScriptsDir = c.FileConf.XdsUtilsScriptsDir
+ }
+ if fCfg.SdkDbUpdate == "" {
+ fCfg.SdkDbUpdate = c.FileConf.SdkDbUpdate
+ }
+ if fCfg.HTTPPort == "" {
+ fCfg.HTTPPort = c.FileConf.HTTPPort
+ }
+ if fCfg.LogsDir == "" {
+ fCfg.LogsDir = c.FileConf.LogsDir
+ }
+ if fCfg.XdsSrvUpdateTime == "" {
+ fCfg.XdsSrvUpdateTime = c.FileConf.XdsSrvUpdateTime
}
- fCfg.ShareRootDir = path.Clean(rep)
- if rep, err = resolveEnvVar(fCfg.SThgConf.Home); err != nil {
- return err
+ for _, field := range vars {
+ var err error
+ if *field, err = common.ResolveEnvVar(*field); err != nil {
+ return err
+ }
}
- fCfg.SThgConf.Home = path.Clean(rep)
- // Config file settings overwrite default config
+ // Resolve webapp dir (support relative or full path)
+ fCfg.WebAppDir = strings.Trim(fCfg.WebAppDir, " ")
+ if !strings.HasPrefix(fCfg.WebAppDir, "/") && exePath != "" {
+ cwd, _ := os.Getwd()
- if fCfg.WebAppDir != "" {
- c.WebAppDir = strings.Trim(fCfg.WebAppDir, " ")
- }
- // Is it a full path ?
- if !strings.HasPrefix(c.WebAppDir, "/") && exePath != "" {
// Check first from current directory
- for _, rootD := range []string{cwd, exePath} {
- ff := path.Join(rootD, c.WebAppDir, "index.html")
- if exists(ff) {
- c.WebAppDir = path.Join(rootD, c.WebAppDir)
+ for _, rootD := range []string{exePath, cwd} {
+ ff := path.Join(rootD, fCfg.WebAppDir, "index.html")
+ if common.Exists(ff) {
+ fCfg.WebAppDir = path.Join(rootD, fCfg.WebAppDir)
break
}
}
}
- if fCfg.ShareRootDir != "" {
- c.ShareRootDir = fCfg.ShareRootDir
- }
-
- if fCfg.HTTPPort != "" {
- c.HTTPPort = fCfg.HTTPPort
- }
-
+ c.FileConf = fCfg
return nil
}
-// resolveEnvVar Resolved environment variable regarding the syntax ${MYVAR}
-func resolveEnvVar(s string) (string, error) {
- re := regexp.MustCompile("\\${(.*)}")
- vars := re.FindAllStringSubmatch(s, -1)
- res := s
- for _, v := range vars {
- val := os.Getenv(v[1])
- if val == "" {
- return res, fmt.Errorf("ERROR: %s env variable not defined", v[1])
- }
+func configFilenameGet(cfgFile string) (string, error) {
+ return path.Join(ConfigRootDir(), cfgFile), nil
+}
- rer := regexp.MustCompile("\\${" + v[1] + "}")
- res = rer.ReplaceAllString(res, val)
- }
+// FoldersConfigFilenameGet Return the FoldersConfig filename
+func FoldersConfigFilenameGet() (string, error) {
+ return configFilenameGet(FoldersConfigFilename)
+}
- return res, nil
+// TargetsConfigFilenameGet Return the TargetsConfig filename
+func TargetsConfigFilenameGet() (string, error) {
+ return configFilenameGet(TargetsConfigFilename)
}
-// exists returns whether the given file or directory exists or not
-func exists(path string) bool {
- _, err := os.Stat(path)
- if err == nil {
- return true
- }
- if os.IsNotExist(err) {
- return false
- }
- return true
+// ServerDataFilenameGet Return the ServerData filename
+func ServerDataFilenameGet() (string, error) {
+ return configFilenameGet(ServerDataFilename)
}