+ // Create new instance to execute command and sent output over WS
+ s.installCmd = eows.New(s.scripts[scriptAdd], cmdArgs, sess.IOSocket, sess.ID, cmdID)
+ s.installCmd.Log = s.Log
+ // TODO: enable Term s.installCmd.PtyMode = true
+ s.installCmd.LineTimeSpan = 500 * time.Millisecond.Nanoseconds()
+ if timeout > 0 {
+ s.installCmd.CmdExecTimeout = timeout
+ } else {
+ s.installCmd.CmdExecTimeout = 30 * 60 // default 30min
+ }
+
+ // Define callback for output (stdout+stderr)
+ s.installCmd.OutputCB = func(e *eows.ExecOverWS, bStdout, bStderr []byte) {
+
+ stdout := string(bStdout)
+ stderr := string(bStderr)
+
+ // paranoia
+ data := e.UserData
+ sdkID := (*data)["SDKID"].(string)
+ if sdkID != s.sdk.ID {
+ s.Log.Errorf("BUG: sdk ID differs: %v != %v", sdkID, s.sdk.ID)
+ }
+
+ // IO socket can be nil when disconnected
+ so := s.sessions.IOSocketGet(e.Sid)
+ if so == nil {
+ s.Log.Infof("%s not emitted: WS closed (sid:%s, msgid:%s)", xsapiv1.EVTSDKManagement, e.Sid, e.CmdID)
+ return
+ }
+
+ if s.LogLevelSilly {
+ s.Log.Debugf("%s emitted - WS sid[4:] %s - id:%s - SDK ID:%s:", xsapiv1.EVTSDKManagement, e.Sid[4:], e.CmdID, sdkID[:16])
+ if stdout != "" {
+ s.Log.Debugf("STDOUT <<%v>>", strings.Replace(stdout, "\n", "\\n", -1))
+ }
+ if stderr != "" {
+ s.Log.Debugf("STDERR <<%v>>", strings.Replace(stderr, "\n", "\\n", -1))
+ }
+ }
+
+ err := (*so).Emit(xsapiv1.EVTSDKManagement, xsapiv1.SDKManagementMsg{
+ CmdID: e.CmdID,
+ Timestamp: time.Now().String(),
+ Action: xsapiv1.SdkMgtActionInstall,
+ Sdk: s.sdk,
+ Progress: 0, // TODO add progress
+ Exited: false,
+ Stdout: stdout,
+ Stderr: stderr,
+ })
+ if err != nil {
+ s.Log.Errorf("WS Emit : %v", err)
+ }
+ }
+
+ // 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)
+ if sdkID != s.sdk.ID {
+ s.Log.Errorf("BUG: sdk ID differs: %v != %v", sdkID, s.sdk.ID)
+ }
+
+ s.Log.Infof("Command SDK ID %s [Cmd ID %s] exited: code %d, exitError: %v", sdkID[:16], e.CmdID, code, exitError)
+
+ // IO socket can be nil when disconnected
+ so := s.sessions.IOSocketGet(e.Sid)
+ if so == nil {
+ s.Log.Infof("%s (exit) not emitted - WS closed (id:%s)", xsapiv1.EVTSDKManagement, e.CmdID)
+ return
+ }
+
+ // Update SDK status
+ if code == 0 && exitError == nil {
+ s.sdk.LastError = ""
+ s.sdk.Status = xsapiv1.SdkStatusInstalled
+
+ // FIXME: better update it using monitoring install dir (inotify)
+ // (see sdks.go / monitorSDKInstallation )
+ // Update SetupFile when n
+ if s.sdk.SetupFile == "" {
+ sdkDef, err := GetSDKInfo(s.sdk.FamilyConf.ScriptsDir, s.sdk.URL, "", "", s.sdk.UUID, s.Log)
+ if err != nil || sdkDef.SetupFile == "" {
+ s.Log.Errorf("GetSDKInfo error: %v", err)
+ code = 1
+ s.sdk.LastError = "Installation failed (cannot init SetupFile path)"
+ s.sdk.Status = xsapiv1.SdkStatusNotInstalled
+ } else {
+ s.sdk.SetupFile = sdkDef.SetupFile
+ }
+ }
+
+ } else {
+ s.sdk.LastError = "Installation failed (code " + strconv.Itoa(code) +
+ ")"
+ if exitError != nil {
+ s.sdk.LastError = ". Error: " + exitError.Error()
+ }
+ s.sdk.Status = xsapiv1.SdkStatusNotInstalled
+ }
+
+ emitErr := ""
+ if exitError != nil {
+ emitErr = exitError.Error()
+ }
+ if emitErr == "" && s.sdk.LastError != "" {
+ emitErr = s.sdk.LastError
+ }
+
+ // Emit event
+ errSoEmit := (*so).Emit(xsapiv1.EVTSDKManagement, xsapiv1.SDKManagementMsg{
+ CmdID: e.CmdID,
+ Timestamp: time.Now().String(),
+ Action: xsapiv1.SdkMgtActionInstall,
+ Sdk: s.sdk,
+ Progress: 100,
+ Exited: true,
+ Code: code,
+ Error: emitErr,
+ })
+ if errSoEmit != nil {
+ s.Log.Errorf("WS Emit EVTSDKManagement : %v", errSoEmit)
+ }
+
+ errSoEmit = s.events.Emit(xsapiv1.EVTSDKStateChange, s.sdk, e.Sid)
+ if errSoEmit != nil {
+ s.Log.Errorf("WS Emit EVTSDKStateChange : %v", errSoEmit)
+ }
+
+ // Cleanup command for the next time
+ s.installCmd = nil
+ }
+
+ // User data (used within callbacks)
+ data := make(map[string]interface{})
+ data["SDKID"] = s.sdk.ID
+ s.installCmd.UserData = &data
+
+ // Start command execution
+ s.Log.Infof("Install SDK %s: cmdID=%v, cmd=%v, args=%v", s.sdk.Name, s.installCmd.CmdID, s.installCmd.Cmd, s.installCmd.Args)
+
+ s.sdk.Status = xsapiv1.SdkStatusInstalling
+ s.sdk.LastError = ""
+
+ if err := s.events.Emit(xsapiv1.EVTSDKStateChange, s.sdk, sess.ID); err != nil {
+ s.Log.Errorf("WS Emit EVTSDKStateChange installing : %v", err)
+ }
+
+ err := s.installCmd.Start()
+
+ return err
+}
+
+// AbortInstallRemove abort an install or remove command
+func (s *CrossSDK) AbortInstallRemove(timeout int) error {
+
+ if s.installCmd == nil {
+ return fmt.Errorf("no installation in progress for this sdk")
+ }
+
+ s.sdk.Status = xsapiv1.SdkStatusNotInstalled
+ return s.installCmd.Signal("SIGKILL")
+}
+
+// Remove Used to remove/uninstall a SDK
+func (s *CrossSDK) Remove(timeout int, sess *ClientSession) error {
+
+ if s.sdk.Status != xsapiv1.SdkStatusInstalled {
+ return fmt.Errorf("this sdk is not installed")
+ }
+
+ // IO socket can be nil when disconnected
+ so := s.sessions.IOSocketGet(sess.ID)
+ if so == nil {
+ return fmt.Errorf("Cannot retrieve socket ")
+ }
+
+ s.sdk.Status = xsapiv1.SdkStatusUninstalling
+
+ // Notify state change
+ if err := s.events.Emit(xsapiv1.EVTSDKStateChange, s.sdk, sess.ID); err != nil {
+ s.Log.Warningf("Cannot notify SDK remove: %v", err)
+ }
+
+ script := s.scripts[scriptRemove]
+ args := s.sdk.Path
+ s.Log.Infof("Uninstall SDK %s: script=%v args=%v", s.sdk.Name, script, args)
+
+ // Notify start removing
+ evData := xsapiv1.SDKManagementMsg{
+ Timestamp: time.Now().String(),
+ Action: xsapiv1.SdkMgtActionRemove,
+ Sdk: s.sdk,
+ Progress: 0,
+ Exited: false,
+ Code: 0,
+ Error: "",
+ }
+ if errEmit := (*so).Emit(xsapiv1.EVTSDKManagement, evData); errEmit != nil {
+ s.Log.Warningf("Cannot notify EVTSDKManagement end: %v", errEmit)
+ }
+
+ // Run command to remove SDK
+ cmd := exec.Command(script, args)
+ stdout, err := cmd.CombinedOutput()
+
+ s.sdk.Status = xsapiv1.SdkStatusNotInstalled
+ s.Log.Debugf("SDK uninstall err %v, output:\n %v", err, string(stdout))
+
+ // Emit end of removing process
+ evData = xsapiv1.SDKManagementMsg{
+ Timestamp: time.Now().String(),
+ Action: xsapiv1.SdkMgtActionRemove,
+ Sdk: s.sdk,
+ Progress: 100,
+ Exited: true,
+ Code: 0,
+ Error: "",
+ }
+
+ // Update error code on error