Skip to content

Commit ee63c1b

Browse files
ingwonsongknm3000
authored andcommitted
Configuration canary for the second or further plugins. (proxy-wasm#289)
Fixes proxy-wasm#175. Signed-off-by: Ingwon Song <[email protected]>
1 parent 3f1fdf6 commit ee63c1b

File tree

11 files changed

+295
-43
lines changed

11 files changed

+295
-43
lines changed

.github/workflows/test.yml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,18 @@ jobs:
5656
--config=clang
5757
-c opt
5858
$(bazel query 'kind(was.*_rust_binary, //test/test_data/...)')
59+
$(bazel query 'kind(_optimized_wasm_cc_binary, //test/test_data/...)')
60+
61+
# Currently, in Github Action, "Bazel build step" creates `wasm_canary_check.wasm` directory as a temporal directory.
62+
# Since the name of this directory has "*.wasm" pattern, the step "Mangle build rules to use existing test data" fails.
63+
# So, here, we clear out the directories in test_data.
64+
- name: Clean up test data
65+
shell: bash
66+
run: |
67+
# Remove temporal directories
68+
for i in $(find bazel-bin/test/test_data/ -mindepth 1 -maxdepth 1 -type d); do \
69+
rm -rf $i; \
70+
done
5971
6072
- name: Upload test data
6173
uses: actions/upload-artifact@v2
@@ -201,7 +213,7 @@ jobs:
201213
os: ubuntu-20.04
202214
arch: s390x
203215
action: test
204-
flags: --config=clang
216+
flags: --config=clang --test_timeout=1800
205217
run_under: docker run --rm --env HOME=$HOME --env USER=$(id -un) --volume "$HOME:$HOME" --workdir $(pwd) --user $(id -u):$(id -g) --platform linux/s390x piotrsikora/build-tools:bazel-5.0.0-clang-13-gcc-11
206218
cache: true
207219
- name: 'Wasmtime on macOS/x86_64'

WORKSPACE

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,15 @@ proxy_wasm_cpp_host_repositories()
77
load("@proxy_wasm_cpp_host//bazel:dependencies.bzl", "proxy_wasm_cpp_host_dependencies")
88

99
proxy_wasm_cpp_host_dependencies()
10+
11+
load("@proxy_wasm_cpp_sdk//bazel:repositories.bzl", "proxy_wasm_cpp_sdk_repositories")
12+
13+
proxy_wasm_cpp_sdk_repositories()
14+
15+
load("@proxy_wasm_cpp_sdk//bazel:dependencies.bzl", "proxy_wasm_cpp_sdk_dependencies")
16+
17+
proxy_wasm_cpp_sdk_dependencies()
18+
19+
load("@proxy_wasm_cpp_sdk//bazel:dependencies_extra.bzl", "proxy_wasm_cpp_sdk_dependencies_extra")
20+
21+
proxy_wasm_cpp_sdk_dependencies_extra()

bazel/repositories.bzl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,9 @@ def proxy_wasm_cpp_host_repositories():
8686
maybe(
8787
http_archive,
8888
name = "proxy_wasm_cpp_sdk",
89-
sha256 = "c57de2425b5c61d7f630c5061e319b4557ae1f1c7526e5a51c33dc1299471b08",
90-
strip_prefix = "proxy-wasm-cpp-sdk-fd0be8405db25de0264bdb78fae3a82668c03782",
91-
urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-sdk/archive/fd0be8405db25de0264bdb78fae3a82668c03782.tar.gz"],
89+
sha256 = "89792fc1abca331f29f99870476a04146de5e82ff903bdffca90e6729c1f2470",
90+
strip_prefix = "proxy-wasm-cpp-sdk-95bb82ce45c41d9100fd1ec15d2ffc67f7f3ceee",
91+
urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-sdk/archive/95bb82ce45c41d9100fd1ec15d2ffc67f7f3ceee.tar.gz"],
9292
)
9393

9494
# Test dependencies.

include/proxy-wasm/wasm.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,10 @@ class WasmBase : public std::enable_shared_from_this<WasmBase> {
314314
std::shared_ptr<VmIdHandle> vm_id_handle_;
315315
};
316316

317+
using WasmHandleFactory = std::function<std::shared_ptr<WasmHandleBase>(std::string_view vm_id)>;
318+
using WasmHandleCloneFactory =
319+
std::function<std::shared_ptr<WasmHandleBase>(std::shared_ptr<WasmHandleBase> wasm)>;
320+
317321
// Handle which enables shutdown operations to run post deletion (e.g. post listener drain).
318322
class WasmHandleBase : public std::enable_shared_from_this<WasmHandleBase> {
319323
public:
@@ -324,6 +328,9 @@ class WasmHandleBase : public std::enable_shared_from_this<WasmHandleBase> {
324328
}
325329
}
326330

331+
bool canary(const std::shared_ptr<PluginBase> &plugin,
332+
const WasmHandleCloneFactory &clone_factory);
333+
327334
void kill() { wasm_base_ = nullptr; }
328335

329336
std::shared_ptr<WasmBase> &wasm() { return wasm_base_; }
@@ -335,10 +342,6 @@ class WasmHandleBase : public std::enable_shared_from_this<WasmHandleBase> {
335342
std::string makeVmKey(std::string_view vm_id, std::string_view configuration,
336343
std::string_view code);
337344

338-
using WasmHandleFactory = std::function<std::shared_ptr<WasmHandleBase>(std::string_view vm_id)>;
339-
using WasmHandleCloneFactory =
340-
std::function<std::shared_ptr<WasmHandleBase>(std::shared_ptr<WasmHandleBase> wasm)>;
341-
342345
// Returns nullptr on failure (i.e. initialization of the VM fails).
343346
std::shared_ptr<WasmHandleBase> createWasm(const std::string &vm_key, const std::string &code,
344347
const std::shared_ptr<PluginBase> &plugin,

src/wasm.cc

Lines changed: 46 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,35 @@ void WasmBase::finishShutdown() {
447447
}
448448
}
449449

450+
bool WasmHandleBase::canary(const std::shared_ptr<PluginBase> &plugin,
451+
const WasmHandleCloneFactory &clone_factory) {
452+
if (this->wasm() == nullptr) {
453+
return false;
454+
}
455+
auto configuration_canary_handle = clone_factory(shared_from_this());
456+
if (!configuration_canary_handle) {
457+
this->wasm()->fail(FailState::UnableToCloneVm, "Failed to clone Base Wasm");
458+
return false;
459+
}
460+
if (!configuration_canary_handle->wasm()->initialize()) {
461+
configuration_canary_handle->wasm()->fail(FailState::UnableToInitializeCode,
462+
"Failed to initialize Wasm code");
463+
return false;
464+
}
465+
auto *root_context = configuration_canary_handle->wasm()->start(plugin);
466+
if (root_context == nullptr) {
467+
configuration_canary_handle->wasm()->fail(FailState::StartFailed, "Failed to start base Wasm");
468+
return false;
469+
}
470+
if (!configuration_canary_handle->wasm()->configure(root_context, plugin)) {
471+
configuration_canary_handle->wasm()->fail(FailState::ConfigureFailed,
472+
"Failed to configure base Wasm plugin");
473+
return false;
474+
}
475+
configuration_canary_handle->kill();
476+
return true;
477+
}
478+
450479
std::shared_ptr<WasmHandleBase> createWasm(const std::string &vm_key, const std::string &code,
451480
const std::shared_ptr<PluginBase> &plugin,
452481
const WasmHandleFactory &factory,
@@ -465,44 +494,29 @@ std::shared_ptr<WasmHandleBase> createWasm(const std::string &vm_key, const std:
465494
base_wasms->erase(it);
466495
}
467496
}
468-
if (wasm_handle) {
469-
return wasm_handle;
470-
}
471-
wasm_handle = factory(vm_key);
472497
if (!wasm_handle) {
473-
return nullptr;
498+
// If no cached base_wasm, creates a new base_wasm, loads the code and initializes it.
499+
wasm_handle = factory(vm_key);
500+
if (!wasm_handle) {
501+
return nullptr;
502+
}
503+
if (!wasm_handle->wasm()->load(code, allow_precompiled)) {
504+
wasm_handle->wasm()->fail(FailState::UnableToInitializeCode, "Failed to load Wasm code");
505+
return nullptr;
506+
}
507+
if (!wasm_handle->wasm()->initialize()) {
508+
wasm_handle->wasm()->fail(FailState::UnableToInitializeCode,
509+
"Failed to initialize Wasm code");
510+
return nullptr;
511+
}
512+
(*base_wasms)[vm_key] = wasm_handle;
474513
}
475-
(*base_wasms)[vm_key] = wasm_handle;
476514
}
477515

478-
if (!wasm_handle->wasm()->load(code, allow_precompiled)) {
479-
wasm_handle->wasm()->fail(FailState::UnableToInitializeCode, "Failed to load Wasm code");
480-
return nullptr;
481-
}
482-
if (!wasm_handle->wasm()->initialize()) {
483-
wasm_handle->wasm()->fail(FailState::UnableToInitializeCode, "Failed to initialize Wasm code");
484-
return nullptr;
485-
}
486-
auto configuration_canary_handle = clone_factory(wasm_handle);
487-
if (!configuration_canary_handle) {
488-
wasm_handle->wasm()->fail(FailState::UnableToCloneVm, "Failed to clone Base Wasm");
489-
return nullptr;
490-
}
491-
if (!configuration_canary_handle->wasm()->initialize()) {
492-
wasm_handle->wasm()->fail(FailState::UnableToInitializeCode, "Failed to initialize Wasm code");
493-
return nullptr;
494-
}
495-
auto *root_context = configuration_canary_handle->wasm()->start(plugin);
496-
if (root_context == nullptr) {
497-
configuration_canary_handle->wasm()->fail(FailState::StartFailed, "Failed to start base Wasm");
516+
// Either creating new one or reusing the existing one, apply canary for each plugin.
517+
if (!wasm_handle->canary(plugin, clone_factory)) {
498518
return nullptr;
499519
}
500-
if (!configuration_canary_handle->wasm()->configure(root_context, plugin)) {
501-
configuration_canary_handle->wasm()->fail(FailState::ConfigureFailed,
502-
"Failed to configure base Wasm plugin");
503-
return nullptr;
504-
}
505-
configuration_canary_handle->kill();
506520
return wasm_handle;
507521
};
508522

test/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ cc_test(
9191
srcs = ["wasm_test.cc"],
9292
data = [
9393
"//test/test_data:abi_export.wasm",
94+
"//test/test_data:canary_check.wasm",
9495
],
9596
linkstatic = 1,
9697
deps = [

test/test_data/BUILD

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
load("@proxy_wasm_cpp_host//bazel:wasm.bzl", "wasm_rust_binary")
2+
load("@proxy_wasm_cpp_sdk//bazel:defs.bzl", "proxy_wasm_cc_binary")
23

34
licenses(["notice"]) # Apache 2
45

@@ -59,3 +60,8 @@ wasm_rust_binary(
5960
srcs = ["random.rs"],
6061
wasi = True,
6162
)
63+
64+
proxy_wasm_cc_binary(
65+
name = "canary_check.wasm",
66+
srcs = ["canary_check.cc"],
67+
)

test/test_data/canary_check.cc

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright 2021 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include <string>
16+
#include <string_view>
17+
#include <unordered_map>
18+
19+
#include "proxy_wasm_intrinsics.h"
20+
21+
class CanaryCheckRootContext1 : public RootContext {
22+
public:
23+
explicit CanaryCheckRootContext1(uint32_t id, std::string_view root_id)
24+
: RootContext(id, root_id) {}
25+
bool onConfigure(size_t s) override {
26+
LOG_TRACE("onConfigure: root_id_1");
27+
return s != 0;
28+
}
29+
};
30+
31+
class CanaryCheckContext : public Context {
32+
public:
33+
explicit CanaryCheckContext(uint32_t id, RootContext *root) : Context(id, root) {}
34+
};
35+
36+
class CanaryCheckRootContext2 : public RootContext {
37+
public:
38+
explicit CanaryCheckRootContext2(uint32_t id, std::string_view root_id)
39+
: RootContext(id, root_id) {}
40+
bool onConfigure(size_t s) override {
41+
LOG_TRACE("onConfigure: root_id_2");
42+
return s != 0;
43+
}
44+
};
45+
46+
static RegisterContextFactory register_CanaryCheckContext1(CONTEXT_FACTORY(CanaryCheckContext),
47+
ROOT_FACTORY(CanaryCheckRootContext1),
48+
"root_id_1");
49+
50+
static RegisterContextFactory register_CanaryCheckContext2(CONTEXT_FACTORY(CanaryCheckContext),
51+
ROOT_FACTORY(CanaryCheckRootContext2),
52+
"root_id_2");

test/utility.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
namespace proxy_wasm {
1818

19+
std::string TestContext::global_log_;
20+
1921
std::vector<std::string> getWasmEngines() {
2022
std::vector<std::string> engines = {
2123
#if defined(PROXY_WASM_HOST_ENGINE_V8)

test/utility.h

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,16 +91,34 @@ class TestIntegration : public WasmVmIntegration {
9191
class TestContext : public ContextBase {
9292
public:
9393
TestContext(WasmBase *wasm) : ContextBase(wasm) {}
94+
TestContext(WasmBase *wasm, const std::shared_ptr<PluginBase> &plugin)
95+
: ContextBase(wasm, plugin) {}
9496

9597
WasmResult log(uint32_t /*log_level*/, std::string_view message) override {
96-
log_ += std::string(message) + "\n";
98+
auto new_log = std::string(message) + "\n";
99+
log_ += new_log;
100+
global_log_ += new_log;
97101
return WasmResult::Ok;
98102
}
99103

104+
WasmResult getProperty(std::string_view path, std::string *result) override {
105+
if (path == "plugin_root_id") {
106+
*result = root_id_;
107+
return WasmResult::Ok;
108+
}
109+
return unimplemented();
110+
}
111+
100112
bool isLogEmpty() { return log_.empty(); }
101113

102114
bool isLogged(std::string_view message) { return log_.find(message) != std::string::npos; }
103115

116+
static bool isGlobalLogged(std::string_view message) {
117+
return global_log_.find(message) != std::string::npos;
118+
}
119+
120+
static void resetGlobalLog() { global_log_ = ""; }
121+
104122
uint64_t getCurrentTimeNanoseconds() override {
105123
return std::chrono::duration_cast<std::chrono::nanoseconds>(
106124
std::chrono::system_clock::now().time_since_epoch())
@@ -114,14 +132,24 @@ class TestContext : public ContextBase {
114132

115133
private:
116134
std::string log_;
135+
static std::string global_log_;
117136
};
118137

119138
class TestWasm : public WasmBase {
120139
public:
121-
TestWasm(std::unique_ptr<WasmVm> wasm_vm, std::unordered_map<std::string, std::string> envs = {})
122-
: WasmBase(std::move(wasm_vm), "", "", "", std::move(envs), {}) {}
140+
TestWasm(std::unique_ptr<WasmVm> wasm_vm, std::unordered_map<std::string, std::string> envs = {},
141+
std::string_view vm_id = "", std::string_view vm_configuration = "",
142+
std::string_view vm_key = "")
143+
: WasmBase(std::move(wasm_vm), vm_id, vm_configuration, vm_key, std::move(envs), {}) {}
144+
145+
TestWasm(const std::shared_ptr<WasmHandleBase> &base_wasm_handle, const WasmVmFactory &factory)
146+
: WasmBase(base_wasm_handle, factory) {}
123147

124148
ContextBase *createVmContext() override { return new TestContext(this); };
149+
150+
ContextBase *createRootContext(const std::shared_ptr<PluginBase> &plugin) override {
151+
return new TestContext(this, plugin);
152+
}
125153
};
126154

127155
class TestVm : public testing::TestWithParam<std::string> {

0 commit comments

Comments
 (0)