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

wasm: add api for configuring environment variable in VmConfig #15136

Merged
merged 31 commits into from
Mar 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
c389247
Add environment_variables field in VmConfig
mathetake Feb 22, 2021
2077a4e
review: fix typo
mathetake Feb 24, 2021
fda8ed6
Review: add warning and fix style
mathetake Feb 25, 2021
8bab14a
Merge remote-tracking branch 'origin/main' into wasm-env-api
mathetake Feb 25, 2021
194471b
Write test
mathetake Feb 25, 2021
1fec667
Merge remote-tracking branch 'origin/main' into wasm-env-api
mathetake Mar 3, 2021
dd00186
Fix test and setenv for NullVm consistency
mathetake Mar 3, 2021
065cbe8
Delete the debug code
mathetake Mar 3, 2021
851bd2e
Fix testname
mathetake Mar 3, 2021
0306a2f
Fix testcase
mathetake Mar 3, 2021
8b602a2
Fix test names
mathetake Mar 3, 2021
cb9b1df
Remove unnecessary changes
mathetake Mar 3, 2021
8fa9a02
Fix format & add test
mathetake Mar 3, 2021
dd9568c
Fix Windows build
mathetake Mar 3, 2021
d1eb946
Fix Windows build: part2
mathetake Mar 3, 2021
e8795f5
review: ignore NullVm, check keys regardless of existence
mathetake Mar 3, 2021
824f0e7
Remove unnecessary changes
mathetake Mar 3, 2021
a917095
Reject NullVm with env vars
mathetake Mar 4, 2021
5c1f0f0
Check NullVm first
mathetake Mar 4, 2021
fc931d4
Review: env check in integration test, rename accessor.
mathetake Mar 4, 2021
d6268a8
Fix include path.
mathetake Mar 4, 2021
041286f
Fix include path: part 2
mathetake Mar 4, 2021
22ee914
Merge remote-tracking branch 'origin/main' into wasm-env-api
mathetake Mar 4, 2021
2f1e10b
review: split string
mathetake Mar 4, 2021
b4e5d56
Merge remote-tracking branch 'origin/main' into wasm-env-api
mathetake Mar 5, 2021
3ed2309
review: fix styles
mathetake Mar 5, 2021
435f69a
Relax the restriction on NullVm
mathetake Mar 5, 2021
3d6dc03
fix format
mathetake Mar 5, 2021
78ac3f8
fix format: part 2
mathetake Mar 5, 2021
4e4ccf7
review: fix styles
mathetake Mar 6, 2021
84a4f5c
Merge remote-tracking branch 'origin/main' into wasm-env-api
mathetake Mar 6, 2021
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
18 changes: 17 additions & 1 deletion api/envoy/extensions/wasm/v3/wasm.proto
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ message SanitizationConfig {
}

// Configuration for a Wasm VM.
// [#next-free-field: 7]
// [#next-free-field: 8]
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
Expand Down Expand Up @@ -93,6 +93,22 @@ message VmConfig {
// update and do a background fetch to fill the cache, otherwise fetch the code asynchronously and enter
// warming state.
bool nack_on_code_cache_miss = 6;

// Specifies environment variables to be injected to this VM which will be available through
// WASI's ``environ_get`` and ``environ_get_sizes`` system calls. Note that these functions are mostly implicitly
// called in your language's standard library, so you do not need to call them directly and you can access to env
// 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;
}

message EnvironmentVariables {
// The keys of *Envoy's* environment variables exposed to this VM. In other words, if a key exists in Envoy's environment
// variables, then that key-value pair will be injected. Note that if a key does not exist, it will be ignored.
repeated string host_env_keys = 1;
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if we want some notion of env vars elsewhere in xDS as well, so we might want to factor this message to base types. @markdroth thoughts?


// Explicitly given key-value pairs to be injected to this VM in the form of "KEY=VALUE".
map<string, string> key_values = 2;
}

