X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=lib%2Fxdsconfig%2Fconfig.go;h=ad3346a8a29b253396f39061971b4c32a95bda8e;hb=5dc2ff003106f0ced38caadb06033f24c792f9b9;hp=801891b3ced56243dfabcbc0989ccea5983e02a1;hpb=87f390b37d51a4c8777d27836389e86e78c690d1;p=src%2Fxds%2Fxds-server.git diff --git a/lib/xdsconfig/config.go b/lib/xdsconfig/config.go index 801891b..ad3346a 100644 --- a/lib/xdsconfig/config.go +++ b/lib/xdsconfig/config.go @@ -1,237 +1,196 @@ +/* + * Copyright (C) 2017-2018 "IoT.bzh" + * Author Sebastien Douheret + * + * 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 ( "fmt" - "strings" - + "io" "os" + "os/user" + "path" + "path/filepath" - "time" - + common "gerrit.automotivelinux.org/gerrit/src/xds/xds-common.git" + "gerrit.automotivelinux.org/gerrit/src/xds/xds-server.git/lib/xsapiv1" "github.com/Sirupsen/logrus" "github.com/codegangsta/cli" - "github.com/iotbzh/xds-server/lib/syncthing" ) // Config parameters (json format) of /config command type Config struct { - Version string `json:"version"` - APIVersion string `json:"apiVersion"` - VersionGitTag string `json:"gitTag"` - Builder BuilderConfig `json:"builder"` - Folders FoldersConfig `json:"folders"` - - // Private / un-exported fields - progName string - fileConf FileConfig - WebAppDir string `json:"-"` - HTTPPort string `json:"-"` - ShareRootDir string `json:"-"` - Log *logrus.Logger `json:"-"` - SThg *st.SyncThing `json:"-"` + // Public APIConfig fields + xsapiv1.APIConfig + + // Private (un-exported fields in REST GET /config route) + Options Options `json:"-"` + FileConf FileConfig `json:"-"` + Log *logrus.Logger `json:"-"` + LogVerboseOut io.Writer `json:"-"` +} + +// Options set at the command line +type Options struct { + ConfigFile string + LogLevel string + LogFile string + NoFolderConfig bool } // Config default values const ( - DefaultAPIVersion = "1" - DefaultPort = "8000" - DefaultShareDir = "/mnt/share" - DefaultLogLevel = "error" + DefaultAPIVersion = "1" + DefaultPort = "8000" + DefaultShareDir = "projects" + DefaultSTHomeDir = "syncthing-config" + DefaultSdkScriptsDir = "${EXEPATH}/sdks" + DefaultXdsUtilsScriptsDir = "${EXEPATH}/xds-utils" + DefaultSdkDbUpdate = "startup" + DefaultXdsSrvUpdateTime = "24h" ) // Init loads the configuration on start-up -func Init(ctx *cli.Context) (Config, error) { +func Init(cliCtx *cli.Context, log *logrus.Logger) (*Config, error) { var err error - // Set logger level and formatter - log := ctx.App.Metadata["logger"].(*logrus.Logger) - - logLevel := ctx.GlobalString("log") - if logLevel == "" { - logLevel = DefaultLogLevel + dfltShareDir := path.Join(ConfigRootDir(), DefaultShareDir) + dfltSTHomeDir := path.Join(ConfigRootDir(), DefaultSTHomeDir) + if resDir, err := common.ResolveEnvVar(dfltShareDir); err == nil { + dfltShareDir = resDir } - if log.Level, err = logrus.ParseLevel(logLevel); err != nil { - fmt.Printf("Invalid log level : \"%v\"\n", logLevel) - os.Exit(1) + if resDir, err := common.ResolveEnvVar(dfltSTHomeDir); err == nil { + dfltSTHomeDir = resDir + } + + // Retrieve Server ID (or create one the first time) + uuid, err := ServerIDGet() + if err != nil { + return nil, err } - log.Formatter = &logrus.TextFormatter{} // Define default configuration c := Config{ - Version: ctx.App.Metadata["version"].(string), - APIVersion: DefaultAPIVersion, - VersionGitTag: ctx.App.Metadata["git-tag"].(string), - Builder: BuilderConfig{}, - Folders: FoldersConfig{}, - - progName: ctx.App.Name, - WebAppDir: "webapp/dist", - HTTPPort: DefaultPort, - ShareRootDir: DefaultShareDir, - Log: log, - SThg: nil, + APIConfig: xsapiv1.APIConfig{ + ServerUID: uuid, + Version: cliCtx.App.Metadata["version"].(string), + APIVersion: DefaultAPIVersion, + VersionGitTag: cliCtx.App.Metadata["git-tag"].(string), + Builder: xsapiv1.BuilderConfig{}, + SupportedSharing: map[string]bool{xsapiv1.TypePathMap: true}, + }, + + Options: Options{ + ConfigFile: cliCtx.GlobalString("config"), + LogLevel: cliCtx.GlobalString("log"), + LogFile: cliCtx.GlobalString("logfile"), + NoFolderConfig: cliCtx.GlobalBool("no-folderconfig"), + }, + FileConf: FileConfig{ + WebAppDir: "www", + ShareRootDir: dfltShareDir, + SdkScriptsDir: DefaultSdkScriptsDir, + XdsUtilsScriptsDir: DefaultXdsUtilsScriptsDir, + SdkDbUpdate: DefaultSdkDbUpdate, + HTTPPort: DefaultPort, + SThgConf: &SyncThingConf{Home: dfltSTHomeDir}, + LogsDir: "", + XdsSrvUpdateTime: DefaultXdsSrvUpdateTime, + }, + Log: log, } + c.Log.Infoln("Server UUID: ", uuid) + // config file settings overwrite default config - err = updateConfigFromFile(&c, ctx.GlobalString("config")) + err = readGlobalConfig(&c, c.Options.ConfigFile) if err != nil { - return Config{}, err + return nil, err } // Update location of shared dir if needed - if !dirExists(c.ShareRootDir) { - if err := os.MkdirAll(c.ShareRootDir, 0770); err != nil { - c.Log.Fatalf("No valid shared directory found (err=%v)", err) + if !common.Exists(c.FileConf.ShareRootDir) { + if err := os.MkdirAll(c.FileConf.ShareRootDir, 0770); err != nil { + return nil, fmt.Errorf("No valid shared directory found: %v", err) } } - c.Log.Infoln("Share root directory: ", c.ShareRootDir) - - // FIXME - add a builder interface and support other builder type (eg. native) - builderType := "syncthing" - - switch builderType { - case "syncthing": - // Syncthing settings only configurable from config.json file - stGuiAddr := c.fileConf.SThgConf.GuiAddress - stGuiApikey := c.fileConf.SThgConf.GuiAPIKey - if stGuiAddr == "" { - stGuiAddr = "http://localhost:8384" - } - if stGuiAddr[0:7] != "http://" { - stGuiAddr = "http://" + stGuiAddr - } - - // Retry if connection fail - retry := 5 - for retry > 0 { - c.SThg = st.NewSyncThing(stGuiAddr, stGuiApikey, c.Log) - if c.SThg != nil { - break + c.Log.Infoln("Share root directory: ", c.FileConf.ShareRootDir) + + // Where Logs are redirected: + // default 'stdout' (logfile option default value) + // else use file (or filepath) set by --logfile option + // that may be overwritten by LogsDir field of config file + logF := c.Options.LogFile + logD := c.FileConf.LogsDir + if logF != "stdout" { + if logD != "" { + lf := filepath.Base(logF) + if lf == "" || lf == "." { + lf = "xds-server.log" } - c.Log.Warningf("Establishing connection to Syncthing (retry %d/5)", retry) - time.Sleep(time.Second) - retry-- - } - if c.SThg == nil { - c.Log.Fatalf("ERROR: cannot connect to Syncthing (url: %s)", stGuiAddr) - } - - // Retrieve Syncthing config - id, err := c.SThg.IDGet() - if err != nil { - return Config{}, err - } - - if c.Builder, err = NewBuilderConfig(id); err != nil { - c.Log.Fatalln(err) - } - - // Retrieve initial Syncthing config - stCfg, err := c.SThg.ConfigGet() - if err != nil { - return Config{}, err + logF = filepath.Join(logD, lf) + } else { + logD = filepath.Dir(logF) } - for _, stFld := range stCfg.Folders { - relativePath := strings.TrimPrefix(stFld.RawPath, c.ShareRootDir) - if relativePath == "" { - relativePath = stFld.RawPath - } - newFld := NewFolderConfig(stFld.ID, stFld.Label, c.ShareRootDir, strings.Trim(relativePath, "/")) - c.Folders = c.Folders.Update(FoldersConfig{newFld}) - } - - default: - log.Fatalln("Unsupported builder type") } - - return c, nil -} - -// GetFolderFromID retrieves the Folder config from id -func (c *Config) GetFolderFromID(id string) *FolderConfig { - if idx := c.Folders.GetIdx(id); idx != -1 { - return &c.Folders[idx] + if logD == "" || logD == "." { + logD = "/tmp/xds/logs" } - return nil -} + c.Options.LogFile = logF + c.FileConf.LogsDir = logD -// UpdateAll updates all the current configuration -func (c *Config) UpdateAll(newCfg Config) error { - return fmt.Errorf("Not Supported") - /* - if err := VerifyConfig(newCfg); err != nil { - return err + if c.FileConf.LogsDir != "" && !common.Exists(c.FileConf.LogsDir) { + if err := os.MkdirAll(c.FileConf.LogsDir, 0770); err != nil { + return nil, fmt.Errorf("Cannot create logs dir: %v", err) } + } - // TODO: c.Builder = c.Builder.Update(newCfg.Builder) - c.Folders = c.Folders.Update(newCfg.Folders) - - // SEB A SUP model.NotifyListeners(c, NotifyFoldersChange, FolderConfig{}) - // FIXME To be tested & improved error handling - for _, f := range c.Folders { - if err := c.SThg.FolderChange(st.FolderChangeArg{ - ID: f.ID, - Label: f.Label, - RelativePath: f.RelativePath, - SyncThingID: f.SyncThingID, - ShareRootDir: c.ShareRootDir, - }); err != nil { - return err - } - } + c.Log.Infoln("Logs file: ", c.Options.LogFile) + c.Log.Infoln("Logs directory: ", c.FileConf.LogsDir) - return nil - */ + return &c, nil } -// UpdateFolder updates a specific folder into the current configuration -func (c *Config) UpdateFolder(newFolder FolderConfig) (FolderConfig, error) { - // rootPath should not be empty - if newFolder.rootPath == "" { - newFolder.rootPath = c.ShareRootDir +// ConfigRootDir return the root directory where xds server save all config files +func ConfigRootDir() string { + root := "$HOME" + if usr, err := user.Current(); err == nil { + root = usr.HomeDir } - // Sanity check of folder settings - if err := FolderVerify(newFolder); err != nil { - return FolderConfig{}, err + // Default $HOME/.xds/server but may be changed by an env variable + if envVar, envDef := os.LookupEnv("XDS_SERVER_ROOT_CFG_DIR"); envDef { + root = envVar } - c.Folders = c.Folders.Update(FoldersConfig{newFolder}) - - // SEB A SUP model.NotifyListeners(c, NotifyFolderAdd, newFolder) - err := c.SThg.FolderChange(st.FolderChangeArg{ - ID: newFolder.ID, - Label: newFolder.Label, - RelativePath: newFolder.RelativePath, - SyncThingID: newFolder.SyncThingID, - ShareRootDir: c.ShareRootDir, - }) - - newFolder.BuilderSThgID = c.Builder.SyncThingID // FIXME - should be removed after local ST config rework - newFolder.Status = FolderStatusEnable - - return newFolder, err + return path.Join(root, "/.xds/server") } -// DeleteFolder deletes a specific folder -func (c *Config) DeleteFolder(id string) (FolderConfig, error) { - var fld FolderConfig - var err error - - //SEB A SUP model.NotifyListeners(c, NotifyFolderDelete, fld) - if err = c.SThg.FolderDelete(id); err != nil { - return fld, err +// WorkspaceRootDir return the path on server side where user xds-workspace dir is accessible +func WorkspaceRootDir() string { + // May be overloaded by an env variable + if envVar, envDef := os.LookupEnv("XDS_SERVER_WORKSPACE_DIR"); envDef { + return envVar } - c.Folders, fld, err = c.Folders.Delete(id) - - return fld, err -} - -func dirExists(path string) bool { - _, err := os.Stat(path) - if os.IsNotExist(err) { - return false + home := "${HOME}" + if usr, err := user.Current(); err == nil { + home = usr.HomeDir } - return true + + // Default value $HOME/xds-workspace + return path.Join(home, "xds-workspace") }