Skip to content

Commit 7958400

Browse files
committed
ovsdb: use ovsdb/internal/jsonrpc
1 parent 097e1e3 commit 7958400

File tree

2 files changed

+69
-85
lines changed

2 files changed

+69
-85
lines changed

ovsdb/client.go

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,50 +18,82 @@ import (
1818
"bytes"
1919
"encoding/json"
2020
"fmt"
21-
"net/rpc"
22-
"net/rpc/jsonrpc"
21+
"log"
22+
"net"
23+
24+
"github.com/digitalocean/go-openvswitch/ovsdb/internal/jsonrpc"
2325
)
2426

2527
// A Client is an OVSDB client.
2628
type Client struct {
27-
rc *rpc.Client
29+
c *jsonrpc.Conn
30+
ll *log.Logger
31+
}
32+
33+
// An OptionFunc is a function which can configure a Client.
34+
type OptionFunc func(c *Client) error
35+
36+
// Debug enables debug logging for a Client.
37+
func Debug(ll *log.Logger) OptionFunc {
38+
return func(c *Client) error {
39+
c.ll = ll
40+
return nil
41+
}
2842
}
2943

3044
// Dial dials a connection to an OVSDB server and returns a Client.
31-
func Dial(network, addr string) (*Client, error) {
32-
c, err := jsonrpc.Dial(network, addr)
45+
func Dial(network, addr string, options ...OptionFunc) (*Client, error) {
46+
conn, err := net.Dial(network, addr)
3347
if err != nil {
3448
return nil, err
3549
}
3650

37-
return &Client{
38-
rc: c,
39-
}, nil
51+
return New(conn, options...)
52+
}
53+
54+
// New wraps an existing connection to an OVSDB server and returns a Client.
55+
func New(conn net.Conn, options ...OptionFunc) (*Client, error) {
56+
client := &Client{}
57+
for _, o := range options {
58+
if err := o(client); err != nil {
59+
return nil, err
60+
}
61+
}
62+
63+
client.c = jsonrpc.NewConn(conn, client.ll)
64+
65+
return client, nil
4066
}
4167

4268
// Close closes a Client's connection.
4369
func (c *Client) Close() error {
44-
return c.rc.Close()
70+
return c.c.Close()
4571
}
4672

4773
// ListDatabases returns the name of all databases known to the OVSDB server.
4874
func (c *Client) ListDatabases() ([]string, error) {
4975
var dbs []string
50-
if err := c.rpc("list_dbs", nil, &dbs); err != nil {
76+
if err := c.rpc("list_dbs", &dbs); err != nil {
5177
return nil, err
5278
}
5379

5480
return dbs, nil
5581
}
5682

5783
// rpc performs a single RPC request, and checks the response for errors.
58-
func (c *Client) rpc(method string, args, reply interface{}) error {
59-
// Captures any JSON-RPC errors.
84+
func (c *Client) rpc(method string, out interface{}, args ...interface{}) error {
85+
// Captures any OVSDB errors.
6086
r := result{
61-
Reply: reply,
87+
Reply: out,
88+
}
89+
90+
req := jsonrpc.Request{
91+
Method: method,
92+
Params: args,
93+
// Let the client handle the request ID.
6294
}
6395

64-
if err := c.rc.Call(method, args, &r); err != nil {
96+
if err := c.c.Execute(req, &r); err != nil {
6597
return err
6698
}
6799

ovsdb/client_test.go

Lines changed: 23 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,25 @@
1515
package ovsdb_test
1616

1717
import (
18-
"encoding/json"
1918
"fmt"
20-
"net"
21-
"sync"
2219
"testing"
2320

2421
"github.com/digitalocean/go-openvswitch/ovsdb"
22+
"github.com/digitalocean/go-openvswitch/ovsdb/internal/jsonrpc"
2523
"github.com/google/go-cmp/cmp"
2624
)
2725

2826
func TestClientError(t *testing.T) {
2927
const str = "some error"
3028

31-
c, done := testClient(t, func(_ string, _ []interface{}) interface{} {
32-
return &ovsdb.Error{
33-
Err: str,
34-
Details: "malformed",
35-
Syntax: "{}",
29+
c, done := testClient(t, func(_ jsonrpc.Request) jsonrpc.Response {
30+
return jsonrpc.Response{
31+
ID: 1,
32+
Result: &ovsdb.Error{
33+
Err: str,
34+
Details: "malformed",
35+
Syntax: "{}",
36+
},
3637
}
3738
})
3839
defer done()
@@ -51,19 +52,23 @@ func TestClientError(t *testing.T) {
5152
t.Fatalf("unexpected error (-want +got):\n%s", diff)
5253
}
5354
}
55+
5456
func TestClientListDatabases(t *testing.T) {
5557
want := []string{"Open_vSwitch", "test"}
5658

57-
c, done := testClient(t, func(method string, params []interface{}) interface{} {
58-
if diff := cmp.Diff("list_dbs", method); diff != "" {
59-
t.Fatalf("unexpected RPC method (-want +got):\n%s", diff)
59+
c, done := testClient(t, func(req jsonrpc.Request) jsonrpc.Response {
60+
if diff := cmp.Diff("list_dbs", req.Method); diff != "" {
61+
panicf("unexpected RPC method (-want +got):\n%s", diff)
6062
}
6163

62-
if diff := cmp.Diff(1, len(params)); diff != "" {
63-
t.Fatalf("unexpected number of RPC parameters (-want +got):\n%s", diff)
64+
if diff := cmp.Diff(0, len(req.Params)); diff != "" {
65+
panicf("unexpected number of RPC parameters (-want +got):\n%s", diff)
6466
}
6567

66-
return want
68+
return jsonrpc.Response{
69+
ID: 1,
70+
Result: want,
71+
}
6772
})
6873
defer done()
6974

@@ -77,70 +82,17 @@ func TestClientListDatabases(t *testing.T) {
7782
}
7883
}
7984

80-
type rpcFunc func(method string, params []interface{}) interface{}
81-
82-
func testClient(t *testing.T, fn rpcFunc) (*ovsdb.Client, func()) {
85+
func testClient(t *testing.T, fn jsonrpc.TestFunc) (*ovsdb.Client, func()) {
8386
t.Helper()
8487

85-
l, err := net.Listen("tcp", ":0")
86-
if err != nil {
87-
t.Fatalf("failed to listen: %v", err)
88-
}
89-
90-
var wg sync.WaitGroup
91-
wg.Add(1)
92-
93-
go func() {
94-
defer wg.Done()
95-
96-
// Accept a single connection.
97-
c, err := l.Accept()
98-
if err != nil {
99-
panicf("failed to accept: %v", err)
100-
}
101-
defer c.Close()
102-
_ = l.Close()
103-
104-
if err := handleConn(c, fn); err != nil {
105-
panicf("failed to handle connection: %v", err)
106-
}
107-
}()
88+
conn, done := jsonrpc.TestNetConn(t, fn)
10889

109-
c, err := ovsdb.Dial("tcp", l.Addr().String())
90+
c, err := ovsdb.New(conn)
11091
if err != nil {
11192
t.Fatalf("failed to dial: %v", err)
11293
}
11394

114-
return c, func() {
115-
// Ensure types are cleaned up, and ensure goroutine stops.
116-
_ = l.Close()
117-
_ = c.Close()
118-
wg.Wait()
119-
}
120-
}
121-
122-
func handleConn(c net.Conn, fn rpcFunc) error {
123-
var req struct {
124-
Method string `json:"method"`
125-
Params []interface{} `json:"params"`
126-
ID int `json:"id"`
127-
}
128-
129-
var res struct {
130-
Result interface{} `json:"result"`
131-
ID int `json:"id"`
132-
}
133-
134-
if err := json.NewDecoder(c).Decode(&req); err != nil {
135-
return err
136-
}
137-
138-
result := fn(req.Method, req.Params)
139-
140-
res.ID = req.ID
141-
res.Result = result
142-
143-
return json.NewEncoder(c).Encode(res)
95+
return c, done
14496
}
14597

14698
func panicf(format string, a ...interface{}) {

0 commit comments

Comments
 (0)