Moved all structs exposed by API into apiv1 package
[src/xds/xds-agent.git] / lib / agent / apiv1-exec.go
1 package agent
2
3 import (
4         "encoding/json"
5         "io/ioutil"
6         "net/http"
7
8         "github.com/gin-gonic/gin"
9         "github.com/iotbzh/xds-agent/lib/apiv1"
10         common "github.com/iotbzh/xds-common/golib"
11         uuid "github.com/satori/go.uuid"
12 )
13
14 var execCmdID = 1
15
16 // ExecCmd executes remotely a command
17 func (s *APIService) execCmd(c *gin.Context) {
18         s._execRequest("/exec", c)
19 }
20
21 // execSignalCmd executes remotely a command
22 func (s *APIService) execSignalCmd(c *gin.Context) {
23         s._execRequest("/signal", c)
24 }
25
26 func (s *APIService) _execRequest(cmd string, c *gin.Context) {
27         data, err := c.GetRawData()
28         if err != nil {
29                 common.APIError(c, err.Error())
30         }
31
32         args := apiv1.ExecArgs{}
33         // XXX - we cannot use c.BindJSON, so directly unmarshall it
34         // (see https://github.com/gin-gonic/gin/issues/1078)
35         if err := json.Unmarshal(data, &args); err != nil {
36                 common.APIError(c, "Invalid arguments")
37                 return
38         }
39
40         // First get Project ID to retrieve Server ID and send command to right server
41         id := c.Param("id")
42         if id == "" {
43                 id = args.ID
44         }
45
46         prj := s.projects.Get(id)
47         if prj == nil {
48                 common.APIError(c, "Unknown id")
49                 return
50         }
51
52         svr := (*prj).GetServer()
53         if svr == nil {
54                 common.APIError(c, "Cannot identify XDS Server")
55                 return
56         }
57
58         // Retrieve session info
59         sess := s.sessions.Get(c)
60         if sess == nil {
61                 common.APIError(c, "Unknown sessions")
62                 return
63         }
64         sock := sess.IOSocket
65         if sock == nil {
66                 common.APIError(c, "Websocket not established")
67                 return
68         }
69
70         // Forward XDSServer WS events to client WS
71         // TODO removed static event name list and get it from XDSServer
72         evtList := []string{
73                 apiv1.ExecInEvent,
74                 apiv1.ExecOutEvent,
75                 apiv1.ExecInferiorInEvent,
76                 apiv1.ExecInferiorOutEvent,
77         }
78         so := *sock
79         fwdFuncID := []uuid.UUID{}
80         for _, evName := range evtList {
81                 evN := evName
82                 fwdFunc := func(evData interface{}) {
83                         // Forward event to Client/Dashboard
84                         so.Emit(evN, evData)
85                 }
86                 id, err := svr.EventOn(evN, fwdFunc)
87                 if err != nil {
88                         common.APIError(c, err.Error())
89                         return
90                 }
91                 fwdFuncID = append(fwdFuncID, id)
92         }
93
94         // Handle Exit event separately to cleanup registered listener
95         var exitFuncID uuid.UUID
96         exitFunc := func(evData interface{}) {
97                 so.Emit(apiv1.ExecExitEvent, evData)
98
99                 // cleanup listener
100                 for i, evName := range evtList {
101                         svr.EventOff(evName, fwdFuncID[i])
102                 }
103                 svr.EventOff(apiv1.ExecExitEvent, exitFuncID)
104         }
105         exitFuncID, err = svr.EventOn(apiv1.ExecExitEvent, exitFunc)
106         if err != nil {
107                 common.APIError(c, err.Error())
108                 return
109         }
110
111         // Forward back command to right server
112         response, err := svr.SendCommand(cmd, data)
113         if err != nil {
114                 common.APIError(c, err.Error())
115                 return
116         }
117
118         // Decode response
119         body, err := ioutil.ReadAll(response.Body)
120         if err != nil {
121                 common.APIError(c, "Cannot read response body")
122                 return
123         }
124         c.JSON(http.StatusOK, string(body))
125 }