aboutsummaryrefslogtreecommitdiffstats
path: root/lib/agent/apiv1-targets.go
diff options
context:
space:
mode:
Diffstat (limited to 'lib/agent/apiv1-targets.go')
-rw-r--r--lib/agent/apiv1-targets.go172
1 files changed, 172 insertions, 0 deletions
diff --git a/lib/agent/apiv1-targets.go b/lib/agent/apiv1-targets.go
new file mode 100644
index 0000000..5a7862a
--- /dev/null
+++ b/lib/agent/apiv1-targets.go
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2018 "IoT.bzh"
+ * Author Sebastien Douheret <sebastien@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package agent
+
+import (
+ "fmt"
+ "net/http"
+
+ "gerrit.automotivelinux.org/gerrit/src/xds/xds-agent/lib/xaapiv1"
+ common "gerrit.automotivelinux.org/gerrit/src/xds/xds-common.git/golib"
+ "gerrit.automotivelinux.org/gerrit/src/xds/xds-server.git/lib/xsapiv1"
+ "github.com/franciscocpg/reflectme"
+ "github.com/gin-gonic/gin"
+ uuid "github.com/satori/go.uuid"
+)
+
+// targetsPassthroughInit Declare passthrough routes for targets
+func (s *APIService) targetsPassthroughInit(svr *XdsServer) error {
+ svr.PassthroughGet("/targets")
+ svr.PassthroughGet("/targets/:id")
+ svr.PassthroughPost("/targets")
+ svr.PassthroughDelete("/targets/:id")
+
+ svr.PassthroughGet("/targets/:id/terminals")
+ svr.PassthroughGet("/targets/:id/terminals/:tid")
+ svr.PassthroughPost("/targets/:id/terminals")
+ svr.PassthroughPut("/targets/:id/terminals/:tid")
+ svr.PassthroughDelete("/targets/:id/terminals/:tid")
+
+ svr.apiRouter.POST("/targets/:id/terminals/:tid/open", s.TargetTerminalOpen)
+
+ svr.PassthroughPost("/targets/:id/terminals/:tid/close")
+ svr.PassthroughPost("/targets/:id/terminals/:tid/resize")
+ svr.PassthroughPost("/targets/:id/terminals/:tid/signal")
+ svr.PassthroughPost("/targets/:id/terminals/:tid/signal/:sig")
+
+ return nil
+}
+
+// GetServerFromTargetID Retrieve XDS Server definition from a target ID
+func (s *APIService) GetServerFromTargetID(targetID, termID string) (*XdsServer, string, error) {
+
+ // FIXME add cache (but take care to support partial term ID)
+ for _, svr := range s.xdsServers {
+ term := xsapiv1.TerminalConfig{}
+ if err := svr.CommandTgtTerminalGet(targetID, termID, &term); err == nil {
+ return svr, term.ID, nil
+ }
+ }
+ return nil, "", fmt.Errorf("Cannot identify XDS Server")
+}
+
+// TargetTerminalOpen Open a target terminal/console
+func (s *APIService) TargetTerminalOpen(c *gin.Context) {
+
+ // First retrieve Server ID and send command to right server
+ targetID := c.Param("id")
+ svr, termID, err := s.GetServerFromTargetID(targetID, c.Param("tid"))
+ if err != nil {
+ common.APIError(c, err.Error())
+ 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 input events from client to XDSServer through WS
+ err = (*sock).On(xsapiv1.TerminalInEvent, func(stdin string) {
+ s.LogSillyf("TARGET TERMINAL EVENT IN (%s) <<%v>>", xsapiv1.TerminalInEvent, stdin)
+ svr.EventEmit(xaapiv1.TerminalInEvent, stdin)
+ })
+ if err != nil {
+ msgErr := "Error while registering WS for " + xsapiv1.TerminalInEvent + " event"
+ s.Log.Errorf(msgErr, ", err: %v", err)
+ common.APIError(c, msgErr)
+ return
+ }
+
+ // Forward output events from XDSServer to client through WS
+ var outFwdFuncID uuid.UUID
+ outFwdFunc := func(pData interface{}, evData interface{}) error {
+ sid := pData.(string)
+ // IO socket can be nil when disconnected
+ so := s.sessions.IOSocketGet(sid)
+ if so == nil {
+ s.Log.Infof("%s not emitted: WS closed (sid:%s)", xaapiv1.TerminalOutEvent, sid)
+ return nil
+ }
+
+ // Add sessionID to event Data
+ reflectme.SetField(evData, "sessionID", sid)
+
+ s.LogSillyf("TARGET TERMINAL EVENT OUT (%s) <<%v>>", xaapiv1.TerminalOutEvent, evData)
+
+ // Forward event to Client/Dashboard
+ (*so).Emit(xaapiv1.TerminalOutEvent, evData)
+ return nil
+ }
+ outFwdFuncID, err = svr.EventOn(xsapiv1.TerminalOutEvent, sess.ID, outFwdFunc)
+ if err != nil {
+ common.APIError(c, err.Error())
+ return
+ }
+
+ // Handle Exit event separately to cleanup registered listener
+ var exitFuncID uuid.UUID
+ exitFunc := func(privD interface{}, evData interface{}) error {
+ evN := xaapiv1.TerminalExitEvent
+
+ pData := privD.(map[string]string)
+ sid := pData["sessID"]
+
+ // Add sessionID to event Data
+ reflectme.SetField(evData, "sessionID", sid)
+
+ // IO socket can be nil when disconnected
+ so := s.sessions.IOSocketGet(sid)
+ if so != nil {
+ (*so).Emit(evN, evData)
+ } else {
+ s.Log.Infof("%s not emitted: WS closed (sid:%s)", evN, sid)
+ }
+
+ // cleanup listener
+ svr.EventOff(xaapiv1.TerminalOutEvent, outFwdFuncID)
+ svr.EventOff(evN, exitFuncID)
+
+ return nil
+ }
+
+ privData := map[string]string{
+ "sessID": sess.ID,
+ }
+ exitFuncID, err = svr.EventOn(xaapiv1.TerminalExitEvent, privData, exitFunc)
+ if err != nil {
+ common.APIError(c, err.Error())
+ return
+ }
+
+ // Forward back command to right server
+ res := xsapiv1.TerminalConfig{}
+ if err := svr.CommandTgtTerminalOpen(targetID, termID, &res); err != nil {
+ common.APIError(c, err.Error())
+ return
+ }
+
+ c.JSON(http.StatusOK, res)
+}