update xds-server package in docker 29/16929/8
authorClément Bénier <clement.benier@iot.bzh>
Mon, 1 Oct 2018 09:51:47 +0000 (11:51 +0200)
committerClément Bénier <clement.benier@iot.bzh>
Tue, 16 Oct 2018 12:57:58 +0000 (14:57 +0200)
scripts/package-update: bash scripts to update xds-server package in docker
monitor updates: default time is 24h, a update is tried at startup
api/v1: 2 new requests:
    - get(updates): return various information about xds-server packages
    - post(updates): update xds-server packages

Change-Id: I1673f7860e57cfe1d4abe5a24609ee46a90b67d8
Signed-off-by: Clément Bénier <clement.benier@iot.bzh>
16 files changed:
conf.d/etc/xds/server/server-config.json
lib/xdsconfig/config.go
lib/xdsconfig/fileconfig.go
lib/xdsserver/apiv1-exec.go
lib/xdsserver/apiv1-sdks.go
lib/xdsserver/apiv1-updates.go [new file with mode: 0644]
lib/xdsserver/apiv1.go
lib/xdsserver/sdk.go
lib/xdsserver/sdks.go
lib/xdsserver/webserver.go
lib/xdsserver/xds-server-update.go [new file with mode: 0644]
lib/xdsserver/xdsserver.go
lib/xsapiv1/xds-server-update.go [new file with mode: 0644]
scripts/xds-utils/getXdsServerPackage [new file with mode: 0755]
scripts/xds-utils/restartXdsServer [new file with mode: 0755]
scripts/xds-utils/updateXdsServerPackage [new file with mode: 0755]

index 47b75ef..87c7ad9 100644 (file)
@@ -3,6 +3,8 @@
     "httpPort": "8000",
     "shareRootDir": "${HOME}/.xds/server/projects",
     "sdkScriptsDir": "${EXEPATH}/sdks",
+    "xdsUtilsScriptsDir": "${EXEPATH}/xds-utils",
+    "xdsSrvUpdateTime": "24h",
     "syncthing": {
         "binDir": "",
         "home": "${HOME}/.xds/server/syncthing-config",
index 4ba97ef..bab3abd 100644 (file)
@@ -53,12 +53,14 @@ type Options struct {
 
 // Config default values
 const (
-       DefaultAPIVersion    = "1"
-       DefaultPort          = "8000"
-       DefaultShareDir      = "projects"
-       DefaultSTHomeDir     = "syncthing-config"
-       DefaultSdkScriptsDir = "${EXEPATH}/sdks"
-       DefaultSdkDbUpdate   = "startup"
+       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
@@ -98,13 +100,15 @@ func Init(cliCtx *cli.Context, log *logrus.Logger) (*Config, error) {
                        NoFolderConfig: cliCtx.GlobalBool("no-folderconfig"),
                },
                FileConf: FileConfig{
-                       WebAppDir:     "webapp/dist",
-                       ShareRootDir:  dfltShareDir,
-                       SdkScriptsDir: DefaultSdkScriptsDir,
-                       SdkDbUpdate:   DefaultSdkDbUpdate,
-                       HTTPPort:      DefaultPort,
-                       SThgConf:      &SyncThingConf{Home: dfltSTHomeDir},
-                       LogsDir:       "",
+                       WebAppDir:          "webapp/dist",
+                       ShareRootDir:       dfltShareDir,
+                       SdkScriptsDir:      DefaultSdkScriptsDir,
+                       XdsUtilsScriptsDir: DefaultXdsUtilsScriptsDir,
+                       SdkDbUpdate:        DefaultSdkDbUpdate,
+                       HTTPPort:           DefaultPort,
+                       SThgConf:           &SyncThingConf{Home: dfltSTHomeDir},
+                       LogsDir:            "",
+                       XdsSrvUpdateTime:   DefaultXdsSrvUpdateTime,
                },
                Log: log,
        }
index 374afa3..a3e0cee 100644 (file)
@@ -50,13 +50,15 @@ type SyncThingConf struct {
 
 // FileConfig is the JSON structure of xds-server config file (server-config.json)
 type FileConfig struct {
-       WebAppDir     string         `json:"webAppDir"`
-       ShareRootDir  string         `json:"shareRootDir"`
-       SdkScriptsDir string         `json:"sdkScriptsDir"`
-       SdkDbUpdate   string         `json:"sdkDbUpdate"`
-       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"`
 }
 
 // readGlobalConfig reads configuration from a config file.
@@ -118,7 +120,9 @@ func readGlobalConfig(c *Config, confFile string) error {
                &fCfg.WebAppDir,
                &fCfg.ShareRootDir,
                &fCfg.SdkScriptsDir,
-               &fCfg.LogsDir}
+               &fCfg.XdsUtilsScriptsDir,
+               &fCfg.LogsDir,
+               &fCfg.XdsSrvUpdateTime}
        if fCfg.SThgConf != nil {
                vars = append(vars, &fCfg.SThgConf.Home, &fCfg.SThgConf.BinDir)
        }
@@ -132,6 +136,9 @@ func readGlobalConfig(c *Config, confFile string) error {
        if fCfg.SdkScriptsDir == "" {
                fCfg.SdkScriptsDir = c.FileConf.SdkScriptsDir
        }
+       if fCfg.XdsUtilsScriptsDir == "" {
+               fCfg.XdsUtilsScriptsDir = c.FileConf.XdsUtilsScriptsDir
+       }
        if fCfg.SdkDbUpdate == "" {
                fCfg.SdkDbUpdate = c.FileConf.SdkDbUpdate
        }
@@ -141,6 +148,9 @@ func readGlobalConfig(c *Config, confFile string) error {
        if fCfg.LogsDir == "" {
                fCfg.LogsDir = c.FileConf.LogsDir
        }
+       if fCfg.XdsSrvUpdateTime == "" {
+               fCfg.XdsSrvUpdateTime = c.FileConf.XdsSrvUpdateTime
+       }
 
        for _, field := range vars {
                var err error
index 57ea1f1..aea34e4 100644 (file)
@@ -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
        }
index 7bb9767..a943da5 100644 (file)
@@ -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 (file)
index 0000000..2b878a6
--- /dev/null
@@ -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")
+}
index e0bfa7f..e394d9e 100644 (file)
@@ -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
 }
index 6cd2619..931db34 100644 (file)
@@ -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)
index 5a8a1fa..685f19d 100644 (file)
@@ -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)
index 24456b9..a50b41e 100644 (file)
@@ -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 (file)
index 0000000..cd9d6b1
--- /dev/null
@@ -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
+}
index 1079eba..e96ab57 100644 (file)
@@ -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)
diff --git a/lib/xsapiv1/xds-server-update.go b/lib/xsapiv1/xds-server-update.go
new file mode 100644 (file)
index 0000000..0c3f793
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * 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 xsapiv1
+
+// XdsSrvUpdate XDS server Version
+type XdsSrvUpdate struct {
+       CurrentVersion string `json:"currentVersion"`
+       NewerVersion   string `json:"newerVersion"`
+       UpdateTime     string `json:"updateTime"`
+}
diff --git a/scripts/xds-utils/getXdsServerPackage b/scripts/xds-utils/getXdsServerPackage
new file mode 100755 (executable)
index 0000000..8b00ac4
--- /dev/null
@@ -0,0 +1,61 @@
+#!/bin/bash
+ ###########################################################################
+# Copyright 2018 IoT.bzh
+#
+# author: Clément Bénier <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.
+###########################################################################
+
+XDSSERVER="xds-server"
+PACKAGE_NAME="agl-${XDSSERVER}"
+
+#test if sudoers without PASSWD
+sudo -n true
+if [ ! $? -eq 0 ]; then
+    exit 1
+fi
+
+function getUpdateDebian() {
+    sudo apt update -o DIR::Etc::sourcelist="AGL.list" &> /dev/null
+    sudo apt-cache policy ${PACKAGE_NAME} |grep -e 'Installed' -e 'Candidate'
+}
+
+function getUpdateFedora() {
+    sudo dnf check-update ${PACKAGE_NAME} --refresh
+    sudo dnf info --installed ${PACKAGE_NAME} | grep Version | sed "s/Version */Installed/g"
+    sudo dnf info --updates ${PACKAGE_NAME} | grep Version | sed "s/Version */Candidate/g"
+}
+
+function getUpdateOpenSuse() {
+    REPOAGL=$(zypper info agl-xds-server | grep Repository | awk -F ":" '{print $2}'))
+    REPOAGL=$(zypper repos | grep "${REPOAGL}" | awk '{print $3}')
+    sudo zypper refresh -r ${REPOAGL}
+    sudo zypper list-updates -r ${REPOAGL} | awk '{if ($3 == "${PACKAGE_NAME}") print "Installed: "$5 "\nCandidate: "$7}'
+}
+
+if [ -f /etc/os-release ]; then
+    source /etc/os-release
+fi
+
+case $ID in
+    "debian")
+        getUpdateDebian;;
+    "fedora")
+        getUpdateFedora;;
+    "opensuse")
+        getUpdateOpenSuse;;
+    *)
+       exit 2;;
+esac
+
diff --git a/scripts/xds-utils/restartXdsServer b/scripts/xds-utils/restartXdsServer
new file mode 100755 (executable)
index 0000000..71981a6
--- /dev/null
@@ -0,0 +1,32 @@
+#!/bin/bash
+ ###########################################################################
+# Copyright 2018 IoT.bzh
+#
+# author: Clément Bénier <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.
+###########################################################################
+
+XDSSERVER="xds-server"
+
+function systemdRestartXdsServer() {
+    systemctl --user daemon-reload
+    systemctl --user restart ${XDSSERVER}
+    if [ ! $? -eq 0 ]; then
+           echo "Cannot restart $XDSSERVER"
+           exit 1
+    fi
+}
+
+systemdRestartXdsServer
+exit 0
\ No newline at end of file
diff --git a/scripts/xds-utils/updateXdsServerPackage b/scripts/xds-utils/updateXdsServerPackage
new file mode 100755 (executable)
index 0000000..012ca6c
--- /dev/null
@@ -0,0 +1,64 @@
+#!/bin/bash
+ ###########################################################################
+# Copyright 2018 IoT.bzh
+#
+# author: Clément Bénier <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.
+###########################################################################
+
+XDSSERVER="xds-server"
+PACKAGE_NAME="agl-${XDSSERVER}"
+
+#test if sudoers without PASSWD
+sudo -n true
+if [ ! $? -eq 0 ]; then
+    exit 1
+fi
+
+
+function checkUpdateDebian() {
+    sudo apt update -o DIR::Etc::sourcelist="AGL.list" &> /dev/null
+    apt list --upgradable | grep ${PACKAGE_NAME}
+    if [ $? -eq 0 ]; then
+        sudo apt-get install ${PACKAGE_NAME}
+    fi
+}
+
+function checkUpdateFedora() {
+    sudo dnf check-update ${PACKAGE_NAME} --refresh
+    sudo dnf update -y ${PACKAGE_NAME}
+}
+
+function checkUpdateOpenSuse() {
+    REPOAGL=$(zypper info agl-xds-server | grep Repository | awk -F ":" '{print $2}'))
+    REPOAGL=$(zypper repos | grep "${REPOAGL}" | awk '{print $3}')
+    sudo zypper refresh -r ${REPOAGL}
+    sudo zypper update -y ${PACKAGE_NAME}
+}
+
+if [ -f /etc/os-release ]; then
+    source /etc/os-release
+fi
+
+case $ID in
+    "debian")
+        res=$(checkUpdateDebian);;
+    "fedora")
+        res=$(checkUpdateFedora);;
+    "opensuse")
+        res=$(checkUpdateOpenSuse);;
+    *)
+        exit 2;;
+esac
+