feat(plugin): add proxywasm plugin (#284)
* feat(plugin): add `proxywasm` plugin The `proxywasm` plugin is a WASM Filter following the ProxyWasm ABI Specification using the proxywasm go sdk This allows extensibility with any reverse proxy who implements the ProxyWasm ABI Specification. The current WASM Filter was successfully tested with APISIX, Envoy, Nginx with ngx_wasm_module from Kong and Istio. Fixes #145
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "Go",
|
"name": "Go",
|
||||||
"image": "mcr.microsoft.com/devcontainers/go:1.22-bookworm",
|
"image": "mcr.microsoft.com/devcontainers/go:1.22",
|
||||||
"features": {
|
"features": {
|
||||||
"ghcr.io/devcontainers/features/node:1": {
|
"ghcr.io/devcontainers/features/node:1": {
|
||||||
"version": "lts"
|
"version": "lts"
|
||||||
|
|||||||
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
* text=auto eol=lf
|
||||||
147
.github/workflows/plugins.yml
vendored
@@ -210,3 +210,150 @@ jobs:
|
|||||||
|
|
||||||
- name: Test ${{ matrix.provider }}
|
- name: Test ${{ matrix.provider }}
|
||||||
run: cd plugins/caddy/e2e/${{ matrix.provider }} && bash ./run.sh
|
run: cd plugins/caddy/e2e/${{ matrix.provider }} && bash ./run.sh
|
||||||
|
|
||||||
|
build-proxywasm:
|
||||||
|
name: Build ProxyWasm Plugin once and share it to ProxyWasm E2E jobs
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup TinyGo
|
||||||
|
uses: acifani/setup-tinygo@v2
|
||||||
|
with:
|
||||||
|
tinygo-version: '0.31.2'
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: make proxywasm
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: proxywasm-plugin-wasm
|
||||||
|
path: ./plugins/proxywasm/sablierproxywasm.wasm
|
||||||
|
|
||||||
|
proxywasm_apisix_e2e:
|
||||||
|
name: Run Sablier E2E tests for Proxywasm middleware on Apache APISIX
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs:
|
||||||
|
- build
|
||||||
|
- build-proxywasm
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
provider: [ docker ] #, docker_swarm, kubernetes]
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Go 1.22
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: 1.22
|
||||||
|
cache-dependency-path: |
|
||||||
|
go.sum
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Download artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: sablier-image-tar
|
||||||
|
path: /tmp
|
||||||
|
|
||||||
|
- name: Load Docker image
|
||||||
|
run: docker load --input /tmp/sablier.tar
|
||||||
|
|
||||||
|
- name: Download Proxywasm artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: proxywasm-plugin-wasm
|
||||||
|
path: ./plugins/proxywasm
|
||||||
|
|
||||||
|
- name: Test ${{ matrix.provider }}
|
||||||
|
run: cd plugins/proxywasm/e2e/apacheapisix/${{ matrix.provider }} && bash ./run.sh
|
||||||
|
|
||||||
|
proxywasm_envoy_e2e:
|
||||||
|
name: Run Sablier E2E tests for Proxywasm middleware on Envoy
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs:
|
||||||
|
- build
|
||||||
|
- build-proxywasm
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
provider: [ docker ] #, docker_swarm, kubernetes]
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Go 1.22
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: 1.22
|
||||||
|
cache-dependency-path: |
|
||||||
|
go.sum
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Download artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: sablier-image-tar
|
||||||
|
path: /tmp
|
||||||
|
|
||||||
|
- name: Load Docker image
|
||||||
|
run: docker load --input /tmp/sablier.tar
|
||||||
|
|
||||||
|
- name: Download Proxywasm artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: proxywasm-plugin-wasm
|
||||||
|
path: ./plugins/proxywasm
|
||||||
|
|
||||||
|
- name: Test ${{ matrix.provider }}
|
||||||
|
run: cd plugins/proxywasm/e2e/envoy/${{ matrix.provider }} && bash ./run.sh
|
||||||
|
|
||||||
|
proxywasm_nginx_e2e:
|
||||||
|
name: Run Sablier E2E tests for Proxywasm middleware on Nginx
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs:
|
||||||
|
- build
|
||||||
|
- build-proxywasm
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
provider: [ docker ] #, docker_swarm, kubernetes]
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Go 1.22
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: 1.22
|
||||||
|
cache-dependency-path: |
|
||||||
|
go.sum
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Download artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: sablier-image-tar
|
||||||
|
path: /tmp
|
||||||
|
|
||||||
|
- name: Load Docker image
|
||||||
|
run: docker load --input /tmp/sablier.tar
|
||||||
|
|
||||||
|
- name: Download Proxywasm artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: proxywasm-plugin-wasm
|
||||||
|
path: ./plugins/proxywasm
|
||||||
|
|
||||||
|
- name: Test ${{ matrix.provider }}
|
||||||
|
run: cd plugins/proxywasm/e2e/nginx/${{ matrix.provider }} && bash ./run.sh
|
||||||
|
|||||||
2
.gitignore
vendored
@@ -2,3 +2,5 @@ sablier.yaml
|
|||||||
./plugins/traefik/e2e/kubeconfig.yaml
|
./plugins/traefik/e2e/kubeconfig.yaml
|
||||||
node_modules
|
node_modules
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
*.wasm
|
||||||
|
kubeconfig.yaml
|
||||||
15
.golangci.yml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
linters:
|
||||||
|
enable:
|
||||||
|
- dupword # Checks for duplicate words in the source code.
|
||||||
|
- goimports
|
||||||
|
- gosec
|
||||||
|
- gosimple
|
||||||
|
- govet
|
||||||
|
- importas
|
||||||
|
- ineffassign
|
||||||
|
- misspell
|
||||||
|
- revive
|
||||||
|
- staticcheck
|
||||||
|
- typecheck
|
||||||
|
- unconvert
|
||||||
|
- unused
|
||||||
6
Makefile
@@ -45,6 +45,12 @@ caddy:
|
|||||||
docker build -t caddy:local plugins/caddy
|
docker build -t caddy:local plugins/caddy
|
||||||
|
|
||||||
release: $(PLATFORMS)
|
release: $(PLATFORMS)
|
||||||
|
|
||||||
|
proxywasm:
|
||||||
|
go generate ./plugins/proxywasm
|
||||||
|
tinygo build -ldflags "-X 'main.Version=$(VERSION)'" -o ./plugins/proxywasm/sablierproxywasm.wasm -scheduler=none -target=wasi ./plugins/proxywasm
|
||||||
|
cp ./plugins/proxywasm/sablierproxywasm.wasm ./sablierproxywasm_$(VERSION).wasm
|
||||||
|
|
||||||
.PHONY: release $(PLATFORMS)
|
.PHONY: release $(PLATFORMS)
|
||||||
|
|
||||||
LAST = 0.0.0
|
LAST = 0.0.0
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
  
|
  
|
||||||
|
|
||||||
*This website is still a work in progress and is based on the **beta** branch version*
|
|
||||||
|
|
||||||
# Sablier - Scale to Zero
|
# Sablier - Scale to Zero
|
||||||
|
|
||||||
Sablier is a **free** and **open-source** software that can scale your workloads on demand.
|
Sablier is a **free** and **open-source** software that can scale your workloads on demand.
|
||||||
@@ -19,7 +17,7 @@ Which allows you to start your containers on demand and shut them down automatic
|
|||||||
|
|
||||||
## Glossary
|
## Glossary
|
||||||
|
|
||||||
I'll use these terms in order to be provider agnostic.
|
I'll use these terms in order to be provider-agnostic.
|
||||||
|
|
||||||
- **Session**: A Session is a set of **instances**
|
- **Session**: A Session is a set of **instances**
|
||||||
- **Instance**: An instance is either a docker container, docker swarm service, kubernetes deployment or kubernetes statefulset
|
- **Instance**: An instance is either a docker container, docker swarm service, kubernetes deployment or kubernetes statefulset
|
||||||
|
|||||||
@@ -8,14 +8,18 @@
|
|||||||
- [Versioning](/versioning)
|
- [Versioning](/versioning)
|
||||||
- **Providers**
|
- **Providers**
|
||||||
- [Overview](/providers/overview)
|
- [Overview](/providers/overview)
|
||||||
- [Docker](/providers/docker)
|
- [<img src="assets/img/docker.svg" height=24px width=24px />Docker](/providers/docker)
|
||||||
- [Docker Swarm](/providers/docker_swarm)
|
- [<img src="assets/img/docker_swarm.png" height=24px width=24px />Docker Swarm](/providers/docker_swarm)
|
||||||
- [Kubernetes](/providers/kubernetes)
|
- [<img src="assets/img/kubernetes.png" height=24px width=24px />Kubernetes](/providers/kubernetes)
|
||||||
- **Reverse Proxy Plugins**
|
- **Reverse Proxy Plugins**
|
||||||
- [Overview](/plugins/overview)
|
- [Overview](/plugins/overview)
|
||||||
- [Traefik](/plugins/traefik)
|
- [<img src="assets/img/apacheapisix.png" height=24px width=24px />Apache APISIX](/plugins/apacheapisix)
|
||||||
- [Nginx](/plugins/nginx)
|
- [<img src="assets/img/caddy.png" height=24px width=24px />Caddy](/plugins/caddy)
|
||||||
- [Caddy](/plugins/caddy)
|
- [<img src="assets/img/envoy.png" height=24px width=24px />Envoy](/plugins/envoy)
|
||||||
|
- [<img src="assets/img/istio.png" height=24px width=24px />Istio](/plugins/istio)
|
||||||
|
- [<img src="assets/img/nginx.svg" height=24px width=24px />Nginx (NJS)](/plugins/nginx)
|
||||||
|
- [<img src="assets/img/nginx.svg" height=24px width=24px />Nginx (ProxyWasm)](/plugins/nginx_proxywasm)
|
||||||
|
- [<img src="assets/img/traefik.png" height=24px /> Traefik](/plugins/traefik)
|
||||||
- **Guides**
|
- **Guides**
|
||||||
- [Overview](/guides/overview)
|
- [Overview](/guides/overview)
|
||||||
- [VSCode Server with Traefik and Kubernetes](/guides/code-server-traefik-kubernetes.md)
|
- [VSCode Server with Traefik and Kubernetes](/guides/code-server-traefik-kubernetes.md)
|
||||||
|
|||||||
BIN
docs/assets/img/apacheapisix.png
Normal file
|
After Width: | Height: | Size: 238 KiB |
BIN
docs/assets/img/caddy.png
Normal file
|
After Width: | Height: | Size: 8.0 KiB |
BIN
docs/assets/img/docker_swarm.png
Normal file
|
After Width: | Height: | Size: 121 KiB |
BIN
docs/assets/img/envoy.png
Normal file
|
After Width: | Height: | Size: 9.5 KiB |
BIN
docs/assets/img/istio.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
docs/assets/img/kubernetes.png
Normal file
|
After Width: | Height: | Size: 163 KiB |
2
docs/assets/img/nginx.svg
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg width="800px" height="800px" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"><title>file_type_nginx</title><path d="M15.948,2h.065a10.418,10.418,0,0,1,.972.528Q22.414,5.65,27.843,8.774a.792.792,0,0,1,.414.788c-.008,4.389,0,8.777-.005,13.164a.813.813,0,0,1-.356.507q-5.773,3.324-11.547,6.644a.587.587,0,0,1-.657.037Q9.912,26.6,4.143,23.274a.7.7,0,0,1-.4-.666q0-6.582,0-13.163a.693.693,0,0,1,.387-.67Q9.552,5.657,14.974,2.535c.322-.184.638-.379.974-.535" style="fill:#019639"/><path d="M8.767,10.538q0,5.429,0,10.859a1.509,1.509,0,0,0,.427,1.087,1.647,1.647,0,0,0,2.06.206,1.564,1.564,0,0,0,.685-1.293c0-2.62-.005-5.24,0-7.86q3.583,4.29,7.181,8.568a2.833,2.833,0,0,0,2.6.782,1.561,1.561,0,0,0,1.251-1.371q.008-5.541,0-11.081a1.582,1.582,0,0,0-3.152,0c0,2.662-.016,5.321,0,7.982-2.346-2.766-4.663-5.556-7-8.332A2.817,2.817,0,0,0,10.17,9.033,1.579,1.579,0,0,0,8.767,10.538Z" style="fill:#fff"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
BIN
docs/assets/img/traefik.png
Normal file
|
After Width: | Height: | Size: 258 KiB |
33
docs/plugins/apacheapisix.md
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Apache APISIX Plugin
|
||||||
|
|
||||||
|
The Apache APISIX Plugin is a WASM Plugin written with the Proxy Wasm SDK.
|
||||||
|
|
||||||
|
## Provider compatibility grid
|
||||||
|
|
||||||
|
| Provider | Dynamic | Blocking |
|
||||||
|
|-----------------------------------------|:-------:|:--------:|
|
||||||
|
| [Docker](/providers/docker) | ✅ | ✅ |
|
||||||
|
| [Docker Swarm](/providers/docker_swarm) | ❓ | ❓ |
|
||||||
|
| [Kubernetes](/providers/kubernetes) | ❓ | ❓ |
|
||||||
|
|
||||||
|
## Install the plugin to Apache APISIX
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
wasm:
|
||||||
|
plugins:
|
||||||
|
- name: proxywasm_sablier_plugin
|
||||||
|
priority: 7997
|
||||||
|
file: /wasm/sablierproxywasm.wasm # Downloaded WASM Filter path
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
You can have the following configuration:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
routes:
|
||||||
|
- uri: "/"
|
||||||
|
plugins:
|
||||||
|
proxywasm_sablier_plugin:
|
||||||
|
conf: '{ "sablier_url": "sablier:10000", "group": ["my-group"], "session_duration": "1m", "dynamic": { "display_name": "Dynamic Whoami" } }'
|
||||||
|
```
|
||||||
48
docs/plugins/envoy.md
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
# Envoy Plugin
|
||||||
|
|
||||||
|
The Envoy Plugin is a WASM Plugin written with the Proxy Wasm SDK.
|
||||||
|
|
||||||
|
## Provider compatibility grid
|
||||||
|
|
||||||
|
| Provider | Dynamic | Blocking |
|
||||||
|
|-----------------------------------------|:-------:|:--------:|
|
||||||
|
| [Docker](/providers/docker) | ✅ | ✅ |
|
||||||
|
| [Docker Swarm](/providers/docker_swarm) | ❓ | ❓ |
|
||||||
|
| [Kubernetes](/providers/kubernetes) | ❓ | ❓ |
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
You can have the following configuration:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
http_filters:
|
||||||
|
- name: sablier-wasm-whoami-dynamic
|
||||||
|
disabled: true
|
||||||
|
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: "sablier-wasm-whoami-dynamic"
|
||||||
|
root_id: "sablier-wasm-whoami-dynamic"
|
||||||
|
configuration:
|
||||||
|
"@type": "type.googleapis.com/google.protobuf.StringValue"
|
||||||
|
value: |
|
||||||
|
{
|
||||||
|
"sablier_url": "sablier:10000",
|
||||||
|
"cluster": "sablier",
|
||||||
|
"names": ["docker_classic_e2e-whoami-1"],
|
||||||
|
"session_duration": "1m",
|
||||||
|
"dynamic": {
|
||||||
|
"display_name": "Dynamic Whoami",
|
||||||
|
"theme": "hacker-terminal"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vm_config:
|
||||||
|
runtime: "envoy.wasm.runtime.v8"
|
||||||
|
vm_id: "vm.sablier.sablier-wasm-whoami-dynamic"
|
||||||
|
code:
|
||||||
|
local:
|
||||||
|
filename: "/etc/sablierproxywasm.wasm"
|
||||||
|
configuration: { }
|
||||||
|
```
|
||||||
45
docs/plugins/istio.md
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# Istio Plugin
|
||||||
|
|
||||||
|
The Istio Plugin is a WASM Plugin written with the Proxy Wasm SDK.
|
||||||
|
|
||||||
|
## Provider compatibility grid
|
||||||
|
|
||||||
|
| Provider | Dynamic | Blocking |
|
||||||
|
|-----------------------------------------|:-------:|:--------:|
|
||||||
|
| [Docker](/providers/docker) | ❌ | ❌ |
|
||||||
|
| [Docker Swarm](/providers/docker_swarm) | ❌ | ❌ |
|
||||||
|
| [Kubernetes](/providers/kubernetes) | ✅ | ✅ |
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
You can have the following configuration:
|
||||||
|
|
||||||
|
!> This only works for ingress gateways.
|
||||||
|
!> Attaching this filter to a side-car would not work because the side-car itself gets shutdown on scaling to zero.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: extensions.istio.io/v1alpha1
|
||||||
|
kind: WasmPlugin
|
||||||
|
metadata:
|
||||||
|
name: sablier-wasm-whoami-dynamic
|
||||||
|
namespace: istio-system
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
istio: ingressgateway
|
||||||
|
url: file:///opt/filters/sablierproxywasm.wasm/..data/sablierproxywasm.wasm
|
||||||
|
# Use https://istio.io/latest/docs/reference/config/proxy_extensions/wasm-plugin/#WasmPlugin-TrafficSelector
|
||||||
|
# To specify which service to apply this filter only
|
||||||
|
phase: UNSPECIFIED_PHASE
|
||||||
|
pluginConfig:
|
||||||
|
{
|
||||||
|
"sablier_url": "sablier.sablier-system.svc.cluster.local",
|
||||||
|
"cluster": "outbound|10000||sablier.sablier-system.svc.cluster.local",
|
||||||
|
"names": [ "deployment_default_whoami_1" ],
|
||||||
|
"session_duration": "1m",
|
||||||
|
"dynamic": {
|
||||||
|
"display_name": "Dynamic Whoami",
|
||||||
|
"theme": "hacker-terminal"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
79
docs/plugins/nginx_proxywasm.md
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
# Nginx Plugin
|
||||||
|
|
||||||
|
The Nginx Plugin is a WASM Plugin written with the Proxy Wasm SDK.
|
||||||
|
|
||||||
|
## Provider compatibility grid
|
||||||
|
|
||||||
|
| Provider | Dynamic | Blocking |
|
||||||
|
|-----------------------------------------|:-------:|:--------:|
|
||||||
|
| [Docker](/providers/docker) | ✅ | ✅ |
|
||||||
|
| [Docker Swarm](/providers/docker_swarm) | ❓ | ❓ |
|
||||||
|
| [Kubernetes](/providers/kubernetes) | ❓ | ❓ |
|
||||||
|
|
||||||
|
# Install ngx_wasm_module
|
||||||
|
|
||||||
|
Install https://github.com/Kong/ngx_wasm_module.
|
||||||
|
|
||||||
|
Example for a Dockerfile:
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
FROM ubuntu:22.04
|
||||||
|
|
||||||
|
RUN apt update && apt install libatomic1
|
||||||
|
|
||||||
|
ADD https://github.com/Kong/ngx_wasm_module/releases/download/prerelease-0.3.0/wasmx-prerelease-0.3.0-v8-x86_64-ubuntu22.04.tar.gz wasmx.tar.gz
|
||||||
|
|
||||||
|
RUN mkdir /etc/nginx
|
||||||
|
RUN tar -xvf wasmx.tar.gz
|
||||||
|
RUN mv /wasmx-prerelease-0.3.0-v8-x86_64-ubuntu22.04/* /etc/nginx/
|
||||||
|
|
||||||
|
WORKDIR /etc/nginx
|
||||||
|
|
||||||
|
CMD [ "./nginx", "-g", "daemon off;" ]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
# nginx.conf
|
||||||
|
events {}
|
||||||
|
|
||||||
|
# nginx master process gets a default 'main' VM
|
||||||
|
# a new top-level configuration block receives all configuration for this main VM
|
||||||
|
wasm {
|
||||||
|
module proxywasm_sablier_plugin /wasm/sablierproxywasm.wasm;
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
access_log /dev/stdout;
|
||||||
|
|
||||||
|
# internal docker resolver, see /etc/resolv.conf on proxy container
|
||||||
|
# needed for docker name resolution
|
||||||
|
resolver 127.0.0.11 valid=1s ipv6=off;
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 8080;
|
||||||
|
|
||||||
|
location /dynamic {
|
||||||
|
proxy_wasm proxywasm_sablier_plugin '{ "sablier_url": "sablier:10000", "names": ["docker_classic_e2e-whoami-1"], "session_duration": "1m", "dynamic": { "display_name": "Dynamic Whoami", "theme": "hacker-terminal" } }';
|
||||||
|
|
||||||
|
# force dns resolution by using a variable
|
||||||
|
# because container will be restarted and change ip a lot of times
|
||||||
|
set $proxy_pass_host whoami:80$request_uri;
|
||||||
|
proxy_pass http://$proxy_pass_host;
|
||||||
|
proxy_set_header Host localhost:8080; # e2e test compliance
|
||||||
|
}
|
||||||
|
|
||||||
|
location /blocking {
|
||||||
|
wasm_socket_read_timeout 60s; # Blocking hangs the request
|
||||||
|
proxy_wasm proxywasm_sablier_plugin '{ "sablier_url": "sablier:10000", "names": ["docker_classic_e2e-whoami-1"], "session_duration": "1m", "blocking": { "timeout": "30s" } }';
|
||||||
|
|
||||||
|
# force dns resolution by using a variable
|
||||||
|
# because container will be restarted and change ip a lot of times
|
||||||
|
set $proxy_pass_host whoami:80$request_uri;
|
||||||
|
proxy_pass http://$proxy_pass_host;
|
||||||
|
proxy_set_header Host localhost:8080; # e2e test compliance
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -12,11 +12,24 @@ It leverages the API calls to plugin integration to catch in-flight requests to
|
|||||||
|
|
||||||
## Available Reverse Proxies
|
## Available Reverse Proxies
|
||||||
|
|
||||||
| Reverse Proxy | Docker | Docker Swarm mode | Kubernetes | Podman |
|
| Reverse Proxy | Docker | Docker Swarm mode | Kubernetes |
|
||||||
| ---------------------------- | :----: | :---------------: | :--------: | :-------------------------------------------------------: |
|
|-------------------------------------------------|:------:|:-----------------:|:----------:|
|
||||||
| [Traefik](/plugins/traefik) | ✅ | ✅ | ✅ | [See #70](https://github.com/acouvreur/sablier/issues/70) |
|
| [Apache APISIX](/plugins/apacheapisix) | ✅ | ✅ | ✅ |
|
||||||
| [Nginx](/plugins/nginx) | ✅ | ✅ | ❌ |
|
|
||||||
| [Caddy](/plugins/caddy) | ✅ | ✅ | ❌ |
|
| [Caddy](/plugins/caddy) | ✅ | ✅ | ❌ |
|
||||||
|
| [Envoy](/plugins/envoy) | ✅ | ❓ | ❓ |
|
||||||
|
| [Istio](plugins/istio) | ❌ | ❌ | ⚠️ |
|
||||||
|
| [Nginx (NJS Module)](/plugins/nginx_njs) | ✅ | ✅ | ✅ |
|
||||||
|
| [Nginx (WASM Module)](/plugins/nginx_proxywasm) | ✅ | ❓ | ❓ |
|
||||||
|
| [Traefik](/plugins/traefik) | ✅ | ✅ | ✅ |
|
||||||
|
| [ProxyWasm](/plugins/proxywasm) | ✅ | ✅ | ✅ |
|
||||||
|
|
||||||
|
> ✅ **Fully compatible**
|
||||||
|
>
|
||||||
|
> ⚠️ **Partially compatible**
|
||||||
|
>
|
||||||
|
> ❓ **Should be compatible (but not tested)**
|
||||||
|
>
|
||||||
|
> ❌ **Not compatible**
|
||||||
|
|
||||||
*Your Reverse Proxy is not on the list? [Open an issue to request the missing reverse proxy integration here!](https://github.com/acouvreur/sablier/issues/new?assignees=&labels=enhancement%2C+reverse-proxy&projects=&template=reverse-proxy-integration-request.md&title=Add+%60%5BREVERSE+PROXY%5D%60+reverse+proxy+integration)*
|
*Your Reverse Proxy is not on the list? [Open an issue to request the missing reverse proxy integration here!](https://github.com/acouvreur/sablier/issues/new?assignees=&labels=enhancement%2C+reverse-proxy&projects=&template=reverse-proxy-integration-request.md&title=Add+%60%5BREVERSE+PROXY%5D%60+reverse+proxy+integration)*
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ A Provider typically have the following capabilities:
|
|||||||
## Available providers
|
## Available providers
|
||||||
|
|
||||||
| Provider | Name | Details |
|
| Provider | Name | Details |
|
||||||
| --------------------------------------- | ------------------------- | ---------------------------------------------------------------- |
|
|-----------------------------------------|---------------------------|------------------------------------------------------------------|
|
||||||
| [Docker](/providers/docker) | `docker` | Stop and start **containers** on demand |
|
| [Docker](/providers/docker) | `docker` | Stop and start **containers** on demand |
|
||||||
| [Docker Swarm](/providers/docker_swarm) | `docker_swarm` or `swarm` | Scale down to zero and up **services** on demand |
|
| [Docker Swarm](/providers/docker_swarm) | `docker_swarm` or `swarm` | Scale down to zero and up **services** on demand |
|
||||||
| [Kubernetes](/providers/kubernetes) | `kubernetes` | Scale down and up **deployments** and **statefulsets** on demand |
|
| [Kubernetes](/providers/kubernetes) | `kubernetes` | Scale down and up **deployments** and **statefulsets** on demand |
|
||||||
|
|||||||
27
go.sum
@@ -20,7 +20,6 @@ github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
|||||||
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@@ -30,8 +29,6 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
|
|||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
|
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
|
||||||
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||||
github.com/docker/docker v26.1.3+incompatible h1:lLCzRbrVZrljpVNobJu1J2FHk8V0s4BawoZippkc+xo=
|
|
||||||
github.com/docker/docker v26.1.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
|
||||||
github.com/docker/docker v26.1.4+incompatible h1:vuTpXDuoga+Z38m1OZHzl7NKisKWaWlhjQk7IDPSLsU=
|
github.com/docker/docker v26.1.4+incompatible h1:vuTpXDuoga+Z38m1OZHzl7NKisKWaWlhjQk7IDPSLsU=
|
||||||
github.com/docker/docker v26.1.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
github.com/docker/docker v26.1.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||||
@@ -83,7 +80,6 @@ github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
|||||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||||
@@ -123,8 +119,7 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm
|
|||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||||
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
|
github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
|
||||||
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
|
||||||
github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
||||||
@@ -203,14 +198,10 @@ github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
|||||||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||||
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
|
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
|
||||||
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||||
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
|
|
||||||
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
|
|
||||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
|
|
||||||
github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
|
|
||||||
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
|
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
|
||||||
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
|
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
@@ -258,8 +249,6 @@ github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZ
|
|||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.48.0 h1:doUP+ExOpH3spVTLS0FcWGLnQrPct/hD/bCPbDRUEAU=
|
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.48.0/go.mod h1:rdENBZMT2OE6Ne/KLwpiXudnAsbdrdBaqBvTN8M8BgA=
|
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
|
||||||
go.opentelemetry.io/otel v1.27.0 h1:9BZoF3yMK/O1AafMiQTVu0YDj5Ea4hPhxCs7sGva+cg=
|
go.opentelemetry.io/otel v1.27.0 h1:9BZoF3yMK/O1AafMiQTVu0YDj5Ea4hPhxCs7sGva+cg=
|
||||||
@@ -299,7 +288,6 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91
|
|||||||
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
|
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
|
||||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
@@ -309,8 +297,6 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su
|
|||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ=
|
|
||||||
golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM=
|
|
||||||
golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
|
golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
|
||||||
golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
|
golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -340,7 +326,6 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX
|
|||||||
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
|
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
|
||||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
@@ -361,11 +346,9 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
|||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
|
||||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
|
||||||
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
||||||
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
||||||
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ=
|
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5 h1:P8OJ/WCl/Xo4E4zoe4/bifHpSmmKwARqyqE4nW6J2GQ=
|
google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5 h1:P8OJ/WCl/Xo4E4zoe4/bifHpSmmKwARqyqE4nW6J2GQ=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5/go.mod h1:RGnPtTG7r4i8sPlNyDeikXF99hMM+hN6QMm4ooG9g2g=
|
google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5/go.mod h1:RGnPtTG7r4i8sPlNyDeikXF99hMM+hN6QMm4ooG9g2g=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291 h1:AgADTJarZTBqgjiUzRgfaBchgYB3/WFTC80GPwsMcRI=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291 h1:AgADTJarZTBqgjiUzRgfaBchgYB3/WFTC80GPwsMcRI=
|
||||||
@@ -396,16 +379,10 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
|||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
|
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
|
||||||
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
|
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
|
||||||
k8s.io/api v0.30.1 h1:kCm/6mADMdbAxmIh0LBjS54nQBE+U4KmbCfIkF5CpJY=
|
|
||||||
k8s.io/api v0.30.1/go.mod h1:ddbN2C0+0DIiPntan/bye3SW3PdwLa11/0yqwvuRrJM=
|
|
||||||
k8s.io/api v0.30.2 h1:+ZhRj+28QT4UOH+BKznu4CBgPWgkXO7XAvMcMl0qKvI=
|
k8s.io/api v0.30.2 h1:+ZhRj+28QT4UOH+BKznu4CBgPWgkXO7XAvMcMl0qKvI=
|
||||||
k8s.io/api v0.30.2/go.mod h1:ULg5g9JvOev2dG0u2hig4Z7tQ2hHIuS+m8MNZ+X6EmI=
|
k8s.io/api v0.30.2/go.mod h1:ULg5g9JvOev2dG0u2hig4Z7tQ2hHIuS+m8MNZ+X6EmI=
|
||||||
k8s.io/apimachinery v0.30.1 h1:ZQStsEfo4n65yAdlGTfP/uSHMQSoYzU/oeEbkmF7P2U=
|
|
||||||
k8s.io/apimachinery v0.30.1/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
|
|
||||||
k8s.io/apimachinery v0.30.2 h1:fEMcnBj6qkzzPGSVsAZtQThU62SmQ4ZymlXRC5yFSCg=
|
k8s.io/apimachinery v0.30.2 h1:fEMcnBj6qkzzPGSVsAZtQThU62SmQ4ZymlXRC5yFSCg=
|
||||||
k8s.io/apimachinery v0.30.2/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
|
k8s.io/apimachinery v0.30.2/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
|
||||||
k8s.io/client-go v0.30.1 h1:uC/Ir6A3R46wdkgCV3vbLyNOYyCJ8oZnjtJGKfytl/Q=
|
|
||||||
k8s.io/client-go v0.30.1/go.mod h1:wrAqLNs2trwiCH/wxxmT/x3hKVH9PuV0GGW0oDoHVqc=
|
|
||||||
k8s.io/client-go v0.30.2 h1:sBIVJdojUNPDU/jObC+18tXWcTJVcwyqS9diGdWHk50=
|
k8s.io/client-go v0.30.2 h1:sBIVJdojUNPDU/jObC+18tXWcTJVcwyqS9diGdWHk50=
|
||||||
k8s.io/client-go v0.30.2/go.mod h1:JglKSWULm9xlJLx4KCkfLLQ7XwtlbflV6uFFSHTMgVs=
|
k8s.io/client-go v0.30.2/go.mod h1:JglKSWULm9xlJLx4KCkfLLQ7XwtlbflV6uFFSHTMgVs=
|
||||||
k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
|
k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
|
||||||
|
|||||||
1
go.work
@@ -6,4 +6,5 @@ use (
|
|||||||
.
|
.
|
||||||
./plugins/caddy
|
./plugins/caddy
|
||||||
./plugins/traefik
|
./plugins/traefik
|
||||||
|
./plugins/proxywasm
|
||||||
)
|
)
|
||||||
|
|||||||
2866
go.work.sum
44
plugins/proxywasm/BlockingConfiguration_json.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import jsoniter "github.com/json-iterator/tinygo"
|
||||||
|
|
||||||
|
type BlockingConfiguration_json struct {
|
||||||
|
}
|
||||||
|
func (json BlockingConfiguration_json) Type() interface{} {
|
||||||
|
var val BlockingConfiguration
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
func (json BlockingConfiguration_json) Unmarshal(iter *jsoniter.Iterator, out interface{}) {
|
||||||
|
BlockingConfiguration_json_unmarshal(iter, out.(*BlockingConfiguration))
|
||||||
|
}
|
||||||
|
func (json BlockingConfiguration_json) Marshal(stream *jsoniter.Stream, val interface{}) {
|
||||||
|
BlockingConfiguration_json_marshal(stream, val.(BlockingConfiguration))
|
||||||
|
}
|
||||||
|
func BlockingConfiguration_json_unmarshal(iter *jsoniter.Iterator, out *BlockingConfiguration) {
|
||||||
|
more := iter.ReadObjectHead()
|
||||||
|
for more {
|
||||||
|
field := iter.ReadObjectField()
|
||||||
|
if !BlockingConfiguration_json_unmarshal_field(iter, field, out) {
|
||||||
|
iter.Skip()
|
||||||
|
}
|
||||||
|
more = iter.ReadObjectMore()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func BlockingConfiguration_json_unmarshal_field(iter *jsoniter.Iterator, field string, out *BlockingConfiguration) bool {
|
||||||
|
switch {
|
||||||
|
case field == `timeout`:
|
||||||
|
iter.ReadString(&(*out).Timeout)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
func BlockingConfiguration_json_marshal(stream *jsoniter.Stream, val BlockingConfiguration) {
|
||||||
|
stream.WriteObjectHead()
|
||||||
|
BlockingConfiguration_json_marshal_field(stream, val)
|
||||||
|
stream.WriteObjectTail()
|
||||||
|
}
|
||||||
|
func BlockingConfiguration_json_marshal_field(stream *jsoniter.Stream, val BlockingConfiguration) {
|
||||||
|
stream.WriteObjectField(`timeout`)
|
||||||
|
stream.WriteString(val.Timeout)
|
||||||
|
stream.WriteMore()
|
||||||
|
}
|
||||||
132
plugins/proxywasm/Config_json.go
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import jsoniter "github.com/json-iterator/tinygo"
|
||||||
|
|
||||||
|
type Config_json struct {
|
||||||
|
}
|
||||||
|
func (json Config_json) Type() interface{} {
|
||||||
|
var val Config
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
func (json Config_json) Unmarshal(iter *jsoniter.Iterator, out interface{}) {
|
||||||
|
Config_json_unmarshal(iter, out.(*Config))
|
||||||
|
}
|
||||||
|
func (json Config_json) Marshal(stream *jsoniter.Stream, val interface{}) {
|
||||||
|
Config_json_marshal(stream, val.(Config))
|
||||||
|
}
|
||||||
|
func Config_json_unmarshal(iter *jsoniter.Iterator, out *Config) {
|
||||||
|
more := iter.ReadObjectHead()
|
||||||
|
for more {
|
||||||
|
field := iter.ReadObjectField()
|
||||||
|
if !Config_json_unmarshal_field(iter, field, out) {
|
||||||
|
iter.Skip()
|
||||||
|
}
|
||||||
|
more = iter.ReadObjectMore()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func Config_json_unmarshal_field(iter *jsoniter.Iterator, field string, out *Config) bool {
|
||||||
|
switch {
|
||||||
|
case field == `sablier_url`:
|
||||||
|
iter.ReadString(&(*out).SablierURL)
|
||||||
|
return true
|
||||||
|
case field == `cluster`:
|
||||||
|
iter.ReadString(&(*out).Cluster)
|
||||||
|
return true
|
||||||
|
case field == `names`:
|
||||||
|
Config_array1_json_unmarshal(iter, &(*out).Names)
|
||||||
|
return true
|
||||||
|
case field == `group`:
|
||||||
|
iter.ReadString(&(*out).Group)
|
||||||
|
return true
|
||||||
|
case field == `session_duration`:
|
||||||
|
iter.ReadString(&(*out).SessionDuration)
|
||||||
|
return true
|
||||||
|
case field == `dynamic`:
|
||||||
|
Config_ptr2_json_unmarshal(iter, &(*out).Dynamic)
|
||||||
|
return true
|
||||||
|
case field == `blocking`:
|
||||||
|
Config_ptr3_json_unmarshal(iter, &(*out).Blocking)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
func Config_array1_json_unmarshal (iter *jsoniter.Iterator, out *[]string) {
|
||||||
|
i := 0
|
||||||
|
val := *out
|
||||||
|
more := iter.ReadArrayHead()
|
||||||
|
for more {
|
||||||
|
if i == len(val) {
|
||||||
|
val = append(val, make([]string, 4)...)
|
||||||
|
}
|
||||||
|
iter.ReadString(&val[i])
|
||||||
|
i++
|
||||||
|
more = iter.ReadArrayMore()
|
||||||
|
}
|
||||||
|
if i == 0 {
|
||||||
|
*out = []string{}
|
||||||
|
} else {
|
||||||
|
*out = val[:i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func Config_ptr2_json_unmarshal (iter *jsoniter.Iterator, out **DynamicConfiguration) {
|
||||||
|
var val DynamicConfiguration
|
||||||
|
DynamicConfiguration_json_unmarshal(iter, &val)
|
||||||
|
if iter.Error == nil {
|
||||||
|
*out = &val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func Config_ptr3_json_unmarshal (iter *jsoniter.Iterator, out **BlockingConfiguration) {
|
||||||
|
var val BlockingConfiguration
|
||||||
|
BlockingConfiguration_json_unmarshal(iter, &val)
|
||||||
|
if iter.Error == nil {
|
||||||
|
*out = &val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func Config_json_marshal(stream *jsoniter.Stream, val Config) {
|
||||||
|
stream.WriteObjectHead()
|
||||||
|
Config_json_marshal_field(stream, val)
|
||||||
|
stream.WriteObjectTail()
|
||||||
|
}
|
||||||
|
func Config_json_marshal_field(stream *jsoniter.Stream, val Config) {
|
||||||
|
stream.WriteObjectField(`sablier_url`)
|
||||||
|
stream.WriteString(val.SablierURL)
|
||||||
|
stream.WriteMore()
|
||||||
|
stream.WriteObjectField(`cluster`)
|
||||||
|
stream.WriteString(val.Cluster)
|
||||||
|
stream.WriteMore()
|
||||||
|
stream.WriteObjectField(`names`)
|
||||||
|
Config_array4_json_marshal(stream, val.Names)
|
||||||
|
stream.WriteMore()
|
||||||
|
stream.WriteObjectField(`group`)
|
||||||
|
stream.WriteString(val.Group)
|
||||||
|
stream.WriteMore()
|
||||||
|
stream.WriteObjectField(`session_duration`)
|
||||||
|
stream.WriteString(val.SessionDuration)
|
||||||
|
stream.WriteMore()
|
||||||
|
stream.WriteObjectField(`dynamic`)
|
||||||
|
if val.Dynamic == nil {
|
||||||
|
stream.WriteNull()
|
||||||
|
} else {
|
||||||
|
DynamicConfiguration_json_marshal(stream, *val.Dynamic)
|
||||||
|
}
|
||||||
|
stream.WriteMore()
|
||||||
|
stream.WriteObjectField(`blocking`)
|
||||||
|
if val.Blocking == nil {
|
||||||
|
stream.WriteNull()
|
||||||
|
} else {
|
||||||
|
BlockingConfiguration_json_marshal(stream, *val.Blocking)
|
||||||
|
}
|
||||||
|
stream.WriteMore()
|
||||||
|
}
|
||||||
|
func Config_array4_json_marshal (stream *jsoniter.Stream, val []string) {
|
||||||
|
if len(val) == 0 {
|
||||||
|
stream.WriteEmptyArray()
|
||||||
|
} else {
|
||||||
|
stream.WriteArrayHead()
|
||||||
|
for i, elem := range val {
|
||||||
|
if i != 0 { stream.WriteMore() }
|
||||||
|
stream.WriteString(elem)
|
||||||
|
}
|
||||||
|
stream.WriteArrayTail()
|
||||||
|
}
|
||||||
|
}
|
||||||
18
plugins/proxywasm/Dockerfile
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
FROM golang:1.22 AS build
|
||||||
|
|
||||||
|
ADD https://github.com/tinygo-org/tinygo/releases/download/v0.31.2/tinygo_0.31.2_amd64.deb tinygo_amd64.deb
|
||||||
|
RUN dpkg -i tinygo_amd64.deb
|
||||||
|
|
||||||
|
WORKDIR /go/src/sablier/plugins/proxywasm
|
||||||
|
|
||||||
|
COPY go.mod ./
|
||||||
|
COPY go.sum ./
|
||||||
|
RUN go mod download
|
||||||
|
|
||||||
|
COPY . /go/src/sablier/plugins/proxywasm
|
||||||
|
|
||||||
|
RUN make
|
||||||
|
|
||||||
|
FROM scratch
|
||||||
|
|
||||||
|
COPY --from=build /go/src/sablier/plugins/proxywasm/sablierproxywasm.wasm ./plugin.wasm
|
||||||
73
plugins/proxywasm/DynamicConfiguration_json.go
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import jsoniter "github.com/json-iterator/tinygo"
|
||||||
|
|
||||||
|
type DynamicConfiguration_json struct {
|
||||||
|
}
|
||||||
|
func (json DynamicConfiguration_json) Type() interface{} {
|
||||||
|
var val DynamicConfiguration
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
func (json DynamicConfiguration_json) Unmarshal(iter *jsoniter.Iterator, out interface{}) {
|
||||||
|
DynamicConfiguration_json_unmarshal(iter, out.(*DynamicConfiguration))
|
||||||
|
}
|
||||||
|
func (json DynamicConfiguration_json) Marshal(stream *jsoniter.Stream, val interface{}) {
|
||||||
|
DynamicConfiguration_json_marshal(stream, val.(DynamicConfiguration))
|
||||||
|
}
|
||||||
|
func DynamicConfiguration_json_unmarshal(iter *jsoniter.Iterator, out *DynamicConfiguration) {
|
||||||
|
more := iter.ReadObjectHead()
|
||||||
|
for more {
|
||||||
|
field := iter.ReadObjectField()
|
||||||
|
if !DynamicConfiguration_json_unmarshal_field(iter, field, out) {
|
||||||
|
iter.Skip()
|
||||||
|
}
|
||||||
|
more = iter.ReadObjectMore()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func DynamicConfiguration_json_unmarshal_field(iter *jsoniter.Iterator, field string, out *DynamicConfiguration) bool {
|
||||||
|
switch {
|
||||||
|
case field == `display_name`:
|
||||||
|
iter.ReadString(&(*out).DisplayName)
|
||||||
|
return true
|
||||||
|
case field == `show_details`:
|
||||||
|
DynamicConfiguration_ptr1_json_unmarshal(iter, &(*out).ShowDetails)
|
||||||
|
return true
|
||||||
|
case field == `theme`:
|
||||||
|
iter.ReadString(&(*out).Theme)
|
||||||
|
return true
|
||||||
|
case field == `refresh_frequency`:
|
||||||
|
iter.ReadString(&(*out).RefreshFrequency)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
func DynamicConfiguration_ptr1_json_unmarshal (iter *jsoniter.Iterator, out **bool) {
|
||||||
|
var val bool
|
||||||
|
iter.ReadBool(&val)
|
||||||
|
if iter.Error == nil {
|
||||||
|
*out = &val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func DynamicConfiguration_json_marshal(stream *jsoniter.Stream, val DynamicConfiguration) {
|
||||||
|
stream.WriteObjectHead()
|
||||||
|
DynamicConfiguration_json_marshal_field(stream, val)
|
||||||
|
stream.WriteObjectTail()
|
||||||
|
}
|
||||||
|
func DynamicConfiguration_json_marshal_field(stream *jsoniter.Stream, val DynamicConfiguration) {
|
||||||
|
stream.WriteObjectField(`display_name`)
|
||||||
|
stream.WriteString(val.DisplayName)
|
||||||
|
stream.WriteMore()
|
||||||
|
stream.WriteObjectField(`show_details`)
|
||||||
|
if val.ShowDetails == nil {
|
||||||
|
stream.WriteNull()
|
||||||
|
} else {
|
||||||
|
stream.WriteBool(*val.ShowDetails)
|
||||||
|
}
|
||||||
|
stream.WriteMore()
|
||||||
|
stream.WriteObjectField(`theme`)
|
||||||
|
stream.WriteString(val.Theme)
|
||||||
|
stream.WriteMore()
|
||||||
|
stream.WriteObjectField(`refresh_frequency`)
|
||||||
|
stream.WriteString(val.RefreshFrequency)
|
||||||
|
stream.WriteMore()
|
||||||
|
}
|
||||||
6
plugins/proxywasm/Makefile
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
build:
|
||||||
|
go generate
|
||||||
|
tinygo build -o sablierproxywasm.wasm -scheduler=none -target=wasi ./
|
||||||
|
|
||||||
|
docker:
|
||||||
|
docker build -t acouvreur/sablier-proxy-wasm:latest .
|
||||||
9
plugins/proxywasm/README.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# Proxy Wasm Sablier Plugin
|
||||||
|
|
||||||
|
See more at
|
||||||
|
- https://github.com/proxy-wasm/spec
|
||||||
|
- https://github.com/tetratelabs/proxy-wasm-go-sdk
|
||||||
|
|
||||||
|
## Prerequisite
|
||||||
|
|
||||||
|
- Install TinyGo: https://tinygo.org/getting-started/install/
|
||||||
2
plugins/proxywasm/e2e/apacheapisix/README.md
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Sablier ProxyWasm Plugin integration with Apache APISIX
|
||||||
|
|
||||||
46
plugins/proxywasm/e2e/apacheapisix/docker/apisix.yaml
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
routes:
|
||||||
|
- uri: "/dynamic/whoami"
|
||||||
|
plugins:
|
||||||
|
proxywasm_sablier_plugin:
|
||||||
|
conf: '{ "sablier_url": "sablier:10000", "names": ["docker_classic_e2e-whoami-1"], "session_duration": "1m", "dynamic": { "display_name": "Dynamic Whoami", "theme": "hacker-terminal" } }'
|
||||||
|
upstream:
|
||||||
|
type: roundrobin
|
||||||
|
nodes:
|
||||||
|
"whoami:80": 1
|
||||||
|
|
||||||
|
- uri: "/blocking/whoami"
|
||||||
|
plugins:
|
||||||
|
proxywasm_sablier_plugin:
|
||||||
|
conf: '{ "sablier_url": "sablier:10000", "names": ["docker_classic_e2e-whoami-1"], "session_duration": "1m", "blocking": { "timeout": "30s" } }'
|
||||||
|
upstream:
|
||||||
|
type: roundrobin
|
||||||
|
nodes:
|
||||||
|
"whoami:80": 1
|
||||||
|
|
||||||
|
- uri: "/multiple/whoami"
|
||||||
|
plugins:
|
||||||
|
proxywasm_sablier_plugin:
|
||||||
|
conf: '{ "sablier_url": "sablier:10000", "names": ["docker_classic_e2e-whoami-1", "docker_classic_e2e-nginx-1"], "session_duration": "1m", "dynamic": { "display_name": "Multiple Whoami" } }'
|
||||||
|
upstream:
|
||||||
|
type: roundrobin
|
||||||
|
nodes:
|
||||||
|
"whoami:80": 1
|
||||||
|
|
||||||
|
- uri: "/multiple/nginx"
|
||||||
|
plugins:
|
||||||
|
proxywasm_sablier_plugin:
|
||||||
|
conf: '{ "sablier_url": "sablier:10000", "names": ["docker_classic_e2e-whoami-1", "docker_classic_e2e-nginx-1"], "session_duration": "1m", "dynamic": { "display_name": "Multiple Whoami" } }'
|
||||||
|
upstream:
|
||||||
|
type: roundrobin
|
||||||
|
nodes:
|
||||||
|
"nginx:80": 1
|
||||||
|
|
||||||
|
- uri: "/healthy/nginx"
|
||||||
|
plugins:
|
||||||
|
proxywasm_sablier_plugin:
|
||||||
|
conf: '{ "sablier_url": "sablier:10000", "names": ["docker_classic_e2e-nginx-1"], "session_duration": "1m", "dynamic": { "display_name": "Healthy Nginx" } }'
|
||||||
|
upstream:
|
||||||
|
type: roundrobin
|
||||||
|
nodes:
|
||||||
|
"nginx:80": 1
|
||||||
|
#END
|
||||||
28
plugins/proxywasm/e2e/apacheapisix/docker/compose.yaml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
services:
|
||||||
|
apisix:
|
||||||
|
image: apache/apisix:3.9.0-debian
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- ./config.yaml:/usr/local/apisix/conf/config.yaml:ro
|
||||||
|
- ./apisix.yaml:/usr/local/apisix/conf/apisix.yaml:ro
|
||||||
|
- ../../../sablierproxywasm.wasm:/wasm/sablierproxywasm.wasm
|
||||||
|
ports:
|
||||||
|
- "8080:9080/tcp"
|
||||||
|
|
||||||
|
sablier:
|
||||||
|
image: acouvreur/sablier:local
|
||||||
|
command:
|
||||||
|
- start
|
||||||
|
- --provider.name=docker
|
||||||
|
- --logging.level=trace
|
||||||
|
volumes:
|
||||||
|
- '/var/run/docker.sock:/var/run/docker.sock'
|
||||||
|
|
||||||
|
whoami:
|
||||||
|
image: containous/whoami:v1.5.0
|
||||||
|
|
||||||
|
nginx:
|
||||||
|
image: nginx:1.26.0
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost"]
|
||||||
|
interval: 5s
|
||||||
11
plugins/proxywasm/e2e/apacheapisix/docker/config.yaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
deployment:
|
||||||
|
role: data_plane
|
||||||
|
role_data_plane:
|
||||||
|
config_provider: yaml
|
||||||
|
|
||||||
|
wasm:
|
||||||
|
plugins:
|
||||||
|
- name: proxywasm_sablier_plugin
|
||||||
|
priority: 7997
|
||||||
|
file: /wasm/sablierproxywasm.wasm
|
||||||
|
|
||||||
39
plugins/proxywasm/e2e/apacheapisix/docker/run.sh
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
DOCKER_COMPOSE_FILE=compose.yaml
|
||||||
|
DOCKER_COMPOSE_PROJECT_NAME=docker_classic_e2e
|
||||||
|
|
||||||
|
errors=0
|
||||||
|
|
||||||
|
echo "Using Docker version:"
|
||||||
|
docker version
|
||||||
|
|
||||||
|
prepare_docker_classic() {
|
||||||
|
docker compose -f $DOCKER_COMPOSE_FILE -p $DOCKER_COMPOSE_PROJECT_NAME up -d
|
||||||
|
docker compose -f $DOCKER_COMPOSE_FILE -p $DOCKER_COMPOSE_PROJECT_NAME stop whoami nginx
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy_docker_classic() {
|
||||||
|
docker compose -f $DOCKER_COMPOSE_FILE -p $DOCKER_COMPOSE_PROJECT_NAME down --remove-orphans || true
|
||||||
|
}
|
||||||
|
|
||||||
|
run_docker_classic_test() {
|
||||||
|
echo "Running Docker Classic Test: $1"
|
||||||
|
prepare_docker_classic
|
||||||
|
sleep 2
|
||||||
|
go clean -testcache
|
||||||
|
if ! go test -count=1 -tags e2e -timeout 30s -run ^${1}$ github.com/acouvreur/sablier/e2e; then
|
||||||
|
errors=1
|
||||||
|
docker compose -f ${DOCKER_COMPOSE_FILE} -p ${DOCKER_COMPOSE_PROJECT_NAME} logs sablier apisix
|
||||||
|
fi
|
||||||
|
destroy_docker_classic
|
||||||
|
}
|
||||||
|
|
||||||
|
trap destroy_docker_classic EXIT
|
||||||
|
|
||||||
|
run_docker_classic_test Test_Dynamic
|
||||||
|
run_docker_classic_test Test_Blocking
|
||||||
|
run_docker_classic_test Test_Multiple
|
||||||
|
run_docker_classic_test Test_Healthy
|
||||||
|
|
||||||
|
exit $errors
|
||||||
27
plugins/proxywasm/e2e/envoy/docker/compose.yaml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
services:
|
||||||
|
envoy:
|
||||||
|
image: envoyproxy/envoy:v1.30-latest
|
||||||
|
command: /usr/local/bin/envoy -c /etc/envoy.yaml
|
||||||
|
volumes:
|
||||||
|
- ./envoy.yaml:/etc/envoy.yaml
|
||||||
|
- ../../../sablierproxywasm.wasm:/etc/sablierproxywasm.wasm
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
|
||||||
|
sablier:
|
||||||
|
image: acouvreur/sablier:local
|
||||||
|
command:
|
||||||
|
- start
|
||||||
|
- --provider.name=docker
|
||||||
|
- --logging.level=trace
|
||||||
|
volumes:
|
||||||
|
- '/var/run/docker.sock:/var/run/docker.sock'
|
||||||
|
|
||||||
|
whoami:
|
||||||
|
image: containous/whoami:v1.5.0
|
||||||
|
|
||||||
|
nginx:
|
||||||
|
image: nginx:1.26.0
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost"]
|
||||||
|
interval: 5s
|
||||||
230
plugins/proxywasm/e2e/envoy/docker/envoy.yaml
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
static_resources:
|
||||||
|
listeners:
|
||||||
|
- name: main
|
||||||
|
address:
|
||||||
|
socket_address:
|
||||||
|
address: 0.0.0.0
|
||||||
|
port_value: 8080
|
||||||
|
filter_chains:
|
||||||
|
- filters:
|
||||||
|
# Dynamic Whoami
|
||||||
|
- 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: "/dynamic/whoami"
|
||||||
|
route:
|
||||||
|
cluster: whoami
|
||||||
|
typed_per_filter_config:
|
||||||
|
sablier-wasm-whoami-dynamic:
|
||||||
|
"@type": type.googleapis.com/envoy.config.route.v3.FilterConfig
|
||||||
|
config: # Note this config field could not be empty because the xDS API requirement.
|
||||||
|
"@type": type.googleapis.com/google.protobuf.Empty # Empty as a placeholder.
|
||||||
|
is_optional: true
|
||||||
|
- match:
|
||||||
|
path: "/blocking/whoami"
|
||||||
|
route:
|
||||||
|
cluster: whoami
|
||||||
|
typed_per_filter_config:
|
||||||
|
sablier-wasm-whoami-blocking:
|
||||||
|
"@type": type.googleapis.com/envoy.config.route.v3.FilterConfig
|
||||||
|
config: # Note this config field could not be empty because the xDS API requirement.
|
||||||
|
"@type": type.googleapis.com/google.protobuf.Empty # Empty as a placeholder.
|
||||||
|
is_optional: true
|
||||||
|
- match:
|
||||||
|
prefix: "/multiple/whoami"
|
||||||
|
route:
|
||||||
|
cluster: whoami
|
||||||
|
typed_per_filter_config:
|
||||||
|
sablier-wasm-multiple:
|
||||||
|
"@type": type.googleapis.com/envoy.config.route.v3.FilterConfig
|
||||||
|
config: # Note this config field could not be empty because the xDS API requirement.
|
||||||
|
"@type": type.googleapis.com/google.protobuf.Empty # Empty as a placeholder.
|
||||||
|
is_optional: true
|
||||||
|
- match:
|
||||||
|
path: "/multiple/nginx"
|
||||||
|
route:
|
||||||
|
cluster: nginx
|
||||||
|
typed_per_filter_config:
|
||||||
|
sablier-wasm-multiple:
|
||||||
|
"@type": type.googleapis.com/envoy.config.route.v3.FilterConfig
|
||||||
|
config: # Note this config field could not be empty because the xDS API requirement.
|
||||||
|
"@type": type.googleapis.com/google.protobuf.Empty # Empty as a placeholder.
|
||||||
|
is_optional: true
|
||||||
|
- match:
|
||||||
|
path: "/healthy/nginx"
|
||||||
|
route:
|
||||||
|
cluster: nginx
|
||||||
|
typed_per_filter_config:
|
||||||
|
sablier-wasm-healthy:
|
||||||
|
"@type": type.googleapis.com/envoy.config.route.v3.FilterConfig
|
||||||
|
config: # Note this config field could not be empty because the xDS API requirement.
|
||||||
|
"@type": type.googleapis.com/google.protobuf.Empty # Empty as a placeholder.
|
||||||
|
is_optional: true
|
||||||
|
|
||||||
|
http_filters:
|
||||||
|
- name: sablier-wasm-whoami-dynamic
|
||||||
|
disabled: true
|
||||||
|
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: "sablier-wasm-whoami-dynamic"
|
||||||
|
root_id: "sablier-wasm-whoami-dynamic"
|
||||||
|
configuration:
|
||||||
|
"@type": "type.googleapis.com/google.protobuf.StringValue"
|
||||||
|
value: |
|
||||||
|
{
|
||||||
|
"sablier_url": "sablier:10000",
|
||||||
|
"cluster": "sablier",
|
||||||
|
"names": ["docker_classic_e2e-whoami-1"],
|
||||||
|
"session_duration": "1m",
|
||||||
|
"dynamic": {
|
||||||
|
"display_name": "Dynamic Whoami",
|
||||||
|
"theme": "hacker-terminal"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vm_config:
|
||||||
|
runtime: "envoy.wasm.runtime.v8"
|
||||||
|
vm_id: "vm.sablier.sablier-wasm-whoami-dynamic"
|
||||||
|
code:
|
||||||
|
local:
|
||||||
|
filename: "/etc/sablierproxywasm.wasm"
|
||||||
|
configuration: { }
|
||||||
|
- name: sablier-wasm-whoami-blocking
|
||||||
|
disabled: true
|
||||||
|
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: "sablier-wasm-whoami-blocking"
|
||||||
|
root_id: "sablier-wasm-whoami-blocking"
|
||||||
|
configuration:
|
||||||
|
"@type": "type.googleapis.com/google.protobuf.StringValue"
|
||||||
|
value: |
|
||||||
|
{
|
||||||
|
"sablier_url": "sablier:10000",
|
||||||
|
"cluster": "sablier",
|
||||||
|
"names": ["docker_classic_e2e-whoami-1"],
|
||||||
|
"session_duration": "1m",
|
||||||
|
"blocking": {
|
||||||
|
"timeout": "30s"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vm_config:
|
||||||
|
runtime: "envoy.wasm.runtime.v8"
|
||||||
|
vm_id: "vm.sablier.sablier-wasm-whoami-blocking"
|
||||||
|
code:
|
||||||
|
local:
|
||||||
|
filename: "/etc/sablierproxywasm.wasm"
|
||||||
|
configuration: { }
|
||||||
|
- name: sablier-wasm-multiple
|
||||||
|
disabled: true
|
||||||
|
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: "sablier-wasm-multiple"
|
||||||
|
root_id: "sablier-wasm-multiple"
|
||||||
|
configuration:
|
||||||
|
"@type": "type.googleapis.com/google.protobuf.StringValue"
|
||||||
|
value: |
|
||||||
|
{
|
||||||
|
"sablier_url": "sablier:10000",
|
||||||
|
"cluster": "sablier",
|
||||||
|
"names": ["docker_classic_e2e-whoami-1", "docker_classic_e2e-nginx-1"],
|
||||||
|
"session_duration": "1m",
|
||||||
|
"dynamic": {
|
||||||
|
"display_name": "Multiple Whoami"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vm_config:
|
||||||
|
runtime: "envoy.wasm.runtime.v8"
|
||||||
|
vm_id: "vm.sablier.sablier-wasm-multiple"
|
||||||
|
code:
|
||||||
|
local:
|
||||||
|
filename: "/etc/sablierproxywasm.wasm"
|
||||||
|
configuration: { }
|
||||||
|
- name: sablier-wasm-healthy
|
||||||
|
disabled: true
|
||||||
|
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: "sablier-wasm-healthy"
|
||||||
|
root_id: "sablier-wasm-healthy"
|
||||||
|
configuration:
|
||||||
|
"@type": "type.googleapis.com/google.protobuf.StringValue"
|
||||||
|
value: |
|
||||||
|
{
|
||||||
|
"sablier_url": "sablier:10000",
|
||||||
|
"cluster": "sablier",
|
||||||
|
"names": ["docker_classic_e2e-nginx-1"],
|
||||||
|
"session_duration": "1m",
|
||||||
|
"dynamic": {
|
||||||
|
"display_name": "Healthy Nginx"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vm_config:
|
||||||
|
runtime: "envoy.wasm.runtime.v8"
|
||||||
|
vm_id: "vm.sablier.sablier-wasm-healthy"
|
||||||
|
code:
|
||||||
|
local:
|
||||||
|
filename: "/etc/sablierproxywasm.wasm"
|
||||||
|
configuration: { }
|
||||||
|
- name: envoy.filters.http.router
|
||||||
|
typed_config:
|
||||||
|
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
|
||||||
|
|
||||||
|
clusters:
|
||||||
|
- name: sablier
|
||||||
|
connect_timeout: 0.25s
|
||||||
|
type: STRICT_DNS
|
||||||
|
lb_policy: round_robin
|
||||||
|
load_assignment:
|
||||||
|
cluster_name: sablier
|
||||||
|
endpoints:
|
||||||
|
- lb_endpoints:
|
||||||
|
- endpoint:
|
||||||
|
address:
|
||||||
|
socket_address:
|
||||||
|
address: sablier
|
||||||
|
port_value: 10000
|
||||||
|
- name: whoami
|
||||||
|
connect_timeout: 0.25s
|
||||||
|
type: STRICT_DNS
|
||||||
|
lb_policy: round_robin
|
||||||
|
load_assignment:
|
||||||
|
cluster_name: whoami
|
||||||
|
endpoints:
|
||||||
|
- lb_endpoints:
|
||||||
|
- endpoint:
|
||||||
|
address:
|
||||||
|
socket_address:
|
||||||
|
address: whoami
|
||||||
|
port_value: 80
|
||||||
|
- name: nginx
|
||||||
|
connect_timeout: 0.25s
|
||||||
|
type: STRICT_DNS
|
||||||
|
lb_policy: round_robin
|
||||||
|
load_assignment:
|
||||||
|
cluster_name: nginx
|
||||||
|
endpoints:
|
||||||
|
- lb_endpoints:
|
||||||
|
- endpoint:
|
||||||
|
address:
|
||||||
|
socket_address:
|
||||||
|
address: nginx
|
||||||
|
port_value: 80
|
||||||
39
plugins/proxywasm/e2e/envoy/docker/run.sh
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
DOCKER_COMPOSE_FILE=compose.yaml
|
||||||
|
DOCKER_COMPOSE_PROJECT_NAME=docker_classic_e2e
|
||||||
|
|
||||||
|
errors=0
|
||||||
|
|
||||||
|
echo "Using Docker version:"
|
||||||
|
docker version
|
||||||
|
|
||||||
|
prepare_docker_classic() {
|
||||||
|
docker compose -f $DOCKER_COMPOSE_FILE -p $DOCKER_COMPOSE_PROJECT_NAME up -d
|
||||||
|
docker compose -f $DOCKER_COMPOSE_FILE -p $DOCKER_COMPOSE_PROJECT_NAME stop whoami nginx
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy_docker_classic() {
|
||||||
|
docker compose -f $DOCKER_COMPOSE_FILE -p $DOCKER_COMPOSE_PROJECT_NAME down --remove-orphans || true
|
||||||
|
}
|
||||||
|
|
||||||
|
run_docker_classic_test() {
|
||||||
|
echo "Running Docker Classic Test: $1"
|
||||||
|
prepare_docker_classic
|
||||||
|
sleep 2
|
||||||
|
go clean -testcache
|
||||||
|
if ! go test -count=1 -tags e2e -timeout 30s -run ^${1}$ github.com/acouvreur/sablier/e2e; then
|
||||||
|
errors=1
|
||||||
|
docker compose -f ${DOCKER_COMPOSE_FILE} -p ${DOCKER_COMPOSE_PROJECT_NAME} logs sablier envoy
|
||||||
|
fi
|
||||||
|
destroy_docker_classic
|
||||||
|
}
|
||||||
|
|
||||||
|
trap destroy_docker_classic EXIT
|
||||||
|
|
||||||
|
run_docker_classic_test Test_Dynamic
|
||||||
|
run_docker_classic_test Test_Blocking
|
||||||
|
run_docker_classic_test Test_Multiple
|
||||||
|
run_docker_classic_test Test_Healthy
|
||||||
|
|
||||||
|
exit $errors
|
||||||
27
plugins/proxywasm/e2e/istio/kubernetes/README.md
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# Install kubectl
|
||||||
|
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
|
||||||
|
|
||||||
|
# Install helm3
|
||||||
|
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
|
||||||
|
|
||||||
|
# Start k3s
|
||||||
|
docker compose up -d
|
||||||
|
sudo chown vscode ./kubeconfig.yaml
|
||||||
|
chmod 600 ./kubeconfig.yaml
|
||||||
|
export KUBECONFIG=./kubeconfig.yaml
|
||||||
|
|
||||||
|
kubectl create configmap -n istio-system sablier-wasm-plugin --from-file ../../sablierproxywasm.wasm
|
||||||
|
|
||||||
|
# Install Istio Helm charts
|
||||||
|
helm repo add istio https://istio-release.storage.googleapis.com/charts
|
||||||
|
helm repo update
|
||||||
|
helm install istio-base istio/base -n istio-system --wait
|
||||||
|
helm install istiod istio/istiod -n istio-system --wait
|
||||||
|
kubectl label namespace istio-system istio-injection=enabled
|
||||||
|
helm install istio-ingressgateway istio/gateway --values ./istio-gateway-values.yaml -n istio-system --wait
|
||||||
|
|
||||||
|
# Install Sablier
|
||||||
|
kubectl apply -f ./manifests/sablier.yml
|
||||||
|
|
||||||
|
# Build proxywasm
|
||||||
|
make docker
|
||||||
24
plugins/proxywasm/e2e/istio/kubernetes/compose.yaml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
version: '3'
|
||||||
|
services:
|
||||||
|
server:
|
||||||
|
image: "rancher/k3s:v1.23.12-k3s1"
|
||||||
|
command: server --no-deploy traefik
|
||||||
|
tmpfs:
|
||||||
|
- /run
|
||||||
|
- /var/run
|
||||||
|
ulimits:
|
||||||
|
nproc: 65535
|
||||||
|
nofile:
|
||||||
|
soft: 65535
|
||||||
|
hard: 65535
|
||||||
|
privileged: true
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
- K3S_KUBECONFIG_OUTPUT=/output/kubeconfig.yaml
|
||||||
|
- K3S_KUBECONFIG_MODE=666
|
||||||
|
volumes:
|
||||||
|
# This is just so that we get the kubeconfig file out
|
||||||
|
- .:/output
|
||||||
|
ports:
|
||||||
|
- 6443:6443 # Kubernetes API Server
|
||||||
|
- 8080:80 # Ingress controller port 80
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
volumes:
|
||||||
|
- name: wasmfilter
|
||||||
|
configMap:
|
||||||
|
name: sablier-wasm-plugin
|
||||||
|
|
||||||
|
volumeMounts:
|
||||||
|
- name: wasmfilter
|
||||||
|
mountPath: /opt/filters/sablierproxywasm.wasm
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
apiVersion: networking.istio.io/v1alpha3
|
||||||
|
kind: Gateway
|
||||||
|
metadata:
|
||||||
|
name: gateway
|
||||||
|
namespace: istio-system
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
istio: ingressgateway
|
||||||
|
servers:
|
||||||
|
- port:
|
||||||
|
number: 80
|
||||||
|
name: http
|
||||||
|
protocol: HTTP
|
||||||
|
hosts:
|
||||||
|
- "*"
|
||||||
55
plugins/proxywasm/e2e/istio/kubernetes/manifests/nginx.yml
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: nginx
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: nginx
|
||||||
|
version: v1
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
version: v1
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
image: nginx:1.26.0
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: nginx
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
service: nginx
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
targetPort: 80
|
||||||
|
port: 80
|
||||||
|
selector:
|
||||||
|
app: nginx
|
||||||
|
---
|
||||||
|
apiVersion: networking.istio.io/v1alpha3
|
||||||
|
kind: VirtualService
|
||||||
|
metadata:
|
||||||
|
name: nginx
|
||||||
|
spec:
|
||||||
|
hosts:
|
||||||
|
- "*"
|
||||||
|
gateways:
|
||||||
|
- gateway.istio-system.svc.cluster.local
|
||||||
|
http:
|
||||||
|
- match:
|
||||||
|
- uri:
|
||||||
|
prefix: "/multiple/nginx"
|
||||||
|
- uri:
|
||||||
|
prefix: "/healthy/nginx"
|
||||||
|
route:
|
||||||
|
- destination:
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
|
host: nginx
|
||||||
83
plugins/proxywasm/e2e/istio/kubernetes/manifests/sablier.yml
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: sablier-system
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: sablier
|
||||||
|
namespace: sablier-system
|
||||||
|
labels:
|
||||||
|
app: sablier
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: sablier
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: sablier
|
||||||
|
spec:
|
||||||
|
serviceAccountName: sablier
|
||||||
|
containers:
|
||||||
|
- name: sablier
|
||||||
|
image: acouvreur/sablier:local
|
||||||
|
args: ["start", "--provider.name=kubernetes", "--logging.level=trace"]
|
||||||
|
ports:
|
||||||
|
- containerPort: 10000
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: sablier
|
||||||
|
namespace: sablier-system
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: sablier
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 10000
|
||||||
|
targetPort: 10000
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: sablier
|
||||||
|
namespace: sablier-system
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: sablier
|
||||||
|
namespace: sablier-system
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- apps
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- deployments
|
||||||
|
- deployments/scale
|
||||||
|
- statefulsets
|
||||||
|
- statefulsets/scale
|
||||||
|
verbs:
|
||||||
|
- patch # Scale up and down
|
||||||
|
- get # Retrieve info about specific dep
|
||||||
|
- update # Scale up and down
|
||||||
|
- list # Events
|
||||||
|
- watch # Events
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: sablier
|
||||||
|
namespace: sablier-system
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: sablier
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: sablier
|
||||||
|
namespace: sablier-system
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
apiVersion: extensions.istio.io/v1alpha1
|
||||||
|
kind: WasmPlugin
|
||||||
|
metadata:
|
||||||
|
name: sablier-wasm-whoami-dynamic
|
||||||
|
namespace: istio-system
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
istio: ingressgateway
|
||||||
|
url: file:///opt/filters/sablierproxywasm.wasm/..data/sablierproxywasm.wasm
|
||||||
|
# Use https://istio.io/latest/docs/reference/config/proxy_extensions/wasm-plugin/#WasmPlugin-TrafficSelector
|
||||||
|
# To specify which service to apply this filter only
|
||||||
|
phase: UNSPECIFIED_PHASE
|
||||||
|
pluginConfig:
|
||||||
|
{
|
||||||
|
"sablier_url": "sablier.sablier-system.svc.cluster.local",
|
||||||
|
"cluster": "outbound|10000||sablier.sablier-system.svc.cluster.local",
|
||||||
|
"names": [ "deployment_default_whoami_1" ],
|
||||||
|
"session_duration": "1m",
|
||||||
|
"dynamic": {
|
||||||
|
"display_name": "Dynamic Whoami",
|
||||||
|
"theme": "hacker-terminal"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
---
|
||||||
|
apiVersion: extensions.istio.io/v1alpha1
|
||||||
|
kind: WasmPlugin
|
||||||
|
metadata:
|
||||||
|
name: sablier-wasm-whoami-blocking
|
||||||
|
namespace: istio-system
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
istio: ingressgateway
|
||||||
|
url: file:///opt/filters/sablierproxywasm.wasm/..data/sablierproxywasm.wasm
|
||||||
|
# Use https://istio.io/latest/docs/reference/config/proxy_extensions/wasm-plugin/#WasmPlugin-TrafficSelector
|
||||||
|
# To specify which service to apply this filter only
|
||||||
|
phase: UNSPECIFIED_PHASE
|
||||||
|
pluginConfig:
|
||||||
|
{
|
||||||
|
"sablier_url": "sablier.sablier-system.svc.cluster.local",
|
||||||
|
"cluster": "outbound|10000||sablier.sablier-system.svc.cluster.local",
|
||||||
|
"names": [ "deployment_default_whoami_1" ],
|
||||||
|
"session_duration": "1m",
|
||||||
|
"blocking": {
|
||||||
|
"timeout": "30s"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
---
|
||||||
|
apiVersion: extensions.istio.io/v1alpha1
|
||||||
|
kind: WasmPlugin
|
||||||
|
metadata:
|
||||||
|
name: sablier-wasm-multiple
|
||||||
|
namespace: istio-system
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
istio: ingressgateway
|
||||||
|
url: file:///opt/filters/sablierproxywasm.wasm/..data/sablierproxywasm.wasm
|
||||||
|
# Use https://istio.io/latest/docs/reference/config/proxy_extensions/wasm-plugin/#WasmPlugin-TrafficSelector
|
||||||
|
# To specify which service to apply this filter only
|
||||||
|
phase: UNSPECIFIED_PHASE
|
||||||
|
pluginConfig:
|
||||||
|
{
|
||||||
|
"sablier_url": "sablier.sablier-system.svc.cluster.local",
|
||||||
|
"cluster": "outbound|10000||sablier.sablier-system.svc.cluster.local",
|
||||||
|
"names": [ "deployment_default_whoami_1", "deployment_default_nginx_1" ],
|
||||||
|
"session_duration": "1m",
|
||||||
|
"dynamic": {
|
||||||
|
"display_name": "Multiple Whoami"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
---
|
||||||
|
apiVersion: extensions.istio.io/v1alpha1
|
||||||
|
kind: WasmPlugin
|
||||||
|
metadata:
|
||||||
|
name: sablier-wasm-healthy
|
||||||
|
namespace: istio-system
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
istio: ingressgateway
|
||||||
|
url: file:///opt/filters/sablierproxywasm.wasm/..data/sablierproxywasm.wasm
|
||||||
|
# Use https://istio.io/latest/docs/reference/config/proxy_extensions/wasm-plugin/#WasmPlugin-TrafficSelector
|
||||||
|
# To specify which service to apply this filter only
|
||||||
|
phase: UNSPECIFIED_PHASE
|
||||||
|
pluginConfig:
|
||||||
|
{
|
||||||
|
"sablier_url": "sablier.sablier-system.svc.cluster.local",
|
||||||
|
"cluster": "outbound|10000||sablier.sablier-system.svc.cluster.local",
|
||||||
|
"names": [ "deployment_default_nginx_1" ],
|
||||||
|
"session_duration": "1m",
|
||||||
|
"dynamic": {
|
||||||
|
"display_name": "Healthy Nginx"
|
||||||
|
}
|
||||||
|
}
|
||||||
57
plugins/proxywasm/e2e/istio/kubernetes/manifests/whoami.yml
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: whoami
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: whoami
|
||||||
|
version: v1
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: whoami
|
||||||
|
version: v1
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: whoami
|
||||||
|
image: containous/whoami:v1.5.0
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: whoami
|
||||||
|
labels:
|
||||||
|
app: whoami
|
||||||
|
service: whoami
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
targetPort: 80
|
||||||
|
port: 80
|
||||||
|
selector:
|
||||||
|
app: whoami
|
||||||
|
---
|
||||||
|
apiVersion: networking.istio.io/v1alpha3
|
||||||
|
kind: VirtualService
|
||||||
|
metadata:
|
||||||
|
name: whoami
|
||||||
|
spec:
|
||||||
|
hosts:
|
||||||
|
- "*"
|
||||||
|
gateways:
|
||||||
|
- gateway.istio-system.svc.cluster.local
|
||||||
|
http:
|
||||||
|
- match:
|
||||||
|
- uri:
|
||||||
|
prefix: "/dynamic/whoami"
|
||||||
|
- uri:
|
||||||
|
prefix: "/blocking/whoami"
|
||||||
|
- uri:
|
||||||
|
prefix: "/multiple/whoami"
|
||||||
|
route:
|
||||||
|
- destination:
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
|
host: whoami
|
||||||
68
plugins/proxywasm/e2e/istio/kubernetes/run.sh
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
export DOCKER_COMPOSE_FILE=compose.yaml
|
||||||
|
export DOCKER_COMPOSE_PROJECT_NAME=kubernetes_e2e
|
||||||
|
|
||||||
|
errors=0
|
||||||
|
|
||||||
|
export KUBECONFIG=./kubeconfig.yaml
|
||||||
|
|
||||||
|
echo "Using Docker version:"
|
||||||
|
docker version
|
||||||
|
|
||||||
|
prepare_kubernetes() {
|
||||||
|
docker compose -f $DOCKER_COMPOSE_FILE -p $DOCKER_COMPOSE_PROJECT_NAME up -d
|
||||||
|
until kubectl get nodes | grep " Ready "; do sleep 1; done
|
||||||
|
echo "Loading acouvreur/sablier:local into k3s..."
|
||||||
|
docker save acouvreur/sablier:local | docker exec -i ${DOCKER_COMPOSE_PROJECT_NAME}-server-1 ctr images import -
|
||||||
|
echo "Loading succeeded."
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy_kubernetes() {
|
||||||
|
docker compose -f $DOCKER_COMPOSE_FILE -p $DOCKER_COMPOSE_PROJECT_NAME down --volumes
|
||||||
|
}
|
||||||
|
|
||||||
|
prepare_istio() {
|
||||||
|
helm repo add istio https://istio-release.storage.googleapis.com/charts
|
||||||
|
helm repo update
|
||||||
|
kubectl create namespace istio-system
|
||||||
|
helm install istio-base istio/base -n istio-system --wait
|
||||||
|
helm install istiod istio/istiod -n istio-system --wait
|
||||||
|
kubectl label namespace istio-system istio-injection=enabled
|
||||||
|
kubectl label namespace default istio-injection=enabled
|
||||||
|
kubectl create configmap -n istio-system sablier-wasm-plugin --from-file ../../../sablierproxywasm.wasm
|
||||||
|
helm install istio-ingressgateway istio/gateway --values ./istio-gateway-values.yaml -n istio-system --wait
|
||||||
|
}
|
||||||
|
|
||||||
|
prepare_manifests() {
|
||||||
|
kubectl apply -f ./manifests
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy_manifests() {
|
||||||
|
kubectl delete -f ./manifests
|
||||||
|
}
|
||||||
|
|
||||||
|
run_kubernetes_test() {
|
||||||
|
echo "---- Running Kubernetes Test: $1 ----"
|
||||||
|
prepare_manifests
|
||||||
|
sleep 10
|
||||||
|
go clean -testcache
|
||||||
|
if ! go test -count=1 -tags e2e -timeout 30s -run ^${1}$ github.com/acouvreur/sablier/e2e; then
|
||||||
|
errors=1
|
||||||
|
kubectl -n kube-system logs deployments/sablier-deployment
|
||||||
|
# kubectl -n kube-system logs deployments/traefik TODO: Log istio
|
||||||
|
fi
|
||||||
|
|
||||||
|
destroy_manifests
|
||||||
|
}
|
||||||
|
|
||||||
|
# trap destroy_kubernetes EXIT
|
||||||
|
|
||||||
|
prepare_kubernetes
|
||||||
|
prepare_istio
|
||||||
|
# run_kubernetes_test Test_Dynamic
|
||||||
|
# run_kubernetes_test Test_Blocking
|
||||||
|
# run_kubernetes_test Test_Multiple
|
||||||
|
# run_kubernetes_test Test_Healthy
|
||||||
|
|
||||||
|
# exit $errors
|
||||||
13
plugins/proxywasm/e2e/nginx/Dockerfile
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
FROM ubuntu:22.04
|
||||||
|
|
||||||
|
RUN apt update && apt install libatomic1
|
||||||
|
|
||||||
|
ADD https://github.com/Kong/ngx_wasm_module/releases/download/prerelease-0.3.0/wasmx-prerelease-0.3.0-v8-x86_64-ubuntu22.04.tar.gz wasmx.tar.gz
|
||||||
|
|
||||||
|
RUN mkdir /etc/nginx
|
||||||
|
RUN tar -xvf wasmx.tar.gz
|
||||||
|
RUN mv /wasmx-prerelease-0.3.0-v8-x86_64-ubuntu22.04/* /etc/nginx/
|
||||||
|
|
||||||
|
WORKDIR /etc/nginx
|
||||||
|
|
||||||
|
CMD [ "./nginx", "-g", "daemon off;" ]
|
||||||
28
plugins/proxywasm/e2e/nginx/docker/compose.yaml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
services:
|
||||||
|
reverseproxy:
|
||||||
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
volumes:
|
||||||
|
- ./nginx.conf:/etc/nginx/nginx.conf
|
||||||
|
- ../../../sablierproxywasm.wasm:/wasm/sablierproxywasm.wasm
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
|
||||||
|
sablier:
|
||||||
|
image: acouvreur/sablier:local
|
||||||
|
command:
|
||||||
|
- start
|
||||||
|
- --provider.name=docker
|
||||||
|
- --logging.level=trace
|
||||||
|
volumes:
|
||||||
|
- '/var/run/docker.sock:/var/run/docker.sock'
|
||||||
|
|
||||||
|
whoami:
|
||||||
|
image: containous/whoami:v1.5.0
|
||||||
|
|
||||||
|
nginx:
|
||||||
|
image: nginx:1.27.0
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost"]
|
||||||
|
interval: 5s
|
||||||
62
plugins/proxywasm/e2e/nginx/docker/nginx.conf
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
# nginx.conf
|
||||||
|
events {}
|
||||||
|
|
||||||
|
# nginx master process gets a default 'main' VM
|
||||||
|
# a new top-level configuration block receives all configuration for this main VM
|
||||||
|
wasm {
|
||||||
|
module proxywasm_sablier_plugin /wasm/sablierproxywasm.wasm;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log /dev/stdout info;
|
||||||
|
|
||||||
|
# each nginx worker process is able to instantiate wasm modules in its subsystems
|
||||||
|
http {
|
||||||
|
access_log /dev/stdout;
|
||||||
|
|
||||||
|
# internal docker resolver, see /etc/resolv.conf on proxy container
|
||||||
|
resolver 127.0.0.11 valid=1s ipv6=off;
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 8080;
|
||||||
|
|
||||||
|
location /dynamic/whoami {
|
||||||
|
proxy_wasm proxywasm_sablier_plugin '{ "sablier_url": "sablier:10000", "names": ["docker_classic_e2e-whoami-1"], "session_duration": "1m", "dynamic": { "display_name": "Dynamic Whoami", "theme": "hacker-terminal" } }';
|
||||||
|
|
||||||
|
set $proxy_pass_host whoami:80$request_uri;
|
||||||
|
proxy_pass http://$proxy_pass_host;
|
||||||
|
proxy_set_header Host localhost:8080; # e2e test compliance
|
||||||
|
}
|
||||||
|
|
||||||
|
location /blocking/whoami {
|
||||||
|
wasm_socket_read_timeout 60s; # Blocking hangs the request
|
||||||
|
proxy_wasm proxywasm_sablier_plugin '{ "sablier_url": "sablier:10000", "names": ["docker_classic_e2e-whoami-1"], "session_duration": "1m", "blocking": { "timeout": "30s" } }';
|
||||||
|
|
||||||
|
set $proxy_pass_host whoami:80$request_uri;
|
||||||
|
proxy_pass http://$proxy_pass_host;
|
||||||
|
proxy_set_header Host localhost:8080; # e2e test compliance
|
||||||
|
}
|
||||||
|
|
||||||
|
location /multiple/whoami {
|
||||||
|
proxy_wasm proxywasm_sablier_plugin '{ "sablier_url": "sablier:10000", "names": ["docker_classic_e2e-whoami-1", "docker_classic_e2e-nginx-1"], "session_duration": "1m", "dynamic": { "display_name": "Multiple Whoami" } }';
|
||||||
|
|
||||||
|
proxy_pass http://whoami:80$request_uri;
|
||||||
|
proxy_set_header Host localhost:8080; # e2e test compliance
|
||||||
|
}
|
||||||
|
|
||||||
|
location /multiple/nginx {
|
||||||
|
proxy_wasm proxywasm_sablier_plugin '{ "sablier_url": "sablier:10000", "names": ["docker_classic_e2e-whoami-1", "docker_classic_e2e-nginx-1"], "session_duration": "1m", "dynamic": { "display_name": "Multiple Whoami" } }';
|
||||||
|
|
||||||
|
set $proxy_pass_host nginx:80$request_uri;
|
||||||
|
proxy_pass http://$proxy_pass_host;
|
||||||
|
proxy_set_header Host localhost:8080; # e2e test compliance
|
||||||
|
}
|
||||||
|
|
||||||
|
location /healthy/nginx {
|
||||||
|
proxy_wasm proxywasm_sablier_plugin '{ "sablier_url": "sablier:10000", "names": ["docker_classic_e2e-nginx-1"], "session_duration": "1m", "dynamic": { "display_name": "Healthy Nginx" } }';
|
||||||
|
|
||||||
|
set $proxy_pass_host nginx:80$request_uri;
|
||||||
|
proxy_pass http://$proxy_pass_host;
|
||||||
|
proxy_set_header Host localhost:8080; # e2e test compliance
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
39
plugins/proxywasm/e2e/nginx/docker/run.sh
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
DOCKER_COMPOSE_FILE=compose.yaml
|
||||||
|
DOCKER_COMPOSE_PROJECT_NAME=docker_classic_e2e
|
||||||
|
|
||||||
|
errors=0
|
||||||
|
|
||||||
|
echo "Using Docker version:"
|
||||||
|
docker version
|
||||||
|
|
||||||
|
prepare_docker_classic() {
|
||||||
|
docker compose -f $DOCKER_COMPOSE_FILE -p $DOCKER_COMPOSE_PROJECT_NAME up -d
|
||||||
|
docker compose -f $DOCKER_COMPOSE_FILE -p $DOCKER_COMPOSE_PROJECT_NAME stop whoami nginx
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy_docker_classic() {
|
||||||
|
docker compose -f $DOCKER_COMPOSE_FILE -p $DOCKER_COMPOSE_PROJECT_NAME down --remove-orphans || true
|
||||||
|
}
|
||||||
|
|
||||||
|
run_docker_classic_test() {
|
||||||
|
echo "Running Docker Classic Test: $1"
|
||||||
|
prepare_docker_classic
|
||||||
|
sleep 2
|
||||||
|
go clean -testcache
|
||||||
|
if ! go test -count=1 -tags e2e -timeout 30s -run ^${1}$ github.com/acouvreur/sablier/e2e; then
|
||||||
|
errors=1
|
||||||
|
docker compose -f ${DOCKER_COMPOSE_FILE} -p ${DOCKER_COMPOSE_PROJECT_NAME} logs sablier reverseproxy
|
||||||
|
fi
|
||||||
|
destroy_docker_classic
|
||||||
|
}
|
||||||
|
|
||||||
|
trap destroy_docker_classic EXIT
|
||||||
|
|
||||||
|
run_docker_classic_test Test_Dynamic
|
||||||
|
run_docker_classic_test Test_Blocking
|
||||||
|
run_docker_classic_test Test_Multiple
|
||||||
|
run_docker_classic_test Test_Healthy
|
||||||
|
|
||||||
|
exit $errors
|
||||||
16
plugins/proxywasm/go.mod
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
module github.com/acouvreur/sablier/plugins/proxy-wasm
|
||||||
|
|
||||||
|
go 1.22
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/json-iterator/tinygo v0.0.0-20211221071957-84b5b690c8a0
|
||||||
|
github.com/tetratelabs/proxy-wasm-go-sdk v0.23.0
|
||||||
|
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/tetratelabs/wazero v1.6.0 // indirect
|
||||||
|
github.com/tidwall/gjson v1.17.1 // indirect
|
||||||
|
github.com/tidwall/match v1.1.1 // indirect
|
||||||
|
github.com/tidwall/pretty v1.2.1 // indirect
|
||||||
|
)
|
||||||
16
plugins/proxywasm/go.sum
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
github.com/json-iterator/tinygo v0.0.0-20211221071957-84b5b690c8a0 h1:/cd98gHSKnKHcYYyBJ9qNvHxYZdXzJC8JMs42gMPp5I=
|
||||||
|
github.com/json-iterator/tinygo v0.0.0-20211221071957-84b5b690c8a0/go.mod h1:sR5SXbtbtp8PxPu3yGjZug4AS5aAur8jQZl9DXYTpP0=
|
||||||
|
github.com/tetratelabs/proxy-wasm-go-sdk v0.23.0 h1:e0dm/ypyd1xudIrg8VTsd8dawuYaSy2gqewH5zD4rU8=
|
||||||
|
github.com/tetratelabs/proxy-wasm-go-sdk v0.23.0/go.mod h1:YqR8JZaY3Ev9ihXgjzAQAMkXEzPKKmy4Q5rsVWt4XGk=
|
||||||
|
github.com/tetratelabs/wazero v1.6.0 h1:z0H1iikCdP8t+q341xqepY4EWvHEw8Es7tlqiVzlP3g=
|
||||||
|
github.com/tetratelabs/wazero v1.6.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A=
|
||||||
|
github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||||
|
github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U=
|
||||||
|
github.com/tidwall/gjson v1.17.1/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/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||||
|
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
||||||
|
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||||
|
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY=
|
||||||
|
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
|
||||||
322
plugins/proxywasm/main.go
Normal file
@@ -0,0 +1,322 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
jsoniter "github.com/json-iterator/tinygo"
|
||||||
|
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm"
|
||||||
|
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm/types"
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Version string
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// SetVMContext is the entrypoint for setting up this entire Wasm VM.
|
||||||
|
// Please make sure that this entrypoint be called during "main()" function, otherwise
|
||||||
|
// this VM would fail.
|
||||||
|
proxywasm.SetVMContext(&vmContext{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// vmContext implements types.VMContext interface of proxy-wasm-go SDK.
|
||||||
|
type vmContext struct {
|
||||||
|
// Embed the default VM context here,
|
||||||
|
// so that we don't need to reimplement all the methods.
|
||||||
|
types.DefaultVMContext
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override types.DefaultVMContext.
|
||||||
|
func (*vmContext) NewPluginContext(contextID uint32) types.PluginContext {
|
||||||
|
return &pluginContext{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type pluginContext struct {
|
||||||
|
// Embed the default plugin context here,
|
||||||
|
// so that we don't need to reimplement all the methods.
|
||||||
|
types.DefaultPluginContext
|
||||||
|
configuration pluginConfiguration
|
||||||
|
}
|
||||||
|
|
||||||
|
type pluginConfiguration struct {
|
||||||
|
cluster string
|
||||||
|
method string
|
||||||
|
path string
|
||||||
|
authority string
|
||||||
|
timeout uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// newPluginConfiguration creates a pluginConfiguration with default values
|
||||||
|
func newPluginConfiguration() pluginConfiguration {
|
||||||
|
return pluginConfiguration{
|
||||||
|
cluster: "sablier:10000",
|
||||||
|
method: "GET",
|
||||||
|
path: "/",
|
||||||
|
authority: "sablier.cluster.local",
|
||||||
|
timeout: 5000, // timeout in milliseconds
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override types.DefaultPluginContext.
|
||||||
|
func (ctx *pluginContext) OnPluginStart(pluginConfigurationSize int) types.OnPluginStartStatus {
|
||||||
|
proxywasm.LogInfof("sablier proxywasm plugin version %v loaded", Version)
|
||||||
|
data, err := proxywasm.GetPluginConfiguration()
|
||||||
|
if err != nil && err != types.ErrorStatusNotFound {
|
||||||
|
proxywasm.LogCriticalf("error reading plugin configuration: %v", err)
|
||||||
|
return types.OnPluginStartStatusFailed
|
||||||
|
}
|
||||||
|
|
||||||
|
proxywasm.LogInfof("plugin config: %s", string(data))
|
||||||
|
config, err := parsePluginConfiguration(data)
|
||||||
|
if err != nil {
|
||||||
|
proxywasm.LogCriticalf("error parsing plugin configuration: %v", err)
|
||||||
|
return types.OnPluginStartStatusFailed
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.configuration = config
|
||||||
|
|
||||||
|
return types.OnPluginStartStatusOK
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:generate go run github.com/json-iterator/tinygo/gen
|
||||||
|
type DynamicConfiguration struct {
|
||||||
|
DisplayName string `json:"display_name"`
|
||||||
|
ShowDetails *bool `json:"show_details"`
|
||||||
|
Theme string `json:"theme"`
|
||||||
|
RefreshFrequency string `json:"refresh_frequency"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:generate go run github.com/json-iterator/tinygo/gen
|
||||||
|
type BlockingConfiguration struct {
|
||||||
|
Timeout string `json:"timeout"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:generate go run github.com/json-iterator/tinygo/gen
|
||||||
|
type Config struct {
|
||||||
|
// SablierURL in the format of hostname:port. The scheme is excluded
|
||||||
|
SablierURL string `json:"sablier_url"`
|
||||||
|
// Cluster is an optional value that allows you to set override the
|
||||||
|
// first argument to `proxywasm.DispatchHttpCall`.
|
||||||
|
// In istio for exemple, the expected value would be: "outbound|port||hostname", e.g.: "outbound|10000||sablier"
|
||||||
|
// In APISIX and Nginx for example, the value would be the same as SablierURL, e.g.: sablier:10000
|
||||||
|
// Defaults to the same value of `SablierURL`.
|
||||||
|
Cluster string `json:"cluster"`
|
||||||
|
Names []string `json:"names"`
|
||||||
|
Group string `json:"group"`
|
||||||
|
SessionDuration string `json:"session_duration"`
|
||||||
|
Dynamic *DynamicConfiguration `json:"dynamic"`
|
||||||
|
Blocking *BlockingConfiguration `json:"blocking"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Config) GetPath() string {
|
||||||
|
path := url.URL{}
|
||||||
|
q := path.Query()
|
||||||
|
|
||||||
|
if c.SessionDuration != "" {
|
||||||
|
dur, err := time.ParseDuration(c.SessionDuration)
|
||||||
|
if err != nil {
|
||||||
|
proxywasm.LogWarnf("parsing session duration failed (ignoring value): %v", err)
|
||||||
|
} else {
|
||||||
|
q.Add("session_duration", dur.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, name := range c.Names {
|
||||||
|
q.Add("names", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Group != "" {
|
||||||
|
q.Add("group", c.Group)
|
||||||
|
}
|
||||||
|
path.RawQuery = q.Encode()
|
||||||
|
|
||||||
|
if c.Dynamic != nil {
|
||||||
|
return c.getDynamicQuery(path)
|
||||||
|
} else if c.Blocking != nil {
|
||||||
|
return c.getBlockingQuery(path)
|
||||||
|
}
|
||||||
|
return "no strategy configured"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Config) getDynamicQuery(path url.URL) string {
|
||||||
|
path.Path = "/api/strategies/dynamic"
|
||||||
|
q := path.Query()
|
||||||
|
|
||||||
|
if c.Dynamic.DisplayName != "" {
|
||||||
|
q.Add("display_name", c.Dynamic.DisplayName)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Dynamic.Theme != "" {
|
||||||
|
q.Add("theme", c.Dynamic.Theme)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Dynamic.RefreshFrequency != "" {
|
||||||
|
dur, err := time.ParseDuration(c.Dynamic.RefreshFrequency)
|
||||||
|
if err != nil {
|
||||||
|
proxywasm.LogWarnf("parsing dynamic refresh frequency failed (ignoring value): %v", err)
|
||||||
|
} else {
|
||||||
|
q.Add("refresh_frequency", dur.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Dynamic.ShowDetails != nil {
|
||||||
|
q.Add("show_details", strconv.FormatBool(*c.Dynamic.ShowDetails))
|
||||||
|
}
|
||||||
|
path.RawQuery = q.Encode()
|
||||||
|
|
||||||
|
return path.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Config) getBlockingQuery(path url.URL) string {
|
||||||
|
path.Path = "/api/strategies/blocking"
|
||||||
|
q := path.Query()
|
||||||
|
|
||||||
|
if c.Blocking.Timeout != "" {
|
||||||
|
dur, err := time.ParseDuration(c.Blocking.Timeout)
|
||||||
|
if err != nil {
|
||||||
|
proxywasm.LogWarnf("parsing blocking timeout duration failed (ignoring value): %v", err)
|
||||||
|
} else {
|
||||||
|
q.Add("timeout", dur.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
path.RawQuery = q.Encode()
|
||||||
|
|
||||||
|
return path.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func parsePluginConfiguration(data []byte) (pluginConfiguration, error) {
|
||||||
|
pluginConf := newPluginConfiguration()
|
||||||
|
if len(data) == 0 {
|
||||||
|
return pluginConf, fmt.Errorf("the plugin configuration is not a valid: %q", string(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
json := jsoniter.CreateJsonAdapter(Config_json{}, BlockingConfiguration_json{}, DynamicConfiguration_json{})
|
||||||
|
|
||||||
|
var c Config
|
||||||
|
err := json.Unmarshal(data, &c)
|
||||||
|
if err != nil {
|
||||||
|
proxywasm.LogErrorf("error parsing configuration: %v", err.Error())
|
||||||
|
return pluginConf, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Blocking == nil && c.Dynamic == nil {
|
||||||
|
return pluginConf, fmt.Errorf("you must specify one strategy (dynamic or blocking)")
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Blocking != nil && c.Dynamic != nil {
|
||||||
|
return pluginConf, fmt.Errorf("you must specify only one strategy")
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Blocking != nil && c.Blocking.Timeout != "" {
|
||||||
|
timeout, err := time.ParseDuration(c.Blocking.Timeout)
|
||||||
|
if err != nil {
|
||||||
|
return pluginConf, fmt.Errorf("cannot parse blocking timeout duration: %v", err)
|
||||||
|
}
|
||||||
|
pluginConf.timeout = uint32(timeout.Milliseconds())
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c.Names) == 0 && len(c.Group) == 0 {
|
||||||
|
return pluginConf, fmt.Errorf("you must specify names or group")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c.Names) > 0 && len(c.Group) > 0 {
|
||||||
|
return pluginConf, fmt.Errorf("you must specify either names or group")
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.SablierURL != "" {
|
||||||
|
pluginConf.authority = c.SablierURL
|
||||||
|
|
||||||
|
// Default to SablierURL
|
||||||
|
pluginConf.cluster = c.SablierURL
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Cluster != "" {
|
||||||
|
pluginConf.cluster = c.Cluster
|
||||||
|
}
|
||||||
|
|
||||||
|
pluginConf.path = c.GetPath()
|
||||||
|
|
||||||
|
return pluginConf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override types.DefaultPluginContext.
|
||||||
|
func (ctx *pluginContext) NewHttpContext(contextID uint32) types.HttpContext {
|
||||||
|
|
||||||
|
headers := [][2]string{
|
||||||
|
{":method", ctx.configuration.method},
|
||||||
|
{":path", ctx.configuration.path},
|
||||||
|
{":authority", ctx.configuration.authority},
|
||||||
|
{"User-Agent", fmt.Sprintf("sablier-proxywasm-plugin/%s", Version)},
|
||||||
|
}
|
||||||
|
return &httpOnDemand{
|
||||||
|
contextID: contextID,
|
||||||
|
headers: headers,
|
||||||
|
cluster: ctx.configuration.cluster,
|
||||||
|
timeout: ctx.configuration.timeout,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type httpOnDemand struct {
|
||||||
|
// Embed the default http context here,
|
||||||
|
// so that we don't need to reimplement all the methods.
|
||||||
|
types.DefaultHttpContext
|
||||||
|
contextID uint32
|
||||||
|
headers [][2]string
|
||||||
|
cluster string
|
||||||
|
timeout uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override types.DefaultHttpContext.
|
||||||
|
func (ctx *httpOnDemand) OnHttpRequestHeaders(numHeaders int, endOfStream bool) types.Action {
|
||||||
|
proxywasm.LogInfof("DispatchHttpCall to %v", ctx.cluster)
|
||||||
|
proxywasm.LogInfof("DispatchHttpCall with headers %v", ctx.headers)
|
||||||
|
if _, err := proxywasm.DispatchHttpCall(ctx.cluster, ctx.headers, nil, nil,
|
||||||
|
ctx.timeout, httpCallResponseCallback); err != nil {
|
||||||
|
proxywasm.LogCriticalf("dipatch httpcall failed: %v", err)
|
||||||
|
proxywasm.LogDebugf("%s: %v", ctx.cluster, ctx.headers)
|
||||||
|
return types.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
proxywasm.LogInfof("http call dispatched to %s", ctx.cluster)
|
||||||
|
|
||||||
|
return types.ActionPause
|
||||||
|
}
|
||||||
|
|
||||||
|
func httpCallResponseCallback(numHeaders, bodySize, numTrailers int) {
|
||||||
|
hs, err := proxywasm.GetHttpCallResponseHeaders()
|
||||||
|
if err != nil {
|
||||||
|
proxywasm.LogCriticalf("failed to get response headers: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
proxywasm.LogInfof("GetHttpCallResponseHeaders: %v", hs)
|
||||||
|
|
||||||
|
headerIndex := slices.IndexFunc(hs, func(h [2]string) bool { return strings.ToLower(h[0]) == "x-sablier-session-status" })
|
||||||
|
if headerIndex < 0 {
|
||||||
|
proxywasm.LogCriticalf("failed to find x-sablier-session-status header: %v", hs)
|
||||||
|
proxywasm.ResumeHttpRequest()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
headerValue := hs[headerIndex][1]
|
||||||
|
|
||||||
|
if headerValue != "ready" {
|
||||||
|
b, err := proxywasm.GetHttpCallResponseBody(0, bodySize)
|
||||||
|
if err != nil {
|
||||||
|
proxywasm.LogCriticalf("failed to get response body: %v", err)
|
||||||
|
proxywasm.ResumeHttpRequest()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
proxywasm.LogInfof("GetHttpCallResponseBody (%v bytes): %v", bodySize, string(b))
|
||||||
|
|
||||||
|
if err := proxywasm.SendHttpResponse(200, hs, b, -1); err != nil {
|
||||||
|
proxywasm.LogErrorf("failed to send local response: %v", err)
|
||||||
|
proxywasm.ResumeHttpRequest()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
proxywasm.ResumeHttpRequest()
|
||||||
|
}
|
||||||
|
}
|
||||||
97
plugins/proxywasm/main_test.go
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm/proxytest"
|
||||||
|
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUnmarshal(t *testing.T) {
|
||||||
|
data := `{
|
||||||
|
"sablier_url": "sablier",
|
||||||
|
"sablier_port": 10000,
|
||||||
|
"group": "demo",
|
||||||
|
"session_duration": "30s",
|
||||||
|
"dynamic": {
|
||||||
|
"display_dame": "From WASM!",
|
||||||
|
"show_details": true,
|
||||||
|
"theme": "hacker-terminal",
|
||||||
|
"refresh_frequency": "5s"
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
|
config, err := parsePluginConfiguration([]byte(data))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log("path:", config.path)
|
||||||
|
t.Log("authority:", config.authority)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPluginContext_OnTick(t *testing.T) {
|
||||||
|
vmTest(t, func(t *testing.T, vm types.VMContext) {
|
||||||
|
data := `{
|
||||||
|
"sablier_url": "sablier",
|
||||||
|
"sablier_port": 10000,
|
||||||
|
"group": "demo",
|
||||||
|
"session_duration": "30s",
|
||||||
|
"dynamic": {
|
||||||
|
"display_dame": "From WASM!",
|
||||||
|
"show_details": true,
|
||||||
|
"theme": "hacker-terminal",
|
||||||
|
"refresh_frequency": "5s"
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
opt := proxytest.NewEmulatorOption().WithVMContext(vm).WithPluginConfiguration([]byte(data))
|
||||||
|
host, reset := proxytest.NewHostEmulator(opt)
|
||||||
|
defer reset()
|
||||||
|
|
||||||
|
// Create http context.
|
||||||
|
id := host.InitializeHttpContext()
|
||||||
|
|
||||||
|
// Call OnRequestHeaders.
|
||||||
|
action := host.CallOnRequestHeaders(id, [][2]string{
|
||||||
|
{"content-length", "10"},
|
||||||
|
}, false)
|
||||||
|
|
||||||
|
// Must be continued.
|
||||||
|
require.Equal(t, types.ActionPause, action)
|
||||||
|
|
||||||
|
// Check the final request headers
|
||||||
|
host.CallOnHttpCallResponse(id, [][2]string{
|
||||||
|
{"x-sablier-session-status", "not-ready"},
|
||||||
|
}, nil, []byte("Response from Sablier"))
|
||||||
|
response := host.GetCurrentResponseBody(id)
|
||||||
|
require.Equal(t,
|
||||||
|
"Response from Sablier",
|
||||||
|
response,
|
||||||
|
"response should be served from sablier.")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// vmTest executes f twice, once with a types.VMContext that executes plugin code directly
|
||||||
|
// in the host, and again by executing the plugin code within the compiled main.wasm binary.
|
||||||
|
// Execution with main.wasm will be skipped if the file cannot be found.
|
||||||
|
func vmTest(t *testing.T, f func(*testing.T, types.VMContext)) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
t.Run("go", func(t *testing.T) {
|
||||||
|
f(t, &vmContext{})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("wasm", func(t *testing.T) {
|
||||||
|
wasm, err := os.ReadFile("sablierproxywasm.wasm")
|
||||||
|
if err != nil {
|
||||||
|
t.Skip("wasm not found")
|
||||||
|
}
|
||||||
|
v, err := proxytest.NewWasmVMContext(wasm)
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer v.Close()
|
||||||
|
f(t, v)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -7,7 +7,7 @@ module.exports = {
|
|||||||
"@semantic-release/commit-analyzer",
|
"@semantic-release/commit-analyzer",
|
||||||
"@semantic-release/release-notes-generator",
|
"@semantic-release/release-notes-generator",
|
||||||
["@semantic-release/exec", {
|
["@semantic-release/exec", {
|
||||||
"publishCmd": "make VERSION=${nextRelease.version} release -j 3"
|
"publishCmd": "make VERSION=${nextRelease.version} release -j 3 && make VERSION=${nextRelease.version} proxywasm"
|
||||||
}],
|
}],
|
||||||
["@semantic-release/github", {
|
["@semantic-release/github", {
|
||||||
"assets": [
|
"assets": [
|
||||||
|
|||||||