-
Notifications
You must be signed in to change notification settings - Fork 5.5k
bootstrap-extensions: fix a crash on http callout #14478
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
Changes from 3 commits
21c5e5f
598c890
02e594a
13e92c5
87620b8
dbe9055
919e67f
039041a
37e53ac
4491188
d6264ad
d181b02
2b39bbc
b95ecaf
2354ea2
b96f116
fddcd70
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,19 +14,18 @@ namespace Extensions { | |
| namespace Bootstrap { | ||
| namespace Wasm { | ||
|
|
||
| static const std::string INLINE_STRING = "<inline>"; | ||
| void WasmServiceExtension::serverInitialized(Server::Configuration::ServerFactoryContext& context) { | ||
| createWasm(context); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we should delay the whole bootstrap extension creation to server initialization. The VM can be still created early, and the bootstrap extension could get this event in later stage and it should make http call there.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the advantage of splitting the VM initialization? |
||
| } | ||
|
|
||
| void WasmFactory::createWasm(const envoy::extensions::wasm::v3::WasmService& config, | ||
| Server::Configuration::ServerFactoryContext& context, | ||
| CreateWasmServiceCallback&& cb) { | ||
| void WasmServiceExtension::createWasm(Server::Configuration::ServerFactoryContext& context) { | ||
| auto plugin = std::make_shared<Common::Wasm::Plugin>( | ||
| config.config().name(), config.config().root_id(), config.config().vm_config().vm_id(), | ||
| config.config().vm_config().runtime(), | ||
| Common::Wasm::anyToBytes(config.config().configuration()), config.config().fail_open(), | ||
| config_.config().name(), config_.config().root_id(), config_.config().vm_config().vm_id(), | ||
| config_.config().vm_config().runtime(), | ||
| Common::Wasm::anyToBytes(config_.config().configuration()), config_.config().fail_open(), | ||
| envoy::config::core::v3::TrafficDirection::UNSPECIFIED, context.localInfo(), nullptr); | ||
|
|
||
| bool singleton = config.singleton(); | ||
| auto callback = [&context, singleton, plugin, cb](Common::Wasm::WasmHandleSharedPtr base_wasm) { | ||
| auto callback = [this, &context, plugin](Common::Wasm::WasmHandleSharedPtr base_wasm) { | ||
| if (!base_wasm) { | ||
| if (plugin->fail_open_) { | ||
| ENVOY_LOG(error, "Unable to create Wasm service {}", plugin->name_); | ||
|
|
@@ -35,10 +34,11 @@ void WasmFactory::createWasm(const envoy::extensions::wasm::v3::WasmService& con | |
| } | ||
| return; | ||
| } | ||
| if (singleton) { | ||
| if (config_.singleton()) { | ||
| // Return a Wasm VM which will be stored as a singleton by the Server. | ||
| cb(std::make_unique<WasmService>(plugin, Common::Wasm::getOrCreateThreadLocalPlugin( | ||
| base_wasm, plugin, context.dispatcher()))); | ||
| wasm_service_ = std::make_unique<WasmService>( | ||
| plugin, | ||
| Common::Wasm::getOrCreateThreadLocalPlugin(base_wasm, plugin, context.dispatcher())); | ||
| return; | ||
| } | ||
| // Per-thread WASM VM. | ||
|
|
@@ -48,11 +48,11 @@ void WasmFactory::createWasm(const envoy::extensions::wasm::v3::WasmService& con | |
| tls_slot->set([base_wasm, plugin](Event::Dispatcher& dispatcher) { | ||
| return Common::Wasm::getOrCreateThreadLocalPlugin(base_wasm, plugin, dispatcher); | ||
| }); | ||
| cb(std::make_unique<WasmService>(plugin, std::move(tls_slot))); | ||
| wasm_service_ = std::make_unique<WasmService>(plugin, std::move(tls_slot)); | ||
| }; | ||
|
|
||
| if (!Common::Wasm::createWasm( | ||
| config.config().vm_config(), plugin, context.scope().createScope(""), | ||
| config_.config().vm_config(), plugin, context.scope().createScope(""), | ||
| context.clusterManager(), context.initManager(), context.dispatcher(), context.api(), | ||
| context.lifecycleNotifier(), remote_data_provider_, std::move(callback))) { | ||
| // NB: throw if we get a synchronous configuration failures as this is how such failures are | ||
|
|
@@ -64,17 +64,12 @@ void WasmFactory::createWasm(const envoy::extensions::wasm::v3::WasmService& con | |
|
|
||
| Server::BootstrapExtensionPtr | ||
| WasmFactory::createBootstrapExtension(const Protobuf::Message& config, | ||
| Server::Configuration::ServerFactoryContext& context) { | ||
| ProtobufMessage::ValidationVisitor& validation_visitor) { | ||
| auto typed_config = | ||
| MessageUtil::downcastAndValidate<const envoy::extensions::wasm::v3::WasmService&>( | ||
| config, context.messageValidationContext().staticValidationVisitor()); | ||
| config, validation_visitor); | ||
|
|
||
| auto wasm_service_extension = std::make_unique<WasmServiceExtension>(); | ||
| createWasm(typed_config, context, | ||
| [extension = wasm_service_extension.get()](WasmServicePtr wasm) { | ||
| extension->wasm_service_ = std::move(wasm); | ||
| }); | ||
| return wasm_service_extension; | ||
| return std::make_unique<WasmServiceExtension>(typed_config); | ||
| } | ||
|
|
||
| // /** | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -139,7 +139,10 @@ InstanceImpl::~InstanceImpl() { | |
| ENVOY_LOG(debug, "destroyed listener manager"); | ||
| } | ||
|
|
||
| Upstream::ClusterManager& InstanceImpl::clusterManager() { return *config_.clusterManager(); } | ||
| Upstream::ClusterManager& InstanceImpl::clusterManager() { | ||
| ASSERT(config_.clusterManager() != nullptr); | ||
| return *config_.clusterManager(); | ||
| } | ||
|
|
||
| void InstanceImpl::drainListeners() { | ||
| ENVOY_LOG(info, "closing and draining listeners"); | ||
|
|
@@ -428,8 +431,8 @@ void InstanceImpl::initialize(const Options& options, | |
| auto config = Config::Utility::translateAnyToFactoryConfig( | ||
| bootstrap_extension.typed_config(), messageValidationContext().staticValidationVisitor(), | ||
| factory); | ||
| bootstrap_extensions_.push_back( | ||
| factory.createBootstrapExtension(*config, serverFactoryContext())); | ||
| bootstrap_extensions_.push_back(factory.createBootstrapExtension( | ||
| *config, messageValidationContext().staticValidationVisitor())); | ||
| } | ||
|
|
||
| // Register the fatal actions. | ||
|
|
@@ -534,6 +537,10 @@ void InstanceImpl::initialize(const Options& options, | |
| // cluster_manager_factory_ is available. | ||
| config_.initialize(bootstrap_, *this, *cluster_manager_factory_); | ||
|
|
||
| for (auto&& bootstrap_extension : bootstrap_extensions_) { | ||
| bootstrap_extension->serverInitialized(serverFactoryContext()); | ||
| } | ||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is still too early because cluster manager isn't fully initialized at this moment either. move this right before the guard dog initialization? |
||
| // Instruct the listener manager to create the LDS provider if needed. This must be done later | ||
| // because various items do not yet exist when the listener manager is created. | ||
| if (bootstrap_.dynamic_resources().has_lds_config() || | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
name this
onServerInitialized. The context can be still passed by constructor, because they are pointing to the same instance.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem is that the Context is not fully initialized in the ctor, and I think it is bug prone (i.e. this bug is a good example) to do that. specifically,
clusterManager()method in the context returns a reference variable is nullptr; i.e. the user wouldn't even think to test it for nullptr as it is a reference.To make it harder to write a bug, i think it is worth passing the bare minimum in the ctor (hence my change).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because that limits too much in createBootstrapExtension's access, there are more things should be made available for extension to be used, such as dispatcher/singletonManager/timeSource/Api etc. We can't just limit it to ValidationVisitor.