From c33b88485515606d2ac99cfcfd377e19bdc1a943 Mon Sep 17 00:00:00 2001 From: Vikas Choudhary Date: Mon, 27 Mar 2023 15:31:28 +0530 Subject: [PATCH] Add support for proxy_log_destination ABI Signed-off-by: Vikas Choudhary --- api/envoy/extensions/wasm/v3/wasm.proto | 15 ++++++++++++- source/extensions/common/wasm/plugin.cc | 30 +++++++++++++++++++++++++ source/extensions/common/wasm/plugin.h | 3 +++ source/extensions/common/wasm/wasm.cc | 16 +++++++------ 4 files changed, 56 insertions(+), 8 deletions(-) diff --git a/api/envoy/extensions/wasm/v3/wasm.proto b/api/envoy/extensions/wasm/v3/wasm.proto index 54ef437cbaf7..10d2cddb87f5 100644 --- a/api/envoy/extensions/wasm/v3/wasm.proto +++ b/api/envoy/extensions/wasm/v3/wasm.proto @@ -40,7 +40,7 @@ message SanitizationConfig { } // Configuration for a Wasm VM. -// [#next-free-field: 8] +// [#next-free-field: 9] message VmConfig { // An ID which will be used along with a hash of the wasm code (or the name of the registered Null // VM plugin) to determine which VM will be used for the plugin. All plugins which use the same @@ -106,6 +106,19 @@ message VmConfig { // vars just like when you do on native platforms. // Warning: Envoy rejects the configuration if there's conflict of key space. EnvironmentVariables environment_variables = 7; + + // Specifies the log destination for the plugin. + // If not specified, the plugin will log to the default Envoy log + // example: "audit-logs": { file_path: "/var/log/audit.log" } + map log_destination = 8; +} + +message LogDestination { + // Target destination for the log messages from the plugin. + oneof target { + string file_path = 1; + // TODO: Remote logging service + } } message EnvironmentVariables { diff --git a/source/extensions/common/wasm/plugin.cc b/source/extensions/common/wasm/plugin.cc index ae1628981e87..4308d94b71eb 100644 --- a/source/extensions/common/wasm/plugin.cc +++ b/source/extensions/common/wasm/plugin.cc @@ -52,6 +52,36 @@ WasmConfig::WasmConfig(const envoy::extensions::wasm::v3::PluginConfig& config) } } } + + if (config.vm_config().runtime() == "envoy.wasm.runtime.null" && + !config_.vm_config().log_destination().empty()) { + throw EnvoyException("envoy.extensions.wasm.v3.VmConfig.log_destination must " + "not be set for NullVm."); + } + // Check key duplication. + absl::flat_hash_set keys; + for (const auto& ld : config_.vm_config().log_destination()) { + keys.insert(ld.first); + } + for (const auto& ld : config_.vm_config().log_destination()) { + if (!keys.insert(ld.first).second) { + throw EnvoyException(fmt::format("Key {} is duplicated in " + "envoy.extensions.wasm.v3.VmConfig.log_destination for {}. " + "All the keys must be unique.", + ld.first, config_.name())); + } + } + // Construct merged key-value pairs. Also check for boundary conditions + // (e.g. empty file path). + for (const auto& ld : config_.vm_config().log_destination()) { + if (ld.second.file_path().empty()) { + throw EnvoyException( + fmt::format("Key {} value envoy.extensions.wasm.v3.VmConfig.LogDestination.file_path " + "must not be empty for {}.", + ld.first, config_.name())); + } + log_destinations_[ld.first] = ld.second.file_path(); + } } } // namespace Wasm diff --git a/source/extensions/common/wasm/plugin.h b/source/extensions/common/wasm/plugin.h index 4268c0476e5d..a192da312701 100644 --- a/source/extensions/common/wasm/plugin.h +++ b/source/extensions/common/wasm/plugin.h @@ -18,6 +18,7 @@ namespace Wasm { // clang-format off using EnvironmentVariableMap = std::unordered_map; +using LogDestinationMap = std::unordered_map; // clang-format on class WasmConfig { @@ -26,11 +27,13 @@ class WasmConfig { const envoy::extensions::wasm::v3::PluginConfig& config() { return config_; } proxy_wasm::AllowedCapabilitiesMap& allowedCapabilities() { return allowed_capabilities_; } EnvironmentVariableMap& environmentVariables() { return envs_; } + LogDestinationMap& logDestinations() { return log_destinations_; } private: const envoy::extensions::wasm::v3::PluginConfig config_; proxy_wasm::AllowedCapabilitiesMap allowed_capabilities_{}; EnvironmentVariableMap envs_; + LogDestinationMap log_destinations_; }; using WasmConfigPtr = std::unique_ptr; diff --git a/source/extensions/common/wasm/wasm.cc b/source/extensions/common/wasm/wasm.cc index 3ba2275915b0..d3b68848bfe2 100644 --- a/source/extensions/common/wasm/wasm.cc +++ b/source/extensions/common/wasm/wasm.cc @@ -75,10 +75,11 @@ void Wasm::initializeLifecycle(Server::ServerLifecycleNotifier& lifecycle_notifi Wasm::Wasm(WasmConfig& config, absl::string_view vm_key, const Stats::ScopeSharedPtr& scope, Api::Api& api, Upstream::ClusterManager& cluster_manager, Event::Dispatcher& dispatcher) - : WasmBase( - createWasmVm(config.config().vm_config().runtime()), config.config().vm_config().vm_id(), - MessageUtil::anyToBytes(config.config().vm_config().configuration()), - toStdStringView(vm_key), config.environmentVariables(), config.allowedCapabilities()), + : WasmBase(createWasmVm(config.config().vm_config().runtime()), + config.config().vm_config().vm_id(), + MessageUtil::anyToBytes(config.config().vm_config().configuration()), + toStdStringView(vm_key), config.environmentVariables(), config.logDestinations(), + config.allowedCapabilities()), scope_(scope), api_(api), stat_name_pool_(scope_->symbolTable()), custom_stat_namespace_(stat_name_pool_.add(CustomStatNamespace)), cluster_manager_(cluster_manager), dispatcher_(dispatcher), @@ -330,7 +331,8 @@ bool createWasm(const PluginSharedPtr& plugin, const Stats::ScopeSharedPtr& scop code_cache = new std::remove_reference::type; } Stats::ScopeSharedPtr create_wasm_stats_scope = stats_handler.lockAndCreateStats(scope); - // Remove entries older than CODE_CACHE_SECONDS_CACHING_TTL except for our target. + // Remove entries older than CODE_CACHE_SECONDS_CACHING_TTL except for our + // target. for (auto it = code_cache->begin(); it != code_cache->end();) { if (now - it->second.use_time > std::chrono::seconds(CODE_CACHE_SECONDS_CACHING_TTL) && it->first != vm_config.code().remote().sha256()) { @@ -423,8 +425,8 @@ bool createWasm(const PluginSharedPtr& plugin, const Stats::ScopeSharedPtr& scop } stats_handler.onRemoteCacheEntriesChanged(code_cache->size()); } - // NB: xDS currently does not support failing asynchronously, so we fail immediately - // if remote Wasm code is not cached and do a background fill. + // NB: xDS currently does not support failing asynchronously, so we fail + // immediately if remote Wasm code is not cached and do a background fill. if (!vm_config.nack_on_code_cache_miss()) { if (code.empty()) { ENVOY_LOG_TO_LOGGER(Envoy::Logger::Registry::getLog(Envoy::Logger::Id::wasm), trace,