2023-03-28 22:48:58 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
2018-04-03 18:10:59 +00:00
|
|
|
package proxy
|
|
|
|
|
|
|
|
import (
|
|
|
|
"testing"
|
2018-04-25 13:53:30 +00:00
|
|
|
"time"
|
2018-04-03 18:10:59 +00:00
|
|
|
|
2022-08-08 15:04:40 +00:00
|
|
|
"github.com/stretchr/testify/assert"
|
2020-11-11 18:15:33 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2018-04-25 13:53:30 +00:00
|
|
|
|
|
|
|
"github.com/hashicorp/consul/agent"
|
|
|
|
"github.com/hashicorp/consul/api"
|
2018-04-03 18:10:59 +00:00
|
|
|
"github.com/hashicorp/consul/connect"
|
2020-01-28 23:50:41 +00:00
|
|
|
"github.com/hashicorp/consul/sdk/testutil"
|
2022-08-08 15:04:40 +00:00
|
|
|
"github.com/hashicorp/consul/sdk/testutil/retry"
|
2018-04-03 18:10:59 +00:00
|
|
|
)
|
|
|
|
|
2018-09-12 16:07:47 +00:00
|
|
|
func TestUpstreamResolverFuncFromClient(t *testing.T) {
|
2018-04-03 18:10:59 +00:00
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
cfg UpstreamConfig
|
|
|
|
want *connect.ConsulResolver
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "service",
|
|
|
|
cfg: UpstreamConfig{
|
2018-09-12 16:07:47 +00:00
|
|
|
DestinationNamespace: "foo",
|
2021-08-20 16:57:45 +00:00
|
|
|
DestinationPartition: "default",
|
2018-09-12 16:07:47 +00:00
|
|
|
DestinationName: "web",
|
|
|
|
Datacenter: "ny1",
|
|
|
|
DestinationType: "service",
|
2018-04-03 18:10:59 +00:00
|
|
|
},
|
|
|
|
want: &connect.ConsulResolver{
|
|
|
|
Namespace: "foo",
|
2021-08-20 16:57:45 +00:00
|
|
|
Partition: "default",
|
2018-04-03 18:10:59 +00:00
|
|
|
Name: "web",
|
|
|
|
Datacenter: "ny1",
|
|
|
|
Type: connect.ConsulResolverTypeService,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "prepared_query",
|
|
|
|
cfg: UpstreamConfig{
|
2018-09-12 16:07:47 +00:00
|
|
|
DestinationNamespace: "foo",
|
2021-08-20 16:57:45 +00:00
|
|
|
DestinationPartition: "default",
|
2018-09-12 16:07:47 +00:00
|
|
|
DestinationName: "web",
|
|
|
|
Datacenter: "ny1",
|
|
|
|
DestinationType: "prepared_query",
|
2018-04-03 18:10:59 +00:00
|
|
|
},
|
|
|
|
want: &connect.ConsulResolver{
|
|
|
|
Namespace: "foo",
|
|
|
|
Name: "web",
|
2021-08-20 16:57:45 +00:00
|
|
|
Partition: "default",
|
2018-04-03 18:10:59 +00:00
|
|
|
Datacenter: "ny1",
|
|
|
|
Type: connect.ConsulResolverTypePreparedQuery,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "unknown behaves like service",
|
|
|
|
cfg: UpstreamConfig{
|
2018-09-12 16:07:47 +00:00
|
|
|
DestinationNamespace: "foo",
|
2021-08-20 16:57:45 +00:00
|
|
|
DestinationPartition: "default",
|
2018-09-12 16:07:47 +00:00
|
|
|
DestinationName: "web",
|
|
|
|
Datacenter: "ny1",
|
|
|
|
DestinationType: "junk",
|
2018-04-03 18:10:59 +00:00
|
|
|
},
|
|
|
|
want: &connect.ConsulResolver{
|
2021-08-20 16:57:45 +00:00
|
|
|
Partition: "default",
|
2018-04-03 18:10:59 +00:00
|
|
|
Namespace: "foo",
|
|
|
|
Name: "web",
|
|
|
|
Datacenter: "ny1",
|
|
|
|
Type: connect.ConsulResolverTypeService,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
// Client doesn't really matter as long as it's passed through.
|
2018-09-12 16:07:47 +00:00
|
|
|
gotFn := UpstreamResolverFuncFromClient(nil)
|
|
|
|
got, err := gotFn(tt.cfg)
|
|
|
|
require.NoError(t, err)
|
2018-04-03 18:10:59 +00:00
|
|
|
require.Equal(t, tt.want, got)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2018-04-25 13:53:30 +00:00
|
|
|
|
2018-09-27 14:00:51 +00:00
|
|
|
func TestAgentConfigWatcherSidecarProxy(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2020-03-31 20:12:33 +00:00
|
|
|
a := agent.StartTestAgent(t, agent.TestAgent{Name: "agent_smith"})
|
2018-09-27 14:00:51 +00:00
|
|
|
defer a.Shutdown()
|
|
|
|
|
|
|
|
client := a.Client()
|
|
|
|
agent := client.Agent()
|
|
|
|
|
2019-08-09 19:19:30 +00:00
|
|
|
// Register a local agent service with a sidecar proxy
|
2018-09-27 14:00:51 +00:00
|
|
|
reg := &api.AgentServiceRegistration{
|
|
|
|
Name: "web",
|
|
|
|
Port: 8080,
|
|
|
|
Connect: &api.AgentServiceConnect{
|
|
|
|
SidecarService: &api.AgentServiceRegistration{
|
|
|
|
Proxy: &api.AgentServiceConnectProxyConfig{
|
|
|
|
Config: map[string]interface{}{
|
|
|
|
"handshake_timeout_ms": 999,
|
|
|
|
},
|
|
|
|
Upstreams: []api.Upstream{
|
|
|
|
{
|
|
|
|
DestinationName: "db",
|
|
|
|
LocalBindPort: 9191,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
err := agent.ServiceRegister(reg)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
w, err := NewAgentConfigWatcher(client, "web-sidecar-proxy",
|
2020-01-28 23:50:41 +00:00
|
|
|
testutil.Logger(t))
|
2018-09-27 14:00:51 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
cfg := testGetConfigValTimeout(t, w, 500*time.Millisecond)
|
|
|
|
|
|
|
|
expectCfg := &Config{
|
|
|
|
ProxiedServiceName: "web",
|
|
|
|
ProxiedServiceNamespace: "default",
|
|
|
|
PublicListener: PublicListenerConfig{
|
|
|
|
BindAddress: "0.0.0.0",
|
|
|
|
BindPort: 21000,
|
|
|
|
LocalServiceAddress: "127.0.0.1:8080",
|
|
|
|
HandshakeTimeoutMs: 999,
|
|
|
|
LocalConnectTimeoutMs: 1000, // from applyDefaults
|
|
|
|
},
|
|
|
|
Upstreams: []UpstreamConfig{
|
|
|
|
{
|
|
|
|
DestinationName: "db",
|
|
|
|
DestinationNamespace: "default",
|
2021-08-20 16:57:45 +00:00
|
|
|
DestinationPartition: "default",
|
2018-09-27 14:00:51 +00:00
|
|
|
DestinationType: "service",
|
|
|
|
LocalBindPort: 9191,
|
|
|
|
LocalBindAddress: "127.0.0.1",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
require.Equal(t, expectCfg, cfg)
|
|
|
|
|
|
|
|
// Now keep watching and update the config.
|
2022-07-27 14:21:27 +00:00
|
|
|
reg.Connect.SidecarService.Proxy.Upstreams = append(reg.Connect.SidecarService.Proxy.Upstreams,
|
|
|
|
api.Upstream{
|
|
|
|
DestinationName: "cache",
|
|
|
|
LocalBindPort: 9292,
|
|
|
|
LocalBindAddress: "127.10.10.10",
|
|
|
|
})
|
|
|
|
reg.Connect.SidecarService.Proxy.Config["local_connect_timeout_ms"] = 444
|
|
|
|
require.NoError(t, agent.ServiceRegister(reg))
|
2018-09-27 14:00:51 +00:00
|
|
|
|
2022-08-08 15:04:40 +00:00
|
|
|
updatedCfg := new(Config)
|
|
|
|
*updatedCfg = *expectCfg
|
|
|
|
updatedCfg.Upstreams = append(updatedCfg.Upstreams, UpstreamConfig{
|
2018-09-27 14:00:51 +00:00
|
|
|
DestinationName: "cache",
|
|
|
|
DestinationNamespace: "default",
|
2021-08-20 16:57:45 +00:00
|
|
|
DestinationPartition: "default",
|
2018-09-27 14:00:51 +00:00
|
|
|
DestinationType: "service",
|
|
|
|
LocalBindPort: 9292,
|
|
|
|
LocalBindAddress: "127.10.10.10",
|
|
|
|
})
|
2022-08-08 15:04:40 +00:00
|
|
|
updatedCfg.PublicListener.LocalConnectTimeoutMs = 444
|
|
|
|
|
|
|
|
retry.Run(t, func(r *retry.R) {
|
|
|
|
cfg := testGetConfigValTimeout(r, w, 500*time.Millisecond)
|
|
|
|
// TODO: These are debug logs to show the diffs against updatedCfg and expectCfg.
|
|
|
|
// Once we figure out what event makes this test flake, we should adjust this test to be deterministic.
|
|
|
|
if !assert.Equal(r, updatedCfg, cfg, "expected config from watcher to match updated") {
|
|
|
|
assert.Equal(r, expectCfg, cfg, "config does not match original or updated config; something else must have fired watch")
|
|
|
|
r.FailNow()
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2018-09-27 14:00:51 +00:00
|
|
|
|
2022-08-08 15:04:40 +00:00
|
|
|
type testingT interface {
|
|
|
|
Helper()
|
|
|
|
Fatalf(format string, args ...interface{})
|
2018-09-27 14:00:51 +00:00
|
|
|
}
|
|
|
|
|
2022-08-08 15:04:40 +00:00
|
|
|
func testGetConfigValTimeout(t testingT, w ConfigWatcher,
|
2018-04-25 13:53:30 +00:00
|
|
|
timeout time.Duration) *Config {
|
|
|
|
t.Helper()
|
|
|
|
select {
|
|
|
|
case cfg := <-w.Watch():
|
|
|
|
return cfg
|
|
|
|
case <-time.After(timeout):
|
|
|
|
t.Fatalf("timeout after %s waiting for config update", timeout)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|