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