Use go module as dependency tool instead of glide
[src/xds/xds-agent.git] / lib / agent / apiv1-targets.go
1 /*
2  * Copyright (C) 2018 "IoT.bzh"
3  * Author Sebastien Douheret <sebastien@iot.bzh>
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 package agent
19
20 import (
21         "encoding/json"
22         "fmt"
23         "net/http"
24
25         "gerrit.automotivelinux.org/gerrit/src/xds/xds-agent.git/lib/xaapiv1"
26         common "gerrit.automotivelinux.org/gerrit/src/xds/xds-common.git"
27         "gerrit.automotivelinux.org/gerrit/src/xds/xds-server.git/lib/xsapiv1"
28         "github.com/franciscocpg/reflectme"
29         "github.com/gin-gonic/gin"
30         uuid "github.com/satori/go.uuid"
31 )
32
33 // targetsPassthroughInit Declare passthrough routes for targets
34 func (s *APIService) targetsPassthroughInit(svr *XdsServer) error {
35         svr.PassthroughGet("/targets")
36         svr.PassthroughGet("/targets/:id")
37         svr.PassthroughPost("/targets")
38         svr.PassthroughDelete("/targets/:id")
39
40         svr.PassthroughGet("/targets/:id/terminals")
41         svr.PassthroughGet("/targets/:id/terminals/:tid")
42         svr.PassthroughPost("/targets/:id/terminals")
43         svr.PassthroughPut("/targets/:id/terminals/:tid")
44         svr.PassthroughDelete("/targets/:id/terminals/:tid")
45
46         svr.apiRouter.POST("/targets/:id/terminals/:tid/open", s.TargetTerminalOpen)
47
48         svr.PassthroughPost("/targets/:id/terminals/:tid/close")
49         svr.PassthroughPost("/targets/:id/terminals/:tid/resize")
50         svr.PassthroughPost("/targets/:id/terminals/:tid/signal")
51         svr.PassthroughPost("/targets/:id/terminals/:tid/signal/:sig")
52
53         return nil
54 }
55
56 // targetsEventsForwardInit Register events forwarder for targets
57 func (s *APIService) targetsEventsForwardInit(svr *XdsServer) error {
58
59         if !svr.Connected {
60                 return fmt.Errorf("Cannot register events: XDS Server %v not connected", svr.ID)
61         }
62
63         // Forward Target events from XDS-server to client
64         if _, err := svr.EventOn(xsapiv1.EVTTargetAdd, xaapiv1.EVTTargetAdd, s._targetsEventCB); err != nil {
65                 s.Log.Errorf("XDS Server EventOn '%s' failed: %v", xsapiv1.EVTTargetAdd, err)
66                 return err
67         }
68         if _, err := svr.EventOn(xsapiv1.EVTTargetRemove, xaapiv1.EVTTargetRemove, s._targetsEventCB); err != nil {
69                 s.Log.Errorf("XDS Server EventOn '%s' failed: %v", xsapiv1.EVTTargetRemove, err)
70                 return err
71         }
72         if _, err := svr.EventOn(xsapiv1.EVTTargetStateChange, xaapiv1.EVTTargetStateChange, s._targetsEventCB); err != nil {
73                 s.Log.Errorf("XDS Server EventOn '%s' failed: %v", xsapiv1.EVTTargetStateChange, err)
74                 return err
75         }
76
77         return nil
78 }
79
80 func (s *APIService) _targetsEventCB(privD interface{}, data interface{}) error {
81         evt := xsapiv1.EventMsg{}
82         d, err := json.Marshal(data)
83         if err != nil {
84                 s.Log.Errorf("Cannot marshal XDS Server Target event err=%v, data=%v", err, data)
85                 return err
86         }
87         if err = json.Unmarshal(d, &evt); err != nil {
88                 s.Log.Errorf("Cannot unmarshal XDS Server Target event err=%v, d=%v", err, string(d))
89                 return err
90         }
91
92         // assume that xsapiv1.TargetConfig == xaapiv1.TargetConfig
93         target, err := evt.DecodeTargetEvent()
94         if err != nil {
95                 s.Log.Errorf("Cannot decode XDS Server Target event: err=%v, data=%v", err, data)
96                 return err
97         }
98
99         evtName := privD.(string)
100
101         if err := s.events.Emit(evtName, target, ""); err != nil {
102                 s.Log.Warningf("Cannot notify %s (from server): %v", evtName, err)
103                 return err
104         }
105         return nil
106 }
107
108 // terminalsEventsForwardInit Register events forwarder for terminals
109 func (s *APIService) terminalsEventsForwardInit(svr *XdsServer) error {
110
111         if !svr.Connected {
112                 return fmt.Errorf("Cannot register events: XDS Server %v not connected", svr.ID)
113         }
114
115         // Forward Terminal events from XDS-server to client
116         if _, err := svr.EventOn(xsapiv1.EVTTargetTerminalAdd, xaapiv1.EVTTargetTerminalAdd, s._terminalsEventCB); err != nil {
117                 s.Log.Errorf("XDS Server EventOn '%s' failed: %v", xsapiv1.EVTTargetTerminalAdd, err)
118                 return err
119         }
120         if _, err := svr.EventOn(xsapiv1.EVTTargetTerminalRemove, xaapiv1.EVTTargetTerminalRemove, s._terminalsEventCB); err != nil {
121                 s.Log.Errorf("XDS Server EventOn '%s' failed: %v", xsapiv1.EVTTargetTerminalRemove, err)
122                 return err
123         }
124         if _, err := svr.EventOn(xsapiv1.EVTTargetTerminalStateChange, xaapiv1.EVTTargetTerminalStateChange, s._terminalsEventCB); err != nil {
125                 s.Log.Errorf("XDS Server EventOn '%s' failed: %v", xsapiv1.EVTTargetTerminalStateChange, err)
126                 return err
127         }
128
129         return nil
130 }
131
132 func (s *APIService) _terminalsEventCB(privD interface{}, data interface{}) error {
133         evt := xsapiv1.EventMsg{}
134         d, err := json.Marshal(data)
135         if err != nil {
136                 s.Log.Errorf("Cannot marshal XDS Server Target event err=%v, data=%v", err, data)
137                 return err
138         }
139         if err = json.Unmarshal(d, &evt); err != nil {
140                 s.Log.Errorf("Cannot unmarshal XDS Server Target event err=%v, d=%v", err, string(d))
141                 return err
142         }
143
144         // assume that xsapiv1.TargetConfig == xaapiv1.TargetConfig
145         target, err := evt.DecodeTerminalEvent()
146         if err != nil {
147                 s.Log.Errorf("Cannot decode XDS Server Target event: err=%v, data=%v", err, data)
148                 return err
149         }
150
151         evtName := privD.(string)
152
153         if err := s.events.Emit(evtName, target, ""); err != nil {
154                 s.Log.Warningf("Cannot notify %s (from server): %v", evtName, err)
155                 return err
156         }
157         return nil
158 }
159
160 // GetServerFromTargetID Retrieve XDS Server definition from a target ID
161 func (s *APIService) GetServerFromTargetID(targetID, termID string) (*XdsServer, string, error) {
162
163         // FIXME add cache (but take care to support partial term ID)
164         for _, svr := range s.xdsServers {
165                 term := xsapiv1.TerminalConfig{}
166                 if err := svr.CommandTgtTerminalGet(targetID, termID, &term); err == nil {
167                         return svr, term.ID, nil
168                 }
169         }
170         return nil, "", fmt.Errorf("Cannot identify XDS Server")
171 }
172
173 // TargetTerminalOpen Open a target terminal/console
174 func (s *APIService) TargetTerminalOpen(c *gin.Context) {
175
176         // First retrieve Server ID and send command to right server
177         targetID := c.Param("id")
178         svr, termID, err := s.GetServerFromTargetID(targetID, c.Param("tid"))
179         if err != nil {
180                 common.APIError(c, err.Error())
181                 return
182         }
183
184         // Retrieve session info
185         sess := s.sessions.Get(c)
186         if sess == nil {
187                 common.APIError(c, "Unknown sessions")
188                 return
189         }
190         sock := sess.IOSocket
191         if sock == nil {
192                 common.APIError(c, "Websocket not established")
193                 return
194         }
195
196         // Forward input events from client to XDSServer through WS
197         err = (*sock).On(xsapiv1.TerminalInEvent, func(stdin string) {
198                 s.LogSillyf("TARGET TERMINAL EVENT IN (%s) <<%v>>", xsapiv1.TerminalInEvent, stdin)
199                 svr.EventEmit(xaapiv1.TerminalInEvent, stdin)
200         })
201         if err != nil {
202                 msgErr := "Error while registering WS for " + xsapiv1.TerminalInEvent + " event"
203                 s.Log.Errorf(msgErr, ", err: %v", err)
204                 common.APIError(c, msgErr)
205                 return
206         }
207
208         // Forward output events from XDSServer to client through WS
209         var outFwdFuncID uuid.UUID
210         outFwdFunc := func(pData interface{}, evData interface{}) error {
211                 sid := pData.(string)
212                 // IO socket can be nil when disconnected
213                 so := s.sessions.IOSocketGet(sid)
214                 if so == nil {
215                         s.Log.Infof("%s not emitted: WS closed (sid:%s)", xaapiv1.TerminalOutEvent, sid)
216                         return nil
217                 }
218
219                 // Add sessionID to event Data
220                 reflectme.SetField(evData, "sessionID", sid)
221
222                 s.LogSillyf("TARGET TERMINAL EVENT OUT (%s) <<%v>>", xaapiv1.TerminalOutEvent, evData)
223
224                 // Forward event to Client/Dashboard
225                 (*so).Emit(xaapiv1.TerminalOutEvent, evData)
226                 return nil
227         }
228         outFwdFuncID, err = svr.EventOn(xsapiv1.TerminalOutEvent, sess.ID, outFwdFunc)
229         if err != nil {
230                 common.APIError(c, err.Error())
231                 return
232         }
233
234         // Handle Exit event separately to cleanup registered listener
235         var exitFuncID uuid.UUID
236         exitFunc := func(privD interface{}, evData interface{}) error {
237                 evN := xaapiv1.TerminalExitEvent
238
239                 pData := privD.(map[string]string)
240                 sid := pData["sessID"]
241
242                 // Add sessionID to event Data
243                 reflectme.SetField(evData, "sessionID", sid)
244
245                 // IO socket can be nil when disconnected
246                 so := s.sessions.IOSocketGet(sid)
247                 if so != nil {
248                         (*so).Emit(evN, evData)
249                 } else {
250                         s.Log.Infof("%s not emitted: WS closed (sid:%s)", evN, sid)
251                 }
252
253                 // cleanup listener
254                 svr.EventOff(xaapiv1.TerminalOutEvent, outFwdFuncID)
255                 svr.EventOff(evN, exitFuncID)
256
257                 return nil
258         }
259
260         privData := map[string]string{
261                 "sessID": sess.ID,
262         }
263         exitFuncID, err = svr.EventOn(xaapiv1.TerminalExitEvent, privData, exitFunc)
264         if err != nil {
265                 common.APIError(c, err.Error())
266                 return
267         }
268
269         // Forward back command to right server
270         res := xsapiv1.TerminalConfig{}
271         if err := svr.CommandTgtTerminalOpen(targetID, termID, &res); err != nil {
272                 common.APIError(c, err.Error())
273                 return
274         }
275
276         c.JSON(http.StatusOK, res)
277 }