consul/agent/envoyextensions/builtin/wasm/wasm_test.go

679 lines
22 KiB
Go
Raw Normal View History

2023-04-06 21:12:07 +00:00
// Copyright (c) HashiCorp, Inc.
[COMPLIANCE] License changes (#18443) * Adding explicit MPL license for sub-package This directory and its subdirectories (packages) contain files licensed with the MPLv2 `LICENSE` file in this directory and are intentionally licensed separately from the BSL `LICENSE` file at the root of this repository. * Adding explicit MPL license for sub-package This directory and its subdirectories (packages) contain files licensed with the MPLv2 `LICENSE` file in this directory and are intentionally licensed separately from the BSL `LICENSE` file at the root of this repository. * Updating the license from MPL to Business Source License Going forward, this project will be licensed under the Business Source License v1.1. Please see our blog post for more details at <Blog URL>, FAQ at www.hashicorp.com/licensing-faq, and details of the license at www.hashicorp.com/bsl. * add missing license headers * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 --------- Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com>
2023-08-11 13:12:13 +00:00
// SPDX-License-Identifier: BUSL-1.1
2023-04-06 21:12:07 +00:00
package wasm
import (
"encoding/json"
"fmt"
"net/url"
"strings"
"testing"
"time"
envoy_core_v3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
envoy_listener_v3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
envoy_http_wasm_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/wasm/v3"
envoy_http_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
envoy_network_wasm_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/wasm/v3"
2023-04-06 21:12:07 +00:00
envoy_wasm_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/wasm/v3"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/anypb"
"google.golang.org/protobuf/types/known/durationpb"
"google.golang.org/protobuf/types/known/wrapperspb"
"github.com/hashicorp/consul/acl"
"github.com/hashicorp/consul/api"
"github.com/hashicorp/consul/envoyextensions/extensioncommon"
"github.com/hashicorp/consul/proto/private/prototest"
)
func TestHttpWasmExtension(t *testing.T) {
t.Parallel()
cases := map[string]struct {
extName string
canApply bool
cfg func(string, bool) *testWasmConfig
rtCfg func(string, bool) *extensioncommon.RuntimeConfig
isInboundFilter bool
errStr string
debug bool
2023-04-06 21:12:07 +00:00
}{
"remote file": {
extName: api.BuiltinWasmExtension,
canApply: true,
cfg: func(proto string, ent bool) *testWasmConfig { return makeTestWasmConfig(proto, ent) },
rtCfg: func(proto string, ent bool) *extensioncommon.RuntimeConfig { return makeTestRuntimeConfig(proto, ent) },
isInboundFilter: true,
2023-04-06 21:12:07 +00:00
},
"local file": {
extName: api.BuiltinWasmExtension,
canApply: true,
cfg: func(proto string, ent bool) *testWasmConfig {
cfg := newTestWasmConfig(proto, ent)
2023-04-06 21:12:07 +00:00
cfg.ListenerType = "inbound"
cfg.PluginConfig.VmConfig.Code.Local.Filename = "plugin.wasm"
return cfg
2023-04-06 21:12:07 +00:00
},
rtCfg: func(proto string, ent bool) *extensioncommon.RuntimeConfig { return makeTestRuntimeConfig(proto, ent) },
isInboundFilter: true,
},
"inbound filters ignored": {
extName: api.BuiltinWasmExtension,
canApply: true,
cfg: func(proto string, ent bool) *testWasmConfig { return makeTestWasmConfig(proto, ent) },
rtCfg: func(proto string, ent bool) *extensioncommon.RuntimeConfig { return makeTestRuntimeConfig(proto, ent) },
isInboundFilter: false,
2023-04-06 21:12:07 +00:00
},
"no cluster for remote file": {
extName: api.BuiltinWasmExtension,
canApply: true,
cfg: func(proto string, ent bool) *testWasmConfig { return makeTestWasmConfig(proto, ent) },
rtCfg: func(proto string, ent bool) *extensioncommon.RuntimeConfig {
rt := makeTestRuntimeConfig(proto, ent)
rt.Upstreams = nil
2023-04-06 21:12:07 +00:00
return rt
},
isInboundFilter: true,
errStr: "no upstream found for remote service",
},
"protocol mismatch": {
extName: api.BuiltinWasmExtension,
canApply: false,
cfg: func(proto string, ent bool) *testWasmConfig { return makeTestWasmConfig(proto, ent) },
rtCfg: func(proto string, ent bool) *extensioncommon.RuntimeConfig {
rt := makeTestRuntimeConfig(proto, ent)
switch proto {
case "http":
rt.Protocol = "tcp"
case "tcp":
rt.Protocol = "http"
}
return rt
},
isInboundFilter: true,
2023-04-06 21:12:07 +00:00
},
}
for _, enterprise := range []bool{false, true} {
for _, protocol := range []string{"tcp", "http"} {
for name, c := range cases {
c := c
t.Run(fmt.Sprintf("%s_%s_ent_%t", name, protocol, enterprise), func(t *testing.T) {
cfg := c.cfg(protocol, enterprise)
rtCfg := c.rtCfg(protocol, enterprise)
rtCfg.EnvoyExtension = api.EnvoyExtension{
Name: c.extName,
Arguments: cfg.toMap(t),
}
2023-04-06 21:12:07 +00:00
w, err := construct(rtCfg.EnvoyExtension)
require.NoError(t, err)
require.Equal(t, c.canApply, w.CanApply(rtCfg))
if !c.canApply {
return
}
2023-04-06 21:12:07 +00:00
var inputFilters []*envoy_listener_v3.Filter
if protocol == "http" {
inputFilters = append(inputFilters, makeHttpConMgr(t, makeTestHttpFilters()))
} else {
inputFilters = makeTestFilters()
}
2023-04-06 21:12:07 +00:00
obsFilters, err := w.PatchFilters(rtCfg, inputFilters, c.isInboundFilter)
if c.errStr == "" {
require.NoError(t, err)
2023-04-06 21:12:07 +00:00
expFilters := cfg.expFilters(t)
if !cfg.matchesDirection(c.isInboundFilter) {
// If the listener type does not match the filter direction then the
// filter should not be applied and the output should match the input.
expFilters = inputFilters
}
2023-04-06 21:12:07 +00:00
if c.debug {
t.Logf("cfg =\n%s\n\n", cfg.toJSON(t))
require.Equal(t, len(expFilters), len(obsFilters))
for idx, expFilter := range expFilters {
t.Logf("expFilterJSON[%d] =\n%s\n\n", idx, prototest.ProtoToJSON(t, expFilter))
t.Logf("obsfilterJSON[%d] =\n%s\n\n", idx, prototest.ProtoToJSON(t, obsFilters[idx]))
}
}
2023-04-06 21:12:07 +00:00
prototest.AssertDeepEqual(t, expFilters, obsFilters)
} else {
require.Error(t, err)
require.Contains(t, err.Error(), c.errStr)
2023-04-06 21:12:07 +00:00
}
})
}
2023-04-06 21:12:07 +00:00
}
}
}
func TestWasmConstructor(t *testing.T) {
t.Parallel()
cases := map[string]struct {
name string
args func(string, bool) map[string]any
2023-04-06 21:12:07 +00:00
errStr string
}{
"with no arguments": {
name: api.BuiltinWasmExtension,
args: func(_ string, _ bool) map[string]any { return nil },
2023-04-06 21:12:07 +00:00
errStr: "VmConfig.Code must provide exactly one of Local or Remote data source",
},
"invalid protocol": {
name: api.BuiltinWasmExtension,
args: func(proto string, ent bool) map[string]any {
cfg := newTestWasmConfig(proto, ent)
2023-04-06 21:12:07 +00:00
cfg.Protocol = "invalid"
return cfg.toMap(t)
},
errStr: `unsupported Protocol "invalid", expected "tcp" or "http"`,
},
"invalid proxy type": {
name: api.BuiltinWasmExtension,
args: func(proto string, ent bool) map[string]any {
cfg := newTestWasmConfig(proto, ent)
2023-04-06 21:12:07 +00:00
cfg.ProxyType = "invalid"
return cfg.toMap(t)
},
errStr: "unsupported ProxyType",
},
"invalid listener type": {
name: api.BuiltinWasmExtension,
args: func(proto string, ent bool) map[string]any {
cfg := newTestWasmConfig(proto, ent)
2023-04-06 21:12:07 +00:00
cfg.ListenerType = "invalid"
return cfg.toMap(t)
},
errStr: `unsupported ListenerType "invalid", expected "inbound" or "outbound"`,
},
"invalid runtime": {
name: api.BuiltinWasmExtension,
args: func(proto string, ent bool) map[string]any {
cfg := newTestWasmConfig(proto, ent)
2023-04-06 21:12:07 +00:00
cfg.PluginConfig.VmConfig.Runtime = "invalid"
return cfg.toMap(t)
},
errStr: "unsupported runtime",
},
"both local and remote files": {
name: api.BuiltinWasmExtension,
args: func(proto string, ent bool) map[string]any {
cfg := newTestWasmConfig(proto, ent)
2023-04-06 21:12:07 +00:00
cfg.PluginConfig.VmConfig.Code.Local.Filename = "plugin.wasm"
cfg.PluginConfig.VmConfig.Code.Remote.HttpURI.Service.Name = "file-server"
cfg.PluginConfig.VmConfig.Code.Remote.HttpURI.URI = "http://file-server/plugin.wasm"
return cfg.toMap(t)
},
errStr: "VmConfig.Code must provide exactly one of Local or Remote data source",
},
"service and uri required for remote files": {
name: api.BuiltinWasmExtension,
args: func(proto string, ent bool) map[string]any {
cfg := newTestWasmConfig(proto, ent)
2023-04-06 21:12:07 +00:00
cfg.PluginConfig.VmConfig.Code.Remote.HttpURI.Service.Name = "file-server"
return cfg.toMap(t)
},
errStr: "both Service and URI are required for Remote data sources",
},
"no sha for remote file": {
name: api.BuiltinWasmExtension,
args: func(proto string, ent bool) map[string]any {
cfg := newTestWasmConfig(proto, ent)
2023-04-06 21:12:07 +00:00
cfg.PluginConfig.VmConfig.Code.Remote.HttpURI.Service.Name = "file-server"
cfg.PluginConfig.VmConfig.Code.Remote.HttpURI.URI = "http://file-server/plugin.wasm"
return cfg.toMap(t)
},
errStr: "SHA256 checksum is required for Remote data sources",
},
"invalid url for remote file": {
name: api.BuiltinWasmExtension,
args: func(proto string, ent bool) map[string]any {
cfg := newTestWasmConfig(proto, ent)
2023-04-06 21:12:07 +00:00
cfg.PluginConfig.VmConfig.Code.Remote.HttpURI.Service.Name = "file-server"
cfg.PluginConfig.VmConfig.Code.Remote.HttpURI.URI = "://bogus.url.com/error"
return cfg.toMap(t)
},
errStr: `invalid HttpURI.URI: parse "://bogus.url.com/error": missing protocol scheme`,
},
"decoding error": {
name: api.BuiltinWasmExtension,
args: func(proto string, ent bool) map[string]any {
a := makeTestWasmConfig(proto, ent).toMap(t)
2023-04-06 21:12:07 +00:00
setField(a, "PluginConfig.VmConfig.Code.Remote.RetryPolicy.RetryBackOff.BaseInterval", 1000)
return a
},
errStr: "got unconvertible type",
},
"invalid http timeout": {
name: api.BuiltinWasmExtension,
args: func(proto string, ent bool) map[string]any {
cfg := newTestWasmConfig(proto, ent)
2023-04-06 21:12:07 +00:00
cfg.PluginConfig.VmConfig.Code.Remote.HttpURI.Timeout = "invalid"
return cfg.toMap(t)
},
errStr: `failed to parse HttpURI.Timeout "invalid" as a duration`,
},
"invalid num retries": {
name: api.BuiltinWasmExtension,
args: func(proto string, ent bool) map[string]any {
cfg := newTestWasmConfig(proto, ent)
2023-04-06 21:12:07 +00:00
cfg.PluginConfig.VmConfig.Code.Remote.RetryPolicy.NumRetries = -1
return cfg.toMap(t)
},
errStr: "RetryPolicy.NumRetries must be greater than or equal to 0",
},
"invalid base interval": {
name: api.BuiltinWasmExtension,
args: func(proto string, ent bool) map[string]any {
cfg := newTestWasmConfig(proto, ent)
2023-04-06 21:12:07 +00:00
cfg.PluginConfig.VmConfig.Code.Remote.RetryPolicy.RetryBackOff.BaseInterval = "0s"
return cfg.toMap(t)
},
errStr: `RetryBackOff.BaseInterval "0s" must be greater than zero and less than or equal to RetryBackOff.MaxInterval`,
},
"invalid max interval": {
name: api.BuiltinWasmExtension,
args: func(proto string, ent bool) map[string]any {
cfg := newTestWasmConfig(proto, ent)
2023-04-06 21:12:07 +00:00
cfg.PluginConfig.VmConfig.Code.Remote.RetryPolicy.RetryBackOff.BaseInterval = "10s"
cfg.PluginConfig.VmConfig.Code.Remote.RetryPolicy.RetryBackOff.MaxInterval = "5s"
return cfg.toMap(t)
},
errStr: `RetryBackOff.MaxInterval "5s" must be greater than or equal to RetryBackOff.BaseInterval "10s"`,
},
"invalid base interval duration": {
name: api.BuiltinWasmExtension,
args: func(proto string, ent bool) map[string]any {
cfg := newTestWasmConfig(proto, ent)
2023-04-06 21:12:07 +00:00
cfg.PluginConfig.VmConfig.Code.Remote.RetryPolicy.RetryBackOff.BaseInterval = "invalid"
return cfg.toMap(t)
},
errStr: `failed to parse RetryBackOff.BaseInterval "invalid"`,
},
"invalid max interval duration": {
name: api.BuiltinWasmExtension,
args: func(proto string, ent bool) map[string]any {
cfg := newTestWasmConfig(proto, ent)
2023-04-06 21:12:07 +00:00
cfg.PluginConfig.VmConfig.Code.Remote.RetryPolicy.RetryBackOff.MaxInterval = "invalid"
return cfg.toMap(t)
},
errStr: `failed to parse RetryBackOff.MaxInterval "invalid"`,
},
"invalid extension name": {
name: "invalid",
args: func(proto string, ent bool) map[string]any { return newTestWasmConfig(proto, ent).toMap(t) },
2023-04-06 21:12:07 +00:00
errStr: `expected extension name "builtin/wasm" but got "invalid"`,
},
"valid configuration": {
name: api.BuiltinWasmExtension,
args: func(proto string, ent bool) map[string]any { return makeTestWasmConfig(proto, ent).toMap(t) },
2023-04-06 21:12:07 +00:00
},
}
for _, enterprise := range []bool{false, true} {
for _, protocol := range []string{"tcp", "http"} {
for name, c := range cases {
c := c
t.Run(fmt.Sprintf("%s_%s_ent_%t", name, protocol, enterprise), func(t *testing.T) {
svc := api.CompoundServiceName{Name: "svc"}
ext := extensioncommon.RuntimeConfig{
ServiceName: svc,
EnvoyExtension: api.EnvoyExtension{
Name: c.name,
Arguments: c.args(protocol, enterprise),
},
}
2023-04-06 21:12:07 +00:00
e, err := Constructor(ext.EnvoyExtension)
2023-04-06 21:12:07 +00:00
if c.errStr == "" {
require.NoError(t, err)
require.NotNil(t, e)
} else {
require.Error(t, err)
require.Contains(t, err.Error(), c.errStr)
}
})
}
2023-04-06 21:12:07 +00:00
}
}
}
type testWasmConfig struct {
Required bool
Protocol string
ProxyType string
ListenerType string
PluginConfig struct {
Name string
RootID string
VmConfig struct {
VmID string
Runtime string
Code struct {
Local struct {
Filename string
}
Remote struct {
HttpURI struct {
Service api.CompoundServiceName
URI string
Timeout string
}
SHA256 string
RetryPolicy struct {
RetryBackOff struct {
BaseInterval string
MaxInterval string
}
NumRetries int
}
}
}
Configuration string
EnvironmentVariables struct {
HostEnvKeys []string
KeyValues map[string]string
}
}
Configuration string
CapabilityRestrictionConfiguration struct {
AllowedCapabilities map[string]any
}
}
}
func (c testWasmConfig) toMap(t *testing.T) map[string]any {
t.Helper()
var m map[string]any
require.NoError(t, json.Unmarshal(c.toJSON(t), &m))
return m
}
func (c testWasmConfig) toJSON(t *testing.T) []byte {
t.Helper()
b, err := json.MarshalIndent(c, "", " ")
require.NoError(t, err)
return b
}
func (cfg testWasmConfig) toWasmPluginConfig(t *testing.T) *envoy_wasm_v3.PluginConfig {
2023-04-06 21:12:07 +00:00
t.Helper()
var code *envoy_core_v3.AsyncDataSource
if cfg.PluginConfig.VmConfig.Code.Local.Filename != "" {
code = &envoy_core_v3.AsyncDataSource{
Specifier: &envoy_core_v3.AsyncDataSource_Local{
Local: &envoy_core_v3.DataSource{
Specifier: &envoy_core_v3.DataSource_Filename{
Filename: cfg.PluginConfig.VmConfig.Code.Local.Filename,
},
},
},
}
} else {
cluster, err := url.Parse(cfg.PluginConfig.VmConfig.Code.Remote.HttpURI.URI)
require.NoError(t, err)
timeout, err := time.ParseDuration(cfg.PluginConfig.VmConfig.Code.Remote.HttpURI.Timeout)
require.NoError(t, err)
baseInterval, err := time.ParseDuration(cfg.PluginConfig.VmConfig.Code.Remote.RetryPolicy.RetryBackOff.BaseInterval)
require.NoError(t, err)
maxInterval, err := time.ParseDuration(cfg.PluginConfig.VmConfig.Code.Remote.RetryPolicy.RetryBackOff.MaxInterval)
require.NoError(t, err)
code = &envoy_core_v3.AsyncDataSource{
Specifier: &envoy_core_v3.AsyncDataSource_Remote{
Remote: &envoy_core_v3.RemoteDataSource{
Sha256: cfg.PluginConfig.VmConfig.Code.Remote.SHA256,
HttpUri: &envoy_core_v3.HttpUri{
Uri: cfg.PluginConfig.VmConfig.Code.Remote.HttpURI.URI,
Timeout: &durationpb.Duration{Seconds: int64(timeout.Seconds())},
HttpUpstreamType: &envoy_core_v3.HttpUri_Cluster{
Cluster: cluster.Host,
},
},
RetryPolicy: &envoy_core_v3.RetryPolicy{
RetryBackOff: &envoy_core_v3.BackoffStrategy{
BaseInterval: &durationpb.Duration{Seconds: int64(baseInterval.Seconds())},
MaxInterval: &durationpb.Duration{Seconds: int64(maxInterval.Seconds())},
},
NumRetries: wrapperspb.UInt32(uint32(cfg.PluginConfig.VmConfig.Code.Remote.RetryPolicy.NumRetries)),
},
},
},
}
}
var capConfig *envoy_wasm_v3.CapabilityRestrictionConfig
if len(cfg.PluginConfig.CapabilityRestrictionConfiguration.AllowedCapabilities) > 0 {
caps := make(map[string]*envoy_wasm_v3.SanitizationConfig)
for cap := range cfg.PluginConfig.CapabilityRestrictionConfiguration.AllowedCapabilities {
caps[cap] = &envoy_wasm_v3.SanitizationConfig{}
}
capConfig = &envoy_wasm_v3.CapabilityRestrictionConfig{AllowedCapabilities: caps}
}
var vmConfiguration *anypb.Any
if cfg.PluginConfig.VmConfig.Configuration != "" {
vmConfiguration = makeAny(t, wrapperspb.String(cfg.PluginConfig.VmConfig.Configuration))
}
var envVars *envoy_wasm_v3.EnvironmentVariables
if len(cfg.PluginConfig.VmConfig.EnvironmentVariables.HostEnvKeys) > 0 ||
len(cfg.PluginConfig.VmConfig.EnvironmentVariables.KeyValues) > 0 {
envVars = &envoy_wasm_v3.EnvironmentVariables{
HostEnvKeys: cfg.PluginConfig.VmConfig.EnvironmentVariables.HostEnvKeys,
KeyValues: cfg.PluginConfig.VmConfig.EnvironmentVariables.KeyValues,
}
}
var pluginConfiguration *anypb.Any
if cfg.PluginConfig.Configuration != "" {
pluginConfiguration = makeAny(t, wrapperspb.String(cfg.PluginConfig.Configuration))
}
rt := cfg.PluginConfig.VmConfig.Runtime
if rt == "" {
rt = supportedRuntimes[0]
}
return &envoy_wasm_v3.PluginConfig{
Name: cfg.PluginConfig.Name,
RootId: cfg.PluginConfig.RootID,
Vm: &envoy_wasm_v3.PluginConfig_VmConfig{
VmConfig: &envoy_wasm_v3.VmConfig{
VmId: cfg.PluginConfig.VmConfig.VmID,
Runtime: fmt.Sprintf("envoy.wasm.runtime.%s", rt),
Code: code,
Configuration: vmConfiguration,
EnvironmentVariables: envVars,
},
},
Configuration: pluginConfiguration,
FailOpen: !cfg.Required,
CapabilityRestrictionConfig: capConfig,
}
}
func (cfg testWasmConfig) toHttpFilter(t *testing.T) *envoy_http_v3.HttpFilter {
return &envoy_http_v3.HttpFilter{
Name: "envoy.filters.http.wasm",
ConfigType: &envoy_http_v3.HttpFilter_TypedConfig{
TypedConfig: makeAny(t,
&envoy_http_wasm_v3.Wasm{
Config: cfg.toWasmPluginConfig(t),
}),
},
}
}
func (cfg testWasmConfig) toNetworkFilter(t *testing.T) *envoy_listener_v3.Filter {
return &envoy_listener_v3.Filter{
Name: "envoy.filters.network.wasm",
ConfigType: &envoy_listener_v3.Filter_TypedConfig{
TypedConfig: makeAny(t,
&envoy_network_wasm_v3.Wasm{
Config: cfg.toWasmPluginConfig(t),
}),
},
}
}
func (cfg testWasmConfig) expFilters(t *testing.T) []*envoy_listener_v3.Filter {
if cfg.Protocol == "http" {
return []*envoy_listener_v3.Filter{makeHttpConMgr(t, cfg.expHttpFilters(t))}
} else {
return cfg.expNetworkFilters(t)
}
}
func (cfg testWasmConfig) expHttpFilters(t *testing.T) []*envoy_http_v3.HttpFilter {
return []*envoy_http_v3.HttpFilter{
{Name: "one"},
{Name: "two"},
cfg.toHttpFilter(t),
{Name: "envoy.filters.http.router"},
{Name: "three"},
}
}
func (cfg testWasmConfig) expNetworkFilters(t *testing.T) []*envoy_listener_v3.Filter {
return []*envoy_listener_v3.Filter{
{Name: "one"},
{Name: "two"},
cfg.toNetworkFilter(t),
{Name: "envoy.filters.network.tcp_proxy"},
{Name: "three"},
}
}
func (cfg testWasmConfig) matchesDirection(isInbound bool) bool {
return (isInbound && cfg.ListenerType == "inbound") ||
(!isInbound && cfg.ListenerType == "outbound")
}
2023-04-06 21:12:07 +00:00
func makeAny(t *testing.T, m proto.Message) *anypb.Any {
t.Helper()
v, err := anypb.New(m)
require.NoError(t, err)
return v
}
func makeHttpConMgr(t *testing.T, filters []*envoy_http_v3.HttpFilter) *envoy_listener_v3.Filter {
t.Helper()
return &envoy_listener_v3.Filter{
Name: "envoy.filters.network.http_connection_manager",
ConfigType: &envoy_listener_v3.Filter_TypedConfig{
TypedConfig: makeAny(t, &envoy_http_v3.HttpConnectionManager{
HttpFilters: filters,
}),
},
}
}
func makeTestFilters() []*envoy_listener_v3.Filter {
return []*envoy_listener_v3.Filter{
{Name: "one"},
{Name: "two"},
{Name: "envoy.filters.network.tcp_proxy"},
{Name: "three"},
}
}
2023-04-06 21:12:07 +00:00
func makeTestHttpFilters() []*envoy_http_v3.HttpFilter {
return []*envoy_http_v3.HttpFilter{
{Name: "one"},
{Name: "two"},
{Name: "envoy.filters.http.router"},
{Name: "three"},
}
}
func makeTestRuntimeConfig(protocol string, enterprise bool) *extensioncommon.RuntimeConfig {
2023-04-06 21:12:07 +00:00
var ns, ap string
if enterprise {
ns = "ns1"
ap = "ap1"
}
return &extensioncommon.RuntimeConfig{
Kind: api.ServiceKindConnectProxy,
ServiceName: api.CompoundServiceName{Name: "test-service"},
Upstreams: map[api.CompoundServiceName]*extensioncommon.UpstreamData{
2023-04-06 21:12:07 +00:00
{
Name: "test-file-server",
Namespace: acl.NamespaceOrDefault(ns),
Partition: acl.PartitionOrDefault(ap),
}: {
SNIs: map[string]struct{}{"test-file-server": {}},
2023-04-06 21:12:07 +00:00
EnvoyID: "test-file-server",
},
},
Protocol: protocol,
2023-04-06 21:12:07 +00:00
}
}
func makeTestWasmConfig(protocol string, enterprise bool) *testWasmConfig {
cfg := newTestWasmConfig(protocol, enterprise)
2023-04-06 21:12:07 +00:00
cfg.Required = false
cfg.Protocol = protocol
2023-04-06 21:12:07 +00:00
cfg.ProxyType = "connect-proxy"
cfg.ListenerType = "inbound"
cfg.PluginConfig.Name = "test-plugin-name"
cfg.PluginConfig.RootID = "test-root-id"
cfg.PluginConfig.VmConfig.VmID = "test-vm-id"
cfg.PluginConfig.VmConfig.Runtime = "wasmtime"
cfg.PluginConfig.VmConfig.Code.Remote.HttpURI.Service.Name = "test-file-server"
cfg.PluginConfig.VmConfig.Code.Remote.HttpURI.URI = "https://test-file-server/plugin.wasm"
cfg.PluginConfig.VmConfig.Code.Remote.HttpURI.Timeout = "5s"
cfg.PluginConfig.VmConfig.Code.Remote.SHA256 = "d05d88b0ce8a8f1d5176481e0af3ae5c65ed82cbfb8c61506c5354b076078545"
cfg.PluginConfig.VmConfig.Code.Remote.RetryPolicy.RetryBackOff.BaseInterval = "3s"
cfg.PluginConfig.VmConfig.Code.Remote.RetryPolicy.RetryBackOff.MaxInterval = "15s"
cfg.PluginConfig.VmConfig.Code.Remote.RetryPolicy.NumRetries = 3
cfg.PluginConfig.VmConfig.Configuration = "test-vm-configuration"
cfg.PluginConfig.VmConfig.EnvironmentVariables.HostEnvKeys = []string{"PATH"}
cfg.PluginConfig.VmConfig.EnvironmentVariables.KeyValues = map[string]string{"TEST_VAR": "TEST_VAL"}
cfg.PluginConfig.Configuration = "test-plugin-configuration"
cfg.PluginConfig.CapabilityRestrictionConfiguration.AllowedCapabilities = map[string]any{"proxy_on_vm_start": true}
return cfg
}
func newTestWasmConfig(protocol string, enterprise bool) *testWasmConfig {
cfg := &testWasmConfig{Protocol: protocol}
2023-04-06 21:12:07 +00:00
if enterprise {
cfg.PluginConfig.VmConfig.Code.Remote.HttpURI.Service.Namespace = "ns1"
cfg.PluginConfig.VmConfig.Code.Remote.HttpURI.Service.Partition = "ap1"
}
return cfg
}
func setField(m map[string]any, path string, value any) {
upsertField(m, path, value, 0)
}
func upsertField(m map[string]any, path string, value any, index int) {
keys := strings.Split(path, ".")
key := keys[index]
if val, ok := m[key]; ok {
// update the value
if index == len(keys)-1 {
m[key] = value
} else {
upsertField(val.(map[string]any), path, value, index+1)
}
} else {
// key does not exist so insert it
if index == len(keys)-1 {
m[key] = value
} else {
newMap := make(map[string]any)
m[key] = newMap
upsertField(newMap, path, value, index+1)
}
}
}