Enhance wasm plugins
Co-authored-by: Michael <[michael.matur@gmail.com](mailto:michael.matur@gmail.com)>
This commit is contained in:
parent
983940ae60
commit
e7d1a98c5e
14 changed files with 329 additions and 26 deletions
|
@ -146,6 +146,7 @@ linters-settings:
|
||||||
- github.com/mailgun/multibuf
|
- github.com/mailgun/multibuf
|
||||||
- github.com/jaguilar/vt100
|
- github.com/jaguilar/vt100
|
||||||
- github.com/cucumber/godog
|
- github.com/cucumber/godog
|
||||||
|
- github.com/http-wasm/http-wasm-host-go
|
||||||
testifylint:
|
testifylint:
|
||||||
disable:
|
disable:
|
||||||
- suite-dont-use-pkg
|
- suite-dont-use-pkg
|
||||||
|
|
|
@ -217,11 +217,29 @@ Timeout defines how long to wait on an idle session before releasing the related
|
||||||
Local plugins configuration. (Default: ```false```)
|
Local plugins configuration. (Default: ```false```)
|
||||||
|
|
||||||
`--experimental.localplugins.<name>.modulename`:
|
`--experimental.localplugins.<name>.modulename`:
|
||||||
plugin's module name.
|
Plugin's module name.
|
||||||
|
|
||||||
|
`--experimental.localplugins.<name>.settings`:
|
||||||
|
Plugin's settings (works only for wasm plugins).
|
||||||
|
|
||||||
|
`--experimental.localplugins.<name>.settings.envs`:
|
||||||
|
Environment variables to forward to the wasm guest.
|
||||||
|
|
||||||
|
`--experimental.localplugins.<name>.settings.mounts`:
|
||||||
|
Directory to mount to the wasm guest.
|
||||||
|
|
||||||
`--experimental.plugins.<name>.modulename`:
|
`--experimental.plugins.<name>.modulename`:
|
||||||
plugin's module name.
|
plugin's module name.
|
||||||
|
|
||||||
|
`--experimental.plugins.<name>.settings`:
|
||||||
|
Plugin's settings (works only for wasm plugins).
|
||||||
|
|
||||||
|
`--experimental.plugins.<name>.settings.envs`:
|
||||||
|
Environment variables to forward to the wasm guest.
|
||||||
|
|
||||||
|
`--experimental.plugins.<name>.settings.mounts`:
|
||||||
|
Directory to mount to the wasm guest.
|
||||||
|
|
||||||
`--experimental.plugins.<name>.version`:
|
`--experimental.plugins.<name>.version`:
|
||||||
plugin's version.
|
plugin's version.
|
||||||
|
|
||||||
|
|
|
@ -217,11 +217,29 @@ Timeout defines how long to wait on an idle session before releasing the related
|
||||||
Local plugins configuration. (Default: ```false```)
|
Local plugins configuration. (Default: ```false```)
|
||||||
|
|
||||||
`TRAEFIK_EXPERIMENTAL_LOCALPLUGINS_<NAME>_MODULENAME`:
|
`TRAEFIK_EXPERIMENTAL_LOCALPLUGINS_<NAME>_MODULENAME`:
|
||||||
plugin's module name.
|
Plugin's module name.
|
||||||
|
|
||||||
|
`TRAEFIK_EXPERIMENTAL_LOCALPLUGINS_<NAME>_SETTINGS`:
|
||||||
|
Plugin's settings (works only for wasm plugins).
|
||||||
|
|
||||||
|
`TRAEFIK_EXPERIMENTAL_LOCALPLUGINS_<NAME>_SETTINGS_ENVS`:
|
||||||
|
Environment variables to forward to the wasm guest.
|
||||||
|
|
||||||
|
`TRAEFIK_EXPERIMENTAL_LOCALPLUGINS_<NAME>_SETTINGS_MOUNTS`:
|
||||||
|
Directory to mount to the wasm guest.
|
||||||
|
|
||||||
`TRAEFIK_EXPERIMENTAL_PLUGINS_<NAME>_MODULENAME`:
|
`TRAEFIK_EXPERIMENTAL_PLUGINS_<NAME>_MODULENAME`:
|
||||||
plugin's module name.
|
plugin's module name.
|
||||||
|
|
||||||
|
`TRAEFIK_EXPERIMENTAL_PLUGINS_<NAME>_SETTINGS`:
|
||||||
|
Plugin's settings (works only for wasm plugins).
|
||||||
|
|
||||||
|
`TRAEFIK_EXPERIMENTAL_PLUGINS_<NAME>_SETTINGS_ENVS`:
|
||||||
|
Environment variables to forward to the wasm guest.
|
||||||
|
|
||||||
|
`TRAEFIK_EXPERIMENTAL_PLUGINS_<NAME>_SETTINGS_MOUNTS`:
|
||||||
|
Directory to mount to the wasm guest.
|
||||||
|
|
||||||
`TRAEFIK_EXPERIMENTAL_PLUGINS_<NAME>_VERSION`:
|
`TRAEFIK_EXPERIMENTAL_PLUGINS_<NAME>_VERSION`:
|
||||||
plugin's version.
|
plugin's version.
|
||||||
|
|
||||||
|
|
|
@ -473,14 +473,26 @@
|
||||||
[experimental.plugins.Descriptor0]
|
[experimental.plugins.Descriptor0]
|
||||||
moduleName = "foobar"
|
moduleName = "foobar"
|
||||||
version = "foobar"
|
version = "foobar"
|
||||||
|
[experimental.plugins.Descriptor0.settings]
|
||||||
|
envs = ["foobar", "foobar"]
|
||||||
|
mounts = ["foobar", "foobar"]
|
||||||
[experimental.plugins.Descriptor1]
|
[experimental.plugins.Descriptor1]
|
||||||
moduleName = "foobar"
|
moduleName = "foobar"
|
||||||
version = "foobar"
|
version = "foobar"
|
||||||
|
[experimental.plugins.Descriptor1.settings]
|
||||||
|
envs = ["foobar", "foobar"]
|
||||||
|
mounts = ["foobar", "foobar"]
|
||||||
[experimental.localPlugins]
|
[experimental.localPlugins]
|
||||||
[experimental.localPlugins.LocalDescriptor0]
|
[experimental.localPlugins.LocalDescriptor0]
|
||||||
moduleName = "foobar"
|
moduleName = "foobar"
|
||||||
|
[experimental.localPlugins.LocalDescriptor0.settings]
|
||||||
|
envs = ["foobar", "foobar"]
|
||||||
|
mounts = ["foobar", "foobar"]
|
||||||
[experimental.localPlugins.LocalDescriptor1]
|
[experimental.localPlugins.LocalDescriptor1]
|
||||||
moduleName = "foobar"
|
moduleName = "foobar"
|
||||||
|
[experimental.localPlugins.LocalDescriptor1.settings]
|
||||||
|
envs = ["foobar", "foobar"]
|
||||||
|
mounts = ["foobar", "foobar"]
|
||||||
|
|
||||||
[core]
|
[core]
|
||||||
defaultRuleSyntax = "foobar"
|
defaultRuleSyntax = "foobar"
|
||||||
|
|
|
@ -512,14 +512,42 @@ experimental:
|
||||||
Descriptor0:
|
Descriptor0:
|
||||||
moduleName: foobar
|
moduleName: foobar
|
||||||
version: foobar
|
version: foobar
|
||||||
|
settings:
|
||||||
|
envs:
|
||||||
|
- foobar
|
||||||
|
- foobar
|
||||||
|
mounts:
|
||||||
|
- foobar
|
||||||
|
- foobar
|
||||||
Descriptor1:
|
Descriptor1:
|
||||||
moduleName: foobar
|
moduleName: foobar
|
||||||
version: foobar
|
version: foobar
|
||||||
|
settings:
|
||||||
|
envs:
|
||||||
|
- foobar
|
||||||
|
- foobar
|
||||||
|
mounts:
|
||||||
|
- foobar
|
||||||
|
- foobar
|
||||||
localPlugins:
|
localPlugins:
|
||||||
LocalDescriptor0:
|
LocalDescriptor0:
|
||||||
moduleName: foobar
|
moduleName: foobar
|
||||||
|
settings:
|
||||||
|
envs:
|
||||||
|
- foobar
|
||||||
|
- foobar
|
||||||
|
mounts:
|
||||||
|
- foobar
|
||||||
|
- foobar
|
||||||
LocalDescriptor1:
|
LocalDescriptor1:
|
||||||
moduleName: foobar
|
moduleName: foobar
|
||||||
|
settings:
|
||||||
|
envs:
|
||||||
|
- foobar
|
||||||
|
- foobar
|
||||||
|
mounts:
|
||||||
|
- foobar
|
||||||
|
- foobar
|
||||||
kubernetesGateway: true
|
kubernetesGateway: true
|
||||||
core:
|
core:
|
||||||
defaultRuleSyntax: foobar
|
defaultRuleSyntax: foobar
|
||||||
|
|
7
go.mod
7
go.mod
|
@ -32,6 +32,7 @@ require (
|
||||||
github.com/http-wasm/http-wasm-host-go v0.6.0
|
github.com/http-wasm/http-wasm-host-go v0.6.0
|
||||||
github.com/influxdata/influxdb-client-go/v2 v2.7.0
|
github.com/influxdata/influxdb-client-go/v2 v2.7.0
|
||||||
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d
|
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d
|
||||||
|
github.com/juliens/wasm-goexport v0.0.6
|
||||||
github.com/klauspost/compress v1.17.2
|
github.com/klauspost/compress v1.17.2
|
||||||
github.com/kvtools/consul v1.0.2
|
github.com/kvtools/consul v1.0.2
|
||||||
github.com/kvtools/etcdv3 v1.0.2
|
github.com/kvtools/etcdv3 v1.0.2
|
||||||
|
@ -53,12 +54,14 @@ require (
|
||||||
github.com/rs/zerolog v1.29.0
|
github.com/rs/zerolog v1.29.0
|
||||||
github.com/sirupsen/logrus v1.9.3
|
github.com/sirupsen/logrus v1.9.3
|
||||||
github.com/spiffe/go-spiffe/v2 v2.1.1
|
github.com/spiffe/go-spiffe/v2 v2.1.1
|
||||||
|
github.com/stealthrocket/wasi-go v0.8.0
|
||||||
|
github.com/stealthrocket/wazergo v0.19.1
|
||||||
github.com/stretchr/testify v1.9.0
|
github.com/stretchr/testify v1.9.0
|
||||||
github.com/stvp/go-udp-testing v0.0.0-20191102171040-06b61409b154
|
github.com/stvp/go-udp-testing v0.0.0-20191102171040-06b61409b154
|
||||||
github.com/tailscale/tscert v0.0.0-20230806124524-28a91b69a046
|
github.com/tailscale/tscert v0.0.0-20230806124524-28a91b69a046
|
||||||
github.com/testcontainers/testcontainers-go v0.30.0
|
github.com/testcontainers/testcontainers-go v0.30.0
|
||||||
github.com/testcontainers/testcontainers-go/modules/k3s v0.30.0
|
github.com/testcontainers/testcontainers-go/modules/k3s v0.30.0
|
||||||
github.com/tetratelabs/wazero v1.5.0
|
github.com/tetratelabs/wazero v1.7.2
|
||||||
github.com/tidwall/gjson v1.17.0
|
github.com/tidwall/gjson v1.17.0
|
||||||
github.com/traefik/grpc-web v0.16.0
|
github.com/traefik/grpc-web v0.16.0
|
||||||
github.com/traefik/paerser v0.2.0
|
github.com/traefik/paerser v0.2.0
|
||||||
|
@ -371,3 +374,5 @@ exclude github.com/tencentcloud/tencentcloud-sdk-go v3.0.83+incompatible
|
||||||
|
|
||||||
// https://github.com/docker/compose/blob/v2.19.0/go.mod#L12
|
// https://github.com/docker/compose/blob/v2.19.0/go.mod#L12
|
||||||
replace github.com/cucumber/godog => github.com/cucumber/godog v0.13.0
|
replace github.com/cucumber/godog => github.com/cucumber/godog v0.13.0
|
||||||
|
|
||||||
|
replace github.com/http-wasm/http-wasm-host-go => github.com/traefik/http-wasm-host-go v0.0.0-20240618100324-3c53dcaa1a70
|
||||||
|
|
14
go.sum
14
go.sum
|
@ -592,8 +592,6 @@ github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/J
|
||||||
github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY=
|
github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY=
|
||||||
github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4=
|
github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/http-wasm/http-wasm-host-go v0.6.0 h1:Vd4XvcFB3NMgWp2VLCQaiqYgLneN2lChbyN9NGoNDro=
|
|
||||||
github.com/http-wasm/http-wasm-host-go v0.6.0/go.mod h1:zQB3w+df4hryDEqBorGyA1DwPJ86LfKIASNLFuj6CuI=
|
|
||||||
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||||
github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU=
|
github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU=
|
||||||
github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||||
|
@ -635,6 +633,8 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
|
github.com/juliens/wasm-goexport v0.0.6 h1:YU0c+j0dF/HNy32vgYTA+K/6wnsZXgGc+ihl/UDw8iA=
|
||||||
|
github.com/juliens/wasm-goexport v0.0.6/go.mod h1:VTTpJVY3tIBet0Gv8r5TxdsNg0vDkkqXYm0Hp5hR42A=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
|
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
|
||||||
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 h1:qGQQKEcAR99REcMpsXCp3lJ03zYT1PkRd3kQGPn9GVg=
|
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 h1:qGQQKEcAR99REcMpsXCp3lJ03zYT1PkRd3kQGPn9GVg=
|
||||||
|
@ -1051,6 +1051,10 @@ github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5q
|
||||||
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||||
github.com/spiffe/go-spiffe/v2 v2.1.1 h1:RT9kM8MZLZIsPTH+HKQEP5yaAk3yd/VBzlINaRjXs8k=
|
github.com/spiffe/go-spiffe/v2 v2.1.1 h1:RT9kM8MZLZIsPTH+HKQEP5yaAk3yd/VBzlINaRjXs8k=
|
||||||
github.com/spiffe/go-spiffe/v2 v2.1.1/go.mod h1:5qg6rpqlwIub0JAiF1UK9IMD6BpPTmvG6yfSgDBs5lg=
|
github.com/spiffe/go-spiffe/v2 v2.1.1/go.mod h1:5qg6rpqlwIub0JAiF1UK9IMD6BpPTmvG6yfSgDBs5lg=
|
||||||
|
github.com/stealthrocket/wasi-go v0.8.0 h1:Hwnv3CUoMhhRyero9vt1vfwaYa9tu/Z5kmCW4WeAmVI=
|
||||||
|
github.com/stealthrocket/wasi-go v0.8.0/go.mod h1:PJ5oVs2E1ciOJnsTnav4nvTtEcJ4D1jUZAewS9pzuZg=
|
||||||
|
github.com/stealthrocket/wazergo v0.19.1 h1:BPrITETPgSFwiytwmToO0MbUC/+RGC39JScz1JmmG6c=
|
||||||
|
github.com/stealthrocket/wazergo v0.19.1/go.mod h1:riI0hxw4ndZA5e6z7PesHg2BtTftcZaMxRcoiGGipTs=
|
||||||
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||||
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||||
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
|
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
|
||||||
|
@ -1086,8 +1090,8 @@ github.com/testcontainers/testcontainers-go v0.30.0 h1:jmn/XS22q4YRrcMwWg0pAwlCl
|
||||||
github.com/testcontainers/testcontainers-go v0.30.0/go.mod h1:K+kHNGiM5zjklKjgTtcrEetF3uhWbMUyqAQoyoh8Pf0=
|
github.com/testcontainers/testcontainers-go v0.30.0/go.mod h1:K+kHNGiM5zjklKjgTtcrEetF3uhWbMUyqAQoyoh8Pf0=
|
||||||
github.com/testcontainers/testcontainers-go/modules/k3s v0.30.0 h1:Mk47J0WcLoY2ig72lPl+/w8GTPYbRCdHoWcPjV2mVr8=
|
github.com/testcontainers/testcontainers-go/modules/k3s v0.30.0 h1:Mk47J0WcLoY2ig72lPl+/w8GTPYbRCdHoWcPjV2mVr8=
|
||||||
github.com/testcontainers/testcontainers-go/modules/k3s v0.30.0/go.mod h1:CNnA3717kbp5wRxz+gU/cAwX6+4+OOispIsjHmKsEWQ=
|
github.com/testcontainers/testcontainers-go/modules/k3s v0.30.0/go.mod h1:CNnA3717kbp5wRxz+gU/cAwX6+4+OOispIsjHmKsEWQ=
|
||||||
github.com/tetratelabs/wazero v1.5.0 h1:Yz3fZHivfDiZFUXnWMPUoiW7s8tC1sjdBtlJn08qYa0=
|
github.com/tetratelabs/wazero v1.7.2 h1:1+z5nXJNwMLPAWaTePFi49SSTL0IMx/i3Fg8Yc25GDc=
|
||||||
github.com/tetratelabs/wazero v1.5.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A=
|
github.com/tetratelabs/wazero v1.7.2/go.mod h1:ytl6Zuh20R/eROuyDaGPkp82O9C/DJfXAwJfQ3X6/7Y=
|
||||||
github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM=
|
github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM=
|
||||||
github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||||
|
@ -1103,6 +1107,8 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
github.com/traefik/grpc-web v0.16.0 h1:eeUWZaFg6ZU0I9dWOYE2D5qkNzRBmXzzuRlxdltascY=
|
github.com/traefik/grpc-web v0.16.0 h1:eeUWZaFg6ZU0I9dWOYE2D5qkNzRBmXzzuRlxdltascY=
|
||||||
github.com/traefik/grpc-web v0.16.0/go.mod h1:2ttniSv7pTgBWIU2HZLokxRfFX3SA60c/DTmQQgVml4=
|
github.com/traefik/grpc-web v0.16.0/go.mod h1:2ttniSv7pTgBWIU2HZLokxRfFX3SA60c/DTmQQgVml4=
|
||||||
|
github.com/traefik/http-wasm-host-go v0.0.0-20240618100324-3c53dcaa1a70 h1:I+oBnV0orhmasb87yaX54tOAfqrV9+yKoQ1Cum5mq8w=
|
||||||
|
github.com/traefik/http-wasm-host-go v0.0.0-20240618100324-3c53dcaa1a70/go.mod h1:zQB3w+df4hryDEqBorGyA1DwPJ86LfKIASNLFuj6CuI=
|
||||||
github.com/traefik/paerser v0.2.0 h1:zqCLGSXoNlcBd+mzqSCLjon/I6phqIjeJL2xFB2ysgQ=
|
github.com/traefik/paerser v0.2.0 h1:zqCLGSXoNlcBd+mzqSCLjon/I6phqIjeJL2xFB2ysgQ=
|
||||||
github.com/traefik/paerser v0.2.0/go.mod h1:afzaVcgF8A+MpTnPG4wBr4whjanCSYA6vK5RwaYVtRc=
|
github.com/traefik/paerser v0.2.0/go.mod h1:afzaVcgF8A+MpTnPG4wBr4whjanCSYA6vK5RwaYVtRc=
|
||||||
github.com/traefik/yaegi v0.16.1 h1:f1De3DVJqIDKmnasUF6MwmWv1dSEEat0wcpXhD2On3E=
|
github.com/traefik/yaegi v0.16.1 h1:f1De3DVJqIDKmnasUF6MwmWv1dSEEat0wcpXhD2On3E=
|
||||||
|
|
|
@ -52,7 +52,7 @@ func NewBuilder(client *Client, plugins map[string]Descriptor, localPlugins map[
|
||||||
|
|
||||||
switch manifest.Type {
|
switch manifest.Type {
|
||||||
case typeMiddleware:
|
case typeMiddleware:
|
||||||
middleware, err := newMiddlewareBuilder(logCtx, client.GoPath(), manifest, desc.ModuleName)
|
middleware, err := newMiddlewareBuilder(logCtx, client.GoPath(), manifest, desc.ModuleName, desc.Settings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ func NewBuilder(client *Client, plugins map[string]Descriptor, localPlugins map[
|
||||||
|
|
||||||
switch manifest.Type {
|
switch manifest.Type {
|
||||||
case typeMiddleware:
|
case typeMiddleware:
|
||||||
middleware, err := newMiddlewareBuilder(logCtx, localGoPath, manifest, desc.ModuleName)
|
middleware, err := newMiddlewareBuilder(logCtx, localGoPath, manifest, desc.ModuleName, desc.Settings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,7 @@ func (b Builder) Build(pName string, config map[string]interface{}, middlewareNa
|
||||||
return nil, fmt.Errorf("unknown plugin type: %s", pName)
|
return nil, fmt.Errorf("unknown plugin type: %s", pName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newMiddlewareBuilder(ctx context.Context, goPath string, manifest *Manifest, moduleName string) (middlewareBuilder, error) {
|
func newMiddlewareBuilder(ctx context.Context, goPath string, manifest *Manifest, moduleName string, settings Settings) (middlewareBuilder, error) {
|
||||||
switch manifest.Runtime {
|
switch manifest.Runtime {
|
||||||
case runtimeWasm:
|
case runtimeWasm:
|
||||||
wasmPath, err := getWasmPath(manifest)
|
wasmPath, err := getWasmPath(manifest)
|
||||||
|
@ -136,7 +136,7 @@ func newMiddlewareBuilder(ctx context.Context, goPath string, manifest *Manifest
|
||||||
return nil, fmt.Errorf("wasm path: %w", err)
|
return nil, fmt.Errorf("wasm path: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return newWasmMiddlewareBuilder(goPath, moduleName, wasmPath), nil
|
return newWasmMiddlewareBuilder(goPath, moduleName, wasmPath, settings)
|
||||||
|
|
||||||
case runtimeYaegi, "":
|
case runtimeYaegi, "":
|
||||||
i, err := newInterpreter(ctx, goPath, manifest.Import)
|
i, err := newInterpreter(ctx, goPath, manifest.Import)
|
||||||
|
|
|
@ -8,20 +8,38 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/http-wasm/http-wasm-host-go/handler"
|
"github.com/http-wasm/http-wasm-host-go/handler"
|
||||||
wasm "github.com/http-wasm/http-wasm-host-go/handler/nethttp"
|
wasm "github.com/http-wasm/http-wasm-host-go/handler/nethttp"
|
||||||
|
"github.com/juliens/wasm-goexport/host"
|
||||||
"github.com/tetratelabs/wazero"
|
"github.com/tetratelabs/wazero"
|
||||||
"github.com/traefik/traefik/v3/pkg/logs"
|
"github.com/traefik/traefik/v3/pkg/logs"
|
||||||
"github.com/traefik/traefik/v3/pkg/middlewares"
|
"github.com/traefik/traefik/v3/pkg/middlewares"
|
||||||
)
|
)
|
||||||
|
|
||||||
type wasmMiddlewareBuilder struct {
|
type wasmMiddlewareBuilder struct {
|
||||||
path string
|
path string
|
||||||
|
cache wazero.CompilationCache
|
||||||
|
settings Settings
|
||||||
}
|
}
|
||||||
|
|
||||||
func newWasmMiddlewareBuilder(goPath string, moduleName, wasmPath string) *wasmMiddlewareBuilder {
|
func newWasmMiddlewareBuilder(goPath, moduleName, wasmPath string, settings Settings) (*wasmMiddlewareBuilder, error) {
|
||||||
return &wasmMiddlewareBuilder{path: filepath.Join(goPath, "src", moduleName, wasmPath)}
|
ctx := context.Background()
|
||||||
|
path := filepath.Join(goPath, "src", moduleName, wasmPath)
|
||||||
|
cache := wazero.NewCompilationCache()
|
||||||
|
|
||||||
|
code, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("loading Wasm binary: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rt := wazero.NewRuntimeWithConfig(ctx, wazero.NewRuntimeConfig().WithCompilationCache(cache))
|
||||||
|
if _, err = rt.CompileModule(ctx, code); err != nil {
|
||||||
|
return nil, fmt.Errorf("compiling guest module: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &wasmMiddlewareBuilder{path: path, cache: cache, settings: settings}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b wasmMiddlewareBuilder) newMiddleware(config map[string]interface{}, middlewareName string) (pluginMiddleware, error) {
|
func (b wasmMiddlewareBuilder) newMiddleware(config map[string]interface{}, middlewareName string) (pluginMiddleware, error) {
|
||||||
|
@ -33,15 +51,64 @@ func (b wasmMiddlewareBuilder) newMiddleware(config map[string]interface{}, midd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b wasmMiddlewareBuilder) newHandler(ctx context.Context, next http.Handler, cfg reflect.Value, middlewareName string) (http.Handler, error) {
|
func (b wasmMiddlewareBuilder) newHandler(ctx context.Context, next http.Handler, cfg reflect.Value, middlewareName string) (http.Handler, error) {
|
||||||
|
h, applyCtx, err := b.buildMiddleware(ctx, next, cfg, middlewareName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("building Wasm middleware: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
h.ServeHTTP(rw, req.WithContext(applyCtx(req.Context())))
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *wasmMiddlewareBuilder) buildMiddleware(ctx context.Context, next http.Handler, cfg reflect.Value, middlewareName string) (http.Handler, func(ctx context.Context) context.Context, error) {
|
||||||
code, err := os.ReadFile(b.path)
|
code, err := os.ReadFile(b.path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("loading Wasm binary: %w", err)
|
return nil, nil, fmt.Errorf("loading binary: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rt := host.NewRuntime(wazero.NewRuntimeWithConfig(ctx, wazero.NewRuntimeConfig().WithCompilationCache(b.cache)))
|
||||||
|
|
||||||
|
guestModule, err := rt.CompileModule(ctx, code)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("compiling guest module: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
applyCtx, err := InstantiateHost(ctx, rt, guestModule, b.settings)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("instantiating host module: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
logger := middlewares.GetLogger(ctx, middlewareName, "wasm")
|
logger := middlewares.GetLogger(ctx, middlewareName, "wasm")
|
||||||
|
|
||||||
|
config := wazero.NewModuleConfig().WithSysWalltime()
|
||||||
|
for _, env := range b.settings.Envs {
|
||||||
|
config.WithEnv(env, os.Getenv(env))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(b.settings.Mounts) > 0 {
|
||||||
|
fsConfig := wazero.NewFSConfig()
|
||||||
|
for _, mount := range b.settings.Mounts {
|
||||||
|
withDir := fsConfig.WithDirMount
|
||||||
|
prefix, readOnly := strings.CutSuffix(mount, ":ro")
|
||||||
|
if readOnly {
|
||||||
|
withDir = fsConfig.WithReadOnlyDirMount
|
||||||
|
}
|
||||||
|
parts := strings.Split(prefix, ":")
|
||||||
|
switch {
|
||||||
|
case len(parts) == 1:
|
||||||
|
withDir(parts[0], parts[0])
|
||||||
|
case len(parts) == 2:
|
||||||
|
withDir(parts[0], parts[1])
|
||||||
|
default:
|
||||||
|
return nil, nil, fmt.Errorf("invalid directory %q", mount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
config.WithFSConfig(fsConfig)
|
||||||
|
}
|
||||||
|
|
||||||
opts := []handler.Option{
|
opts := []handler.Option{
|
||||||
handler.ModuleConfig(wazero.NewModuleConfig().WithSysWalltime()),
|
handler.ModuleConfig(config),
|
||||||
handler.Logger(logs.NewWasmLogger(logger)),
|
handler.Logger(logs.NewWasmLogger(logger)),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,23 +116,27 @@ func (b wasmMiddlewareBuilder) newHandler(ctx context.Context, next http.Handler
|
||||||
if i != nil {
|
if i != nil {
|
||||||
config, ok := i.(map[string]interface{})
|
config, ok := i.(map[string]interface{})
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("could not type assert config: %T", i)
|
return nil, nil, fmt.Errorf("could not type assert config: %T", i)
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := json.Marshal(config)
|
data, err := json.Marshal(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("marshaling config: %w", err)
|
return nil, nil, fmt.Errorf("marshaling config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
opts = append(opts, handler.GuestConfig(data))
|
opts = append(opts, handler.GuestConfig(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
mw, err := wasm.NewMiddleware(context.Background(), code, opts...)
|
opts = append(opts, handler.Runtime(func(ctx context.Context) (wazero.Runtime, error) {
|
||||||
|
return rt, nil
|
||||||
|
}))
|
||||||
|
|
||||||
|
mw, err := wasm.NewMiddleware(applyCtx(ctx), code, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, fmt.Errorf("creating middleware: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return mw.NewHandler(ctx, next), nil
|
return mw.NewHandler(ctx, next), applyCtx, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// WasmMiddleware is an HTTP handler plugin wrapper.
|
// WasmMiddleware is an HTTP handler plugin wrapper.
|
||||||
|
|
|
@ -10,6 +10,11 @@ const (
|
||||||
typeProvider = "provider"
|
typeProvider = "provider"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Settings struct {
|
||||||
|
Envs []string `description:"Environment variables to forward to the wasm guest." json:"envs,omitempty" toml:"envs,omitempty" yaml:"envs,omitempty"`
|
||||||
|
Mounts []string `description:"Directory to mount to the wasm guest." json:"mounts,omitempty" toml:"mounts,omitempty" yaml:"mounts,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// Descriptor The static part of a plugin configuration.
|
// Descriptor The static part of a plugin configuration.
|
||||||
type Descriptor struct {
|
type Descriptor struct {
|
||||||
// ModuleName (required)
|
// ModuleName (required)
|
||||||
|
@ -17,12 +22,18 @@ type Descriptor struct {
|
||||||
|
|
||||||
// Version (required)
|
// Version (required)
|
||||||
Version string `description:"plugin's version." json:"version,omitempty" toml:"version,omitempty" yaml:"version,omitempty" export:"true"`
|
Version string `description:"plugin's version." json:"version,omitempty" toml:"version,omitempty" yaml:"version,omitempty" export:"true"`
|
||||||
|
|
||||||
|
// Settings (optional)
|
||||||
|
Settings Settings `description:"Plugin's settings (works only for wasm plugins)." json:"settings,omitempty" toml:"settings,omitempty" yaml:"settings,omitempty" export:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// LocalDescriptor The static part of a local plugin configuration.
|
// LocalDescriptor The static part of a local plugin configuration.
|
||||||
type LocalDescriptor struct {
|
type LocalDescriptor struct {
|
||||||
// ModuleName (required)
|
// ModuleName (required)
|
||||||
ModuleName string `description:"plugin's module name." json:"moduleName,omitempty" toml:"moduleName,omitempty" yaml:"moduleName,omitempty" export:"true"`
|
ModuleName string `description:"Plugin's module name." json:"moduleName,omitempty" toml:"moduleName,omitempty" yaml:"moduleName,omitempty" export:"true"`
|
||||||
|
|
||||||
|
// Settings (optional)
|
||||||
|
Settings Settings `description:"Plugin's settings (works only for wasm plugins)." json:"settings,omitempty" toml:"settings,omitempty" yaml:"settings,omitempty" export:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manifest The plugin manifest.
|
// Manifest The plugin manifest.
|
||||||
|
|
59
pkg/plugins/wasip.go
Normal file
59
pkg/plugins/wasip.go
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
//go:build !windows
|
||||||
|
|
||||||
|
package plugins
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/stealthrocket/wasi-go/imports"
|
||||||
|
wazergo_wasip1 "github.com/stealthrocket/wasi-go/imports/wasi_snapshot_preview1"
|
||||||
|
"github.com/stealthrocket/wazergo"
|
||||||
|
"github.com/tetratelabs/wazero"
|
||||||
|
wazero_wasip1 "github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ContextApplier func(ctx context.Context) context.Context
|
||||||
|
|
||||||
|
// InstantiateHost instantiates the Host module according to the guest requirements (for now only SocketExtensions).
|
||||||
|
func InstantiateHost(ctx context.Context, runtime wazero.Runtime, mod wazero.CompiledModule, settings Settings) (ContextApplier, error) {
|
||||||
|
if extension := imports.DetectSocketsExtension(mod); extension != nil {
|
||||||
|
envs := []string{}
|
||||||
|
for _, env := range settings.Envs {
|
||||||
|
envs = append(envs, fmt.Sprintf("%s=%s", env, os.Getenv(env)))
|
||||||
|
}
|
||||||
|
|
||||||
|
builder := imports.NewBuilder().WithSocketsExtension("auto", mod)
|
||||||
|
if len(envs) > 0 {
|
||||||
|
builder.WithEnv(envs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(settings.Mounts) > 0 {
|
||||||
|
builder.WithDirs(settings.Mounts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, sys, err := builder.Instantiate(ctx, runtime)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
inst, err := wazergo.Instantiate(ctx, runtime, wazergo_wasip1.NewHostModule(*extension), wazergo_wasip1.WithWASI(sys))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("wazergo instantiation: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return func(ctx context.Context) context.Context {
|
||||||
|
return wazergo.WithModuleInstance(ctx, inst)
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := wazero_wasip1.Instantiate(ctx, runtime)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("wazero instantiation: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return func(ctx context.Context) context.Context {
|
||||||
|
return ctx
|
||||||
|
}, nil
|
||||||
|
}
|
18
pkg/plugins/wasip_windows.go
Normal file
18
pkg/plugins/wasip_windows.go
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package plugins
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/tetratelabs/wazero"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ContextApplier func(ctx context.Context) context.Context
|
||||||
|
|
||||||
|
// InstantiateHost instantiates the Host module.
|
||||||
|
func InstantiateHost(ctx context.Context, runtime wazero.Runtime, mod wazero.CompiledModule, settings Settings) (ContextApplier, error) {
|
||||||
|
return func(ctx context.Context) context.Context {
|
||||||
|
return ctx
|
||||||
|
}, nil
|
||||||
|
}
|
|
@ -907,18 +907,34 @@ func TestDo_staticConfiguration(t *testing.T) {
|
||||||
"Descriptor0": {
|
"Descriptor0": {
|
||||||
ModuleName: "foobar",
|
ModuleName: "foobar",
|
||||||
Version: "foobar",
|
Version: "foobar",
|
||||||
|
Settings: plugins.Settings{
|
||||||
|
Envs: []string{"a", "b"},
|
||||||
|
Mounts: []string{"a", "b"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"Descriptor1": {
|
"Descriptor1": {
|
||||||
ModuleName: "foobar",
|
ModuleName: "foobar",
|
||||||
Version: "foobar",
|
Version: "foobar",
|
||||||
|
Settings: plugins.Settings{
|
||||||
|
Envs: []string{"a", "b"},
|
||||||
|
Mounts: []string{"a", "b"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
LocalPlugins: map[string]plugins.LocalDescriptor{
|
LocalPlugins: map[string]plugins.LocalDescriptor{
|
||||||
"Descriptor0": {
|
"Descriptor0": {
|
||||||
ModuleName: "foobar",
|
ModuleName: "foobar",
|
||||||
|
Settings: plugins.Settings{
|
||||||
|
Envs: []string{"a", "b"},
|
||||||
|
Mounts: []string{"a", "b"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"Descriptor1": {
|
"Descriptor1": {
|
||||||
ModuleName: "foobar",
|
ModuleName: "foobar",
|
||||||
|
Settings: plugins.Settings{
|
||||||
|
Envs: []string{"a", "b"},
|
||||||
|
Mounts: []string{"a", "b"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -388,19 +388,59 @@
|
||||||
"plugins": {
|
"plugins": {
|
||||||
"Descriptor0": {
|
"Descriptor0": {
|
||||||
"moduleName": "foobar",
|
"moduleName": "foobar",
|
||||||
"version": "foobar"
|
"version": "foobar",
|
||||||
|
"settings": {
|
||||||
|
"envs": [
|
||||||
|
"xxxx",
|
||||||
|
"xxxx"
|
||||||
|
],
|
||||||
|
"mounts": [
|
||||||
|
"xxxx",
|
||||||
|
"xxxx"
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"Descriptor1": {
|
"Descriptor1": {
|
||||||
"moduleName": "foobar",
|
"moduleName": "foobar",
|
||||||
"version": "foobar"
|
"version": "foobar",
|
||||||
|
"settings": {
|
||||||
|
"envs": [
|
||||||
|
"xxxx",
|
||||||
|
"xxxx"
|
||||||
|
],
|
||||||
|
"mounts": [
|
||||||
|
"xxxx",
|
||||||
|
"xxxx"
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"localPlugins": {
|
"localPlugins": {
|
||||||
"Descriptor0": {
|
"Descriptor0": {
|
||||||
"moduleName": "foobar"
|
"moduleName": "foobar",
|
||||||
|
"settings": {
|
||||||
|
"envs": [
|
||||||
|
"xxxx",
|
||||||
|
"xxxx"
|
||||||
|
],
|
||||||
|
"mounts": [
|
||||||
|
"xxxx",
|
||||||
|
"xxxx"
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"Descriptor1": {
|
"Descriptor1": {
|
||||||
"moduleName": "foobar"
|
"moduleName": "foobar",
|
||||||
|
"settings": {
|
||||||
|
"envs": [
|
||||||
|
"xxxx",
|
||||||
|
"xxxx"
|
||||||
|
],
|
||||||
|
"mounts": [
|
||||||
|
"xxxx",
|
||||||
|
"xxxx"
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue