Stats API: added GetMemory()
[govpp.git] / proxy / client.go
1 //  Copyright (c) 2019 Cisco and/or its affiliates.
2 //
3 //  Licensed under the Apache License, Version 2.0 (the "License");
4 //  you may not use this file except in compliance with the License.
5 //  You may obtain a copy of the License at:
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 //  Unless required by applicable law or agreed to in writing, software
10 //  distributed under the License is distributed on an "AS IS" BASIS,
11 //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 //  See the License for the specific language governing permissions and
13 //  limitations under the License.
14
15 package proxy
16
17 import (
18         "fmt"
19         "net/rpc"
20         "reflect"
21         "time"
22
23         "git.fd.io/govpp.git/api"
24         "git.fd.io/govpp.git/core"
25 )
26
27 type Client struct {
28         serverAddr string
29         rpc        *rpc.Client
30 }
31
32 // Connect dials remote proxy server on given address and
33 // returns new client if successful.
34 func Connect(addr string) (*Client, error) {
35         client, err := rpc.DialHTTP("tcp", addr)
36         if err != nil {
37                 return nil, fmt.Errorf("connection error:%v", err)
38         }
39         c := &Client{
40                 serverAddr: addr,
41                 rpc:        client,
42         }
43         return c, nil
44 }
45
46 // NewStatsClient returns new StatsClient which implements api.StatsProvider.
47 func (c *Client) NewStatsClient() (*StatsClient, error) {
48         stats := &StatsClient{
49                 rpc: c.rpc,
50         }
51         return stats, nil
52 }
53
54 // NewBinapiClient returns new BinapiClient which implements api.Channel.
55 func (c *Client) NewBinapiClient() (*BinapiClient, error) {
56         binapi := &BinapiClient{
57                 rpc:     c.rpc,
58                 timeout: core.DefaultReplyTimeout,
59         }
60         return binapi, nil
61 }
62
63 type StatsClient struct {
64         rpc *rpc.Client
65 }
66
67 func (s *StatsClient) GetSystemStats(sysStats *api.SystemStats) error {
68         // we need to start with a clean, zeroed item before decoding
69         // 'cause if the new values are 'zero' for the type, they will be ignored
70         // by the decoder. (i.e the old values will be left unchanged).
71         req := StatsRequest{StatsType: "system"}
72         resp := StatsResponse{SysStats: new(api.SystemStats)}
73         if err := s.rpc.Call("StatsRPC.GetStats", req, &resp); err != nil {
74                 return err
75         }
76         *sysStats = *resp.SysStats
77         return nil
78 }
79
80 func (s *StatsClient) GetNodeStats(nodeStats *api.NodeStats) error {
81         req := StatsRequest{StatsType: "node"}
82         resp := StatsResponse{NodeStats: new(api.NodeStats)}
83         if err := s.rpc.Call("StatsRPC.GetStats", req, &resp); err != nil {
84                 return err
85         }
86         *nodeStats = *resp.NodeStats
87         return nil
88 }
89
90 func (s *StatsClient) GetInterfaceStats(ifaceStats *api.InterfaceStats) error {
91         req := StatsRequest{StatsType: "interface"}
92         resp := StatsResponse{IfaceStats: new(api.InterfaceStats)}
93         if err := s.rpc.Call("StatsRPC.GetStats", req, &resp); err != nil {
94                 return err
95         }
96         *ifaceStats = *resp.IfaceStats
97         return nil
98 }
99
100 func (s *StatsClient) GetErrorStats(errStats *api.ErrorStats) error {
101         req := StatsRequest{StatsType: "error"}
102         resp := StatsResponse{ErrStats: new(api.ErrorStats)}
103         if err := s.rpc.Call("StatsRPC.GetStats", req, &resp); err != nil {
104                 return err
105         }
106         *errStats = *resp.ErrStats
107         return nil
108 }
109
110 func (s *StatsClient) GetBufferStats(bufStats *api.BufferStats) error {
111         req := StatsRequest{StatsType: "buffer"}
112         resp := StatsResponse{BufStats: new(api.BufferStats)}
113         if err := s.rpc.Call("StatsRPC.GetStats", req, &resp); err != nil {
114                 return err
115         }
116         *bufStats = *resp.BufStats
117         return nil
118 }
119
120 func (s *StatsClient) GetMemoryStats(memStats *api.MemoryStats) error {
121         req := StatsRequest{StatsType: "memory"}
122         resp := StatsResponse{MemStats: new(api.MemoryStats)}
123         if err := s.rpc.Call("StatsRPC.GetStats", req, &resp); err != nil {
124                 return err
125         }
126         *memStats = *resp.MemStats
127         return nil
128 }
129
130 type BinapiClient struct {
131         rpc     *rpc.Client
132         timeout time.Duration
133 }
134
135 func (b *BinapiClient) SendRequest(msg api.Message) api.RequestCtx {
136         req := &requestCtx{
137                 rpc:     b.rpc,
138                 timeout: b.timeout,
139                 req:     msg,
140         }
141         log.Debugf("SendRequest: %T %+v", msg, msg)
142         return req
143 }
144
145 type requestCtx struct {
146         rpc     *rpc.Client
147         req     api.Message
148         timeout time.Duration
149 }
150
151 func (r *requestCtx) ReceiveReply(msg api.Message) error {
152         req := BinapiRequest{
153                 Msg:      r.req,
154                 ReplyMsg: msg,
155                 Timeout:  r.timeout,
156         }
157         resp := BinapiResponse{}
158
159         err := r.rpc.Call("BinapiRPC.Invoke", req, &resp)
160         if err != nil {
161                 return fmt.Errorf("RPC call failed: %v", err)
162         }
163
164         // we set the value of msg to the value from response
165         reflect.ValueOf(msg).Elem().Set(reflect.ValueOf(resp.Msg).Elem())
166
167         return nil
168 }
169
170 func (b *BinapiClient) SendMultiRequest(msg api.Message) api.MultiRequestCtx {
171         req := &multiRequestCtx{
172                 rpc:     b.rpc,
173                 timeout: b.timeout,
174                 req:     msg,
175         }
176         log.Debugf("SendMultiRequest: %T %+v", msg, msg)
177         return req
178 }
179
180 type multiRequestCtx struct {
181         rpc     *rpc.Client
182         req     api.Message
183         timeout time.Duration
184
185         index   int
186         replies []api.Message
187 }
188
189 func (r *multiRequestCtx) ReceiveReply(msg api.Message) (stop bool, err error) {
190         // we call Invoke only on first ReceiveReply
191         if r.index == 0 {
192                 req := BinapiRequest{
193                         Msg:      r.req,
194                         ReplyMsg: msg,
195                         IsMulti:  true,
196                         Timeout:  r.timeout,
197                 }
198                 resp := BinapiResponse{}
199
200                 err := r.rpc.Call("BinapiRPC.Invoke", req, &resp)
201                 if err != nil {
202                         return false, fmt.Errorf("RPC call failed: %v", err)
203                 }
204
205                 r.replies = resp.Msgs
206         }
207
208         if r.index >= len(r.replies) {
209                 return true, nil
210         }
211
212         // we set the value of msg to the value from response
213         reflect.ValueOf(msg).Elem().Set(reflect.ValueOf(r.replies[r.index]).Elem())
214         r.index++
215
216         return false, nil
217 }
218
219 func (b *BinapiClient) SubscribeNotification(notifChan chan api.Message, event api.Message) (api.SubscriptionCtx, error) {
220         panic("implement me")
221 }
222
223 func (b *BinapiClient) SetReplyTimeout(timeout time.Duration) {
224         b.timeout = timeout
225 }
226
227 func (b *BinapiClient) CheckCompatiblity(msgs ...api.Message) error {
228         msgNamesCrscs := make([]string, 0, len(msgs))
229
230         for _, msg := range msgs {
231                 msgNamesCrscs = append(msgNamesCrscs, msg.GetMessageName()+"_"+msg.GetCrcString())
232         }
233
234         req := BinapiCompatibilityRequest{MsgNameCrcs: msgNamesCrscs}
235         resp := BinapiCompatibilityResponse{}
236
237         if err := b.rpc.Call("BinapiRPC.Compatibility", req, &resp); err != nil {
238                 return err
239         }
240
241         return nil
242 }
243
244 func (b *BinapiClient) Close() {
245         b.rpc.Close()
246 }