// Base Configuration for Wasm Plugins e.g. filters and services.
Expand Down
6 changes: 3 additions & 3 deletions bazel/repository_locations.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -936,8 +936,8 @@ REPOSITORY_LOCATIONS_SPEC = dict(
project_name = "WebAssembly for Proxies (C++ host implementation)",
project_desc = "WebAssembly for Proxies (C++ host implementation)",
project_url = "https://github.com/proxy-wasm/proxy-wasm-cpp-host",
version = "d1a2a7db59a72edacc9a6286b64280b72767d2d0",
sha256 = "3e81235c963291bd01f9425ed6e34d6b44ca0adc9f281b0cafc5cba6ad3bcc6d",
version = "dd33aa6d825cd63deaa0f793c8caca8a9132a05f",
sha256 = "dac7998459616396684f17f35890fb03116450110f4d3bce3d9ae652141f2d3f",
strip_prefix = "proxy-wasm-cpp-host-{version}",
urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-host/archive/{version}.tar.gz"],
use_category = ["dataplane_ext"],
Expand All @@ -952,7 +952,7 @@ REPOSITORY_LOCATIONS_SPEC = dict(
"envoy.wasm.runtime.wavm",
"envoy.wasm.runtime.wasmtime",
],
release_date = "2021-02-19",
release_date = "2021-03-03",
cpe = "N/A",
),
proxy_wasm_rust_sdk = dict(
Expand Down
26 changes: 24 additions & 2 deletions bazel/wasm/wasm.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ def _wasm_rust_transition_impl(settings, attr):
"//command_line_option:platforms": "@rules_rust//rust/platform:wasm",
}

def _wasi_rust_transition_impl(settings, attr):
return {
"//command_line_option:platforms": "@rules_rust//rust/platform:wasi",
}

wasm_rust_transition = transition(
implementation = _wasm_rust_transition_impl,
inputs = [],
Expand All @@ -14,6 +19,14 @@ wasm_rust_transition = transition(
],
)

wasi_rust_transition = transition(
implementation = _wasi_rust_transition_impl,
inputs = [],
outputs = [
"//command_line_option:platforms",
],
)

def _wasm_binary_impl(ctx):
out = ctx.actions.declare_file(ctx.label.name)
if ctx.attr.precompile:
Expand Down Expand Up @@ -47,6 +60,11 @@ wasm_rust_binary_rule = rule(
attrs = _wasm_attrs(wasm_rust_transition),
)

wasi_rust_binary_rule = rule(
implementation = _wasm_binary_impl,
attrs = _wasm_attrs(wasi_rust_transition),
)

def envoy_wasm_cc_binary(name, deps = [], tags = [], **kwargs):
wasm_cc_binary(
name = name,
Expand All @@ -55,7 +73,7 @@ def envoy_wasm_cc_binary(name, deps = [], tags = [], **kwargs):
**kwargs
)

def wasm_rust_binary(name, tags = [], **kwargs):
def wasm_rust_binary(name, tags = [], wasi = False, **kwargs):
wasm_name = "_wasm_" + name.replace(".", "_")
kwargs.setdefault("visibility", ["//visibility:public"])

Expand All @@ -68,7 +86,11 @@ def wasm_rust_binary(name, tags = [], **kwargs):
**kwargs
)

