diff --git a/bazel/repositories.bzl b/bazel/repositories.bzl index 827cd624a7985..504a85122a6fc 100644 --- a/bazel/repositories.bzl +++ b/bazel/repositories.bzl @@ -106,15 +106,15 @@ def envoy_api_deps(skip_targets): native.git_repository( name = "envoy_api", remote = REPO_LOCATIONS["envoy_api"], - commit = "8047d578919175cdcaddad8364511d77db5bba87", + commit = "422332bf5fb251904dd53ed8cbb5f28e892ed69d", ) native.bind( name = "envoy_base", - actual = "@envoy_api//api:base", + actual = "@envoy_api//api:base_cc", ) native.bind( name = "envoy_eds", - actual = "@envoy_api//api:eds", + actual = "@envoy_api//api:eds_cc", ) native.bind( name = "http_api_protos", diff --git a/source/common/config/BUILD b/source/common/config/BUILD index e9e135dab084a..b2900bbecee39 100644 --- a/source/common/config/BUILD +++ b/source/common/config/BUILD @@ -64,6 +64,14 @@ envoy_cc_library( ], ) +envoy_cc_library( + name = "metadata_lib", + srcs = ["metadata.cc"], + hdrs = ["metadata.h"], + external_deps = ["envoy_base"], + deps = ["//source/common/common:singleton"], +) + envoy_cc_library( name = "utility_lib", srcs = ["utility.cc"], diff --git a/source/common/config/metadata.cc b/source/common/config/metadata.cc new file mode 100644 index 0000000000000..7312b0fbab0f0 --- /dev/null +++ b/source/common/config/metadata.cc @@ -0,0 +1,27 @@ +#include "common/config/metadata.h" + +namespace Envoy { +namespace Config { + +const google::protobuf::Value& Metadata::metadataValue(const envoy::api::v2::Metadata& metadata, + const std::string& filter, + const std::string& key) { + const auto filter_it = metadata.filter_metadata().find(filter); + if (filter_it == metadata.filter_metadata().end()) { + return google::protobuf::Value::default_instance(); + } + const auto fields_it = filter_it->second.fields().find(key); + if (fields_it == filter_it->second.fields().end()) { + return google::protobuf::Value::default_instance(); + } + return fields_it->second; +} + +google::protobuf::Value& Metadata::mutableMetadataValue(envoy::api::v2::Metadata& metadata, + const std::string& filter, + const std::string& key) { + return (*(*metadata.mutable_filter_metadata())[filter].mutable_fields())[key]; +} + +} // namespace Config +} // namespace Envoy diff --git a/source/common/config/metadata.h b/source/common/config/metadata.h new file mode 100644 index 0000000000000..2b68bc7dd71fc --- /dev/null +++ b/source/common/config/metadata.h @@ -0,0 +1,63 @@ +#pragma once + +#include + +#include "common/common/singleton.h" + +#include "api/base.pb.h" + +namespace Envoy { +namespace Config { + +/** + * Config metadata helpers. + */ +class Metadata { +public: + /** + * Lookup value of a key for a given filter in Metadata. + * @param metadata reference. + * @param filter name. + * @param key for filter metadata. + * @return const google::protobuf::Value& value if found, empty if not found. + */ + static const google::protobuf::Value& metadataValue(const envoy::api::v2::Metadata& metadata, + const std::string& filter, + const std::string& key); + + /** + * Obtain mutable reference to metadata value for a given filter and key. + * @param metadata reference. + * @param filter name. + * @param key for filter metadata. + * @return google::protobuf::Value&. A Value message is created if not found. + */ + static google::protobuf::Value& mutableMetadataValue(envoy::api::v2::Metadata& metadata, + const std::string& filter, + const std::string& key); +}; + +/** + * Well-known metadata filter namespaces. + */ +class MetadataFilterValues { +public: + // Filter namespace for built-in load balancer. + const std::string ENVOY_LB = "envoy.lb"; +}; + +typedef ConstSingleton MetadataFilters; + +/** + * Keys for MetadataFilterConstants::ENVOY_LB metadata. + */ +class MetadataEnvoyLbKeyValues { +public: + // Key in envoy.lb filter namespace for endpoint canary bool value. + const std::string CANARY = "canary"; +}; + +typedef ConstSingleton MetadataEnvoyLbKeys; + +} // namespace Config +} // namespace Envoy diff --git a/source/common/upstream/BUILD b/source/common/upstream/BUILD index e39a58906e47f..9fe01683a8d32 100644 --- a/source/common/upstream/BUILD +++ b/source/common/upstream/BUILD @@ -172,6 +172,7 @@ envoy_cc_library( ":upstream_includes", "//include/envoy/config:subscription_interface", "//include/envoy/local_info:local_info_interface", + "//source/common/config:metadata_lib", "//source/common/config:subscription_factory_lib", "//source/common/config:utility_lib", "//source/common/network:address_lib", @@ -190,6 +191,7 @@ envoy_cc_library( deps = [ "//include/envoy/config:subscription_interface", "//source/common/common:assert_lib", + "//source/common/config:metadata_lib", "//source/common/config:utility_lib", "//source/common/http:headers_lib", "//source/common/http:rest_api_fetcher_lib", diff --git a/source/common/upstream/eds.cc b/source/common/upstream/eds.cc index 983f656bb1590..67c16f0780bc8 100644 --- a/source/common/upstream/eds.cc +++ b/source/common/upstream/eds.cc @@ -2,6 +2,7 @@ #include "envoy/common/exception.h" +#include "common/config/metadata.h" #include "common/config/subscription_factory.h" #include "common/config/utility.h" #include "common/network/address_impl.h" @@ -47,12 +48,16 @@ void EdsClusterImpl::onConfigUpdate(const ResourceVector& resources) { const std::string& zone = locality_lb_endpoint.locality().zone(); for (const auto& lb_endpoint : locality_lb_endpoint.lb_endpoints()) { - new_hosts.emplace_back(new HostImpl( - info_, "", - Network::Address::InstanceConstSharedPtr{new Network::Address::Ipv4Instance( - lb_endpoint.endpoint().address().socket_address().ip_address(), - lb_endpoint.endpoint().address().socket_address().port().value())}, - lb_endpoint.canary().value(), lb_endpoint.load_balancing_weight().value(), zone)); + const bool canary = Config::Metadata::metadataValue(lb_endpoint.metadata(), + Config::MetadataFilters::get().ENVOY_LB, + Config::MetadataEnvoyLbKeys::get().CANARY) + .bool_value(); + new_hosts.emplace_back( + new HostImpl(info_, "", + Network::Address::InstanceConstSharedPtr{new Network::Address::Ipv4Instance( + lb_endpoint.endpoint().address().socket_address().ip_address(), + lb_endpoint.endpoint().address().socket_address().port().value())}, + canary, lb_endpoint.load_balancing_weight().value(), zone)); } } diff --git a/source/common/upstream/sds_subscription.cc b/source/common/upstream/sds_subscription.cc index 668718dbf6134..0978e95a9fa04 100644 --- a/source/common/upstream/sds_subscription.cc +++ b/source/common/upstream/sds_subscription.cc @@ -6,6 +6,7 @@ #include "envoy/common/exception.h" +#include "common/config/metadata.h" #include "common/config/utility.h" #include "common/http/headers.h" #include "common/json/config_schemas.h" @@ -54,9 +55,10 @@ void SdsSubscription::parseResponse(const Http::Message& response) { auto* address = lb_endpoint->mutable_endpoint()->mutable_address()->mutable_socket_address(); address->set_ip_address(host->getString("ip_address")); address->mutable_port()->set_value(host->getInteger("port")); - // TODO(htuch): This will eventually be generalized metadata/labels, see - // https://github.com/lyft/envoy-api/issues/81. - lb_endpoint->mutable_canary()->set_value(canary); + Config::Metadata::mutableMetadataValue(*lb_endpoint->mutable_metadata(), + Config::MetadataFilters::get().ENVOY_LB, + Config::MetadataEnvoyLbKeys::get().CANARY) + .set_bool_value(canary); lb_endpoint->mutable_load_balancing_weight()->set_value(weight); } diff --git a/test/common/config/BUILD b/test/common/config/BUILD index 081fc710e2390..0253a092e8e2e 100644 --- a/test/common/config/BUILD +++ b/test/common/config/BUILD @@ -118,6 +118,12 @@ envoy_cc_test_library( deps = ["//test/mocks/stats:stats_mocks"], ) +envoy_cc_test( + name = "metadata_test", + srcs = ["metadata_test.cc"], + deps = ["//source/common/config:metadata_lib"], +) + envoy_cc_test( name = "utility_test", srcs = ["utility_test.cc"], diff --git a/test/common/config/metadata_test.cc b/test/common/config/metadata_test.cc new file mode 100644 index 0000000000000..9860a9b06a5d1 --- /dev/null +++ b/test/common/config/metadata_test.cc @@ -0,0 +1,24 @@ +#include "common/config/metadata.h" + +#include "gtest/gtest.h" + +namespace Envoy { +namespace Config { +namespace { + +TEST(MetadataTest, MetadataValue) { + envoy::api::v2::Metadata metadata; + Metadata::mutableMetadataValue(metadata, MetadataFilters::get().ENVOY_LB, + MetadataEnvoyLbKeys::get().CANARY) + .set_bool_value(true); + EXPECT_TRUE(Metadata::metadataValue(metadata, MetadataFilters::get().ENVOY_LB, + MetadataEnvoyLbKeys::get().CANARY) + .bool_value()); + EXPECT_FALSE(Metadata::metadataValue(metadata, "foo", "bar").bool_value()); + EXPECT_FALSE( + Metadata::metadataValue(metadata, MetadataFilters::get().ENVOY_LB, "bar").bool_value()); +} + +} // namespace +} // namespace Config +} // namespace Envoy diff --git a/test/common/upstream/sds_test.cc b/test/common/upstream/sds_test.cc index c11c1ad14763f..7c07000b8c093 100644 --- a/test/common/upstream/sds_test.cc +++ b/test/common/upstream/sds_test.cc @@ -26,6 +26,7 @@ namespace Envoy { using testing::DoAll; +using testing::InSequence; using testing::Invoke; using testing::NiceMock; using testing::Return; @@ -128,10 +129,10 @@ TEST_F(SdsTest, PoolFailure) { } TEST_F(SdsTest, NoHealthChecker) { + InSequence s; setupRequest(); cluster_->initialize(); - EXPECT_CALL(membership_updated_, ready()).Times(3); cluster_->addMemberUpdateCb( [&](const std::vector&, const std::vector&) -> void { membership_updated_.ready(); @@ -143,6 +144,7 @@ TEST_F(SdsTest, NoHealthChecker) { message->body().reset(new Buffer::OwnedImpl(Filesystem::fileReadToEnd( TestEnvironment::runfilesPath("test/common/upstream/test_data/sds_response.json")))); + EXPECT_CALL(membership_updated_, ready()).Times(2); EXPECT_CALL(*timer_, enableTimer(_)); callbacks_->onSuccess(std::move(message)); EXPECT_EQ(13UL, cluster_->hosts().size()); @@ -171,6 +173,7 @@ TEST_F(SdsTest, NoHealthChecker) { message->body().reset( new Buffer::OwnedImpl(Filesystem::fileReadToEnd(TestEnvironment::runfilesPath( "test/common/upstream/test_data/sds_response_weight_change.json")))); + EXPECT_CALL(membership_updated_, ready()); EXPECT_CALL(*timer_, enableTimer(_)); callbacks_->onSuccess(std::move(message)); EXPECT_EQ(13UL, cluster_->hosts().size()); @@ -216,9 +219,10 @@ TEST_F(SdsTest, NoHealthChecker) { } TEST_F(SdsTest, HealthChecker) { + InSequence s; MockHealthChecker* health_checker = new MockHealthChecker(); EXPECT_CALL(*health_checker, start()); - EXPECT_CALL(*health_checker, addHostCheckCompleteCb(_)).Times(2); + EXPECT_CALL(*health_checker, addHostCheckCompleteCb(_)); cluster_->setHealthChecker(HealthCheckerPtr{health_checker}); cluster_->setInitializedCb([&]() -> void { membership_updated_.ready(); }); @@ -232,6 +236,7 @@ TEST_F(SdsTest, HealthChecker) { message->body().reset(new Buffer::OwnedImpl(Filesystem::fileReadToEnd( TestEnvironment::runfilesPath("test/common/upstream/test_data/sds_response.json")))); + EXPECT_CALL(*health_checker, addHostCheckCompleteCb(_)); EXPECT_CALL(*timer_, enableTimer(_)); callbacks_->onSuccess(std::move(message)); EXPECT_EQ(13UL, cluster_->hosts().size());