Skip to content

Commit ec3b59c

Browse files
maxbrunetDmitriyMV
authored andcommitted
fix: address all gRPC deprecations
This addresses all deprecation warnings from `grpc-go` in tests and examples (e.g. use `NewClient` instead of `DialContext`, the context from `DialContext` was only useful if the [`grpc.WithBlock()`] option was used, this is also deprecated) The only exceptions is the change in `proxy/codec.go` to implement `encoding.Codec` instead `grpc.Codec` which is a breaking change. The clients must now use `grpc.NewClient` with the `grpc.WithDefaultCallOptions(grpc.ForceCodec(proxy.Codec()))` option. And servers must now use `grpc.NewServer` `encoding.RegisterCodec(proxy.Codec())` `grpc.ForceServerCodec(proxy.Codec())` option. [`grpc.WithBlock()`]: https://pkg.go.dev/google.golang.org/grpc#WithBlock Signed-off-by: Maxime Brunet <max@brnt.mx> Signed-off-by: Dmitriy Matrenichev <dmitry.matrenichev@siderolabs.com>
1 parent 02f82db commit ec3b59c

File tree

7 files changed

+92
-75
lines changed

7 files changed

+92
-75
lines changed

.golangci.yml

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -94,17 +94,19 @@ linters-settings:
9494
cyclop:
9595
# the maximal code complexity to report
9696
max-complexity: 20
97-
# depguard:
98-
# Main:
99-
# deny:
100-
# - github.com/OpenPeeDeeP/depguard # this is just an example
97+
# depguard:
98+
# rules:
99+
# Main:
100+
# list-mode: lax
101+
# deny:
102+
# - pkg: github.com/OpenPeeDeeP/depguard
103+
# desc: this is just an example
101104

102105
linters:
103106
enable-all: true
104107
disable-all: false
105108
fast: false
106109
disable:
107-
- exhaustivestruct
108110
- exhaustruct
109111
- err113
110112
- forbidigo
@@ -120,27 +122,19 @@ linters:
120122
- mnd
121123
- nestif
122124
- nonamedreturns
123-
- nosnakecase
124125
- paralleltest
125126
- tagalign
126127
- tagliatelle
127128
- thelper
128129
- typecheck
129130
- varnamelen
130131
- wrapcheck
131-
- depguard # Disabled because starting with golangci-lint 1.53.0 it doesn't allow denylist alone anymore
132+
- depguard # an Allow and/or Deny package list must be configured
132133
- testifylint # complains about our assert recorder and has a number of false positives for assert.Greater(t, thing, 1)
133134
- protogetter # complains about us using Value field on typed spec, instead of GetValue which has a different signature
134135
- perfsprint # complains about us using fmt.Sprintf in non-performance critical code, updating just kres took too long
135136
# abandoned linters for which golangci shows the warning that the repo is archived by the owner
136-
- deadcode
137-
- golint
138-
- ifshort
139-
- interfacer
140-
- maligned
141-
- scopelint
142-
- structcheck
143-
- varcheck
137+
- execinquery
144138
# disabled as it seems to be broken - goes into imported libraries and reports issues there
145139
- musttag
146140
- goimports # same as gci

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ GRPC_GATEWAY_VERSION ?= 2.20.0
2323
VTPROTOBUF_VERSION ?= 0.6.0
2424
GOIMPORTS_VERSION ?= 0.21.0
2525
DEEPCOPY_VERSION ?= v0.5.6
26-
GOLANGCILINT_VERSION ?= v1.58.2
26+
GOLANGCILINT_VERSION ?= v1.59.1
2727
GOFUMPT_VERSION ?= v0.6.0
2828
GO_VERSION ?= 1.22.3
2929
GO_BUILDFLAGS ?=

README.md

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,39 +36,47 @@ First, define `Backend` implementation to identify specific upstream.
3636
For one to one proxying, `SingleBackend` might be used:
3737

