summaryrefslogtreecommitdiffstats
path: root/lib/agent/apiv1-exec.go
diff options
context:
space:
mode:
Diffstat (limited to 'lib/agent/apiv1-exec.go')
-rw-r--r--lib/agent/apiv1-exec.go131
1 files changed, 131 insertions, 0 deletions
diff --git a/lib/agent/apiv1-exec.go b/lib/agent/apiv1-exec.go
new file mode 100644
index 0000000..37070f7
--- /dev/null
+++ b/lib/agent/apiv1-exec.go
@@ -0,0 +1,131 @@
+package agent
+
+import (
+ "encoding/json"
+ "io/ioutil"
+ "net/http"
+
+ "github.com/gin-gonic/gin"
+ common "github.com/iotbzh/xds-common/golib"
+ uuid "github.com/satori/go.uuid"
+)
+
+// ExecArgs Only define used fields
+type ExecArgs struct {
+ ID string `json:"id" binding:"required"`
+ CmdID string `json:"cmdID"` // command unique ID
+}
+
+var execCmdID = 1
+
+// ExecCmd executes remotely a command
+func (s *APIService) execCmd(c *gin.Context) {
+ s._execRequest("/exec", c)
+}
+
+// execSignalCmd executes remotely a command
+func (s *APIService) execSignalCmd(c *gin.Context) {
+ s._execRequest("/signal", c)
+}
+
+func (s *APIService) _execRequest(cmd string, c *gin.Context) {
+ data, err := c.GetRawData()
+ if err != nil {
+ common.APIError(c, err.Error())
+ }
+
+ args := ExecArgs{}
+ // XXX - we cannot use c.BindJSON, so directly unmarshall it
+ // (see https://github.com/gin-gonic/gin/issues/1078)
+ if err := json.Unmarshal(data, &args); err != nil {
+ common.APIError(c, "Invalid arguments")
+ return
+ }
+
+ // First get Project ID to retrieve Server ID and send command to right server
+ id := c.Param("id")
+ if id == "" {
+ id = args.ID
+ }
+
+ prj := s.projects.Get(id)
+ if prj == nil {
+ common.APIError(c, "Unknown id")
+ return
+ }
+
+ svr := (*prj).GetServer()
+ if svr == nil {
+ common.APIError(c, "Cannot identify XDS Server")
+ return
+ }
+
+ // Retrieve session info
+ sess := s.sessions.Get(c)
+ if sess == nil {
+ common.APIError(c, "Unknown sessions")
+ return
+ }
+ sock := sess.IOSocket
+ if sock == nil {
+ common.APIError(c, "Websocket not established")
+ return
+ }
+
+ // Forward XDSServer WS events to client WS
+ // TODO removed static event name list and get it from XDSServer
+ evtList := []string{
+ "exec:input",
+ "exec:output",
+ "exec:inferior-input",
+ "exec:inferior-output",
+ }
+ so := *sock
+ fwdFuncID := []uuid.UUID{}
+ for _, evName := range evtList {
+ evN := evName
+ fwdFunc := func(evData interface{}) {
+ // Forward event to Client/Dashboard
+ so.Emit(evN, evData)
+ }
+ id, err := svr.EventOn(evN, fwdFunc)
+ if err != nil {
+ common.APIError(c, err.Error())
+ return
+ }
+ fwdFuncID = append(fwdFuncID, id)
+ }
+
+ // Handle Exit event separately to cleanup registered listener
+ var exitFuncID uuid.UUID
+ exitFunc := func(evData interface{}) {
+ so.Emit("exec:exit", evData)
+
+ // cleanup listener
+ for i, evName := range evtList {
+ svr.EventOff(evName, fwdFuncID[i])
+ }
+ svr.EventOff("exec:exit", exitFuncID)
+ }
+ exitFuncID, err = svr.EventOn("exec:exit", exitFunc)
+ if err != nil {
+ common.APIError(c, err.Error())
+ return
+ }
+
+ // Forward back command to right server
+ response, err := svr.SendCommand(cmd, data)
+ if err != nil {
+ common.APIError(c, err.Error())
+ return
+ }
+
+ // Decode response
+ body, err := ioutil.ReadAll(response.Body)
+ if err != nil {
+ common.APIError(c, "Cannot read response body")
+ return
+ }
+ c.JSON(http.StatusOK, string(body))
+
+}