Skip to content
This repository has been archived by the owner on May 16, 2024. It is now read-only.

Commit

Permalink
Add dispatch call e2e test (#37)
Browse files Browse the repository at this point in the history
  • Loading branch information
anuraaga authored Oct 26, 2023
1 parent 9b18576 commit f18af31
Show file tree
Hide file tree
Showing 19 changed files with 663 additions and 47 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,7 @@ jobs:
- name: setup wasmtime for tinygo
run: go install github.com/wasilibs/tools/cmd/wasmtime@e3baa6a6b2955f731f4490728b09fb87b35e27e9

- run: go run mage.go check
- run: go run mage.go lint
if: ${{ startsWith(matrix.os, 'ubuntu-') }}

- run: go run mage.go test
6 changes: 6 additions & 0 deletions .github/workflows/e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ jobs:
matrix:
target:
- coraza
- envoyDispatchCall
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v4
Expand All @@ -29,3 +30,8 @@ jobs:
tinygo-version: 0.30.0

- run: go run mage.go e2e${{ matrix.target }}

- uses: actions/upload-artifact@v3
with:
name: logs
path: build/logs/
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.idea
build
e2e/coraza-proxy-wasm
go.work.sum
6 changes: 3 additions & 3 deletions bench/bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func TestExportsMalloc(t *testing.T) {
r := wazero.NewRuntime(ctx)
wasi_snapshot_preview1.MustInstantiate(ctx, r)

mod, err := r.InstantiateModuleFromBinary(ctx, wasm)
mod, err := r.Instantiate(ctx, wasm)
if err != nil {
t.Fatal(err)
}
Expand All @@ -52,7 +52,7 @@ func TestEnvoyDoesNotExportMalloc(t *testing.T) {
r := wazero.NewRuntime(ctx)
wasi_snapshot_preview1.MustInstantiate(ctx, r)

mod, err := r.InstantiateModuleFromBinary(ctx, wasm)
mod, err := r.Instantiate(ctx, wasm)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -82,7 +82,7 @@ func BenchmarkGC(b *testing.B) {
r := wazero.NewRuntime(ctx)
wasi_snapshot_preview1.MustInstantiate(ctx, r)

mod, err := r.InstantiateModuleFromBinary(ctx, wasm)
mod, err := r.Instantiate(ctx, wasm)
if err != nil {
b.Fatal(err)
}
Expand Down
5 changes: 4 additions & 1 deletion bench/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ go 1.19

require github.com/wasilibs/nottinygc v0.0.0-00010101000000-000000000000

require github.com/tetratelabs/wazero v1.0.0-pre.8 // indirect
require (
github.com/magefile/mage v1.14.0 // indirect
github.com/tetratelabs/wazero v1.5.0
)

replace github.com/wasilibs/nottinygc => ../
6 changes: 4 additions & 2 deletions bench/go.sum
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
github.com/tetratelabs/wazero v1.0.0-pre.8 h1:Ir82PWj79WCppH+9ny73eGY2qv+oCnE3VwMY92cBSyI=
github.com/tetratelabs/wazero v1.0.0-pre.8/go.mod h1:u8wrFmpdrykiFK0DFPiFm5a4+0RzsdmXYVtijBKqUVo=
github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo=
github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/tetratelabs/wazero v1.5.0 h1:Yz3fZHivfDiZFUXnWMPUoiW7s8tC1sjdBtlJn08qYa0=
github.com/tetratelabs/wazero v1.5.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A=
19 changes: 19 additions & 0 deletions e2e/envoy-dispatch-call/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
services:
httpbin:
image: mccutchen/go-httpbin:v2.9.0
command: [ "/bin/go-httpbin", "-port", "8081" ]
ports:
- 8081:8081
envoy:
depends_on:
- httpbin
image: ${ENVOY_IMAGE:-envoyproxy/envoy:v1.28-latest}
command:
- -c
- /conf/envoy-config.yaml
volumes:
- ./build:/build
- ./envoy:/conf
ports:
- 8080:8080
- 8082:8082
81 changes: 81 additions & 0 deletions e2e/envoy-dispatch-call/envoy/envoy-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
static_resources:
listeners:
- address:
socket_address:
address: 0.0.0.0
port_value: 8080
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
stat_prefix: ingress_http
codec_type: auto
route_config:
virtual_hosts:
- name: local_route
domains:
- "*"
routes:
- match:
prefix: "/"
route:
cluster: local_server
http_filters:
- name: envoy.filters.http.wasm
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm
config:
name: "wasm-test"
root_id: ""
configuration:
"@type": "type.googleapis.com/google.protobuf.StringValue"
value: |
{
"auth_cluster_name": "auth_server",
"auth_authority": "localhost:8081"
}
vm_config:
runtime: "envoy.wasm.runtime.v8"
vm_id: "my_vm_id"
code:
local:
filename: "build/plugin.wasm"
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

clusters:
- name: local_server
connect_timeout: 6000s
type: STRICT_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: local_server
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: httpbin
port_value: 8081
- name: auth_server
connect_timeout: 6000s
type: STRICT_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: local_server
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: httpbin
port_value: 8081

admin:
access_log_path: "/dev/null"
address:
socket_address:
address: 0.0.0.0
port_value: 8082
18 changes: 18 additions & 0 deletions e2e/envoy-dispatch-call/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module github.com/wasilibs/nottinygc/e2e/envoy-dispatch-call

go 1.20

replace github.com/wasilibs/nottinygc => ../..

require (
github.com/tetratelabs/proxy-wasm-go-sdk v0.22.0
github.com/tidwall/gjson v1.14.4
github.com/wasilibs/nottinygc v0.6.0
)

require (
github.com/magefile/mage v1.14.0 // indirect
github.com/stretchr/testify v1.8.3 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
)
15 changes: 15 additions & 0 deletions e2e/envoy-dispatch-call/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo=
github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/tetratelabs/proxy-wasm-go-sdk v0.22.0 h1:kS7BvMKN+FiptV4pfwiNX8e3q14evxAWkhYbxt8EI1M=
github.com/tetratelabs/proxy-wasm-go-sdk v0.22.0/go.mod h1:qkW5MBz2jch2u8bS59wws65WC+Gtx3x0aPUX5JL7CXI=
github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
91 changes: 91 additions & 0 deletions e2e/envoy-dispatch-call/internal/auth_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright wasilibs authors
// SPDX-License-Identifier: MIT

package internal

import (
"strconv"

"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm"
)

type AuthClient struct {
XRequestID string
Conf *Config
Metrics *Metrics
}

func (d *AuthClient) RequestJWT() {
// Now actually call the Auth Service.
_, err := proxywasm.DispatchHttpCall(
d.Conf.AuthClusterName,
[][2]string{
{"accept", "*/*"},
{":authority", d.Conf.AuthAuthority},
{":method", "GET"},
{":path", "/status/200"}, // get Httpbin to return some fake data
},
nil,
nil,
d.Conf.AuthTimeout,
d.authCallback,
)
if err != nil {
proxywasm.LogCriticalf("%s: failed to call AuthService: %v", d.XRequestID, err)
// We want to resume the intercepted request even if we couldn't get an authentication header
_ = proxywasm.ResumeHttpRequest()
}
}

func (d *AuthClient) authCallback(_, _, _ int) {
responseStatus := uint32(500)
d.Metrics.Increment("authCallback_count", nil)

// We want to always resume the intercepted request regardless of success/fail to avoid indefinitely blocking anything
defer func() {
if responseStatus != 200 {
responseErr := proxywasm.SendHttpResponse(responseStatus, [][2]string{{"generated-by", "My WASM plugin"}}, []byte("Failed to add JWT"), -1)
if responseErr == nil {
return // Need to skip calling ResumeHttpRequest to avoid sending this to upstream service
}
proxywasm.LogErrorf("%s: failed to send %d back to client: %v", d.XRequestID, responseStatus, responseErr)
}
if err := proxywasm.ResumeHttpRequest(); err != nil {
proxywasm.LogCriticalf("%s: failed to ResumeHttpRequest after calling auth: %v", d.XRequestID, err)
}
}()

// Get the response headers from our call to AuthService
headers, err := proxywasm.GetHttpCallResponseHeaders()
if err != nil {
proxywasm.LogCriticalf("%s: failed to GetHttpCallResponseHeaders from auth response: %v", d.XRequestID, err)
return
}

// Convert to map to make it easier to get specific headers
authResponseHeaders := headerArrayToMap(headers)

// Note we're using `:status` instead of just `status`. This is the same for any HTTP-transport-specific headers like ':method', ':path', ':authority', ...
// You don't need the ':' prefix for headers like 'user-agent', 'accept, ...
if authResponseHeaders[":status"] == "200" {
h := "x-test"

if err := proxywasm.AddHttpRequestHeader(h, "foo"); err != nil {
// proxywasm.LogCriticalf("%s: failed to add header '%v' to request: %v", fc.XRequestID, h, err)
d.Metrics.Increment("error_count", nil)
return
}

responseStatus = 200
d.Metrics.Increment("authCallback_success_count", nil)
return
}

if len(authResponseHeaders[":status"]) > 0 {
status, err := strconv.ParseInt(authResponseHeaders[":status"], 10, 0)
if err == nil {
responseStatus = uint32(status)
}
}
d.Metrics.Increment("authCallback_fail_count", nil)
}
69 changes: 69 additions & 0 deletions e2e/envoy-dispatch-call/internal/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright wasilibs authors
// SPDX-License-Identifier: MIT

package internal

import (
"time"

"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm"
"github.com/tidwall/gjson"
)

const (
AuthTimeoutDefault = time.Second
)

// Config is used to extract any WASMPlugin configuration defined in the deployed YML
type Config struct {
AuthClusterName string
AuthAuthority string
AuthTimeout uint32
}

func NewConfig() *Config {
configuration := getPluginConfiguration()
config := Config{
AuthClusterName: getStringFromConfig(configuration, "auth_cluster_name"),
AuthAuthority: getStringFromConfig(configuration, "auth_authority"),
AuthTimeout: uint32(getInt64FromConfig(configuration, "auth_timeout_ms", AuthTimeoutDefault.Milliseconds())),
}

return &config
}

func getPluginConfiguration() gjson.Result {
proxywasm.LogWarnf("Getting WASM plugin config...")
configuration, err := proxywasm.GetPluginConfiguration()
if err != nil {
proxywasm.LogCriticalf("error reading plugin configuration: %v", err)
}
if len(configuration) == 0 {
proxywasm.LogCritical("WASM plugin config was empty")
return gjson.Result{}
}
if !gjson.ValidBytes(configuration) {
proxywasm.LogCriticalf("WASM plugin config was invalid: %s", configuration)
return gjson.Result{}
}

result := gjson.ParseBytes(configuration)
return result
}

func getStringFromConfig(configuration gjson.Result, key string) string {
result := configuration.Get(key)
if result.Exists() {
return result.String()
}
proxywasm.LogCriticalf("Configuration for '%s' wasn't set in config:%s", key, configuration)
return ""
}

func getInt64FromConfig(configuration gjson.Result, key string, defaultResult int64) int64 {
result := configuration.Get(key)
if result.Exists() {
return result.Int()
}
return defaultResult
}
Loading

0 comments on commit f18af31

Please sign in to comment.