3838
```go
39+
conn, err := grpc.NewClient(
40+
"api-service.staging.svc.local",
41+
grpc.WithDefaultCallOptions(grpc.ForceCodec(proxy.Codec())),
42+
)
43+
if err != nil {
44+
log.Fatal(err)
45+
}
46+
3947
backend := &proxy.SingleBackend{
4048
GetConn: func(ctx context.Context) (context.Context, *grpc.ClientConn, error) {
4149
md, _ := metadata.FromIncomingContext(ctx)
4250

4351
// Copy the inbound metadata explicitly.
4452
outCtx := metadata.NewOutgoingContext(ctx, md.Copy())
45-
// Make sure we use DialContext so the dialing can be cancelled/time out together with the context.
46-
conn, err := grpc.DialContext(ctx, "api-service.staging.svc.local", grpc.WithCodec(proxy.Codec())) // nolint: staticcheck
4753

48-
return outCtx, conn, err
54+
return outCtx, conn, nil
4955
},
5056
}
5157
```
5258

5359
Defining a `StreamDirector` that decides where (if at all) to send the request
5460

5561
```go
56-
director = func(ctx context.Context, fullMethodName string) (context.Context, *grpc.ClientConn, error) {
62+
director = func(ctx context.Context, fullMethodName string) (proxy.Mode, []proxy.Backend, error) {
5763
// Make sure we never forward internal services.
5864
if strings.HasPrefix(fullMethodName, "/com.example.internal.") {
59-
return nil, nil, grpc.Errorf(codes.Unimplemented, "Unknown method")
65+
return proxy.One2One, nil, status.Errorf(codes.Unimplemented, "Unknown method")
6066
}
61-
md, ok := metadata.FromContext(ctx)
67+
68+
md, ok := metadata.FromIncomingContext(ctx)
69+
6270
if ok {
6371
// Decide on which backend to dial
6472
if val, exists := md[":authority"]; exists && val[0] == "staging.api.example.com" {
65-
// Make sure we use DialContext so the dialing can be cancelled/time out together with the context.
66-
return ctx, backend1, nil
73+
return proxy.One2One, []proxy.Backend{stagingBackend}, nil
6774
} else if val, exists := md[":authority"]; exists && val[0] == "api.example.com" {
68-
return ctx, backend2, nil
75+
return proxy.One2One, []proxy.Backend{prodBackend}, nil
6976
}
7077
}
71-
return nil, grpc.Errorf(codes.Unimplemented, "Unknown method")
78+
79+
return proxy.One2One, nil, status.Errorf(codes.Unimplemented, "Unknown method")
7280
}
7381
```
7482

@@ -77,7 +85,7 @@ The server may have other handlers that will be served locally:
7785

