support dynamically defined rds

This commit is contained in:
Caleb Doxsey 2023-04-13 17:03:00 -06:00
parent 4d3c2be99b
commit a8350a17e3
3 changed files with 60 additions and 39 deletions

View file

@ -166,7 +166,7 @@ func (b *Builder) BuildBootstrapStaticResources(
return nil, fmt.Errorf("error building clusters: %w", err) return nil, fmt.Errorf("error building clusters: %w", err)
} }
staticResources.Listeners, err = b.BuildListeners(ctx, cfg) staticResources.Listeners, err = b.BuildListeners(ctx, cfg, fullyStatic)
if err != nil { if err != nil {
return nil, fmt.Errorf("error building listeners: %w", err) return nil, fmt.Errorf("error building listeners: %w", err)
} }

View file

@ -56,11 +56,15 @@ func init() {
} }
// BuildListeners builds envoy listeners from the given config. // BuildListeners builds envoy listeners from the given config.
func (b *Builder) BuildListeners(ctx context.Context, cfg *config.Config) ([]*envoy_config_listener_v3.Listener, error) { func (b *Builder) BuildListeners(
ctx context.Context,
cfg *config.Config,
fullyStatic bool,
) ([]*envoy_config_listener_v3.Listener, error) {
var listeners []*envoy_config_listener_v3.Listener var listeners []*envoy_config_listener_v3.Listener
if config.IsAuthenticate(cfg.Options.Services) || config.IsProxy(cfg.Options.Services) { if config.IsAuthenticate(cfg.Options.Services) || config.IsProxy(cfg.Options.Services) {
li, err := b.buildMainListener(ctx, cfg) li, err := b.buildMainListener(ctx, cfg, fullyStatic)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -128,7 +132,11 @@ func (b *Builder) buildTLSSocket(ctx context.Context, cfg *config.Config, certs
}, nil }, nil
} }
func (b *Builder) buildMainListener(ctx context.Context, cfg *config.Config) (*envoy_config_listener_v3.Listener, error) { func (b *Builder) buildMainListener(
ctx context.Context,
cfg *config.Config,
fullyStatic bool,
) (*envoy_config_listener_v3.Listener, error) {
li := newEnvoyListener("http-ingress") li := newEnvoyListener("http-ingress")
if cfg.Options.UseProxyProtocol { if cfg.Options.UseProxyProtocol {
li.ListenerFilters = append(li.ListenerFilters, ProxyProtocolFilter()) li.ListenerFilters = append(li.ListenerFilters, ProxyProtocolFilter())
@ -137,7 +145,7 @@ func (b *Builder) buildMainListener(ctx context.Context, cfg *config.Config) (*e
if cfg.Options.InsecureServer { if cfg.Options.InsecureServer {
li.Address = buildAddress(cfg.Options.Addr, 80) li.Address = buildAddress(cfg.Options.Addr, 80)
filter, err := b.buildMainHTTPConnectionManagerFilter(cfg.Options) filter, err := b.buildMainHTTPConnectionManagerFilter(ctx, cfg, fullyStatic)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -156,7 +164,7 @@ func (b *Builder) buildMainListener(ctx context.Context, cfg *config.Config) (*e
return nil, err return nil, err
} }
filter, err := b.buildMainHTTPConnectionManagerFilter(cfg.Options, allCertificates...) filter, err := b.buildMainHTTPConnectionManagerFilter(ctx, cfg, fullyStatic)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -254,12 +262,13 @@ func (b *Builder) buildMetricsListener(cfg *config.Config) (*envoy_config_listen
} }
func (b *Builder) buildMainHTTPConnectionManagerFilter( func (b *Builder) buildMainHTTPConnectionManagerFilter(
options *config.Options, ctx context.Context,
certs ...tls.Certificate, cfg *config.Config,
fullyStatic bool,
) (*envoy_config_listener_v3.Filter, error) { ) (*envoy_config_listener_v3.Filter, error) {
var grpcClientTimeout *durationpb.Duration var grpcClientTimeout *durationpb.Duration
if options.GRPCClientTimeout != 0 { if cfg.Options.GRPCClientTimeout != 0 {
grpcClientTimeout = durationpb.New(options.GRPCClientTimeout) grpcClientTimeout = durationpb.New(cfg.Options.GRPCClientTimeout)
} else { } else {
grpcClientTimeout = durationpb.New(30 * time.Second) grpcClientTimeout = durationpb.New(30 * time.Second)
} }
@ -274,21 +283,48 @@ func (b *Builder) buildMainHTTPConnectionManagerFilter(
filters = append(filters, HTTPRouterFilter()) filters = append(filters, HTTPRouterFilter())
var maxStreamDuration *durationpb.Duration var maxStreamDuration *durationpb.Duration
if options.WriteTimeout > 0 { if cfg.Options.WriteTimeout > 0 {
maxStreamDuration = durationpb.New(options.WriteTimeout) maxStreamDuration = durationpb.New(cfg.Options.WriteTimeout)
} }
tracingProvider, err := buildTracingHTTP(options) tracingProvider, err := buildTracingHTTP(cfg.Options)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return HTTPConnectionManagerFilter(&envoy_http_connection_manager.HttpConnectionManager{ mgr := &envoy_http_connection_manager.HttpConnectionManager{
AlwaysSetRequestIdInResponse: true, AlwaysSetRequestIdInResponse: true,
CodecType: cfg.Options.GetCodecType().ToEnvoy(),
StatPrefix: "ingress",
HttpFilters: filters,
AccessLog: buildAccessLogs(cfg.Options),
CommonHttpProtocolOptions: &envoy_config_core_v3.HttpProtocolOptions{
IdleTimeout: durationpb.New(cfg.Options.IdleTimeout),
MaxStreamDuration: maxStreamDuration,
},
HttpProtocolOptions: http1ProtocolOptions,
RequestTimeout: durationpb.New(cfg.Options.ReadTimeout),
Tracing: &envoy_http_connection_manager.HttpConnectionManager_Tracing{
RandomSampling: &envoy_type_v3.Percent{Value: cfg.Options.TracingSampleRate * 100},
Provider: tracingProvider,
},
// See https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/headers#x-forwarded-for
UseRemoteAddress: &wrappers.BoolValue{Value: true},
SkipXffAppend: cfg.Options.SkipXffAppend,
XffNumTrustedHops: cfg.Options.XffNumTrustedHops,
LocalReplyConfig: b.buildLocalReplyConfig(cfg.Options, false),
}
CodecType: options.GetCodecType().ToEnvoy(), if fullyStatic {
StatPrefix: "ingress", routeConfiguration, err := b.buildMainRouteConfiguration(ctx, cfg)
RouteSpecifier: &envoy_http_connection_manager.HttpConnectionManager_Rds{ if err != nil {
return nil, err
}
mgr.RouteSpecifier = &envoy_http_connection_manager.HttpConnectionManager_RouteConfig{
RouteConfig: routeConfiguration,
}
} else {
mgr.RouteSpecifier = &envoy_http_connection_manager.HttpConnectionManager_Rds{
Rds: &envoy_http_connection_manager.Rds{ Rds: &envoy_http_connection_manager.Rds{
ConfigSource: &envoy_config_core_v3.ConfigSource{ ConfigSource: &envoy_config_core_v3.ConfigSource{
ResourceApiVersion: envoy_config_core_v3.ApiVersion_V3, ResourceApiVersion: envoy_config_core_v3.ApiVersion_V3,
@ -296,25 +332,10 @@ func (b *Builder) buildMainHTTPConnectionManagerFilter(
}, },
RouteConfigName: "main", RouteConfigName: "main",
}, },
}, }
HttpFilters: filters, }
AccessLog: buildAccessLogs(options),
CommonHttpProtocolOptions: &envoy_config_core_v3.HttpProtocolOptions{ return HTTPConnectionManagerFilter(mgr), nil
IdleTimeout: durationpb.New(options.IdleTimeout),
MaxStreamDuration: maxStreamDuration,
},
HttpProtocolOptions: http1ProtocolOptions,
RequestTimeout: durationpb.New(options.ReadTimeout),
Tracing: &envoy_http_connection_manager.HttpConnectionManager_Tracing{
RandomSampling: &envoy_type_v3.Percent{Value: options.TracingSampleRate * 100},
Provider: tracingProvider,
},
// See https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/headers#x-forwarded-for
UseRemoteAddress: &wrappers.BoolValue{Value: true},
SkipXffAppend: options.SkipXffAppend,
XffNumTrustedHops: options.XffNumTrustedHops,
LocalReplyConfig: b.buildLocalReplyConfig(options, false),
}), nil
} }
func (b *Builder) buildMetricsHTTPConnectionManagerFilter() (*envoy_config_listener_v3.Filter, error) { func (b *Builder) buildMetricsHTTPConnectionManagerFilter() (*envoy_config_listener_v3.Filter, error) {

View file

@ -65,7 +65,7 @@ func Test_buildMainHTTPConnectionManagerFilter(t *testing.T) {
options.SkipXffAppend = true options.SkipXffAppend = true
options.XffNumTrustedHops = 1 options.XffNumTrustedHops = 1
options.AuthenticateURLString = "https://authenticate.example.com" options.AuthenticateURLString = "https://authenticate.example.com"
filter, err := b.buildMainHTTPConnectionManagerFilter(options) filter, err := b.buildMainHTTPConnectionManagerFilter(context.Background(), &config.Config{Options: options}, false)
require.NoError(t, err) require.NoError(t, err)
testutil.AssertProtoJSONEqual(t, testData(t, "main_http_connection_manager_filter.json", nil), filter) testutil.AssertProtoJSONEqual(t, testData(t, "main_http_connection_manager_filter.json", nil), filter)
} }
@ -353,7 +353,7 @@ func Test_requireProxyProtocol(t *testing.T) {
li, err := b.buildMainListener(context.Background(), &config.Config{Options: &config.Options{ li, err := b.buildMainListener(context.Background(), &config.Config{Options: &config.Options{
UseProxyProtocol: true, UseProxyProtocol: true,
InsecureServer: true, InsecureServer: true,
}}) }}, false)
require.NoError(t, err) require.NoError(t, err)
testutil.AssertProtoJSONEqual(t, `[ testutil.AssertProtoJSONEqual(t, `[
{ {
@ -368,7 +368,7 @@ func Test_requireProxyProtocol(t *testing.T) {
li, err := b.buildMainListener(context.Background(), &config.Config{Options: &config.Options{ li, err := b.buildMainListener(context.Background(), &config.Config{Options: &config.Options{
UseProxyProtocol: false, UseProxyProtocol: false,
InsecureServer: true, InsecureServer: true,
}}) }}, false)
require.NoError(t, err) require.NoError(t, err)
assert.Len(t, li.GetListenerFilters(), 0) assert.Len(t, li.GetListenerFilters(), 0)
}) })