Skip to content

Commit ad0b327

Browse files
authored
Refactor towards End-use doc. (tetratelabs#190)
Signed-off-by: Takeshi Yoneda <[email protected]>
1 parent e9861eb commit ad0b327

File tree

25 files changed

+550
-696
lines changed

25 files changed

+550
-696
lines changed

README.md

+22-81
Original file line numberDiff line numberDiff line change
@@ -3,58 +3,19 @@ __This project is in its early stage, and the API is likely to change and not st
33
# WebAssembly for Proxies (Go SDK) [![Build](https://github.com/tetratelabs/proxy-wasm-go-sdk/workflows/test/badge.svg)](https://github.com/tetratelabs/proxy-wasm-go-sdk/actions) [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
44

55
The Go SDK for
6-
[Proxy-Wasm](https://github.com/proxy-wasm/spec), enabling developers to write Proxy-Wasm extensions in Go.
7-
6+
[Proxy-Wasm](https://github.com/proxy-wasm/spec), enabling developers to write Proxy-Wasm plugins in Go.
87
This SDK is powered by [TinyGo](https://tinygo.org/) and does not support the official Go compiler.
98

10-
```golang
11-
import (
12-
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm"
13-
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm/types"
14-
)
15-
16-
type vmContext struct{}
17-
18-
// Implement types.VMContext.
19-
func (*vmContext) NewPluginContext(contextID uint32) types.PluginContext {
20-
return &pluginContext{}
21-
}
22-
23-
type pluginContext struct {
24-
counter proxywasm.MetricCounter
25-
}
26-
27-
// Implement types.PluginContext.
28-
func (*pluginContext) NewHttpContext(contextID uint32) types.HttpContext {
29-
return &httpContext{counter: proxywasm.DefineCounterMetric("proxy_wasm_go.request_counter")}
30-
}
31-
32-
type httpContext struct {
33-
counter proxywasm.MetricCounter
34-
}
35-
36-
// Implement types.HttpContext.
37-
func (ctx *httpContext) OnHttpRequestHeaders(int, bool) types.Action {
38-
// Increment the request counter when we receive request headers.
39-
ctx.counter.Increment(1)
40-
return types.ActionContinue
41-
}
42-
```
43-
44-
## Requirements
45-
46-
This SDK depends on TinyGo and leverages its [WASI](https://github.com/WebAssembly/WASI) (WebAssembly System Interface) target.
9+
## Getting Started
4710

48-
Please follow the official instruction [here](https://tinygo.org/getting-started/) for installing TinyGo.
11+
- [examples](examples) directory contains the example codes on top of this SDK.
4912

50-
### Compatible ABI / Envoy builds (tested on CI)
13+
## Requirements
5114

52-
| proxy-wasm-go-sdk| proxy-wasm ABI version |istio/proxyv2| Envoy upstream|
53-
|:-------------:|:-------------:|:-------------:|:-------------:|
54-
| main | 0.2.0| 1.9, 1.10 | 1.18 |
55-
| v0.3.0 | 0.2.0| 1.9, 1.10 | 1.18 |
15+
- [TinyGo](https://tinygo.org/) - This SDK depends on TinyGo and leverages its [WASI](https://github.com/WebAssembly/WASI) (WebAssembly System Interface) target. Please follow the official instruction [here](https://tinygo.org/getting-started/) for installing TinyGo.
16+
- [Envoy](https://www.envoyproxy.io) - To run compiled examples, you need to have Envoy binary. Please follow [the official instruction](https://www.envoyproxy.io/docs/envoy/latest/start/install).
5617

57-
## Development
18+
## Build and run Examples
5819

5920
```bash
6021
# Build all examples.
@@ -64,48 +25,28 @@ make build.examples
6425
make build.example name=helloworld
6526

6627
# Run a specific example.
67-
# This requires you to have Envoy binary locally.
6828
make run name=helloworld
29+
```
6930

70-
# Run local tests without running envoy processes.
71-
make test
31+
## Compatible Envoy builds (tested on CI)
7232

73-
# Run all e2e tests.
74-
# This requires you to have Envoy binary locally.
75-
make test.e2e
33+
Envoy is the first host side implementation of Proxy-Wasm ABI,
34+
and we run end-to-end tests with multiple Envoy versions in order to verify Proxy-Wasm Go SDK works as expected.
7635

77-
# Run e2e tests for a specific example.
78-
# This requires you to have Envoy binary locally.
79-
make test.e2e.single name=helloworld
80-
```
36+
| proxy-wasm-go-sdk| istio/proxyv2| Envoy upstream|
37+
|:-------------:|:-------------:|:-------------:|
38+
| main | 1.9, 1.10 | 1.18 |
39+
| v0.3.0 | 1.9, 1.10 | 1.18 |
40+
41+
## Contributing
42+
43+
We welcome contributions from the community! See [CONTRIBUTING.md](doc/CONTRIBUTING.md) for how to contribute to this repository.
8144

82-
## Limitations and Considerations
83-
84-
- Some of existing libraries are not available (importable but runtime panic / non-importable)
85-
- There are several reasons for this:
86-
1. TinyGo's WASI target does not support some of syscall: For example, we cannot import `crypto/rand` package.
87-
2. TinyGo does not implement all of reflect package([examples](https://github.com/tinygo-org/tinygo/blob/v0.14.1/src/reflect/value.go#L299-L305)).
88-
3. [proxy-wasm-cpp-host](https://github.com/proxy-wasm/proxy-wasm-cpp-host) has not supported some of WASI APIs yet
89-
- These issues will be mitigated as TinyGo and proxy-wasm-cpp-host evolve.
90-
- There's performance overhead of using Go/TinyGo due to GC
91-
- `runtime.GC` is called whenever the heap runs out (see [1](https://tinygo.org/lang-support/#garbage-collection),
92-
[2](https://github.com/tinygo-org/tinygo/blob/v0.14.1/src/runtime/gc_conservative.go#L218-L239)).
93-
- TinyGo allows us to disable GC, but we cannot do that since we need to use maps (implicitly causes allocation)
94-
for saving the plugin's [state](https://github.com/tetratelabs/proxy-wasm-go-sdk/blob/cf6ad74ed58b284d3d8ceeb8c5dba2280d5b1007/proxywasm/vmstate.go#L41-L46).
95-
- Theoretically, we can implement our own GC algorithms tailored for proxy-wasm through `alloc(uintptr)` [interface](https://github.com/tinygo-org/tinygo/blob/v0.14.1/src/runtime/gc_none.go#L13)
96-
with `-gc=none` option. This is the future TODO.
97-
- `recover` is [not implemented](https://github.com/tinygo-org/tinygo/issues/891) in TinyGo, and there's no way to prevent the Wasm virtual machine from aborting.
98-
- Goroutine support
99-
- In TinyGo, Goroutine is implmeneted through LLVM's coroutine (see [this blog post](https://aykevl.nl/2019/02/tinygo-goroutines)).
100-
- In Envoy, Wasm modules are run in the event driven manner, and therefore the "scheduler" is not executed once the main function exits.
101-
That means you cannot have the expected behavior of Goroutine as in ordinary host environments.
102-
- The question "How to deal with Goroutine in a thread local Wasm VM executed in the event drive manner" has yet to be answered.
103-
- We strongly recommend that you implement the `OnTick` function for any asynchronous task instead of using Goroutine.
104-
- The scheduler can be disabled with `-scheduler=none` option of TinyGo.
105-
106-
## References
45+
## External links
10746

10847
- [WebAssembly for Proxies (ABI specification)](https://github.com/proxy-wasm/spec)
48+
- [WebAssembly for Proxies (AssemblyScript SDK)](https://github.com/solo-io/proxy-runtime)
10949
- [WebAssembly for Proxies (C++ SDK)](https://github.com/proxy-wasm/proxy-wasm-cpp-sdk)
11050
- [WebAssembly for Proxies (Rust SDK)](https://github.com/proxy-wasm/proxy-wasm-rust-sdk)
51+
- [WebAssembly for Proxies (Zig SDK)](https://github.com/mathetake/proxy-wasm-zig-sdk)
11152
- [TinyGo - Go compiler for small places](https://tinygo.org/)

doc/CONTRIBUTING.md

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Contributing
2+
3+
We welcome contributions from the community. Please read the following guidelines carefully to maximize the chances of your PR being merged.
4+
5+
## Coding Style
6+
7+
The code is linted using a stringent golang-ci. To run this linter (and a few others) use run `make check`. To format your files, you can run `make format`.
8+
9+
## Running tests
10+
11+
```
12+
# Run local tests without running envoy processes.
13+
make test
14+
15+
# Run all e2e tests.
16+
# This requires you to have Envoy binary locally.
17+
make test.e2e
18+
19+
# Run e2e tests for a specific example.
20+
# This requires you to have Envoy binary locally.
21+
make test.e2e.single name=helloworld
22+
```
23+
24+
## Code Reviews
25+
26+
* Indicate the priority of each comment, following this
27+
[feedback ladder](https://www.netlify.com/blog/2020/03/05/feedback-ladders-how-we-encode-code-reviews-at-netlify/).
28+
If none was indicated it will be treated as `[dust]`.
29+
* A single approval is sufficient to merge, except when the change cuts
30+
across several components; then it should be approved by at least one owner
31+
of each component. If a reviewer asks for changes in a PR they should be
32+
addressed before the PR is merged, even if another reviewer has already
33+
approved the PR.
34+
* During the review, address the comments and commit the changes _without_ squashing the commits.
35+
This facilitates incremental reviews since the reviewer does not go through all the code again to
36+
find out what has changed since the last review.

e2e/e2e_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ func Test_network(t *testing.T) {
220220
func Test_shared_data(t *testing.T) {
221221
stdErr, kill := startEnvoy(t, 8001)
222222
defer kill()
223-
var count int
223+
var count int = 10000000
224224
require.Eventually(t, func() bool {
225225
res, err := http.Get("http://localhost:18000")
226226
if err != nil {
@@ -231,7 +231,7 @@ func Test_shared_data(t *testing.T) {
231231
return false
232232
}
233233
count++
234-
return count == 10
234+
return count == 10000010
235235
}, 5*time.Second, time.Millisecond, "Endpoint not healthy.")
236236
require.Eventually(t, func() bool {
237237
return checkMessage(stdErr.String(), []string{fmt.Sprintf("shared value: %d", count)}, nil)

examples/dispatch_call_on_tick/main_test.go

+7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
// These tests are supposed to run with `proxytest` build tag, and this way we can leverage the testing framework in "proxytest" package.
2+
// The framework emulates the expected behavior of Envoyproxy, and you can test your extensions without running Envoy and with
3+
// the standard Go CLI. To run tests, simply run
4+
// go test -tags=proxytest ./...
5+
6+
//+build proxytest
7+
18
package main
29

310
import (

examples/foreign_call_on_tick/main_test.go

+7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
// These tests are supposed to run with `proxytest` build tag, and this way we can leverage the testing framework in "proxytest" package.
2+
// The framework emulates the expected behavior of Envoyproxy, and you can test your extensions without running Envoy and with
3+
// the standard Go CLI. To run tests, simply run
4+
// go test -tags=proxytest ./...
5+
6+
//+build proxytest
7+
18
package main
29

310
import (

examples/helloworld/main_test.go

+7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
// These tests are supposed to run with `proxytest` build tag, and this way we can leverage the testing framework in "proxytest" package.
2+
// The framework emulates the expected behavior of Envoyproxy, and you can test your extensions without running Envoy and with
3+
// the standard Go CLI. To run tests, simply run
4+
// go test -tags=proxytest ./...
5+
6+
//+build proxytest
7+
18
package main
29

310
import (

examples/http_auth_random/main_test.go

+7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
// These tests are supposed to run with `proxytest` build tag, and this way we can leverage the testing framework in "proxytest" package.
2+
// The framework emulates the expected behavior of Envoyproxy, and you can test your extensions without running Envoy and with
3+
// the standard Go CLI. To run tests, simply run
4+
// go test -tags=proxytest ./...
5+
6+
//+build proxytest
7+
18
package main
29

310
import (

examples/http_body/main_test.go

+7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
// These tests are supposed to run with `proxytest` build tag, and this way we can leverage the testing framework in "proxytest" package.
2+
// The framework emulates the expected behavior of Envoyproxy, and you can test your extensions without running Envoy and with
3+
// the standard Go CLI. To run tests, simply run
4+
// go test -tags=proxytest ./...
5+
6+
//+build proxytest
7+
18
package main
29

310
import (

examples/http_headers/main_test.go

+7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
// These tests are supposed to run with `proxytest` build tag, and this way we can leverage the testing framework in "proxytest" package.
2+
// The framework emulates the expected behavior of Envoyproxy, and you can test your extensions without running Envoy and with
3+
// the standard Go CLI. To run tests, simply run
4+
// go test -tags=proxytest ./...
5+
6+
//+build proxytest
7+
18
package main
29

310
import (

examples/http_routing/main_test.go

+7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
// These tests are supposed to run with `proxytest` build tag, and this way we can leverage the testing framework in "proxytest" package.
2+
// The framework emulates the expected behavior of Envoyproxy, and you can test your extensions without running Envoy and with
3+
// the standard Go CLI. To run tests, simply run
4+
// go test -tags=proxytest ./...
5+
6+
//+build proxytest
7+
18
package main
29

310
import (

examples/metrics/main_test.go

+7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
// These tests are supposed to run with `proxytest` build tag, and this way we can leverage the testing framework in "proxytest" package.
2+
// The framework emulates the expected behavior of Envoyproxy, and you can test your extensions without running Envoy and with
3+
// the standard Go CLI. To run tests, simply run
4+
// go test -tags=proxytest ./...
5+
6+
//+build proxytest
7+
18
package main
29

310
import (

examples/network/main_test.go

+6-13
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,9 @@
1-
// Copyright 2020-2021 Tetrate
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.
1+
// These tests are supposed to run with `proxytest` build tag, and this way we can leverage the testing framework in "proxytest" package.
2+
// The framework emulates the expected behavior of Envoyproxy, and you can test your extensions without running Envoy and with
3+
// the standard Go CLI. To run tests, simply run
4+
// go test -tags=proxytest ./...
5+
6+
//+build proxytest
147

158
package main
169

examples/shared_data/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
## shared_data
33

44
this example uses the shared key value store (across VMs)
5-
and increments the value in response to http requests atomically.
5+
and increments the global value in response to http requests atomically.
66

77
```
88
wasm log: shared value: 1

examples/shared_data/main.go

+17-9
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,17 @@
1515
package main
1616

1717
import (
18+
"encoding/binary"
1819
"errors"
1920

2021
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm"
2122
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm/types"
2223
)
2324

24-
const sharedDataKey = "shared_data_key"
25+
const (
26+
sharedDataKey = "shared_data_key"
27+
sharedDataInitialValue uint64 = 10000000
28+
)
2529

2630
func main() {
2731
proxywasm.SetVMContext(&vmContext{})
@@ -44,7 +48,9 @@ type (
4448

4549
// Override types.VMContext.
4650
func (*vmContext) OnVMStart(vmConfigurationSize int) types.OnVMStartStatus {
47-
if err := proxywasm.SetSharedData(sharedDataKey, []byte{0}, 0); err != nil {
51+
initialValueBuf := make([]byte, 8)
52+
binary.LittleEndian.PutUint64(initialValueBuf, sharedDataInitialValue)
53+
if err := proxywasm.SetSharedData(sharedDataKey, initialValueBuf, 0); err != nil {
4854
proxywasm.LogWarnf("error setting shared data on OnVMStart: %v", err)
4955
}
5056
return types.OnVMStartStatusOK
@@ -65,7 +71,7 @@ func (ctx *httpContext) OnHttpRequestHeaders(numHeaders int, endOfStream bool) t
6571
for {
6672
value, err := ctx.incrementData()
6773
if err == nil {
68-
proxywasm.LogInfof("shared value: %d", value[0])
74+
proxywasm.LogInfof("shared value: %d", value)
6975
} else if errors.Is(err, types.ErrorStatusCasMismatch) {
7076
continue
7177
}
@@ -74,17 +80,19 @@ func (ctx *httpContext) OnHttpRequestHeaders(numHeaders int, endOfStream bool) t
7480
return types.ActionContinue
7581
}
7682

77-
func (ctx *httpContext) incrementData() ([]byte, error) {
83+
func (ctx *httpContext) incrementData() (uint64, error) {
7884
value, cas, err := proxywasm.GetSharedData(sharedDataKey)
7985
if err != nil {
8086
proxywasm.LogWarnf("error getting shared data on OnHttpRequestHeaders: %v", err)
81-
return value, err
87+
return 0, err
8288
}
8389

84-
value[0]++
85-
if err := proxywasm.SetSharedData(sharedDataKey, value, cas); err != nil {
90+
buf := make([]byte, 8)
91+
ret := binary.LittleEndian.Uint64(value) + 1
92+
binary.LittleEndian.PutUint64(buf, ret)
93+
if err := proxywasm.SetSharedData(sharedDataKey, buf, cas); err != nil {
8694
proxywasm.LogWarnf("error setting shared data on OnHttpRequestHeaders: %v", err)
87-
return value, err
95+
return 0, err
8896
}
89-
return value, err
97+
return ret, err
9098
}

0 commit comments

Comments
 (0)