7886
```go
7987
server := grpc.NewServer(
80-
grpc.CustomCodec(proxy.Codec()),
88+
grpc.ForceServerCodec(proxy.Codec()),
8189
grpc.UnknownServiceHandler(
8290
proxy.TransparentHandler(director),
8391
proxy.WithMode(proxy.One2One),

proxy/codec.go

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,29 @@ package proxy
33
import (
44
"fmt"
55

6-
"google.golang.org/grpc"
6+
"google.golang.org/grpc/encoding"
77
"google.golang.org/protobuf/proto"
88
)
99

10-
// Codec returns a proxying grpc.Codec with the default protobuf codec as parent.
10+
// Codec returns a proxying [encoding.Coder] with the default protobuf codec as parent.
1111
//
1212
// See CodecWithParent.
13-
//
14-
//nolint:staticcheck
15-
func Codec() grpc.Codec { //nolint:ireturn
13+
func Codec() encoding.Codec {
1614
return CodecWithParent(&protoCodec{})
1715
}
1816

19-
// CodecWithParent returns a proxying grpc.Codec with a user provided codec as parent.
17+
// CodecWithParent returns a proxying [encoding.Codec] with a user provided codec as parent.
2018
//
2119
// This codec is *crucial* to the functioning of the proxy. It allows the proxy server to be oblivious
2220
// to the schema of the forwarded messages. It basically treats a gRPC message frame as raw bytes.
2321
// However, if the server handler, or the client caller are not proxy-internal functions it will fall back
2422
// to trying to decode the message using a fallback codec.
25-
//
26-
//nolint:staticcheck
27-
func CodecWithParent(fallback grpc.Codec) grpc.Codec { //nolint:ireturn
23+
func CodecWithParent(fallback encoding.Codec) encoding.Codec {
2824
return &rawCodec{fallback}
2925
}
3026

3127
type rawCodec struct {
32-
parentCodec grpc.Codec //nolint: staticcheck
28+
parentCodec encoding.Codec
3329
}
3430

3531
type frame struct {
@@ -61,8 +57,8 @@ func (c *rawCodec) Unmarshal(data []byte, v interface{}) error {
6157
return nil
6258
}
6359

64-
func (c *rawCodec) String() string {
65-
return fmt.Sprintf("proxy>%s", c.parentCodec.String())
60+
func (c *rawCodec) Name() string {
61+
return fmt.Sprintf("proxy>%s", c.parentCodec.Name())
6662
}
6763

6864
// protoCodec is a Codec implementation with protobuf. It is the default rawCodec for gRPC.
@@ -76,6 +72,6 @@ func (protoCodec) Unmarshal(data []byte, v interface{}) error {
7672
return proto.Unmarshal(data, v.(proto.Message)) //nolint:forcetypeassert
7773
}
7874

79-
func (protoCodec) String() string {
75+
func (protoCodec) Name() string {
8076
return "proto"
8177
}

proxy/examples_test.go

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ package proxy_test
55

66
import (
77
"context"
8+
"log"
89
"strings"
910

1011
"google.golang.org/grpc"
1112
"google.golang.org/grpc/codes"
13+
"google.golang.org/grpc/credentials/insecure"
1214
"google.golang.org/grpc/metadata"
1315
"google.golang.org/grpc/status"
1416

@@ -20,7 +22,7 @@ var director proxy.StreamDirector
2022
// ExampleRegisterService is a simple example of registering a service with the proxy.
2123
func ExampleRegisterService() {
2224
// A gRPC server with the proxying codec enabled.
23-
server := grpc.NewServer(grpc.CustomCodec(proxy.Codec())) //nolint: staticcheck
25+
server := grpc.NewServer(grpc.ForceServerCodec(proxy.Codec()))
2426

2527
// Register a TestService with 4 of its methods explicitly.
2628
proxy.RegisterService(server, director,
@@ -35,28 +37,46 @@ func ExampleRegisterService() {
3537
// ExampleTransparentHandler is an example of redirecting all requests to the proxy.
3638
func ExampleTransparentHandler() {
3739
grpc.NewServer(
38-
grpc.CustomCodec(proxy.Codec()), //nolint: staticcheck
39-
grpc.UnknownServiceHandler(proxy.TransparentHandler(director)))
40+
grpc.ForceServerCodec(proxy.Codec()),
41+
grpc.UnknownServiceHandler(proxy.TransparentHandler(director)),
42+
)
4043

4144
// Output:
4245
}
4346

4447
// Provide sa simple example of a director that shields internal services and dials a staging or production backend.
4548
// This is a *very naive* implementation that creates a new connection on every request. Consider using pooling.
4649
func ExampleStreamDirector() {
47-
simpleBackendGen := func(hostname string) proxy.Backend {
50+
simpleBackendGen := func(hostname string) (proxy.Backend, error) {
51+
conn, err := grpc.NewClient(
52+
hostname,
53+
grpc.WithDefaultCallOptions(grpc.ForceCodec(proxy.Codec())),
54+
grpc.WithTransportCredentials(insecure.NewCredentials()),
55+
)
56+
if err != nil {
57+
return nil, err
58+
}
59+
4860
return &proxy.SingleBackend{
4961
GetConn: func(ctx context.Context) (context.Context, *grpc.ClientConn, error) {
5062
md, _ := metadata.FromIncomingContext(ctx)
5163

5264
// Copy the inbound metadata explicitly.
5365
outCtx := metadata.NewOutgoingContext(ctx, md.Copy())
54-
// Make sure we use DialContext so the dialing can be canceled/time out together with the context.
55-
conn, err := grpc.DialContext(ctx, hostname, grpc.WithCodec(proxy.Codec())) //nolint: staticcheck
5666

57-
return outCtx, conn, err
67+
return outCtx, conn, nil
5868
},
59-
}
69+
}, nil
70+
}
71+
72+
stagingBackend, err := simpleBackendGen("api-service.staging.svc.local")
73+
if err != nil {
74+
log.Fatal("failed to create staging backend:", err)
75+
}
76+
77+
prodBackend, err := simpleBackendGen("api-service.prod.svc.local")
78+
if err != nil {
79+
log.Fatal("failed to create production backend:", err)
6080
}
6181

6282
director = func(ctx context.Context, fullMethodName string) (proxy.Mode, []proxy.Backend, error) {
@@ -70,9 +90,9 @@ func ExampleStreamDirector() {
7090
if ok {
7191
// Decide on which backend to dial
7292
if val, exists := md[":authority"]; exists && val[0] == "staging.api.example.com" {
73-
return proxy.One2One, []proxy.Backend{simpleBackendGen("api-service.staging.svc.local")}, nil
93+
return proxy.One2One, []proxy.Backend{stagingBackend}, nil
7494
} else if val, exists := md[":authority"]; exists && val[0] == "api.example.com" {
75-
return proxy.One2One, []proxy.Backend{simpleBackendGen("api-service.prod.svc.local")}, nil
95+
return proxy.One2One, []proxy.Backend{prodBackend}, nil
7696
}
7797
}
7898

proxy/handler_one2many_test.go

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,10 @@ import (
99
"errors"
1010
"fmt"
1111
"io"
12-
"log"
1312
"net"
1413
"os"
1514
"strconv"
1615
"strings"
17-
"sync"
1816
"testing"
1917
"time"
2018

@@ -141,11 +139,7 @@ func (s *assertingMultiService) PingStreamError(pb.MultiService_PingStreamErrorS
141139

142140
type assertingBackend struct {
143141
conn *grpc.ClientConn
144-
145-
addr string
146142
i int
147-
148-
mu sync.Mutex
149143
}
150144

151145
func (b *assertingBackend) String() string {
@@ -157,21 +151,11 @@ func (b *assertingBackend) GetConnection(ctx context.Context, _ string) (context
157151
// Explicitly copy the metadata, otherwise the tests will fail.
158152
outCtx := metadata.NewOutgoingContext(ctx, md.Copy())
159153

160-
if b.addr == "fail" {
154+
if b.conn == nil {
161155
return ctx, nil, status.Error(codes.Unavailable, "backend connection failed")
162156
}
163157

164-
b.mu.Lock()
165-
defer b.mu.Unlock()
166-
167-
if b.conn != nil {
168-
return outCtx, b.conn, nil
169-
}
170-
171-
var err error
172-
b.conn, err = grpc.DialContext(ctx, b.addr, grpc.WithInsecure(), grpc.WithCodec(proxy.Codec())) //nolint: staticcheck
173-
174-
return outCtx, b.conn, err
158+
return outCtx, b.conn, nil
175159
}
176160

177161
func (b *assertingBackend) AppendInfo(streaming bool, resp []byte) ([]byte, error) {
@@ -574,15 +558,23 @@ func (s *ProxyOne2ManySuite) SetupSuite() {
574558
backends := make([]*assertingBackend, numUpstreams)
575559

576560
for i := range backends {
561+
var conn *grpc.ClientConn
562+
conn, err = grpc.NewClient(
563+
s.serverListeners[i].Addr().String(),
564+
grpc.WithTransportCredentials(insecure.NewCredentials()),
565+
grpc.WithDefaultCallOptions(grpc.ForceCodec(proxy.Codec())),
566+
)
567+
require.NoError(s.T(), err)
568+
577569
backends[i] = &assertingBackend{
570+
conn: conn,
578571
i: i,
579-
addr: s.serverListeners[i].Addr().String(),
580572
}
581573
}
582574

583575
failingBackend := &assertingBackend{
576+
conn: nil,
584577
i: -1,
585-
addr: "fail",
586578
}
587579

588580
// Setup of the proxy's Director.
@@ -629,7 +621,7 @@ func (s *ProxyOne2ManySuite) SetupSuite() {
629621
}
630622

631623
s.proxy = grpc.NewServer(
632-
grpc.CustomCodec(proxy.Codec()), //nolint: staticcheck
624+
grpc.ForceServerCodec(proxy.Codec()),
633625
grpc.UnknownServiceHandler(proxy.TransparentHandler(director)),
634626
)
635627
// Ping handler is handled as an explicit registration and not as a TransparentHandler.
@@ -694,5 +686,5 @@ func TestProxyOne2ManySuite(t *testing.T) {
694686
}
695687

696688
func init() {
697-
grpclog.SetLogger(log.New(os.Stderr, "grpc: ", log.LstdFlags)) //nolint: staticcheck
689+
grpclog.SetLoggerV2(grpclog.NewLoggerV2(os.Stderr, os.Stderr, os.Stderr))
698690
}

0 commit comments

Comments
 (0)