summaryrefslogtreecommitdiffstats
path: root/lib/xdsserver
diff options
context:
space:
mode:
Diffstat (limited to 'lib/xdsserver')
-rw-r--r--lib/xdsserver/apiv1-exec.go3
-rw-r--r--lib/xdsserver/apiv1-sdks.go8
-rw-r--r--lib/xdsserver/apiv1-updates.go40
-rw-r--r--lib/xdsserver/apiv1.go3
-rw-r--r--lib/xdsserver/sdk.go2
-rw-r--r--lib/xdsserver/sdks.go2
-rw-r--r--lib/xdsserver/webserver.go11
-rw-r--r--lib/xdsserver/xds-server-update.go164
-rw-r--r--lib/xdsserver/xdsserver.go50
9 files changed, 260 insertions, 23 deletions
diff --git a/lib/xdsserver/apiv1-exec.go b/lib/xdsserver/apiv1-exec.go
index 57ea1f1..aea34e4 100644
--- a/lib/xdsserver/apiv1-exec.go
+++ b/lib/xdsserver/apiv1-exec.go
@@ -261,6 +261,7 @@ func (s *APIService) execCmd(c *gin.Context) {
execWS.ExitCB = func(e *eows.ExecOverWS, code int, err error) {
s.Log.Debugf("Command [Cmd ID %s] exited: code %d, error: %v", e.CmdID, code, err)
+ defer LockXdsUpdateCounter(s.Context, false)
// Close client tty
defer func() {
if gdbPty != nil {
@@ -330,8 +331,10 @@ func (s *APIService) execCmd(c *gin.Context) {
// Start command execution
s.Log.Infof("Execute [Cmd ID %s]: %v %v", execWS.CmdID, execWS.Cmd, execWS.Args)
+ LockXdsUpdateCounter(s.Context, true)
err = execWS.Start()
if err != nil {
+ LockXdsUpdateCounter(s.Context, false)
common.APIError(c, err.Error())
return
}
diff --git a/lib/xdsserver/apiv1-sdks.go b/lib/xdsserver/apiv1-sdks.go
index 7bb9767..a943da5 100644
--- a/lib/xdsserver/apiv1-sdks.go
+++ b/lib/xdsserver/apiv1-sdks.go
@@ -74,8 +74,13 @@ func (s *APIService) installSdk(c *gin.Context) {
return
}
+ //increment lock xds counter: it will be decremented,
+ //when SDK is installed in file sdk.go in function ExitCB
+ //at line 308 or when install is aborted in following function
+ LockXdsUpdateCounter(s.Context, true)
sdk, err := s.sdks.Install(id, args.Filename, args.Force, args.Timeout, args.InstallArgs, sess)
if err != nil {
+ LockXdsUpdateCounter(s.Context, false)
common.APIError(c, err.Error())
return
}
@@ -103,6 +108,7 @@ func (s *APIService) abortInstallSdk(c *gin.Context) {
return
}
+ LockXdsUpdateCounter(s.Context, false)
c.JSON(http.StatusOK, sdk)
}
@@ -123,10 +129,12 @@ func (s *APIService) removeSdk(c *gin.Context) {
s.Log.Debugln("Remove SDK id ", id)
+ LockXdsUpdateCounter(s.Context, true)
delEntry, err := s.sdks.Remove(id, -1, sess)
if err != nil {
common.APIError(c, err.Error())
return
}
+ LockXdsUpdateCounter(s.Context, false)
c.JSON(http.StatusOK, delEntry)
}
diff --git a/lib/xdsserver/apiv1-updates.go b/lib/xdsserver/apiv1-updates.go
new file mode 100644
index 0000000..2b878a6
--- /dev/null
+++ b/lib/xdsserver/apiv1-updates.go
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017-2018 "IoT.bzh"
+ * Author Clément Bénier <clement.benier@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 xdsserver
+
+import (
+ "net/http"
+
+ common "gerrit.automotivelinux.org/gerrit/src/xds/xds-common.git/golib"
+ "github.com/gin-gonic/gin"
+)
+
+// getXdsSrvUpdate : return various information about pkg update
+func (s *APIService) getXdsSrvUpdate(c *gin.Context) {
+ response := GetXdsSrvUpdate(s.Context)
+ c.JSON(http.StatusOK, response)
+}
+
+// xdsSrvUpdate: update xds server package
+func (s *APIService) xdsSrvUpdate(c *gin.Context) {
+ if err := UpdateXdsServer(s.Context); err != 0 {
+ common.APIError(c, "cannot update package")
+ return
+ }
+ c.JSON(http.StatusOK, "OK")
+}
diff --git a/lib/xdsserver/apiv1.go b/lib/xdsserver/apiv1.go
index e0bfa7f..e394d9e 100644
--- a/lib/xdsserver/apiv1.go
+++ b/lib/xdsserver/apiv1.go
@@ -78,5 +78,8 @@ func NewAPIV1(ctx *Context) *APIService {
s.apiRouter.POST("/targets/:id/terminals/:tid/signal", s.signalTgtTerm)
s.apiRouter.POST("/targets/:id/terminals/:tid/signal/:sig", s.signalTgtTerm)
+ s.apiRouter.GET("/updates", s.getXdsSrvUpdate)
+ s.apiRouter.POST("/updates", s.xdsSrvUpdate)
+
return s
}
diff --git a/lib/xdsserver/sdk.go b/lib/xdsserver/sdk.go
index 6cd2619..931db34 100644
--- a/lib/xdsserver/sdk.go
+++ b/lib/xdsserver/sdk.go
@@ -305,6 +305,8 @@ func (s *CrossSDK) Install(file string, force bool, timeout int, args []string,
// Define callback for output
s.installCmd.ExitCB = func(e *eows.ExecOverWS, code int, exitError error) {
+ defer LockXdsUpdateCounter(s.Context, false)
+
// paranoia
data := e.UserData
sdkID := (*data)["SDKID"].(string)
diff --git a/lib/xdsserver/sdks.go b/lib/xdsserver/sdks.go
index 5a8a1fa..685f19d 100644
--- a/lib/xdsserver/sdks.go
+++ b/lib/xdsserver/sdks.go
@@ -50,7 +50,7 @@ func SDKsConstructor(ctx *Context) (*SDKs, error) {
scriptsDir := ctx.Config.FileConf.SdkScriptsDir
if !common.Exists(scriptsDir) {
- // allow to use scripts/sdk in debug mode
+ // allow to use scripts/sdk when debugging with vscode(EXEPATH=WORKSPACE)
scriptsDir = filepath.Join(filepath.Dir(ctx.Config.FileConf.SdkScriptsDir), "scripts", "sdks")
if !common.Exists(scriptsDir) {
return &s, fmt.Errorf("scripts directory doesn't exist (%v)", scriptsDir)
diff --git a/lib/xdsserver/webserver.go b/lib/xdsserver/webserver.go
index 24456b9..a50b41e 100644
--- a/lib/xdsserver/webserver.go
+++ b/lib/xdsserver/webserver.go
@@ -84,6 +84,7 @@ func (s *WebServer) Serve() error {
s.router.Use(gin.Recovery())
s.router.Use(s.middlewareXDSDetails())
s.router.Use(s.middlewareCORS())
+ s.router.Use(s.lockRequest())
// Create REST API
s.api = NewAPIV1(s.Context)
@@ -172,6 +173,16 @@ func (s *WebServer) middlewareCORS() gin.HandlerFunc {
}
}
+//lockRequest handles to increment/decrement xds package update
+//to avoid updating xds-server when request is done
+func (s *WebServer) lockRequest() gin.HandlerFunc {
+ return func(c *gin.Context) {
+ LockXdsUpdateCounter(s.Context, true)
+ c.Next()
+ LockXdsUpdateCounter(s.Context, false)
+ }
+}
+
// socketHandler is the handler for the "main" websocket connection
func (s *WebServer) socketHandler(c *gin.Context) {
diff --git a/lib/xdsserver/xds-server-update.go b/lib/xdsserver/xds-server-update.go
new file mode 100644
index 0000000..cd9d6b1
--- /dev/null
+++ b/lib/xdsserver/xds-server-update.go
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2018 "IoT.bzh"
+ * Author Clément Bénier <clement.benier@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 xdsserver
+
+import (
+ "os/exec"
+ "path"
+ "path/filepath"
+ "strings"
+ sc "sync"
+ "time"
+
+ common "gerrit.automotivelinux.org/gerrit/src/xds/xds-common.git/golib"
+ "gerrit.automotivelinux.org/gerrit/src/xds/xds-server/lib/xdsconfig"
+ "gerrit.automotivelinux.org/gerrit/src/xds/xds-server/lib/xsapiv1"
+)
+
+const (
+ scriptXdsSrvUpdate = "updateXdsServerPackage"
+ scriptGetXdsSrvUpdate = "getXdsServerPackage"
+ scriptXdsSrvRestart = "restartXdsServer"
+)
+
+//LockXdsUpdate allows to lock xds-server avoiding restart
+type LockXdsUpdate struct {
+ sc.Mutex
+ LockCpt int
+}
+
+//LockXdsUpdateCounter Inc/decrement lock counter
+func LockXdsUpdateCounter(ctx *Context, inc bool) {
+ if inc {
+ //paranoia lock count > 10
+ if ctx.lockXdsSrvUpdate.LockCpt > 10 {
+ ctx.Log.Errorf("lock counter value is abnormally high: LockCpt=%v", ctx.lockXdsSrvUpdate.LockCpt)
+ }
+ ctx.lockXdsSrvUpdate.Lock()
+ ctx.lockXdsSrvUpdate.LockCpt++
+ ctx.lockXdsSrvUpdate.Unlock()
+ } else {
+ //paranoia lock count < 0
+ if ctx.lockXdsSrvUpdate.LockCpt <= 0 {
+ ctx.Log.Errorf("lock counter value is lower than 0: LockCpt=%v", ctx.lockXdsSrvUpdate.LockCpt)
+ return
+ }
+ ctx.lockXdsSrvUpdate.Lock()
+ ctx.lockXdsSrvUpdate.LockCpt--
+ ctx.lockXdsSrvUpdate.Unlock()
+ }
+}
+
+//MonitorUpdates try to update xds-server package at first
+// then monitor updates
+func MonitorUpdates(ctx *Context) {
+ UpdateXdsServer(ctx) //try to update at startup
+
+ updateTime, err := time.ParseDuration(ctx.Config.FileConf.XdsSrvUpdateTime)
+ if err != nil {
+ ctx.Log.Errorf("Wrong format type of XdsSrvUpdateTime\n"+
+ "err=%v \n"+
+ "Valid time units are ns, us, ms, s, m, h\n"+
+ "Here an example: 1h10m10s\n"+
+ "So, default value is set %v", err, xdsconfig.DefaultXdsSrvUpdateTime)
+ updateTime, _ = time.ParseDuration(xdsconfig.DefaultXdsSrvUpdateTime)
+ }
+ ctx.Log.Infof("Update time for package xds-server is %v", updateTime)
+ go func(ctx *Context) {
+ for {
+ currentUpdateTime := updateTime
+ for currentUpdateTime > 0 {
+ time.Sleep(currentUpdateTime)
+ currentUpdateTime = UpdateXdsServer(ctx)
+ }
+ }
+ }(ctx)
+}
+
+func getScriptsDir(ctx *Context) string {
+ scriptsDir := ctx.Config.FileConf.XdsUtilsScriptsDir
+ if !common.Exists(scriptsDir) {
+ // allow to use scripts/xds-utils when debugging with vscode(EXEPATH=WORKSPACE)
+ scriptsDir = filepath.Join(filepath.Dir(ctx.Config.FileConf.XdsUtilsScriptsDir), "scripts", "xds-utils")
+ if !common.Exists(scriptsDir) {
+ ctx.Log.Errorf("scripts directory doesn't exist (%v)", scriptsDir)
+ }
+ }
+ return scriptsDir
+}
+
+// UpdateXdsServer launches update package xds-server script
+func UpdateXdsServer(ctx *Context) time.Duration {
+ timeToRestartIfBusy := 0 * time.Minute
+ scriptsDir := getScriptsDir(ctx)
+
+ ctx.Log.Infof("Trying to update xds-server package, "+
+ "xds-utils scripts dir: %s", scriptsDir)
+
+ //launch xds-server update package script
+ cmd := exec.Command(path.Join(scriptsDir, scriptXdsSrvUpdate))
+ _, err := cmd.CombinedOutput()
+ if err != nil {
+ ctx.Log.Errorf("Cannot update xds-server package err=%v", err)
+ return 0
+ }
+
+ //launch xds-server restart script
+ cmd = exec.Command(path.Join(scriptsDir, scriptXdsSrvRestart))
+ ctx.lockXdsSrvUpdate.Lock()
+ if ctx.lockXdsSrvUpdate.LockCpt == 0 { //no action in progress
+ _, err = cmd.CombinedOutput()
+ if err != nil {
+ ctx.Log.Errorf("Cannot restart xds-server service err=%v", err)
+ return 0
+ }
+ } else {
+ timeToRestartIfBusy = 1 * time.Minute
+ ctx.Log.Infof("Cannot restart xds-server service because "+
+ "xds-server has an action in progress, trying to restart in a %v", timeToRestartIfBusy)
+ }
+ ctx.lockXdsSrvUpdate.Unlock()
+
+ return timeToRestartIfBusy
+}
+
+// GetXdsSrvUpdate gets information about package
+func GetXdsSrvUpdate(ctx *Context) xsapiv1.XdsSrvUpdate {
+ var xdsSrvUpdate xsapiv1.XdsSrvUpdate
+ scriptsDir := getScriptsDir(ctx)
+
+ //exec getXdsSrvUpdate script
+ cmd := exec.Command(path.Join(scriptsDir, scriptGetXdsSrvUpdate))
+ stdout, err := cmd.CombinedOutput()
+ if err != nil {
+ ctx.Log.Errorf("Cannot get xds-server package information err=%v", err)
+ return xdsSrvUpdate
+ }
+
+ //stdout is formatting with 'version: xxxxx'
+ outputs := strings.Split(string(stdout[:]), "\n")
+ installedVersion := strings.Split(outputs[0], ": ")[1]
+ candidateVersion := strings.Split(outputs[1], ": ")[1]
+ ctx.Log.Infof("XdsSrvUpdate: candidateVersion:%v installedVersion:%v", candidateVersion, installedVersion)
+ xdsSrvUpdate = xsapiv1.XdsSrvUpdate{
+ CurrentVersion: installedVersion,
+ NewerVersion: candidateVersion,
+ UpdateTime: ctx.Config.FileConf.XdsSrvUpdateTime,
+ }
+ return xdsSrvUpdate
+}
diff --git a/lib/xdsserver/xdsserver.go b/lib/xdsserver/xdsserver.go
index 1079eba..e96ab57 100644
--- a/lib/xdsserver/xdsserver.go
+++ b/lib/xdsserver/xdsserver.go
@@ -37,22 +37,23 @@ const cookieMaxAge = "3600"
// Context holds the XDS server context
type Context struct {
- ProgName string
- Cli *cli.Context
- Config *xdsconfig.Config
- Log *logrus.Logger
- LogLevelSilly bool
- LogSillyf func(format string, args ...interface{})
- SThg *st.SyncThing
- SThgCmd *exec.Cmd
- SThgInotCmd *exec.Cmd
- mfolders *Folders
- sdks *SDKs
- targets *Targets
- WWWServer *WebServer
- sessions *Sessions
- events *Events
- Exit chan os.Signal
+ ProgName string
+ Cli *cli.Context
+ Config *xdsconfig.Config
+ Log *logrus.Logger
+ LogLevelSilly bool
+ LogSillyf func(format string, args ...interface{})
+ SThg *st.SyncThing
+ SThgCmd *exec.Cmd
+ SThgInotCmd *exec.Cmd
+ mfolders *Folders
+ sdks *SDKs
+ targets *Targets
+ WWWServer *WebServer
+ sessions *Sessions
+ events *Events
+ lockXdsSrvUpdate LockXdsUpdate
+ Exit chan os.Signal
}
// NewXdsServer Create a new instance of XDS server
@@ -83,12 +84,13 @@ func NewXdsServer(cliCtx *cli.Context) *Context {
// Define default configuration
ctx := Context{
- ProgName: cliCtx.App.Name,
- Cli: cliCtx,
- Log: log,
- LogLevelSilly: logSilly,
- LogSillyf: sillyFunc,
- Exit: make(chan os.Signal, 1),
+ ProgName: cliCtx.App.Name,
+ Cli: cliCtx,
+ Log: log,
+ LogLevelSilly: logSilly,
+ LogSillyf: sillyFunc,
+ lockXdsSrvUpdate: LockXdsUpdate{LockCpt: 0},
+ Exit: make(chan os.Signal, 1),
}
// register handler on SIGTERM / exit
@@ -206,6 +208,10 @@ func (ctx *Context) Run() (int, error) {
// Sessions manager
ctx.sessions = ClientSessionsConstructor(ctx, cookieMaxAge)
+ // Check if a new package version is available
+ // and monitor updates
+ MonitorUpdates(ctx)
+
// Run Web Server until exit requested (blocking call)
if err = ctx.WWWServer.Serve(); err != nil {
ctx.Log.Println(err)