wasm_rust_binary_rule(
bin_rule = wasm_rust_binary_rule
if wasi:
bin_rule = wasi_rust_binary_rule

bin_rule(
name = name,
precompile = select({
"@envoy//bazel:linux_x86_64": True,
Expand Down
18 changes: 17 additions & 1 deletion generated_api_shadow/envoy/extensions/wasm/v3/wasm.proto

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

47 changes: 41 additions & 6 deletions source/extensions/common/wasm/plugin.cc
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
#include "extensions/common/wasm/plugin.h"

#include <memory>
#include "envoy/common/exception.h"

#include "envoy/extensions/wasm/v3/wasm.pb.validate.h"
#include "envoy/local_info/local_info.h"

#include "common/protobuf/protobuf.h"
#include "common/protobuf/utility.h"
#include "extensions/common/wasm/well_known_names.h"

#include "include/proxy-wasm/wasm.h"

Expand All @@ -20,6 +16,45 @@ WasmConfig::WasmConfig(const envoy::extensions::wasm::v3::PluginConfig& config)
// TODO(rapilado): Set the SanitizationConfig fields once sanitization is implemented.
allowed_capabilities_[capability.first] = proxy_wasm::SanitizationConfig();
}

if (config_.vm_config().has_environment_variables()) {
const auto& envs = config_.vm_config().environment_variables();

// We reject NullVm with key_values configuration
// since it directly accesses Envoy's env vars and we should not modify Envoy's env vars here.
// TODO(mathetake): Once proxy_get_map_values(type::EnvironmentVariables, ..) call is supported,
// then remove this restriction.
if (config.vm_config().runtime() == WasmRuntimeNames::get().Null &&
!envs.key_values().empty()) {
throw EnvoyException("envoy.extensions.wasm.v3.VmConfig.EnvironmentVariables.key_values must "
"not be set for NullVm.");
}

// Check key duplication.
absl::flat_hash_set<std::string> keys;
for (const auto& env : envs.key_values()) {
keys.insert(env.first);
}
for (const auto& key : envs.host_env_keys()) {
if (!keys.insert(key).second) {
throw EnvoyException(
fmt::format("Key {} is duplicated in "
"envoy.extensions.wasm.v3.VmConfig.environment_variables for {}. "
"All the keys must be unique.",
key, config_.name()));
}
}

// Construct merged key-value pairs.
for (const auto& env : envs.key_values()) {
envs_[env.first] = env.second;
}
for (const auto& key : envs.host_env_keys()) {
if (auto value = std::getenv(key.data())) {
envs_[key] = value;
}
}
}
}

} // namespace Wasm
Expand Down
6 changes: 6 additions & 0 deletions source/extensions/common/wasm/plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,21 @@ namespace Extensions {
namespace Common {
namespace Wasm {

// clang-format off
using EnvironmentVariableMap = std::unordered_map<std::string, std::string>;
Copy link
Member

Choose a reason for hiding this comment

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

Nit: absl::flat_hash_map?

Copy link
Member Author

Choose a reason for hiding this comment

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

The reason why this is not absl is that we have decided not to use absl as a dependency in proxy-wasm-cpp-host which is supposed to be used in other proxies in theory.

// clang-format on

class WasmConfig {
public:
WasmConfig(const envoy::extensions::wasm::v3::PluginConfig& config);
const envoy::extensions::wasm::v3::PluginConfig& config() { return config_; }
proxy_wasm::AllowedCapabilitiesMap& allowedCapabilities() { return allowed_capabilities_; }
EnvironmentVariableMap& environmentVariables() { return envs_; }

private:
const envoy::extensions::wasm::v3::PluginConfig& config_;
proxy_wasm::AllowedCapabilitiesMap allowed_capabilities_{};
EnvironmentVariableMap envs_;
};

using WasmConfigPtr = std::unique_ptr<WasmConfig>;
Expand Down
2 changes: 1 addition & 1 deletion source/extensions/common/wasm/wasm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ Wasm::Wasm(WasmConfig& config, absl::string_view vm_key, const Stats::ScopeShare
: WasmBase(createWasmVm(config.config().vm_config().runtime()),
config.config().vm_config().vm_id(),
MessageUtil::anyToBytes(config.config().vm_config().configuration()), vm_key,
config.allowedCapabilities()),
config.environmentVariables(), config.allowedCapabilities()),
scope_(scope), cluster_manager_(cluster_manager), dispatcher_(dispatcher),
time_source_(dispatcher.timeSource()),
wasm_stats_(WasmStats{ALL_WASM_STATS(
Expand Down
1 change: 1 addition & 0 deletions test/extensions/bootstrap/wasm/test_data/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ envoy_package()
wasm_rust_binary(
name = "logging_rust.wasm",
srcs = ["logging_rust.rs"],
wasi = True,
deps = [
"@proxy_wasm_rust_sdk//:proxy_wasm",
"@proxy_wasm_rust_sdk//bazel/cargo:log",
Expand Down
9 changes: 9 additions & 0 deletions test/extensions/bootstrap/wasm/test_data/http_cpp.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ START_WASM_PLUGIN(WasmHttpCpp)
WASM_EXPORT(void, proxy_abi_version_0_1_0, ()) {}

WASM_EXPORT(uint32_t, proxy_on_configure, (uint32_t, uint32_t)) {
if (std::getenv("NON_EXIST")) {
logError("NON_EXIST should not exist in the environment variable key space");
return 0;
}
if (std::string(std::getenv("KEY")) != "VALUE") {
logError("Environment variable KEY=VALUE must exist");
return 0;
}
proxy_set_tick_period_milliseconds(100);
return 1;
}
Expand All @@ -31,6 +39,7 @@ WASM_EXPORT(void, proxy_on_tick, (uint32_t)) {
}

WASM_EXPORT(void, proxy_on_http_call_response, (uint32_t, uint32_t, uint32_t headers, uint32_t, uint32_t)) {
logTrace("KEY: " + std::string(std::getenv("KEY")));
if (headers != 0) {
auto status = getHeaderMapValue(WasmHeaderMapType::HttpCallResponseHeaders, "status");
if ("200" == status->view()) {
Expand Down
2 changes: 2 additions & 0 deletions test/extensions/bootstrap/wasm/test_data/logging_cpp.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
extern "C" PROXY_WASM_KEEPALIVE void proxy_abi_version_0_1_0() {}

extern "C" PROXY_WASM_KEEPALIVE uint32_t proxy_on_configure(uint32_t, uint32_t configuration_size) {
logTrace("ON_CONFIGURE: " + std::string(std::getenv("ON_CONFIGURE")));
fprintf(stdout, "printf stdout test");
fflush(stdout);
fprintf(stderr, "printf stderr test");
Expand All @@ -29,6 +30,7 @@ extern "C" PROXY_WASM_KEEPALIVE void proxy_on_context_create(uint32_t, uint32_t)
extern "C" PROXY_WASM_KEEPALIVE uint32_t proxy_on_vm_start(uint32_t, uint32_t) { return 1; }

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_tick(uint32_t) {
logTrace("ON_TICK: " + std::string(std::getenv("ON_TICK")));
const char* root_id = nullptr;
size_t size;
proxy_get_property("plugin_root_id", sizeof("plugin_root_id") - 1, &root_id, &size);
Expand Down
10 changes: 10 additions & 0 deletions test/extensions/bootstrap/wasm/test_data/logging_rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,16 @@ use log::{debug, error, info, trace, warn};
use proxy_wasm::traits::{Context, RootContext};
use proxy_wasm::types::LogLevel;

#[no_mangle]
extern "C" {
fn __wasilibc_initialize_environ();
}

#[no_mangle]
pub fn _start() {
unsafe {
__wasilibc_initialize_environ();
}
proxy_wasm::set_log_level(LogLevel::Trace);
proxy_wasm::set_root_context(|_| -> Box<dyn RootContext> { Box::new(TestRoot) });
}
Expand All @@ -16,6 +24,7 @@ impl RootContext for TestRoot {
}

fn on_configure(&mut self, _: usize) -> bool {
trace!("ON_CONFIGURE: {}", std::env::var("ON_CONFIGURE").unwrap());
trace!("test trace logging");
debug!("test debug logging");
error!("test error logging");
Expand All @@ -26,6 +35,7 @@ impl RootContext for TestRoot {
}

fn on_tick(&mut self) {
trace!("ON_TICK: {}", std::env::var("ON_TICK").unwrap());
if let Some(value) = self.get_property(vec!["plugin_root_id"]) {
info!("test tick logging{}", String::from_utf8(value).unwrap());
} else {
Expand Down
4 changes: 4 additions & 0 deletions test/extensions/bootstrap/wasm/wasm_integration_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ name: envoy.filters.http.wasm
value: ""
vm_config:
vm_id: "my_vm_id"
environment_variables:
host_env_keys: ["NON_EXIST"]
key_values:
KEY: VALUE
runtime: "envoy.wasm.runtime.{}"
code:
local:
Expand Down
9 changes: 6 additions & 3 deletions test/extensions/bootstrap/wasm/wasm_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class WasmTestBase {
nullptr);
auto config = plugin_->wasmConfig();
config.allowedCapabilities() = allowed_capabilities_;
config.environmentVariables() = envs_;
wasm_ = std::make_shared<Extensions::Common::Wasm::Wasm>(config, vm_key_, scope_,
cluster_manager, *dispatcher_);
EXPECT_NE(wasm_, nullptr);
Expand All @@ -79,6 +80,7 @@ class WasmTestBase {
std::string vm_configuration_;
std::string vm_key_;
proxy_wasm::AllowedCapabilitiesMap allowed_capabilities_;
Extensions::Common::Wasm::EnvironmentVariableMap envs_{};
std::string plugin_configuration_;
std::shared_ptr<Extensions::Common::Wasm::Plugin> plugin_;
std::shared_ptr<Extensions::Common::Wasm::Wasm> wasm_;
Expand Down Expand Up @@ -132,17 +134,16 @@ INSTANTIATE_TEST_SUITE_P(RuntimesAndLanguages, WasmTestMatrix,
testing::Values("cpp", "rust")));
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WasmTestMatrix);

TEST_P(WasmTestMatrix, Logging) {
TEST_P(WasmTestMatrix, LoggingWithEnvVars) {
plugin_configuration_ = "configure-test";
envs_ = {{"ON_TICK", "TICK_VALUE"}, {"ON_CONFIGURE", "CONFIGURE_VALUE"}};
createWasm();
setWasmCode("logging");

auto wasm_weak = std::weak_ptr<Extensions::Common::Wasm::Wasm>(wasm_);
auto wasm_handler = std::make_unique<Extensions::Common::Wasm::WasmHandle>(std::move(wasm_));

EXPECT_TRUE(wasm_weak.lock()->initialize(code_, false));
auto context = static_cast<TestContext*>(wasm_weak.lock()->start(plugin_));

if (std::get<1>(GetParam()) == "cpp") {
EXPECT_CALL(*context, log_(spdlog::level::info, Eq("printf stdout test")));
EXPECT_CALL(*context, log_(spdlog::level::err, Eq("printf stderr test")));
Expand All @@ -155,6 +156,8 @@ TEST_P(WasmTestMatrix, Logging) {
.Times(testing::AtLeast(1));
EXPECT_CALL(*context, log_(spdlog::level::info, Eq("onDone logging")));
EXPECT_CALL(*context, log_(spdlog::level::info, Eq("onDelete logging")));
EXPECT_CALL(*context, log_(spdlog::level::trace, Eq("ON_CONFIGURE: CONFIGURE_VALUE")));
EXPECT_CALL(*context, log_(spdlog::level::trace, Eq("ON_TICK: TICK_VALUE")));

EXPECT_TRUE(wasm_weak.lock()->configure(context, plugin_));
wasm_handler.reset();
Expand Down
9 changes: 9 additions & 0 deletions test/extensions/common/wasm/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ envoy_cc_test(
],
)

envoy_cc_test(
name = "plugin_test",
srcs = ["plugin_test.cc"],
deps = [
"//source/extensions/common/wasm:wasm_lib",
"//test/test_common:environment_lib",
],
)

envoy_cc_test_binary(
name = "wasm_speed_test",
srcs = ["wasm_speed_test.cc"],
Expand Down
Loading