2 * Copyright (C) 2017-2018 "IoT.bzh"
3 * Author Sebastien Douheret <sebastien@iot.bzh>
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
23 "gerrit.automotivelinux.org/gerrit/src/xds/xds-agent.git/lib/xaapiv1"
24 common "gerrit.automotivelinux.org/gerrit/src/xds/xds-common.git"
25 "gerrit.automotivelinux.org/gerrit/src/xds/xds-server.git/lib/xsapiv1"
26 "github.com/franciscocpg/reflectme"
27 "github.com/gin-gonic/gin"
28 uuid "github.com/satori/go.uuid"
31 // ExecCmd executes remotely a command
32 func (s *APIService) execCmd(c *gin.Context) {
34 args := xaapiv1.ExecArgs{}
35 if err := c.BindJSON(&args); err != nil {
36 s.Log.Warningf("/exec invalid args, err=%v", err)
37 common.APIError(c, "Invalid arguments")
41 // First get Project ID to retrieve Server ID and send command to right server
46 id, err := s.projects.ResolveID(iid)
48 common.APIError(c, err.Error())
51 prj := s.projects.Get(id)
53 common.APIError(c, "Unknown id")
57 svr := (*prj).GetServer()
59 common.APIError(c, "Cannot identify XDS Server")
63 // Retrieve session info
64 sess := s.sessions.Get(c)
66 common.APIError(c, "Unknown sessions")
71 common.APIError(c, "Websocket not established")
75 // Forward input events from client to XDSServer through WS
76 // TODO use XDSServer events names definition
77 evtInList := []string{
79 xaapiv1.ExecInferiorInEvent,
81 for _, evName := range evtInList {
83 err := (*sock).On(evN, func(stdin string) {
84 s.LogSillyf("EXEC EVENT IN (%s) <<%v>>", evN, stdin)
85 svr.EventEmit(evN, stdin)
88 msgErr := "Error while registering WS for " + evN + " event"
89 s.Log.Errorf(msgErr, ", err: %v", err)
90 common.APIError(c, msgErr)
95 // Forward output events from XDSServer to client through WS
96 // TODO use XDSServer events names definition
97 var fwdFuncID []uuid.UUID
98 evtOutList := []string{
100 xaapiv1.ExecInferiorOutEvent,
102 for _, evName := range evtOutList {
104 fwdFunc := func(pData interface{}, evData interface{}) error {
105 sid := pData.(string)
106 // IO socket can be nil when disconnected
107 so := s.sessions.IOSocketGet(sid)
109 s.Log.Infof("%s not emitted: WS closed (sid:%s)", evN, sid)
113 // Add sessionID to event Data
114 reflectme.SetField(evData, "sessionID", sid)
116 s.LogSillyf("EXEC EVENT OUT (%s) <<%v>>", evN, evData)
118 // Forward event to Client/Dashboard
119 (*so).Emit(evN, evData)
122 id, err := svr.EventOn(evN, sess.ID, fwdFunc)
124 common.APIError(c, err.Error())
127 fwdFuncID = append(fwdFuncID, id)
130 // Handle Exit event separately to cleanup registered listener
131 var exitFuncID uuid.UUID
132 exitFunc := func(privD interface{}, evData interface{}) error {
133 evN := xaapiv1.ExecExitEvent
135 pData := privD.(map[string]string)
136 sid := pData["sessID"]
137 prjID := pData["prjID"]
139 // Add sessionID to event Data
140 reflectme.SetField(evData, "sessionID", sid)
142 // IO socket can be nil when disconnected
143 so := s.sessions.IOSocketGet(sid)
145 (*so).Emit(evN, evData)
147 s.Log.Infof("%s not emitted: WS closed (sid:%s)", evN, sid)
150 prj := s.projects.Get(prjID)
152 evD := evData.(map[string]interface{})
153 cmdIDData, cmdIDExist := evD["cmdID"]
154 svr := (*prj).GetServer()
155 if svr != nil && cmdIDExist {
156 svr.CommandDelete(cmdIDData.(string))
158 s.Log.Infof("%s: cannot retrieve server for sid=%s, prjID=%s, evD=%v", evN, sid, prjID, evD)
161 s.Log.Infof("%s: cannot retrieve project for sid=%s, prjID=%s", evN, sid, prjID)
165 for i, evName := range evtOutList {
166 svr.EventOff(evName, fwdFuncID[i])
168 svr.EventOff(evN, exitFuncID)
173 prjCfg := (*prj).GetProject()
174 privData := map[string]string{"sessID": sess.ID, "prjID": prjCfg.ID}
175 exitFuncID, err = svr.EventOn(xaapiv1.ExecExitEvent, privData, exitFunc)
177 common.APIError(c, err.Error())
181 // Forward back command to right server
182 res := xsapiv1.ExecResult{}
183 xsArgs := &xsapiv1.ExecArgs{
192 TTYGdbserverFix: args.TTYGdbserverFix,
193 LdLibPathNoReset: args.LdLibPathNoReset,
194 ExitImmediate: args.ExitImmediate,
195 CmdTimeout: args.CmdTimeout,
197 if err := svr.CommandExec(xsArgs, &res); err != nil {
198 common.APIError(c, err.Error())
202 // Add command to running commands list
203 if err := svr.CommandAdd(res.CmdID, xsArgs); err != nil {
204 common.APIError(c, err.Error())
208 c.JSON(http.StatusOK, xaapiv1.ExecResult{Status: res.Status, CmdID: res.CmdID})
211 // execSignalCmd executes remotely the signal command
212 func (s *APIService) execSignalCmd(c *gin.Context) {
214 args := xaapiv1.ExecSignalArgs{}
215 if err := c.BindJSON(&args); err != nil {
216 s.Log.Warningf("/signal invalid args, err=%v", err)
217 common.APIError(c, "Invalid arguments")
221 // Retrieve on which xds-server the command is running
223 var dataCmd interface{}
224 for _, svr = range s.xdsServers {
225 dataCmd = svr.CommandGet(args.CmdID)
231 common.APIError(c, "Cannot retrieve XDS Server for this cmdID")
235 // Forward back command to right server
236 res := xsapiv1.ExecSigResult{}
237 xsArgs := &xsapiv1.ExecSignalArgs{
241 if err := svr.CommandSignal(xsArgs, &res); err != nil {
242 common.APIError(c, err.Error())
246 c.JSON(http.StatusOK, xaapiv1.ExecSignalResult{Status: res.Status, CmdID: res.CmdID})