Skip to content

Commit 38b2894

Browse files
author
Sunghoon Kang
committed
Import go-akuity into grpc-gateway-client
Signed-off-by: Sunghoon Kang <[email protected]>
1 parent 4acdaf7 commit 38b2894

30 files changed

+1723
-121
lines changed

go.mod

+5-3
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,21 @@ module github.com/akuity/grpc-gateway-client
33
go 1.20
44

55
require (
6-
github.com/akuity/go-akuity v0.0.0-20230304081857-7177ba20624a
6+
github.com/alevinval/sse v1.0.1
7+
github.com/go-resty/resty/v2 v2.7.0
78
github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2
89
github.com/stretchr/testify v1.8.2
910
google.golang.org/genproto v0.0.0-20230303212802-e74f57abe488
1011
google.golang.org/grpc v1.53.0
12+
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0
1113
google.golang.org/protobuf v1.28.2-0.20230222093303-bc1253ad3743
1214
)
1315

1416
require (
15-
github.com/alevinval/sse v1.0.1 // indirect
1617
github.com/davecgh/go-spew v1.1.1 // indirect
17-
github.com/go-resty/resty/v2 v2.7.0 // indirect
18+
github.com/golang/glog v1.0.0 // indirect
1819
github.com/golang/protobuf v1.5.2 // indirect
20+
github.com/kr/text v0.2.0 // indirect
1921
github.com/pmezard/go-difflib v1.0.0 // indirect
2022
golang.org/x/net v0.7.0 // indirect
2123
golang.org/x/sys v0.5.0 // indirect

go.sum

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
github.com/akuity/go-akuity v0.0.0-20230304081857-7177ba20624a h1:sZ9MaltiOMC/ydyWEOQgLFYgorhYq+4JnbhQsdDhu50=
2-
github.com/akuity/go-akuity v0.0.0-20230304081857-7177ba20624a/go.mod h1:iBOIBw6+nnYKr021QHY+hO5/u9cTlgvN5dSgZGYeEIw=
31
github.com/alevinval/sse v1.0.1 h1:cFubh2lMNdHT6niFLCsyTuhAgljaAWbdmceAe6qPIfo=
42
github.com/alevinval/sse v1.0.1/go.mod h1:Bvl1EawUlmW1y1vSU5uDl03+1Zsqqz/+6D2PAUvftcw=
3+
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
54
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
65
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
76
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
87
github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY=
98
github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I=
109
github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=
10+
github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
1111
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
1212
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
1313
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
@@ -17,6 +17,7 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2 h1:gDLXvp5S9izjldquuoAhDzccbsk
1717
github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2/go.mod h1:7pdNwVWBBHGiCxa9lAszqCJMbfTISJ7oMftp8+UGV08=
1818
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
1919
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
20+
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
2021
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
2122
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
2223
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -43,6 +44,8 @@ google.golang.org/genproto v0.0.0-20230303212802-e74f57abe488 h1:QQF+HdiI4iocoxU
4344
google.golang.org/genproto v0.0.0-20230303212802-e74f57abe488/go.mod h1:TvhZT5f700eVlTNwND1xoEZQeWTB2RY/65kplwl/bFA=
4445
google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc=
4546
google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
47+
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 h1:rNBFJjBCOgVr9pWD7rs/knKL4FRTKgpZmsRfV214zcA=
48+
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0/go.mod h1:Dk1tviKTvMCz5tvh7t+fh94dhmQVHuCt2OzJB3CTW9Y=
4649
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
4750
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
4851
google.golang.org/protobuf v1.28.2-0.20230222093303-bc1253ad3743 h1:yqElulDvOF26oZ2O+2/aoX7mQ8DY/6+p39neytrycd8=

internal/generator/packages.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ var (
1111

1212
// Akuity packages
1313
var (
14-
pkgGatewayClient = protogen.GoImportPath("github.com/akuity/go-akuity/pkg/grpc/gateway")
14+
pkgGatewayClient = protogen.GoImportPath("github.com/akuity/grpc-gateway-client/pkg/grpc/gateway")
1515
)
1616

1717
// protobuf packages

pkg/context/context.go

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package context
2+
3+
import "context"
4+
5+
func Get[K comparable, V any](ctx context.Context, key K) (V, bool) {
6+
v, ok := ctx.Value(key).(V)
7+
return v, ok
8+
}
9+
10+
func Set[K comparable, V any](ctx context.Context, key K, val V) context.Context {
11+
return context.WithValue(ctx, key, val)
12+
}

pkg/context/context_test.go

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package context
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/stretchr/testify/require"
8+
)
9+
10+
type dummyKey struct {
11+
/* explicitly empty */
12+
}
13+
14+
func TestGet(t *testing.T) {
15+
type testSet[K, V any] struct {
16+
newContextFunc func() context.Context
17+
key K
18+
shouldExists bool
19+
value V
20+
}
21+
testSets := map[string]testSet[dummyKey, string]{
22+
"get existing value": {
23+
newContextFunc: func() context.Context {
24+
return context.WithValue(context.TODO(), dummyKey{}, "some value")
25+
},
26+
key: dummyKey{},
27+
value: "some value",
28+
shouldExists: true,
29+
},
30+
"get non-existing value": {
31+
newContextFunc: context.TODO,
32+
key: dummyKey{},
33+
shouldExists: false,
34+
},
35+
}
36+
for name, ts := range testSets {
37+
t.Run(name, func(t *testing.T) {
38+
ctx := ts.newContextFunc()
39+
actual, ok := Get[dummyKey, string](ctx, ts.key)
40+
if !ts.shouldExists {
41+
require.False(t, ok)
42+
return
43+
}
44+
require.True(t, ok)
45+
require.Equal(t, ts.value, actual)
46+
})
47+
}
48+
}
49+
50+
func TestSet(t *testing.T) {
51+
testSets := map[string]struct {
52+
key interface{}
53+
value interface{}
54+
}{
55+
"set boolean value": {
56+
key: dummyKey{},
57+
value: true,
58+
},
59+
"set integer value": {
60+
key: dummyKey{},
61+
value: 1234,
62+
},
63+
"set string value": {
64+
key: dummyKey{},
65+
value: "some value",
66+
},
67+
}
68+
for name, ts := range testSets {
69+
t.Run(name, func(t *testing.T) {
70+
ctx := Set(context.TODO(), ts.key, ts.value)
71+
require.Equal(t, ctx.Value(ts.key), ts.value)
72+
})
73+
}
74+
}

pkg/grpc/gateway/client.go

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package gateway
2+
3+
import (
4+
"net/http"
5+
6+
"github.com/go-resty/resty/v2"
7+
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
8+
)
9+
10+
type Client interface {
11+
NewRequest(method, url string) *resty.Request
12+
13+
Marshal(v interface{}) ([]byte, error)
14+
Unmarshal(data []byte, v interface{}) error
15+
}
16+
17+
type client struct {
18+
httpClient *http.Client
19+
skipTLSVerify bool
20+
rc *resty.Client
21+
22+
marshaller *runtime.JSONPb
23+
}
24+
25+
func NewClient(baseURL string, opts ...ClientOption) Client {
26+
c := &client{}
27+
for _, opt := range opts {
28+
opt(c)
29+
}
30+
31+
if c.httpClient == nil {
32+
c.httpClient = &http.Client{}
33+
}
34+
if c.httpClient.Transport == nil {
35+
c.httpClient.Transport = http.DefaultTransport.(*http.Transport).Clone()
36+
}
37+
setSkipTLSVerify(c.httpClient, c.skipTLSVerify)
38+
39+
if c.marshaller == nil {
40+
c.marshaller = &runtime.JSONPb{}
41+
}
42+
c.rc = resty.NewWithClient(c.httpClient).SetBaseURL(baseURL)
43+
c.rc.JSONMarshal = c.marshaller.Marshal
44+
c.rc.JSONUnmarshal = c.marshaller.Unmarshal
45+
return c
46+
}
47+
48+
func (c *client) NewRequest(method string, url string) *resty.Request {
49+
req := c.rc.NewRequest()
50+
req.Method = method
51+
req.URL = url
52+
return req
53+
}
54+
55+
func (c *client) Marshal(v interface{}) ([]byte, error) {
56+
return c.marshaller.Marshal(v)
57+
}
58+
59+
func (c *client) Unmarshal(data []byte, v interface{}) error {
60+
return c.marshaller.Unmarshal(data, v)
61+
}

pkg/grpc/gateway/http.go

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package gateway
2+
3+
import (
4+
"crypto/tls"
5+
"net/http"
6+
7+
"google.golang.org/grpc/codes"
8+
9+
"github.com/akuity/grpc-gateway-client/pkg/http/roundtripper"
10+
)
11+
12+
func setSkipTLSVerify(hc *http.Client, skip bool) {
13+
rt := roundtripper.GetRoundTripper(hc)
14+
for {
15+
ht, ok := rt.(*http.Transport)
16+
if ok {
17+
if ht.TLSClientConfig == nil {
18+
ht.TLSClientConfig = &tls.Config{}
19+
}
20+
ht.TLSClientConfig.InsecureSkipVerify = skip
21+
break
22+
}
23+
24+
wrapped, ok := rt.(roundtripper.WrappedRoundTripper)
25+
if !ok {
26+
break
27+
}
28+
rt = wrapped.Unwrap()
29+
}
30+
}
31+
32+
// HTTPStatusToCode converts HTTP status code to gRPC error code
33+
// https://github.com/grpc/grpc/blob/9d2a1a3d1aba56d94c56d2e01cf2511d1a082445/doc/http-grpc-status-mapping.md
34+
func HTTPStatusToCode(code int) codes.Code {
35+
switch code {
36+
case http.StatusOK:
37+
return codes.OK
38+
case http.StatusBadRequest:
39+
return codes.Internal
40+
case http.StatusUnauthorized:
41+
return codes.Unauthenticated
42+
case http.StatusForbidden:
43+
return codes.PermissionDenied
44+
case http.StatusNotFound:
45+
return codes.Unimplemented
46+
case http.StatusTooManyRequests:
47+
return codes.Unavailable
48+
case http.StatusBadGateway:
49+
return codes.Unavailable
50+
case http.StatusServiceUnavailable:
51+
return codes.Unavailable
52+
case http.StatusGatewayTimeout:
53+
return codes.Unavailable
54+
default:
55+
return codes.Unknown
56+
}
57+
}

pkg/grpc/gateway/http_test.go

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package gateway
2+
3+
import (
4+
"net/http"
5+
"net/http/httptest"
6+
"testing"
7+
8+
"github.com/stretchr/testify/require"
9+
10+
"github.com/akuity/grpc-gateway-client/pkg/http/roundtripper"
11+
)
12+
13+
var (
14+
_ roundtripper.WrappedRoundTripper = &wrappedTransport{}
15+
_ http.RoundTripper = &unwrappableTransport{}
16+
)
17+
18+
type wrappedTransport struct {
19+
rt http.RoundTripper
20+
}
21+
22+
func (t *wrappedTransport) RoundTrip(req *http.Request) (*http.Response, error) {
23+
return t.rt.RoundTrip(req)
24+
}
25+
26+
func (t *wrappedTransport) Unwrap() http.RoundTripper {
27+
return t.rt
28+
}
29+
30+
type unwrappableTransport struct {
31+
rt http.RoundTripper
32+
}
33+
34+
func (t unwrappableTransport) RoundTrip(req *http.Request) (*http.Response, error) {
35+
return t.rt.RoundTrip(req)
36+
}
37+
38+
func Test_setSkipTLSVerify(t *testing.T) {
39+
testSets := map[string]struct {
40+
newClientFunc func() *http.Client
41+
errExpected bool
42+
}{
43+
"client with default transport": {
44+
newClientFunc: func() *http.Client {
45+
return &http.Client{
46+
Transport: http.DefaultTransport.(*http.Transport).Clone(),
47+
}
48+
},
49+
errExpected: false,
50+
},
51+
"client with wrapped transport": {
52+
newClientFunc: func() *http.Client {
53+
return &http.Client{
54+
Transport: &wrappedTransport{
55+
rt: http.DefaultTransport.(*http.Transport).Clone(),
56+
},
57+
}
58+
},
59+
errExpected: false,
60+
},
61+
"client with unwrappable transport": {
62+
newClientFunc: func() *http.Client {
63+
return &http.Client{
64+
Transport: &unwrappableTransport{
65+
rt: http.DefaultTransport.(*http.Transport).Clone(),
66+
},
67+
}
68+
},
69+
errExpected: true,
70+
},
71+
}
72+
for name, ts := range testSets {
73+
t.Run(name, func(t *testing.T) {
74+
srv := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
75+
w.WriteHeader(http.StatusNoContent)
76+
}))
77+
78+
hc := ts.newClientFunc()
79+
setSkipTLSVerify(hc, true)
80+
res, err := hc.Get(srv.URL)
81+
if ts.errExpected {
82+
require.Error(t, err)
83+
} else {
84+
require.NotNil(t, res)
85+
require.Equal(t, http.StatusNoContent, res.StatusCode)
86+
}
87+
})
88+
}
89+
}

0 commit comments

Comments
 (0)