diff --git a/docs/configuration/cluster_manager/cds.rst b/docs/configuration/cluster_manager/cds.rst index 51870c22a9f5..8b7191abc1d1 100644 --- a/docs/configuration/cluster_manager/cds.rst +++ b/docs/configuration/cluster_manager/cds.rst @@ -59,6 +59,8 @@ CDS has a statistics tree rooted at *cluster_manager.cds.* with the following st :header: Name, Type, Description :widths: 1, 1, 2 + config_reload, Counter, Total API fetches that resulted in a config reload due to a different config update_attempt, Counter, Total API fetches attempted update_success, Counter, Total API fetches completed successfully update_failure, Counter, Total API fetches that failed (either network or schema errors) + version, Gauge, Hash of the contents from the last successful API fetch diff --git a/docs/configuration/cluster_manager/cluster_stats.rst b/docs/configuration/cluster_manager/cluster_stats.rst index 01bffed7f73d..a0c0f6a519bd 100644 --- a/docs/configuration/cluster_manager/cluster_stats.rst +++ b/docs/configuration/cluster_manager/cluster_stats.rst @@ -61,9 +61,11 @@ Every cluster has a statistics tree rooted at *cluster..* with the followi membership_healthy, Gauge, Current cluster healthy total (inclusive of both health checking and outlier detection) membership_total, Gauge, Current cluster membership total retry_or_shadow_abandoned, Counter, Total number of times shadowing or retry buffering was canceled due to buffer limits. + config_reload, Counter, Total API fetches that resulted in a config reload due to a different config update_attempt, Counter, Total cluster membership update attempts update_success, Counter, Total cluster membership update successes update_failure, Counter, Total cluster membership update failures + version, Gauge, Hash of the contents from the last successful API fetch max_host_weight, Gauge, Maximum weight of any host in the cluster bind_errors, Counter, Total errors binding the socket to the configured source address. diff --git a/docs/configuration/http_conn_man/rds.rst b/docs/configuration/http_conn_man/rds.rst index 49d995f44cb4..a8e3205250b6 100644 --- a/docs/configuration/http_conn_man/rds.rst +++ b/docs/configuration/http_conn_man/rds.rst @@ -69,7 +69,9 @@ will only perform a full reload if the hash value changes. Statistics ---------- -RDS has a statistics tree rooted at *http..rds.* with the following statistics: +RDS has a statistics tree rooted at *http..rds..*. +Any ``:`` character in the ``route_config_name`` name gets replaced with ``_`` in the +stats tree. The stats tree contains the following statistics: .. csv-table:: :header: Name, Type, Description @@ -79,3 +81,4 @@ RDS has a statistics tree rooted at *http..rds.* with the following update_attempt, Counter, Total API fetches attempted update_success, Counter, Total API fetches completed successfully update_failure, Counter, Total API fetches that failed (either network or schema errors) + version, Gauge, Hash of the contents from the last successful API fetch diff --git a/docs/configuration/listeners/lds.rst b/docs/configuration/listeners/lds.rst index 054ad87f5a1f..27867b6b48e3 100644 --- a/docs/configuration/listeners/lds.rst +++ b/docs/configuration/listeners/lds.rst @@ -77,6 +77,8 @@ LDS has a statistics tree rooted at *listener_manager.lds.* with the following s :header: Name, Type, Description :widths: 1, 1, 2 + config_reload, Counter, Total API fetches that resulted in a config reload due to a different config update_attempt, Counter, Total API fetches attempted update_success, Counter, Total API fetches completed successfully update_failure, Counter, Total API fetches that failed (either network or schema errors) + version, Gauge, Hash of the contents from the last successful API fetch diff --git a/include/envoy/config/subscription.h b/include/envoy/config/subscription.h index 5d45017edf78..ad164bcc3c1b 100644 --- a/include/envoy/config/subscription.h +++ b/include/envoy/config/subscription.h @@ -75,18 +75,19 @@ template class Subscription { * Per subscription stats. @see stats_macros.h */ // clang-format off -#define ALL_SUBSCRIPTION_STATS(COUNTER) \ - COUNTER(update_attempt) \ - COUNTER(update_success) \ - COUNTER(update_failure) \ - COUNTER(update_rejected) +#define ALL_SUBSCRIPTION_STATS(COUNTER, GAUGE) \ + COUNTER(update_attempt) \ + COUNTER(update_success) \ + COUNTER(update_failure) \ + COUNTER(update_rejected) \ + GAUGE(version) // clang-format on /** * Struct definition for per subscription stats. @see stats_macros.h */ struct SubscriptionStats { - ALL_SUBSCRIPTION_STATS(GENERATE_COUNTER_STRUCT) + ALL_SUBSCRIPTION_STATS(GENERATE_COUNTER_STRUCT, GENERATE_GAUGE_STRUCT) }; } // namespace Config diff --git a/include/envoy/upstream/upstream.h b/include/envoy/upstream/upstream.h index 9b219486d0e4..d8144335b5ad 100644 --- a/include/envoy/upstream/upstream.h +++ b/include/envoy/upstream/upstream.h @@ -235,7 +235,8 @@ class HostSet { COUNTER(update_attempt) \ COUNTER(update_success) \ COUNTER(update_failure) \ - COUNTER(update_empty) + COUNTER(update_empty) \ + GAUGE(version) // clang-format on diff --git a/source/common/config/filesystem_subscription_impl.h b/source/common/config/filesystem_subscription_impl.h index e695865bd213..1bf5bd22e8fd 100644 --- a/source/common/config/filesystem_subscription_impl.h +++ b/source/common/config/filesystem_subscription_impl.h @@ -63,6 +63,7 @@ class FilesystemSubscriptionImpl : public Config::Subscription, config_update_available = true; callbacks_->onConfigUpdate(typed_resources); version_info_ = message.version_info(); + stats_.version_.set(HashUtil::xxHash64(version_info_)); stats_.update_success_.inc(); ENVOY_LOG(debug, "Filesystem config update accepted for {}: {}", path_, message.DebugString()); diff --git a/source/common/config/grpc_mux_subscription_impl.h b/source/common/config/grpc_mux_subscription_impl.h index 48dd6fd4d847..2e473f7d0eee 100644 --- a/source/common/config/grpc_mux_subscription_impl.h +++ b/source/common/config/grpc_mux_subscription_impl.h @@ -55,6 +55,7 @@ class GrpcMuxSubscriptionImpl : public Subscription, stats_.update_success_.inc(); stats_.update_attempt_.inc(); version_info_ = version_info; + stats_.version_.set(HashUtil::xxHash64(version_info_)); ENVOY_LOG(debug, "gRPC config for {} accepted with {} resources", type_url_, resources.size()); #ifndef NVLOG diff --git a/source/common/config/http_subscription_impl.h b/source/common/config/http_subscription_impl.h index ace175c20283..8da4312e05d0 100644 --- a/source/common/config/http_subscription_impl.h +++ b/source/common/config/http_subscription_impl.h @@ -83,6 +83,7 @@ class HttpSubscriptionImpl : public Http::RestApiFetcher, try { callbacks_->onConfigUpdate(typed_resources); request_.set_version_info(message.version_info()); + stats_.version_.set(HashUtil::xxHash64(request_.version_info())); stats_.update_success_.inc(); } catch (const EnvoyException& e) { ENVOY_LOG(warn, "REST config update rejected: {}", e.what()); diff --git a/source/common/config/utility.h b/source/common/config/utility.h index ab66a1d447e7..6e54bac4b42b 100644 --- a/source/common/config/utility.h +++ b/source/common/config/utility.h @@ -5,6 +5,7 @@ #include "envoy/json/json_object.h" #include "envoy/local_info/local_info.h" #include "envoy/registry/registry.h" +#include "envoy/stats/stats.h" #include "envoy/upstream/cluster_manager.h" #include "common/common/assert.h" @@ -59,11 +60,15 @@ class Utility { } /** - * Legacy APIs uses JSON and do not have an explicit version. Hash the body and append - * a user-friendly prefix. + * Legacy APIs uses JSON and do not have an explicit version. + * @param input the input to hash. + * @return std::pair the string is the hash converted into + * a hex string, pre-pended by a user friendly prefix. The uint64_t is the + * raw hash. */ - static std::string computeHashedVersion(const std::string& input) { - return "hash_" + Hex::uint64ToHex(HashUtil::xxHash64(input)); + static std::pair computeHashedVersion(const std::string& input) { + uint64_t hash = HashUtil::xxHash64(input); + return std::make_pair("hash_" + Hex::uint64ToHex(hash), hash); } /** @@ -149,7 +154,7 @@ class Utility { * @return SubscriptionStats for scope. */ static SubscriptionStats generateStats(Stats::Scope& scope) { - return {ALL_SUBSCRIPTION_STATS(POOL_COUNTER(scope))}; + return {ALL_SUBSCRIPTION_STATS(POOL_COUNTER(scope), POOL_GAUGE(scope))}; } /** diff --git a/source/common/router/rds_impl.cc b/source/common/router/rds_impl.cc index 84e24aa22004..3dcc82467022 100644 --- a/source/common/router/rds_impl.cc +++ b/source/common/router/rds_impl.cc @@ -47,7 +47,8 @@ RdsRouteConfigProviderImpl::RdsRouteConfigProviderImpl( const std::string& stat_prefix, ThreadLocal::SlotAllocator& tls, RouteConfigProviderManagerImpl& route_config_provider_manager) : runtime_(runtime), cm_(cm), tls_(tls.allocateSlot()), - route_config_name_(rds.route_config_name()), scope_(scope.createScope(stat_prefix + "rds.")), + route_config_name_(rds.route_config_name()), + scope_(scope.createScope(stat_prefix + "rds." + route_config_name_ + ".")), stats_({ALL_RDS_STATS(POOL_COUNTER(*scope_))}), route_config_provider_manager_(route_config_provider_manager), manager_identifier_(manager_identifier) { diff --git a/source/common/router/rds_subscription.cc b/source/common/router/rds_subscription.cc index 313b90d982c9..8ff2ece083a6 100644 --- a/source/common/router/rds_subscription.cc +++ b/source/common/router/rds_subscription.cc @@ -49,7 +49,10 @@ void RdsSubscription::parseResponse(const Http::Message& response) { Envoy::Config::RdsJson::translateRouteConfiguration(*response_json, *resources.Add()); resources[0].set_name(route_config_name_); callbacks_->onConfigUpdate(resources); - version_info_ = Envoy::Config::Utility::computeHashedVersion(response_body); + std::pair hash = + Envoy::Config::Utility::computeHashedVersion(response_body); + version_info_ = hash.first; + stats_.version_.set(hash.second); stats_.update_success_.inc(); } diff --git a/source/common/upstream/cds_subscription.cc b/source/common/upstream/cds_subscription.cc index 0feac2866534..c9db2b90ab86 100644 --- a/source/common/upstream/cds_subscription.cc +++ b/source/common/upstream/cds_subscription.cc @@ -52,7 +52,10 @@ void CdsSubscription::parseResponse(const Http::Message& response) { } callbacks_->onConfigUpdate(resources); - version_info_ = Config::Utility::computeHashedVersion(response_body); + std::pair hash = + Envoy::Config::Utility::computeHashedVersion(response_body); + version_info_ = hash.first; + stats_.version_.set(hash.second); stats_.update_success_.inc(); } diff --git a/source/common/upstream/sds_subscription.cc b/source/common/upstream/sds_subscription.cc index 160627c0a5cf..70a8095eedda 100644 --- a/source/common/upstream/sds_subscription.cc +++ b/source/common/upstream/sds_subscription.cc @@ -73,7 +73,10 @@ void SdsSubscription::parseResponse(const Http::Message& response) { } callbacks_->onConfigUpdate(resources); - version_info_ = Config::Utility::computeHashedVersion(response_body); + std::pair hash = + Envoy::Config::Utility::computeHashedVersion(response_body); + version_info_ = hash.first; + stats_.version_.set(hash.second); stats_.update_success_.inc(); } diff --git a/source/server/lds_subscription.cc b/source/server/lds_subscription.cc index ba37e43c1c49..6e8c66a03723 100644 --- a/source/server/lds_subscription.cc +++ b/source/server/lds_subscription.cc @@ -52,7 +52,10 @@ void LdsSubscription::parseResponse(const Http::Message& response) { } callbacks_->onConfigUpdate(resources); - version_info_ = Config::Utility::computeHashedVersion(response_body); + std::pair hash = + Envoy::Config::Utility::computeHashedVersion(response_body); + version_info_ = hash.first; + stats_.version_.set(hash.second); stats_.update_success_.inc(); } diff --git a/test/common/config/filesystem_subscription_impl_test.cc b/test/common/config/filesystem_subscription_impl_test.cc index 6f04814714a9..36be2b0f10aa 100644 --- a/test/common/config/filesystem_subscription_impl_test.cc +++ b/test/common/config/filesystem_subscription_impl_test.cc @@ -12,19 +12,19 @@ class FilesystemSubscriptionImplTest : public FilesystemSubscriptionTestHarness, // Validate that the client can recover from bad JSON responses. TEST_F(FilesystemSubscriptionImplTest, BadJsonRecovery) { startSubscription({"cluster0", "cluster1"}); - verifyStats(1, 0, 0, 0); + verifyStats(1, 0, 0, 0, 0); EXPECT_CALL(callbacks_, onConfigUpdateFailed(_)); updateFile(";!@#badjso n"); - verifyStats(2, 0, 0, 1); + verifyStats(2, 0, 0, 1, 0); deliverConfigUpdate({"cluster0", "cluster1"}, "0", true); - verifyStats(3, 1, 0, 1); + verifyStats(3, 1, 0, 1, 7148434200721666028); } // Validate that a file that is initially available results in a successful update. TEST_F(FilesystemSubscriptionImplTest, InitialFile) { updateFile("{\"versionInfo\": \"0\", \"resources\": []}", false); startSubscription({"cluster0", "cluster1"}); - verifyStats(1, 1, 0, 0); + verifyStats(1, 1, 0, 0, 7148434200721666028); } } // namespace diff --git a/test/common/config/filesystem_subscription_test_harness.h b/test/common/config/filesystem_subscription_test_harness.h index 0cc9c7251d37..765e00c5ccff 100644 --- a/test/common/config/filesystem_subscription_test_harness.h +++ b/test/common/config/filesystem_subscription_test_harness.h @@ -83,11 +83,11 @@ class FilesystemSubscriptionTestHarness : public SubscriptionTestHarness { EXPECT_EQ(version_, subscription_.versionInfo()); } - void verifyStats(uint32_t attempt, uint32_t success, uint32_t rejected, - uint32_t failure) override { + void verifyStats(uint32_t attempt, uint32_t success, uint32_t rejected, uint32_t failure, + uint64_t version) override { // The first attempt always fail unless there was a file there to begin with. SubscriptionTestHarness::verifyStats(attempt, success, rejected, - failure + (file_at_start_ ? 0 : 1)); + failure + (file_at_start_ ? 0 : 1), version); } const std::string path_; diff --git a/test/common/config/grpc_subscription_impl_test.cc b/test/common/config/grpc_subscription_impl_test.cc index f61ebdd470eb..452b7da7870c 100644 --- a/test/common/config/grpc_subscription_impl_test.cc +++ b/test/common/config/grpc_subscription_impl_test.cc @@ -17,7 +17,7 @@ TEST_F(GrpcSubscriptionImplTest, StreamCreationFailure) { EXPECT_CALL(callbacks_, onConfigUpdateFailed(_)); EXPECT_CALL(*timer_, enableTimer(_)); subscription_->start({"cluster0", "cluster1"}, callbacks_); - verifyStats(2, 0, 0, 1); + verifyStats(2, 0, 0, 1, 0); // Ensure this doesn't cause an issue by sending a request, since we don't // have a gRPC stream. subscription_->updateResources({"cluster2"}); @@ -25,24 +25,24 @@ TEST_F(GrpcSubscriptionImplTest, StreamCreationFailure) { EXPECT_CALL(*async_client_, start(_, _)).WillOnce(Return(&async_stream_)); expectSendMessage({"cluster2"}, ""); timer_cb_(); - verifyStats(3, 0, 0, 1); + verifyStats(3, 0, 0, 1, 0); } // Validate that the client can recover from a remote stream closure via retry. TEST_F(GrpcSubscriptionImplTest, RemoteStreamClose) { startSubscription({"cluster0", "cluster1"}); - verifyStats(1, 0, 0, 0); + verifyStats(1, 0, 0, 0, 0); Http::HeaderMapPtr trailers{new Http::TestHeaderMapImpl{}}; subscription_->grpcMux().onReceiveTrailingMetadata(std::move(trailers)); EXPECT_CALL(*timer_, enableTimer(_)); EXPECT_CALL(callbacks_, onConfigUpdateFailed(_)); subscription_->grpcMux().onRemoteClose(Grpc::Status::GrpcStatus::Canceled, ""); - verifyStats(2, 0, 0, 1); + verifyStats(2, 0, 0, 1, 0); // Retry and succeed. EXPECT_CALL(*async_client_, start(_, _)).WillOnce(Return(&async_stream_)); expectSendMessage({"cluster0", "cluster1"}, ""); timer_cb_(); - verifyStats(2, 0, 0, 1); + verifyStats(2, 0, 0, 1, 0); } // Validate that When the management server gets multiple requests for the same version, it can @@ -50,21 +50,21 @@ TEST_F(GrpcSubscriptionImplTest, RemoteStreamClose) { TEST_F(GrpcSubscriptionImplTest, RepeatedNonce) { InSequence s; startSubscription({"cluster0", "cluster1"}); - verifyStats(1, 0, 0, 0); + verifyStats(1, 0, 0, 0, 0); // First with the initial, empty version update to "0". updateResources({"cluster2"}); - verifyStats(2, 0, 0, 0); + verifyStats(2, 0, 0, 0, 0); deliverConfigUpdate({"cluster0", "cluster2"}, "0", false); - verifyStats(3, 0, 1, 0); + verifyStats(3, 0, 1, 0, 0); deliverConfigUpdate({"cluster0", "cluster2"}, "0", true); - verifyStats(4, 1, 1, 0); + verifyStats(4, 1, 1, 0, 7148434200721666028); // Now with version "0" update to "1". updateResources({"cluster3"}); - verifyStats(5, 1, 1, 0); + verifyStats(5, 1, 1, 0, 7148434200721666028); deliverConfigUpdate({"cluster3"}, "1", false); - verifyStats(6, 1, 2, 0); + verifyStats(6, 1, 2, 0, 7148434200721666028); deliverConfigUpdate({"cluster3"}, "1", true); - verifyStats(7, 2, 2, 0); + verifyStats(7, 2, 2, 0, 13237225503670494420U); } } // namespace diff --git a/test/common/config/http_subscription_impl_test.cc b/test/common/config/http_subscription_impl_test.cc index 4018cdff2945..db09ce93963e 100644 --- a/test/common/config/http_subscription_impl_test.cc +++ b/test/common/config/http_subscription_impl_test.cc @@ -15,11 +15,11 @@ TEST_F(HttpSubscriptionImplTest, OnRequestReset) { EXPECT_CALL(*timer_, enableTimer(_)); EXPECT_CALL(callbacks_, onConfigUpdateFailed(_)); http_callbacks_->onFailure(Http::AsyncClient::FailureReason::Reset); - verifyStats(1, 0, 0, 1); + verifyStats(1, 0, 0, 1, 0); timerTick(); - verifyStats(2, 0, 0, 1); + verifyStats(2, 0, 0, 1, 0); deliverConfigUpdate({"cluster0", "cluster1"}, "0", true); - verifyStats(3, 1, 0, 1); + verifyStats(3, 1, 0, 1, 7148434200721666028); } // Validate that the client can recover from bad JSON responses. @@ -32,12 +32,12 @@ TEST_F(HttpSubscriptionImplTest, BadJsonRecovery) { EXPECT_CALL(*timer_, enableTimer(_)); EXPECT_CALL(callbacks_, onConfigUpdateFailed(_)); http_callbacks_->onSuccess(std::move(message)); - verifyStats(1, 0, 0, 1); + verifyStats(1, 0, 0, 1, 0); request_in_progress_ = false; timerTick(); - verifyStats(2, 0, 0, 1); + verifyStats(2, 0, 0, 1, 0); deliverConfigUpdate({"cluster0", "cluster1"}, "0", true); - verifyStats(3, 1, 0, 1); + verifyStats(3, 1, 0, 1, 7148434200721666028); } } // namespace diff --git a/test/common/config/subscription_impl_test.cc b/test/common/config/subscription_impl_test.cc index 9ebcf9af9130..5e68ea9f9712 100644 --- a/test/common/config/subscription_impl_test.cc +++ b/test/common/config/subscription_impl_test.cc @@ -42,8 +42,9 @@ class SubscriptionImplTest : public testing::TestWithParam { test_harness_->expectSendMessage(cluster_names, version); } - void verifyStats(uint32_t attempt, uint32_t success, uint32_t rejected, uint32_t failure) { - test_harness_->verifyStats(attempt, success, rejected, failure); + void verifyStats(uint32_t attempt, uint32_t success, uint32_t rejected, uint32_t failure, + uint64_t version) { + test_harness_->verifyStats(attempt, success, rejected, failure, version); } void deliverConfigUpdate(const std::vector cluster_names, const std::string& version, @@ -61,57 +62,57 @@ INSTANTIATE_TEST_CASE_P(SubscriptionImplTest, SubscriptionImplTest, // Validate basic request-response succeeds. TEST_P(SubscriptionImplTest, InitialRequestResponse) { startSubscription({"cluster0", "cluster1"}); - verifyStats(1, 0, 0, 0); + verifyStats(1, 0, 0, 0, 0); deliverConfigUpdate({"cluster0", "cluster1"}, "0", true); - verifyStats(2, 1, 0, 0); + verifyStats(2, 1, 0, 0, 7148434200721666028); } // Validate that multiple streamed updates succeed. TEST_P(SubscriptionImplTest, ResponseStream) { startSubscription({"cluster0", "cluster1"}); - verifyStats(1, 0, 0, 0); + verifyStats(1, 0, 0, 0, 0); deliverConfigUpdate({"cluster0", "cluster1"}, "0", true); - verifyStats(2, 1, 0, 0); + verifyStats(2, 1, 0, 0, 7148434200721666028); deliverConfigUpdate({"cluster0", "cluster1"}, "1", true); - verifyStats(3, 2, 0, 0); + verifyStats(3, 2, 0, 0, 13237225503670494420U); } // Validate that the client can reject a config. TEST_P(SubscriptionImplTest, RejectConfig) { startSubscription({"cluster0", "cluster1"}); - verifyStats(1, 0, 0, 0); + verifyStats(1, 0, 0, 0, 0); deliverConfigUpdate({"cluster0", "cluster1"}, "0", false); - verifyStats(2, 0, 1, 0); + verifyStats(2, 0, 1, 0, 0); } // Validate that the client can reject a config and accept the same config later. TEST_P(SubscriptionImplTest, RejectAcceptConfig) { startSubscription({"cluster0", "cluster1"}); - verifyStats(1, 0, 0, 0); + verifyStats(1, 0, 0, 0, 0); deliverConfigUpdate({"cluster0", "cluster1"}, "0", false); - verifyStats(2, 0, 1, 0); + verifyStats(2, 0, 1, 0, 0); deliverConfigUpdate({"cluster0", "cluster1"}, "0", true); - verifyStats(3, 1, 1, 0); + verifyStats(3, 1, 1, 0, 7148434200721666028); } // Validate that the client can reject a config and accept another config later. TEST_P(SubscriptionImplTest, RejectAcceptNextConfig) { startSubscription({"cluster0", "cluster1"}); - verifyStats(1, 0, 0, 0); + verifyStats(1, 0, 0, 0, 0); deliverConfigUpdate({"cluster0", "cluster1"}, "0", false); - verifyStats(2, 0, 1, 0); + verifyStats(2, 0, 1, 0, 0); deliverConfigUpdate({"cluster0", "cluster1"}, "1", true); - verifyStats(3, 1, 1, 0); + verifyStats(3, 1, 1, 0, 13237225503670494420U); } // Validate that stream updates send a message with the updated resources. TEST_P(SubscriptionImplTest, UpdateResources) { startSubscription({"cluster0", "cluster1"}); - verifyStats(1, 0, 0, 0); + verifyStats(1, 0, 0, 0, 0); deliverConfigUpdate({"cluster0", "cluster1"}, "0", true); - verifyStats(2, 1, 0, 0); + verifyStats(2, 1, 0, 0, 7148434200721666028); updateResources({"cluster2"}); - verifyStats(3, 1, 0, 0); + verifyStats(3, 1, 0, 0, 7148434200721666028); } } // namespace diff --git a/test/common/config/subscription_test_harness.h b/test/common/config/subscription_test_harness.h index 7ea361fa25cf..05dcf3eb239b 100644 --- a/test/common/config/subscription_test_harness.h +++ b/test/common/config/subscription_test_harness.h @@ -49,12 +49,13 @@ class SubscriptionTestHarness { virtual void deliverConfigUpdate(const std::vector cluster_names, const std::string& version, bool accept) PURE; - virtual void verifyStats(uint32_t attempt, uint32_t success, uint32_t rejected, - uint32_t failure) { + virtual void verifyStats(uint32_t attempt, uint32_t success, uint32_t rejected, uint32_t failure, + uint64_t version) { EXPECT_EQ(attempt, stats_.update_attempt_.value()); EXPECT_EQ(success, stats_.update_success_.value()); EXPECT_EQ(rejected, stats_.update_rejected_.value()); EXPECT_EQ(failure, stats_.update_failure_.value()); + EXPECT_EQ(version, stats_.version_.value()); } Stats::MockIsolatedStatsStore stats_store_; diff --git a/test/common/config/utility_test.cc b/test/common/config/utility_test.cc index 5b653cf71a78..b5b6696ebad9 100644 --- a/test/common/config/utility_test.cc +++ b/test/common/config/utility_test.cc @@ -32,8 +32,8 @@ TEST(UtilityTest, GetTypedResources) { } TEST(UtilityTest, ComputeHashedVersion) { - EXPECT_EQ("hash_2e1472b57af294d1", Utility::computeHashedVersion("{}")); - EXPECT_EQ("hash_33bf00a859c4ba3f", Utility::computeHashedVersion("foo")); + EXPECT_EQ("hash_2e1472b57af294d1", Utility::computeHashedVersion("{}").first); + EXPECT_EQ("hash_33bf00a859c4ba3f", Utility::computeHashedVersion("foo").first); } TEST(UtilityTest, ApiConfigSourceRefreshDelay) { diff --git a/test/common/router/rds_impl_test.cc b/test/common/router/rds_impl_test.cc index 5c9d88e8b423..58196f4cb0a0 100644 --- a/test/common/router/rds_impl_test.cc +++ b/test/common/router/rds_impl_test.cc @@ -213,6 +213,7 @@ TEST_F(RdsImplTest, Basic) { EXPECT_EQ(Http::Code::OK, handler_callback_("/routes", data)); EXPECT_EQ(routes_expected_output_no_routes, TestUtility::bufferToString(data)); data.drain(data.length()); + EXPECT_EQ(0UL, store_.gauge("foo.rds.foo_route_config.version").value()); // Initial request. const std::string response1_json = R"EOF( @@ -243,6 +244,7 @@ TEST_F(RdsImplTest, Basic) { EXPECT_EQ(Http::Code::OK, handler_callback_("/routes", data)); EXPECT_EQ(routes_expected_output_only_name, TestUtility::bufferToString(data)); data.drain(data.length()); + EXPECT_EQ(1580011435426663819U, store_.gauge("foo.rds.foo_route_config.version").value()); expectRequest(); interval_timer_->callback_(); @@ -260,6 +262,7 @@ TEST_F(RdsImplTest, Basic) { EXPECT_EQ(Http::Code::OK, handler_callback_("/routes", data)); EXPECT_EQ(routes_expected_output_only_name, TestUtility::bufferToString(data)); data.drain(data.length()); + EXPECT_EQ(1580011435426663819U, store_.gauge("foo.rds.foo_route_config.version").value()); expectRequest(); interval_timer_->callback_(); @@ -317,6 +320,7 @@ TEST_F(RdsImplTest, Basic) { EXPECT_EQ(Http::Code::OK, handler_callback_("/routes", data)); EXPECT_EQ(routes_expected_output_full_table, TestUtility::bufferToString(data)); data.drain(data.length()); + EXPECT_EQ(8808926191882896258U, store_.gauge("foo.rds.foo_route_config.version").value()); // Test that we get the same dump if we specify the route name. EXPECT_EQ(Http::Code::OK, handler_callback_("/routes?route_config_name=foo_route_config", data)); @@ -341,9 +345,10 @@ TEST_F(RdsImplTest, Basic) { // Old config use count should be 1 now. EXPECT_EQ(1, config.use_count()); - EXPECT_EQ(2UL, store_.counter("foo.rds.config_reload").value()); - EXPECT_EQ(3UL, store_.counter("foo.rds.update_attempt").value()); - EXPECT_EQ(3UL, store_.counter("foo.rds.update_success").value()); + EXPECT_EQ(2UL, store_.counter("foo.rds.foo_route_config.config_reload").value()); + EXPECT_EQ(3UL, store_.counter("foo.rds.foo_route_config.update_attempt").value()); + EXPECT_EQ(3UL, store_.counter("foo.rds.foo_route_config.update_success").value()); + EXPECT_EQ(8808926191882896258U, store_.gauge("foo.rds.foo_route_config.version").value()); } TEST_F(RdsImplTest, Failure) { @@ -371,8 +376,8 @@ TEST_F(RdsImplTest, Failure) { EXPECT_CALL(*interval_timer_, enableTimer(_)); callbacks_->onFailure(Http::AsyncClient::FailureReason::Reset); - EXPECT_EQ(2UL, store_.counter("foo.rds.update_attempt").value()); - EXPECT_EQ(2UL, store_.counter("foo.rds.update_failure").value()); + EXPECT_EQ(2UL, store_.counter("foo.rds.foo_route_config.update_attempt").value()); + EXPECT_EQ(2UL, store_.counter("foo.rds.foo_route_config.update_failure").value()); } TEST_F(RdsImplTest, FailureArray) { @@ -392,8 +397,8 @@ TEST_F(RdsImplTest, FailureArray) { EXPECT_CALL(*interval_timer_, enableTimer(_)); callbacks_->onSuccess(std::move(message)); - EXPECT_EQ(1UL, store_.counter("foo.rds.update_attempt").value()); - EXPECT_EQ(1UL, store_.counter("foo.rds.update_failure").value()); + EXPECT_EQ(1UL, store_.counter("foo.rds.foo_route_config.update_attempt").value()); + EXPECT_EQ(1UL, store_.counter("foo.rds.foo_route_config.update_failure").value()); } class RouteConfigProviderManagerImplTest : public testing::Test { @@ -498,7 +503,7 @@ TEST_F(RouteConfigProviderManagerImplTest, onConfigUpdateEmpty) { auto& provider_impl = dynamic_cast(*provider.get()); EXPECT_CALL(init_manager_.initialized_, ready()); provider_impl.onConfigUpdate({}); - EXPECT_EQ(1UL, store_.counter("foo_prefix.rds.update_empty").value()); + EXPECT_EQ(1UL, store_.counter("foo_prefix.rds.foo_route_config.update_empty").value()); } TEST_F(RouteConfigProviderManagerImplTest, onConfigUpdateWrongSize) { diff --git a/test/common/upstream/cds_api_impl_test.cc b/test/common/upstream/cds_api_impl_test.cc index 30b0e4409d59..79a8a7d69977 100644 --- a/test/common/upstream/cds_api_impl_test.cc +++ b/test/common/upstream/cds_api_impl_test.cc @@ -132,8 +132,10 @@ TEST_F(CdsApiImplTest, Basic) { EXPECT_CALL(initialized_, ready()); EXPECT_CALL(*interval_timer_, enableTimer(_)); EXPECT_EQ("", cds_->versionInfo()); + EXPECT_EQ(0UL, store_.gauge("cluster_manager.cds.version").value()); callbacks_->onSuccess(std::move(message)); - EXPECT_EQ(Config::Utility::computeHashedVersion(response1_json), cds_->versionInfo()); + EXPECT_EQ(Config::Utility::computeHashedVersion(response1_json).first, cds_->versionInfo()); + EXPECT_EQ(4054905652974790809U, store_.gauge("cluster_manager.cds.version").value()); expectRequest(); interval_timer_->callback_(); @@ -155,7 +157,8 @@ TEST_F(CdsApiImplTest, Basic) { EXPECT_EQ(2UL, store_.counter("cluster_manager.cds.update_attempt").value()); EXPECT_EQ(2UL, store_.counter("cluster_manager.cds.update_success").value()); - EXPECT_EQ(Config::Utility::computeHashedVersion(response2_json), cds_->versionInfo()); + EXPECT_EQ(Config::Utility::computeHashedVersion(response2_json).first, cds_->versionInfo()); + EXPECT_EQ(1872764556139482420U, store_.gauge("cluster_manager.cds.version").value()); } TEST_F(CdsApiImplTest, Failure) { @@ -187,6 +190,7 @@ TEST_F(CdsApiImplTest, Failure) { EXPECT_EQ("", cds_->versionInfo()); EXPECT_EQ(2UL, store_.counter("cluster_manager.cds.update_attempt").value()); EXPECT_EQ(2UL, store_.counter("cluster_manager.cds.update_failure").value()); + EXPECT_EQ(0UL, store_.gauge("cluster_manager.cds.version").value()); } TEST_F(CdsApiImplTest, FailureArray) { @@ -210,6 +214,7 @@ TEST_F(CdsApiImplTest, FailureArray) { EXPECT_EQ("", cds_->versionInfo()); EXPECT_EQ(1UL, store_.counter("cluster_manager.cds.update_attempt").value()); EXPECT_EQ(1UL, store_.counter("cluster_manager.cds.update_failure").value()); + EXPECT_EQ(0UL, store_.gauge("cluster_manager.cds.version").value()); } } // namespace Upstream diff --git a/test/common/upstream/sds_test.cc b/test/common/upstream/sds_test.cc index ca8cbd05abc6..2bcedea06a1e 100644 --- a/test/common/upstream/sds_test.cc +++ b/test/common/upstream/sds_test.cc @@ -155,6 +155,7 @@ TEST_F(SdsTest, NoHealthChecker) { EXPECT_EQ(4UL, cluster_->healthyHostsPerLocality()[0].size()); EXPECT_EQ(5UL, cluster_->healthyHostsPerLocality()[1].size()); EXPECT_EQ(4UL, cluster_->healthyHostsPerLocality()[2].size()); + EXPECT_EQ(6860994315024339285U, cluster_->info()->stats().version_.value()); // Hosts in SDS and static clusters should have empty hostname EXPECT_EQ("", cluster_->hosts()[0]->hostname()); @@ -188,6 +189,7 @@ TEST_F(SdsTest, NoHealthChecker) { EXPECT_EQ(4UL, cluster_->healthyHostsPerLocality()[0].size()); EXPECT_EQ(5UL, cluster_->healthyHostsPerLocality()[1].size()); EXPECT_EQ(4UL, cluster_->healthyHostsPerLocality()[2].size()); + EXPECT_EQ(3250177750903005831U, cluster_->info()->stats().version_.value()); // Now test the failure case, our cluster size should not change. setupRequest(); @@ -219,6 +221,7 @@ TEST_F(SdsTest, NoHealthChecker) { EXPECT_EQ(4UL, cluster_->healthyHostsPerLocality()[0].size()); EXPECT_EQ(5UL, cluster_->healthyHostsPerLocality()[1].size()); EXPECT_EQ(4UL, cluster_->healthyHostsPerLocality()[2].size()); + EXPECT_EQ(3250177750903005831U, cluster_->info()->stats().version_.value()); } TEST_F(SdsTest, HealthChecker) { @@ -252,6 +255,7 @@ TEST_F(SdsTest, HealthChecker) { EXPECT_EQ(0UL, cluster_->healthyHostsPerLocality()[0].size()); EXPECT_EQ(0UL, cluster_->healthyHostsPerLocality()[1].size()); EXPECT_EQ(0UL, cluster_->healthyHostsPerLocality()[2].size()); + EXPECT_EQ(6860994315024339285U, cluster_->info()->stats().version_.value()); // Now run through and make all the hosts healthy except for the first one. for (size_t i = 1; i < cluster_->hosts().size(); i++) { @@ -277,6 +281,7 @@ TEST_F(SdsTest, HealthChecker) { EXPECT_EQ(4UL, cluster_->healthyHostsPerLocality()[0].size()); EXPECT_EQ(5UL, cluster_->healthyHostsPerLocality()[1].size()); EXPECT_EQ(4UL, cluster_->healthyHostsPerLocality()[2].size()); + EXPECT_EQ(6860994315024339285U, cluster_->info()->stats().version_.value()); // Now we will remove some hosts, but since they are all healthy, they shouldn't actually be gone. setupRequest(); @@ -297,6 +302,7 @@ TEST_F(SdsTest, HealthChecker) { EXPECT_EQ(4UL, cluster_->healthyHostsPerLocality()[0].size()); EXPECT_EQ(5UL, cluster_->healthyHostsPerLocality()[1].size()); EXPECT_EQ(4UL, cluster_->healthyHostsPerLocality()[2].size()); + EXPECT_EQ(4145707046791707664U, cluster_->info()->stats().version_.value()); // Now set one of the removed hosts to unhealthy, and return the same query again, this should // remove it. @@ -318,6 +324,7 @@ TEST_F(SdsTest, HealthChecker) { EXPECT_EQ(3UL, cluster_->healthyHostsPerLocality()[0].size()); EXPECT_EQ(5UL, cluster_->healthyHostsPerLocality()[1].size()); EXPECT_EQ(4UL, cluster_->healthyHostsPerLocality()[2].size()); + EXPECT_EQ(4145707046791707664U, cluster_->info()->stats().version_.value()); // Now add back one of the hosts that was previously missing but we still have and make sure // nothing changes. @@ -338,6 +345,7 @@ TEST_F(SdsTest, HealthChecker) { EXPECT_EQ(3UL, cluster_->healthyHostsPerLocality()[0].size()); EXPECT_EQ(5UL, cluster_->healthyHostsPerLocality()[1].size()); EXPECT_EQ(4UL, cluster_->healthyHostsPerLocality()[2].size()); + EXPECT_EQ(13400729244851125029U, cluster_->info()->stats().version_.value()); } TEST_F(SdsTest, Failure) { diff --git a/test/server/lds_api_test.cc b/test/server/lds_api_test.cc index d2206efb4ceb..7863338e45ff 100644 --- a/test/server/lds_api_test.cc +++ b/test/server/lds_api_test.cc @@ -157,7 +157,8 @@ TEST_F(LdsApiTest, Basic) { EXPECT_CALL(*interval_timer_, enableTimer(_)); callbacks_->onSuccess(std::move(message)); - EXPECT_EQ(Config::Utility::computeHashedVersion(response1_json), lds_->versionInfo()); + EXPECT_EQ(Config::Utility::computeHashedVersion(response1_json).first, lds_->versionInfo()); + EXPECT_EQ(15400115654359694268U, store_.gauge("listener_manager.lds.version").value()); expectRequest(); interval_timer_->callback_(); @@ -188,10 +189,11 @@ TEST_F(LdsApiTest, Basic) { EXPECT_CALL(listener_manager_, removeListener("listener2")).WillOnce(Return(true)); EXPECT_CALL(*interval_timer_, enableTimer(_)); callbacks_->onSuccess(std::move(message)); - EXPECT_EQ(Config::Utility::computeHashedVersion(response2_json), lds_->versionInfo()); + EXPECT_EQ(Config::Utility::computeHashedVersion(response2_json).first, lds_->versionInfo()); EXPECT_EQ(2UL, store_.counter("listener_manager.lds.update_attempt").value()); EXPECT_EQ(2UL, store_.counter("listener_manager.lds.update_success").value()); + EXPECT_EQ(18068408981723255507U, store_.gauge("listener_manager.lds.version").value()); } TEST_F(LdsApiTest, Failure) { @@ -222,6 +224,7 @@ TEST_F(LdsApiTest, Failure) { EXPECT_EQ(2UL, store_.counter("listener_manager.lds.update_attempt").value()); EXPECT_EQ(2UL, store_.counter("listener_manager.lds.update_failure").value()); + EXPECT_EQ(0UL, store_.gauge("listener_manager.lds.version").value()); } } // namespace Server