8 "github.com/franciscocpg/reflectme"
9 "github.com/gin-gonic/gin"
10 "github.com/iotbzh/xds-agent/lib/apiv1"
11 common "github.com/iotbzh/xds-common/golib"
12 uuid "github.com/satori/go.uuid"
15 // ExecCmd executes remotely a command
16 func (s *APIService) execCmd(c *gin.Context) {
17 s._execRequest("/exec", c)
20 // execSignalCmd executes remotely a command
21 func (s *APIService) execSignalCmd(c *gin.Context) {
22 s._execRequest("/signal", c)
25 func (s *APIService) _execRequest(cmd string, c *gin.Context) {
26 data, err := c.GetRawData()
28 common.APIError(c, err.Error())
31 args := apiv1.ExecArgs{}
32 // XXX - we cannot use c.BindJSON, so directly unmarshall it
33 // (see https://github.com/gin-gonic/gin/issues/1078)
34 if err := json.Unmarshal(data, &args); err != nil {
35 common.APIError(c, "Invalid arguments")
39 // First get Project ID to retrieve Server ID and send command to right server
44 id, err := s.projects.ResolveID(iid)
46 common.APIError(c, err.Error())
49 prj := s.projects.Get(id)
51 common.APIError(c, "Unknown id")
55 svr := (*prj).GetServer()
57 common.APIError(c, "Cannot identify XDS Server")
61 // Retrieve session info
62 sess := s.sessions.Get(c)
64 common.APIError(c, "Unknown sessions")
69 common.APIError(c, "Websocket not established")
73 // Forward XDSServer WS events to client WS
74 // TODO removed static event name list and get it from XDSServer
78 apiv1.ExecInferiorInEvent,
79 apiv1.ExecInferiorOutEvent,
82 var fwdFuncID []uuid.UUID
83 for _, evName := range evtList {
85 fwdFunc := func(pData interface{}, evData interface{}) error {
87 // IO socket can be nil when disconnected
88 so := s.sessions.IOSocketGet(sid)
90 s.Log.Infof("%s not emitted: WS closed (sid:%s)", evN, sid)
94 // Add sessionID to event Data
95 reflectme.SetField(evData, "sessionID", sid)
97 // Forward event to Client/Dashboard
98 (*so).Emit(evN, evData)
101 id, err := svr.EventOn(evN, sess.ID, fwdFunc)
103 common.APIError(c, err.Error())
106 fwdFuncID = append(fwdFuncID, id)
109 // Handle Exit event separately to cleanup registered listener
110 var exitFuncID uuid.UUID
111 exitFunc := func(pData interface{}, evData interface{}) error {
112 evN := apiv1.ExecExitEvent
113 sid := pData.(string)
115 // Add sessionID to event Data
116 reflectme.SetField(evData, "sessionID", sid)
118 // IO socket can be nil when disconnected
119 so := s.sessions.IOSocketGet(sid)
121 (*so).Emit(evN, evData)
123 s.Log.Infof("%s not emitted: WS closed (sid:%s)", evN, sid)
127 for i, evName := range evtList {
128 svr.EventOff(evName, fwdFuncID[i])
130 svr.EventOff(evN, exitFuncID)
134 exitFuncID, err = svr.EventOn(apiv1.ExecExitEvent, sess.ID, exitFunc)
136 common.APIError(c, err.Error())
140 // Forward back command to right server
141 response, err := svr.SendCommand(cmd, data)
143 common.APIError(c, err.Error())
148 body, err := ioutil.ReadAll(response.Body)
150 common.APIError(c, "Cannot read response body")
153 c.JSON(http.StatusOK, string(body))