mirror of https://github.com/grpc/grpc-go.git
xds: Add route to filterchain (#4610)
* Added RDS Information from LDS in filter chain
This commit is contained in:
parent
6ba56c814b
commit
74370577fa
|
|
@ -30,6 +30,7 @@ import (
|
|||
|
||||
v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
|
||||
v3listenerpb "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
|
||||
v3routepb "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
|
||||
v3httppb "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
|
||||
v3tlspb "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3"
|
||||
wrapperspb "github.com/golang/protobuf/ptypes/wrappers"
|
||||
|
|
@ -87,7 +88,20 @@ var listenerWithFilterChains = &v3listenerpb.Listener{
|
|||
{
|
||||
Name: "filter-1",
|
||||
ConfigType: &v3listenerpb.Filter_TypedConfig{
|
||||
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{}),
|
||||
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
|
||||
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
|
||||
RouteConfig: &v3routepb.RouteConfiguration{
|
||||
Name: "routeName",
|
||||
VirtualHosts: []*v3routepb.VirtualHost{{
|
||||
Domains: []string{"lds.target.good:3333"},
|
||||
Routes: []*v3routepb.Route{{
|
||||
Match: &v3routepb.RouteMatch{
|
||||
PathSpecifier: &v3routepb.RouteMatch_Prefix{Prefix: "/"},
|
||||
},
|
||||
Action: &v3routepb.Route_NonForwardingAction{},
|
||||
}}}}},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -199,7 +199,20 @@ func DefaultServerListener(host string, port uint32, secLevel SecurityLevel) *v3
|
|||
{
|
||||
Name: "filter-1",
|
||||
ConfigType: &v3listenerpb.Filter_TypedConfig{
|
||||
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{}),
|
||||
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
|
||||
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
|
||||
RouteConfig: &v3routepb.RouteConfiguration{
|
||||
Name: "routeName",
|
||||
VirtualHosts: []*v3routepb.VirtualHost{{
|
||||
Domains: []string{"lds.target.good:3333"},
|
||||
Routes: []*v3routepb.Route{{
|
||||
Match: &v3routepb.RouteMatch{
|
||||
PathSpecifier: &v3routepb.RouteMatch_Prefix{Prefix: "/"},
|
||||
},
|
||||
Action: &v3routepb.Route_NonForwardingAction{},
|
||||
}}}}},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -230,7 +243,20 @@ func DefaultServerListener(host string, port uint32, secLevel SecurityLevel) *v3
|
|||
{
|
||||
Name: "filter-1",
|
||||
ConfigType: &v3listenerpb.Filter_TypedConfig{
|
||||
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{}),
|
||||
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
|
||||
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
|
||||
RouteConfig: &v3routepb.RouteConfiguration{
|
||||
Name: "routeName",
|
||||
VirtualHosts: []*v3routepb.VirtualHost{{
|
||||
Domains: []string{"lds.target.good:3333"},
|
||||
Routes: []*v3routepb.Route{{
|
||||
Match: &v3routepb.RouteMatch{
|
||||
PathSpecifier: &v3routepb.RouteMatch_Prefix{Prefix: "/"},
|
||||
},
|
||||
Action: &v3routepb.Route_NonForwardingAction{},
|
||||
}}}}},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -294,6 +294,25 @@ type HashPolicy struct {
|
|||
RegexSubstitution string
|
||||
}
|
||||
|
||||
// RouteAction is the action of the route from a received RDS response.
|
||||
type RouteAction int
|
||||
|
||||
const (
|
||||
// RouteActionUnsupported are routing types currently unsupported by grpc.
|
||||
// According to A36, "A Route with an inappropriate action causes RPCs
|
||||
// matching that route to fail."
|
||||
RouteActionUnsupported RouteAction = iota
|
||||
// RouteActionRoute is the expected route type on the client side. Route
|
||||
// represents routing a request to some upstream cluster. On the client
|
||||
// side, if an RPC matches to a route that is not RouteActionRoute, the RPC
|
||||
// will fail according to A36.
|
||||
RouteActionRoute
|
||||
// RouteActionNonForwardingAction is the expected route type on the server
|
||||
// side. NonForwardingAction represents when a route will generate a
|
||||
// response directly, without forwarding to an upstream host.
|
||||
RouteActionNonForwardingAction
|
||||
)
|
||||
|
||||
// Route is both a specification of how to match a request as well as an
|
||||
// indication of the action to take upon match.
|
||||
type Route struct {
|
||||
|
|
@ -321,6 +340,8 @@ type Route struct {
|
|||
// unused if the matching WeightedCluster contains an override for that
|
||||
// filter.
|
||||
HTTPFilterConfigOverride map[string]httpfilter.FilterConfig
|
||||
|
||||
RouteAction RouteAction
|
||||
}
|
||||
|
||||
// WeightedCluster contains settings for an xds RouteAction.WeightedCluster.
|
||||
|
|
|
|||
|
|
@ -24,8 +24,10 @@ import (
|
|||
"net"
|
||||
|
||||
v3listenerpb "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
|
||||
v3httppb "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
|
||||
v3tlspb "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/golang/protobuf/ptypes"
|
||||
"google.golang.org/grpc/xds/internal/version"
|
||||
)
|
||||
|
||||
|
|
@ -54,6 +56,15 @@ type FilterChain struct {
|
|||
SecurityCfg *SecurityConfig
|
||||
// HTTPFilters represent the HTTP Filters that comprise this FilterChain.
|
||||
HTTPFilters []HTTPFilter
|
||||
// RouteConfigName is the route configuration name for this FilterChain.
|
||||
//
|
||||
// Only one of RouteConfigName and InlineRouteConfig is set.
|
||||
RouteConfigName string
|
||||
// InlineRouteConfig is the inline route configuration (RDS response)
|
||||
// returned for this filter chain.
|
||||
//
|
||||
// Only one of RouteConfigName and InlineRouteConfig is set.
|
||||
InlineRouteConfig *RouteConfigUpdate
|
||||
}
|
||||
|
||||
// SourceType specifies the connection source IP match type.
|
||||
|
|
@ -109,6 +120,11 @@ type FilterChainManager struct {
|
|||
dstPrefixes []*destPrefixEntry
|
||||
|
||||
def *FilterChain // Default filter chain, if specified.
|
||||
|
||||
// RouteConfigNames are the route configuration names which need to be
|
||||
// dynamically queried for RDS Configuration for any FilterChains which
|
||||
// specify to load RDS Configuration dynamically.
|
||||
RouteConfigNames map[string]bool
|
||||
}
|
||||
|
||||
// destPrefixEntry is the value type of the map indexed on destination prefixes.
|
||||
|
|
@ -158,7 +174,10 @@ type sourcePrefixEntry struct {
|
|||
// create a FilterChainManager.
|
||||
func NewFilterChainManager(lis *v3listenerpb.Listener) (*FilterChainManager, error) {
|
||||
// Parse all the filter chains and build the internal data structures.
|
||||
fci := &FilterChainManager{dstPrefixMap: make(map[string]*destPrefixEntry)}
|
||||
fci := &FilterChainManager{
|
||||
dstPrefixMap: make(map[string]*destPrefixEntry),
|
||||
RouteConfigNames: make(map[string]bool),
|
||||
}
|
||||
if err := fci.addFilterChains(lis.GetFilterChains()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -187,7 +206,7 @@ func NewFilterChainManager(lis *v3listenerpb.Listener) (*FilterChainManager, err
|
|||
var def *FilterChain
|
||||
if dfc := lis.GetDefaultFilterChain(); dfc != nil {
|
||||
var err error
|
||||
if def, err = filterChainFromProto(dfc); err != nil {
|
||||
if def, err = fci.filterChainFromProto(dfc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
|
@ -368,7 +387,7 @@ func (fci *FilterChainManager) addFilterChainsForSourcePorts(srcEntry *sourcePre
|
|||
srcPorts = append(srcPorts, int(port))
|
||||
}
|
||||
|
||||
fc, err := filterChainFromProto(fcProto)
|
||||
fc, err := fci.filterChainFromProto(fcProto)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -391,13 +410,19 @@ func (fci *FilterChainManager) addFilterChainsForSourcePorts(srcEntry *sourcePre
|
|||
}
|
||||
|
||||
// filterChainFromProto extracts the relevant information from the FilterChain
|
||||
// proto and stores it in our internal representation.
|
||||
func filterChainFromProto(fc *v3listenerpb.FilterChain) (*FilterChain, error) {
|
||||
httpFilters, err := processNetworkFilters(fc.GetFilters())
|
||||
// proto and stores it in our internal representation. It also persists any
|
||||
// RouteNames which need to be queried dynamically via RDS.
|
||||
func (fci *FilterChainManager) filterChainFromProto(fc *v3listenerpb.FilterChain) (*FilterChain, error) {
|
||||
filterChain, err := processNetworkFilters(fc.GetFilters())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filterChain := &FilterChain{HTTPFilters: httpFilters}
|
||||
// These route names will be dynamically queried via RDS in the wrapped
|
||||
// listener, which receives the LDS response, if specified for the filter
|
||||
// chain.
|
||||
if filterChain.RouteConfigName != "" {
|
||||
fci.RouteConfigNames[filterChain.RouteConfigName] = true
|
||||
}
|
||||
// If the transport_socket field is not specified, it means that the control
|
||||
// plane has not sent us any security config. This is fine and the server
|
||||
// will use the fallback credentials configured as part of the
|
||||
|
|
@ -435,6 +460,93 @@ func filterChainFromProto(fc *v3listenerpb.FilterChain) (*FilterChain, error) {
|
|||
return filterChain, nil
|
||||
}
|
||||
|
||||
func processNetworkFilters(filters []*v3listenerpb.Filter) (*FilterChain, error) {
|
||||
filterChain := &FilterChain{}
|
||||
seenNames := make(map[string]bool, len(filters))
|
||||
seenHCM := false
|
||||
for _, filter := range filters {
|
||||
name := filter.GetName()
|
||||
if name == "" {
|
||||
return nil, fmt.Errorf("network filters {%+v} is missing name field in filter: {%+v}", filters, filter)
|
||||
}
|
||||
if seenNames[name] {
|
||||
return nil, fmt.Errorf("network filters {%+v} has duplicate filter name %q", filters, name)
|
||||
}
|
||||
seenNames[name] = true
|
||||
|
||||
// Network filters have a oneof field named `config_type` where we
|
||||
// only support `TypedConfig` variant.
|
||||
switch typ := filter.GetConfigType().(type) {
|
||||
case *v3listenerpb.Filter_TypedConfig:
|
||||
// The typed_config field has an `anypb.Any` proto which could
|
||||
// directly contain the serialized bytes of the actual filter
|
||||
// configuration, or it could be encoded as a `TypedStruct`.
|
||||
// TODO: Add support for `TypedStruct`.
|
||||
tc := filter.GetTypedConfig()
|
||||
|
||||
// The only network filter that we currently support is the v3
|
||||
// HttpConnectionManager. So, we can directly check the type_url
|
||||
// and unmarshal the config.
|
||||
// TODO: Implement a registry of supported network filters (like
|
||||
// we have for HTTP filters), when we have to support network
|
||||
// filters other than HttpConnectionManager.
|
||||
if tc.GetTypeUrl() != version.V3HTTPConnManagerURL {
|
||||
return nil, fmt.Errorf("network filters {%+v} has unsupported network filter %q in filter {%+v}", filters, tc.GetTypeUrl(), filter)
|
||||
}
|
||||
hcm := &v3httppb.HttpConnectionManager{}
|
||||
if err := ptypes.UnmarshalAny(tc, hcm); err != nil {
|
||||
return nil, fmt.Errorf("network filters {%+v} failed unmarshaling of network filter {%+v}: %v", filters, filter, err)
|
||||
}
|
||||
// "Any filters after HttpConnectionManager should be ignored during
|
||||
// connection processing but still be considered for validity.
|
||||
// HTTPConnectionManager must have valid http_filters." - A36
|
||||
filters, err := processHTTPFilters(hcm.GetHttpFilters(), true)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("network filters {%+v} had invalid server side HTTP Filters {%+v}", filters, hcm.GetHttpFilters())
|
||||
}
|
||||
if !seenHCM {
|
||||
// TODO: Implement terminal filter logic, as per A36.
|
||||
filterChain.HTTPFilters = filters
|
||||
seenHCM = true
|
||||
switch hcm.RouteSpecifier.(type) {
|
||||
case *v3httppb.HttpConnectionManager_Rds:
|
||||
if hcm.GetRds().GetConfigSource().GetAds() == nil {
|
||||
return nil, fmt.Errorf("ConfigSource is not ADS: %+v", hcm)
|
||||
}
|
||||
name := hcm.GetRds().GetRouteConfigName()
|
||||
if name == "" {
|
||||
return nil, fmt.Errorf("empty route_config_name: %+v", hcm)
|
||||
}
|
||||
filterChain.RouteConfigName = name
|
||||
case *v3httppb.HttpConnectionManager_RouteConfig:
|
||||
// "RouteConfiguration validation logic inherits all
|
||||
// previous validations made for client-side usage as RDS
|
||||
// does not distinguish between client-side and
|
||||
// server-side." - A36
|
||||
// Can specify v3 here, as will never get to this function
|
||||
// if v2.
|
||||
routeU, err := generateRDSUpdateFromRouteConfiguration(hcm.GetRouteConfig(), nil, false)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse inline RDS resp: %v", err)
|
||||
}
|
||||
filterChain.InlineRouteConfig = &routeU
|
||||
case nil:
|
||||
// No-op, as no route specifier is a valid configuration on
|
||||
// the server side.
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported type %T for RouteSpecifier", hcm.RouteSpecifier)
|
||||
}
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("network filters {%+v} has unsupported config_type %T in filter %s", filters, typ, filter.GetName())
|
||||
}
|
||||
}
|
||||
if !seenHCM {
|
||||
return nil, fmt.Errorf("network filters {%+v} missing HttpConnectionManager filter", filters)
|
||||
}
|
||||
return filterChain, nil
|
||||
}
|
||||
|
||||
// FilterChainLookupParams wraps parameters to be passed to Lookup.
|
||||
type FilterChainLookupParams struct {
|
||||
// IsUnspecified indicates whether the server is listening on a wildcard
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import (
|
|||
|
||||
v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
|
||||
v3listenerpb "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
|
||||
v3routepb "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
|
||||
v3httppb "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
|
||||
v3tlspb "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
|
@ -41,11 +42,30 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
routeConfig = &v3routepb.RouteConfiguration{
|
||||
Name: "routeName",
|
||||
VirtualHosts: []*v3routepb.VirtualHost{{
|
||||
Domains: []string{"lds.target.good:3333"},
|
||||
Routes: []*v3routepb.Route{{
|
||||
Match: &v3routepb.RouteMatch{
|
||||
PathSpecifier: &v3routepb.RouteMatch_Prefix{Prefix: "/"},
|
||||
},
|
||||
Action: &v3routepb.Route_NonForwardingAction{},
|
||||
}}}}}
|
||||
inlineRouteConfig = &RouteConfigUpdate{
|
||||
VirtualHosts: []*VirtualHost{{
|
||||
Domains: []string{"lds.target.good:3333"},
|
||||
Routes: []*Route{{Prefix: newStringP("/"), RouteAction: RouteActionNonForwardingAction}},
|
||||
}}}
|
||||
emptyValidNetworkFilters = []*v3listenerpb.Filter{
|
||||
{
|
||||
Name: "filter-1",
|
||||
ConfigType: &v3listenerpb.Filter_TypedConfig{
|
||||
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{}),
|
||||
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
|
||||
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
|
||||
RouteConfig: routeConfig,
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
@ -249,8 +269,7 @@ func TestNewFilterChainImpl_Failure_OverlappingMatchingRules(t *testing.T) {
|
|||
const wantErr = "multiple filter chains with overlapping matching rules are defined"
|
||||
for _, test := range tests {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
_, err := NewFilterChainManager(test.lis)
|
||||
if err == nil || !strings.Contains(err.Error(), wantErr) {
|
||||
if _, err := NewFilterChainManager(test.lis); err == nil || !strings.Contains(err.Error(), wantErr) {
|
||||
t.Fatalf("NewFilterChainManager() returned err: %v, wantErr: %s", err, wantErr)
|
||||
}
|
||||
})
|
||||
|
|
@ -417,6 +436,323 @@ func TestNewFilterChainImpl_Failure_BadSecurityConfig(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestNewFilterChainImpl_Success_RouteUpdate tests the construction of the
|
||||
// filter chain with valid HTTP Filters present.
|
||||
func TestNewFilterChainImpl_Success_RouteUpdate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
lis *v3listenerpb.Listener
|
||||
wantFC *FilterChainManager
|
||||
}{
|
||||
{
|
||||
name: "rds",
|
||||
lis: &v3listenerpb.Listener{
|
||||
FilterChains: []*v3listenerpb.FilterChain{
|
||||
{
|
||||
Name: "filter-chain-1",
|
||||
Filters: []*v3listenerpb.Filter{
|
||||
{
|
||||
Name: "hcm",
|
||||
ConfigType: &v3listenerpb.Filter_TypedConfig{
|
||||
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
|
||||
RouteSpecifier: &v3httppb.HttpConnectionManager_Rds{
|
||||
Rds: &v3httppb.Rds{
|
||||
ConfigSource: &v3corepb.ConfigSource{
|
||||
ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{Ads: &v3corepb.AggregatedConfigSource{}},
|
||||
},
|
||||
RouteConfigName: "route-1",
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
DefaultFilterChain: &v3listenerpb.FilterChain{
|
||||
Filters: []*v3listenerpb.Filter{
|
||||
{
|
||||
Name: "hcm",
|
||||
ConfigType: &v3listenerpb.Filter_TypedConfig{
|
||||
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
|
||||
RouteSpecifier: &v3httppb.HttpConnectionManager_Rds{
|
||||
Rds: &v3httppb.Rds{
|
||||
ConfigSource: &v3corepb.ConfigSource{
|
||||
ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{Ads: &v3corepb.AggregatedConfigSource{}},
|
||||
},
|
||||
RouteConfigName: "route-1",
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantFC: &FilterChainManager{
|
||||
dstPrefixMap: map[string]*destPrefixEntry{
|
||||
unspecifiedPrefixMapKey: {
|
||||
srcTypeArr: [3]*sourcePrefixes{
|
||||
{
|
||||
srcPrefixMap: map[string]*sourcePrefixEntry{
|
||||
unspecifiedPrefixMapKey: {
|
||||
srcPortMap: map[int]*FilterChain{
|
||||
0: {
|
||||
RouteConfigName: "route-1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
def: &FilterChain{
|
||||
RouteConfigName: "route-1",
|
||||
},
|
||||
RouteConfigNames: map[string]bool{"route-1": true},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "inline route config",
|
||||
lis: &v3listenerpb.Listener{
|
||||
FilterChains: []*v3listenerpb.FilterChain{
|
||||
{
|
||||
Name: "filter-chain-1",
|
||||
Filters: []*v3listenerpb.Filter{
|
||||
{
|
||||
Name: "hcm",
|
||||
ConfigType: &v3listenerpb.Filter_TypedConfig{
|
||||
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
|
||||
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
|
||||
RouteConfig: routeConfig,
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
DefaultFilterChain: &v3listenerpb.FilterChain{
|
||||
Filters: []*v3listenerpb.Filter{
|
||||
{
|
||||
Name: "hcm",
|
||||
ConfigType: &v3listenerpb.Filter_TypedConfig{
|
||||
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
|
||||
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
|
||||
RouteConfig: routeConfig,
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantFC: &FilterChainManager{
|
||||
dstPrefixMap: map[string]*destPrefixEntry{
|
||||
unspecifiedPrefixMapKey: {
|
||||
srcTypeArr: [3]*sourcePrefixes{
|
||||
{
|
||||
srcPrefixMap: map[string]*sourcePrefixEntry{
|
||||
unspecifiedPrefixMapKey: {
|
||||
srcPortMap: map[int]*FilterChain{
|
||||
0: {
|
||||
InlineRouteConfig: inlineRouteConfig,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
def: &FilterChain{
|
||||
InlineRouteConfig: inlineRouteConfig,
|
||||
},
|
||||
},
|
||||
},
|
||||
// two rds tests whether the Filter Chain Manager successfully persists
|
||||
// the two RDS names that need to be dynamically queried.
|
||||
{
|
||||
name: "two rds",
|
||||
lis: &v3listenerpb.Listener{
|
||||
FilterChains: []*v3listenerpb.FilterChain{
|
||||
{
|
||||
Name: "filter-chain-1",
|
||||
Filters: []*v3listenerpb.Filter{
|
||||
{
|
||||
Name: "hcm",
|
||||
ConfigType: &v3listenerpb.Filter_TypedConfig{
|
||||
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
|
||||
RouteSpecifier: &v3httppb.HttpConnectionManager_Rds{
|
||||
Rds: &v3httppb.Rds{
|
||||
ConfigSource: &v3corepb.ConfigSource{
|
||||
ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{Ads: &v3corepb.AggregatedConfigSource{}},
|
||||
},
|
||||
RouteConfigName: "route-1",
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
DefaultFilterChain: &v3listenerpb.FilterChain{
|
||||
Filters: []*v3listenerpb.Filter{
|
||||
{
|
||||
Name: "hcm",
|
||||
ConfigType: &v3listenerpb.Filter_TypedConfig{
|
||||
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
|
||||
RouteSpecifier: &v3httppb.HttpConnectionManager_Rds{
|
||||
Rds: &v3httppb.Rds{
|
||||
ConfigSource: &v3corepb.ConfigSource{
|
||||
ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{Ads: &v3corepb.AggregatedConfigSource{}},
|
||||
},
|
||||
RouteConfigName: "route-2",
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantFC: &FilterChainManager{
|
||||
dstPrefixMap: map[string]*destPrefixEntry{
|
||||
unspecifiedPrefixMapKey: {
|
||||
srcTypeArr: [3]*sourcePrefixes{
|
||||
{
|
||||
srcPrefixMap: map[string]*sourcePrefixEntry{
|
||||
unspecifiedPrefixMapKey: {
|
||||
srcPortMap: map[int]*FilterChain{
|
||||
0: {
|
||||
RouteConfigName: "route-1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
def: &FilterChain{
|
||||
RouteConfigName: "route-2",
|
||||
},
|
||||
RouteConfigNames: map[string]bool{
|
||||
"route-1": true,
|
||||
"route-2": true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
gotFC, err := NewFilterChainManager(test.lis)
|
||||
if err != nil {
|
||||
t.Fatalf("NewFilterChainManager() returned err: %v, wantErr: nil", err)
|
||||
}
|
||||
if !cmp.Equal(gotFC, test.wantFC, cmp.AllowUnexported(FilterChainManager{}, destPrefixEntry{}, sourcePrefixes{}, sourcePrefixEntry{}), cmpOpts) {
|
||||
t.Fatalf("NewFilterChainManager() returned %+v, want: %+v", gotFC, test.wantFC)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestNewFilterChainImpl_Failure_BadRouteUpdate verifies cases where the Route
|
||||
// Update in the filter chain are invalid.
|
||||
func TestNewFilterChainImpl_Failure_BadRouteUpdate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
lis *v3listenerpb.Listener
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "not-ads",
|
||||
lis: &v3listenerpb.Listener{
|
||||
FilterChains: []*v3listenerpb.FilterChain{
|
||||
{
|
||||
Name: "filter-chain-1",
|
||||
Filters: []*v3listenerpb.Filter{
|
||||
{
|
||||
Name: "hcm",
|
||||
ConfigType: &v3listenerpb.Filter_TypedConfig{
|
||||
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
|
||||
RouteSpecifier: &v3httppb.HttpConnectionManager_Rds{
|
||||
Rds: &v3httppb.Rds{
|
||||
RouteConfigName: "route-1",
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
DefaultFilterChain: &v3listenerpb.FilterChain{
|
||||
Filters: []*v3listenerpb.Filter{
|
||||
{
|
||||
Name: "hcm",
|
||||
ConfigType: &v3listenerpb.Filter_TypedConfig{
|
||||
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
|
||||
RouteSpecifier: &v3httppb.HttpConnectionManager_Rds{
|
||||
Rds: &v3httppb.Rds{
|
||||
RouteConfigName: "route-1",
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: "ConfigSource is not ADS",
|
||||
},
|
||||
{
|
||||
name: "unsupported-route-specifier",
|
||||
lis: &v3listenerpb.Listener{
|
||||
FilterChains: []*v3listenerpb.FilterChain{
|
||||
{
|
||||
Name: "filter-chain-1",
|
||||
Filters: []*v3listenerpb.Filter{
|
||||
{
|
||||
Name: "hcm",
|
||||
ConfigType: &v3listenerpb.Filter_TypedConfig{
|
||||
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
|
||||
RouteSpecifier: &v3httppb.HttpConnectionManager_ScopedRoutes{},
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
DefaultFilterChain: &v3listenerpb.FilterChain{
|
||||
Filters: []*v3listenerpb.Filter{
|
||||
{
|
||||
Name: "hcm",
|
||||
ConfigType: &v3listenerpb.Filter_TypedConfig{
|
||||
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
|
||||
RouteSpecifier: &v3httppb.HttpConnectionManager_ScopedRoutes{},
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: "unsupported type",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
_, err := NewFilterChainManager(test.lis)
|
||||
if err == nil || !strings.Contains(err.Error(), test.wantErr) {
|
||||
t.Fatalf("NewFilterChainManager() returned err: %v, wantErr: %s", err, test.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestNewFilterChainImpl_Failure_BadHTTPFilters verifies cases where the HTTP
|
||||
// Filters in the filter chain are invalid.
|
||||
func TestNewFilterChainImpl_Failure_BadHTTPFilters(t *testing.T) {
|
||||
|
|
@ -513,6 +849,9 @@ func TestNewFilterChainImpl_Success_HTTPFilters(t *testing.T) {
|
|||
HttpFilters: []*v3httppb.HttpFilter{
|
||||
validServerSideHTTPFilter1,
|
||||
},
|
||||
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
|
||||
RouteConfig: routeConfig,
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
|
|
@ -528,6 +867,9 @@ func TestNewFilterChainImpl_Success_HTTPFilters(t *testing.T) {
|
|||
HttpFilters: []*v3httppb.HttpFilter{
|
||||
validServerSideHTTPFilter1,
|
||||
},
|
||||
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
|
||||
RouteConfig: routeConfig,
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
|
|
@ -548,7 +890,9 @@ func TestNewFilterChainImpl_Success_HTTPFilters(t *testing.T) {
|
|||
Filter: serverOnlyHTTPFilter{},
|
||||
Config: filterConfig{Cfg: serverOnlyCustomFilterConfig},
|
||||
},
|
||||
}},
|
||||
},
|
||||
InlineRouteConfig: inlineRouteConfig,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -556,13 +900,14 @@ func TestNewFilterChainImpl_Success_HTTPFilters(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
def: &FilterChain{HTTPFilters: []HTTPFilter{
|
||||
{
|
||||
def: &FilterChain{
|
||||
HTTPFilters: []HTTPFilter{{
|
||||
Name: "serverOnlyCustomFilter",
|
||||
Filter: serverOnlyHTTPFilter{},
|
||||
Config: filterConfig{Cfg: serverOnlyCustomFilterConfig},
|
||||
},
|
||||
}},
|
||||
}},
|
||||
InlineRouteConfig: inlineRouteConfig,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -580,6 +925,9 @@ func TestNewFilterChainImpl_Success_HTTPFilters(t *testing.T) {
|
|||
validServerSideHTTPFilter1,
|
||||
validServerSideHTTPFilter2,
|
||||
},
|
||||
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
|
||||
RouteConfig: routeConfig,
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
|
|
@ -596,6 +944,9 @@ func TestNewFilterChainImpl_Success_HTTPFilters(t *testing.T) {
|
|||
validServerSideHTTPFilter1,
|
||||
validServerSideHTTPFilter2,
|
||||
},
|
||||
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
|
||||
RouteConfig: routeConfig,
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
|
|
@ -621,7 +972,9 @@ func TestNewFilterChainImpl_Success_HTTPFilters(t *testing.T) {
|
|||
Filter: serverOnlyHTTPFilter{},
|
||||
Config: filterConfig{Cfg: serverOnlyCustomFilterConfig},
|
||||
},
|
||||
}},
|
||||
},
|
||||
InlineRouteConfig: inlineRouteConfig,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -641,6 +994,7 @@ func TestNewFilterChainImpl_Success_HTTPFilters(t *testing.T) {
|
|||
Config: filterConfig{Cfg: serverOnlyCustomFilterConfig},
|
||||
},
|
||||
},
|
||||
InlineRouteConfig: inlineRouteConfig,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -661,6 +1015,9 @@ func TestNewFilterChainImpl_Success_HTTPFilters(t *testing.T) {
|
|||
validServerSideHTTPFilter1,
|
||||
validServerSideHTTPFilter2,
|
||||
},
|
||||
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
|
||||
RouteConfig: routeConfig,
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
|
|
@ -671,6 +1028,9 @@ func TestNewFilterChainImpl_Success_HTTPFilters(t *testing.T) {
|
|||
HttpFilters: []*v3httppb.HttpFilter{
|
||||
validServerSideHTTPFilter1,
|
||||
},
|
||||
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
|
||||
RouteConfig: routeConfig,
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
|
|
@ -687,6 +1047,9 @@ func TestNewFilterChainImpl_Success_HTTPFilters(t *testing.T) {
|
|||
validServerSideHTTPFilter1,
|
||||
validServerSideHTTPFilter2,
|
||||
},
|
||||
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
|
||||
RouteConfig: routeConfig,
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
|
|
@ -697,6 +1060,9 @@ func TestNewFilterChainImpl_Success_HTTPFilters(t *testing.T) {
|
|||
HttpFilters: []*v3httppb.HttpFilter{
|
||||
validServerSideHTTPFilter1,
|
||||
},
|
||||
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
|
||||
RouteConfig: routeConfig,
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
|
|
@ -722,7 +1088,9 @@ func TestNewFilterChainImpl_Success_HTTPFilters(t *testing.T) {
|
|||
Filter: serverOnlyHTTPFilter{},
|
||||
Config: filterConfig{Cfg: serverOnlyCustomFilterConfig},
|
||||
},
|
||||
}},
|
||||
},
|
||||
InlineRouteConfig: inlineRouteConfig,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -742,6 +1110,7 @@ func TestNewFilterChainImpl_Success_HTTPFilters(t *testing.T) {
|
|||
Config: filterConfig{Cfg: serverOnlyCustomFilterConfig},
|
||||
},
|
||||
},
|
||||
InlineRouteConfig: inlineRouteConfig,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -789,7 +1158,7 @@ func TestNewFilterChainImpl_Success_SecurityConfig(t *testing.T) {
|
|||
srcPrefixMap: map[string]*sourcePrefixEntry{
|
||||
unspecifiedPrefixMapKey: {
|
||||
srcPortMap: map[int]*FilterChain{
|
||||
0: {},
|
||||
0: {InlineRouteConfig: inlineRouteConfig},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -797,7 +1166,7 @@ func TestNewFilterChainImpl_Success_SecurityConfig(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
def: &FilterChain{},
|
||||
def: &FilterChain{InlineRouteConfig: inlineRouteConfig},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -851,6 +1220,7 @@ func TestNewFilterChainImpl_Success_SecurityConfig(t *testing.T) {
|
|||
IdentityInstanceName: "identityPluginInstance",
|
||||
IdentityCertName: "identityCertName",
|
||||
},
|
||||
InlineRouteConfig: inlineRouteConfig,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -864,6 +1234,7 @@ func TestNewFilterChainImpl_Success_SecurityConfig(t *testing.T) {
|
|||
IdentityInstanceName: "defaultIdentityPluginInstance",
|
||||
IdentityCertName: "defaultIdentityCertName",
|
||||
},
|
||||
InlineRouteConfig: inlineRouteConfig,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -936,6 +1307,7 @@ func TestNewFilterChainImpl_Success_SecurityConfig(t *testing.T) {
|
|||
IdentityCertName: "identityCertName",
|
||||
RequireClientCert: true,
|
||||
},
|
||||
InlineRouteConfig: inlineRouteConfig,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -952,6 +1324,7 @@ func TestNewFilterChainImpl_Success_SecurityConfig(t *testing.T) {
|
|||
IdentityCertName: "defaultIdentityCertName",
|
||||
RequireClientCert: true,
|
||||
},
|
||||
InlineRouteConfig: inlineRouteConfig,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -982,7 +1355,7 @@ func TestNewFilterChainImpl_Success_UnsupportedMatchFields(t *testing.T) {
|
|||
srcPrefixMap: map[string]*sourcePrefixEntry{
|
||||
unspecifiedPrefixMapKey: {
|
||||
srcPortMap: map[int]*FilterChain{
|
||||
0: {},
|
||||
0: {InlineRouteConfig: inlineRouteConfig},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -1018,7 +1391,7 @@ func TestNewFilterChainImpl_Success_UnsupportedMatchFields(t *testing.T) {
|
|||
dstPrefixMap: map[string]*destPrefixEntry{
|
||||
unspecifiedPrefixMapKey: unspecifiedEntry,
|
||||
},
|
||||
def: &FilterChain{},
|
||||
def: &FilterChain{InlineRouteConfig: inlineRouteConfig},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -1047,7 +1420,7 @@ func TestNewFilterChainImpl_Success_UnsupportedMatchFields(t *testing.T) {
|
|||
net: ipNetFromCIDR("192.168.2.2/16"),
|
||||
},
|
||||
},
|
||||
def: &FilterChain{},
|
||||
def: &FilterChain{InlineRouteConfig: inlineRouteConfig},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -1076,7 +1449,7 @@ func TestNewFilterChainImpl_Success_UnsupportedMatchFields(t *testing.T) {
|
|||
net: ipNetFromCIDR("192.168.2.2/16"),
|
||||
},
|
||||
},
|
||||
def: &FilterChain{},
|
||||
def: &FilterChain{InlineRouteConfig: inlineRouteConfig},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -1105,7 +1478,7 @@ func TestNewFilterChainImpl_Success_UnsupportedMatchFields(t *testing.T) {
|
|||
net: ipNetFromCIDR("192.168.2.2/16"),
|
||||
},
|
||||
},
|
||||
def: &FilterChain{},
|
||||
def: &FilterChain{InlineRouteConfig: inlineRouteConfig},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
@ -1175,7 +1548,7 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
|
|||
srcPrefixMap: map[string]*sourcePrefixEntry{
|
||||
unspecifiedPrefixMapKey: {
|
||||
srcPortMap: map[int]*FilterChain{
|
||||
0: {},
|
||||
0: {InlineRouteConfig: inlineRouteConfig},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -1191,7 +1564,7 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
|
|||
srcPrefixMap: map[string]*sourcePrefixEntry{
|
||||
unspecifiedPrefixMapKey: {
|
||||
srcPortMap: map[int]*FilterChain{
|
||||
0: {},
|
||||
0: {InlineRouteConfig: inlineRouteConfig},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -1207,7 +1580,7 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
|
|||
srcPrefixMap: map[string]*sourcePrefixEntry{
|
||||
unspecifiedPrefixMapKey: {
|
||||
srcPortMap: map[int]*FilterChain{
|
||||
0: {},
|
||||
0: {InlineRouteConfig: inlineRouteConfig},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -1221,7 +1594,7 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
|
|||
srcPrefixMap: map[string]*sourcePrefixEntry{
|
||||
unspecifiedPrefixMapKey: {
|
||||
srcPortMap: map[int]*FilterChain{
|
||||
0: {},
|
||||
0: {InlineRouteConfig: inlineRouteConfig},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -1235,7 +1608,7 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
|
|||
srcPrefixMap: map[string]*sourcePrefixEntry{
|
||||
unspecifiedPrefixMapKey: {
|
||||
srcPortMap: map[int]*FilterChain{
|
||||
0: {},
|
||||
0: {InlineRouteConfig: inlineRouteConfig},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -1243,7 +1616,7 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
def: &FilterChain{},
|
||||
def: &FilterChain{InlineRouteConfig: inlineRouteConfig},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -1273,7 +1646,7 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
|
|||
srcPrefixMap: map[string]*sourcePrefixEntry{
|
||||
unspecifiedPrefixMapKey: {
|
||||
srcPortMap: map[int]*FilterChain{
|
||||
0: {},
|
||||
0: {InlineRouteConfig: inlineRouteConfig},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -1289,7 +1662,7 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
|
|||
srcPrefixMap: map[string]*sourcePrefixEntry{
|
||||
unspecifiedPrefixMapKey: {
|
||||
srcPortMap: map[int]*FilterChain{
|
||||
0: {},
|
||||
0: {InlineRouteConfig: inlineRouteConfig},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -1297,7 +1670,7 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
def: &FilterChain{},
|
||||
def: &FilterChain{InlineRouteConfig: inlineRouteConfig},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -1327,7 +1700,7 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
|
|||
"10.0.0.0/8": {
|
||||
net: ipNetFromCIDR("10.0.0.0/8"),
|
||||
srcPortMap: map[int]*FilterChain{
|
||||
0: {},
|
||||
0: {InlineRouteConfig: inlineRouteConfig},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -1342,7 +1715,7 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
|
|||
"192.168.0.0/16": {
|
||||
net: ipNetFromCIDR("192.168.0.0/16"),
|
||||
srcPortMap: map[int]*FilterChain{
|
||||
0: {},
|
||||
0: {InlineRouteConfig: inlineRouteConfig},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -1350,7 +1723,7 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
def: &FilterChain{},
|
||||
def: &FilterChain{InlineRouteConfig: inlineRouteConfig},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -1381,9 +1754,9 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
|
|||
srcPrefixMap: map[string]*sourcePrefixEntry{
|
||||
unspecifiedPrefixMapKey: {
|
||||
srcPortMap: map[int]*FilterChain{
|
||||
1: {},
|
||||
2: {},
|
||||
3: {},
|
||||
1: {InlineRouteConfig: inlineRouteConfig},
|
||||
2: {InlineRouteConfig: inlineRouteConfig},
|
||||
3: {InlineRouteConfig: inlineRouteConfig},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -1400,9 +1773,9 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
|
|||
"192.168.0.0/16": {
|
||||
net: ipNetFromCIDR("192.168.0.0/16"),
|
||||
srcPortMap: map[int]*FilterChain{
|
||||
1: {},
|
||||
2: {},
|
||||
3: {},
|
||||
1: {InlineRouteConfig: inlineRouteConfig},
|
||||
2: {InlineRouteConfig: inlineRouteConfig},
|
||||
3: {InlineRouteConfig: inlineRouteConfig},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -1410,7 +1783,7 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
def: &FilterChain{},
|
||||
def: &FilterChain{InlineRouteConfig: inlineRouteConfig},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -1484,7 +1857,7 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
|
|||
srcPrefixMap: map[string]*sourcePrefixEntry{
|
||||
unspecifiedPrefixMapKey: {
|
||||
srcPortMap: map[int]*FilterChain{
|
||||
0: {},
|
||||
0: {InlineRouteConfig: inlineRouteConfig},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -1498,7 +1871,7 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
|
|||
srcPrefixMap: map[string]*sourcePrefixEntry{
|
||||
unspecifiedPrefixMapKey: {
|
||||
srcPortMap: map[int]*FilterChain{
|
||||
0: {},
|
||||
0: {InlineRouteConfig: inlineRouteConfig},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -1512,7 +1885,7 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
|
|||
srcPrefixMap: map[string]*sourcePrefixEntry{
|
||||
unspecifiedPrefixMapKey: {
|
||||
srcPortMap: map[int]*FilterChain{
|
||||
0: {},
|
||||
0: {InlineRouteConfig: inlineRouteConfig},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -1532,7 +1905,7 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
|
|||
srcTypeArr: [3]*sourcePrefixes{},
|
||||
},
|
||||
},
|
||||
def: &FilterChain{},
|
||||
def: &FilterChain{InlineRouteConfig: inlineRouteConfig},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
@ -1804,7 +2177,10 @@ func TestLookup_Successes(t *testing.T) {
|
|||
IsUnspecifiedListener: true,
|
||||
DestAddr: net.IPv4(10, 1, 1, 1),
|
||||
},
|
||||
wantFC: &FilterChain{SecurityCfg: &SecurityConfig{IdentityInstanceName: "default"}},
|
||||
wantFC: &FilterChain{
|
||||
SecurityCfg: &SecurityConfig{IdentityInstanceName: "default"},
|
||||
InlineRouteConfig: inlineRouteConfig,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "unspecified destination match",
|
||||
|
|
@ -1815,7 +2191,10 @@ func TestLookup_Successes(t *testing.T) {
|
|||
SourceAddr: net.IPv4(10, 1, 1, 1),
|
||||
SourcePort: 1,
|
||||
},
|
||||
wantFC: &FilterChain{SecurityCfg: &SecurityConfig{IdentityInstanceName: "unspecified-dest-and-source-prefix"}},
|
||||
wantFC: &FilterChain{
|
||||
SecurityCfg: &SecurityConfig{IdentityInstanceName: "unspecified-dest-and-source-prefix"},
|
||||
InlineRouteConfig: inlineRouteConfig,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "wildcard destination match v4",
|
||||
|
|
@ -1826,7 +2205,10 @@ func TestLookup_Successes(t *testing.T) {
|
|||
SourceAddr: net.IPv4(10, 1, 1, 1),
|
||||
SourcePort: 1,
|
||||
},
|
||||
wantFC: &FilterChain{SecurityCfg: &SecurityConfig{IdentityInstanceName: "wildcard-prefixes-v4"}},
|
||||
wantFC: &FilterChain{
|
||||
SecurityCfg: &SecurityConfig{IdentityInstanceName: "wildcard-prefixes-v4"},
|
||||
InlineRouteConfig: inlineRouteConfig,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "wildcard source match v6",
|
||||
|
|
@ -1837,7 +2219,10 @@ func TestLookup_Successes(t *testing.T) {
|
|||
SourceAddr: net.ParseIP("2001:68::2"),
|
||||
SourcePort: 1,
|
||||
},
|
||||
wantFC: &FilterChain{SecurityCfg: &SecurityConfig{IdentityInstanceName: "wildcard-source-prefix-v6"}},
|
||||
wantFC: &FilterChain{
|
||||
SecurityCfg: &SecurityConfig{IdentityInstanceName: "wildcard-source-prefix-v6"},
|
||||
InlineRouteConfig: inlineRouteConfig,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "specific destination and wildcard source type match",
|
||||
|
|
@ -1848,7 +2233,10 @@ func TestLookup_Successes(t *testing.T) {
|
|||
SourceAddr: net.IPv4(192, 168, 100, 1),
|
||||
SourcePort: 80,
|
||||
},
|
||||
wantFC: &FilterChain{SecurityCfg: &SecurityConfig{IdentityInstanceName: "specific-destination-prefix-unspecified-source-type"}},
|
||||
wantFC: &FilterChain{
|
||||
SecurityCfg: &SecurityConfig{IdentityInstanceName: "specific-destination-prefix-unspecified-source-type"},
|
||||
InlineRouteConfig: inlineRouteConfig,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "specific destination and source type match",
|
||||
|
|
@ -1859,7 +2247,10 @@ func TestLookup_Successes(t *testing.T) {
|
|||
SourceAddr: net.IPv4(10, 1, 1, 1),
|
||||
SourcePort: 80,
|
||||
},
|
||||
wantFC: &FilterChain{SecurityCfg: &SecurityConfig{IdentityInstanceName: "specific-destination-prefix-specific-source-type"}},
|
||||
wantFC: &FilterChain{
|
||||
SecurityCfg: &SecurityConfig{IdentityInstanceName: "specific-destination-prefix-specific-source-type"},
|
||||
InlineRouteConfig: inlineRouteConfig,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "specific destination source type and source prefix",
|
||||
|
|
@ -1870,7 +2261,10 @@ func TestLookup_Successes(t *testing.T) {
|
|||
SourceAddr: net.IPv4(192, 168, 92, 100),
|
||||
SourcePort: 70,
|
||||
},
|
||||
wantFC: &FilterChain{SecurityCfg: &SecurityConfig{IdentityInstanceName: "specific-destination-prefix-specific-source-type-specific-source-prefix"}},
|
||||
wantFC: &FilterChain{
|
||||
SecurityCfg: &SecurityConfig{IdentityInstanceName: "specific-destination-prefix-specific-source-type-specific-source-prefix"},
|
||||
InlineRouteConfig: inlineRouteConfig,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "specific destination source type source prefix and source port",
|
||||
|
|
@ -1881,7 +2275,10 @@ func TestLookup_Successes(t *testing.T) {
|
|||
SourceAddr: net.IPv4(192, 168, 92, 100),
|
||||
SourcePort: 80,
|
||||
},
|
||||
wantFC: &FilterChain{SecurityCfg: &SecurityConfig{IdentityInstanceName: "specific-destination-prefix-specific-source-type-specific-source-prefix-specific-source-port"}},
|
||||
wantFC: &FilterChain{
|
||||
SecurityCfg: &SecurityConfig{IdentityInstanceName: "specific-destination-prefix-specific-source-type-specific-source-prefix-specific-source-port"},
|
||||
InlineRouteConfig: inlineRouteConfig,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -1918,6 +2315,8 @@ func (fci *FilterChainManager) Equal(other *FilterChainManager) bool {
|
|||
// TODO: Support comparing dstPrefixes slice?
|
||||
case !cmp.Equal(fci.def, other.def, cmpopts.EquateEmpty(), protocmp.Transform()):
|
||||
return false
|
||||
case !cmp.Equal(fci.RouteConfigNames, other.RouteConfigNames, cmpopts.EquateEmpty()):
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -493,7 +493,7 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) {
|
|||
InlineRouteConfig: &RouteConfigUpdate{
|
||||
VirtualHosts: []*VirtualHost{{
|
||||
Domains: []string{v3LDSTarget},
|
||||
Routes: []*Route{{Prefix: newStringP("/"), WeightedClusters: map[string]WeightedCluster{clusterName: {Weight: 1}}}},
|
||||
Routes: []*Route{{Prefix: newStringP("/"), WeightedClusters: map[string]WeightedCluster{clusterName: {Weight: 1}}, RouteAction: RouteActionRoute}},
|
||||
}}},
|
||||
MaxStreamDuration: time.Second,
|
||||
Raw: v3LisWithInlineRoute,
|
||||
|
|
@ -563,11 +563,30 @@ func (s) TestUnmarshalListener_ServerSide(t *testing.T) {
|
|||
)
|
||||
|
||||
var (
|
||||
routeConfig = &v3routepb.RouteConfiguration{
|
||||
Name: "routeName",
|
||||
VirtualHosts: []*v3routepb.VirtualHost{{
|
||||
Domains: []string{"lds.target.good:3333"},
|
||||
Routes: []*v3routepb.Route{{
|
||||
Match: &v3routepb.RouteMatch{
|
||||
PathSpecifier: &v3routepb.RouteMatch_Prefix{Prefix: "/"},
|
||||
},
|
||||
Action: &v3routepb.Route_NonForwardingAction{},
|
||||
}}}}}
|
||||
inlineRouteConfig = &RouteConfigUpdate{
|
||||
VirtualHosts: []*VirtualHost{{
|
||||
Domains: []string{"lds.target.good:3333"},
|
||||
Routes: []*Route{{Prefix: newStringP("/"), RouteAction: RouteActionNonForwardingAction}},
|
||||
}}}
|
||||
emptyValidNetworkFilters = []*v3listenerpb.Filter{
|
||||
{
|
||||
Name: "filter-1",
|
||||
ConfigType: &v3listenerpb.Filter_TypedConfig{
|
||||
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{}),
|
||||
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
|
||||
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
|
||||
RouteConfig: routeConfig,
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
@ -806,13 +825,21 @@ func (s) TestUnmarshalListener_ServerSide(t *testing.T) {
|
|||
{
|
||||
Name: "name",
|
||||
ConfigType: &v3listenerpb.Filter_TypedConfig{
|
||||
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{}),
|
||||
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
|
||||
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
|
||||
RouteConfig: routeConfig,
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "name",
|
||||
ConfigType: &v3listenerpb.Filter_TypedConfig{
|
||||
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{}),
|
||||
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
|
||||
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
|
||||
RouteConfig: routeConfig,
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -1051,7 +1078,7 @@ func (s) TestUnmarshalListener_ServerSide(t *testing.T) {
|
|||
srcPrefixMap: map[string]*sourcePrefixEntry{
|
||||
unspecifiedPrefixMapKey: {
|
||||
srcPortMap: map[int]*FilterChain{
|
||||
0: {},
|
||||
0: {InlineRouteConfig: inlineRouteConfig},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -1144,6 +1171,7 @@ func (s) TestUnmarshalListener_ServerSide(t *testing.T) {
|
|||
IdentityInstanceName: "identityPluginInstance",
|
||||
IdentityCertName: "identityCertName",
|
||||
},
|
||||
InlineRouteConfig: inlineRouteConfig,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -1157,6 +1185,7 @@ func (s) TestUnmarshalListener_ServerSide(t *testing.T) {
|
|||
IdentityInstanceName: "defaultIdentityPluginInstance",
|
||||
IdentityCertName: "defaultIdentityCertName",
|
||||
},
|
||||
InlineRouteConfig: inlineRouteConfig,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -1192,6 +1221,7 @@ func (s) TestUnmarshalListener_ServerSide(t *testing.T) {
|
|||
IdentityCertName: "identityCertName",
|
||||
RequireClientCert: true,
|
||||
},
|
||||
InlineRouteConfig: inlineRouteConfig,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -1208,6 +1238,7 @@ func (s) TestUnmarshalListener_ServerSide(t *testing.T) {
|
|||
IdentityCertName: "defaultIdentityCertName",
|
||||
RequireClientCert: true,
|
||||
},
|
||||
InlineRouteConfig: inlineRouteConfig,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ func (s) TestRDSGenerateRDSUpdateFromRouteConfiguration(t *testing.T) {
|
|||
Routes: []*Route{{
|
||||
Prefix: newStringP("/"),
|
||||
WeightedClusters: map[string]WeightedCluster{clusterName: {Weight: 1}},
|
||||
RouteAction: RouteActionRoute,
|
||||
}},
|
||||
HTTPFilterConfigOverride: cfgs,
|
||||
}},
|
||||
|
|
@ -178,7 +179,10 @@ func (s) TestRDSGenerateRDSUpdateFromRouteConfiguration(t *testing.T) {
|
|||
VirtualHosts: []*VirtualHost{
|
||||
{
|
||||
Domains: []string{ldsTarget},
|
||||
Routes: []*Route{{Prefix: newStringP("/"), CaseInsensitive: true, WeightedClusters: map[string]WeightedCluster{clusterName: {Weight: 1}}}},
|
||||
Routes: []*Route{{Prefix: newStringP("/"),
|
||||
CaseInsensitive: true,
|
||||
WeightedClusters: map[string]WeightedCluster{clusterName: {Weight: 1}},
|
||||
RouteAction: RouteActionRoute}},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -220,11 +224,15 @@ func (s) TestRDSGenerateRDSUpdateFromRouteConfiguration(t *testing.T) {
|
|||
VirtualHosts: []*VirtualHost{
|
||||
{
|
||||
Domains: []string{uninterestingDomain},
|
||||
Routes: []*Route{{Prefix: newStringP(""), WeightedClusters: map[string]WeightedCluster{uninterestingClusterName: {Weight: 1}}}},
|
||||
Routes: []*Route{{Prefix: newStringP(""),
|
||||
WeightedClusters: map[string]WeightedCluster{uninterestingClusterName: {Weight: 1}},
|
||||
RouteAction: RouteActionRoute}},
|
||||
},
|
||||
{
|
||||
Domains: []string{ldsTarget},
|
||||
Routes: []*Route{{Prefix: newStringP(""), WeightedClusters: map[string]WeightedCluster{clusterName: {Weight: 1}}}},
|
||||
Routes: []*Route{{Prefix: newStringP(""),
|
||||
WeightedClusters: map[string]WeightedCluster{clusterName: {Weight: 1}},
|
||||
RouteAction: RouteActionRoute}},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -254,7 +262,9 @@ func (s) TestRDSGenerateRDSUpdateFromRouteConfiguration(t *testing.T) {
|
|||
VirtualHosts: []*VirtualHost{
|
||||
{
|
||||
Domains: []string{ldsTarget},
|
||||
Routes: []*Route{{Prefix: newStringP("/"), WeightedClusters: map[string]WeightedCluster{clusterName: {Weight: 1}}}},
|
||||
Routes: []*Route{{Prefix: newStringP("/"),
|
||||
WeightedClusters: map[string]WeightedCluster{clusterName: {Weight: 1}},
|
||||
RouteAction: RouteActionRoute}},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -331,6 +341,7 @@ func (s) TestRDSGenerateRDSUpdateFromRouteConfiguration(t *testing.T) {
|
|||
"b": {Weight: 3},
|
||||
"c": {Weight: 5},
|
||||
},
|
||||
RouteAction: RouteActionRoute,
|
||||
}},
|
||||
},
|
||||
},
|
||||
|
|
@ -365,6 +376,7 @@ func (s) TestRDSGenerateRDSUpdateFromRouteConfiguration(t *testing.T) {
|
|||
Prefix: newStringP("/"),
|
||||
WeightedClusters: map[string]WeightedCluster{clusterName: {Weight: 1}},
|
||||
MaxStreamDuration: newDurationP(time.Second),
|
||||
RouteAction: RouteActionRoute,
|
||||
}},
|
||||
},
|
||||
},
|
||||
|
|
@ -399,6 +411,7 @@ func (s) TestRDSGenerateRDSUpdateFromRouteConfiguration(t *testing.T) {
|
|||
Prefix: newStringP("/"),
|
||||
WeightedClusters: map[string]WeightedCluster{clusterName: {Weight: 1}},
|
||||
MaxStreamDuration: newDurationP(time.Second),
|
||||
RouteAction: RouteActionRoute,
|
||||
}},
|
||||
},
|
||||
},
|
||||
|
|
@ -433,6 +446,7 @@ func (s) TestRDSGenerateRDSUpdateFromRouteConfiguration(t *testing.T) {
|
|||
Prefix: newStringP("/"),
|
||||
WeightedClusters: map[string]WeightedCluster{clusterName: {Weight: 1}},
|
||||
MaxStreamDuration: newDurationP(0),
|
||||
RouteAction: RouteActionRoute,
|
||||
}},
|
||||
},
|
||||
},
|
||||
|
|
@ -621,11 +635,15 @@ func (s) TestUnmarshalRouteConfig(t *testing.T) {
|
|||
VirtualHosts: []*VirtualHost{
|
||||
{
|
||||
Domains: []string{uninterestingDomain},
|
||||
Routes: []*Route{{Prefix: newStringP(""), WeightedClusters: map[string]WeightedCluster{uninterestingClusterName: {Weight: 1}}}},
|
||||
Routes: []*Route{{Prefix: newStringP(""),
|
||||
WeightedClusters: map[string]WeightedCluster{uninterestingClusterName: {Weight: 1}},
|
||||
RouteAction: RouteActionRoute}},
|
||||
},
|
||||
{
|
||||
Domains: []string{ldsTarget},
|
||||
Routes: []*Route{{Prefix: newStringP(""), WeightedClusters: map[string]WeightedCluster{v2ClusterName: {Weight: 1}}}},
|
||||
Routes: []*Route{{Prefix: newStringP(""),
|
||||
WeightedClusters: map[string]WeightedCluster{v2ClusterName: {Weight: 1}},
|
||||
RouteAction: RouteActionRoute}},
|
||||
},
|
||||
},
|
||||
Raw: v2RouteConfig,
|
||||
|
|
@ -644,11 +662,15 @@ func (s) TestUnmarshalRouteConfig(t *testing.T) {
|
|||
VirtualHosts: []*VirtualHost{
|
||||
{
|
||||
Domains: []string{uninterestingDomain},
|
||||
Routes: []*Route{{Prefix: newStringP(""), WeightedClusters: map[string]WeightedCluster{uninterestingClusterName: {Weight: 1}}}},
|
||||
Routes: []*Route{{Prefix: newStringP(""),
|
||||
WeightedClusters: map[string]WeightedCluster{uninterestingClusterName: {Weight: 1}},
|
||||
RouteAction: RouteActionRoute}},
|
||||
},
|
||||
{
|
||||
Domains: []string{ldsTarget},
|
||||
Routes: []*Route{{Prefix: newStringP(""), WeightedClusters: map[string]WeightedCluster{v3ClusterName: {Weight: 1}}}},
|
||||
Routes: []*Route{{Prefix: newStringP(""),
|
||||
WeightedClusters: map[string]WeightedCluster{v3ClusterName: {Weight: 1}},
|
||||
RouteAction: RouteActionRoute}},
|
||||
},
|
||||
},
|
||||
Raw: v3RouteConfig,
|
||||
|
|
@ -667,11 +689,15 @@ func (s) TestUnmarshalRouteConfig(t *testing.T) {
|
|||
VirtualHosts: []*VirtualHost{
|
||||
{
|
||||
Domains: []string{uninterestingDomain},
|
||||
Routes: []*Route{{Prefix: newStringP(""), WeightedClusters: map[string]WeightedCluster{uninterestingClusterName: {Weight: 1}}}},
|
||||
Routes: []*Route{{Prefix: newStringP(""),
|
||||
WeightedClusters: map[string]WeightedCluster{uninterestingClusterName: {Weight: 1}},
|
||||
RouteAction: RouteActionRoute}},
|
||||
},
|
||||
{
|
||||
Domains: []string{ldsTarget},
|
||||
Routes: []*Route{{Prefix: newStringP(""), WeightedClusters: map[string]WeightedCluster{v3ClusterName: {Weight: 1}}}},
|
||||
Routes: []*Route{{Prefix: newStringP(""),
|
||||
WeightedClusters: map[string]WeightedCluster{v3ClusterName: {Weight: 1}},
|
||||
RouteAction: RouteActionRoute}},
|
||||
},
|
||||
},
|
||||
Raw: v3RouteConfig,
|
||||
|
|
@ -680,11 +706,15 @@ func (s) TestUnmarshalRouteConfig(t *testing.T) {
|
|||
VirtualHosts: []*VirtualHost{
|
||||
{
|
||||
Domains: []string{uninterestingDomain},
|
||||
Routes: []*Route{{Prefix: newStringP(""), WeightedClusters: map[string]WeightedCluster{uninterestingClusterName: {Weight: 1}}}},
|
||||
Routes: []*Route{{Prefix: newStringP(""),
|
||||
WeightedClusters: map[string]WeightedCluster{uninterestingClusterName: {Weight: 1}},
|
||||
RouteAction: RouteActionRoute}},
|
||||
},
|
||||
{
|
||||
Domains: []string{ldsTarget},
|
||||
Routes: []*Route{{Prefix: newStringP(""), WeightedClusters: map[string]WeightedCluster{v2ClusterName: {Weight: 1}}}},
|
||||
Routes: []*Route{{Prefix: newStringP(""),
|
||||
WeightedClusters: map[string]WeightedCluster{v2ClusterName: {Weight: 1}},
|
||||
RouteAction: RouteActionRoute}},
|
||||
},
|
||||
},
|
||||
Raw: v2RouteConfig,
|
||||
|
|
@ -714,11 +744,15 @@ func (s) TestUnmarshalRouteConfig(t *testing.T) {
|
|||
VirtualHosts: []*VirtualHost{
|
||||
{
|
||||
Domains: []string{uninterestingDomain},
|
||||
Routes: []*Route{{Prefix: newStringP(""), WeightedClusters: map[string]WeightedCluster{uninterestingClusterName: {Weight: 1}}}},
|
||||
Routes: []*Route{{Prefix: newStringP(""),
|
||||
WeightedClusters: map[string]WeightedCluster{uninterestingClusterName: {Weight: 1}},
|
||||
RouteAction: RouteActionRoute}},
|
||||
},
|
||||
{
|
||||
Domains: []string{ldsTarget},
|
||||
Routes: []*Route{{Prefix: newStringP(""), WeightedClusters: map[string]WeightedCluster{v3ClusterName: {Weight: 1}}}},
|
||||
Routes: []*Route{{Prefix: newStringP(""),
|
||||
WeightedClusters: map[string]WeightedCluster{v3ClusterName: {Weight: 1}},
|
||||
RouteAction: RouteActionRoute}},
|
||||
},
|
||||
},
|
||||
Raw: v3RouteConfig,
|
||||
|
|
@ -727,11 +761,15 @@ func (s) TestUnmarshalRouteConfig(t *testing.T) {
|
|||
VirtualHosts: []*VirtualHost{
|
||||
{
|
||||
Domains: []string{uninterestingDomain},
|
||||
Routes: []*Route{{Prefix: newStringP(""), WeightedClusters: map[string]WeightedCluster{uninterestingClusterName: {Weight: 1}}}},
|
||||
Routes: []*Route{{Prefix: newStringP(""),
|
||||
WeightedClusters: map[string]WeightedCluster{uninterestingClusterName: {Weight: 1}},
|
||||
RouteAction: RouteActionRoute}},
|
||||
},
|
||||
{
|
||||
Domains: []string{ldsTarget},
|
||||
Routes: []*Route{{Prefix: newStringP(""), WeightedClusters: map[string]WeightedCluster{v2ClusterName: {Weight: 1}}}},
|
||||
Routes: []*Route{{Prefix: newStringP(""),
|
||||
WeightedClusters: map[string]WeightedCluster{v2ClusterName: {Weight: 1}},
|
||||
RouteAction: RouteActionRoute}},
|
||||
},
|
||||
},
|
||||
Raw: v2RouteConfig,
|
||||
|
|
@ -794,6 +832,7 @@ func (s) TestRoutesProtoToSlice(t *testing.T) {
|
|||
CaseInsensitive: true,
|
||||
WeightedClusters: map[string]WeightedCluster{"A": {Weight: 40}, "B": {Weight: 60, HTTPFilterConfigOverride: cfgs}},
|
||||
HTTPFilterConfigOverride: cfgs,
|
||||
RouteAction: RouteActionRoute,
|
||||
}}
|
||||
}
|
||||
)
|
||||
|
|
@ -833,6 +872,7 @@ func (s) TestRoutesProtoToSlice(t *testing.T) {
|
|||
Prefix: newStringP("/"),
|
||||
CaseInsensitive: true,
|
||||
WeightedClusters: map[string]WeightedCluster{"A": {Weight: 40}, "B": {Weight: 60}},
|
||||
RouteAction: RouteActionRoute,
|
||||
}},
|
||||
},
|
||||
{
|
||||
|
|
@ -880,6 +920,7 @@ func (s) TestRoutesProtoToSlice(t *testing.T) {
|
|||
},
|
||||
Fraction: newUInt32P(10000),
|
||||
WeightedClusters: map[string]WeightedCluster{"A": {Weight: 40}, "B": {Weight: 60}},
|
||||
RouteAction: RouteActionRoute,
|
||||
}},
|
||||
wantErr: false,
|
||||
},
|
||||
|
|
@ -925,6 +966,7 @@ func (s) TestRoutesProtoToSlice(t *testing.T) {
|
|||
},
|
||||
Fraction: newUInt32P(10000),
|
||||
WeightedClusters: map[string]WeightedCluster{"A": {Weight: 40}, "B": {Weight: 60}},
|
||||
RouteAction: RouteActionRoute,
|
||||
}},
|
||||
wantErr: false,
|
||||
},
|
||||
|
|
@ -959,6 +1001,7 @@ func (s) TestRoutesProtoToSlice(t *testing.T) {
|
|||
wantRoutes: []*Route{{
|
||||
Prefix: newStringP("/a/"),
|
||||
WeightedClusters: map[string]WeightedCluster{"A": {Weight: 40}, "B": {Weight: 60}},
|
||||
RouteAction: RouteActionRoute,
|
||||
}},
|
||||
wantErr: false,
|
||||
},
|
||||
|
|
@ -1126,6 +1169,7 @@ func (s) TestRoutesProtoToSlice(t *testing.T) {
|
|||
wantRoutes: []*Route{{
|
||||
Prefix: newStringP("/a/"),
|
||||
WeightedClusters: map[string]WeightedCluster{"A": {Weight: 40}, "B": {Weight: 60}},
|
||||
RouteAction: RouteActionRoute,
|
||||
}},
|
||||
wantErr: false,
|
||||
},
|
||||
|
|
@ -1151,6 +1195,7 @@ func (s) TestRoutesProtoToSlice(t *testing.T) {
|
|||
wantRoutes: []*Route{{
|
||||
Prefix: newStringP("/a/"),
|
||||
WeightedClusters: map[string]WeightedCluster{"A": {Weight: 20}, "B": {Weight: 30}},
|
||||
RouteAction: RouteActionRoute,
|
||||
}},
|
||||
wantErr: false,
|
||||
},
|
||||
|
|
@ -1206,6 +1251,7 @@ func (s) TestRoutesProtoToSlice(t *testing.T) {
|
|||
HashPolicies: []*HashPolicy{
|
||||
{HashPolicyType: HashPolicyTypeChannelID},
|
||||
},
|
||||
RouteAction: RouteActionRoute,
|
||||
}},
|
||||
wantErr: false,
|
||||
},
|
||||
|
|
@ -1264,6 +1310,7 @@ func (s) TestRoutesProtoToSlice(t *testing.T) {
|
|||
{HashPolicyType: HashPolicyTypeHeader,
|
||||
HeaderName: ":path"},
|
||||
},
|
||||
RouteAction: RouteActionRoute,
|
||||
}},
|
||||
wantErr: false,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -111,11 +111,16 @@ func (s) TestRDSHandleResponseWithRouting(t *testing.T) {
|
|||
VirtualHosts: []*xdsclient.VirtualHost{
|
||||
{
|
||||
Domains: []string{uninterestingDomain},
|
||||
Routes: []*xdsclient.Route{{Prefix: newStringP(""), WeightedClusters: map[string]xdsclient.WeightedCluster{uninterestingClusterName: {Weight: 1}}}},
|
||||
Routes: []*xdsclient.Route{{Prefix: newStringP(""),
|
||||
WeightedClusters: map[string]xdsclient.WeightedCluster{uninterestingClusterName: {Weight: 1}},
|
||||
RouteAction: xdsclient.RouteActionRoute}},
|
||||
},
|
||||
{
|
||||
Domains: []string{goodLDSTarget1},
|
||||
Routes: []*xdsclient.Route{{Prefix: newStringP(""), WeightedClusters: map[string]xdsclient.WeightedCluster{goodClusterName2: {Weight: 1}}}},
|
||||
Routes: []*xdsclient.Route{{
|
||||
Prefix: newStringP(""),
|
||||
WeightedClusters: map[string]xdsclient.WeightedCluster{goodClusterName2: {Weight: 1}},
|
||||
RouteAction: xdsclient.RouteActionRoute}},
|
||||
},
|
||||
},
|
||||
Raw: marshaledGoodRouteConfig2,
|
||||
|
|
@ -136,11 +141,16 @@ func (s) TestRDSHandleResponseWithRouting(t *testing.T) {
|
|||
VirtualHosts: []*xdsclient.VirtualHost{
|
||||
{
|
||||
Domains: []string{uninterestingDomain},
|
||||
Routes: []*xdsclient.Route{{Prefix: newStringP(""), WeightedClusters: map[string]xdsclient.WeightedCluster{uninterestingClusterName: {Weight: 1}}}},
|
||||
Routes: []*xdsclient.Route{{
|
||||
Prefix: newStringP(""),
|
||||
WeightedClusters: map[string]xdsclient.WeightedCluster{uninterestingClusterName: {Weight: 1}},
|
||||
RouteAction: xdsclient.RouteActionRoute}},
|
||||
},
|
||||
{
|
||||
Domains: []string{goodLDSTarget1},
|
||||
Routes: []*xdsclient.Route{{Prefix: newStringP(""), WeightedClusters: map[string]xdsclient.WeightedCluster{goodClusterName1: {Weight: 1}}}},
|
||||
Routes: []*xdsclient.Route{{Prefix: newStringP(""),
|
||||
WeightedClusters: map[string]xdsclient.WeightedCluster{goodClusterName1: {Weight: 1}},
|
||||
RouteAction: xdsclient.RouteActionRoute}},
|
||||
},
|
||||
},
|
||||
Raw: marshaledGoodRouteConfig1,
|
||||
|
|
|
|||
|
|
@ -277,65 +277,6 @@ func processServerSideListener(lis *v3listenerpb.Listener) (*ListenerUpdate, err
|
|||
return lu, nil
|
||||
}
|
||||
|
||||
func processNetworkFilters(filters []*v3listenerpb.Filter) ([]HTTPFilter, error) {
|
||||
seenNames := make(map[string]bool, len(filters))
|
||||
seenHCM := false
|
||||
var httpFilters []HTTPFilter
|
||||
for _, filter := range filters {
|
||||
name := filter.GetName()
|
||||
if name == "" {
|
||||
return nil, fmt.Errorf("network filters {%+v} is missing name field in filter: {%+v}", filters, filter)
|
||||
}
|
||||
if seenNames[name] {
|
||||
return nil, fmt.Errorf("network filters {%+v} has duplicate filter name %q", filters, name)
|
||||
}
|
||||
seenNames[name] = true
|
||||
|
||||
// Network filters have a oneof field named `config_type` where we
|
||||
// only support `TypedConfig` variant.
|
||||
switch typ := filter.GetConfigType().(type) {
|
||||
case *v3listenerpb.Filter_TypedConfig:
|
||||
// The typed_config field has an `anypb.Any` proto which could
|
||||
// directly contain the serialized bytes of the actual filter
|
||||
// configuration, or it could be encoded as a `TypedStruct`.
|
||||
// TODO: Add support for `TypedStruct`.
|
||||
tc := filter.GetTypedConfig()
|
||||
|
||||
// The only network filter that we currently support is the v3
|
||||
// HttpConnectionManager. So, we can directly check the type_url
|
||||
// and unmarshal the config.
|
||||
// TODO: Implement a registry of supported network filters (like
|
||||
// we have for HTTP filters), when we have to support network
|
||||
// filters other than HttpConnectionManager.
|
||||
if tc.GetTypeUrl() != version.V3HTTPConnManagerURL {
|
||||
return nil, fmt.Errorf("network filters {%+v} has unsupported network filter %q in filter {%+v}", filters, tc.GetTypeUrl(), filter)
|
||||
}
|
||||
hcm := &v3httppb.HttpConnectionManager{}
|
||||
if err := ptypes.UnmarshalAny(tc, hcm); err != nil {
|
||||
return nil, fmt.Errorf("network filters {%+v} failed unmarshaling of network filter {%+v}: %v", filters, filter, err)
|
||||
}
|
||||
// "Any filters after HttpConnectionManager should be ignored during
|
||||
// connection processing but still be considered for validity.
|
||||
// HTTPConnectionManager must have valid http_filters." - A36
|
||||
filters, err := processHTTPFilters(hcm.GetHttpFilters(), true)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("network filters {%+v} had invalid server side HTTP Filters {%+v}", filters, hcm.GetHttpFilters())
|
||||
}
|
||||
if !seenHCM {
|
||||
// TODO: Implement terminal filter logic, as per A36.
|
||||
httpFilters = filters
|
||||
seenHCM = true
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("network filters {%+v} has unsupported config_type %T in filter %s", filters, typ, filter.GetName())
|
||||
}
|
||||
}
|
||||
if !seenHCM {
|
||||
return nil, fmt.Errorf("network filters {%+v} missing HttpConnectionManager filter", filters)
|
||||
}
|
||||
return httpFilters, nil
|
||||
}
|
||||
|
||||
// UnmarshalRouteConfig processes resources received in an RDS response,
|
||||
// validates them, and transforms them into a native struct which contains only
|
||||
// fields we are interested in. The provided hostname determines the route
|
||||
|
|
@ -491,65 +432,74 @@ func routesProtoToSlice(routes []*v3routepb.Route, logger *grpclog.PrefixLogger,
|
|||
route.Fraction = &n
|
||||
}
|
||||
|
||||
route.WeightedClusters = make(map[string]WeightedCluster)
|
||||
action := r.GetRoute()
|
||||
switch r.GetAction().(type) {
|
||||
case *v3routepb.Route_Route:
|
||||
route.WeightedClusters = make(map[string]WeightedCluster)
|
||||
action := r.GetRoute()
|
||||
|
||||
// Hash Policies are only applicable for a Ring Hash LB.
|
||||
if env.RingHashSupport {
|
||||
hp, err := hashPoliciesProtoToSlice(action.HashPolicy, logger)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
route.HashPolicies = hp
|
||||
}
|
||||
|
||||
switch a := action.GetClusterSpecifier().(type) {
|
||||
case *v3routepb.RouteAction_Cluster:
|
||||
route.WeightedClusters[a.Cluster] = WeightedCluster{Weight: 1}
|
||||
case *v3routepb.RouteAction_WeightedClusters:
|
||||
wcs := a.WeightedClusters
|
||||
var totalWeight uint32
|
||||
for _, c := range wcs.Clusters {
|
||||
w := c.GetWeight().GetValue()
|
||||
if w == 0 {
|
||||
continue
|
||||
// Hash Policies are only applicable for a Ring Hash LB.
|
||||
if env.RingHashSupport {
|
||||
hp, err := hashPoliciesProtoToSlice(action.HashPolicy, logger)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wc := WeightedCluster{Weight: w}
|
||||
if !v2 {
|
||||
cfgs, err := processHTTPFilterOverrides(c.GetTypedPerFilterConfig())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("route %+v, action %+v: %v", r, a, err)
|
||||
route.HashPolicies = hp
|
||||
}
|
||||
|
||||
switch a := action.GetClusterSpecifier().(type) {
|
||||
case *v3routepb.RouteAction_Cluster:
|
||||
route.WeightedClusters[a.Cluster] = WeightedCluster{Weight: 1}
|
||||
case *v3routepb.RouteAction_WeightedClusters:
|
||||
wcs := a.WeightedClusters
|
||||
var totalWeight uint32
|
||||
for _, c := range wcs.Clusters {
|
||||
w := c.GetWeight().GetValue()
|
||||
if w == 0 {
|
||||
continue
|
||||
}
|
||||
wc.HTTPFilterConfigOverride = cfgs
|
||||
wc := WeightedCluster{Weight: w}
|
||||
if !v2 {
|
||||
cfgs, err := processHTTPFilterOverrides(c.GetTypedPerFilterConfig())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("route %+v, action %+v: %v", r, a, err)
|
||||
}
|
||||
wc.HTTPFilterConfigOverride = cfgs
|
||||
}
|
||||
route.WeightedClusters[c.GetName()] = wc
|
||||
totalWeight += w
|
||||
}
|
||||
route.WeightedClusters[c.GetName()] = wc
|
||||
totalWeight += w
|
||||
// envoy xds doc
|
||||
// default TotalWeight https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto.html#envoy-v3-api-field-config-route-v3-weightedcluster-total-weight
|
||||
wantTotalWeight := uint32(100)
|
||||
if tw := wcs.GetTotalWeight(); tw != nil {
|
||||
wantTotalWeight = tw.GetValue()
|
||||
}
|
||||
if totalWeight != wantTotalWeight {
|
||||
return nil, fmt.Errorf("route %+v, action %+v, weights of clusters do not add up to total total weight, got: %v, expected total weight from response: %v", r, a, totalWeight, wantTotalWeight)
|
||||
}
|
||||
if totalWeight == 0 {
|
||||
return nil, fmt.Errorf("route %+v, action %+v, has no valid cluster in WeightedCluster action", r, a)
|
||||
}
|
||||
case *v3routepb.RouteAction_ClusterHeader:
|
||||
continue
|
||||
}
|
||||
// envoy xds doc
|
||||
// default TotalWeight https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto.html#envoy-v3-api-field-config-route-v3-weightedcluster-total-weight
|
||||
wantTotalWeight := uint32(100)
|
||||
if tw := wcs.GetTotalWeight(); tw != nil {
|
||||
wantTotalWeight = tw.GetValue()
|
||||
}
|
||||
if totalWeight != wantTotalWeight {
|
||||
return nil, fmt.Errorf("route %+v, action %+v, weights of clusters do not add up to total total weight, got: %v, expected total weight from response: %v", r, a, totalWeight, wantTotalWeight)
|
||||
}
|
||||
if totalWeight == 0 {
|
||||
return nil, fmt.Errorf("route %+v, action %+v, has no valid cluster in WeightedCluster action", r, a)
|
||||
}
|
||||
case *v3routepb.RouteAction_ClusterHeader:
|
||||
continue
|
||||
}
|
||||
|
||||
msd := action.GetMaxStreamDuration()
|
||||
// Prefer grpc_timeout_header_max, if set.
|
||||
dur := msd.GetGrpcTimeoutHeaderMax()
|
||||
if dur == nil {
|
||||
dur = msd.GetMaxStreamDuration()
|
||||
}
|
||||
if dur != nil {
|
||||
d := dur.AsDuration()
|
||||
route.MaxStreamDuration = &d
|
||||
msd := action.GetMaxStreamDuration()
|
||||
// Prefer grpc_timeout_header_max, if set.
|
||||
dur := msd.GetGrpcTimeoutHeaderMax()
|
||||
if dur == nil {
|
||||
dur = msd.GetMaxStreamDuration()
|
||||
}
|
||||
if dur != nil {
|
||||
d := dur.AsDuration()
|
||||
route.MaxStreamDuration = &d
|
||||
}
|
||||
route.RouteAction = RouteActionRoute
|
||||
case *v3routepb.Route_NonForwardingAction:
|
||||
// Expected to be used on server side.
|
||||
route.RouteAction = RouteActionNonForwardingAction
|
||||
default:
|
||||
route.RouteAction = RouteActionUnsupported
|
||||
}
|
||||
|
||||
if !v2 {
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import (
|
|||
|
||||
v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
|
||||
v3listenerpb "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
|
||||
v3routepb "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
|
||||
v3httppb "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
|
||||
v3tlspb "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3"
|
||||
"google.golang.org/grpc"
|
||||
|
|
@ -688,7 +689,20 @@ func (s) TestHandleListenerUpdate_NoXDSCreds(t *testing.T) {
|
|||
{
|
||||
Name: "filter-1",
|
||||
ConfigType: &v3listenerpb.Filter_TypedConfig{
|
||||
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{}),
|
||||
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
|
||||
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
|
||||
RouteConfig: &v3routepb.RouteConfiguration{
|
||||
Name: "routeName",
|
||||
VirtualHosts: []*v3routepb.VirtualHost{{
|
||||
Domains: []string{"lds.target.good:3333"},
|
||||
Routes: []*v3routepb.Route{{
|
||||
Match: &v3routepb.RouteMatch{
|
||||
PathSpecifier: &v3routepb.RouteMatch_Prefix{Prefix: "/"},
|
||||
},
|
||||
Action: &v3routepb.Route_NonForwardingAction{},
|
||||
}}}}},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in New Issue