Skip to content

Commit fe40830

Browse files
committed
address comments
1 parent a09c8a3 commit fe40830

5 files changed

Lines changed: 70 additions & 89 deletions

File tree

internal/xds/xdsclient/xdsresource/metadata.go

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,35 +27,39 @@ import (
2727
)
2828

2929
func init() {
30-
Register("envoy.http11_proxy_transport_socket.proxy_address", ProxyAddressConvertor{})
30+
Register("envoy.http11_proxy_transport_socket.proxy_address", proxyAddressConvertor{})
3131
}
3232

3333
var (
3434
// metadataregistry is a map from proto type to Converter.
35-
metadataregistry = make(map[string]Converter)
35+
metadataregistry = make(map[string]converter)
3636
)
3737

3838
// MetadataValue is the interface for a converted metadata value. It is
3939
// implemented by concrete types that hold the converted metadata.
4040
type MetadataValue interface {
41+
// Type returns the type.
4142
Type() string
4243
}
4344

44-
// Converter is the interface for a metadata converter. It is implemented by
45+
// converter is the interface for a metadata converter. It is implemented by
4546
// concrete types that convert raw bytes into a MetadataValue.
46-
type Converter interface {
47-
// Convert parses the raw bytes of an Any proto into a MetadataValue.
48-
Convert([]byte) (MetadataValue, error)
47+
type converter interface {
48+
// convert parses the proto serialized bytes of an Any proto or
49+
// google.protobuf.Struct into a MetadataValue. The bytes of an Any proto
50+
// are from the value field, which has proto serialized bytes of the
51+
// protobuf message type specified by the type_url field.
52+
convert([]byte) (MetadataValue, error)
4953
}
5054

5155
// Register registers the converter to the map keyed on a proto type. Must be
5256
// called at init time. Not thread safe.
53-
func Register(protoType string, c Converter) {
57+
func Register(protoType string, c converter) {
5458
metadataregistry[protoType] = c
5559
}
5660

5761
// ConverterForType retrieves a converter based on key given.
58-
func ConverterForType(typeURL string) Converter {
62+
func ConverterForType(typeURL string) converter {
5963
return metadataregistry[typeURL]
6064
}
6165

@@ -66,9 +70,11 @@ type JSONMetadata struct {
6670
Data json.RawMessage
6771
}
6872

69-
// ProxyAddressMetadataValue holds the address parsed from A.86 metadata.
73+
// ProxyAddressMetadataValue holds the address parsed from the
74+
// envoy.config.core.v3.Address proto message, as specified in gRFC A86.
7075
type ProxyAddressMetadataValue struct {
71-
MetadataValue
76+
// Address stores the proxy address configured (A86). It will be in the form
77+
// of host:port. It has to be either IPv6 or IPv4.
7278
Address string
7379
}
7480

@@ -78,11 +84,11 @@ func (ProxyAddressMetadataValue) Type() string {
7884
}
7985

8086
// ProxyAddressConvertor implements the converter for A86 (Proxy Address) metadata.
81-
type ProxyAddressConvertor struct{}
87+
type proxyAddressConvertor struct{}
8288

83-
// Convert parses the raw bytes of an Any proto containing an Address proto into
84-
// a ProxyAddressMetadataValue.
85-
func (ProxyAddressConvertor) Convert(anyBytes []byte) (MetadataValue, error) {
89+
// Convert parses the bytes from the value field of an Any proto containing an
90+
// Address proto into a ProxyAddressMetadataValue.
91+
func (proxyAddressConvertor) convert(anyBytes []byte) (MetadataValue, error) {
8692
addressProto := &v3corepb.Address{}
8793
if err := proto.Unmarshal(anyBytes, addressProto); err != nil {
8894
return nil, fmt.Errorf("failed to unmarshal resource: %v", err)
@@ -91,15 +97,16 @@ func (ProxyAddressConvertor) Convert(anyBytes []byte) (MetadataValue, error) {
9197
if socketaddress == nil {
9298
return nil, fmt.Errorf("no socket_address field in metadata")
9399
}
100+
if _, err := netip.ParseAddr(socketaddress.GetAddress()); err != nil {
101+
return nil, fmt.Errorf("address field is not a valid IPv4 or IPv6 address: %q", socketaddress.GetAddress())
102+
}
94103
portvalue := socketaddress.GetPortValue()
95104
if portvalue == 0 {
96105
return nil, fmt.Errorf("port value not set in socket_address")
97106
}
98-
if _, err := netip.ParseAddr(socketaddress.GetAddress()); err != nil {
99-
return nil, fmt.Errorf("address field is not a valid IPv4 or IPv6 address: %q", socketaddress.GetAddress())
100-
}
107+
101108
metadata := ProxyAddressMetadataValue{
102-
Address: socketaddress.Address,
109+
Address: parseAddress(socketaddress),
103110
}
104111
return metadata, nil
105112
}

internal/xds/xdsclient/xdsresource/metadata_test.go

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import (
2121

2222
v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
2323
"github.com/google/go-cmp/cmp"
24-
"google.golang.org/protobuf/proto"
24+
"google.golang.org/grpc/internal/testutils"
2525
)
2626

2727
const proxyAddressFilterName = "envoy.http11_proxy_transport_socket.proxy_address"
@@ -49,7 +49,7 @@ func (s) TestProxyAddressConverterSuccess(t *testing.T) {
4949
},
5050
},
5151
want: ProxyAddressMetadataValue{
52-
Address: "192.168.1.1",
52+
Address: "192.168.1.1:8080",
5353
},
5454
},
5555
{
@@ -65,23 +65,20 @@ func (s) TestProxyAddressConverterSuccess(t *testing.T) {
6565
},
6666
},
6767
want: ProxyAddressMetadataValue{
68-
Address: "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
68+
Address: "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:9090",
6969
},
7070
},
7171
}
7272

7373
for _, tt := range tests {
7474
t.Run(tt.name, func(t *testing.T) {
75-
anyBytes, err := proto.Marshal(tt.addr)
76-
if err != nil {
77-
t.Fatalf("Failed to marshal address proto: %v", err)
78-
}
79-
got, err := converter.Convert(anyBytes)
75+
anyProto := testutils.MarshalAny(t, tt.addr)
76+
got, err := converter.convert(anyProto.GetValue())
8077
if err != nil {
8178
t.Fatalf("convert() failed with error: %v", err)
8279
}
8380
if diff := cmp.Diff(tt.want, got, cmp.AllowUnexported(ProxyAddressMetadataValue{})); diff != "" {
84-
t.Errorf("convert() returned unexpected value:\n%s", diff)
81+
t.Errorf("convert() returned unexpected value (-want +got):\n%s", diff)
8582
}
8683
})
8784
}
@@ -103,9 +100,6 @@ func (s) TestProxyAddressConverterFailure(t *testing.T) {
103100
Address: &v3corepb.Address_SocketAddress{
104101
SocketAddress: &v3corepb.SocketAddress{
105102
Address: "invalid-ip",
106-
PortSpecifier: &v3corepb.SocketAddress_PortValue{
107-
PortValue: 8080,
108-
},
109103
},
110104
},
111105
},
@@ -147,15 +141,10 @@ func (s) TestProxyAddressConverterFailure(t *testing.T) {
147141

148142
for _, tt := range tests {
149143
t.Run(tt.name, func(t *testing.T) {
150-
anyBytes, err := proto.Marshal(tt.addr)
151-
if err != nil {
152-
t.Fatalf("Failed to marshal address proto: %v", err)
153-
}
154-
155-
// Call the convert function and check the returned error.
156-
_, gotErr := converter.Convert(anyBytes)
157-
if gotErr == nil || gotErr.Error() != tt.wantErr {
158-
t.Errorf("convert() got error = %v, wantErr = %q", gotErr, tt.wantErr)
144+
anyProto := testutils.MarshalAny(t, tt.addr)
145+
_, err := converter.convert(anyProto.GetValue())
146+
if err == nil || err.Error() != tt.wantErr {
147+
t.Errorf("convert() got error = %v, wantErr = %q", err, tt.wantErr)
159148
}
160149
})
161150
}

internal/xds/xdsclient/xdsresource/type_eds.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ type Endpoint struct {
5353
HealthStatus EndpointHealthStatus
5454
Weight uint32
5555
HashKey string
56+
Metadata *Metadata
5657
}
5758

5859
// Locality contains information of a locality.
@@ -61,6 +62,7 @@ type Locality struct {
6162
ID clients.Locality
6263
Priority uint32
6364
Weight uint32
65+
Metadata *Metadata
6466
}
6567

6668
// EndpointsUpdate contains an EDS update.

internal/xds/xdsclient/xdsresource/unmarshal_eds.go

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,20 @@ func parseEndpoints(lbEndpoints []*v3endpointpb.LbEndpoint, uniqueEndpointAddrs
110110
}
111111
uniqueEndpointAddrs[a] = true
112112
}
113+
var endpointMetadata *Metadata
114+
if md := lbEndpoint.GetMetadata(); md != nil {
115+
m, err := validateAndConstructMetadata(md)
116+
if err != nil {
117+
return nil, err
118+
}
119+
endpointMetadata = &m
120+
}
113121
endpoints = append(endpoints, Endpoint{
114122
HealthStatus: EndpointHealthStatus(lbEndpoint.GetHealthStatus()),
115123
Addresses: addrs,
116124
Weight: weight,
117125
HashKey: hashKey(lbEndpoint),
126+
Metadata: endpointMetadata,
118127
})
119128
}
120129
return endpoints, nil
@@ -192,11 +201,20 @@ func parseEDSRespProto(m *v3endpointpb.ClusterLoadAssignment) (EndpointsUpdate,
192201
if err != nil {
193202
return EndpointsUpdate{}, err
194203
}
204+
var localityMetadata *Metadata
205+
if md := locality.GetMetadata(); md != nil {
206+
m, err := validateAndConstructMetadata(md)
207+
if err != nil {
208+
return EndpointsUpdate{}, err
209+
}
210+
localityMetadata = &m
211+
}
195212
ret.Localities = append(ret.Localities, Locality{
196213
ID: lid,
197214
Endpoints: endpoints,
198215
Weight: weight,
199216
Priority: priority,
217+
Metadata: localityMetadata,
200218
})
201219
}
202220
for i := 0; i < len(priorities); i++ {
@@ -209,30 +227,25 @@ func parseEDSRespProto(m *v3endpointpb.ClusterLoadAssignment) (EndpointsUpdate,
209227

210228
func validateAndConstructMetadata(metadataProto *v3corepb.Metadata) (Metadata, error) {
211229
metadata := make(map[string]MetadataValue)
212-
if metadataProto == nil {
213-
return Metadata{Metadata: metadata}, nil
214-
}
215230
// First go through TypedFilterMetadata.
216231
for key, anyProto := range metadataProto.GetTypedFilterMetadata() {
217-
converter := ConverterForType(anyProto.GetTypeUrl())
232+
converter := ConverterForType(key)
218233
// Ignore types we don't have a converter for.
219234
if converter == nil {
220235
continue
221236
}
222-
223-
val, err := converter.Convert(anyProto.GetValue())
237+
val, err := converter.convert(anyProto.GetValue())
224238
if err != nil {
225239
// If the converter fails, nack the whole resource.
226-
return Metadata{}, fmt.Errorf("metadata parser for key %q and type %q failed: %v", key, anyProto.GetTypeUrl(), err)
240+
return Metadata{}, fmt.Errorf("metadata converting for key %q and type %q failed: %v", key, anyProto.GetTypeUrl(), err)
227241
}
228242
metadata[key] = val
229243
}
230244

231245
// Process FilterMetadata for any keys not already handled.
232246
for key, structProto := range metadataProto.GetFilterMetadata() {
233-
_, exists := metadata[key]
234247
// Skip keys already added from TyperFilterMetadata.
235-
if exists {
248+
if metadata[key] != nil {
236249
continue
237250
}
238251
b, err := protojson.Marshal(structProto)

internal/xds/xdsclient/xdsresource/unmarshal_eds_test.go

Lines changed: 11 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -590,21 +590,6 @@ func (s) TestUnmarshalEndpoints(t *testing.T) {
590590
}
591591

592592
func (s) TestValidateAndConstructMetadata(t *testing.T) {
593-
originalRegistry := metadataregistry
594-
// Restore the original registry.
595-
defer func() {
596-
metadataregistry = originalRegistry
597-
}()
598-
newRegistry := make(map[string]Converter)
599-
metadataregistry = newRegistry
600-
601-
// Register a mock converter for this test. The key is the type URL for an
602-
// envoy.config.core.v3.Address proto, which will be used in the success case.
603-
Register("type.googleapis.com/envoy.config.core.v3.Address", testMetadataValueConvertor{})
604-
metadataMap := map[string]MetadataValue{
605-
"type.googleapis.com/envoy.config.core.v3.Address": testMetadataValue{Address: "1.2.3.4"},
606-
"untyped-key": JSONMetadata{Data: json.RawMessage(`{"field":"value"}`)},
607-
}
608593
tests := []struct {
609594
name string
610595
metadataProto *v3corepb.Metadata
@@ -615,23 +600,28 @@ func (s) TestValidateAndConstructMetadata(t *testing.T) {
615600
name: "success-case",
616601
metadataProto: &v3corepb.Metadata{
617602
TypedFilterMetadata: map[string]*anypb.Any{
618-
"type.googleapis.com/envoy.config.core.v3.Address": testutils.MarshalAny(t, &v3corepb.Address{
603+
"envoy.http11_proxy_transport_socket.proxy_address": testutils.MarshalAny(t, &v3corepb.Address{
619604
Address: &v3corepb.Address_SocketAddress{
620-
SocketAddress: &v3corepb.SocketAddress{Address: "1.2.3.4"},
605+
SocketAddress: &v3corepb.SocketAddress{Address: "1.2.3.4", PortSpecifier: &v3corepb.SocketAddress_PortValue{
606+
PortValue: 8080,
607+
}},
621608
},
622609
}),
623610
},
624611
FilterMetadata: map[string]*structpb.Struct{
625612
"untyped-key": {Fields: map[string]*structpb.Value{"field": structpb.NewStringValue("value")}},
626613
},
627614
},
628-
want: Metadata{Metadata: metadataMap},
615+
want: Metadata{Metadata: map[string]MetadataValue{
616+
"envoy.http11_proxy_transport_socket.proxy_address": ProxyAddressMetadataValue{Address: "1.2.3.4:8080"},
617+
"untyped-key": JSONMetadata{Data: json.RawMessage(`{"field":"value"}`)},
618+
}},
629619
},
630620
{
631621
name: "failure-case-converter-error",
632622
metadataProto: &v3corepb.Metadata{
633623
TypedFilterMetadata: map[string]*anypb.Any{
634-
"type.googleapis.com/envoy.config.core.v3.Address": testutils.MarshalAny(t, &v3corepb.Address{
624+
"envoy.http11_proxy_transport_socket.proxy_address": testutils.MarshalAny(t, &v3corepb.Address{
635625
Address: &v3corepb.Address_SocketAddress{
636626
SocketAddress: &v3corepb.SocketAddress{Address: "invalid"},
637627
},
@@ -649,33 +639,13 @@ func (s) TestValidateAndConstructMetadata(t *testing.T) {
649639
t.Errorf("validateAndConstructMetadata() error = %v, wantErr %v", err, tt.wantErr)
650640
return
651641
}
652-
if diff := cmp.Diff(got, tt.want, cmp.AllowUnexported(testMetadataValue{})); diff != "" {
653-
t.Errorf("validateAndConstructMetadata() returned unexpected value:\n%s", diff)
642+
if diff := cmp.Diff(got, tt.want, cmp.AllowUnexported(ProxyAddressMetadataValue{})); diff != "" {
643+
t.Errorf("validateAndConstructMetadata() returned unexpected diff (-want +got):\n%s", diff)
654644
}
655645
})
656646
}
657647
}
658648

659-
type testMetadataValue struct {
660-
MetadataValue
661-
Address string
662-
}
663-
664-
type testMetadataValueConvertor struct{}
665-
666-
// testMetadataValueConvertor is a mock converter for testing purposes.
667-
func (testMetadataValueConvertor) Convert(anyBytes []byte) (MetadataValue, error) {
668-
addrProto := &v3corepb.Address{}
669-
if err := proto.Unmarshal(anyBytes, addrProto); err != nil {
670-
return nil, fmt.Errorf("failed to unmarshal address proto: %v", err)
671-
}
672-
// For the failure case, return an error if the address is "invalid".
673-
if addrProto.GetSocketAddress().GetAddress() == "invalid" {
674-
return nil, fmt.Errorf("mock parser error: invalid address")
675-
}
676-
return testMetadataValue{Address: addrProto.GetSocketAddress().GetAddress()}, nil
677-
}
678-
679649
// claBuilder builds a ClusterLoadAssignment, aka EDS
680650
// response.
681651
type claBuilder struct {

0 commit comments

Comments
 (0)