Skip to content

Commit ce3e5ec

Browse files
authored
v1.38.x: backport (#4453)
* interop/xds: support xds security on interop server (#4444) * interop/xds: dockerfile for the xds interop client (#4443) * xds/cds: add env var for aggregated and DNS cluster (#4440) * xds: use same format while registering and watching resources (#4422) * client: fix ForceCodec to set content-type header appropriately (#4401)
1 parent 5f95ad6 commit ce3e5ec

File tree

9 files changed

+287
-31
lines changed

9 files changed

+287
-31
lines changed

internal/xds/env/env.go

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,13 @@ const (
3737
// and kept in variable BootstrapFileName.
3838
//
3939
// When both bootstrap FileName and FileContent are set, FileName is used.
40-
BootstrapFileContentEnv = "GRPC_XDS_BOOTSTRAP_CONFIG"
40+
BootstrapFileContentEnv = "GRPC_XDS_BOOTSTRAP_CONFIG"
41+
4142
circuitBreakingSupportEnv = "GRPC_XDS_EXPERIMENTAL_CIRCUIT_BREAKING"
4243
timeoutSupportEnv = "GRPC_XDS_EXPERIMENTAL_ENABLE_TIMEOUT"
4344
faultInjectionSupportEnv = "GRPC_XDS_EXPERIMENTAL_FAULT_INJECTION"
4445
clientSideSecuritySupportEnv = "GRPC_XDS_EXPERIMENTAL_SECURITY_SUPPORT"
46+
aggregateAndDNSSupportEnv = "GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER"
4547

4648
c2pResolverSupportEnv = "GRPC_EXPERIMENTAL_GOOGLE_C2P_RESOLVER"
4749
c2pResolverTestOnlyTrafficDirectorURIEnv = "GRPC_TEST_ONLY_GOOGLE_C2P_RESOLVER_TRAFFIC_DIRECTOR_URI"
@@ -60,6 +62,7 @@ var (
6062
//
6163
// When both bootstrap FileName and FileContent are set, FileName is used.
6264
BootstrapFileContent = os.Getenv(BootstrapFileContentEnv)
65+
6366
// CircuitBreakingSupport indicates whether circuit breaking support is
6467
// enabled, which can be disabled by setting the environment variable
6568
// "GRPC_XDS_EXPERIMENTAL_CIRCUIT_BREAKING" to "false".
@@ -71,17 +74,24 @@ var (
7174
// FaultInjectionSupport is used to control both fault injection and HTTP
7275
// filter support.
7376
FaultInjectionSupport = !strings.EqualFold(os.Getenv(faultInjectionSupportEnv), "false")
74-
// C2PResolverSupport indicates whether support for C2P resolver is enabled.
75-
// This can be enabled by setting the environment variable
76-
// "GRPC_EXPERIMENTAL_GOOGLE_C2P_RESOLVER" to "true".
77-
C2PResolverSupport = strings.EqualFold(os.Getenv(c2pResolverSupportEnv), "true")
7877
// ClientSideSecuritySupport is used to control processing of security
7978
// configuration on the client-side.
8079
//
8180
// Note that there is no env var protection for the server-side because we
8281
// have a brand new API on the server-side and users explicitly need to use
8382
// the new API to get security integration on the server.
8483
ClientSideSecuritySupport = strings.EqualFold(os.Getenv(clientSideSecuritySupportEnv), "true")
84+
// AggregateAndDNSSupportEnv indicates whether processing of aggregated
85+
// cluster and DNS cluster is enabled, which can be enabled by setting the
86+
// environment variable
87+
// "GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER" to
88+
// "true".
89+
AggregateAndDNSSupportEnv = strings.EqualFold(os.Getenv(aggregateAndDNSSupportEnv), "true")
90+
91+
// C2PResolverSupport indicates whether support for C2P resolver is enabled.
92+
// This can be enabled by setting the environment variable
93+
// "GRPC_EXPERIMENTAL_GOOGLE_C2P_RESOLVER" to "true".
94+
C2PResolverSupport = strings.EqualFold(os.Getenv(c2pResolverSupportEnv), "true")
8595
// C2PResolverTestOnlyTrafficDirectorURI is the TD URI for testing.
8696
C2PResolverTestOnlyTrafficDirectorURI = os.Getenv(c2pResolverTestOnlyTrafficDirectorURIEnv)
8797
)

interop/xds/client/Dockerfile

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Copyright 2021 gRPC authors.
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+
# Dockerfile for building the xDS interop client. To build the image, run the
16+
# following command from grpc-go directory:
17+
# docker build -t <TAG> -f interop/xds/client/Dockerfile .
18+
19+
FROM golang:1.16-alpine as build
20+
21+
# Make a grpc-go directory and copy the repo into it.
22+
WORKDIR /go/src/grpc-go
23+
COPY . .
24+
25+
# Build a static binary without cgo so that we can copy just the binary in the
26+
# final image, and can get rid of Go compiler and gRPC-Go dependencies.
27+
RUN go build -tags osusergo,netgo interop/xds/client/client.go
28+
29+
# Second stage of the build which copies over only the client binary and skips
30+
# the Go compiler and gRPC repo from the earlier stage. This significantly
31+
# reduces the docker image size.
32+
FROM alpine
33+
COPY --from=build /go/src/grpc-go/client .
34+
ENTRYPOINT ["./client"]

interop/xds/server/Dockerfile

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Copyright 2021 gRPC authors.
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+
# Dockerfile for building the xDS interop server. To build the image, run the
16+
# following command from grpc-go directory:
17+
# docker build -t <TAG> -f interop/xds/server/Dockerfile .
18+
19+
FROM golang:1.16-alpine as build
20+
21+
# Make a grpc-go directory and copy the repo into it.
22+
WORKDIR /go/src/grpc-go
23+
COPY . .
24+
25+
# Build a static binary without cgo so that we can copy just the binary in the
26+
# final image, and can get rid of the Go compiler and gRPC-Go dependencies.
27+
RUN go build -tags osusergo,netgo interop/xds/server/server.go
28+
29+
# Second stage of the build which copies over only the client binary and skips
30+
# the Go compiler and gRPC repo from the earlier stage. This significantly
31+
# reduces the docker image size.
32+
FROM alpine
33+
COPY --from=build /go/src/grpc-go/server .
34+
ENTRYPOINT ["./server"]

interop/xds/server/server.go

Lines changed: 124 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
*
3-
* Copyright 2020 gRPC authors.
3+
* Copyright 2021 gRPC authors.
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
66
* you may not use this file except in compliance with the License.
@@ -16,29 +16,37 @@
1616
*
1717
*/
1818

19-
// Binary server for xDS interop tests.
19+
// Binary server is the server used for xDS interop tests.
2020
package main
2121

2222
import (
2323
"context"
2424
"flag"
25+
"fmt"
2526
"log"
2627
"net"
2728
"os"
28-
"strconv"
2929

3030
"google.golang.org/grpc"
31+
"google.golang.org/grpc/admin"
32+
"google.golang.org/grpc/credentials/insecure"
3133
"google.golang.org/grpc/grpclog"
34+
"google.golang.org/grpc/health"
3235
"google.golang.org/grpc/metadata"
36+
"google.golang.org/grpc/reflection"
37+
"google.golang.org/grpc/xds"
3338

39+
xdscreds "google.golang.org/grpc/credentials/xds"
40+
healthpb "google.golang.org/grpc/health/grpc_health_v1"
3441
testgrpc "google.golang.org/grpc/interop/grpc_testing"
3542
testpb "google.golang.org/grpc/interop/grpc_testing"
3643
)
3744

3845
var (
39-
port = flag.Int("port", 8080, "The server port")
40-
serverID = flag.String("server_id", "go_server", "Server ID included in response")
41-
hostname = getHostname()
46+
port = flag.Int("port", 8080, "Listening port for test service")
47+
maintenancePort = flag.Int("maintenance_port", 8081, "Listening port for maintenance services like health, reflection, channelz etc when -secure_mode is true. When -secure_mode is false, all these services will be registered on -port")
48+
serverID = flag.String("server_id", "go_server", "Server ID included in response")
49+
secureMode = flag.Bool("secure_mode", false, "If true, retrieve security configuration from the management server. Else, use insecure credentials.")
4250

4351
logger = grpclog.Component("interop")
4452
)
@@ -51,28 +59,126 @@ func getHostname() string {
5159
return hostname
5260
}
5361

54-
type server struct {
62+
// testServiceImpl provides an implementation of the TestService defined in
63+
// grpc.testing package.
64+
type testServiceImpl struct {
5565
testgrpc.UnimplementedTestServiceServer
66+
hostname string
5667
}
5768

58-
func (s *server) EmptyCall(ctx context.Context, _ *testpb.Empty) (*testpb.Empty, error) {
59-
grpc.SetHeader(ctx, metadata.Pairs("hostname", hostname))
69+
func (s *testServiceImpl) EmptyCall(ctx context.Context, _ *testpb.Empty) (*testpb.Empty, error) {
70+
grpc.SetHeader(ctx, metadata.Pairs("hostname", s.hostname))
6071
return &testpb.Empty{}, nil
6172
}
6273

63-
func (s *server) UnaryCall(ctx context.Context, in *testpb.SimpleRequest) (*testpb.SimpleResponse, error) {
64-
grpc.SetHeader(ctx, metadata.Pairs("hostname", hostname))
65-
return &testpb.SimpleResponse{ServerId: *serverID, Hostname: hostname}, nil
74+
func (s *testServiceImpl) UnaryCall(ctx context.Context, in *testpb.SimpleRequest) (*testpb.SimpleResponse, error) {
75+
grpc.SetHeader(ctx, metadata.Pairs("hostname", s.hostname))
76+
return &testpb.SimpleResponse{ServerId: *serverID, Hostname: s.hostname}, nil
77+
}
78+
79+
// xdsUpdateHealthServiceImpl provides an implementation of the
80+
// XdsUpdateHealthService defined in grpc.testing package.
81+
type xdsUpdateHealthServiceImpl struct {
82+
testgrpc.UnimplementedXdsUpdateHealthServiceServer
83+
healthServer *health.Server
84+
}
85+
86+
func (x *xdsUpdateHealthServiceImpl) SetServing(_ context.Context, _ *testpb.Empty) (*testpb.Empty, error) {
87+
x.healthServer.SetServingStatus("", healthpb.HealthCheckResponse_SERVING)
88+
return &testpb.Empty{}, nil
89+
90+
}
91+
92+
func (x *xdsUpdateHealthServiceImpl) SetNotServing(_ context.Context, _ *testpb.Empty) (*testpb.Empty, error) {
93+
x.healthServer.SetServingStatus("", healthpb.HealthCheckResponse_NOT_SERVING)
94+
return &testpb.Empty{}, nil
95+
}
96+
97+
func xdsServingModeCallback(addr net.Addr, args xds.ServingModeChangeArgs) {
98+
logger.Infof("Serving mode for xDS server at %s changed to %s", addr.String(), args.Mode)
99+
if args.Err != nil {
100+
logger.Infof("ServingModeCallback returned error: %v", args.Err)
101+
}
66102
}
67103

68104
func main() {
69105
flag.Parse()
70-
p := strconv.Itoa(*port)
71-
lis, err := net.Listen("tcp", ":"+p)
106+
107+
if *secureMode && *port == *maintenancePort {
108+
logger.Fatal("-port and -maintenance_port must be different when -secure_mode is set")
109+
}
110+
111+
testService := &testServiceImpl{hostname: getHostname()}
112+
healthServer := health.NewServer()
113+
updateHealthService := &xdsUpdateHealthServiceImpl{healthServer: healthServer}
114+
115+
// If -secure_mode is not set, expose all services on -port with a regular
116+
// gRPC server.
117+
if !*secureMode {
118+
lis, err := net.Listen("tcp4", fmt.Sprintf(":%d", *port))
119+
if err != nil {
120+
logger.Fatalf("net.Listen(%s) failed: %v", fmt.Sprintf(":%d", *port), err)
121+
}
122+
123+
server := grpc.NewServer()
124+
testgrpc.RegisterTestServiceServer(server, testService)
125+
healthServer.SetServingStatus("", healthpb.HealthCheckResponse_SERVING)
126+
healthpb.RegisterHealthServer(server, healthServer)
127+
testgrpc.RegisterXdsUpdateHealthServiceServer(server, updateHealthService)
128+
reflection.Register(server)
129+
cleanup, err := admin.Register(server)
130+
if err != nil {
131+
logger.Fatalf("Failed to register admin services: %v", err)
132+
}
133+
defer cleanup()
134+
if err := server.Serve(lis); err != nil {
135+
logger.Errorf("Serve() failed: %v", err)
136+
}
137+
return
138+
}
139+
140+
// Create a listener on -port to expose the test service.
141+
testLis, err := net.Listen("tcp4", fmt.Sprintf(":%d", *port))
72142
if err != nil {
73-
logger.Fatalf("failed to listen: %v", err)
143+
logger.Fatalf("net.Listen(%s) failed: %v", fmt.Sprintf(":%d", *port), err)
144+
}
145+
146+
// Create server-side xDS credentials with a plaintext fallback.
147+
creds, err := xdscreds.NewServerCredentials(xdscreds.ServerOptions{FallbackCreds: insecure.NewCredentials()})
148+
if err != nil {
149+
logger.Fatalf("Failed to create xDS credentials: %v", err)
150+
}
151+
152+
// Create an xDS enabled gRPC server, register the test service
153+
// implementation and start serving.
154+
testServer := xds.NewGRPCServer(grpc.Creds(creds), xds.ServingModeCallback(xdsServingModeCallback))
155+
testgrpc.RegisterTestServiceServer(testServer, testService)
156+
go func() {
157+
if err := testServer.Serve(testLis); err != nil {
158+
logger.Errorf("test server Serve() failed: %v", err)
159+
}
160+
}()
161+
defer testServer.Stop()
162+
163+
// Create a listener on -maintenance_port to expose other services.
164+
maintenanceLis, err := net.Listen("tcp4", fmt.Sprintf(":%d", *maintenancePort))
165+
if err != nil {
166+
logger.Fatalf("net.Listen(%s) failed: %v", fmt.Sprintf(":%d", *maintenancePort), err)
167+
}
168+
169+
// Create a regular gRPC server and register the maintenance services on
170+
// it and start serving.
171+
maintenanceServer := grpc.NewServer()
172+
healthServer.SetServingStatus("", healthpb.HealthCheckResponse_SERVING)
173+
healthpb.RegisterHealthServer(maintenanceServer, healthServer)
174+
testgrpc.RegisterXdsUpdateHealthServiceServer(maintenanceServer, updateHealthService)
175+
reflection.Register(maintenanceServer)
176+
cleanup, err := admin.Register(maintenanceServer)
177+
if err != nil {
178+
logger.Fatalf("Failed to register admin services: %v", err)
179+
}
180+
defer cleanup()
181+
if err := maintenanceServer.Serve(maintenanceLis); err != nil {
182+
logger.Errorf("maintenance server Serve() failed: %v", err)
74183
}
75-
s := grpc.NewServer()
76-
testgrpc.RegisterTestServiceServer(s, &server{})
77-
s.Serve(lis)
78184
}

rpc_util.go

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -429,9 +429,10 @@ func (o ContentSubtypeCallOption) before(c *callInfo) error {
429429
}
430430
func (o ContentSubtypeCallOption) after(c *callInfo, attempt *csAttempt) {}
431431

432-
// ForceCodec returns a CallOption that will set codec to be
433-
// used for all request and response messages for a call. The result of calling
434-
// Name() will be used as the content-subtype in a case-insensitive manner.
432+
// ForceCodec returns a CallOption that will set codec to be used for all
433+
// request and response messages for a call. The result of calling Name() will
434+
// be used as the content-subtype after converting to lowercase, unless
435+
// CallContentSubtype is also used.
435436
//
436437
// See Content-Type on
437438
// https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests for
@@ -853,7 +854,17 @@ func toRPCErr(err error) error {
853854
// setCallInfoCodec should only be called after CallOptions have been applied.
854855
func setCallInfoCodec(c *callInfo) error {
855856
if c.codec != nil {
856-
// codec was already set by a CallOption; use it.
857+
// codec was already set by a CallOption; use it, but set the content
858+
// subtype if it is not set.
859+
if c.contentSubtype == "" {
860+
// c.codec is a baseCodec to hide the difference between grpc.Codec and
861+
// encoding.Codec (Name vs. String method name). We only support
862+
// setting content subtype from encoding.Codec to avoid a behavior
863+
// change with the deprecated version.
864+
if ec, ok := c.codec.(encoding.Codec); ok {
865+
c.contentSubtype = strings.ToLower(ec.Name())
866+
}
867+
}
857868
return nil
858869
}
859870

0 commit comments

Comments
 (0)