Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sds: allow multiple init managers share sds target #14357

Merged
merged 9 commits into from
Dec 16, 2020
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/root/version_history/current.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Bug Fixes
* http: sending CONNECT_ERROR for HTTP/2 where appropriate during CONNECT requests.
* proxy_proto: fixed a bug where the wrong downstream address got sent to upstream connections.
* proxy_proto: fixed a bug where network filters would not have the correct downstreamRemoteAddress() when accessed from the StreamInfo. This could result in incorrect enforcement of RBAC rules in the RBAC network filter (but not in the RBAC HTTP filter), or incorrect access log addresses from tcp_proxy.
* sds: fix a bug that clusters sharing same sds target are marked active immediately.
* tls: fix detection of the upstream connection close event.
* tls: fix read resumption after triggering buffer high-watermark and all remaining request/response bytes are stored in the SSL connection's internal buffers.
* udp: fixed issue in which receiving truncated UDP datagrams would cause Envoy to crash.
Expand Down
5 changes: 0 additions & 5 deletions source/common/secret/sds_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,6 @@ SdsApi::SdsApi(envoy::config::core::v3::ConfigSource sds_config, absl::string_vi
// This has to happen here (rather than in initialize()) as it can throw exceptions.
subscription_ = subscription_factory_.subscriptionFromConfigSource(
sds_config_, Grpc::Common::typeUrl(resource_name), *scope_, *this, resource_decoder_);

// TODO(JimmyCYJ): Implement chained_init_manager, so that multiple init_manager
// can be chained together to behave as one init_manager. In that way, we let
// two listeners which share same SdsApi to register at separate init managers, and
// each init manager has a chance to initialize its targets.
}

