2019-04-29 16:27:57 +00:00
|
|
|
package envoy
|
|
|
|
|
|
|
|
import (
|
|
|
|
"reflect"
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
expectedPromListener = `{
|
|
|
|
"name": "envoy_prometheus_metrics_listener",
|
|
|
|
"address": {
|
|
|
|
"socket_address": {
|
|
|
|
"address": "0.0.0.0",
|
|
|
|
"port_value": 9000
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"filter_chains": [
|
|
|
|
{
|
|
|
|
"filters": [
|
|
|
|
{
|
|
|
|
"name": "envoy.http_connection_manager",
|
|
|
|
"config": {
|
|
|
|
"stat_prefix": "envoy_prometheus_metrics",
|
|
|
|
"codec_type": "HTTP1",
|
|
|
|
"route_config": {
|
|
|
|
"name": "self_admin_route",
|
|
|
|
"virtual_hosts": [
|
|
|
|
{
|
|
|
|
"name": "self_admin",
|
|
|
|
"domains": [
|
|
|
|
"*"
|
|
|
|
],
|
|
|
|
"routes": [
|
|
|
|
{
|
|
|
|
"match": {
|
|
|
|
"path": "/metrics"
|
|
|
|
},
|
|
|
|
"route": {
|
|
|
|
"cluster": "self_admin",
|
|
|
|
"prefix_rewrite": "/stats/prometheus"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"match": {
|
|
|
|
"prefix": "/"
|
|
|
|
},
|
|
|
|
"direct_response": {
|
|
|
|
"status": 404
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"http_filters": [
|
|
|
|
{
|
|
|
|
"name": "envoy.router"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}`
|
|
|
|
expectedPromCluster = `{
|
|
|
|
"name": "self_admin",
|
|
|
|
"connect_timeout": "5s",
|
|
|
|
"type": "STATIC",
|
|
|
|
"http_protocol_options": {},
|
|
|
|
"hosts": [
|
|
|
|
{
|
|
|
|
"socket_address": {
|
|
|
|
"address": "127.0.0.1",
|
|
|
|
"port_value": 19000
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}`
|
2020-02-03 17:19:34 +00:00
|
|
|
expectedStatsListener = `{
|
|
|
|
"name": "envoy_metrics_listener",
|
|
|
|
"address": {
|
|
|
|
"socket_address": {
|
|
|
|
"address": "0.0.0.0",
|
|
|
|
"port_value": 9000
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"filter_chains": [
|
|
|
|
{
|
|
|
|
"filters": [
|
|
|
|
{
|
|
|
|
"name": "envoy.http_connection_manager",
|
|
|
|
"config": {
|
|
|
|
"stat_prefix": "envoy_metrics",
|
|
|
|
"codec_type": "HTTP1",
|
|
|
|
"route_config": {
|
|
|
|
"name": "self_admin_route",
|
|
|
|
"virtual_hosts": [
|
|
|
|
{
|
|
|
|
"name": "self_admin",
|
|
|
|
"domains": [
|
|
|
|
"*"
|
|
|
|
],
|
|
|
|
"routes": [
|
|
|
|
{
|
|
|
|
"match": {
|
|
|
|
"prefix": "/stats"
|
|
|
|
},
|
|
|
|
"route": {
|
|
|
|
"cluster": "self_admin",
|
|
|
|
"prefix_rewrite": "/stats"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"match": {
|
|
|
|
"prefix": "/"
|
|
|
|
},
|
|
|
|
"direct_response": {
|
|
|
|
"status": 404
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"http_filters": [
|
|
|
|
{
|
|
|
|
"name": "envoy.router"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}`
|
|
|
|
expectedStatsCluster = `{
|
|
|
|
"name": "self_admin",
|
|
|
|
"connect_timeout": "5s",
|
|
|
|
"type": "STATIC",
|
|
|
|
"http_protocol_options": {},
|
|
|
|
"hosts": [
|
|
|
|
{
|
|
|
|
"socket_address": {
|
|
|
|
"address": "127.0.0.1",
|
|
|
|
"port_value": 19000
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}`
|
2019-04-29 16:27:57 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestBootstrapConfig_ConfigureArgs(t *testing.T) {
|
2019-08-16 14:30:17 +00:00
|
|
|
sniTagJSON := strings.Join(sniTagJSONs, ",\n")
|
|
|
|
defaultStatsConfigJSON := `{
|
|
|
|
"stats_tags": [
|
|
|
|
` + sniTagJSON + `
|
|
|
|
],
|
|
|
|
"use_all_default_tags": true
|
|
|
|
}`
|
2019-04-29 16:27:57 +00:00
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
input BootstrapConfig
|
|
|
|
env []string
|
|
|
|
baseArgs BootstrapTplArgs
|
|
|
|
wantArgs BootstrapTplArgs
|
|
|
|
wantErr bool
|
|
|
|
}{
|
|
|
|
{
|
2019-08-16 14:30:17 +00:00
|
|
|
name: "defaults",
|
|
|
|
input: BootstrapConfig{},
|
|
|
|
wantArgs: BootstrapTplArgs{
|
|
|
|
StatsConfigJSON: defaultStatsConfigJSON,
|
|
|
|
},
|
|
|
|
wantErr: false,
|
2019-04-29 16:27:57 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "extra-stats-sinks",
|
|
|
|
input: BootstrapConfig{
|
|
|
|
StatsSinksJSON: `{
|
|
|
|
"name": "envoy.custom_exciting_sink",
|
|
|
|
"config": {
|
|
|
|
"foo": "bar"
|
|
|
|
}
|
|
|
|
}`,
|
|
|
|
},
|
|
|
|
wantArgs: BootstrapTplArgs{
|
2019-08-16 14:30:17 +00:00
|
|
|
StatsConfigJSON: defaultStatsConfigJSON,
|
2019-04-29 16:27:57 +00:00
|
|
|
StatsSinksJSON: `[{
|
|
|
|
"name": "envoy.custom_exciting_sink",
|
|
|
|
"config": {
|
|
|
|
"foo": "bar"
|
|
|
|
}
|
|
|
|
}]`,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "simple-statsd-sink",
|
|
|
|
input: BootstrapConfig{
|
|
|
|
StatsdURL: "udp://127.0.0.1:9125",
|
|
|
|
},
|
|
|
|
wantArgs: BootstrapTplArgs{
|
2019-08-16 14:30:17 +00:00
|
|
|
StatsConfigJSON: defaultStatsConfigJSON,
|
2019-04-29 16:27:57 +00:00
|
|
|
StatsSinksJSON: `[{
|
|
|
|
"name": "envoy.statsd",
|
|
|
|
"config": {
|
|
|
|
"address": {
|
|
|
|
"socket_address": {
|
|
|
|
"address": "127.0.0.1",
|
|
|
|
"port_value": 9125
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}]`,
|
|
|
|
},
|
|
|
|
wantErr: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "simple-statsd-sink-plus-extra",
|
|
|
|
input: BootstrapConfig{
|
|
|
|
StatsdURL: "udp://127.0.0.1:9125",
|
|
|
|
StatsSinksJSON: `{
|
|
|
|
"name": "envoy.custom_exciting_sink",
|
|
|
|
"config": {
|
|
|
|
"foo": "bar"
|
|
|
|
}
|
|
|
|
}`,
|
|
|
|
},
|
|
|
|
wantArgs: BootstrapTplArgs{
|
2019-08-16 14:30:17 +00:00
|
|
|
StatsConfigJSON: defaultStatsConfigJSON,
|
2019-04-29 16:27:57 +00:00
|
|
|
StatsSinksJSON: `[{
|
|
|
|
"name": "envoy.statsd",
|
|
|
|
"config": {
|
|
|
|
"address": {
|
|
|
|
"socket_address": {
|
|
|
|
"address": "127.0.0.1",
|
|
|
|
"port_value": 9125
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"name": "envoy.custom_exciting_sink",
|
|
|
|
"config": {
|
|
|
|
"foo": "bar"
|
|
|
|
}
|
|
|
|
}]`,
|
|
|
|
},
|
|
|
|
wantErr: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "simple-statsd-sink-env",
|
|
|
|
input: BootstrapConfig{
|
|
|
|
StatsdURL: "$MY_STATSD_URL",
|
|
|
|
},
|
|
|
|
env: []string{"MY_STATSD_URL=udp://127.0.0.1:9125"},
|
|
|
|
wantArgs: BootstrapTplArgs{
|
2019-08-16 14:30:17 +00:00
|
|
|
StatsConfigJSON: defaultStatsConfigJSON,
|
2019-04-29 16:27:57 +00:00
|
|
|
StatsSinksJSON: `[{
|
|
|
|
"name": "envoy.statsd",
|
|
|
|
"config": {
|
|
|
|
"address": {
|
|
|
|
"socket_address": {
|
|
|
|
"address": "127.0.0.1",
|
|
|
|
"port_value": 9125
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}]`,
|
|
|
|
},
|
|
|
|
wantErr: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "simple-dogstatsd-sink",
|
|
|
|
input: BootstrapConfig{
|
|
|
|
DogstatsdURL: "udp://127.0.0.1:9125",
|
|
|
|
},
|
|
|
|
wantArgs: BootstrapTplArgs{
|
2019-08-16 14:30:17 +00:00
|
|
|
StatsConfigJSON: defaultStatsConfigJSON,
|
2019-04-29 16:27:57 +00:00
|
|
|
StatsSinksJSON: `[{
|
|
|
|
"name": "envoy.dog_statsd",
|
|
|
|
"config": {
|
|
|
|
"address": {
|
|
|
|
"socket_address": {
|
|
|
|
"address": "127.0.0.1",
|
|
|
|
"port_value": 9125
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}]`,
|
|
|
|
},
|
|
|
|
wantErr: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "simple-dogstatsd-unix-sink",
|
|
|
|
input: BootstrapConfig{
|
|
|
|
DogstatsdURL: "unix:///var/run/dogstatsd.sock",
|
|
|
|
},
|
|
|
|
wantArgs: BootstrapTplArgs{
|
2019-08-16 14:30:17 +00:00
|
|
|
StatsConfigJSON: defaultStatsConfigJSON,
|
2019-04-29 16:27:57 +00:00
|
|
|
StatsSinksJSON: `[{
|
|
|
|
"name": "envoy.dog_statsd",
|
|
|
|
"config": {
|
|
|
|
"address": {
|
|
|
|
"pipe": {
|
|
|
|
"path": "/var/run/dogstatsd.sock"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}]`,
|
|
|
|
},
|
|
|
|
wantErr: false,
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
name: "simple-dogstatsd-sink-env",
|
|
|
|
input: BootstrapConfig{
|
|
|
|
DogstatsdURL: "$MY_STATSD_URL",
|
|
|
|
},
|
|
|
|
env: []string{"MY_STATSD_URL=udp://127.0.0.1:9125"},
|
|
|
|
wantArgs: BootstrapTplArgs{
|
2019-08-16 14:30:17 +00:00
|
|
|
StatsConfigJSON: defaultStatsConfigJSON,
|
2019-04-29 16:27:57 +00:00
|
|
|
StatsSinksJSON: `[{
|
|
|
|
"name": "envoy.dog_statsd",
|
|
|
|
"config": {
|
|
|
|
"address": {
|
|
|
|
"socket_address": {
|
|
|
|
"address": "127.0.0.1",
|
|
|
|
"port_value": 9125
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}]`,
|
|
|
|
},
|
|
|
|
wantErr: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "stats-config-override",
|
|
|
|
input: BootstrapConfig{
|
|
|
|
StatsConfigJSON: `{
|
|
|
|
"use_all_default_tags": true
|
|
|
|
}`,
|
|
|
|
},
|
|
|
|
wantArgs: BootstrapTplArgs{
|
|
|
|
StatsConfigJSON: `{
|
|
|
|
"use_all_default_tags": true
|
|
|
|
}`,
|
|
|
|
},
|
|
|
|
wantErr: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "simple-tags",
|
|
|
|
input: BootstrapConfig{
|
|
|
|
StatsTags: []string{"canary", "foo=bar", "baz=2"},
|
|
|
|
},
|
|
|
|
wantArgs: BootstrapTplArgs{
|
|
|
|
StatsConfigJSON: `{
|
|
|
|
"stats_tags": [
|
2019-08-16 14:30:17 +00:00
|
|
|
` + sniTagJSON + `,
|
2019-04-29 16:27:57 +00:00
|
|
|
{
|
|
|
|
"tag_name": "canary",
|
|
|
|
"fixed_value": "1"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"tag_name": "foo",
|
|
|
|
"fixed_value": "bar"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"tag_name": "baz",
|
|
|
|
"fixed_value": "2"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"use_all_default_tags": true
|
|
|
|
}`,
|
|
|
|
},
|
|
|
|
wantErr: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "prometheus-bind-addr",
|
|
|
|
input: BootstrapConfig{
|
|
|
|
PrometheusBindAddr: "0.0.0.0:9000",
|
|
|
|
},
|
|
|
|
baseArgs: BootstrapTplArgs{
|
|
|
|
AdminBindAddress: "127.0.0.1",
|
|
|
|
AdminBindPort: "19000",
|
|
|
|
},
|
|
|
|
wantArgs: BootstrapTplArgs{
|
|
|
|
AdminBindAddress: "127.0.0.1",
|
|
|
|
AdminBindPort: "19000",
|
|
|
|
// Should add a static cluster for the self-proxy to admin
|
|
|
|
StaticClustersJSON: expectedPromCluster,
|
|
|
|
// Should add a static http listener too
|
|
|
|
StaticListenersJSON: expectedPromListener,
|
2019-08-16 14:30:17 +00:00
|
|
|
StatsConfigJSON: defaultStatsConfigJSON,
|
2019-04-29 16:27:57 +00:00
|
|
|
},
|
|
|
|
wantErr: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "prometheus-bind-addr-with-overrides",
|
|
|
|
input: BootstrapConfig{
|
|
|
|
PrometheusBindAddr: "0.0.0.0:9000",
|
|
|
|
StaticClustersJSON: `{"foo":"bar"}`,
|
|
|
|
StaticListenersJSON: `{"baz":"qux"}`,
|
|
|
|
},
|
|
|
|
baseArgs: BootstrapTplArgs{
|
|
|
|
AdminBindAddress: "127.0.0.1",
|
|
|
|
AdminBindPort: "19000",
|
|
|
|
},
|
|
|
|
wantArgs: BootstrapTplArgs{
|
|
|
|
AdminBindAddress: "127.0.0.1",
|
|
|
|
AdminBindPort: "19000",
|
|
|
|
// Should add a static cluster for the self-proxy to admin
|
|
|
|
StaticClustersJSON: `{"foo":"bar"},` + expectedPromCluster,
|
|
|
|
// Should add a static http listener too
|
|
|
|
StaticListenersJSON: `{"baz":"qux"},` + expectedPromListener,
|
2019-08-16 14:30:17 +00:00
|
|
|
StatsConfigJSON: defaultStatsConfigJSON,
|
2019-04-29 16:27:57 +00:00
|
|
|
},
|
|
|
|
wantErr: false,
|
|
|
|
},
|
2020-02-03 17:19:34 +00:00
|
|
|
{
|
|
|
|
name: "stats-bind-addr",
|
|
|
|
input: BootstrapConfig{
|
|
|
|
StatsBindAddr: "0.0.0.0:9000",
|
|
|
|
},
|
|
|
|
baseArgs: BootstrapTplArgs{
|
|
|
|
AdminBindAddress: "127.0.0.1",
|
|
|
|
AdminBindPort: "19000",
|
|
|
|
},
|
|
|
|
wantArgs: BootstrapTplArgs{
|
|
|
|
AdminBindAddress: "127.0.0.1",
|
|
|
|
AdminBindPort: "19000",
|
|
|
|
// Should add a static cluster for the self-proxy to admin
|
|
|
|
StaticClustersJSON: expectedStatsCluster,
|
|
|
|
// Should add a static http listener too
|
|
|
|
StaticListenersJSON: expectedStatsListener,
|
|
|
|
StatsConfigJSON: defaultStatsConfigJSON,
|
|
|
|
},
|
|
|
|
wantErr: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "stats-bind-addr-with-overrides",
|
|
|
|
input: BootstrapConfig{
|
|
|
|
StatsBindAddr: "0.0.0.0:9000",
|
|
|
|
StaticClustersJSON: `{"foo":"bar"}`,
|
|
|
|
StaticListenersJSON: `{"baz":"qux"}`,
|
|
|
|
},
|
|
|
|
baseArgs: BootstrapTplArgs{
|
|
|
|
AdminBindAddress: "127.0.0.1",
|
|
|
|
AdminBindPort: "19000",
|
|
|
|
},
|
|
|
|
wantArgs: BootstrapTplArgs{
|
|
|
|
AdminBindAddress: "127.0.0.1",
|
|
|
|
AdminBindPort: "19000",
|
|
|
|
// Should add a static cluster for the self-proxy to admin
|
|
|
|
StaticClustersJSON: `{"foo":"bar"},` + expectedStatsCluster,
|
|
|
|
// Should add a static http listener too
|
|
|
|
StaticListenersJSON: `{"baz":"qux"},` + expectedStatsListener,
|
|
|
|
StatsConfigJSON: defaultStatsConfigJSON,
|
|
|
|
},
|
|
|
|
wantErr: false,
|
|
|
|
},
|
2019-04-29 16:27:57 +00:00
|
|
|
{
|
|
|
|
name: "stats-flush-interval",
|
|
|
|
input: BootstrapConfig{
|
|
|
|
StatsFlushInterval: `10s`,
|
|
|
|
},
|
|
|
|
wantArgs: BootstrapTplArgs{
|
2019-08-16 14:30:17 +00:00
|
|
|
StatsConfigJSON: defaultStatsConfigJSON,
|
2019-04-29 16:27:57 +00:00
|
|
|
StatsFlushInterval: `10s`,
|
|
|
|
},
|
|
|
|
wantErr: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "override-tracing",
|
|
|
|
input: BootstrapConfig{
|
|
|
|
TracingConfigJSON: `{"foo": "bar"}`,
|
|
|
|
},
|
|
|
|
wantArgs: BootstrapTplArgs{
|
2019-08-16 14:30:17 +00:00
|
|
|
StatsConfigJSON: defaultStatsConfigJSON,
|
2019-04-29 16:27:57 +00:00
|
|
|
TracingConfigJSON: `{"foo": "bar"}`,
|
|
|
|
},
|
|
|
|
wantErr: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "err-bad-prometheus-addr",
|
|
|
|
input: BootstrapConfig{
|
|
|
|
PrometheusBindAddr: "asdasdsad",
|
|
|
|
},
|
|
|
|
wantErr: true,
|
|
|
|
},
|
2020-02-03 17:19:34 +00:00
|
|
|
{
|
|
|
|
name: "err-bad-stats-addr",
|
|
|
|
input: BootstrapConfig{
|
|
|
|
StatsBindAddr: "asdasdsad",
|
|
|
|
},
|
|
|
|
wantErr: true,
|
|
|
|
},
|
2019-04-29 16:27:57 +00:00
|
|
|
{
|
|
|
|
name: "err-bad-statsd-addr",
|
|
|
|
input: BootstrapConfig{
|
|
|
|
StatsdURL: "asdasdsad",
|
|
|
|
},
|
|
|
|
wantErr: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "err-bad-dogstatsd-addr",
|
|
|
|
input: BootstrapConfig{
|
|
|
|
DogstatsdURL: "asdasdsad",
|
|
|
|
},
|
|
|
|
wantErr: true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
args := tt.baseArgs
|
|
|
|
|
|
|
|
defer testSetAndResetEnv(t, tt.env)()
|
|
|
|
|
|
|
|
err := tt.input.ConfigureArgs(&args)
|
|
|
|
if tt.wantErr {
|
|
|
|
require.Error(t, err)
|
|
|
|
} else {
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// Want to compare JSON fields with JSONEq
|
|
|
|
argV := reflect.ValueOf(args)
|
|
|
|
wantV := reflect.ValueOf(tt.wantArgs)
|
|
|
|
argT := reflect.TypeOf(args)
|
|
|
|
for i := 0; i < argT.NumField(); i++ {
|
|
|
|
f := argT.Field(i)
|
|
|
|
if strings.HasSuffix(f.Name, "JSON") && wantV.Field(i).String() != "" {
|
|
|
|
// Some of our JSON strings are comma separated objects to be
|
|
|
|
// insertedinto an array which is not valid JSON on it's own so wrap
|
|
|
|
// them all in an array. For simple values this is still valid JSON
|
|
|
|
// too.
|
|
|
|
want := "[" + wantV.Field(i).String() + "]"
|
|
|
|
got := "[" + argV.Field(i).String() + "]"
|
|
|
|
require.JSONEq(t, want, got, "field %s should be equivalent JSON", f.Name)
|
|
|
|
} else {
|
|
|
|
require.Equalf(t, wantV.Field(i).Interface(),
|
|
|
|
argV.Field(i).Interface(), "field %s should be equal", f.Name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|