diff --git a/include/envoy/network/BUILD b/include/envoy/network/BUILD index 270a45cf96f6..a492f4f94a68 100644 --- a/include/envoy/network/BUILD +++ b/include/envoy/network/BUILD @@ -65,3 +65,11 @@ envoy_cc_library( name = "listener_interface", hdrs = ["listener.h"], ) + +envoy_cc_library( + name = "resolver_interface", + hdrs = ["resolver.h"], + deps = [ + ":address_interface", + ], +) diff --git a/include/envoy/network/address.h b/include/envoy/network/address.h index 0aab5e84deb9..4479d9f9fae8 100644 --- a/include/envoy/network/address.h +++ b/include/envoy/network/address.h @@ -101,7 +101,8 @@ class Instance { bool operator!=(const Instance& rhs) const { return !operator==(rhs); } /** - * @return a human readable string for the address. + * @return a human readable string for the address that represents the + * physical/resolved address. * * This string will be in the following format: * For IPv4 addresses: "1.2.3.4:80" @@ -110,6 +111,15 @@ class Instance { */ virtual const std::string& asString() const PURE; + /** + * @return a human readable string for the address that represents the + * logical/unresolved name. + * + * This string has a source-dependent format and should preserve the original + * name for Address::Instances resolved by a Network::Address::Resolver. + */ + virtual const std::string& logicalName() const PURE; + /** * Bind a socket to this address. The socket should have been created with a call to socket() on * an Instance of the same address family. diff --git a/include/envoy/network/resolver.h b/include/envoy/network/resolver.h new file mode 100644 index 000000000000..b4c93bc145dc --- /dev/null +++ b/include/envoy/network/resolver.h @@ -0,0 +1,40 @@ +#pragma once + +#include + +#include +#include + +#include "envoy/common/pure.h" +#include "envoy/network/address.h" + +#include "api/address.pb.h" + +namespace Envoy { +namespace Network { +namespace Address { + +/** + * Interface for all network address resolvers. + */ +class Resolver { +public: + virtual ~Resolver() {} + + /** + * Resolve a custom address string and port to an Address::Instance. + * @param socket_address supplies the socket address to resolve. + * @return InstanceConstSharedPtr appropriate Address::Instance. + */ + virtual InstanceConstSharedPtr resolve(const envoy::api::v2::SocketAddress& socket_address) PURE; + + /** + * @return std::string the identifying name for a particular implementation of + * a resolver. + */ + virtual std::string name() const PURE; +}; + +} // namespace Address +} // namespace Network +} // namespace Envoy diff --git a/include/envoy/registry/registry.h b/include/envoy/registry/registry.h index 42f96dd44703..05e659bd8c57 100644 --- a/include/envoy/registry/registry.h +++ b/include/envoy/registry/registry.h @@ -46,6 +46,16 @@ template class FactoryRegistry { return it->second; } + /** + * Remove a factory by name. + */ + static void unregisterFactory(Base& factory) { + auto result = factories().erase(factory.name()); + if (result == 0) { + throw EnvoyException(fmt::format("No registration for name: '{}'", factory.name())); + } + } + private: /** * Gets the current map of factory implementations. @@ -73,10 +83,17 @@ template class RegisterFactory { /** * Contructor that registers an instance of the factory with the FactoryRegistry. */ - RegisterFactory() { - static T* instance = new T; - FactoryRegistry::registerFactory(*instance); - } + RegisterFactory() { FactoryRegistry::registerFactory(instance_); } + + /** + * Destructor that removes an instance of the factory from the FactoryRegistry. + */ + ~RegisterFactory() { FactoryRegistry::unregisterFactory(instance_); } + + T& testGetFactory() { return instance_; } + +private: + T instance_; }; } // namespace Registry diff --git a/source/common/config/well_known_names.h b/source/common/config/well_known_names.h index db097f3bee27..e6752050ab70 100644 --- a/source/common/config/well_known_names.h +++ b/source/common/config/well_known_names.h @@ -77,6 +77,17 @@ class NetworkFilterNameValues { typedef ConstSingleton NetworkFilterNames; +/** + * Well-known address resolver names. + */ +class AddressResolverNameValues { +public: + // Basic IP resolver + const std::string IP = "envoy.ip"; +}; + +typedef ConstSingleton AddressResolverNames; + /** * Well-known http filter names. */ diff --git a/source/common/network/BUILD b/source/common/network/BUILD index 8bd0c66c363a..5cdb0d2eeffe 100644 --- a/source/common/network/BUILD +++ b/source/common/network/BUILD @@ -132,6 +132,22 @@ envoy_cc_library( ], ) +envoy_cc_library( + name = "resolver_lib", + srcs = ["resolver_impl.cc"], + hdrs = ["resolver_impl.h"], + external_deps = ["envoy_base"], + deps = [ + ":utility_lib", + "//include/envoy/network:address_interface", + "//include/envoy/network:resolver_interface", + "//include/envoy/registry", + "//source/common/config:well_known_names", + "//source/common/network:address_lib", + "//source/common/protobuf", + ], +) + envoy_cc_library( name = "utility_lib", srcs = ["utility.cc"], diff --git a/source/common/network/address_impl.h b/source/common/network/address_impl.h index b6b8a4fa282a..5a2306adc851 100644 --- a/source/common/network/address_impl.h +++ b/source/common/network/address_impl.h @@ -48,6 +48,8 @@ class InstanceBase : public Instance { // Network::Address::Instance bool operator==(const Instance& rhs) const override { return asString() == rhs.asString(); } const std::string& asString() const override { return friendly_name_; } + // Default logical name is the human-readable name. + const std::string& logicalName() const override { return asString(); } Type type() const override { return type_; } protected: diff --git a/source/common/network/resolver_impl.cc b/source/common/network/resolver_impl.cc new file mode 100644 index 000000000000..64bec7b5b213 --- /dev/null +++ b/source/common/network/resolver_impl.cc @@ -0,0 +1,75 @@ +#include "common/network/resolver_impl.h" + +#include "envoy/common/exception.h" +#include "envoy/network/address.h" +#include "envoy/network/resolver.h" +#include "envoy/registry/registry.h" + +#include "common/config/well_known_names.h" +#include "common/network/address_impl.h" +#include "common/network/utility.h" + +#include "api/address.pb.h" + +namespace Envoy { +namespace Network { +namespace Address { + +/** + * Implementation of a resolver for IP addresses. + */ +class IpResolver : public Resolver { + +public: + InstanceConstSharedPtr resolve(const envoy::api::v2::SocketAddress& socket_address) override { + switch (socket_address.port_specifier_case()) { + case envoy::api::v2::SocketAddress::kPortValue: + // Default to port 0 if no port value is specified. + case envoy::api::v2::SocketAddress::PORT_SPECIFIER_NOT_SET: + return Network::Utility::parseInternetAddress(socket_address.address(), + socket_address.port_value()); + + default: + throw EnvoyException(fmt::format("IP resolver can't handle port specifier type {}", + socket_address.port_specifier_case())); + } + } + + std::string name() const override { return Config::AddressResolverNames::get().IP; } +}; + +/** + * Static registration for the IP resolver. @see RegisterFactory. + */ +static Registry::RegisterFactory ip_registered_; + +InstanceConstSharedPtr resolveProtoAddress(const envoy::api::v2::Address& address) { + switch (address.address_case()) { + case envoy::api::v2::Address::kSocketAddress: + return resolveProtoSocketAddress(address.socket_address()); + case envoy::api::v2::Address::kPipe: + return InstanceConstSharedPtr{new PipeInstance(address.pipe().path())}; + default: + throw EnvoyException("Address must be a socket or pipe: " + address.DebugString()); + } +} + +InstanceConstSharedPtr +resolveProtoSocketAddress(const envoy::api::v2::SocketAddress& socket_address) { + Resolver* resolver = nullptr; + const std::string& resolver_name = socket_address.resolver_name(); + if (resolver_name.empty()) { + resolver = + Registry::FactoryRegistry::getFactory(Config::AddressResolverNames::get().IP); + } else { + resolver = Registry::FactoryRegistry::getFactory(resolver_name); + } + if (resolver == nullptr) { + throw EnvoyException(fmt::format("Unknown address resolver: {}", resolver_name)); + } + return resolver->resolve(socket_address); +} + +} // namespace Address +} // namespace Network +} // namespace Envoy diff --git a/source/common/network/resolver_impl.h b/source/common/network/resolver_impl.h new file mode 100644 index 000000000000..30af33cb5a1c --- /dev/null +++ b/source/common/network/resolver_impl.h @@ -0,0 +1,30 @@ +#pragma once + +#include "envoy/network/address.h" +#include "envoy/network/connection.h" +#include "envoy/network/resolver.h" + +#include "common/network/address_impl.h" + +#include "api/address.pb.h" + +namespace Envoy { +namespace Network { +namespace Address { +/** + * Create an Instance from a envoy::api::v2::Address. + * @param address supplies the address proto to resolve. + * @return pointer to the Instance. + */ +Address::InstanceConstSharedPtr resolveProtoAddress(const envoy::api::v2::Address& address); + +/** + * Create an Instance from a envoy::api::v2::SocketAddress. + * @param address supplies the socket address proto to resolve. + * @return pointer to the Instance. + */ +Address::InstanceConstSharedPtr +resolveProtoSocketAddress(const envoy::api::v2::SocketAddress& address); +} // namespace Address +} // namespace Network +} // namespace Envoy diff --git a/source/common/network/utility.cc b/source/common/network/utility.cc index 091c7f5fccce..64172cd80d42 100644 --- a/source/common/network/utility.cc +++ b/source/common/network/utility.cc @@ -146,25 +146,6 @@ Address::InstanceConstSharedPtr Utility::copyInternetAddressAndPort(const Addres return std::make_shared(ip.addressAsString(), ip.port()); } -Address::InstanceConstSharedPtr Utility::fromProtoAddress(const envoy::api::v2::Address& address) { - switch (address.address_case()) { - case envoy::api::v2::Address::kSocketAddress: - return Utility::fromProtoSocketAddress(address.socket_address()); - case envoy::api::v2::Address::kPipe: - return Address::InstanceConstSharedPtr{new Address::PipeInstance(address.pipe().path())}; - default: - throw EnvoyException("Address must be a socket or pipe: " + address.DebugString()); - } -} - -Address::InstanceConstSharedPtr -Utility::fromProtoSocketAddress(const envoy::api::v2::SocketAddress& socket_address) { - // TODO(htuch): Support custom resolvers #1477. - ASSERT(socket_address.resolver_name().empty()); - ASSERT(socket_address.named_port().empty()); - return parseInternetAddress(socket_address.address(), socket_address.port_value()); -} - void Utility::throwWithMalformedIp(const std::string& ip_address) { throw EnvoyException(fmt::format("malformed IP address: {}", ip_address)); } diff --git a/source/common/network/utility.h b/source/common/network/utility.h index 9b0feac5bbc5..fc7ea76d8eb8 100644 --- a/source/common/network/utility.h +++ b/source/common/network/utility.h @@ -85,21 +85,6 @@ class Utility { */ static Address::InstanceConstSharedPtr parseInternetAddressAndPort(const std::string& ip_address); - /** - * Create an Instance from a envoy::api::v2::Address. - * @param address message. - * @return pointer to the Instance. - */ - static Address::InstanceConstSharedPtr fromProtoAddress(const envoy::api::v2::Address& address); - - /** - * Create an Instance from a envoy::api::v2::SocketAddress. - * @param socket address message. - * @return pointer to the Instance. - */ - static Address::InstanceConstSharedPtr - fromProtoSocketAddress(const envoy::api::v2::SocketAddress& address); - /** * Get the local address of the first interface address that is of type * version and is not a loopback address. If no matches are found, return the diff --git a/source/common/upstream/BUILD b/source/common/upstream/BUILD index b8c2445bead3..be69120578ca 100644 --- a/source/common/upstream/BUILD +++ b/source/common/upstream/BUILD @@ -70,6 +70,7 @@ envoy_cc_library( "//source/common/http:async_client_lib", "//source/common/http/http1:conn_pool_lib", "//source/common/http/http2:conn_pool_lib", + "//source/common/network:resolver_lib", "//source/common/network:utility_lib", "//source/common/protobuf:utility_lib", "//source/common/router:shadow_writer_lib", @@ -218,6 +219,7 @@ envoy_cc_library( "//source/common/config:utility_lib", "//source/common/config:well_known_names", "//source/common/network:address_lib", + "//source/common/network:resolver_lib", "//source/common/network:utility_lib", ], ) @@ -265,6 +267,7 @@ envoy_cc_library( "//source/common/config:tls_context_json_lib", "//source/common/http:utility_lib", "//source/common/network:address_lib", + "//source/common/network:resolver_lib", "//source/common/network:utility_lib", "//source/common/protobuf", "//source/common/protobuf:utility_lib", diff --git a/source/common/upstream/cluster_manager_impl.cc b/source/common/upstream/cluster_manager_impl.cc index 83514e468338..a02abf41870b 100644 --- a/source/common/upstream/cluster_manager_impl.cc +++ b/source/common/upstream/cluster_manager_impl.cc @@ -19,6 +19,7 @@ #include "common/http/http1/conn_pool.h" #include "common/http/http2/conn_pool.h" #include "common/json/config_schemas.h" +#include "common/network/resolver_impl.h" #include "common/network/utility.h" #include "common/protobuf/utility.h" #include "common/router/shadow_writer_impl.h" @@ -196,7 +197,7 @@ ClusterManagerImpl::ClusterManagerImpl(const envoy::api::v2::Bootstrap& bootstra } if (bootstrap.cluster_manager().upstream_bind_config().has_source_address()) { - source_address_ = Network::Utility::fromProtoSocketAddress( + source_address_ = Network::Address::resolveProtoSocketAddress( bootstrap.cluster_manager().upstream_bind_config().source_address()); } diff --git a/source/common/upstream/eds.cc b/source/common/upstream/eds.cc index 6072215b1fe6..6808465366bf 100644 --- a/source/common/upstream/eds.cc +++ b/source/common/upstream/eds.cc @@ -7,6 +7,7 @@ #include "common/config/utility.h" #include "common/config/well_known_names.h" #include "common/network/address_impl.h" +#include "common/network/resolver_impl.h" #include "common/network/utility.h" #include "common/upstream/sds_subscription.h" @@ -60,7 +61,7 @@ void EdsClusterImpl::onConfigUpdate(const ResourceVector& resources) { for (const auto& locality_lb_endpoint : cluster_load_assignment.endpoints()) { for (const auto& lb_endpoint : locality_lb_endpoint.lb_endpoints()) { new_hosts.emplace_back(new HostImpl( - info_, "", Network::Utility::fromProtoAddress(lb_endpoint.endpoint().address()), + info_, "", Network::Address::resolveProtoAddress(lb_endpoint.endpoint().address()), lb_endpoint.metadata(), lb_endpoint.load_balancing_weight().value(), locality_lb_endpoint.locality())); } diff --git a/source/common/upstream/upstream_impl.cc b/source/common/upstream/upstream_impl.cc index 3bd569b3b8b0..3ae6476f63cd 100644 --- a/source/common/upstream/upstream_impl.cc +++ b/source/common/upstream/upstream_impl.cc @@ -20,6 +20,7 @@ #include "common/config/tls_context_json.h" #include "common/http/utility.h" #include "common/network/address_impl.h" +#include "common/network/resolver_impl.h" #include "common/network/utility.h" #include "common/protobuf/protobuf.h" #include "common/protobuf/utility.h" @@ -41,7 +42,7 @@ getSourceAddress(const envoy::api::v2::Cluster& cluster, const Network::Address::InstanceConstSharedPtr source_address) { // The source address from cluster config takes precedence. if (cluster.upstream_bind_config().has_source_address()) { - return Network::Utility::fromProtoSocketAddress( + return Network::Address::resolveProtoSocketAddress( cluster.upstream_bind_config().source_address()); } // If there's no source address in the cluster config, use any default from the bootstrap proto. @@ -150,7 +151,7 @@ ClusterSharedPtr ClusterImplBase::create(const envoy::api::v2::Cluster& cluster, std::vector resolvers; resolvers.reserve(resolver_addrs.size()); for (const auto& resolver_addr : resolver_addrs) { - resolvers.push_back(Network::Utility::fromProtoAddress(resolver_addr)); + resolvers.push_back(Network::Address::resolveProtoAddress(resolver_addr)); } selected_dns_resolver = dispatcher.createDnsResolver(resolvers); } @@ -342,7 +343,7 @@ StaticClusterImpl::StaticClusterImpl(const envoy::api::v2::Cluster& cluster, HostVectorSharedPtr new_hosts(new std::vector()); for (const auto& host : cluster.hosts()) { new_hosts->emplace_back( - HostSharedPtr{new HostImpl(info_, "", Network::Utility::fromProtoAddress(host), + HostSharedPtr{new HostImpl(info_, "", Network::Address::resolveProtoAddress(host), envoy::api::v2::Metadata::default_instance(), 1, envoy::api::v2::Locality().default_instance())}); } diff --git a/source/server/BUILD b/source/server/BUILD index d998c2d01df9..e33387e6a8f3 100644 --- a/source/server/BUILD +++ b/source/server/BUILD @@ -40,6 +40,7 @@ envoy_cc_library( "//source/common/common:utility_lib", "//source/common/config:lds_json_lib", "//source/common/config:utility_lib", + "//source/common/network:resolver_lib", "//source/common/network:utility_lib", "//source/common/protobuf:utility_lib", "//source/common/ratelimit:ratelimit_lib", diff --git a/source/server/config/stats/BUILD b/source/server/config/stats/BUILD index 7c9b95170460..3048f8a08621 100644 --- a/source/server/config/stats/BUILD +++ b/source/server/config/stats/BUILD @@ -19,6 +19,7 @@ envoy_cc_library( "//include/envoy/registry", "//source/common/config:well_known_names", "//source/common/network:address_lib", + "//source/common/network:resolver_lib", "//source/common/stats:statsd_lib", "//source/server:configuration_lib", ], diff --git a/source/server/config/stats/statsd.cc b/source/server/config/stats/statsd.cc index 14615c15d1f4..5fa3b5a52ca8 100644 --- a/source/server/config/stats/statsd.cc +++ b/source/server/config/stats/statsd.cc @@ -5,6 +5,7 @@ #include "envoy/registry/registry.h" #include "common/config/well_known_names.h" +#include "common/network/resolver_impl.h" #include "common/stats/statsd.h" #include "api/bootstrap.pb.h" @@ -20,7 +21,7 @@ Stats::SinkPtr StatsdSinkFactory::createStatsSink(const Protobuf::Message& confi switch (statsd_sink.statsd_specifier_case()) { case envoy::api::v2::StatsdSink::kAddress: { Network::Address::InstanceConstSharedPtr address = - Network::Utility::fromProtoAddress(statsd_sink.address()); + Network::Address::resolveProtoAddress(statsd_sink.address()); ENVOY_LOG(info, "statsd UDP ip address: {}", address->asString()); return Stats::SinkPtr( new Stats::Statsd::UdpStatsdSink(server.threadLocal(), std::move(address))); diff --git a/source/server/configuration_impl.cc b/source/server/configuration_impl.cc index cfcb8da944fe..bba9b9006a92 100644 --- a/source/server/configuration_impl.cc +++ b/source/server/configuration_impl.cc @@ -123,7 +123,7 @@ InitialImpl::InitialImpl(const envoy::api::v2::Bootstrap& bootstrap) { admin_.access_log_path_ = admin.access_log_path(); admin_.profile_path_ = admin.profile_path().empty() ? "/var/log/envoy/envoy.prof" : admin.profile_path(); - admin_.address_ = Network::Utility::fromProtoAddress(admin.address()); + admin_.address_ = Network::Address::resolveProtoAddress(admin.address()); if (!bootstrap.flags_path().empty()) { flags_path_.value(bootstrap.flags_path()); diff --git a/source/server/configuration_impl.h b/source/server/configuration_impl.h index ee06faf824d5..6d4ea01cda0c 100644 --- a/source/server/configuration_impl.h +++ b/source/server/configuration_impl.h @@ -18,6 +18,7 @@ #include "common/common/logger.h" #include "common/json/json_loader.h" +#include "common/network/resolver_impl.h" #include "common/network/utility.h" #include "server/lds_api.h" diff --git a/test/common/network/BUILD b/test/common/network/BUILD index 746a555447f7..20cf438930fe 100644 --- a/test/common/network/BUILD +++ b/test/common/network/BUILD @@ -138,6 +138,18 @@ envoy_cc_test( ], ) +envoy_cc_test( + name = "resolver_test", + srcs = ["resolver_impl_test.cc"], + deps = [ + "//source/common/network:address_lib", + "//source/common/network:resolver_lib", + "//source/common/protobuf", + "//test/mocks/network:network_mocks", + "//test/test_common:environment_lib", + ], +) + envoy_cc_test( name = "utility_test", srcs = ["utility_test.cc"], diff --git a/test/common/network/resolver_impl_test.cc b/test/common/network/resolver_impl_test.cc new file mode 100644 index 000000000000..4be15c4bd435 --- /dev/null +++ b/test/common/network/resolver_impl_test.cc @@ -0,0 +1,153 @@ +#include +#include +#include + +#include "envoy/common/exception.h" +#include "envoy/network/resolver.h" +#include "envoy/registry/registry.h" + +#include "common/common/thread.h" +#include "common/network/address_impl.h" +#include "common/network/resolver_impl.h" + +#include "test/mocks/network/mocks.h" +#include "test/test_common/environment.h" +#include "test/test_common/utility.h" + +#include "api/address.pb.h" +#include "gtest/gtest.h" + +namespace Envoy { +namespace Network { +namespace Address { +class IpResolverTest : public testing::Test { +public: + Resolver* resolver_{Registry::FactoryRegistry::getFactory("envoy.ip")}; +}; + +TEST_F(IpResolverTest, Basic) { + envoy::api::v2::SocketAddress socket_address; + socket_address.set_address("1.2.3.4"); + socket_address.set_port_value(443); + auto address = resolver_->resolve(socket_address); + EXPECT_EQ(address->ip()->addressAsString(), "1.2.3.4"); + EXPECT_EQ(address->ip()->port(), 443); +} + +TEST_F(IpResolverTest, DisallowsNamedPort) { + envoy::api::v2::SocketAddress socket_address; + socket_address.set_address("1.2.3.4"); + socket_address.set_named_port("http"); + EXPECT_THROW_WITH_MESSAGE(resolver_->resolve(socket_address), EnvoyException, + fmt::format("IP resolver can't handle port specifier type {}", + envoy::api::v2::SocketAddress::kNamedPort)); +} + +TEST(ResolverTest, FromProtoAddress) { + envoy::api::v2::Address ipv4_address; + ipv4_address.mutable_socket_address()->set_address("1.2.3.4"); + ipv4_address.mutable_socket_address()->set_port_value(5); + EXPECT_EQ("1.2.3.4:5", resolveProtoAddress(ipv4_address)->asString()); + + envoy::api::v2::Address ipv6_address; + ipv4_address.mutable_socket_address()->set_address("1::1"); + ipv4_address.mutable_socket_address()->set_port_value(2); + EXPECT_EQ("[1::1]:2", resolveProtoAddress(ipv4_address)->asString()); + + envoy::api::v2::Address pipe_address; + pipe_address.mutable_pipe()->set_path("/foo/bar"); + EXPECT_EQ("/foo/bar", resolveProtoAddress(pipe_address)->asString()); +} + +class TestResolver : public Resolver { +public: + InstanceConstSharedPtr resolve(const envoy::api::v2::SocketAddress& socket_address) override { + const std::string logical = socket_address.address(); + const std::string physical = getPhysicalName(logical); + const std::string port = getPort(socket_address); + return InstanceConstSharedPtr{new MockResolvedAddress(fmt::format("{}:{}", logical, port), + fmt::format("{}:{}", physical, port))}; + } + + void addMapping(const std::string& logical, const std::string& physical) { + name_mappings_[logical] = physical; + } + + std::string name() const override { return "envoy.test.resolver"; } + +private: + std::string getPhysicalName(const std::string& logical) { + auto it = name_mappings_.find(logical); + if (it == name_mappings_.end()) { + throw EnvoyException("no such mapping exists"); + } + return it->second; + } + + std::string getPort(const envoy::api::v2::SocketAddress& socket_address) { + switch (socket_address.port_specifier_case()) { + case envoy::api::v2::SocketAddress::kNamedPort: + return socket_address.named_port(); + case envoy::api::v2::SocketAddress::kPortValue: + // default to port 0 if no port value is specified + case envoy::api::v2::SocketAddress::PORT_SPECIFIER_NOT_SET: + return fmt::format("{}", socket_address.port_value()); + + default: + throw EnvoyException( + fmt::format("Unknown port specifier type {}", socket_address.port_specifier_case())); + } + } + + std::map name_mappings_; +}; + +TEST(ResolverTest, NonStandardResolver) { + // TODO(akonradi) Use singleton override instead of adding and removing + // resolvers for this test once issue #1808 is resolved. + Registry::RegisterFactory register_resolver; + auto& test_resolver = register_resolver.testGetFactory(); + test_resolver.addMapping("foo", "1.2.3.4"); + test_resolver.addMapping("bar", "4.3.2.1"); + + { + envoy::api::v2::Address address; + auto socket = address.mutable_socket_address(); + socket->set_address("foo"); + socket->set_port_value(5); + socket->set_resolver_name("envoy.test.resolver"); + auto instance = resolveProtoAddress(address); + EXPECT_EQ("1.2.3.4:5", instance->asString()); + EXPECT_EQ("foo:5", instance->logicalName()); + } + { + envoy::api::v2::Address address; + auto socket = address.mutable_socket_address(); + socket->set_address("bar"); + socket->set_named_port("http"); + socket->set_resolver_name("envoy.test.resolver"); + auto instance = resolveProtoAddress(address); + EXPECT_EQ("4.3.2.1:http", instance->asString()); + EXPECT_EQ("bar:http", instance->logicalName()); + } +} + +TEST(ResolverTest, UninitializedAddress) { + envoy::api::v2::Address address; + EXPECT_THROW_WITH_MESSAGE(resolveProtoAddress(address), EnvoyException, + "Address must be a socket or pipe: "); +} + +TEST(ResolverTest, NoSuchResolver) { + envoy::api::v2::Address address; + auto socket = address.mutable_socket_address(); + socket->set_address("foo"); + socket->set_port_value(5); + socket->set_resolver_name("envoy.test.resolver"); + EXPECT_THROW_WITH_MESSAGE(resolveProtoAddress(address), EnvoyException, + "Unknown address resolver: envoy.test.resolver"); +} + +} // namespace Address +} // namespace Network +} // namespace Envoy diff --git a/test/common/network/utility_test.cc b/test/common/network/utility_test.cc index 956f82211311..7a1abd9923df 100644 --- a/test/common/network/utility_test.cc +++ b/test/common/network/utility_test.cc @@ -119,22 +119,6 @@ TEST(NetworkUtility, ParseInternetAddressAndPort) { EXPECT_EQ("[::1]:0", Utility::parseInternetAddressAndPort("[::1]:0")->asString()); } -TEST(NetworkUtility, FromProtoAddress) { - envoy::api::v2::Address ipv4_address; - ipv4_address.mutable_socket_address()->set_address("1.2.3.4"); - ipv4_address.mutable_socket_address()->set_port_value(5); - EXPECT_EQ("1.2.3.4:5", Utility::fromProtoAddress(ipv4_address)->asString()); - - envoy::api::v2::Address ipv6_address; - ipv4_address.mutable_socket_address()->set_address("1::1"); - ipv4_address.mutable_socket_address()->set_port_value(2); - EXPECT_EQ("[1::1]:2", Utility::fromProtoAddress(ipv4_address)->asString()); - - envoy::api::v2::Address pipe_address; - pipe_address.mutable_pipe()->set_path("/foo/bar"); - EXPECT_EQ("/foo/bar", Utility::fromProtoAddress(pipe_address)->asString()); -} - class NetworkUtilityGetLocalAddress : public testing::TestWithParam {}; INSTANTIATE_TEST_CASE_P(IpVersions, NetworkUtilityGetLocalAddress, diff --git a/test/mocks/network/mocks.h b/test/mocks/network/mocks.h index 73e370a36056..9024a1550583 100644 --- a/test/mocks/network/mocks.h +++ b/test/mocks/network/mocks.h @@ -249,5 +249,27 @@ class MockConnectionHandler : public ConnectionHandler { MOCK_METHOD0(stopListeners, void()); }; +class MockResolvedAddress : public Address::Instance { +public: + MockResolvedAddress(const std::string& logical, const std::string& physical) + : logical_(logical), physical_(physical) {} + + bool operator==(const Address::Instance& other) const override { + return asString() == other.asString(); + } + + MOCK_CONST_METHOD1(bind, int(int)); + MOCK_CONST_METHOD1(connect, int(int)); + MOCK_CONST_METHOD0(ip, Address::Ip*()); + MOCK_CONST_METHOD1(socket, int(Address::SocketType)); + MOCK_CONST_METHOD0(type, Address::Type()); + + const std::string& asString() const override { return physical_; } + const std::string& logicalName() const override { return logical_; } + + const std::string logical_; + const std::string physical_; +}; + } // namespace Network } // namespace Envoy