tetratelabs / proxy-wasm-go-sdk Goto Github PK
View Code? Open in Web Editor NEWWebAssembly for Proxies (Go SDK)
License: Apache License 2.0
WebAssembly for Proxies (Go SDK)
License: Apache License 2.0
With the following code:
// override
func (ctx faultInjection) OnHttpRequestHeaders(int, bool) types.Action {
if time.Now().UnixNano()%100 < 5 {
time.Sleep(time.Millisecond * 500)
proxywasm.LogInfo("sleep for 500 milliseconds...")
}
return types.ActionContinue
}
we have the following compile error
tinygo build -o ./examples/fault_injection/main.go.wasm -target=wasi -wasm-abi=generic ./examples/fault_injection/main.go
panic: trying to make exported function async: proxy_on_request_headers
goroutine 1 [running]:
github.com/tinygo-org/tinygo/transform.(*coroutineLoweringPass).findAsyncFuncs(0xc003e7b040)
/home/circleci/project/transform/coroutines.go:186 +0xa64
github.com/tinygo-org/tinygo/transform.(*coroutineLoweringPass).load(0xc003e7b040, 0x20, 0x7f79bca925f0)
/home/circleci/project/transform/coroutines.go:305 +0x36c
github.com/tinygo-org/tinygo/transform.LowerCoroutines(0x838d8b0, 0x838d801, 0x0, 0x0)
/home/circleci/project/transform/coroutines.go:70 +0x15f
github.com/tinygo-org/tinygo/transform.Optimize(0x838d8b0, 0xc000267dd0, 0x2, 0x2, 0x5, 0x0, 0x0, 0x0)
/home/circleci/project/transform/optimizer.go:120 +0xef0
github.com/tinygo-org/tinygo/builder.Build(0x7ffe3611dae1, 0x22, 0x7ffe3611da9a, 0x27, 0xc000267dd0, 0xc003e7bba8, 0x0, 0x0)
/home/circleci/project/builder/build.go:109 +0x337a
main.Build(0x7ffe3611dae1, 0x22, 0x7ffe3611da9a, 0x27, 0xc0002a8000, 0x0, 0x12)
/home/circleci/project/main.go:99 +0xc5
main.main()
/home/circleci/project/main.go:909 +0x2071
make: *** [Makefile:10: build.example] Error 2
This seems something to do with scheduler
How to support developers to run programs in debugging mode?
I tried to get a compilation error:
# github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm/rawhostcall
../../proxywasm/rawhostcall/rawhostcall.go:24:6: missing function body
../../proxywasm/rawhostcall/rawhostcall.go:27:6: missing function body
../../proxywasm/rawhostcall/rawhostcall.go:31:6: missing function body
../../proxywasm/rawhostcall/rawhostcall.go:34:6: missing function body
../../proxywasm/rawhostcall/rawhostcall.go:37:6: missing function body
../../proxywasm/rawhostcall/rawhostcall.go:40:6: missing function body
../../proxywasm/rawhostcall/rawhostcall.go:43:6: missing function body
../../proxywasm/rawhostcall/rawhostcall.go:46:6: missing function body
../../proxywasm/rawhostcall/rawhostcall.go:49:6: missing function body
../../proxywasm/rawhostcall/rawhostcall.go:52:6: missing function body
../../proxywasm/rawhostcall/rawhostcall.go:52:6: too many errors
e.g. executing runtime.GC
in OnTick
I was wondering if it would be possible to rebuild the latest docker container for every master pipeline. Currently the newest image is 12 days old
I also noticed a rather annoying typo in the readme:
getenvoy/extention-tingyo-builder:wasi-dev
Should be:
getenvoy/extension-tingyo-builder:wasi-dev
Might be nice to add an example of building filters using the docker file in the REAMDE as well!
ENV:
envoy version: 5c801b25cae04f06bf48248c90e87d623d7a6283/1.17.0/Modified/DEBUG/BoringSSL
tinygo v0.16.0.
Hi
I refer to examples/http_body
func (ctx *context) OnHttpRequestBody(bodySize int, endOfStream bool) types.Action {
proxywasm.LogInfof("body size: %d", bodySize)
if bodySize != 0 {
initialBody, err := proxywasm.GetHttpRequestBody(0, bodySize)
if err != nil {
proxywasm.LogErrorf("failed to get request body: %v", err)
return types.ActionContinue
}
proxywasm.LogInfof("initial request body: %s", string(initialBody))
err = proxywasm.SetHttpRequestBody([]byte(`{"hello":"henry"}`))
if err != nil {
proxywasm.LogErrorf("failed to set request body: %v", err)
return types.ActionContinue
}
proxywasm.LogInfof("on http request body finished")
}
return types.ActionContinue
}
envoy debug
[2021-02-03 16:20:45.965][1141921][info][wasm] [source/extensions/common/wasm/context.cc:1171] wasm log: body size: 5
[2021-02-03 16:20:45.965][1141921][info][wasm] [source/extensions/common/wasm/context.cc:1171] wasm log: initial request body: {"hello":"Alice"}
[2021-02-03 16:20:45.965][1141921][error][wasm] [source/extensions/common/wasm/context.cc:1177] wasm log: failed to set request body: error status returned by host: bad argument
but in the Test case everything is ok, So why failed to set request body: error status returned by host: bad argument
thanks
I'm trying to modify the upstream data being sent back from a network filter and encountering a bad argument status from
I thought perhaps #45 may have covered this case, but the implementations seem to be specific to l7 filters.
Is this currently supported and I'm just setting the wrong buffer type or is it currently not supported by the sdk, cpp-host, or wasi?
I've tried this demo code
func (ctx *httpHeaders) OnHttpRequestHeaders(numHeaders int, endOfStream bool) types.Action {
hs, err := proxywasm.GetHttpRequestHeaders()
token := // get token from header
if len(token) == 0 { // token does not exist
proxywasm.SendHttpResponse(401, [][2]string{
{"powered-by", "proxy-wasm-go-sdk!!"},
}, "reject")
}
return types.ActionContinue
}
and got error
envoy bug failure: !state_.local_complete_ || status == FilterHeadersStatus::StopIteration. Details: Filters should return FilterHeadersStatus::StopIteration after sending a local reply.
Caught Abort trap: 6, suspect faulting address 0x7fff20307462
Backtrace (use tools/stack_decode.py to get line numbers):
Envoy version: d6a4496e712d7a2335b26e2f76210d5904002c26/1.17.1/Modified/DEBUG/BoringSSL
#0: Envoy::SignalAction::sigHandler() [0x118340bdc]
#1: _sigtramp [0x7fff20379d7d]
#2: [0x0]
#3: abort [0x7fff20288720]
#4: Envoy::Http::FilterManager::decodeHeaders() [0x116a99b0f]
#5: Envoy::Http::FilterManager::decodeHeaders() [0x1169d4dd6]
#6: Envoy::Http::ConnectionManagerImpl::ActiveStream::decodeHeaders() [0x1169d3976]
#7: Envoy::Http::Http1::ServerConnectionImpl::onMessageComplete() [0x116b9d34a]
#8: Envoy::Http::Http1::ConnectionImpl::onMessageCompleteBase() [0x116b9932d]
#9: Envoy::Http::Http1::ConnectionImpl::$_8::operator()() [0x116ba9440]
#10: Envoy::Http::Http1::ConnectionImpl::$_8::__invoke() [0x116b8e2e5]
#11: http_parser_execute [0x1181a2d30]
#12: Envoy::Http::Http1::ConnectionImpl::dispatchSlice() [0x116b93b44]
#13: Envoy::Http::Http1::ConnectionImpl::innerDispatch() [0x116b92306]
#14: Envoy::Http::Http1::ConnectionImpl::dispatch()::$_14::operator()() [0x116be190e]
#15: std::__1::__invoke<>() [0x116be18bb]
#16: std::__1::__invoke_void_return_wrapper<>::__call<>() [0x116be183b]
#17: std::__1::__function::__alloc_func<>::operator()() [0x116be17cb]
#18: std::__1::__function::__func<>::operator()() [0x116be04cd]
#19: std::__1::__function::__value_func<>::operator()() [0x117f3f18b]
#20: std::__1::function<>::operator()() [0x117f02946]
#21: Envoy::Http::Utility::exceptionToStatus() [0x117f02618]
#22: Envoy::Http::Http1::ConnectionImpl::dispatch() [0x116b90e53]
#23: Envoy::Http::Http1::ConnectionImpl::dispatch() [0x116b90f3b]
#24: Envoy::Http::ConnectionManagerImpl::onData() [0x1169c8bf4]
#25: Envoy::Network::FilterManagerImpl::onContinueReading() [0x114e79791]
#26: Envoy::Network::FilterManagerImpl::onRead() [0x114e7a012]
#27: Envoy::Network::ConnectionImpl::onRead() [0x114df6454]
#28: Envoy::Network::ConnectionImpl::onReadReady() [0x114dffdb1]
#29: Envoy::Network::ConnectionImpl::onFileEvent() [0x114dfc3e0]
#30: Envoy::Network::ConnectionImpl::ConnectionImpl()::$_6::operator()() [0x114e409be]
#31: std::__1::__invoke<>() [0x114e40981]
#32: std::__1::__invoke_void_return_wrapper<>::__call<>() [0x114e40922]
#33: std::__1::__function::__alloc_func<>::operator()() [0x114e408d2]
#34: std::__1::__function::__func<>::operator()() [0x114e3f5f3]
#35: std::__1::__function::__value_func<>::operator()() [0x114d0144d]
#36: std::__1::function<>::operator()() [0x114d013ef]
#37: Envoy::Event::DispatcherImpl::createFileEvent()::$_3::operator()() [0x114d013b4]
#38: std::__1::__invoke<>() [0x114d01361]
#39: std::__1::__invoke_void_return_wrapper<>::__call<>() [0x114d01302]
#40: std::__1::__function::__alloc_func<>::operator()() [0x114d012b2]
#41: std::__1::__function::__func<>::operator()() [0x114cffe83]
#42: std::__1::__function::__value_func<>::operator()() [0x114d0144d]
#43: std::__1::function<>::operator()() [0x114d013ef]
#44: Envoy::Event::FileEventImpl::mergeInjectedEventsAndRunCb() [0x114d0b5d5]
#45: Envoy::Event::FileEventImpl::assignEvents()::$_1::operator()() [0x114d0bb83]
#46: Envoy::Event::FileEventImpl::assignEvents()::$_1::__invoke() [0x114d0b786]
#47: event_persist_closure [0x11818f0e5]
#48: event_process_active_single_queue [0x11818e718]
#49: event_process_active [0x118188ee4]
#50: event_base_loop [0x118187dab]
#51: Envoy::Event::LibeventScheduler::run() [0x118077af4]
#52: Envoy::Event::DispatcherImpl::run() [0x114cc820a]
#53: Envoy::Server::WorkerImpl::threadRoutine() [0x114bd43e5]
#54: Envoy::Server::WorkerImpl::start()::$_5::operator()() [0x114c0804c]
#55: std::__1::__invoke<>() [0x114c0800d]
#56: std::__1::__invoke_void_return_wrapper<>::__call<>() [0x114c07fbd]
#57: std::__1::__function::__alloc_func<>::operator()() [0x114c07f8d]
#58: std::__1::__function::__func<>::operator()() [0x114c06cbe]
#59: std::__1::__function::__value_func<>::operator()() [0x10ab1fb55]
#60: std::__1::function<>::operator()() [0x10ab1f925]
by following C++ SDK
serves as a corresponding one to https://github.com/tetratelabs/envoy-wasm-rust-sdk
I cannot run the demo program,I use the latest version of Envoy。
FROM envoyproxy/envoy-dev:latest
COPY ./envoy.yaml /etc/envoy.yaml
COPY ./lib/envoy_filter_http_wasm_example.wasm /lib/envoy_filter_http_wasm_example.wasm
RUN chmod go+r /etc/envoy.yaml /lib/envoy_filter_http_wasm_example.wasm
CMD ["/usr/local/bin/envoy", "-c", "/etc/envoy.yaml", "--service-cluster", "proxy", "-l", "debug"]
Envoy Config:
static_resources:
listeners:
- address:
socket_address:
address: 0.0.0.0
port_value: 8000
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
codec_type: auto
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains:
- "*"
routes:
- match:
prefix: "/"
route:
cluster: web_service
http_filters:
- name: envoy.filters.http.wasm
typed_config:
"@type": type.googleapis.com/udpa.type.v1.TypedStruct
type_url: type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm
value:
config:
name: "my_plugin"
root_id: "my_root_id"
configuration:
"@type": "type.googleapis.com/google.protobuf.StringValue"
value: |
{}
vm_config:
runtime: "envoy.wasm.runtime.v8"
vm_id: "my_vm_id"
code:
local:
filename: "lib/envoy_filter_http_wasm_example.wasm"
configuration: {}
- name: envoy.filters.http.router
typed_config: {}
clusters:
- name: web_service
connect_timeout: 0.25s
type: strict_dns
lb_policy: round_robin
load_assignment:
cluster_name: service1
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: web_service
port_value: 9000
admin:
access_log_path: "/dev/null"
address:
socket_address:
address: 0.0.0.0
port_value: 8001
Golang Code:
package main
import (
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm"
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm/types"
)
func main() {
proxywasm.SetNewHttpContext(newContext)
}
type httpHeaders struct {
// you must embed the default context so that you need not to reimplement all the methods by yourself
proxywasm.DefaultHttpContext
contextID uint32
}
func newContext(rootContextID, contextID uint32) proxywasm.HttpContext {
return &httpHeaders{contextID: contextID}
}
// override
func (ctx *httpHeaders) OnHttpRequestHeaders(numHeaders int, endOfStream bool) types.Action {
hs, err := proxywasm.GetHttpRequestHeaders()
if err != nil {
proxywasm.LogCriticalf("failed to get request headers: %v", err)
}
for _, h := range hs {
proxywasm.LogInfof("request header --> %s: %s", h[0], h[1])
}
return types.ActionContinue
}
// override
func (ctx *httpHeaders) OnHttpResponseHeaders(numHeaders int, endOfStream bool) types.Action {
hs, err := proxywasm.GetHttpResponseHeaders()
if err != nil {
proxywasm.LogCriticalf("failed to get request headers: %v", err)
}
for _, h := range hs {
proxywasm.LogInfof("response header <-- %s: %s", h[0], h[1])
}
return types.ActionContinue
}
// override
func (ctx *httpHeaders) OnHttpStreamDone() {
proxywasm.LogInfof("%d finished", ctx.contextID)
}
The version information of tinygo is as follows
tinygo version
tinygo version 0.15.0 darwin/amd64 (using go version go1.15.3 and LLVM version 10.0.1)
The build method is as follows
tinygo build -o ./main.go.wasm -target=wasm -wasm-abi=generic ./main.go
not sure if this is a bug in Envoy release/v1.15.0 or this SDK.
I need to get wordload instance information in proxy-wasm extension. I have tried to get these information through environment variables and reading files(such as /etc/istio/pod/labels) mounted by envoy, but all have failed. Can someone help me?
This is a great project and I have been studying wasm-go recently. Is there any update? thanks
Hi,
I am trying to experiment with the go SDK and encountered following issue when building the examples.
$tinygo build -o wasm.wasm -wasm-abi=generic -target wasm ./main.go && docker-compose up | grep OnTick
/main.go: cannot find package "github.com/mathetake/proxy-wasm-go/runtime" in any of:
/usr/local/go/src/github.com/mathetake/proxy-wasm-go/runtime (from $GOROOT)
/Users/menakajayawardena/go/src/github.com/mathetake/proxy-wasm-go/runtime (from $GOPATH)
Could you please let me know if anything to be done to overcome this?
Thanks
I find some funcs such as proxy_get_header_map_value
that don't include contextid,how can host impl to return the corrent request header ?
Hi,
While experimenting with the SDK, I was trying to do actions like JSON decoding the headers etc.
The code is compiling but throws an error when starting up envoy.
proxy_1 | Failed to load WASM module due to a missing import: env.syscall/js.valueGet
I was also trying to do io stuff like reading a file etc. But got the same error.
What could be the reason for this? Would there be any workaround which can be done in the sdk level to fix this?
I see APIs for modifying the request/response headers and body, but none for modifying the request query params. Is this not supported?
this is more generic and not limited to proxy-wasm, will do in another repository
https://github.com/proxy-wasm/spec/tree/master/abi-versions#memory-ownership
I see only malloc mem, how to free mem on Golang? thx
//go:export malloc
func malloc(size uint) *byte {
buf := make([]byte, size)
return &buf[0]
}
Go-based SDK extensions, does the plugin support memory release?
Opened a PR
somewhat related to #12
It would be great to have examples in this SDK as many as possible under examples/
directory. Please feel free to add and send PRs 😉
I found out of memory problems with wasm extension in the following two situations:
So, I want to know how to set the maximum memory each VM can allocate? Can someone help me?
There's a ABI called proxy_set_buffer_bytes
but it currently always returns BadArgument
almost similar to #67 and clock_time_get
is not implemented in host yet
Failed to load Wasm module due to a missing import: wasi_unstable.clock_time_get
some of the if statements can be removed by trusting host implementations:
proxy-wasm-go-sdk/proxywasm/vmstate.go
Lines 59 to 65 in 0638371
we should discuss how to deal with this
If I use GetCalloutAttributesFromContext on a callout with a body the body is not returned.
Is there a particular reason the body is not added here? If it can simply be added here I'd be happy to open a PR https://github.com/tetratelabs/proxy-wasm-go-sdk/blob/main/proxytest/root.go#L250
I'd like to see proxy_get_buffer_status(), e.g. https://github.com/proxy-wasm/proxy-wasm-cpp-host/blob/92f02c0001592199d99f946cea34637ff095a8ba/include/proxy-wasm/wasm_api_impl.h#L147
Also proxy_get_header_map_size() , e.g. https://github.com/proxy-wasm/proxy-wasm-cpp-host/blob/92f02c0001592199d99f946cea34637ff095a8ba/include/proxy-wasm/wasm_api_impl.h#L192
I use these when debugging new extensions.
Would there be concurrent risk since native map in golang doesn't support concurrent write ?
std::terminate called! (possible uncaught exception, see trace)
Backtrace (use tools/stack_decode.py to get line numbers):
Envoy version: 7a49df81214b249c9928a2e77e3bd4e540fa6ab1/1.18.0-dev/Clean/DEBUG/BoringSSL
#0: Envoy::TerminateHandler::logOnTerminate()::$_0::operator()() [0x56202304c184]
#1: Envoy::TerminateHandler::logOnTerminate()::$_0::__invoke() [0x56202304bf69]
#2: __cxxabiv1::__terminate() [0x562023e98b06]
Caught Aborted, suspect faulting address 0x3e800007f10
Backtrace (use tools/stack_decode.py to get line numbers):
Envoy version: 7a49df81214b249c9928a2e77e3bd4e540fa6ab1/1.18.0-dev/Clean/DEBUG/BoringSSL
#0: Envoy::SignalAction::sigHandler() [0x562022dde169]
#1: __restore_rt [0x7fa3905363c0]
#2: Envoy::TerminateHandler::logOnTerminate()::$_0::__invoke() [0x56202304bf69]
#3: __cxxabiv1::__terminate() [0x562023e98b06]
ActiveStream 0x57d33dc67600, stream_id_: 4762672115198020022&filter_manager_:
I want to load and cache some data into the filter.
func (ctx *rootContext) OnTick() {
updateRules()
}
func updateRules() {
hs := [][2]string{{":method", "GET"}, {":authority", "some_authority"}, {":path", "/path/to/service"}, {"accept", "*/*"}}
if _, err := proxywasm.DispatchHttpCall(clusterName, hs, "", [][2]string{},
5000, httpCallResponseCallback1); err != nil {
proxywasm.LogCriticalf("dipatch1 httpcall failed: %v", err)
}
}
And it causes 'runtime error: nil pointer dereference'. Is it a bug ? Is it possible somehow to solve this ?
which requires me to implement the fake host
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.