You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by ki...@apache.org on 2023/03/26 14:56:56 UTC
[trafficserver] branch master updated: Add support for multiple yaml config files for wasm plugin (#9483)
This is an automated email from the ASF dual-hosted git repository.
kichan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push:
new a5b1dd2e4 Add support for multiple yaml config files for wasm plugin (#9483)
a5b1dd2e4 is described below
commit a5b1dd2e40aff3d391df91e8be744cb87520c141
Author: Kit Chan <ki...@apache.org>
AuthorDate: Sun Mar 26 07:56:47 2023 -0700
Add support for multiple yaml config files for wasm plugin (#9483)
* Add support for multiple yaml config files
* fix clang-format issues
* fix clang-format issues
* Update wasm.en.rst
* Fix problem with breaks and add error message related to file read
---
doc/admin-guide/plugins/wasm.en.rst | 3 +-
plugins/experimental/wasm/wasm_main.cc | 502 ++++++++++++++++++---------------
2 files changed, 275 insertions(+), 230 deletions(-)
diff --git a/doc/admin-guide/plugins/wasm.en.rst b/doc/admin-guide/plugins/wasm.en.rst
index ec129cbbe..9b83b8b8e 100644
--- a/doc/admin-guide/plugins/wasm.en.rst
+++ b/doc/admin-guide/plugins/wasm.en.rst
@@ -97,6 +97,8 @@ generated wasm modules with the plugin.
Runtime can be chosen by changing the ``runtime`` field inside the yaml configuration file for the plugin.
``ats.wasm.runtime.wamr`` is for WAMR while ``ats.wasm.runtime.wasmedge`` is for WasmEdge.
+The plugin can also take more than one yaml file as arguments and can thus load more than one wasm modules.
+
TODO
====
@@ -104,7 +106,6 @@ TODO
* Need to support functionality for retrieving and setting request/response body
* Need to support functionality for making async request call
* Need to support L4 lifecycle handler functions
-* Support loading more than one Wasm module
Limitations
===========
diff --git a/plugins/experimental/wasm/wasm_main.cc b/plugins/experimental/wasm/wasm_main.cc
index c9ac17e26..5267914db 100644
--- a/plugins/experimental/wasm/wasm_main.cc
+++ b/plugins/experimental/wasm/wasm_main.cc
@@ -37,10 +37,9 @@
// struct for storing plugin configuration
struct WasmInstanceConfig {
- std::string config_filename;
- std::string wasm_filename;
- std::shared_ptr<ats_wasm::Wasm> wasm = nullptr;
- std::shared_ptr<proxy_wasm::PluginBase> plugin = nullptr;
+ std::list<std::string> config_filenames = {};
+
+ std::list<std::pair<std::shared_ptr<ats_wasm::Wasm>, std::shared_ptr<proxy_wasm::PluginBase>>> configs = {};
std::list<std::pair<std::shared_ptr<ats_wasm::Wasm>, std::shared_ptr<proxy_wasm::PluginBase>>> deleted_configs = {};
};
@@ -60,23 +59,31 @@ schedule_handler(TSCont contp, TSEvent /*event*/, void * /*data*/)
c->onTick(0); // use 0 as token
- if (!wasm_config->wasm) {
- TSError("[wasm][%s] Configuration object is null", __FUNCTION__);
+ if (wasm_config->configs.empty()) {
+ TSError("[wasm][%s] Configuration objects are empty", __FUNCTION__);
TSMutexUnlock(old_wasm->mutex());
return 0;
}
- if (c->wasm() == wasm_config->wasm.get()) {
- auto *wasm = static_cast<ats_wasm::Wasm *>(c->wasm());
- uint32_t root_context_id = c->id();
- if (wasm->existsTimerPeriod(root_context_id)) {
- TSDebug(WASM_DEBUG_TAG, "[%s] reschedule continuation", __FUNCTION__);
- std::chrono::milliseconds period = wasm->getTimerPeriod(root_context_id);
- TSContScheduleOnPool(contp, static_cast<TSHRTime>(period.count()), TS_THREAD_POOL_NET);
- } else {
- TSDebug(WASM_DEBUG_TAG, "[%s] can't find period for root context id: %d", __FUNCTION__, root_context_id);
+ bool found = false;
+ for (auto it = wasm_config->configs.begin(); it != wasm_config->configs.end(); it++) {
+ std::shared_ptr<ats_wasm::Wasm> wbp = it->first;
+ if (wbp.get() == old_wasm) {
+ found = true;
+ auto *wasm = static_cast<ats_wasm::Wasm *>(c->wasm());
+ uint32_t root_context_id = c->id();
+ if (wasm->existsTimerPeriod(root_context_id)) {
+ TSDebug(WASM_DEBUG_TAG, "[%s] reschedule continuation", __FUNCTION__);
+ std::chrono::milliseconds period = wasm->getTimerPeriod(root_context_id);
+ TSContScheduleOnPool(contp, static_cast<TSHRTime>(period.count()), TS_THREAD_POOL_NET);
+ } else {
+ TSDebug(WASM_DEBUG_TAG, "[%s] can't find period for root context id: %d", __FUNCTION__, root_context_id);
+ }
+ break;
}
- } else {
+ }
+
+ if (!found) {
std::shared_ptr<ats_wasm::Wasm> temp = nullptr;
uint32_t root_context_id = c->id();
old_wasm->removeTimerPeriod(root_context_id);
@@ -181,11 +188,20 @@ http_event_handler(TSCont contp, TSEvent event, void *data)
case TS_EVENT_HTTP_READ_CACHE_HDR:
break;
- case TS_EVENT_HTTP_TXN_CLOSE:
+ case TS_EVENT_HTTP_TXN_CLOSE: {
context->onDone();
context->onDelete();
- if (context->wasm() == wasm_config->wasm.get()) {
+ bool found = false;
+ for (auto it = wasm_config->configs.begin(); it != wasm_config->configs.end(); it++) {
+ std::shared_ptr<ats_wasm::Wasm> wbp = it->first;
+ if (wbp.get() == context->wasm()) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
TSDebug(WASM_DEBUG_TAG, "[%s] config wasm has not changed", __FUNCTION__);
} else {
if (old_wasm->readyShutdown()) {
@@ -220,7 +236,7 @@ http_event_handler(TSCont contp, TSEvent event, void *data)
TSContDestroy(contp);
result = 0;
break;
-
+ }
default:
break;
}
@@ -244,24 +260,28 @@ http_event_handler(TSCont contp, TSEvent event, void *data)
static int
global_hook_handler(TSCont /*contp*/, TSEvent /*event*/, void *data)
{
- auto *wasm = wasm_config->wasm.get();
- TSMutexLock(wasm->mutex());
- auto *rootContext = wasm->getRootContext(wasm_config->plugin, false);
- auto *context = new ats_wasm::Context(wasm, rootContext->id(), wasm_config->plugin);
- auto *txnp = static_cast<TSHttpTxn>(data);
- context->initialize(txnp);
- context->onCreate();
- TSMutexUnlock(wasm->mutex());
-
- // create continuation for transaction
- TSCont txn_contp = TSContCreate(http_event_handler, nullptr);
- TSHttpTxnHookAdd(txnp, TS_HTTP_READ_REQUEST_HDR_HOOK, txn_contp);
- TSHttpTxnHookAdd(txnp, TS_HTTP_READ_RESPONSE_HDR_HOOK, txn_contp);
- TSHttpTxnHookAdd(txnp, TS_HTTP_TXN_CLOSE_HOOK, txn_contp);
- // add send response hook for local reply if needed
- TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, txn_contp);
-
- TSContDataSet(txn_contp, context);
+ auto *txnp = static_cast<TSHttpTxn>(data);
+ for (auto it = wasm_config->configs.begin(); it != wasm_config->configs.end(); it++) {
+ std::shared_ptr<ats_wasm::Wasm> wbp = it->first;
+ std::shared_ptr<proxy_wasm::PluginBase> plg = it->second;
+ auto *wasm = wbp.get();
+ TSMutexLock(wasm->mutex());
+ auto *rootContext = wasm->getRootContext(plg, false);
+ auto *context = new ats_wasm::Context(wasm, rootContext->id(), plg);
+ context->initialize(txnp);
+ context->onCreate();
+ TSMutexUnlock(wasm->mutex());
+
+ // create continuation for transaction
+ TSCont txn_contp = TSContCreate(http_event_handler, nullptr);
+ TSHttpTxnHookAdd(txnp, TS_HTTP_READ_REQUEST_HDR_HOOK, txn_contp);
+ TSHttpTxnHookAdd(txnp, TS_HTTP_READ_RESPONSE_HDR_HOOK, txn_contp);
+ TSHttpTxnHookAdd(txnp, TS_HTTP_TXN_CLOSE_HOOK, txn_contp);
+ // add send response hook for local reply if needed
+ TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, txn_contp);
+
+ TSContDataSet(txn_contp, context);
+ }
TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
return 0;
@@ -273,13 +293,26 @@ read_file(const std::string &fn, std::string *s)
{
auto fd = open(fn.c_str(), O_RDONLY);
if (fd < 0) {
+ char *errmsg = strerror(errno);
+ TSError("[wasm][%s] wasm unable to open: %s", __FUNCTION__, errmsg);
return -1;
}
auto n = ::lseek(fd, 0, SEEK_END);
+ if (n < 0) {
+ char *errmsg = strerror(errno);
+ TSError("[wasm][%s] wasm unable to lseek: %s", __FUNCTION__, errmsg);
+ return -1;
+ }
::lseek(fd, 0, SEEK_SET);
s->resize(n);
auto nn = ::read(fd, const_cast<char *>(&*s->begin()), n);
+ if (nn < 0) {
+ char *errmsg = strerror(errno);
+ TSError("[wasm][%s] wasm unable to read: %s", __FUNCTION__, errmsg);
+ return -1;
+ }
if (nn != static_cast<ssize_t>(n)) {
+ TSError("[wasm][%s] wasm unable to read: size different from buffer", __FUNCTION__);
return -1;
}
return 0;
@@ -289,239 +322,248 @@ read_file(const std::string &fn, std::string *s)
static bool
read_configuration()
{
- // PluginBase parameters
- std::string name = "";
- std::string root_id = "";
- std::string configuration = "";
- bool fail_open = true;
-
- // WasmBase parameters
- std::string runtime = "";
- std::string vm_id = "";
- std::string vm_configuration = "";
- std::string wasm_filename = "";
- bool allow_precompiled = true;
-
- proxy_wasm::AllowedCapabilitiesMap cap_maps;
- std::unordered_map<std::string, std::string> envs;
-
- try {
- YAML::Node config = YAML::LoadFile(wasm_config->config_filename);
-
- for (YAML::const_iterator it = config.begin(); it != config.end(); ++it) {
- const std::string &node_name = it->first.as<std::string>();
- YAML::NodeType::value type = it->second.Type();
-
- if (node_name != "config" || type != YAML::NodeType::Map) {
- TSError("[wasm][%s] Invalid YAML Configuration format for wasm: %s, reason: Top level nodes must be named config and be of "
- "type map",
- __FUNCTION__, wasm_config->config_filename.c_str());
- return false;
- }
+ std::list<std::pair<std::shared_ptr<ats_wasm::Wasm>, std::shared_ptr<proxy_wasm::PluginBase>>> new_configs = {};
+
+ for (auto const &cfn : wasm_config->config_filenames) {
+ // PluginBase parameters
+ std::string name = "";
+ std::string root_id = "";
+ std::string configuration = "";
+ bool fail_open = true;
+
+ // WasmBase parameters
+ std::string runtime = "";
+ std::string vm_id = "";
+ std::string vm_configuration = "";
+ std::string wasm_filename = "";
+ bool allow_precompiled = true;
+
+ proxy_wasm::AllowedCapabilitiesMap cap_maps;
+ std::unordered_map<std::string, std::string> envs;
+
+ try {
+ YAML::Node config = YAML::LoadFile(cfn);
+
+ for (YAML::const_iterator it = config.begin(); it != config.end(); ++it) {
+ const std::string &node_name = it->first.as<std::string>();
+ YAML::NodeType::value type = it->second.Type();
+
+ if (node_name != "config" || type != YAML::NodeType::Map) {
+ TSError(
+ "[wasm][%s] Invalid YAML Configuration format for wasm: %s, reason: Top level nodes must be named config and be of "
+ "type map",
+ __FUNCTION__, cfn.c_str());
+ return false;
+ }
- for (YAML::const_iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2) {
- const YAML::Node first = it2->first;
- const YAML::Node second = it2->second;
+ for (YAML::const_iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2) {
+ const YAML::Node first = it2->first;
+ const YAML::Node second = it2->second;
- const std::string &key = first.as<std::string>();
- if (second.IsScalar()) {
- const std::string &value = second.as<std::string>();
- if (key == "name") {
- name = value;
- }
- if (key == "root_id" || key == "rootId") {
- root_id = value;
- }
- if (key == "configuration") {
- configuration = value;
- }
- if (key == "fail_open") {
- if (value == "false") {
- fail_open = false;
+ const std::string &key = first.as<std::string>();
+ if (second.IsScalar()) {
+ const std::string &value = second.as<std::string>();
+ if (key == "name") {
+ name = value;
+ }
+ if (key == "root_id" || key == "rootId") {
+ root_id = value;
+ }
+ if (key == "configuration") {
+ configuration = value;
+ }
+ if (key == "fail_open") {
+ if (value == "false") {
+ fail_open = false;
+ }
}
}
- }
- if (second.IsMap() && (key == "capability_restriction_config")) {
- if (second["allowed_capabilities"]) {
- const YAML::Node ac_node = second["allowed_capabilities"];
- if (ac_node.IsSequence()) {
- for (const auto &i : ac_node) {
- auto ac = i.as<std::string>();
- proxy_wasm::SanitizationConfig sc;
- cap_maps[ac] = sc;
+ if (second.IsMap() && (key == "capability_restriction_config")) {
+ if (second["allowed_capabilities"]) {
+ const YAML::Node ac_node = second["allowed_capabilities"];
+ if (ac_node.IsSequence()) {
+ for (const auto &i : ac_node) {
+ auto ac = i.as<std::string>();
+ proxy_wasm::SanitizationConfig sc;
+ cap_maps[ac] = sc;
+ }
}
}
}
- }
- if (second.IsMap() && (key == "vm_config" || key == "vmConfig")) {
- for (YAML::const_iterator it3 = second.begin(); it3 != second.end(); ++it3) {
- const YAML::Node vm_config_first = it3->first;
- const YAML::Node vm_config_second = it3->second;
+ if (second.IsMap() && (key == "vm_config" || key == "vmConfig")) {
+ for (YAML::const_iterator it3 = second.begin(); it3 != second.end(); ++it3) {
+ const YAML::Node vm_config_first = it3->first;
+ const YAML::Node vm_config_second = it3->second;
- const std::string &vm_config_key = vm_config_first.as<std::string>();
- if (vm_config_second.IsScalar()) {
- const std::string &vm_config_value = vm_config_second.as<std::string>();
- if (vm_config_key == "runtime") {
- runtime = vm_config_value;
- }
- if (vm_config_key == "vm_id" || vm_config_key == "vmId") {
- vm_id = vm_config_value;
- }
- if (vm_config_key == "configuration") {
- vm_configuration = vm_config_value;
- }
- if (vm_config_key == "allow_precompiled") {
- if (vm_config_value == "false") {
- allow_precompiled = false;
+ const std::string &vm_config_key = vm_config_first.as<std::string>();
+ if (vm_config_second.IsScalar()) {
+ const std::string &vm_config_value = vm_config_second.as<std::string>();
+ if (vm_config_key == "runtime") {
+ runtime = vm_config_value;
+ }
+ if (vm_config_key == "vm_id" || vm_config_key == "vmId") {
+ vm_id = vm_config_value;
+ }
+ if (vm_config_key == "configuration") {
+ vm_configuration = vm_config_value;
+ }
+ if (vm_config_key == "allow_precompiled") {
+ if (vm_config_value == "false") {
+ allow_precompiled = false;
+ }
}
}
- }
- if (vm_config_key == "environment_variables" && vm_config_second.IsMap()) {
- if (vm_config_second["host_env_keys"]) {
- const YAML::Node ek_node = vm_config_second["host_env_keys"];
- if (ek_node.IsSequence()) {
- for (const auto &i : ek_node) {
- auto ek = i.as<std::string>();
- if (auto *value = std::getenv(ek.data())) {
- envs[ek] = value;
+ if (vm_config_key == "environment_variables" && vm_config_second.IsMap()) {
+ if (vm_config_second["host_env_keys"]) {
+ const YAML::Node ek_node = vm_config_second["host_env_keys"];
+ if (ek_node.IsSequence()) {
+ for (const auto &i : ek_node) {
+ auto ek = i.as<std::string>();
+ if (auto *value = std::getenv(ek.data())) {
+ envs[ek] = value;
+ }
}
}
}
- }
- if (vm_config_second["key_values"]) {
- const YAML::Node kv_node = vm_config_second["key_values"];
- if (kv_node.IsMap()) {
- for (YAML::const_iterator it4 = kv_node.begin(); it4 != kv_node.end(); ++it4) {
- envs[it4->first.as<std::string>()] = it4->second.as<std::string>();
+ if (vm_config_second["key_values"]) {
+ const YAML::Node kv_node = vm_config_second["key_values"];
+ if (kv_node.IsMap()) {
+ for (YAML::const_iterator it4 = kv_node.begin(); it4 != kv_node.end(); ++it4) {
+ envs[it4->first.as<std::string>()] = it4->second.as<std::string>();
+ }
}
}
}
- }
- if (vm_config_key == "code" && vm_config_second.IsMap()) {
- if (vm_config_second["local"]) {
- const YAML::Node local_node = vm_config_second["local"];
- if (local_node["filename"]) {
- wasm_filename = local_node["filename"].as<std::string>();
+ if (vm_config_key == "code" && vm_config_second.IsMap()) {
+ if (vm_config_second["local"]) {
+ const YAML::Node local_node = vm_config_second["local"];
+ if (local_node["filename"]) {
+ wasm_filename = local_node["filename"].as<std::string>();
+ }
}
}
}
}
}
- }
- // only allowed one config block (first one) for now
- break;
+ // only allowed one config block (first one) for now
+ break;
+ }
+ } catch (const YAML::Exception &e) {
+ TSError("[wasm][%s] YAML::Exception %s when parsing YAML config file %s for wasm", __FUNCTION__, e.what(), cfn.c_str());
+ return false;
}
- } catch (const YAML::Exception &e) {
- TSError("[wasm][%s] YAML::Exception %s when parsing YAML config file %s for wasm", __FUNCTION__, e.what(),
- wasm_config->config_filename.c_str());
- return false;
- }
- std::shared_ptr<ats_wasm::Wasm> wasm;
- if (runtime == "ats.wasm.runtime.wasmedge") {
+ std::shared_ptr<ats_wasm::Wasm> wasm;
+ if (runtime == "ats.wasm.runtime.wasmedge") {
#ifdef WASMEDGE
- wasm = std::make_shared<ats_wasm::Wasm>(proxy_wasm::createWasmEdgeVm(), // VM
- vm_id, // vm_id
- vm_configuration, // vm_configuration
- "", // vm_key,
- envs, // envs
- cap_maps // allowed capabilities
- );
+ wasm = std::make_shared<ats_wasm::Wasm>(proxy_wasm::createWasmEdgeVm(), // VM
+ vm_id, // vm_id
+ vm_configuration, // vm_configuration
+ "", // vm_key,
+ envs, // envs
+ cap_maps // allowed capabilities
+ );
#else
- TSError("[wasm][%s] wasm unable to use WasmEdge runtime", __FUNCTION__);
- return false;
+ TSError("[wasm][%s] wasm unable to use WasmEdge runtime", __FUNCTION__);
+ return false;
#endif
- } else if (runtime == "ats.wasm.runtime.wamr") {
+ } else if (runtime == "ats.wasm.runtime.wamr") {
#ifdef WAMR
- wasm = std::make_shared<ats_wasm::Wasm>(proxy_wasm::createWamrVm(), // VM
- vm_id, // vm_id
- vm_configuration, // vm_configuration
- "", // vm_key,
- envs, // envs
- cap_maps // allowed capabilities
- );
+ wasm = std::make_shared<ats_wasm::Wasm>(proxy_wasm::createWamrVm(), // VM
+ vm_id, // vm_id
+ vm_configuration, // vm_configuration
+ "", // vm_key,
+ envs, // envs
+ cap_maps // allowed capabilities
+ );
#else
- TSError("[wasm][%s] wasm unable to use WAMR runtime", __FUNCTION__);
- return false;
+ TSError("[wasm][%s] wasm unable to use WAMR runtime", __FUNCTION__);
+ return false;
#endif
- } else {
- TSError("[wasm][%s] wasm unable to use %s runtime", __FUNCTION__, runtime.c_str());
- return false;
- }
- wasm->wasm_vm()->integration() = std::make_unique<ats_wasm::ATSWasmVmIntegration>();
-
- auto plugin = std::make_shared<proxy_wasm::PluginBase>(name, // name
- root_id, // root_id
- vm_id, // vm_id
- runtime, // engine
- configuration, // plugin_configuration
- fail_open, // failopen
- "" // TODO: plugin key from where ?
- );
-
- wasm_config->wasm_filename = wasm_filename;
- if (*wasm_config->wasm_filename.begin() != '/') {
- wasm_config->wasm_filename = std::string(TSConfigDirGet()) + "/" + wasm_config->wasm_filename;
- }
- std::string code;
- if (read_file(wasm_config->wasm_filename, &code) < 0) {
- TSError("[wasm][%s] wasm unable to read file '%s'", __FUNCTION__, wasm_config->wasm_filename.c_str());
- return false;
- }
+ } else {
+ TSError("[wasm][%s] wasm unable to use %s runtime", __FUNCTION__, runtime.c_str());
+ return false;
+ }
+ wasm->wasm_vm()->integration() = std::make_unique<ats_wasm::ATSWasmVmIntegration>();
+
+ auto plugin = std::make_shared<proxy_wasm::PluginBase>(name, // name
+ root_id, // root_id
+ vm_id, // vm_id
+ runtime, // engine
+ configuration, // plugin_configuration
+ fail_open, // failopen
+ "" // TODO: plugin key from where ?
+ );
- if (code.empty()) {
- TSError("[wasm][%s] code is empty", __FUNCTION__);
- return false;
- }
+ if (*wasm_filename.begin() != '/') {
+ wasm_filename = std::string(TSConfigDirGet()) + "/" + wasm_filename;
+ }
+ std::string code;
+ if (read_file(wasm_filename, &code) < 0) {
+ TSError("[wasm][%s] wasm unable to read file '%s'", __FUNCTION__, wasm_filename.c_str());
+ return false;
+ }
- if (!wasm) {
- TSError("[wasm][%s] wasm wasm wasm unable to create vm", __FUNCTION__);
- return false;
- }
- if (!wasm->load(code, allow_precompiled)) {
- TSError("[wasm][%s] Failed to load Wasm code", __FUNCTION__);
- return false;
- }
- if (!wasm->initialize()) {
- TSError("[wasm][%s] Failed to initialize Wasm code", __FUNCTION__);
- return false;
- }
+ if (code.empty()) {
+ TSError("[wasm][%s] code is empty", __FUNCTION__);
+ return false;
+ }
+
+ if (!wasm) {
+ TSError("[wasm][%s] wasm wasm wasm unable to create vm", __FUNCTION__);
+ return false;
+ }
+ if (!wasm->load(code, allow_precompiled)) {
+ TSError("[wasm][%s] Failed to load Wasm code", __FUNCTION__);
+ return false;
+ }
+ if (!wasm->initialize()) {
+ TSError("[wasm][%s] Failed to initialize Wasm code", __FUNCTION__);
+ return false;
+ }
- TSCont contp = TSContCreate(schedule_handler, TSMutexCreate());
- auto *rootContext = wasm->start(plugin, contp);
+ TSCont contp = TSContCreate(schedule_handler, TSMutexCreate());
+ auto *rootContext = wasm->start(plugin, contp);
- if (!wasm->configure(rootContext, plugin)) {
- TSError("[wasm][%s] Failed to configure Wasm", __FUNCTION__);
- return false;
+ if (!wasm->configure(rootContext, plugin)) {
+ TSError("[wasm][%s] Failed to configure Wasm", __FUNCTION__);
+ return false;
+ }
+
+ auto new_config = std::make_pair(wasm, plugin);
+ new_configs.push_front(new_config);
}
- auto old_wasm = wasm_config->wasm;
- auto old_plugin = wasm_config->plugin;
+ auto old_configs = wasm_config->configs;
- wasm_config->wasm = wasm;
- wasm_config->plugin = plugin;
+ wasm_config->configs = new_configs;
- if (old_wasm != nullptr) {
- TSDebug(WASM_DEBUG_TAG, "[%s] previous WasmBase exists", __FUNCTION__);
- TSMutexLock(old_wasm->mutex());
- if (old_wasm->readyShutdown()) {
- TSDebug(WASM_DEBUG_TAG, "[%s] starting WasmBase Shutdown", __FUNCTION__);
- old_wasm->startShutdown();
- if (!old_wasm->readyDelete()) {
- TSDebug(WASM_DEBUG_TAG, "[%s] not ready to delete WasmBase/PluginBase", __FUNCTION__);
+ for (auto it = old_configs.begin(); it != old_configs.end(); it++) {
+ std::shared_ptr<ats_wasm::Wasm> old_wasm = it->first;
+ std::shared_ptr<proxy_wasm::PluginBase> old_plugin = it->second;
+
+ if (old_wasm != nullptr) {
+ TSDebug(WASM_DEBUG_TAG, "[%s] previous WasmBase exists", __FUNCTION__);
+ TSMutexLock(old_wasm->mutex());
+ if (old_wasm->readyShutdown()) {
+ TSDebug(WASM_DEBUG_TAG, "[%s] starting WasmBase Shutdown", __FUNCTION__);
+ old_wasm->startShutdown();
+ if (!old_wasm->readyDelete()) {
+ TSDebug(WASM_DEBUG_TAG, "[%s] not ready to delete WasmBase/PluginBase", __FUNCTION__);
+ auto deleted_config = std::make_pair(old_wasm, old_plugin);
+ wasm_config->deleted_configs.push_front(deleted_config);
+ }
+ } else {
+ TSDebug(WASM_DEBUG_TAG, "[%s] not ready to shutdown WasmBase", __FUNCTION__);
auto deleted_config = std::make_pair(old_wasm, old_plugin);
wasm_config->deleted_configs.push_front(deleted_config);
}
- } else {
- TSDebug(WASM_DEBUG_TAG, "[%s] not ready to shutdown WasmBase", __FUNCTION__);
- auto deleted_config = std::make_pair(old_wasm, old_plugin);
- wasm_config->deleted_configs.push_front(deleted_config);
+ TSMutexUnlock(old_wasm->mutex());
}
- TSMutexUnlock(old_wasm->mutex());
}
return true;
@@ -556,11 +598,13 @@ TSPluginInit(int argc, const char *argv[])
wasm_config = std::make_unique<WasmInstanceConfig>();
- std::string filename = std::string(argv[1]);
- if (*filename.begin() != '/') {
- filename = std::string(TSConfigDirGet()) + "/" + filename;
+ for (int i = 1; i < argc; i++) {
+ std::string filename = std::string(argv[i]);
+ if (*filename.begin() != '/') {
+ filename = std::string(TSConfigDirGet()) + "/" + filename;
+ }
+ wasm_config->config_filenames.push_front(filename);
}
- wasm_config->config_filename = filename;
if (!read_configuration()) {
return;