Use go module as dependency tool instead of glide
[src/xds/xds-agent.git] / lib / agent / xdsmonitoring.go
1 /*
2  * Copyright (C) 2017-2019 "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         "fmt"
22         "io"
23         "strings"
24         "time"
25
26         common "gerrit.automotivelinux.org/gerrit/src/xds/xds-common.git"
27         uuid "github.com/satori/go.uuid"
28 )
29
30 // XdsMonitoring .
31 type XdsMonitoring struct {
32         *Context
33         ID        string
34         BaseURL   string
35         ConnRetry int
36         Connected bool
37         Disabled  bool
38
39         // Private fields
40         client      *common.HTTPClient
41         logOut      io.Writer
42         cbOnConnect OnConnectedXdsSupervCB
43 }
44
45 // XdsSuperVTraceConfig
46 type XdsSuperVTraceConfig struct {
47         Pid    int    `json:"pid"`
48         Pids   []int  `json:"pids"`
49         WsName string `json:"ws"`
50 }
51
52 // OnConnectedXdsSupervCB connect callback
53 type OnConnectedXdsSupervCB func(svr *XdsMonitoring) error
54
55 // NewXdsMonitoring creates an instance of XdsMonitoring
56 func NewXdsMonitoring(ctx *Context) *XdsMonitoring {
57         return &XdsMonitoring{
58                 Context:   ctx,
59                 ID:        "XdsMonitoring-" + uuid.NewV1().String(),
60                 BaseURL:   ctx.Config.FileConf.ProfileConf.XDSMonitoring.URL,
61                 ConnRetry: ctx.Config.FileConf.ProfileConf.XDSMonitoring.ConnRetry,
62                 Connected: false,
63                 Disabled:  false,
64
65                 logOut: ctx.Log.Out,
66         }
67 }
68
69 // Connect Establish HTTP connection with XDS Monitoring Dameon
70 func (xs *XdsMonitoring) Connect() error {
71         var err error
72         var retry int
73
74         xs.Disabled = false
75         xs.Connected = false
76
77         err = nil
78         for retry = xs.ConnRetry; retry > 0; retry-- {
79                 if err = xs._CreateConnectHTTP(); err == nil {
80                         break
81                 }
82                 if retry == xs.ConnRetry {
83                         // Notify only on the first conn error
84                         // doing that avoid 2 notifs (conn false; conn true) on startup
85                         xs._NotifyState()
86                 }
87                 xs.Log.Infof("Establishing connection to XDS Monitoring daemon (retry %d/%d)", retry, xs.ConnRetry)
88                 time.Sleep(time.Second)
89         }
90         if retry == 0 {
91                 // FIXME: re-use _Reconnect to wait longer in background
92                 return fmt.Errorf("Connection to XDS Monitoring daemon failure")
93         }
94         if err != nil {
95                 return err
96         }
97
98         // Check HTTP connection and establish WS connection
99         err = xs._Connect(false)
100
101         return err
102 }
103
104 // ConnectOn Register a callback on events reception
105 func (xs *XdsMonitoring) ConnectOn(f OnConnectedXdsSupervCB) error {
106         xs.cbOnConnect = f
107         return nil
108 }
109
110 // GetVersion Send Get request to retrieve XDS Monitoring version
111 func (xs *XdsMonitoring) GetVersion(res interface{}) error {
112         // FIXME add suffix URLSuffix in common HTTP client lib instead of _BuildURL
113         return xs.client.Get(xs._BuildURL("/version"), &res)
114 }
115
116 // GetTopo Send Get request to retrieve Services/Daemons topology
117 func (xs *XdsMonitoring) GetTopo(res interface{}) error {
118         return xs.client.Get(xs._BuildURL("/list"), &res)
119 }
120
121 // StartTrace Send Monitoring config and start tracing
122 func (xs *XdsMonitoring) StartTrace(cfg XdsSuperVTraceConfig, res interface{}) error {
123         return xs.client.Post(xs._BuildURL("/trace/start"), cfg, &res)
124 }
125
126 // StopTrace Send Monitoring stop tracing
127 func (xs *XdsMonitoring) StopTrace(res interface{}) error {
128         var cfg interface{}
129         return xs.client.Post(xs._BuildURL("/trace/stop"), cfg, res)
130 }
131
132 /***
133 ** Private functions
134 ***/
135
136 // _BuildURL .
137 func (xs *XdsMonitoring) _BuildURL(url string) string {
138         return url + "?token=HELLO&uuid=magic"
139 }
140
141 // Create HTTP client
142 func (xs *XdsMonitoring) _CreateConnectHTTP() error {
143         var err error
144         // FIXME SEB - Client key not in header but in cookie
145         // temporary workaround: used _BuildURL to append uuid=magic in URL
146         // map[Set-Cookie:[x-afb-uuid-5678=2b185cc3-276b-4097-91fa-d607eaf937e6; Path=/api; Max-Age=32000000; ...
147         //port := strings.Split(xs.BaseURL, ":")[2]
148         //"x-afb-uuid-" + port
149
150         xs.client, err = common.HTTPNewClient(xs.BaseURL,
151                 common.HTTPClientConfig{
152                         //HeaderClientKeyName: "Xds-Sid",
153                         HeaderAPIKeyName: "token",
154                         Apikey:           "HELLO",
155                         URLPrefix:        "/api/xds",
156                         CsrfDisable:      true,
157                         LogOut:           xs.logOut,
158                         LogPrefix:        "XDSSUPERV: ",
159                         LogLevel:         common.HTTPLogLevelWarning,
160                 })
161
162         xs.client.SetLogLevel(xs.Log.Level.String())
163
164         if err != nil {
165                 msg := ": " + err.Error()
166                 if strings.Contains(err.Error(), "connection refused") {
167                         msg = fmt.Sprintf("(url: %s)", xs.BaseURL)
168                 }
169                 return fmt.Errorf("ERROR: cannot connect to XDS Monitoring %s", msg)
170         }
171         if xs.client == nil {
172                 return fmt.Errorf("ERROR: cannot connect to XDS Monitoring (null client)")
173         }
174
175         return nil
176 }
177
178 // _Connect Established HTTP and WS connection
179 func (xs *XdsMonitoring) _Connect(reConn bool) error {
180
181         var res interface{}
182         if err := xs.client.Get(xs._BuildURL("/ping"), &res); err != nil {
183                 xs.Connected = false
184                 if !reConn {
185                         xs._NotifyState()
186                 }
187                 return err
188         }
189
190         xs.Connected = true
191
192         // Call OnConnect callback
193         if xs.cbOnConnect != nil {
194                 xs.cbOnConnect(xs)
195         }
196
197         xs._NotifyState()
198         return nil
199 }
200
201 // _NotifyState Send event to notify changes
202 func (xs *XdsMonitoring) _NotifyState() {
203
204         /* TODO
205         evSts := xaapiv1.ServerCfg{
206                 ID:         xs.ID,
207                 URL:        xs.BaseURL,
208                 APIURL:     xs.APIURL,
209                 PartialURL: xs.PartialURL,
210                 ConnRetry:  xs.ConnRetry,
211                 Connected:  xs.Connected,
212         }
213         if err := xs.events.Emit(xaapiv1.EVTServerConfig, evSts, ""); err != nil {
214                 xs.Log.Warningf("Cannot notify XdsServer state change: %v", err)
215         }
216         */
217 }