diff --git a/docs/root/configuration/overview/extension.rst b/docs/root/configuration/overview/extension.rst new file mode 100644 index 0000000000000..e131a7515cc3a --- /dev/null +++ b/docs/root/configuration/overview/extension.rst @@ -0,0 +1,63 @@ +.. _config_overview_extension_configuration: + +Extension configuration +----------------------- + +Each configuration resource in Envoy has a type URL in the `typed_config`. This +type corresponds to a versioned schema. If the type URL uniquely identifies an +extension capable of interpreting the configuration, then the extension is +selected regardless of the `name` field. In this case the `name` field becomes +optional and can be used as an identifier or as an annotation for the +particular instance of the extension configuration. For example, the following +filter configuration snippet is permitted: + +.. code-block:: yaml + + name: front-http-proxy + typed_config: + "@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager + stat_prefix: ingress_http + codec_type: AUTO + rds: + route_config_name: local_route + config_source: + api_config_source: + api_type: GRPC + grpc_services: + envoy_grpc: + cluster_name: xds_cluster + http_filters: + - name: front-router + typed_config: + "@type": type.googleapis.com/envoy.config.filter.http.router.v2.Router + dynamic_stats: true + +In case the control plane lacks the schema definitions for an extension, +`udpa.type.v1.TypedStruct` should be used as a generic container. The type URL +inside it is then used by a client to convert the contents to a typed +configuration resource. For example, the above example could be written as +follows: + +.. code-block:: yaml + + name: front-http-proxy + typed_config: + "@type": type.googleapis.com/udpa.type.v1.TypedStruct + type_url: type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager + value: + stat_prefix: ingress_http + codec_type: AUTO + rds: + route_config_name: local_route + config_source: + api_config_source: + api_type: GRPC + grpc_services: + envoy_grpc: + cluster_name: xds_cluster + http_filters: + - name: front-router + typed_config: + "@type": type.googleapis.com/udpa.type.v1.TypedStruct + type_url: type.googleapis.com/envoy.config.filter.http.router.v2.Router + diff --git a/docs/root/configuration/overview/overview.rst b/docs/root/configuration/overview/overview.rst index ae1e00c179617..0c8bbe70b96e3 100644 --- a/docs/root/configuration/overview/overview.rst +++ b/docs/root/configuration/overview/overview.rst @@ -10,5 +10,6 @@ Overview versioning bootstrap examples + extension xds_api mgmt_server diff --git a/docs/root/intro/version_history.rst b/docs/root/intro/version_history.rst index b0bba454f3959..27dc4523010c0 100644 --- a/docs/root/intro/version_history.rst +++ b/docs/root/intro/version_history.rst @@ -3,6 +3,7 @@ Version history 1.14.0 (Pending) ================ +* config: use type URL to select an extension whenever the config type URL (or its previous versions) uniquely identify a typed extension, see :ref:`extension configuration `. * retry: added a retry predicate that :ref:`rejects hosts based on metadata. ` 1.13.0 (January 20, 2020) diff --git a/include/envoy/registry/BUILD b/include/envoy/registry/BUILD index 6cdb209aa68c6..4c1cecb928d43 100644 --- a/include/envoy/registry/BUILD +++ b/include/envoy/registry/BUILD @@ -13,6 +13,7 @@ envoy_cc_library( hdrs = ["registry.h"], deps = [ "//source/common/common:assert_lib", + "//source/common/config:api_type_oracle_lib", "//source/common/protobuf:utility_lib", "@envoy_api//envoy/config/core/v3:pkg_cc_proto", ], diff --git a/include/envoy/registry/registry.h b/include/envoy/registry/registry.h index 65572e49af0f3..f0c698a6c8e23 100644 --- a/include/envoy/registry/registry.h +++ b/include/envoy/registry/registry.h @@ -12,6 +12,7 @@ #include "common/common/assert.h" #include "common/common/fmt.h" #include "common/common/logger.h" +#include "common/config/api_type_oracle.h" #include "common/protobuf/utility.h" #include "absl/base/attributes.h" @@ -188,6 +189,55 @@ template class FactoryRegistry : public Logger::Loggable& factoriesByType() { + static absl::flat_hash_map* factories_by_type = + [] { + auto mapping = std::make_unique>(); + + for (const auto& factory : factories()) { + if (factory.second == nullptr) { + continue; + } + + // Skip untyped factories. + std::string config_type = factory.second->configType(); + if (config_type.empty()) { + continue; + } + + // Register config types in the mapping and traverse the deprecated message type chain. + while (true) { + auto it = mapping->find(config_type); + if (it != mapping->end() && it->second != factory.second) { + // Mark double-registered types with a nullptr. + // See issue https://github.com/envoyproxy/envoy/issues/9643. + ENVOY_LOG(warn, "Double registration for type: '{}' by '{}' and '{}'", config_type, + factory.second->name(), it->second ? it->second->name() : ""); + it->second = nullptr; + } else { + mapping->emplace(std::make_pair(config_type, factory.second)); + } + + const Protobuf::Descriptor* previous = + Config::ApiTypeOracle::getEarlierVersionDescriptor(config_type); + if (previous == nullptr) { + break; + } + config_type = previous->full_name(); + } + } + return mapping; + }() + .release(); + + return *factories_by_type; + } + /** * instead_value are used when passed name was deprecated. */ @@ -262,6 +312,14 @@ template class FactoryRegistry : public Logger::Loggablesecond; } + static Base* getFactoryByType(absl::string_view type) { + auto it = factoriesByType().find(type); + if (it == factoriesByType().end()) { + return nullptr; + } + return it->second; + } + /** * @return the canonical name of the factory. If the given name is a * deprecated factory name, the canonical name is returned instead. @@ -320,6 +378,12 @@ template class FactoryRegistry : public Logger::Loggable class FactoryRegistry : public Logger::Loggablefull_name(); - - // Determine if there is an earlier API version for target_type. +ApiTypeOracle::getEarlierVersionDescriptor(const std::string& message_type) { + // Determine if there is an earlier API version for message_type. const Protobuf::Descriptor* desc = - Protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName(std::string{target_type}); + Protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName(std::string{message_type}); if (desc == nullptr) { return nullptr; } diff --git a/source/common/config/api_type_oracle.h b/source/common/config/api_type_oracle.h index e8ae307fe827b..8c57b5c1243fb 100644 --- a/source/common/config/api_type_oracle.h +++ b/source/common/config/api_type_oracle.h @@ -12,11 +12,11 @@ class ApiTypeOracle { * this message. If so, return the descriptor for the earlier * message, to support upgrading via VersionConverter::upgrade(). * - * @param message protobuf message. + * @param message_type protobuf message type * @return const Protobuf::Descriptor* descriptor for earlier message version * corresponding to message, if any, otherwise nullptr. */ - static const Protobuf::Descriptor* getEarlierVersionDescriptor(const Protobuf::Message& message); + static const Protobuf::Descriptor* getEarlierVersionDescriptor(const std::string& message_type); }; } // namespace Config diff --git a/source/common/config/utility.cc b/source/common/config/utility.cc index 1db3dc4f8a63a..d2716adb8ea33 100644 --- a/source/common/config/utility.cc +++ b/source/common/config/utility.cc @@ -24,8 +24,6 @@ #include "common/stats/stats_matcher_impl.h" #include "common/stats/tag_producer_impl.h" -#include "udpa/type/v1/typed_struct.pb.h" - namespace Envoy { namespace Config { diff --git a/source/common/config/utility.h b/source/common/config/utility.h index a7e6ef1beac33..6b30747bfb318 100644 --- a/source/common/config/utility.h +++ b/source/common/config/utility.h @@ -26,6 +26,8 @@ #include "common/protobuf/utility.h" #include "common/singleton/const_singleton.h" +#include "udpa/type/v1/typed_struct.pb.h" + namespace Envoy { namespace Config { @@ -215,6 +217,26 @@ class Utility { */ template static Factory& getAndCheckFactory(const ProtoMessage& message) { + const ProtobufWkt::Any& typed_config = message.typed_config(); + static const std::string& typed_struct_type = + udpa::type::v1::TypedStruct::default_instance().GetDescriptor()->full_name(); + + if (!typed_config.value().empty()) { + // Unpack methods will only use the fully qualified type name after the last '/'. + // https://github.com/protocolbuffers/protobuf/blob/3.6.x/src/google/protobuf/any.proto#L87 + auto type = std::string(TypeUtil::typeUrlToDescriptorFullName(typed_config.type_url())); + if (type == typed_struct_type) { + udpa::type::v1::TypedStruct typed_struct; + MessageUtil::unpackTo(typed_config, typed_struct); + // Not handling nested structs or typed structs in typed structs + type = typed_struct.type_url(); + } + Factory* factory = Registry::FactoryRegistry::getFactoryByType(type); + if (factory != nullptr) { + return *factory; + } + } + return Utility::getAndCheckFactoryByName(message.name()); } diff --git a/source/common/config/version_converter.cc b/source/common/config/version_converter.cc index 544085033446f..54b14e9962149 100644 --- a/source/common/config/version_converter.cc +++ b/source/common/config/version_converter.cc @@ -170,7 +170,8 @@ DynamicMessagePtr VersionConverter::recoverOriginal(const Protobuf::Message& upg } DynamicMessagePtr VersionConverter::downgrade(const Protobuf::Message& message) { - const Protobuf::Descriptor* prev_desc = ApiTypeOracle::getEarlierVersionDescriptor(message); + const Protobuf::Descriptor* prev_desc = + ApiTypeOracle::getEarlierVersionDescriptor(message.GetDescriptor()->full_name()); return createForDescriptorWithCast(message, prev_desc); } diff --git a/source/common/protobuf/utility.cc b/source/common/protobuf/utility.cc index 053216949a54e..55412b9d146ea 100644 --- a/source/common/protobuf/utility.cc +++ b/source/common/protobuf/utility.cc @@ -137,7 +137,7 @@ class ApiBoostRetryException : public EnvoyException { // vN/v(N+1) mechanical transforms. void tryWithApiBoosting(MessageXformFn f, Protobuf::Message& message) { const Protobuf::Descriptor* earlier_version_desc = - Config::ApiTypeOracle::getEarlierVersionDescriptor(message); + Config::ApiTypeOracle::getEarlierVersionDescriptor(message.GetDescriptor()->full_name()); // If there is no earlier version of a message, just apply f directly. if (earlier_version_desc == nullptr) { f(message, MessageVersion::LATEST_VERSION); @@ -528,7 +528,7 @@ void MessageUtil::unpackTo(const ProtobufWkt::Any& any_message, Protobuf::Messag TypeUtil::typeUrlToDescriptorFullName(any_message.type_url()); if (any_full_name != message.GetDescriptor()->full_name()) { const Protobuf::Descriptor* earlier_version_desc = - Config::ApiTypeOracle::getEarlierVersionDescriptor(message); + Config::ApiTypeOracle::getEarlierVersionDescriptor(message.GetDescriptor()->full_name()); // If the earlier version matches, unpack and upgrade. if (earlier_version_desc != nullptr && any_full_name == earlier_version_desc->full_name()) { Protobuf::DynamicMessageFactory dmf; diff --git a/test/common/config/api_type_oracle_test.cc b/test/common/config/api_type_oracle_test.cc index 0b9e5ab342c1b..ef333bff03417 100644 --- a/test/common/config/api_type_oracle_test.cc +++ b/test/common/config/api_type_oracle_test.cc @@ -16,9 +16,12 @@ TEST(ApiTypeOracleTest, All) { envoy::extensions::filters::http::ip_tagging::v3::IPTagging v3_config; ProtobufWkt::Any non_api_type; - EXPECT_EQ(nullptr, ApiTypeOracle::getEarlierVersionDescriptor(non_api_type)); - EXPECT_EQ(nullptr, ApiTypeOracle::getEarlierVersionDescriptor(v2_config)); - const auto* desc = ApiTypeOracle::getEarlierVersionDescriptor(v3_config); + EXPECT_EQ(nullptr, + ApiTypeOracle::getEarlierVersionDescriptor(non_api_type.GetDescriptor()->full_name())); + EXPECT_EQ(nullptr, + ApiTypeOracle::getEarlierVersionDescriptor(v2_config.GetDescriptor()->full_name())); + const auto* desc = + ApiTypeOracle::getEarlierVersionDescriptor(v3_config.GetDescriptor()->full_name()); EXPECT_EQ(envoy::config::filter::http::ip_tagging::v2::IPTagging::descriptor()->full_name(), desc->full_name()); } diff --git a/test/common/router/router_test.cc b/test/common/router/router_test.cc index 69267e35257d3..a00fca26ef133 100644 --- a/test/common/router/router_test.cc +++ b/test/common/router/router_test.cc @@ -61,7 +61,7 @@ using testing::StartsWith; namespace Envoy { namespace Router { -class TestFilter : public Filter { +class RouterTestFilter : public Filter { public: using Filter::Filter; // Filter @@ -267,7 +267,7 @@ class RouterTestBase : public testing::Test { MockShadowWriter* shadow_writer_; NiceMock local_info_; FilterConfig config_; - TestFilter router_; + RouterTestFilter router_; Event::MockTimer* response_timeout_{}; Event::MockTimer* per_try_timeout_{}; Network::Address::InstanceConstSharedPtr host_address_{ diff --git a/test/extensions/access_loggers/file/config_test.cc b/test/extensions/access_loggers/file/config_test.cc index 63db36bb551b7..19343c80bdbec 100644 --- a/test/extensions/access_loggers/file/config_test.cc +++ b/test/extensions/access_loggers/file/config_test.cc @@ -31,26 +31,26 @@ TEST(FileAccessLogConfigTest, ValidateFail) { TEST(FileAccessLogConfigTest, ConfigureFromProto) { envoy::config::accesslog::v3::AccessLog config; + NiceMock context; + EXPECT_THROW_WITH_MESSAGE(AccessLog::AccessLogFactory::fromProto(config, context), EnvoyException, + "Provided name for static registration lookup was empty."); + + config.set_name("INVALID"); + + EXPECT_THROW_WITH_MESSAGE(AccessLog::AccessLogFactory::fromProto(config, context), EnvoyException, + "Didn't find a registered implementation for name: 'INVALID'"); + envoy::extensions::access_loggers::file::v3::FileAccessLog fal_config; fal_config.set_path("/dev/null"); config.mutable_typed_config()->PackFrom(fal_config); - NiceMock context; - EXPECT_THROW_WITH_MESSAGE(AccessLog::AccessLogFactory::fromProto(config, context), EnvoyException, - "Provided name for static registration lookup was empty."); - config.set_name(AccessLogNames::get().File); AccessLog::InstanceSharedPtr log = AccessLog::AccessLogFactory::fromProto(config, context); EXPECT_NE(nullptr, log); EXPECT_NE(nullptr, dynamic_cast(log.get())); - - config.set_name("INVALID"); - - EXPECT_THROW_WITH_MESSAGE(AccessLog::AccessLogFactory::fromProto(config, context), EnvoyException, - "Didn't find a registered implementation for name: 'INVALID'"); } TEST(FileAccessLogConfigTest, FileAccessLogTest) { @@ -79,6 +79,15 @@ TEST(FileAccessLogConfigTest, FileAccessLogTest) { TEST(FileAccessLogConfigTest, FileAccessLogJsonTest) { envoy::config::accesslog::v3::AccessLog config; + NiceMock context; + EXPECT_THROW_WITH_MESSAGE(AccessLog::AccessLogFactory::fromProto(config, context), EnvoyException, + "Provided name for static registration lookup was empty."); + + config.set_name("INVALID"); + + EXPECT_THROW_WITH_MESSAGE(AccessLog::AccessLogFactory::fromProto(config, context), EnvoyException, + "Didn't find a registered implementation for name: 'INVALID'"); + envoy::extensions::access_loggers::file::v3::FileAccessLog fal_config; fal_config.set_path("/dev/null"); @@ -93,21 +102,12 @@ TEST(FileAccessLogConfigTest, FileAccessLogJsonTest) { envoy::extensions::access_loggers::file::v3::FileAccessLog::AccessLogFormatCase::kJsonFormat); config.mutable_typed_config()->PackFrom(fal_config); - NiceMock context; - EXPECT_THROW_WITH_MESSAGE(AccessLog::AccessLogFactory::fromProto(config, context), EnvoyException, - "Provided name for static registration lookup was empty."); - config.set_name(AccessLogNames::get().File); AccessLog::InstanceSharedPtr log = AccessLog::AccessLogFactory::fromProto(config, context); EXPECT_NE(nullptr, log); EXPECT_NE(nullptr, dynamic_cast(log.get())); - - config.set_name("INVALID"); - - EXPECT_THROW_WITH_MESSAGE(AccessLog::AccessLogFactory::fromProto(config, context), EnvoyException, - "Didn't find a registered implementation for name: 'INVALID'"); } TEST(FileAccessLogConfigTest, FileAccessLogTypedJsonTest) { diff --git a/test/integration/BUILD b/test/integration/BUILD index e9a3ee8940cd8..0645598a9a4c1 100644 --- a/test/integration/BUILD +++ b/test/integration/BUILD @@ -919,6 +919,7 @@ envoy_cc_test( deps = [ ":http_integration_lib", "//source/common/stats:stats_lib", + "//test/test_common:registry_lib", "@envoy_api//envoy/extensions/filters/network/tcp_proxy/v3:pkg_cc_proto", ], ) diff --git a/test/integration/dynamic_validation_integration_test.cc b/test/integration/dynamic_validation_integration_test.cc index b53d41f8452c5..3363b5341f4f4 100644 --- a/test/integration/dynamic_validation_integration_test.cc +++ b/test/integration/dynamic_validation_integration_test.cc @@ -7,6 +7,7 @@ #include "test/integration/http_integration.h" #include "test/test_common/environment.h" +#include "test/test_common/registry.h" #include "gtest/gtest.h" @@ -43,9 +44,6 @@ class TestDynamicValidationNetworkFilterConfigFactory } }; -REGISTER_FACTORY(TestDynamicValidationNetworkFilterConfigFactory, - Server::Configuration::NamedNetworkFilterConfigFactory); - // Pretty-printing of parameterized test names. std::string dynamicValidationTestParamsToString( const ::testing::TestParamInfo>& params) { @@ -76,6 +74,11 @@ class DynamicValidationIntegrationTest ApiFilesystemConfig api_filesystem_config_; const bool reject_unknown_dynamic_fields_; bool allow_lds_rejection_{}; + +private: + TestDynamicValidationNetworkFilterConfigFactory factory_; + Registry::InjectFactory register_{ + factory_}; }; INSTANTIATE_TEST_SUITE_P( diff --git a/test/integration/xds_integration_test.cc b/test/integration/xds_integration_test.cc index 4be8a537b2e4c..9442b682c7a36 100644 --- a/test/integration/xds_integration_test.cc +++ b/test/integration/xds_integration_test.cc @@ -119,6 +119,7 @@ TEST_P(LdsIntegrationTest, FailConfigLoad) { config_helper_.addConfigModifier([&](envoy::config::bootstrap::v3::Bootstrap& bootstrap) -> void { auto* listener = bootstrap.mutable_static_resources()->mutable_listeners(0); auto* filter_chain = listener->mutable_filter_chains(0); + filter_chain->mutable_filters(0)->clear_typed_config(); filter_chain->mutable_filters(0)->set_name("grewgragra"); }); EXPECT_DEATH_LOG_TO_STDERR(initialize(), diff --git a/test/server/BUILD b/test/server/BUILD index 6ca389536809d..400c4b80fab88 100644 --- a/test/server/BUILD +++ b/test/server/BUILD @@ -141,8 +141,11 @@ envoy_cc_test( srcs = ["options_impl_test.cc"], deps = [ "//include/envoy/config:typed_config_interface", + "//include/envoy/server:filter_config_interface", "//source/common/common:utility_lib", "//source/common/stats:stats_lib", + "//source/extensions/filters/http:well_known_names", + "//source/extensions/filters/http/ip_tagging:config", "//source/server:options_lib", "//test/mocks/api:api_mocks", "//test/test_common:environment_lib", @@ -151,6 +154,8 @@ envoy_cc_test( "//test/test_common:utility_lib", "@envoy_api//envoy/admin/v3:pkg_cc_proto", "@envoy_api//envoy/config/bootstrap/v3:pkg_cc_proto", + "@envoy_api//envoy/config/filter/http/ip_tagging/v2:pkg_cc_proto", + "@envoy_api//envoy/extensions/filters/http/ip_tagging/v3:pkg_cc_proto", ], ) diff --git a/test/server/configuration_impl_test.cc b/test/server/configuration_impl_test.cc index 7d678526c5492..5e16abeaa2aaf 100644 --- a/test/server/configuration_impl_test.cc +++ b/test/server/configuration_impl_test.cc @@ -25,6 +25,7 @@ #include "fmt/printf.h" #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "udpa/type/v1/typed_struct.pb.h" using testing::Return; @@ -257,9 +258,12 @@ TEST_F(ConfigurationImplTest, ConfigurationFailsWhenInvalidTracerSpecified) { "http": { "name": "invalid", "typed_config": { - "@type": "type.googleapis.com/envoy.config.trace.v2.LightstepConfig", - "collector_cluster": "cluster_0", - "access_token_file": "/etc/envoy/envoy.cfg" + "@type": "type.googleapis.com/udpa.type.v1.TypedStruct", + "type_url": "type.googleapis.com/envoy.config.trace.v2.BlackHoleConfig", + "value": { + "collector_cluster": "cluster_0", + "access_token_file": "/etc/envoy/envoy.cfg" + } } } }, @@ -336,7 +340,6 @@ TEST_F(ConfigurationImplTest, StatsSinkWithInvalidName) { envoy::config::metrics::v3::StatsSink& sink = *bootstrap.mutable_stats_sinks()->Add(); sink.set_name("envoy.invalid"); - addStatsdFakeClusterConfig(sink); MainImpl config; EXPECT_THROW_WITH_MESSAGE(config.initialize(bootstrap, server_, cluster_manager_factory_), @@ -365,8 +368,40 @@ TEST_F(ConfigurationImplTest, StatsSinkWithNoName) { auto bootstrap = Upstream::parseBootstrapFromV2Json(json); + bootstrap.mutable_stats_sinks()->Add(); + + MainImpl config; + EXPECT_THROW_WITH_MESSAGE(config.initialize(bootstrap, server_, cluster_manager_factory_), + EnvoyException, + "Provided name for static registration lookup was empty."); +} + +TEST_F(ConfigurationImplTest, StatsSinkWithNoType) { + std::string json = R"EOF( + { + "static_resources": { + "listeners": [], + "clusters": [] + }, + "admin": { + "access_log_path": "/dev/null", + "address": { + "socket_address": { + "address": "1.2.3.4", + "port_value": 5678 + } + } + } + } + )EOF"; + + auto bootstrap = Upstream::parseBootstrapFromV2Json(json); + auto& sink = *bootstrap.mutable_stats_sinks()->Add(); - addStatsdFakeClusterConfig(sink); + udpa::type::v1::TypedStruct typed_struct; + auto untyped_struct = typed_struct.mutable_value(); + (*untyped_struct->mutable_fields())["foo"].set_string_value("bar"); + sink.mutable_typed_config()->PackFrom(typed_struct); MainImpl config; EXPECT_THROW_WITH_MESSAGE(config.initialize(bootstrap, server_, cluster_manager_factory_), diff --git a/test/server/listener_manager_impl_test.cc b/test/server/listener_manager_impl_test.cc index 149cd04428e10..510ddf5f42196 100644 --- a/test/server/listener_manager_impl_test.cc +++ b/test/server/listener_manager_impl_test.cc @@ -359,9 +359,9 @@ class NonTerminalFilterFactory : public Configuration::NamedNetworkFilterConfigF }; TEST_F(ListenerManagerImplWithRealFiltersTest, TerminalNotLast) { - Registry::RegisterFactory - registered; + NonTerminalFilterFactory filter; + Registry::InjectFactory registered(filter); + const std::string yaml = R"EOF( address: socket_address: @@ -441,8 +441,8 @@ class TestStatsConfigFactory : public Configuration::NamedNetworkFilterConfigFac }; TEST_F(ListenerManagerImplWithRealFiltersTest, StatsScopeTest) { - Registry::RegisterFactory - registered; + TestStatsConfigFactory filter; + Registry::InjectFactory registered(filter); const std::string yaml = R"EOF( address: diff --git a/test/server/options_impl_test.cc b/test/server/options_impl_test.cc index d86a1495dc9aa..f2fd9db4a6779 100644 --- a/test/server/options_impl_test.cc +++ b/test/server/options_impl_test.cc @@ -8,12 +8,18 @@ #include "envoy/admin/v3/server_info.pb.h" #include "envoy/common/exception.h" #include "envoy/config/bootstrap/v3/bootstrap.pb.h" +#include "envoy/config/filter/http/ip_tagging/v2/ip_tagging.pb.h" #include "envoy/config/typed_config.h" +#include "envoy/extensions/filters/http/ip_tagging/v3/ip_tagging.pb.h" +#include "envoy/server/filter_config.h" #include "common/common/utility.h" #include "server/options_impl.h" +#include "extensions/filters/http/ip_tagging/ip_tagging_filter.h" +#include "extensions/filters/http/well_known_names.h" + #if defined(__linux__) #include #include "server/options_impl_platform_linux.h" @@ -451,10 +457,14 @@ TEST_F(OptionsImplPlatformLinuxTest, AffinityTest4) { #endif -class TestFactory : public Config::UntypedFactory { +class TestFactory : public Config::TypedFactory { public: virtual ~TestFactory() = default; std::string category() const override { return "test"; } + std::string configType() override { return "google.protobuf.StringValue"; } + ProtobufTypes::MessagePtr createEmptyConfigProto() override { + return std::make_unique(); + } }; class TestTestFactory : public TestFactory { @@ -462,10 +472,14 @@ class TestTestFactory : public TestFactory { std::string name() const override { return "test"; } }; -class TestingFactory : public Config::UntypedFactory { +class TestingFactory : public Config::TypedFactory { public: virtual ~TestingFactory() = default; std::string category() const override { return "testing"; } + std::string configType() override { return "google.protobuf.StringValue"; } + ProtobufTypes::MessagePtr createEmptyConfigProto() override { + return std::make_unique(); + } }; class TestTestingFactory : public TestingFactory { @@ -486,6 +500,8 @@ TEST(DisableExtensions, IsDisabled) { EXPECT_NE(Registry::FactoryRegistry::getFactory("test"), nullptr); EXPECT_NE(Registry::FactoryRegistry::getFactory("test-1"), nullptr); EXPECT_NE(Registry::FactoryRegistry::getFactory("test-2"), nullptr); + EXPECT_NE(Registry::FactoryRegistry::getFactoryByType("google.protobuf.StringValue"), + nullptr); EXPECT_NE(Registry::FactoryRegistry::getFactory("test"), nullptr); EXPECT_NE(Registry::FactoryRegistry::getFactory("test-1"), nullptr); @@ -502,6 +518,30 @@ TEST(DisableExtensions, IsDisabled) { EXPECT_EQ(Registry::FactoryRegistry::getFactory("test"), nullptr); EXPECT_EQ(Registry::FactoryRegistry::getFactory("test-1"), nullptr); EXPECT_EQ(Registry::FactoryRegistry::getFactory("test-2"), nullptr); + + // Typing map for TestingFactory should be constructed here after disabling + EXPECT_EQ( + Registry::FactoryRegistry::getFactoryByType("google.protobuf.StringValue"), + nullptr); +} + +TEST(FactoryByTypeTest, EarlierVersionConfigType) { + envoy::config::filter::http::ip_tagging::v2::IPTagging v2_config; + auto factory = Registry::FactoryRegistry:: + getFactoryByType(v2_config.GetDescriptor()->full_name()); + EXPECT_NE(factory, nullptr); + EXPECT_EQ(factory->name(), Extensions::HttpFilters::HttpFilterNames::get().IpTagging); + + envoy::extensions::filters::http::ip_tagging::v3::IPTagging v3_config; + factory = Registry::FactoryRegistry:: + getFactoryByType(v3_config.GetDescriptor()->full_name()); + EXPECT_NE(factory, nullptr); + EXPECT_EQ(factory->name(), Extensions::HttpFilters::HttpFilterNames::get().IpTagging); + + ProtobufWkt::Any non_api_type; + factory = Registry::FactoryRegistry:: + getFactoryByType(non_api_type.GetDescriptor()->full_name()); + EXPECT_EQ(factory, nullptr); } } // namespace diff --git a/test/test_common/registry.h b/test/test_common/registry.h index ccbbac80ef66f..85a3b7990026d 100644 --- a/test/test_common/registry.h +++ b/test/test_common/registry.h @@ -24,7 +24,8 @@ template class InjectFactory { auto injected = Registry::FactoryRegistry::replaceFactoryForTest(*displaced_); EXPECT_EQ(injected, &instance_); } else { - Registry::FactoryRegistry::removeFactoryForTest(instance_.name()); + Registry::FactoryRegistry::removeFactoryForTest(instance_.name(), + instance_.configType()); } }