diff options
Diffstat (limited to 'lib/agent/apiv1-targets.go')
-rw-r--r-- | lib/agent/apiv1-targets.go | 172 |
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) +} |