diff options
Diffstat (limited to 'lib/xdsconfig')
-rw-r--r-- | lib/xdsconfig/config.go | 65 | ||||
-rw-r--r-- | lib/xdsconfig/fileconfig.go | 120 |
2 files changed, 185 insertions, 0 deletions
diff --git a/lib/xdsconfig/config.go b/lib/xdsconfig/config.go new file mode 100644 index 0000000..1f53cbd --- /dev/null +++ b/lib/xdsconfig/config.go @@ -0,0 +1,65 @@ +package xdsconfig + +import ( + "fmt" + + "os" + + "github.com/Sirupsen/logrus" + "github.com/codegangsta/cli" +) + +// Config parameters (json format) of /config command +type Config struct { + Version string `json:"version"` + APIVersion string `json:"apiVersion"` + VersionGitTag string `json:"gitTag"` + + // Private / un-exported fields + HTTPPort string `json:"-"` + FileConf *FileConfig + log *logrus.Logger +} + +// Config default values +const ( + DefaultAPIVersion = "1" + DefaultPort = "8010" + DefaultLogLevel = "error" +) + +// Init loads the configuration on start-up +func Init(ctx *cli.Context, log *logrus.Logger) (Config, error) { + var err error + + // Define default configuration + c := Config{ + Version: ctx.App.Metadata["version"].(string), + APIVersion: DefaultAPIVersion, + VersionGitTag: ctx.App.Metadata["git-tag"].(string), + + HTTPPort: DefaultPort, + log: log, + } + + // config file settings overwrite default config + c.FileConf, err = updateConfigFromFile(&c, ctx.GlobalString("config")) + if err != nil { + return Config{}, err + } + + return c, nil +} + +// UpdateAll Update the current configuration +func (c *Config) UpdateAll(newCfg Config) error { + return fmt.Errorf("Not Supported") +} + +func dirExists(path string) bool { + _, err := os.Stat(path) + if os.IsNotExist(err) { + return false + } + return true +} diff --git a/lib/xdsconfig/fileconfig.go b/lib/xdsconfig/fileconfig.go new file mode 100644 index 0000000..0c4828c --- /dev/null +++ b/lib/xdsconfig/fileconfig.go @@ -0,0 +1,120 @@ +package xdsconfig + +import ( + "encoding/json" + "fmt" + "os" + "os/user" + "path" + "path/filepath" + "regexp" +) + +type SyncThingConf struct { + BinDir string `json:"binDir"` + Home string `json:"home"` + GuiAddress string `json:"gui-address"` + GuiAPIKey string `json:"gui-apikey"` +} + +type FileConfig struct { + HTTPPort string `json:"httpPort"` + SThgConf *SyncThingConf `json:"syncthing"` +} + +// getConfigFromFile 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/agent-config.json file +// 3/ <current_dir>/agent-config.json file +// 4/ <executable dir>/agent-config.json file + +func updateConfigFromFile(c *Config, confFile string) (*FileConfig, 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", "agent-config.json")) + } + cwd, err := os.Getwd() + if err == nil { + searchIn = append(searchIn, path.Join(cwd, "agent-config.json")) + } + exePath, err := filepath.Abs(filepath.Dir(os.Args[0])) + if err == nil { + searchIn = append(searchIn, path.Join(exePath, "agent-config.json")) + } + + var cFile *string + for _, p := range searchIn { + if _, err := os.Stat(p); err == nil { + cFile = &p + break + } + } + fCfg := FileConfig{} + if cFile == nil { + // No config file found + return &fCfg, nil + } + + 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() + if err := json.NewDecoder(fd).Decode(&fCfg); err != nil { + return nil, err + } + + // Support environment variables (IOW ${MY_ENV_VAR} syntax) in agent-config.json + // TODO: better to use reflect package to iterate on fields and be more generic + var rep string + + if rep, err = resolveEnvVar(fCfg.SThgConf.BinDir); err != nil { + return nil, err + } + fCfg.SThgConf.BinDir = path.Clean(rep) + + if rep, err = resolveEnvVar(fCfg.SThgConf.Home); err != nil { + return nil, err + } + fCfg.SThgConf.Home = path.Clean(rep) + + return &fCfg, 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]) + } + + rer := regexp.MustCompile("\\${" + v[1] + "}") + res = rer.ReplaceAllString(res, val) + } + + return res, nil +} + +// 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 +} |