diff --git a/source/exe/BUILD b/source/exe/BUILD index 192c7ca8fd58..ed61583b45f2 100644 --- a/source/exe/BUILD +++ b/source/exe/BUILD @@ -35,8 +35,10 @@ envoy_cc_library( "//source/server/config/http:dynamo_lib", "//source/server/config/http:fault_lib", "//source/server/config/http:grpc_http1_bridge_lib", + "//source/server/config/http:lightstep_lib", "//source/server/config/http:ratelimit_lib", "//source/server/config/http:router_lib", + "//source/server/config/http:zipkin_lib", "//source/server/config/network:client_ssl_auth_lib", "//source/server/config/network:echo_lib", "//source/server/config/network:http_connection_manager_lib", diff --git a/source/server/config/http/BUILD b/source/server/config/http/BUILD index 49800b12c349..2aad7bb20b21 100644 --- a/source/server/config/http/BUILD +++ b/source/server/config/http/BUILD @@ -53,6 +53,17 @@ envoy_cc_library( ], ) +envoy_cc_library( + name = "lightstep_lib", + srcs = ["lightstep_http_tracer.cc"], + hdrs = ["lightstep_http_tracer.h"], + deps = [ + "//include/envoy/server:instance_interface", + "//source/common/tracing:http_tracer_lib", + "//source/server:configuration_lib", + ], +) + envoy_cc_library( name = "ratelimit_lib", srcs = ["ratelimit.cc"], @@ -77,3 +88,14 @@ envoy_cc_library( "//source/server/config/network:http_connection_manager_lib", ], ) + +envoy_cc_library( + name = "zipkin_lib", + srcs = ["zipkin_http_tracer.cc"], + hdrs = ["zipkin_http_tracer.h"], + deps = [ + "//include/envoy/server:instance_interface", + "//source/common/tracing/zipkin:zipkin_lib", + "//source/server:configuration_lib", + ], +) diff --git a/source/server/config/http/buffer.cc b/source/server/config/http/buffer.cc index 9c777e46f40d..d5ced667dd44 100644 --- a/source/server/config/http/buffer.cc +++ b/source/server/config/http/buffer.cc @@ -11,13 +11,13 @@ namespace Envoy { namespace Server { namespace Configuration { -HttpFilterFactoryCb BufferFilterConfig::tryCreateFilterFactory(HttpFilterType type, - const std::string& name, - const Json::Object& json_config, - const std::string& stats_prefix, - Server::Instance& server) { - if (type != HttpFilterType::Decoder || name != "buffer") { - return nullptr; +HttpFilterFactoryCb BufferFilterConfig::createFilterFactory(HttpFilterType type, + const Json::Object& json_config, + const std::string& stats_prefix, + Server::Instance& server) { + if (type != HttpFilterType::Decoder) { + throw EnvoyException( + fmt::format("{} http filter must be configured as a decoder filter.", name())); } json_config.validateSchema(Json::Schema::BUFFER_HTTP_FILTER_SCHEMA); @@ -32,10 +32,12 @@ HttpFilterFactoryCb BufferFilterConfig::tryCreateFilterFactory(HttpFilterType ty }; } +std::string BufferFilterConfig::name() { return "buffer"; } + /** - * Static registration for the buffer filter. @see RegisterHttpFilterConfigFactory. + * Static registration for the buffer filter. @see RegisterNamedHttpFilterConfigFactory. */ -static RegisterHttpFilterConfigFactory register_; +static RegisterNamedHttpFilterConfigFactory register_; } // Configuration } // Server diff --git a/source/server/config/http/buffer.h b/source/server/config/http/buffer.h index bbfa2ee2dc33..c72eb35a6f7d 100644 --- a/source/server/config/http/buffer.h +++ b/source/server/config/http/buffer.h @@ -11,14 +11,14 @@ namespace Server { namespace Configuration { /** - * Config registration for the buffer filter. @see HttpFilterConfigFactory. + * Config registration for the buffer filter. @see NamedHttpFilterConfigFactory. */ -class BufferFilterConfig : public HttpFilterConfigFactory { +class BufferFilterConfig : public NamedHttpFilterConfigFactory { public: - HttpFilterFactoryCb tryCreateFilterFactory(HttpFilterType type, const std::string& name, - const Json::Object& json_config, - const std::string& stats_prefix, - Server::Instance& server) override; + HttpFilterFactoryCb createFilterFactory(HttpFilterType type, const Json::Object& json_config, + const std::string& stats_prefix, + Server::Instance& server) override; + std::string name() override; }; } // Configuration diff --git a/source/server/config/http/dynamo.cc b/source/server/config/http/dynamo.cc index 843fffcf4bd9..1184e4de0795 100644 --- a/source/server/config/http/dynamo.cc +++ b/source/server/config/http/dynamo.cc @@ -8,13 +8,13 @@ namespace Envoy { namespace Server { namespace Configuration { -HttpFilterFactoryCb DynamoFilterConfig::tryCreateFilterFactory(HttpFilterType type, - const std::string& name, - const Json::Object&, - const std::string& stat_prefix, - Server::Instance& server) { - if (type != HttpFilterType::Both || name != "http_dynamo_filter") { - return nullptr; +HttpFilterFactoryCb DynamoFilterConfig::createFilterFactory(HttpFilterType type, + const Json::Object&, + const std::string& stat_prefix, + Server::Instance& server) { + if (type != HttpFilterType::Both) { + throw EnvoyException(fmt::format( + "{} http filter must be configured as both a decoder and encoder filter.", name())); } return [&server, stat_prefix](Http::FilterChainFactoryCallbacks& callbacks) -> void { @@ -23,10 +23,12 @@ HttpFilterFactoryCb DynamoFilterConfig::tryCreateFilterFactory(HttpFilterType ty }; } +std::string DynamoFilterConfig::name() { return "http_dynamo_filter"; } + /** - * Static registration for the http dynamodb filter. @see RegisterHttpFilterConfigFactory. + * Static registration for the http dynamodb filter. @see RegisterNamedHttpFilterConfigFactory. */ -static RegisterHttpFilterConfigFactory register_; +static RegisterNamedHttpFilterConfigFactory register_; } // Configuration } // Server diff --git a/source/server/config/http/dynamo.h b/source/server/config/http/dynamo.h index cfaa9f36360b..dae2852e217c 100644 --- a/source/server/config/http/dynamo.h +++ b/source/server/config/http/dynamo.h @@ -11,11 +11,12 @@ namespace Configuration { /** * Config registration for http dynamodb filter. */ -class DynamoFilterConfig : public HttpFilterConfigFactory { +class DynamoFilterConfig : public NamedHttpFilterConfigFactory { public: - HttpFilterFactoryCb tryCreateFilterFactory(HttpFilterType type, const std::string& name, - const Json::Object&, const std::string& stat_prefix, - Server::Instance& server) override; + HttpFilterFactoryCb createFilterFactory(HttpFilterType type, const Json::Object&, + const std::string& stat_prefix, + Server::Instance& server) override; + std::string name() override; }; } // Configuration diff --git a/source/server/config/http/fault.cc b/source/server/config/http/fault.cc index 69c7402faf29..d4002d54bbd5 100644 --- a/source/server/config/http/fault.cc +++ b/source/server/config/http/fault.cc @@ -9,13 +9,13 @@ namespace Envoy { namespace Server { namespace Configuration { -HttpFilterFactoryCb FaultFilterConfig::tryCreateFilterFactory(HttpFilterType type, - const std::string& name, - const Json::Object& json_config, - const std::string& stats_prefix, - Server::Instance& server) { - if (type != HttpFilterType::Decoder || name != "fault") { - return nullptr; +HttpFilterFactoryCb FaultFilterConfig::createFilterFactory(HttpFilterType type, + const Json::Object& json_config, + const std::string& stats_prefix, + Server::Instance& server) { + if (type != HttpFilterType::Decoder) { + throw EnvoyException( + fmt::format("{} http filter must be configured as a decoder filter.", name())); } Http::FaultFilterConfigSharedPtr config( @@ -26,10 +26,12 @@ HttpFilterFactoryCb FaultFilterConfig::tryCreateFilterFactory(HttpFilterType typ }; } +std::string FaultFilterConfig::name() { return "fault"; } + /** - * Static registration for the fault filter. @see RegisterHttpFilterConfigFactory. + * Static registration for the fault filter. @see RegisterNamedHttpFilterConfigFactory. */ -static RegisterHttpFilterConfigFactory register_; +static RegisterNamedHttpFilterConfigFactory register_; } // Configuration } // Server diff --git a/source/server/config/http/fault.h b/source/server/config/http/fault.h index 530e13aafd88..dfe810f9867d 100644 --- a/source/server/config/http/fault.h +++ b/source/server/config/http/fault.h @@ -11,14 +11,14 @@ namespace Server { namespace Configuration { /** - * Config registration for the fault injection filter. @see HttpFilterConfigFactory. + * Config registration for the fault injection filter. @see NamedHttpFilterConfigFactory. */ -class FaultFilterConfig : public HttpFilterConfigFactory { +class FaultFilterConfig : public NamedHttpFilterConfigFactory { public: - HttpFilterFactoryCb tryCreateFilterFactory(HttpFilterType type, const std::string& name, - const Json::Object& json_config, - const std::string& stats_prefix, - Server::Instance& server) override; + HttpFilterFactoryCb createFilterFactory(HttpFilterType type, const Json::Object& json_config, + const std::string& stats_prefix, + Server::Instance& server) override; + std::string name() override; }; } // Configuration diff --git a/source/server/config/http/grpc_http1_bridge.cc b/source/server/config/http/grpc_http1_bridge.cc index 079c4f79c836..5eac2197dbbc 100644 --- a/source/server/config/http/grpc_http1_bridge.cc +++ b/source/server/config/http/grpc_http1_bridge.cc @@ -8,13 +8,13 @@ namespace Envoy { namespace Server { namespace Configuration { -HttpFilterFactoryCb GrpcHttp1BridgeFilterConfig::tryCreateFilterFactory(HttpFilterType type, - const std::string& name, - const Json::Object&, - const std::string&, - Server::Instance& server) { - if (type != HttpFilterType::Both || name != "grpc_http1_bridge") { - return nullptr; +HttpFilterFactoryCb GrpcHttp1BridgeFilterConfig::createFilterFactory(HttpFilterType type, + const Json::Object&, + const std::string&, + Server::Instance& server) { + if (type != HttpFilterType::Both) { + throw EnvoyException(fmt::format( + "{} http filter must be configured as both a decoder and encoder filter.", name())); } return [&server](Http::FilterChainFactoryCallbacks& callbacks) -> void { @@ -23,10 +23,12 @@ HttpFilterFactoryCb GrpcHttp1BridgeFilterConfig::tryCreateFilterFactory(HttpFilt }; } +std::string GrpcHttp1BridgeFilterConfig::name() { return "grpc_http1_bridge"; } + /** - * Static registration for the grpc HTTP1 bridge filter. @see RegisterHttpFilterConfigFactory. + * Static registration for the grpc HTTP1 bridge filter. @see RegisterNamedHttpFilterConfigFactory. */ -static RegisterHttpFilterConfigFactory register_; +static RegisterNamedHttpFilterConfigFactory register_; } // Configuration } // Server diff --git a/source/server/config/http/grpc_http1_bridge.h b/source/server/config/http/grpc_http1_bridge.h index fef25d1e57b1..8d7aa767592c 100644 --- a/source/server/config/http/grpc_http1_bridge.h +++ b/source/server/config/http/grpc_http1_bridge.h @@ -11,13 +11,13 @@ namespace Server { namespace Configuration { /** - * Config registration for the grpc HTTP1 bridge filter. @see HttpFilterConfigFactory. + * Config registration for the grpc HTTP1 bridge filter. @see NamedHttpFilterConfigFactory. */ -class GrpcHttp1BridgeFilterConfig : public HttpFilterConfigFactory { +class GrpcHttp1BridgeFilterConfig : public NamedHttpFilterConfigFactory { public: - HttpFilterFactoryCb tryCreateFilterFactory(HttpFilterType type, const std::string& name, - const Json::Object&, const std::string&, - Server::Instance& server) override; + HttpFilterFactoryCb createFilterFactory(HttpFilterType type, const Json::Object&, + const std::string&, Server::Instance& server) override; + std::string name() override; }; } // Configuration diff --git a/source/server/config/http/lightstep_http_tracer.cc b/source/server/config/http/lightstep_http_tracer.cc new file mode 100644 index 000000000000..980bdeaa2056 --- /dev/null +++ b/source/server/config/http/lightstep_http_tracer.cc @@ -0,0 +1,46 @@ +#include "server/config/http/lightstep_http_tracer.h" + +#include + +#include "common/common/utility.h" +#include "common/tracing/http_tracer_impl.h" +#include "common/tracing/lightstep_tracer_impl.h" + +#include "lightstep/options.h" +#include "lightstep/tracer.h" + +namespace Envoy { +namespace Server { +namespace Configuration { + +Tracing::HttpTracerPtr +LightstepHttpTracerFactory::createHttpTracer(const Json::Object& json_config, + Server::Instance& server, + Upstream::ClusterManager& cluster_manager) { + + Envoy::Runtime::RandomGenerator& rand = server.random(); + + std::unique_ptr opts(new lightstep::TracerOptions()); + opts->access_token = server.api().fileReadToEnd(json_config.getString("access_token_file")); + StringUtil::rtrim(opts->access_token); + + opts->tracer_attributes["lightstep.component_name"] = server.localInfo().clusterName(); + opts->guid_generator = [&rand]() { return rand.random(); }; + + Tracing::DriverPtr lightstep_driver( + new Tracing::LightStepDriver(json_config, cluster_manager, server.stats(), + server.threadLocal(), server.runtime(), std::move(opts))); + return Tracing::HttpTracerPtr( + new Tracing::HttpTracerImpl(std::move(lightstep_driver), server.localInfo())); +} + +std::string LightstepHttpTracerFactory::name() { return "lightstep"; } + +/** + * Static registration for the lightstep http tracer. @see RegisterHttpTracerFactory. + */ +static RegisterHttpTracerFactory register_; + +} // Configuration +} // Server +} // Envoy diff --git a/source/server/config/http/lightstep_http_tracer.h b/source/server/config/http/lightstep_http_tracer.h new file mode 100644 index 000000000000..721ea7458025 --- /dev/null +++ b/source/server/config/http/lightstep_http_tracer.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +#include "envoy/server/instance.h" + +#include "server/configuration_impl.h" + +namespace Envoy { +namespace Server { +namespace Configuration { + +/** + * Config registration for the lightstep tracer. @see HttpTracerFactory. + */ +class LightstepHttpTracerFactory : public HttpTracerFactory { +public: + // HttpTracerFactory + Tracing::HttpTracerPtr createHttpTracer(const Json::Object& json_config, Server::Instance& server, + Upstream::ClusterManager& cluster_manager) override; + + std::string name() override; +}; + +} // Configuration +} // Server +} // Envoy diff --git a/source/server/config/http/ratelimit.cc b/source/server/config/http/ratelimit.cc index f2b5ad9541ba..a08dab171e80 100644 --- a/source/server/config/http/ratelimit.cc +++ b/source/server/config/http/ratelimit.cc @@ -9,13 +9,13 @@ namespace Envoy { namespace Server { namespace Configuration { -HttpFilterFactoryCb RateLimitFilterConfig::tryCreateFilterFactory(HttpFilterType type, - const std::string& name, - const Json::Object& config, - const std::string&, - Server::Instance& server) { - if (type != HttpFilterType::Decoder || name != "rate_limit") { - return nullptr; +HttpFilterFactoryCb RateLimitFilterConfig::createFilterFactory(HttpFilterType type, + const Json::Object& config, + const std::string&, + Server::Instance& server) { + if (type != HttpFilterType::Decoder) { + throw EnvoyException( + fmt::format("{} http filter must be configured as a decoder filter.", name())); } Http::RateLimit::FilterConfigSharedPtr filter_config(new Http::RateLimit::FilterConfig( @@ -26,10 +26,12 @@ HttpFilterFactoryCb RateLimitFilterConfig::tryCreateFilterFactory(HttpFilterType }; } +std::string RateLimitFilterConfig::name() { return "rate_limit"; } + /** - * Static registration for the rate limit filter. @see RegisterHttpFilterConfigFactory. + * Static registration for the rate limit filter. @see RegisterNamedHttpFilterConfigFactory. */ -static RegisterHttpFilterConfigFactory register_; +static RegisterNamedHttpFilterConfigFactory register_; } // Configuration } // Server diff --git a/source/server/config/http/ratelimit.h b/source/server/config/http/ratelimit.h index 8988e0d82ef7..b26faee251e6 100644 --- a/source/server/config/http/ratelimit.h +++ b/source/server/config/http/ratelimit.h @@ -11,13 +11,13 @@ namespace Server { namespace Configuration { /** - * Config registration for the rate limit filter. @see HttpFilterConfigFactory. + * Config registration for the rate limit filter. @see NamedHttpFilterConfigFactory. */ -class RateLimitFilterConfig : public HttpFilterConfigFactory { +class RateLimitFilterConfig : public NamedHttpFilterConfigFactory { public: - HttpFilterFactoryCb tryCreateFilterFactory(HttpFilterType type, const std::string& name, - const Json::Object& config, const std::string&, - Server::Instance& server) override; + HttpFilterFactoryCb createFilterFactory(HttpFilterType type, const Json::Object& config, + const std::string&, Server::Instance& server) override; + std::string name() override; }; } // Configuration diff --git a/source/server/config/http/router.cc b/source/server/config/http/router.cc index 8e7b8332524f..eea5977f1c40 100644 --- a/source/server/config/http/router.cc +++ b/source/server/config/http/router.cc @@ -10,13 +10,13 @@ namespace Envoy { namespace Server { namespace Configuration { -HttpFilterFactoryCb RouterFilterConfig::tryCreateFilterFactory(HttpFilterType type, - const std::string& name, - const Json::Object& json_config, - const std::string& stat_prefix, - Server::Instance& server) { - if (type != HttpFilterType::Decoder || name != "router") { - return nullptr; +HttpFilterFactoryCb RouterFilterConfig::createFilterFactory(HttpFilterType type, + const Json::Object& json_config, + const std::string& stat_prefix, + Server::Instance& server) { + if (type != HttpFilterType::Decoder) { + throw EnvoyException( + fmt::format("{} http filter must be configured as a decoder filter.", name())); } json_config.validateSchema(Json::Schema::ROUTER_HTTP_FILTER_SCHEMA); @@ -31,10 +31,12 @@ HttpFilterFactoryCb RouterFilterConfig::tryCreateFilterFactory(HttpFilterType ty -> void { callbacks.addStreamDecoderFilter(std::make_shared(*config)); }; } +std::string RouterFilterConfig::name() { return "router"; } + /** - * Static registration for the router filter. @see RegisterHttpFilterConfigFactory. + * Static registration for the router filter. @see RegisterNamedHttpFilterConfigFactory. */ -static RegisterHttpFilterConfigFactory register_; +static RegisterNamedHttpFilterConfigFactory register_; } // Configuration } // Server diff --git a/source/server/config/http/router.h b/source/server/config/http/router.h index b8136c6f8234..41434beacb74 100644 --- a/source/server/config/http/router.h +++ b/source/server/config/http/router.h @@ -11,14 +11,14 @@ namespace Server { namespace Configuration { /** - * Config registration for the router filter. @see HttpFilterConfigFactory. + * Config registration for the router filter. @see NamedHttpFilterConfigFactory. */ -class RouterFilterConfig : public HttpFilterConfigFactory { +class RouterFilterConfig : public NamedHttpFilterConfigFactory { public: - HttpFilterFactoryCb tryCreateFilterFactory(HttpFilterType type, const std::string& name, - const Json::Object& json_config, - const std::string& stat_prefix, - Server::Instance& server) override; + HttpFilterFactoryCb createFilterFactory(HttpFilterType type, const Json::Object& json_config, + const std::string& stat_prefix, + Server::Instance& server) override; + std::string name() override; }; } // Configuration diff --git a/source/server/config/http/zipkin_http_tracer.cc b/source/server/config/http/zipkin_http_tracer.cc new file mode 100644 index 000000000000..ae002740aaae --- /dev/null +++ b/source/server/config/http/zipkin_http_tracer.cc @@ -0,0 +1,36 @@ +#include "server/config/http/zipkin_http_tracer.h" + +#include + +#include "common/common/utility.h" +#include "common/tracing/http_tracer_impl.h" +#include "common/tracing/zipkin/zipkin_tracer_impl.h" + +namespace Envoy { +namespace Server { +namespace Configuration { + +Tracing::HttpTracerPtr +ZipkinHttpTracerFactory::createHttpTracer(const Json::Object& json_config, Server::Instance& server, + Upstream::ClusterManager& cluster_manager) { + + Envoy::Runtime::RandomGenerator& rand = server.random(); + + Tracing::DriverPtr zipkin_driver(new Zipkin::Driver(json_config, cluster_manager, server.stats(), + server.threadLocal(), server.runtime(), + server.localInfo(), rand)); + + return Tracing::HttpTracerPtr( + new Tracing::HttpTracerImpl(std::move(zipkin_driver), server.localInfo())); +} + +std::string ZipkinHttpTracerFactory::name() { return "zipkin"; } + +/** + * Static registration for the lightstep http tracer. @see RegisterHttpTracerFactory. + */ +static RegisterHttpTracerFactory register_; + +} // Configuration +} // Server +} // Envoy diff --git a/source/server/config/http/zipkin_http_tracer.h b/source/server/config/http/zipkin_http_tracer.h new file mode 100644 index 000000000000..fc464f6c99f0 --- /dev/null +++ b/source/server/config/http/zipkin_http_tracer.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +#include "envoy/server/instance.h" + +#include "server/configuration_impl.h" + +namespace Envoy { +namespace Server { +namespace Configuration { + +/** + * Config registration for the zipkin http tracer. @see HttpTracerFactory. + */ +class ZipkinHttpTracerFactory : public HttpTracerFactory { +public: + // HttpTracerFactory + Tracing::HttpTracerPtr createHttpTracer(const Json::Object& json_config, Server::Instance& server, + Upstream::ClusterManager& cluster_manager) override; + std::string name() override; +}; + +} // Configuration +} // Server +} // Envoy \ No newline at end of file diff --git a/source/server/config/network/client_ssl_auth.cc b/source/server/config/network/client_ssl_auth.cc index 7ead762cdbc6..6362648ba28e 100644 --- a/source/server/config/network/client_ssl_auth.cc +++ b/source/server/config/network/client_ssl_auth.cc @@ -11,12 +11,11 @@ namespace Envoy { namespace Server { namespace Configuration { -NetworkFilterFactoryCb -ClientSslAuthConfigFactory::tryCreateFilterFactory(NetworkFilterType type, const std::string& name, - const Json::Object& json_config, - Server::Instance& server) { - if (type != NetworkFilterType::Read || name != "client_ssl_auth") { - return nullptr; +NetworkFilterFactoryCb ClientSslAuthConfigFactory::createFilterFactory( + NetworkFilterType type, const Json::Object& json_config, Server::Instance& server) { + if (type != NetworkFilterType::Read) { + throw EnvoyException( + fmt::format("{} network filter must be configured as a read filter.", name())); } Filter::Auth::ClientSsl::ConfigSharedPtr config(Filter::Auth::ClientSsl::Config::create( @@ -28,10 +27,12 @@ ClientSslAuthConfigFactory::tryCreateFilterFactory(NetworkFilterType type, const }; } +std::string ClientSslAuthConfigFactory::name() { return "client_ssl_auth"; } + /** - * Static registration for the client SSL auth filter. @see RegisterNetworkFilterConfigFactory. + * Static registration for the client SSL auth filter. @see RegisterNamedNetworkFilterConfigFactory. */ -static RegisterNetworkFilterConfigFactory registered_; +static RegisterNamedNetworkFilterConfigFactory registered_; } // Configuration } // Server diff --git a/source/server/config/network/client_ssl_auth.h b/source/server/config/network/client_ssl_auth.h index 56bb6ecf9696..5818d4b1e870 100644 --- a/source/server/config/network/client_ssl_auth.h +++ b/source/server/config/network/client_ssl_auth.h @@ -9,14 +9,15 @@ namespace Server { namespace Configuration { /** - * Config registration for the client SSL auth filter. @see NetworkFilterConfigFactory. + * Config registration for the client SSL auth filter. @see NamedNetworkFilterConfigFactory. */ -class ClientSslAuthConfigFactory : public NetworkFilterConfigFactory { +class ClientSslAuthConfigFactory : public NamedNetworkFilterConfigFactory { public: - // NetworkFilterConfigFactory - NetworkFilterFactoryCb tryCreateFilterFactory(NetworkFilterType type, const std::string& name, - const Json::Object& json_config, - Server::Instance& server); + // NamedNetworkFilterConfigFactory + NetworkFilterFactoryCb createFilterFactory(NetworkFilterType type, + const Json::Object& json_config, + Server::Instance& server) override; + std::string name() override; }; } // Configuration diff --git a/source/server/config/network/echo.cc b/source/server/config/network/echo.cc index 63e14de6f9e5..136d0202e742 100644 --- a/source/server/config/network/echo.cc +++ b/source/server/config/network/echo.cc @@ -11,26 +11,29 @@ namespace Server { namespace Configuration { /** - * Config registration for the echo filter. @see NetworkFilterConfigFactory. + * Config registration for the echo filter. @see NamedNetworkFilterConfigFactory. */ -class EchoConfigFactory : public NetworkFilterConfigFactory { +class EchoConfigFactory : public NamedNetworkFilterConfigFactory { public: - // NetworkFilterConfigFactory - NetworkFilterFactoryCb tryCreateFilterFactory(NetworkFilterType type, const std::string& name, - const Json::Object&, Server::Instance&) { - if (type != NetworkFilterType::Read || name != "echo") { - return nullptr; + // NamedNetworkFilterConfigFactory + NetworkFilterFactoryCb createFilterFactory(NetworkFilterType type, const Json::Object&, + Server::Instance&) override { + if (type != NetworkFilterType::Read) { + throw EnvoyException( + fmt::format("{} network filter must be configured as a read filter.", name())); } return [](Network::FilterManager& filter_manager) -> void { filter_manager.addReadFilter(Network::ReadFilterSharedPtr{new Filter::Echo()}); }; } + + std::string name() override { return "echo"; } }; /** - * Static registration for the echo filter. @see RegisterNetworkFilterConfigFactory. + * Static registration for the echo filter. @see RegisterNamedNetworkFilterConfigFactory. */ -static RegisterNetworkFilterConfigFactory registered_; +static RegisterNamedNetworkFilterConfigFactory registered_; } // Configuration } // Server diff --git a/source/server/config/network/http_connection_manager.cc b/source/server/config/network/http_connection_manager.cc index 252b41b94571..a78ee2c82a7c 100644 --- a/source/server/config/network/http_connection_manager.cc +++ b/source/server/config/network/http_connection_manager.cc @@ -26,11 +26,11 @@ namespace Configuration { const std::string HttpConnectionManagerConfig::DEFAULT_SERVER_STRING = "envoy"; -NetworkFilterFactoryCb HttpConnectionManagerFilterConfigFactory::tryCreateFilterFactory( - NetworkFilterType type, const std::string& name, const Json::Object& config, - Server::Instance& server) { - if (type != NetworkFilterType::Read || name != "http_connection_manager") { - return nullptr; +NetworkFilterFactoryCb HttpConnectionManagerFilterConfigFactory::createFilterFactory( + NetworkFilterType type, const Json::Object& config, Server::Instance& server) { + if (type != NetworkFilterType::Read) { + throw EnvoyException( + fmt::format("{} network filter must be configured as a read filter.", name())); } std::shared_ptr http_config( @@ -42,11 +42,14 @@ NetworkFilterFactoryCb HttpConnectionManagerFilterConfigFactory::tryCreateFilter }; } +std::string HttpConnectionManagerFilterConfigFactory::name() { return "http_connection_manager"; } + /** * Static registration for the HTTP connection manager filter. @see - * RegisterNetworkFilterConfigFactory. + * RegisterNamedNetworkFilterConfigFactory. */ -static RegisterNetworkFilterConfigFactory registered_; +static RegisterNamedNetworkFilterConfigFactory + registered_; std::string HttpConnectionManagerConfigUtility::determineNextProtocol(Network::Connection& connection, @@ -152,20 +155,31 @@ HttpConnectionManagerConfig::HttpConnectionManagerConfig(const Json::Object& con log().info(" name: {}", string_name); HttpFilterType type = stringToType(string_type); - bool found_filter = false; - for (HttpFilterConfigFactory* factory : filterConfigFactories()) { + + // Now see if there is a factory that will accept the config. + auto search_it = namedFilterConfigFactories().find(string_name); + if (search_it != namedFilterConfigFactories().end()) { HttpFilterFactoryCb callback = - factory->tryCreateFilterFactory(type, string_name, *config_object, stats_prefix_, server); - if (callback) { - filter_factories_.push_back(callback); - found_filter = true; - break; + search_it->second->createFilterFactory(type, *config_object, stats_prefix_, server); + filter_factories_.push_back(callback); + } else { + // DEPRECATED + // This name wasn't found in the named map, so search in the deprecated list registry. + bool found_filter = false; + for (HttpFilterConfigFactory* config_factory : filterConfigFactories()) { + HttpFilterFactoryCb callback = config_factory->tryCreateFilterFactory( + type, string_name, *config_object, stats_prefix_, server); + if (callback) { + filter_factories_.push_back(callback); + found_filter = true; + break; + } } - } - if (!found_filter) { - throw EnvoyException(fmt::format("unable to create http filter factory for '{}'/'{}'", - string_name, string_type)); + if (!found_filter) { + throw EnvoyException(fmt::format("unable to create http filter factory for '{}'/'{}'", + string_name, string_type)); + } } } } diff --git a/source/server/config/network/http_connection_manager.h b/source/server/config/network/http_connection_manager.h index b040329d4d21..304874056d26 100644 --- a/source/server/config/network/http_connection_manager.h +++ b/source/server/config/network/http_connection_manager.h @@ -24,15 +24,16 @@ namespace Configuration { enum class HttpFilterType { Decoder, Encoder, Both }; /** - * Config registration for the HTTP connection manager filter. @see NetworkFilterConfigFactory. + * Config registration for the HTTP connection manager filter. @see NamedNetworkFilterConfigFactory. */ class HttpConnectionManagerFilterConfigFactory : Logger::Loggable, - public NetworkFilterConfigFactory { + public NamedNetworkFilterConfigFactory { public: - // NetworkFilterConfigFactory - NetworkFilterFactoryCb tryCreateFilterFactory(NetworkFilterType type, const std::string& name, - const Json::Object& config, - Server::Instance& server); + // NamedNetworkFilterConfigFactory + NetworkFilterFactoryCb createFilterFactory(NetworkFilterType type, const Json::Object& config, + Server::Instance& server) override; + + std::string name() override; }; /** @@ -41,8 +42,8 @@ class HttpConnectionManagerFilterConfigFactory : Logger::Loggable HttpFilterFactoryCb; /** - * Implemented by each HTTP filter and registered via registerHttpFilterConfigFactory() or the - * convenience class RegisterHttpFilterConfigFactory. + * DEPRECATED - Implemented by each HTTP filter and registered via registerHttpFilterConfigFactory() + * or the convenience class RegisterHttpFilterConfigFactory. */ class HttpFilterConfigFactory { public: @@ -54,6 +55,35 @@ class HttpFilterConfigFactory { Server::Instance& server) PURE; }; +/** + * Implemented by each HTTP filter and registered via registerNamedHttpFilterConfigFactory() or the + * convenience class RegisterNamedHttpFilterConfigFactory. + */ +class NamedHttpFilterConfigFactory { +public: + virtual ~NamedHttpFilterConfigFactory() {} + + /** + * Create a particular http filter factory implementation. If the implementation is unable to + * produce a factory with the provided parameters, it should throw an EnvoyException in the case of + * general error or a Json::Exception if the json configuration is erroneous. The returned + * callback should always be initialized. + * @param type supplies type of filter to initialize (decoder, encoder, or both) + * @param config supplies the general json configuration for the filter + * @param stat_prefix prefix for stat logging + * @param server supplies the server instance + */ + virtual HttpFilterFactoryCb createFilterFactory(HttpFilterType type, const Json::Object& config, + const std::string& stat_prefix, + Server::Instance& server) PURE; + + /** + * Returns the identifying name for a particular implementation of an http filter produced by the + * factory. + */ + virtual std::string name() PURE; +}; + /** * Utilities for the HTTP connection manager that facilitate testing. */ @@ -104,18 +134,56 @@ class HttpConnectionManagerConfig : Logger::Loggable, const Network::Address::Instance& localAddress() override; const Optional& userAgent() override { return user_agent_; } + /** + * DEPRECATED - Register an HttpFilterConfigFactory implementation as an option to create + * instances of HttpFilterFactoryCb. + * @param factory the HttpFilterConfigFactory implementation + */ static void registerHttpFilterConfigFactory(HttpFilterConfigFactory& factory) { filterConfigFactories().push_back(&factory); } + /** + * Register a NamedHttpFilterConfigFactory implementation as an option to create instances of + * HttpFilterFactoryCb. + * @param factory the NamedHttpFilterConfigFactory implementation + */ + static void registerNamedHttpFilterConfigFactory(NamedHttpFilterConfigFactory& factory) { + auto result = namedFilterConfigFactories().emplace(std::make_pair(factory.name(), &factory)); + + // result is a pair whose second member is a boolean indicating, if false, that the key exists + // and that the value was not inserted. + if (!result.second) { + throw EnvoyException(fmt::format( + "Attempted to register multiple NamedHttpFilterConfigFactory objects with name: '{}'", + factory.name())); + } + } + static const std::string DEFAULT_SERVER_STRING; private: enum class CodecType { HTTP1, HTTP2, AUTO }; + /** + * DEPRECATED - Returns a list of the currently registered HttpFilterConfigFactory + * implementations. + */ static std::list& filterConfigFactories() { - static std::list filter_config_factories; - return filter_config_factories; + static std::list* filter_config_factories = + new std::list; + return *filter_config_factories; + } + + /** + * Returns a map of the currently registered NamedHttpFilterConfigFactory implementations. + */ + static std::unordered_map& + namedFilterConfigFactories() { + static std::unordered_map* + named_filter_config_factories = + new std::unordered_map; + return *named_filter_config_factories; } HttpFilterType stringToType(const std::string& type); @@ -140,13 +208,34 @@ class HttpConnectionManagerConfig : Logger::Loggable, }; /** - * @see HttpFilterConfigFactory. + * @see NamedHttpFilterConfigFactory. An instantiation of this class registers a + * NamedHttpFilterConfigFactory implementation (T) so it can be used to create instances of + * HttpFilterFactoryCb. + */ +template class RegisterNamedHttpFilterConfigFactory { +public: + /** + * Registers the implementation. + */ + RegisterNamedHttpFilterConfigFactory() { + static T* instance = new T; + HttpConnectionManagerConfig::registerNamedHttpFilterConfigFactory(*instance); + } +}; + +/** + * DEPRECATED @see HttpFilterConfigFactory. An instantiation of this class registers a + * HttpFilterConfigFactory implementation (T) so it can be used to create instances of + * HttpFilterFactoryCb. */ template class RegisterHttpFilterConfigFactory { public: + /** + * Registers the implementation. + */ RegisterHttpFilterConfigFactory() { - static T instance; - HttpConnectionManagerConfig::registerHttpFilterConfigFactory(instance); + static T* instance = new T; + HttpConnectionManagerConfig::registerHttpFilterConfigFactory(*instance); } }; diff --git a/source/server/config/network/mongo_proxy.cc b/source/server/config/network/mongo_proxy.cc index db8462252c03..9a05b496b31a 100644 --- a/source/server/config/network/mongo_proxy.cc +++ b/source/server/config/network/mongo_proxy.cc @@ -12,11 +12,11 @@ namespace Envoy { namespace Server { namespace Configuration { -NetworkFilterFactoryCb MongoProxyFilterConfigFactory::tryCreateFilterFactory( - NetworkFilterType type, const std::string& name, const Json::Object& config, - Server::Instance& server) { - if (type != NetworkFilterType::Both || name != "mongo_proxy") { - return nullptr; +NetworkFilterFactoryCb MongoProxyFilterConfigFactory::createFilterFactory( + NetworkFilterType type, const Json::Object& config, Server::Instance& server) { + if (type != NetworkFilterType::Both) { + throw EnvoyException(fmt::format( + "{} network filter must be configured as both a read and write filter.", name())); } config.validateSchema(Json::Schema::MONGO_PROXY_NETWORK_FILTER_SCHEMA); @@ -34,10 +34,12 @@ NetworkFilterFactoryCb MongoProxyFilterConfigFactory::tryCreateFilterFactory( }; } +std::string MongoProxyFilterConfigFactory::name() { return "mongo_proxy"; } + /** - * Static registration for the mongo filter. @see RegisterNetworkFilterConfigFactory. + * Static registration for the mongo filter. @see RegisterNamedNetworkFilterConfigFactory. */ -static RegisterNetworkFilterConfigFactory registered_; +static RegisterNamedNetworkFilterConfigFactory registered_; } // Configuration } // Server diff --git a/source/server/config/network/mongo_proxy.h b/source/server/config/network/mongo_proxy.h index 678ad40e2a82..901b0297c28c 100644 --- a/source/server/config/network/mongo_proxy.h +++ b/source/server/config/network/mongo_proxy.h @@ -9,14 +9,15 @@ namespace Server { namespace Configuration { /** - * Config registration for the mongo proxy filter. @see NetworkFilterConfigFactory. + * Config registration for the mongo proxy filter. @see NamedNetworkFilterConfigFactory. */ -class MongoProxyFilterConfigFactory : public NetworkFilterConfigFactory { +class MongoProxyFilterConfigFactory : public NamedNetworkFilterConfigFactory { public: - // NetworkFilterConfigFactory - NetworkFilterFactoryCb tryCreateFilterFactory(NetworkFilterType type, const std::string& name, - const Json::Object& config, - Server::Instance& server); + // NamedNetworkFilterConfigFactory + NetworkFilterFactoryCb createFilterFactory(NetworkFilterType type, const Json::Object& config, + Server::Instance& server) override; + + std::string name() override; }; } // Configuration diff --git a/source/server/config/network/ratelimit.cc b/source/server/config/network/ratelimit.cc index 0f46b20cedde..23c7a781afee 100644 --- a/source/server/config/network/ratelimit.cc +++ b/source/server/config/network/ratelimit.cc @@ -11,12 +11,12 @@ namespace Envoy { namespace Server { namespace Configuration { -NetworkFilterFactoryCb -RateLimitConfigFactory::tryCreateFilterFactory(NetworkFilterType type, const std::string& name, - const Json::Object& json_config, - Server::Instance& server) { - if (type != NetworkFilterType::Read || name != "ratelimit") { - return nullptr; +NetworkFilterFactoryCb RateLimitConfigFactory::createFilterFactory(NetworkFilterType type, + const Json::Object& json_config, + Server::Instance& server) { + if (type != NetworkFilterType::Read) { + throw EnvoyException( + fmt::format("{} network filter must be configured as a read filter.", name())); } RateLimit::TcpFilter::ConfigSharedPtr config( @@ -27,10 +27,12 @@ RateLimitConfigFactory::tryCreateFilterFactory(NetworkFilterType type, const std }; } +std::string RateLimitConfigFactory::name() { return "ratelimit"; } + /** - * Static registration for the rate limit filter. @see RegisterNetworkFilterConfigFactory. + * Static registration for the rate limit filter. @see RegisterNamedNetworkFilterConfigFactory. */ -static RegisterNetworkFilterConfigFactory registered_; +static RegisterNamedNetworkFilterConfigFactory registered_; } // Configuration } // Server diff --git a/source/server/config/network/ratelimit.h b/source/server/config/network/ratelimit.h index 972b4f346edb..d6bb11672c3a 100644 --- a/source/server/config/network/ratelimit.h +++ b/source/server/config/network/ratelimit.h @@ -9,14 +9,16 @@ namespace Server { namespace Configuration { /** - * Config registration for the rate limit filter. @see NetworkFilterConfigFactory. + * Config registration for the rate limit filter. @see NamedNetworkFilterConfigFactory. */ -class RateLimitConfigFactory : public NetworkFilterConfigFactory { +class RateLimitConfigFactory : public NamedNetworkFilterConfigFactory { public: - // NetworkFilterConfigFactory - NetworkFilterFactoryCb tryCreateFilterFactory(NetworkFilterType type, const std::string& name, - const Json::Object& json_config, - Server::Instance& server); + // NamedNetworkFilterConfigFactory + NetworkFilterFactoryCb createFilterFactory(NetworkFilterType type, + const Json::Object& json_config, + Server::Instance& server) override; + + std::string name() override; }; } // Configuration diff --git a/source/server/config/network/redis_proxy.cc b/source/server/config/network/redis_proxy.cc index c614298318bb..c950d8b71b97 100644 --- a/source/server/config/network/redis_proxy.cc +++ b/source/server/config/network/redis_proxy.cc @@ -12,11 +12,11 @@ namespace Envoy { namespace Server { namespace Configuration { -NetworkFilterFactoryCb RedisProxyFilterConfigFactory::tryCreateFilterFactory( - NetworkFilterType type, const std::string& name, const Json::Object& config, - Server::Instance& server) { - if (type != NetworkFilterType::Read || name != "redis_proxy") { - return nullptr; +NetworkFilterFactoryCb RedisProxyFilterConfigFactory::createFilterFactory( + NetworkFilterType type, const Json::Object& config, Server::Instance& server) { + if (type != NetworkFilterType::Read) { + throw EnvoyException( + fmt::format("{} network filter must be configured as a read filter.", name())); } Redis::ProxyFilterConfigSharedPtr filter_config( @@ -35,10 +35,12 @@ NetworkFilterFactoryCb RedisProxyFilterConfigFactory::tryCreateFilterFactory( }; } +std::string RedisProxyFilterConfigFactory::name() { return "redis_proxy"; } + /** - * Static registration for the redis filter. @see RegisterNetworkFilterConfigFactory. + * Static registration for the redis filter. @see RegisterNamedNetworkFilterConfigFactory. */ -static RegisterNetworkFilterConfigFactory registered_; +static RegisterNamedNetworkFilterConfigFactory registered_; } // Configuration } // Server diff --git a/source/server/config/network/redis_proxy.h b/source/server/config/network/redis_proxy.h index 058da13ec6ad..a162a2a26633 100644 --- a/source/server/config/network/redis_proxy.h +++ b/source/server/config/network/redis_proxy.h @@ -9,14 +9,14 @@ namespace Server { namespace Configuration { /** - * Config registration for the redis proxy filter. @see NetworkFilterConfigFactory. + * Config registration for the redis proxy filter. @see NamedNetworkFilterConfigFactory. */ -class RedisProxyFilterConfigFactory : public NetworkFilterConfigFactory { +class RedisProxyFilterConfigFactory : public NamedNetworkFilterConfigFactory { public: - // NetworkFilterConfigFactory - NetworkFilterFactoryCb tryCreateFilterFactory(NetworkFilterType type, const std::string& name, - const Json::Object& config, - Server::Instance& server); + // NamedNetworkFilterConfigFactory + NetworkFilterFactoryCb createFilterFactory(NetworkFilterType type, const Json::Object& config, + Server::Instance& server) override; + std::string name() override; }; } // Configuration diff --git a/source/server/config/network/tcp_proxy.cc b/source/server/config/network/tcp_proxy.cc index f1f4afad0513..7365a3de727e 100644 --- a/source/server/config/network/tcp_proxy.cc +++ b/source/server/config/network/tcp_proxy.cc @@ -11,12 +11,12 @@ namespace Envoy { namespace Server { namespace Configuration { -NetworkFilterFactoryCb TcpProxyConfigFactory::tryCreateFilterFactory(NetworkFilterType type, - const std::string& name, - const Json::Object& config, - Server::Instance& server) { - if (type != NetworkFilterType::Read || name != "tcp_proxy") { - return nullptr; +NetworkFilterFactoryCb TcpProxyConfigFactory::createFilterFactory(NetworkFilterType type, + const Json::Object& config, + Server::Instance& server) { + if (type != NetworkFilterType::Read) { + throw EnvoyException( + fmt::format("{} network filter must be configured as a read filter.", name())); } Filter::TcpProxyConfigSharedPtr filter_config( @@ -27,10 +27,12 @@ NetworkFilterFactoryCb TcpProxyConfigFactory::tryCreateFilterFactory(NetworkFilt }; } +std::string TcpProxyConfigFactory::name() { return "tcp_proxy"; } + /** - * Static registration for the tcp_proxy filter. @see RegisterNetworkFilterConfigFactory. + * Static registration for the tcp_proxy filter. @see RegisterNamedNetworkFilterConfigFactory. */ -static RegisterNetworkFilterConfigFactory registered_; +static RegisterNamedNetworkFilterConfigFactory registered_; } // Configuration } // Server diff --git a/source/server/config/network/tcp_proxy.h b/source/server/config/network/tcp_proxy.h index 94a817a517c4..6ce37826ba85 100644 --- a/source/server/config/network/tcp_proxy.h +++ b/source/server/config/network/tcp_proxy.h @@ -9,14 +9,14 @@ namespace Server { namespace Configuration { /** - * Config registration for the tcp proxy filter. @see NetworkFilterConfigFactory. + * Config registration for the tcp proxy filter. @see NamedNetworkFilterConfigFactory. */ -class TcpProxyConfigFactory : public NetworkFilterConfigFactory { +class TcpProxyConfigFactory : public NamedNetworkFilterConfigFactory { public: - // NetworkFilterConfigFactory - NetworkFilterFactoryCb tryCreateFilterFactory(NetworkFilterType type, const std::string& name, - const Json::Object& config, - Server::Instance& server); + // NamedNetworkFilterConfigFactory + NetworkFilterFactoryCb createFilterFactory(NetworkFilterType type, const Json::Object& config, + Server::Instance& server) override; + std::string name() override; }; } // Configuration diff --git a/source/server/configuration_impl.cc b/source/server/configuration_impl.cc index d98f8e605734..ecce1aa5424f 100644 --- a/source/server/configuration_impl.cc +++ b/source/server/configuration_impl.cc @@ -116,32 +116,14 @@ void MainImpl::initializeTracers(const Json::Object& configuration) { std::string type = driver->getString("type"); log().info(fmt::format(" loading tracing driver: {}", type)); - Envoy::Runtime::RandomGenerator& rand = server_.random(); + Json::ObjectSharedPtr driver_config = driver->getObject("config"); - if (type == "lightstep") { - Json::ObjectSharedPtr lightstep_config = driver->getObject("config"); - - std::unique_ptr opts(new lightstep::TracerOptions()); - opts->access_token = - server_.api().fileReadToEnd(lightstep_config->getString("access_token_file")); - StringUtil::rtrim(opts->access_token); - - opts->tracer_attributes["lightstep.component_name"] = server_.localInfo().clusterName(); - opts->guid_generator = [&rand]() { return rand.random(); }; - - Tracing::DriverPtr lightstep_driver( - new Tracing::LightStepDriver(*lightstep_config, *cluster_manager_, server_.stats(), - server_.threadLocal(), server_.runtime(), std::move(opts))); - http_tracer_.reset( - new Tracing::HttpTracerImpl(std::move(lightstep_driver), server_.localInfo())); + // Now see if there is a factory that will accept the config. + auto search_it = httpTracerFactories().find(type); + if (search_it != httpTracerFactories().end()) { + http_tracer_ = search_it->second->createHttpTracer(*driver_config, server_, *cluster_manager_); } else { - ASSERT(type == "zipkin"); - - Tracing::DriverPtr zipkin_driver( - new Zipkin::Driver(*driver->getObject("config"), *cluster_manager_, server_.stats(), - server_.threadLocal(), server_.runtime(), server_.localInfo(), rand)); - - http_tracer_.reset(new Tracing::HttpTracerImpl(std::move(zipkin_driver), server_.localInfo())); + throw EnvoyException(fmt::format("No HttpTracerFactory found for type: {}", type)); } } @@ -193,20 +175,29 @@ MainImpl::ListenerConfig::ListenerConfig(MainImpl& parent, Json::Object& json) : } // Now see if there is a factory that will accept the config. - bool found_filter = false; - for (NetworkFilterConfigFactory* config_factory : filterConfigFactories()) { + auto search_it = namedFilterConfigFactories().find(string_name); + if (search_it != namedFilterConfigFactories().end()) { NetworkFilterFactoryCb callback = - config_factory->tryCreateFilterFactory(type, string_name, *config, parent_.server_); - if (callback) { - filter_factories_.push_back(callback); - found_filter = true; - break; + search_it->second->createFilterFactory(type, *config, parent_.server_); + filter_factories_.push_back(callback); + } else { + // DEPRECATED + // This name wasn't found in the named map, so search in the deprecated list registry. + bool found_filter = false; + for (NetworkFilterConfigFactory* config_factory : filterConfigFactories()) { + NetworkFilterFactoryCb callback = + config_factory->tryCreateFilterFactory(type, string_name, *config, parent_.server_); + if (callback) { + filter_factories_.push_back(callback); + found_filter = true; + break; + } } - } - if (!found_filter) { - throw EnvoyException( - fmt::format("unable to create filter factory for '{}'/'{}'", string_name, string_type)); + if (!found_filter) { + throw EnvoyException( + fmt::format("unable to create filter factory for '{}'/'{}'", string_name, string_type)); + } } } } diff --git a/source/server/configuration_impl.h b/source/server/configuration_impl.h index b339dda5f289..9ae0bf38444c 100644 --- a/source/server/configuration_impl.h +++ b/source/server/configuration_impl.h @@ -6,11 +6,14 @@ #include #include #include +#include +#include #include "envoy/http/filter.h" #include "envoy/network/filter.h" #include "envoy/server/configuration.h" #include "envoy/server/instance.h" +#include "envoy/tracing/http_tracer.h" #include "common/common/logger.h" #include "common/json/json_loader.h" @@ -30,8 +33,8 @@ enum class NetworkFilterType { Read, Write, Both }; typedef std::function NetworkFilterFactoryCb; /** - * Implemented by each network filter and registered via registerNetworkFilterConfigFactory() or - * the convenience class RegisterNetworkFilterConfigFactory. + * DEPRECATED - Implemented by each network filter and registered via + * registerNetworkFilterConfigFactory() or the convenience class RegisterNetworkFilterConfigFactory. */ class NetworkFilterConfigFactory { public: @@ -43,6 +46,62 @@ class NetworkFilterConfigFactory { Server::Instance& server) PURE; }; +/** + * Implemented by each network filter and registered via registerNamedNetworkFilterConfigFactory() + * or the convenience class RegisterNamedNetworkFilterConfigFactory. + */ +class NamedNetworkFilterConfigFactory { +public: + virtual ~NamedNetworkFilterConfigFactory() {} + + /** + * Create a particular network filter factory implementation. If the implementation is unable to + * produce a factory with the provided parameters, it should throw an EnvoyException in the case + * of general error or a Json::Exception if the json configuration is erroneous. The returned + * callback should always be initialized. + * @param type supplies type of filter to initialize (read, write, or both) + * @param config supplies the general json configuration for the filter + * @param server supplies the server instance + */ + virtual NetworkFilterFactoryCb createFilterFactory(NetworkFilterType type, + const Json::Object& config, + Server::Instance& server) PURE; + + /** + * Returns the identifying name for a particular implementation of a network filter produced by + * the factory. + */ + virtual std::string name() PURE; +}; + +/** + * Implemented by each HttpTracer and registered via registerHttpTracerFactory() or + * the convenience class RegisterHttpTracerFactory. + */ +class HttpTracerFactory { +public: + virtual ~HttpTracerFactory() {} + + /** + * Create a particular HttpTracer implementation. If the implementation is unable to produce an + * HttpTracer with the provided parameters, it should throw an EnvoyException in the case of + * general error or a Json::Exception if the json configuration is erroneous. The returned pointer + * should always be valid. + * @param json_config supplies the general json configuration for the HttpTracer + * @param server supplies the server instance + * @param cluster_manager supplies the cluster_manager instance + */ + virtual Tracing::HttpTracerPtr createHttpTracer(const Json::Object& json_config, + Server::Instance& server, + Upstream::ClusterManager& cluster_manager) PURE; + + /** + * Returns the identifying name for a particular implementation of HttpTracer produced by the + * factory. + */ + virtual std::string name() PURE; +}; + /** * Utilities for creating a filter chain for a network connection. */ @@ -63,10 +122,48 @@ class MainImpl : Logger::Loggable, public Main { public: MainImpl(Server::Instance& server); + /** + * DEPRECATED - Register an NetworkFilterConfigFactory implementation as an option to create + * instances of NetworkFilterFactoryCb. + * @param factory the NetworkFilterConfigFactory implementation + */ static void registerNetworkFilterConfigFactory(NetworkFilterConfigFactory& factory) { filterConfigFactories().push_back(&factory); } + /** + * Register an NamedNetworkFilterConfigFactory implementation as an option to create instances of + * NetworkFilterFactoryCb. + * @param factory the NamedNetworkFilterConfigFactory implementation + */ + static void registerNamedNetworkFilterConfigFactory(NamedNetworkFilterConfigFactory& factory) { + auto result = namedFilterConfigFactories().emplace(std::make_pair(factory.name(), &factory)); + + // result is a pair whose second member is a boolean indicating, if false, that the key exists + // and that the value was not inserted. + if (!result.second) { + throw EnvoyException(fmt::format( + "Attempted to register multiple NamedNetworkFilterConfigFactory objects with name: '{}'", + factory.name())); + } + } + + /** + * Register an HttpTracerFactory as an option to create instances of HttpTracers. + * @param factory the HttpTracerFactory implementation + */ + static void registerHttpTracerFactory(HttpTracerFactory& factory) { + auto result = httpTracerFactories().emplace(std::make_pair(factory.name(), &factory)); + + // result is a pair whose second member is a boolean indicating, if false, that the key exists + // and that the value was not inserted. + if (!result.second) { + throw EnvoyException( + fmt::format("Attempted to register multiple HttpTracerFactory objects with name: '{}'", + factory.name())); + } + } + /** * Initialize the configuration. This happens here vs. the constructor because the initialization * will call through the server to get the cluster manager so the server variable must be @@ -130,9 +227,33 @@ class MainImpl : Logger::Loggable, public Main { std::list filter_factories_; }; + /** + * DEPRECATED - Returns a list of the currently registered NetworkConfigFactories. + */ static std::list& filterConfigFactories() { - static std::list filter_config_factories; - return filter_config_factories; + static std::list* filter_config_factories = + new std::list; + return *filter_config_factories; + } + + /** + * Returns a map of the currently registered NamedNetworkConfigFactories. + */ + static std::unordered_map& + namedFilterConfigFactories() { + static std::unordered_map* + named_filter_config_factories = + new std::unordered_map; + return *named_filter_config_factories; + } + + /** + * Returns a map of the currently registered HttpTracerFactories. + */ + static std::unordered_map& httpTracerFactories() { + static std::unordered_map* http_tracer_factories = + new std::unordered_map; + return *http_tracer_factories; } Server::Instance& server_; @@ -151,13 +272,49 @@ class MainImpl : Logger::Loggable, public Main { }; /** - * @see NetworkFilterConfigFactory. + * DEPRECATED - @see NetworkFilterConfigFactory. An instantiation of this class registers a + * NetworkFilterConfigFactory implementation (T) so it can be used to create instances of + * NetworkFilterFactoryCb. */ template class RegisterNetworkFilterConfigFactory { public: + /** + * Registers the implementation. + */ RegisterNetworkFilterConfigFactory() { - static T instance; - MainImpl::registerNetworkFilterConfigFactory(instance); + static T* instance = new T; + MainImpl::registerNetworkFilterConfigFactory(*instance); + } +}; + +/** + * @see NamedNetworkFilterConfigFactory. An instantiation of this class registers a + * NamedNetworkFilterConfigFactory implementation (T) so it can be used to create instances of + * NetworkFilterFactoryCb. + */ +template class RegisterNamedNetworkFilterConfigFactory { +public: + /** + * Registers the implementation. + */ + RegisterNamedNetworkFilterConfigFactory() { + static T* instance = new T; + MainImpl::registerNamedNetworkFilterConfigFactory(*instance); + } +}; + +/** + * @see HttpTracerFactory. An instantiation of this class registers an HttpTracerFactory + * implementation (T) so it can be used to create instances of HttpTracer. + */ +template class RegisterHttpTracerFactory { +public: + /** + * Registers the implementation. + */ + RegisterHttpTracerFactory() { + static T* instance = new T; + MainImpl::registerHttpTracerFactory(*instance); } }; diff --git a/source/server/http/health_check.cc b/source/server/http/health_check.cc index 96df845baebb..00b722341eab 100644 --- a/source/server/http/health_check.cc +++ b/source/server/http/health_check.cc @@ -22,15 +22,15 @@ namespace Server { namespace Configuration { /** - * Config registration for the health check filter. @see HttpFilterConfigFactory. + * Config registration for the health check filter. @see NamedHttpFilterConfigFactory. */ -HttpFilterFactoryCb HealthCheckFilterConfig::tryCreateFilterFactory(HttpFilterType type, - const std::string& name, - const Json::Object& config, - const std::string&, - Server::Instance& server) { - if (type != HttpFilterType::Both || name != "health_check") { - return nullptr; +HttpFilterFactoryCb HealthCheckFilterConfig::createFilterFactory(HttpFilterType type, + const Json::Object& config, + const std::string&, + Server::Instance& server) { + if (type != HttpFilterType::Both) { + throw EnvoyException(fmt::format( + "{} network filter must be configured as both a read and write filter.", name())); } config.validateSchema(Json::Schema::HEALTH_CHECK_HTTP_FILTER_SCHEMA); @@ -56,10 +56,12 @@ HttpFilterFactoryCb HealthCheckFilterConfig::tryCreateFilterFactory(HttpFilterTy }; } +std::string HealthCheckFilterConfig::name() { return "health_check"; } + /** - * Static registration for the health check filter. @see RegisterHttpFilterConfigFactory. + * Static registration for the health check filter. @see RegisterNamedHttpFilterConfigFactory. */ -static RegisterHttpFilterConfigFactory register_; +static RegisterNamedHttpFilterConfigFactory register_; } // Configuration } // Server diff --git a/source/server/http/health_check.h b/source/server/http/health_check.h index 6237573ec1c7..7430cbb97ae3 100644 --- a/source/server/http/health_check.h +++ b/source/server/http/health_check.h @@ -14,11 +14,11 @@ namespace Envoy { namespace Server { namespace Configuration { -class HealthCheckFilterConfig : public HttpFilterConfigFactory { +class HealthCheckFilterConfig : public NamedHttpFilterConfigFactory { public: - HttpFilterFactoryCb tryCreateFilterFactory(HttpFilterType type, const std::string& name, - const Json::Object& config, const std::string&, - Server::Instance& server) override; + HttpFilterFactoryCb createFilterFactory(HttpFilterType type, const Json::Object& config, + const std::string&, Server::Instance& server) override; + std::string name() override; }; } // Configuration diff --git a/test/integration/BUILD b/test/integration/BUILD index d33c5e2510d8..9ba65c128035 100644 --- a/test/integration/BUILD +++ b/test/integration/BUILD @@ -128,8 +128,10 @@ envoy_cc_test_library( "//source/server/config/http:dynamo_lib", "//source/server/config/http:fault_lib", "//source/server/config/http:grpc_http1_bridge_lib", + "//source/server/config/http:lightstep_lib", "//source/server/config/http:ratelimit_lib", "//source/server/config/http:router_lib", + "//source/server/config/http:zipkin_lib", "//source/server/config/network:client_ssl_auth_lib", "//source/server/config/network:echo_lib", "//source/server/config/network:http_connection_manager_lib", diff --git a/test/server/BUILD b/test/server/BUILD index 77ea8fc38a61..3339c39e3b05 100644 --- a/test/server/BUILD +++ b/test/server/BUILD @@ -21,11 +21,13 @@ envoy_cc_test( data = ["//test/common/ssl/test_data:certs"], deps = [ "//source/common/event:dispatcher_lib", + "//source/common/filter:echo_lib", "//source/server:configuration_lib", "//test/mocks:common_lib", "//test/mocks/network:network_mocks", "//test/mocks/server:server_mocks", "//test/test_common:environment_lib", + "//test/test_common:utility_lib", ], ) diff --git a/test/server/config/http/BUILD b/test/server/config/http/BUILD index 373c8530f437..1de16b1b075f 100644 --- a/test/server/config/http/BUILD +++ b/test/server/config/http/BUILD @@ -16,9 +16,12 @@ envoy_cc_test( "//source/server/config/http:dynamo_lib", "//source/server/config/http:fault_lib", "//source/server/config/http:grpc_http1_bridge_lib", + "//source/server/config/http:lightstep_lib", "//source/server/config/http:ratelimit_lib", "//source/server/config/http:router_lib", + "//source/server/config/http:zipkin_lib", "//source/server/http:health_check_lib", "//test/mocks/server:server_mocks", + "//test/test_common:utility_lib", ], ) diff --git a/test/server/config/http/config_test.cc b/test/server/config/http/config_test.cc index 42f8e3bb39b0..2469caafe049 100644 --- a/test/server/config/http/config_test.cc +++ b/test/server/config/http/config_test.cc @@ -4,11 +4,14 @@ #include "server/config/http/dynamo.h" #include "server/config/http/fault.h" #include "server/config/http/grpc_http1_bridge.h" +#include "server/config/http/lightstep_http_tracer.h" #include "server/config/http/ratelimit.h" #include "server/config/http/router.h" +#include "server/config/http/zipkin_http_tracer.h" #include "server/http/health_check.h" #include "test/mocks/server/mocks.h" +#include "test/test_common/utility.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -16,6 +19,7 @@ namespace Envoy { using testing::_; using testing::NiceMock; +using testing::Return; namespace Server { namespace Configuration { @@ -31,8 +35,8 @@ TEST(HttpFilterConfigTest, BufferFilter) { Json::ObjectSharedPtr json_config = Json::Factory::loadFromString(json_string); NiceMock server; BufferFilterConfig factory; - HttpFilterFactoryCb cb = factory.tryCreateFilterFactory(HttpFilterType::Decoder, "buffer", - *json_config, "stats", server); + HttpFilterFactoryCb cb = + factory.createFilterFactory(HttpFilterType::Decoder, *json_config, "stats", server); Http::MockFilterChainFactoryCallbacks filter_callback; EXPECT_CALL(filter_callback, addStreamDecoderFilter(_)); cb(filter_callback); @@ -49,8 +53,7 @@ TEST(HttpFilterConfigTest, BadBufferFilterConfig) { Json::ObjectSharedPtr json_config = Json::Factory::loadFromString(json_string); NiceMock server; BufferFilterConfig factory; - EXPECT_THROW(factory.tryCreateFilterFactory(HttpFilterType::Decoder, "buffer", *json_config, - "stats", server), + EXPECT_THROW(factory.createFilterFactory(HttpFilterType::Decoder, *json_config, "stats", server), Json::Exception); } @@ -63,8 +66,8 @@ TEST(HttpFilterConfigTest, DynamoFilter) { Json::ObjectSharedPtr json_config = Json::Factory::loadFromString(json_string); NiceMock server; DynamoFilterConfig factory; - HttpFilterFactoryCb cb = factory.tryCreateFilterFactory( - HttpFilterType::Both, "http_dynamo_filter", *json_config, "stats", server); + HttpFilterFactoryCb cb = + factory.createFilterFactory(HttpFilterType::Both, *json_config, "stats", server); Http::MockFilterChainFactoryCallbacks filter_callback; EXPECT_CALL(filter_callback, addStreamFilter(_)); cb(filter_callback); @@ -84,8 +87,8 @@ TEST(HttpFilterConfigTest, FaultFilter) { Json::ObjectSharedPtr json_config = Json::Factory::loadFromString(json_string); NiceMock server; FaultFilterConfig factory; - HttpFilterFactoryCb cb = factory.tryCreateFilterFactory(HttpFilterType::Decoder, "fault", - *json_config, "stats", server); + HttpFilterFactoryCb cb = + factory.createFilterFactory(HttpFilterType::Decoder, *json_config, "stats", server); Http::MockFilterChainFactoryCallbacks filter_callback; EXPECT_CALL(filter_callback, addStreamDecoderFilter(_)); cb(filter_callback); @@ -100,8 +103,8 @@ TEST(HttpFilterConfigTest, GrpcHttp1BridgeFilter) { Json::ObjectSharedPtr json_config = Json::Factory::loadFromString(json_string); NiceMock server; GrpcHttp1BridgeFilterConfig factory; - HttpFilterFactoryCb cb = factory.tryCreateFilterFactory(HttpFilterType::Both, "grpc_http1_bridge", - *json_config, "stats", server); + HttpFilterFactoryCb cb = + factory.createFilterFactory(HttpFilterType::Both, *json_config, "stats", server); Http::MockFilterChainFactoryCallbacks filter_callback; EXPECT_CALL(filter_callback, addStreamFilter(_)); cb(filter_callback); @@ -118,8 +121,8 @@ TEST(HttpFilterConfigTest, HealthCheckFilter) { Json::ObjectSharedPtr json_config = Json::Factory::loadFromString(json_string); NiceMock server; HealthCheckFilterConfig factory; - HttpFilterFactoryCb cb = factory.tryCreateFilterFactory(HttpFilterType::Both, "health_check", - *json_config, "stats", server); + HttpFilterFactoryCb cb = + factory.createFilterFactory(HttpFilterType::Both, *json_config, "stats", server); Http::MockFilterChainFactoryCallbacks filter_callback; EXPECT_CALL(filter_callback, addStreamFilter(_)); cb(filter_callback); @@ -137,8 +140,7 @@ TEST(HttpFilterConfigTest, BadHealthCheckFilterConfig) { Json::ObjectSharedPtr json_config = Json::Factory::loadFromString(json_string); NiceMock server; HealthCheckFilterConfig factory; - EXPECT_THROW(factory.tryCreateFilterFactory(HttpFilterType::Both, "health_check", *json_config, - "stats", server), + EXPECT_THROW(factory.createFilterFactory(HttpFilterType::Both, *json_config, "stats", server), Json::Exception); } @@ -152,8 +154,8 @@ TEST(HttpFilterConfigTest, RouterFilter) { Json::ObjectSharedPtr json_config = Json::Factory::loadFromString(json_string); NiceMock server; RouterFilterConfig factory; - HttpFilterFactoryCb cb = factory.tryCreateFilterFactory(HttpFilterType::Decoder, "router", - *json_config, "stats", server); + HttpFilterFactoryCb cb = + factory.createFilterFactory(HttpFilterType::Decoder, *json_config, "stats", server); Http::MockFilterChainFactoryCallbacks filter_callback; EXPECT_CALL(filter_callback, addStreamDecoderFilter(_)); cb(filter_callback); @@ -170,11 +172,58 @@ TEST(HttpFilterConfigTest, BadRouterFilterConfig) { Json::ObjectSharedPtr json_config = Json::Factory::loadFromString(json_string); NiceMock server; RouterFilterConfig factory; - EXPECT_THROW(factory.tryCreateFilterFactory(HttpFilterType::Decoder, "router", *json_config, - "stats", server), + EXPECT_THROW(factory.createFilterFactory(HttpFilterType::Decoder, *json_config, "stats", server), Json::Exception); } +TEST(HttpFilterConfigTest, DoubleRegistrationTest) { + EXPECT_THROW_WITH_MESSAGE( + RegisterNamedHttpFilterConfigFactory(), EnvoyException, + "Attempted to register multiple NamedHttpFilterConfigFactory objects with name: 'router'"); +} + +TEST(HttpTracerConfigTest, LightstepHttpTracer) { + NiceMock cm; + EXPECT_CALL(cm, get("fake_cluster")).WillRepeatedly(Return(&cm.thread_local_cluster_)); + ON_CALL(*cm.thread_local_cluster_.cluster_.info_, features()) + .WillByDefault(Return(Upstream::ClusterInfo::Features::HTTP2)); + + std::string valid_config = R"EOF( + { + "collector_cluster": "fake_cluster", + "access_token_file": "fake_file" + } + )EOF"; + Json::ObjectSharedPtr valid_json = Json::Factory::loadFromString(valid_config); + NiceMock server; + LightstepHttpTracerFactory factory; + Tracing::HttpTracerPtr lightstep_tracer = factory.createHttpTracer(*valid_json, server, cm); + EXPECT_NE(nullptr, lightstep_tracer); +} + +TEST(HttpTracerConfigTest, ZipkinHttpTracer) { + NiceMock cm; + EXPECT_CALL(cm, get("fake_cluster")).WillRepeatedly(Return(&cm.thread_local_cluster_)); + + std::string valid_config = R"EOF( + { + "collector_cluster": "fake_cluster", + "collector_endpoint": "/api/v1/spans" + } + )EOF"; + Json::ObjectSharedPtr valid_json = Json::Factory::loadFromString(valid_config); + NiceMock server; + ZipkinHttpTracerFactory factory; + Tracing::HttpTracerPtr zipkin_tracer = factory.createHttpTracer(*valid_json, server, cm); + EXPECT_NE(nullptr, zipkin_tracer); +} + +TEST(HttpTracerConfigTest, DoubleRegistrationTest) { + EXPECT_THROW_WITH_MESSAGE( + RegisterHttpTracerFactory(), EnvoyException, + "Attempted to register multiple HttpTracerFactory objects with name: 'zipkin'"); +} + } // Configuration } // Server } // Envoy diff --git a/test/server/config/network/BUILD b/test/server/config/network/BUILD index d825cfc00d67..75e17b1c21a9 100644 --- a/test/server/config/network/BUILD +++ b/test/server/config/network/BUILD @@ -12,6 +12,7 @@ envoy_cc_test( name = "config_test", srcs = ["config_test.cc"], deps = [ + "//source/common/dynamo:dynamo_filter_lib", "//source/server/config/network:client_ssl_auth_lib", "//source/server/config/network:http_connection_manager_lib", "//source/server/config/network:mongo_proxy_lib", @@ -19,6 +20,7 @@ envoy_cc_test( "//source/server/config/network:redis_proxy_lib", "//source/server/config/network:tcp_proxy_lib", "//test/mocks/server:server_mocks", + "//test/test_common:utility_lib", ], ) diff --git a/test/server/config/network/config_test.cc b/test/server/config/network/config_test.cc index fcae5c40ff43..3319714f730e 100644 --- a/test/server/config/network/config_test.cc +++ b/test/server/config/network/config_test.cc @@ -1,5 +1,7 @@ #include +#include "common/dynamo/dynamo_filter.h" + #include "server/config/network/client_ssl_auth.h" #include "server/config/network/http_connection_manager.h" #include "server/config/network/mongo_proxy.h" @@ -8,6 +10,7 @@ #include "server/config/network/tcp_proxy.h" #include "test/mocks/server/mocks.h" +#include "test/test_common/utility.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -34,7 +37,7 @@ TEST(NetworkFilterConfigTest, RedisProxy) { NiceMock server; RedisProxyFilterConfigFactory factory; NetworkFilterFactoryCb cb = - factory.tryCreateFilterFactory(NetworkFilterType::Read, "redis_proxy", *json_config, server); + factory.createFilterFactory(NetworkFilterType::Read, *json_config, server); Network::MockConnection connection; EXPECT_CALL(connection, addReadFilter(_)); cb(connection); @@ -52,7 +55,7 @@ TEST(NetworkFilterConfigTest, MongoProxy) { NiceMock server; MongoProxyFilterConfigFactory factory; NetworkFilterFactoryCb cb = - factory.tryCreateFilterFactory(NetworkFilterType::Both, "mongo_proxy", *json_config, server); + factory.createFilterFactory(NetworkFilterType::Both, *json_config, server); Network::MockConnection connection; EXPECT_CALL(connection, addFilter(_)); cb(connection); @@ -70,9 +73,8 @@ TEST(NetworkFilterConfigTest, BadMongoProxyConfig) { Json::ObjectSharedPtr json_config = Json::Factory::loadFromString(json_string); NiceMock server; MongoProxyFilterConfigFactory factory; - EXPECT_THROW( - factory.tryCreateFilterFactory(NetworkFilterType::Both, "mongo_proxy", *json_config, server), - Json::Exception); + EXPECT_THROW(factory.createFilterFactory(NetworkFilterType::Both, *json_config, server), + Json::Exception); } TEST(NetworkFilterConfigTest, TcpProxy) { @@ -107,13 +109,13 @@ TEST(NetworkFilterConfigTest, TcpProxy) { NiceMock server; TcpProxyConfigFactory factory; NetworkFilterFactoryCb cb = - factory.tryCreateFilterFactory(NetworkFilterType::Read, "tcp_proxy", *json_config, server); + factory.createFilterFactory(NetworkFilterType::Read, *json_config, server); Network::MockConnection connection; EXPECT_CALL(connection, addReadFilter(_)); cb(connection); - EXPECT_EQ(nullptr, factory.tryCreateFilterFactory(NetworkFilterType::Both, "tcp_proxy", - *json_config, server)); + EXPECT_THROW(factory.createFilterFactory(NetworkFilterType::Both, *json_config, server), + EnvoyException); } TEST(NetworkFilterConfigTest, ClientSslAuth) { @@ -128,8 +130,8 @@ TEST(NetworkFilterConfigTest, ClientSslAuth) { Json::ObjectSharedPtr json_config = Json::Factory::loadFromString(json_string); NiceMock server; ClientSslAuthConfigFactory factory; - NetworkFilterFactoryCb cb = factory.tryCreateFilterFactory( - NetworkFilterType::Read, "client_ssl_auth", *json_config, server); + NetworkFilterFactoryCb cb = + factory.createFilterFactory(NetworkFilterType::Read, *json_config, server); Network::MockConnection connection; EXPECT_CALL(connection, addReadFilter(_)); cb(connection); @@ -148,7 +150,7 @@ TEST(NetworkFilterConfigTest, Ratelimit) { NiceMock server; RateLimitConfigFactory factory; NetworkFilterFactoryCb cb = - factory.tryCreateFilterFactory(NetworkFilterType::Read, "ratelimit", *json_config, server); + factory.createFilterFactory(NetworkFilterType::Read, *json_config, server); Network::MockConnection connection; EXPECT_CALL(connection, addReadFilter(_)); cb(connection); @@ -180,8 +182,7 @@ TEST(NetworkFilterConfigTest, BadHttpConnectionMangerConfig) { Json::ObjectSharedPtr json_config = Json::Factory::loadFromString(json_string); HttpConnectionManagerFilterConfigFactory factory; NiceMock server; - EXPECT_THROW(factory.tryCreateFilterFactory(NetworkFilterType::Read, "http_connection_manager", - *json_config, server), + EXPECT_THROW(factory.createFilterFactory(NetworkFilterType::Read, *json_config, server), Json::Exception); } @@ -223,8 +224,7 @@ TEST(NetworkFilterConfigTest, BadAccessLogConfig) { Json::ObjectSharedPtr json_config = Json::Factory::loadFromString(json_string); HttpConnectionManagerFilterConfigFactory factory; NiceMock server; - EXPECT_THROW(factory.tryCreateFilterFactory(NetworkFilterType::Read, "http_connection_manager", - *json_config, server), + EXPECT_THROW(factory.createFilterFactory(NetworkFilterType::Read, *json_config, server), Json::Exception); } @@ -268,8 +268,7 @@ TEST(NetworkFilterConfigTest, BadAccessLogType) { Json::ObjectSharedPtr json_config = Json::Factory::loadFromString(json_string); HttpConnectionManagerFilterConfigFactory factory; NiceMock server; - EXPECT_THROW(factory.tryCreateFilterFactory(NetworkFilterType::Read, "http_connection_manager", - *json_config, server), + EXPECT_THROW(factory.createFilterFactory(NetworkFilterType::Read, *json_config, server), Json::Exception); } @@ -323,11 +322,77 @@ TEST(NetworkFilterConfigTest, BadAccessLogNestedTypes) { Json::ObjectSharedPtr json_config = Json::Factory::loadFromString(json_string); HttpConnectionManagerFilterConfigFactory factory; NiceMock server; - EXPECT_THROW(factory.tryCreateFilterFactory(NetworkFilterType::Read, "http_connection_manager", - *json_config, server), + EXPECT_THROW(factory.createFilterFactory(NetworkFilterType::Read, *json_config, server), Json::Exception); } +/** + * Deprecated version of config registration for http dynamodb filter. + */ +class TestDeprecatedDynamoFilterConfig : public HttpFilterConfigFactory { +public: + HttpFilterFactoryCb tryCreateFilterFactory(HttpFilterType type, const std::string& name, + const Json::Object&, const std::string& stat_prefix, + Server::Instance& server) override { + if (type != HttpFilterType::Both || name != "http_dynamo_filter_deprecated") { + return nullptr; + } + + return [&server, stat_prefix](Http::FilterChainFactoryCallbacks& callbacks) -> void { + callbacks.addStreamFilter(Http::StreamFilterSharedPtr{ + new Dynamo::DynamoFilter(server.runtime(), stat_prefix, server.stats())}); + }; + } +}; + +TEST(NetworkFilterConfigTest, DeprecatedHttpFilterConfigFactoryTest) { + // Test just ensures that the deprecated http filter registration still works without error. + + // Register the config factory + RegisterHttpFilterConfigFactory registered; + + std::string json = R"EOF( + { + "codec_type" : "http1", + "stat_prefix" : "my_stat_prefix", + "route_config" : { + "virtual_hosts" : [ + { + "name" : "default", + "domains" : ["*"], + "routes" : [ + { + "prefix" : "/", + "cluster": "fake_cluster" + } + ] + } + ] + }, + "filters" : [ + { + "type" : "both", + "name" : "http_dynamo_filter_deprecated", + "config" : {} + } + ] + } + )EOF"; + + Json::ObjectSharedPtr loader = Json::Factory::loadFromString(json); + + HttpConnectionManagerFilterConfigFactory factory; + NiceMock server; + factory.createFilterFactory(NetworkFilterType::Read, *loader, server); +} + +TEST(NetworkFilterConfigTest, DoubleRegistrationTest) { + EXPECT_THROW_WITH_MESSAGE(RegisterNamedNetworkFilterConfigFactory(), + EnvoyException, "Attempted to register multiple " + "NamedNetworkFilterConfigFactory objects with name: " + "'client_ssl_auth'"); +} + } // Configuration } // Server } // Envoy diff --git a/test/server/configuration_impl_test.cc b/test/server/configuration_impl_test.cc index 7bcb89e8ed62..62a168bb638b 100644 --- a/test/server/configuration_impl_test.cc +++ b/test/server/configuration_impl_test.cc @@ -2,12 +2,15 @@ #include #include +#include "common/filter/echo.h" + #include "server/configuration_impl.h" #include "test/mocks/common.h" #include "test/mocks/network/mocks.h" #include "test/mocks/server/mocks.h" #include "test/test_common/environment.h" +#include "test/test_common/utility.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -275,6 +278,35 @@ TEST(ConfigurationImplTest, BadFilterConfig) { EXPECT_THROW(config.initialize(*loader), Json::Exception); } +TEST(ConfigurationImplTest, BadFilterName) { + std::string json = R"EOF( + { + "listeners" : [ + { + "address": "tcp://127.0.0.1:1234", + "filters": [ + { + "type" : "read", + "name" : "invalid", + "config" : {} + } + ] + } + ], + "cluster_manager": { + "clusters": [] + } + } + )EOF"; + + Json::ObjectSharedPtr loader = Json::Factory::loadFromString(json); + + NiceMock server; + MainImpl config(server); + EXPECT_THROW_WITH_MESSAGE(config.initialize(*loader), EnvoyException, + "unable to create filter factory for 'invalid'/'read'"); +} + TEST(ConfigurationImplTest, ServiceClusterNotSetWhenLSTracing) { std::string json = R"EOF( { @@ -368,6 +400,88 @@ TEST(ConfigurationImplTest, NullTracerSetWhenHttpKeyAbsentFromTracerConfiguratio EXPECT_NE(nullptr, dynamic_cast(&config.httpTracer())); } +TEST(ConfigurationImplTest, ConfigurationFailsWhenInvalidTracerSpecified) { + std::string json = R"EOF( + { + "listeners" : [ + { + "address": "tcp://127.0.0.1:1234", + "filters": [] + } + ], + "cluster_manager": { + "clusters": [] + }, + "tracing": { + "http": { + "driver": { + "type": "invalid", + "config": { + "access_token_file": "/etc/envoy/envoy.cfg" + } + } + } + } + } + )EOF"; + + Json::ObjectSharedPtr loader = Json::Factory::loadFromString(json); + + NiceMock server; + MainImpl config(server); + EXPECT_THROW_WITH_MESSAGE(config.initialize(*loader), EnvoyException, + "No HttpTracerFactory found for type: invalid"); +} + +/** + * Config registration for the echo filter using the deprecated registration class. + */ +class TestDeprecatedEchoConfigFactory : public NetworkFilterConfigFactory { +public: + // NetworkFilterConfigFactory + NetworkFilterFactoryCb tryCreateFilterFactory(NetworkFilterType type, const std::string& name, + const Json::Object&, Server::Instance&) override { + if (type != NetworkFilterType::Read || name != "echo_deprecated") { + return nullptr; + } + + return [](Network::FilterManager& filter_manager) + -> void { filter_manager.addReadFilter(Network::ReadFilterSharedPtr{new Filter::Echo()}); }; + } +}; + +TEST(NetworkFilterConfigTest, DeprecatedFilterConfigFactoryRegistrationTest) { + // Test ensures that the deprecated network filter registration still works without error. + + // Register the config factory + RegisterNetworkFilterConfigFactory registered; + + std::string json = R"EOF( + { + "listeners" : [ + { + "address": "tcp://127.0.0.1:1234", + "filters": [ + { + "type" : "read", + "name" : "echo_deprecated", + "config" : {} + } + ] + } + ], + "cluster_manager": { + "clusters": [] + } + } + )EOF"; + + Json::ObjectSharedPtr loader = Json::Factory::loadFromString(json); + + NiceMock server; + MainImpl config(server); + config.initialize(*loader); +} } // Configuration } // Server } // Envoy diff --git a/test/server/http/health_check_test.cc b/test/server/http/health_check_test.cc index 49755cd24864..977342ffe2ce 100644 --- a/test/server/http/health_check_test.cc +++ b/test/server/http/health_check_test.cc @@ -208,10 +208,10 @@ TEST(HealthCheckFilterConfig, failsWhenNotPassThroughButTimeoutSet) { "{\"pass_through_mode\":false, \"cache_time_ms\":234, \"endpoint\":\"foo\"}"); NiceMock serverMock; - EXPECT_THROW(healthCheckFilterConfig.tryCreateFilterFactory( - Server::Configuration::HttpFilterType::Both, "health_check", *config, - "dummy_stats_prefix", serverMock), - EnvoyException); + EXPECT_THROW( + healthCheckFilterConfig.createFilterFactory(Server::Configuration::HttpFilterType::Both, + *config, "dummy_stats_prefix", serverMock), + EnvoyException); } TEST(HealthCheckFilterConfig, notFailingWhenNotPassThroughAndTimeoutNotSet) { @@ -220,8 +220,7 @@ TEST(HealthCheckFilterConfig, notFailingWhenNotPassThroughAndTimeoutNotSet) { Json::Factory::loadFromString("{\"pass_through_mode\":false, \"endpoint\":\"foo\"}"); NiceMock serverMock; - healthCheckFilterConfig.tryCreateFilterFactory(Server::Configuration::HttpFilterType::Both, - "health_check", *config, "dummy_stats_prefix", - serverMock); + healthCheckFilterConfig.createFilterFactory(Server::Configuration::HttpFilterType::Both, *config, + "dummy_stats_prefix", serverMock); } } // Envoy