-
Notifications
You must be signed in to change notification settings - Fork 63
/
client.go
133 lines (119 loc) · 3.37 KB
/
client.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Copyright (c) 2016 Arista Networks, Inc.
// Use of this source code is governed by the Apache License 2.0
// that can be found in the COPYING file.
// Package client provides helper functions for OpenConfig CLI tools.
package client
import (
"io"
"strings"
"sync"
"github.com/aristanetworks/glog"
"github.com/openconfig/gnmi/proto/gnmi"
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
"google.golang.org/protobuf/proto"
)
const defaultPort = "6030"
// PublishFunc is the method to publish responses
type PublishFunc func(addr string, message proto.Message)
// Client is a connected gRPC client
type Client struct {
client gnmi.GNMIClient
ctx context.Context
device string
}
// New creates a new gRPC client and connects it
func New(username, password, addr string, opts []grpc.DialOption) *Client {
device := addr
if !strings.ContainsRune(addr, ':') {
addr += ":" + defaultPort
}
// Make sure we don't move past the grpc.Dial() call until we actually
// established an HTTP/2 connection successfully.
opts = append(opts, grpc.WithBlock())
conn, err := grpc.Dial(addr, opts...)
if err != nil {
glog.Fatalf("Failed to dial: %s", err)
}
glog.Infof("Connected to %s", addr)
client := gnmi.NewGNMIClient(conn)
ctx := context.Background()
if username != "" {
ctx = metadata.NewOutgoingContext(ctx, metadata.Pairs(
"username", username,
"password", password))
}
return &Client{
client: client,
device: device,
ctx: ctx,
}
}
// Get sends a get request and returns the responses
func (c *Client) Get(path string) []*gnmi.Notification {
req := &gnmi.GetRequest{
Path: []*gnmi.Path{
{
Element: strings.Split(path, "/"),
},
},
}
response, err := c.client.Get(c.ctx, req)
if err != nil {
glog.Fatalf("Get failed: %s", err)
}
return response.Notification
}
// Subscribe sends subscriptions, and consumes responses.
// The given publish function is used to publish SubscribeResponses received
// for the given subscriptions, when connected to the given host, with the
// given user/pass pair, or the client-side cert specified in the gRPC opts.
// This function does not normally return so it should probably be run in its
// own goroutine. When this function returns, the given WaitGroup is marked
// as done.
func (c *Client) Subscribe(wg *sync.WaitGroup, subscriptions []string,
publish PublishFunc) {
defer wg.Done()
stream, err := c.client.Subscribe(c.ctx)
if err != nil {
glog.Fatalf("Subscribe failed: %s", err)
}
defer stream.CloseSend()
for _, path := range subscriptions {
sub := &gnmi.SubscribeRequest{
Request: &gnmi.SubscribeRequest_Subscribe{
Subscribe: &gnmi.SubscriptionList{
Subscription: []*gnmi.Subscription{
{
Path: &gnmi.Path{Element: strings.Split(path, "/")},
},
},
},
},
}
glog.Infof("Sending subscribe request: %s", sub)
err = stream.Send(sub)
if err != nil {
glog.Fatalf("Failed to subscribe: %s", err)
}
}
for {
resp, err := stream.Recv()
if err != nil {
if err != io.EOF {
glog.Fatalf("Error received from the server: %s", err)
}
return
}
switch resp := resp.Response.(type) {
case *gnmi.SubscribeResponse_SyncResponse:
if !resp.SyncResponse {
panic("initial sync failed," +
" check that you're using a client compatible with the server")
}
}
glog.V(3).Info(resp)
publish(c.device, resp)
}
}