agent/consul: proxy registration and tests
This commit is contained in:
parent
6cd9e0e37c
commit
8a72826483
|
@ -47,6 +47,24 @@ func (c *Catalog) Register(args *structs.RegisterRequest, reply *struct{}) error
|
||||||
|
|
||||||
// Handle a service registration.
|
// Handle a service registration.
|
||||||
if args.Service != nil {
|
if args.Service != nil {
|
||||||
|
// Connect proxy specific logic
|
||||||
|
if args.Service.Kind == structs.ServiceKindConnectProxy {
|
||||||
|
// Name is optional, if it isn't set, we default to the
|
||||||
|
// proxy name. It actually MUST be this, but the validation
|
||||||
|
// below this will verify.
|
||||||
|
if args.Service.Service == "" {
|
||||||
|
args.Service.Service = fmt.Sprintf(
|
||||||
|
"%s-connect-proxy", args.Service.ProxyDestination)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate the service. This is in addition to the below since
|
||||||
|
// the above just hasn't been moved over yet. We should move it over
|
||||||
|
// in time.
|
||||||
|
if err := args.Service.Validate(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// If no service id, but service name, use default
|
// If no service id, but service name, use default
|
||||||
if args.Service.ID == "" && args.Service.Service != "" {
|
if args.Service.ID == "" && args.Service.Service != "" {
|
||||||
args.Service.ID = args.Service.Service
|
args.Service.ID = args.Service.Service
|
||||||
|
|
|
@ -333,6 +333,87 @@ func TestCatalog_Register_ForwardDC(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCatalog_Register_ConnectProxy(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := assert.New(t)
|
||||||
|
dir1, s1 := testServer(t)
|
||||||
|
defer os.RemoveAll(dir1)
|
||||||
|
defer s1.Shutdown()
|
||||||
|
codec := rpcClient(t, s1)
|
||||||
|
defer codec.Close()
|
||||||
|
|
||||||
|
args := structs.TestRegisterRequestProxy(t)
|
||||||
|
|
||||||
|
// Register
|
||||||
|
var out struct{}
|
||||||
|
assert.Nil(msgpackrpc.CallWithCodec(codec, "Catalog.Register", &args, &out))
|
||||||
|
|
||||||
|
// List
|
||||||
|
req := structs.ServiceSpecificRequest{
|
||||||
|
Datacenter: "dc1",
|
||||||
|
ServiceName: args.Service.Service,
|
||||||
|
}
|
||||||
|
var resp structs.IndexedServiceNodes
|
||||||
|
assert.Nil(msgpackrpc.CallWithCodec(codec, "Catalog.ServiceNodes", &req, &resp))
|
||||||
|
assert.Len(resp.ServiceNodes, 1)
|
||||||
|
v := resp.ServiceNodes[0]
|
||||||
|
assert.Equal(structs.ServiceKindConnectProxy, v.ServiceKind)
|
||||||
|
assert.Equal(args.Service.ProxyDestination, v.ServiceProxyDestination)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test an invalid ConnectProxy. We don't need to exhaustively test because
|
||||||
|
// this is all tested in structs on the Validate method.
|
||||||
|
func TestCatalog_Register_ConnectProxy_invalid(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := assert.New(t)
|
||||||
|
dir1, s1 := testServer(t)
|
||||||
|
defer os.RemoveAll(dir1)
|
||||||
|
defer s1.Shutdown()
|
||||||
|
codec := rpcClient(t, s1)
|
||||||
|
defer codec.Close()
|
||||||
|
|
||||||
|
args := structs.TestRegisterRequestProxy(t)
|
||||||
|
args.Service.ProxyDestination = ""
|
||||||
|
|
||||||
|
// Register
|
||||||
|
var out struct{}
|
||||||
|
err := msgpackrpc.CallWithCodec(codec, "Catalog.Register", &args, &out)
|
||||||
|
assert.NotNil(err)
|
||||||
|
assert.Contains(err.Error(), "ProxyDestination")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test registering a proxy with no name set, which should work.
|
||||||
|
func TestCatalog_Register_ConnectProxy_noName(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := assert.New(t)
|
||||||
|
dir1, s1 := testServer(t)
|
||||||
|
defer os.RemoveAll(dir1)
|
||||||
|
defer s1.Shutdown()
|
||||||
|
codec := rpcClient(t, s1)
|
||||||
|
defer codec.Close()
|
||||||
|
|
||||||
|
args := structs.TestRegisterRequestProxy(t)
|
||||||
|
args.Service.Service = ""
|
||||||
|
|
||||||
|
// Register
|
||||||
|
var out struct{}
|
||||||
|
assert.Nil(msgpackrpc.CallWithCodec(codec, "Catalog.Register", &args, &out))
|
||||||
|
|
||||||
|
// List
|
||||||
|
req := structs.ServiceSpecificRequest{
|
||||||
|
Datacenter: "dc1",
|
||||||
|
ServiceName: fmt.Sprintf("%s-connect-proxy", args.Service.ProxyDestination),
|
||||||
|
}
|
||||||
|
var resp structs.IndexedServiceNodes
|
||||||
|
assert.Nil(msgpackrpc.CallWithCodec(codec, "Catalog.ServiceNodes", &req, &resp))
|
||||||
|
assert.Len(resp.ServiceNodes, 1)
|
||||||
|
v := resp.ServiceNodes[0]
|
||||||
|
assert.Equal(structs.ServiceKindConnectProxy, v.ServiceKind)
|
||||||
|
}
|
||||||
|
|
||||||
func TestCatalog_Deregister(t *testing.T) {
|
func TestCatalog_Deregister(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
dir1, s1 := testServer(t)
|
dir1, s1 := testServer(t)
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"github.com/hashicorp/consul/api"
|
"github.com/hashicorp/consul/api"
|
||||||
"github.com/hashicorp/consul/types"
|
"github.com/hashicorp/consul/types"
|
||||||
"github.com/hashicorp/go-msgpack/codec"
|
"github.com/hashicorp/go-msgpack/codec"
|
||||||
|
"github.com/hashicorp/go-multierror"
|
||||||
"github.com/hashicorp/serf/coordinate"
|
"github.com/hashicorp/serf/coordinate"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -488,6 +489,31 @@ type NodeService struct {
|
||||||
RaftIndex
|
RaftIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate validates the node service configuration.
|
||||||
|
//
|
||||||
|
// NOTE(mitchellh): This currently only validates fields for a ConnectProxy.
|
||||||
|
// Historically validation has been directly in the Catalog.Register RPC.
|
||||||
|
// ConnectProxy validation was moved here for easier table testing, but
|
||||||
|
// other validation still exists in Catalog.Register.
|
||||||
|
func (s *NodeService) Validate() error {
|
||||||
|
var result error
|
||||||
|
|
||||||
|
// ConnectProxy validation
|
||||||
|
if s.Kind == ServiceKindConnectProxy {
|
||||||
|
if strings.TrimSpace(s.ProxyDestination) == "" {
|
||||||
|
result = multierror.Append(result, fmt.Errorf(
|
||||||
|
"ProxyDestination must be non-empty for Connect proxy services"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Port == 0 {
|
||||||
|
result = multierror.Append(result, fmt.Errorf(
|
||||||
|
"Port must be set for a Connect proxy"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
// IsSame checks if one NodeService is the same as another, without looking
|
// IsSame checks if one NodeService is the same as another, without looking
|
||||||
// at the Raft information (that's why we didn't call it IsEqual). This is
|
// at the Raft information (that's why we didn't call it IsEqual). This is
|
||||||
// useful for seeing if an update would be idempotent for all the functional
|
// useful for seeing if an update would be idempotent for all the functional
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
|
|
||||||
"github.com/hashicorp/consul/api"
|
"github.com/hashicorp/consul/api"
|
||||||
"github.com/hashicorp/consul/types"
|
"github.com/hashicorp/consul/types"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEncodeDecode(t *testing.T) {
|
func TestEncodeDecode(t *testing.T) {
|
||||||
|
@ -208,6 +209,60 @@ func TestStructs_ServiceNode_Conversions(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStructs_NodeService_ValidateConnectProxy(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
Name string
|
||||||
|
Modify func(*NodeService)
|
||||||
|
Err string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"valid",
|
||||||
|
func(x *NodeService) {},
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"connect-proxy: no ProxyDestination",
|
||||||
|
func(x *NodeService) { x.ProxyDestination = "" },
|
||||||
|
"ProxyDestination must be",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"connect-proxy: whitespace ProxyDestination",
|
||||||
|
func(x *NodeService) { x.ProxyDestination = " " },
|
||||||
|
"ProxyDestination must be",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"connect-proxy: valid ProxyDestination",
|
||||||
|
func(x *NodeService) { x.ProxyDestination = "hello" },
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"connect-proxy: no port set",
|
||||||
|
func(x *NodeService) { x.Port = 0 },
|
||||||
|
"Port must",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range cases {
|
||||||
|
t.Run(tc.Name, func(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
ns := TestNodeServiceProxy(t)
|
||||||
|
tc.Modify(ns)
|
||||||
|
|
||||||
|
err := ns.Validate()
|
||||||
|
assert.Equal(err != nil, tc.Err != "", err)
|
||||||
|
if err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Contains(strings.ToLower(err.Error()), strings.ToLower(tc.Err))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestStructs_NodeService_IsSame(t *testing.T) {
|
func TestStructs_NodeService_IsSame(t *testing.T) {
|
||||||
ns := &NodeService{
|
ns := &NodeService{
|
||||||
ID: "node1",
|
ID: "node1",
|
||||||
|
|
|
@ -11,12 +11,18 @@ func TestRegisterRequestProxy(t testing.T) *RegisterRequest {
|
||||||
Datacenter: "dc1",
|
Datacenter: "dc1",
|
||||||
Node: "foo",
|
Node: "foo",
|
||||||
Address: "127.0.0.1",
|
Address: "127.0.0.1",
|
||||||
Service: &NodeService{
|
Service: TestNodeServiceProxy(t),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestNodeServiceProxy returns a *NodeService representing a valid
|
||||||
|
// Connect proxy.
|
||||||
|
func TestNodeServiceProxy(t testing.T) *NodeService {
|
||||||
|
return &NodeService{
|
||||||
Kind: ServiceKindConnectProxy,
|
Kind: ServiceKindConnectProxy,
|
||||||
Service: ConnectProxyServiceName,
|
Service: ConnectProxyServiceName,
|
||||||
Address: "127.0.0.2",
|
Address: "127.0.0.2",
|
||||||
Port: 2222,
|
Port: 2222,
|
||||||
ProxyDestination: "web",
|
ProxyDestination: "web",
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue