update xds-server package in docker
[src/xds/xds-server.git] / lib / xdsserver / xds-server-update.go
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
+}