void SdsApi::resolveDataSource(const FileContentMap& files,
Expand Down
16 changes: 4 additions & 12 deletions source/common/secret/sds_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,13 +138,11 @@ class TlsCertificateSdsApi : public SdsApi, public TlsCertificateConfigProvider
// We need to do this early as we invoke the subscription factory during initialization, which
// is too late to throw.
Config::Utility::checkLocalInfo("TlsCertificateSdsApi", secret_provider_context.localInfo());
auto ret = std::make_shared<TlsCertificateSdsApi>(
return std::make_shared<TlsCertificateSdsApi>(
sds_config, sds_config_name, secret_provider_context.clusterManager().subscriptionFactory(),
secret_provider_context.dispatcher().timeSource(),
secret_provider_context.messageValidationVisitor(), secret_provider_context.stats(),
destructor_cb, secret_provider_context.dispatcher(), secret_provider_context.api());
secret_provider_context.initManager().add(*ret->initTarget());
return ret;
}

TlsCertificateSdsApi(const envoy::config::core::v3::ConfigSource& sds_config,
Expand Down Expand Up @@ -223,13 +221,11 @@ class CertificateValidationContextSdsApi : public SdsApi,
// is too late to throw.
Config::Utility::checkLocalInfo("CertificateValidationContextSdsApi",
secret_provider_context.localInfo());
auto ret = std::make_shared<CertificateValidationContextSdsApi>(
return std::make_shared<CertificateValidationContextSdsApi>(
sds_config, sds_config_name, secret_provider_context.clusterManager().subscriptionFactory(),
secret_provider_context.dispatcher().timeSource(),
secret_provider_context.messageValidationVisitor(), secret_provider_context.stats(),
destructor_cb, secret_provider_context.dispatcher(), secret_provider_context.api());
secret_provider_context.initManager().add(*ret->initTarget());
return ret;
}
CertificateValidationContextSdsApi(const envoy::config::core::v3::ConfigSource& sds_config,
const std::string& sds_config_name,
Expand Down Expand Up @@ -318,13 +314,11 @@ class TlsSessionTicketKeysSdsApi : public SdsApi, public TlsSessionTicketKeysCon
// is too late to throw.
Config::Utility::checkLocalInfo("TlsSessionTicketKeysSdsApi",
secret_provider_context.localInfo());
auto ret = std::make_shared<TlsSessionTicketKeysSdsApi>(
return std::make_shared<TlsSessionTicketKeysSdsApi>(
sds_config, sds_config_name, secret_provider_context.clusterManager().subscriptionFactory(),
secret_provider_context.dispatcher().timeSource(),
secret_provider_context.messageValidationVisitor(), secret_provider_context.stats(),
destructor_cb, secret_provider_context.dispatcher(), secret_provider_context.api());
secret_provider_context.initManager().add(*ret->initTarget());
return ret;
}

TlsSessionTicketKeysSdsApi(const envoy::config::core::v3::ConfigSource& sds_config,
Expand Down Expand Up @@ -391,13 +385,11 @@ class GenericSecretSdsApi : public SdsApi, public GenericSecretConfigProvider {
// We need to do this early as we invoke the subscription factory during initialization, which
// is too late to throw.
Config::Utility::checkLocalInfo("GenericSecretSdsApi", secret_provider_context.localInfo());
auto ret = std::make_shared<GenericSecretSdsApi>(
return std::make_shared<GenericSecretSdsApi>(
sds_config, sds_config_name, secret_provider_context.clusterManager().subscriptionFactory(),
secret_provider_context.dispatcher().timeSource(),
secret_provider_context.messageValidationVisitor(), secret_provider_context.stats(),
destructor_cb, secret_provider_context.dispatcher(), secret_provider_context.api());
secret_provider_context.initManager().add(*ret->initTarget());
return ret;
}

GenericSecretSdsApi(const envoy::config::core::v3::ConfigSource& sds_config,
Expand Down
1 change: 1 addition & 0 deletions source/common/secret/secret_manager_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ class SecretManagerImpl : public SecretManager {
config_name, unregister_secret_provider);
dynamic_secret_providers_[map_key] = secret_provider;
}
secret_provider_context.initManager().add(*secret_provider->initTarget());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a comment explaining the importance of doing it here?

return secret_provider;
}

Expand Down
1 change: 1 addition & 0 deletions test/integration/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ envoy_cc_test(
"//test/test_common:utility_lib",
"@envoy_api//envoy/config/bootstrap/v3:pkg_cc_proto",
"@envoy_api//envoy/config/cluster/v3:pkg_cc_proto",
"@envoy_api//envoy/config/core/v3:pkg_cc_proto",
"@envoy_api//envoy/config/endpoint/v3:pkg_cc_proto",
"@envoy_api//envoy/config/listener/v3:pkg_cc_proto",
"@envoy_api//envoy/config/route/v3:pkg_cc_proto",
Expand Down
58 changes: 58 additions & 0 deletions test/integration/ads_integration_test.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "envoy/config/bootstrap/v3/bootstrap.pb.h"
#include "envoy/config/cluster/v3/cluster.pb.h"
#include "envoy/config/core/v3/base.pb.h"
#include "envoy/config/endpoint/v3/endpoint.pb.h"
#include "envoy/config/listener/v3/listener.pb.h"
#include "envoy/config/route/v3/route.pb.h"
Expand Down Expand Up @@ -168,6 +169,63 @@ TEST_P(AdsIntegrationTest, ClusterInitializationUpdateOneOfThe2Warming) {
test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 0);
test_server_->waitForGaugeGe("cluster_manager.active_clusters", 4);
}

// Make sure two clusters sharing same secret are both kept warming before secret
// arrives. Verify that the clusters are eventually initialized.
// This is a regression test of #11120.
TEST_P(AdsIntegrationTest, ClusterSharingSecretWarming) {
initialize();
const auto cds_type_url = Config::getTypeUrl<envoy::config::cluster::v3::Cluster>(
envoy::config::core::v3::ApiVersion::V3);
const auto sds_type_url =
Config::getTypeUrl<envoy::extensions::transport_sockets::tls::v3::Secret>(
envoy::config::core::v3::ApiVersion::V3);

envoy::config::core::v3::TransportSocket sds_transport_socket;
TestUtility::loadFromYaml(R"EOF(
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
common_tls_context:
validation_context_sds_secret_config:
name: validation_context
sds_config:
resource_api_version: V3
ads: {}
)EOF",
sds_transport_socket);
auto cluster_template = ConfigHelper::buildStaticCluster("cluster", 8000, "127.0.0.1");
*cluster_template.mutable_transport_socket() = sds_transport_socket;

auto cluster_0 = cluster_template;
cluster_0.set_name("cluster_0");
auto cluster_1 = cluster_template;
cluster_1.set_name("cluster_1");

EXPECT_TRUE(compareDiscoveryRequest(cds_type_url, "", {}, {}, {}, true));
sendDiscoveryResponse<envoy::config::cluster::v3::Cluster>(
cds_type_url, {cluster_0, cluster_1}, {cluster_0, cluster_1}, {}, "1", false);

EXPECT_TRUE(compareDiscoveryRequest(sds_type_url, "", {"validation_context"},
{"validation_context"}, {}));
test_server_->waitForGaugeGe("cluster_manager.warming_clusters", 2);

envoy::extensions::transport_sockets::tls::v3::Secret validation_context;
TestUtility::loadFromYaml(fmt::format(R"EOF(
name: validation_context
validation_context:
trusted_ca:
filename: {}
)EOF",
TestEnvironment::runfilesPath(
"test/config/integration/certs/upstreamcacert.pem")),
validation_context);

sendDiscoveryResponse<envoy::extensions::transport_sockets::tls::v3::Secret>(
sds_type_url, {validation_context}, {validation_context}, {}, "1");
test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 0);
}

// Validate basic config delivery and upgrade with RateLimiting.
TEST_P(AdsIntegrationTest, BasicWithRateLimiting) {
initializeAds(true);
Expand Down
17 changes: 8 additions & 9 deletions test/integration/base_integration_test.h
Original file line number Diff line number Diff line change
Expand Up @@ -257,16 +257,15 @@ class BaseIntegrationTest : protected Logger::Loggable<Logger::Id::testing> {
}

private:
std::string intResourceName(const envoy::config::listener::v3::Listener& m) { return m.name(); }
std::string intResourceName(const envoy::config::route::v3::RouteConfiguration& m) {
return m.name();
}
std::string intResourceName(const envoy::config::cluster::v3::Cluster& m) { return m.name(); }
std::string intResourceName(const envoy::config::endpoint::v3::ClusterLoadAssignment& m) {
return m.cluster_name();
template <class T> std::string intResourceName(const T& m) {
// gcc doesn't allow inline template function to be specialized, using a constexpr if to
// workaround.
if constexpr (std::is_same<T, envoy::config::endpoint::v3::ClusterLoadAssignment>::value) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is_same_v?

return m.cluster_name();
} else {
return m.name();
}
}
std::string intResourceName(const envoy::config::route::v3::VirtualHost& m) { return m.name(); }
std::string intResourceName(const envoy::service::runtime::v3::Runtime& m) { return m.name(); }

Event::GlobalTimeSystem time_system_;

Expand Down