agent/structs: validate service definitions, port required for proxy

This commit is contained in:
Mitchell Hashimoto 2018-05-04 14:10:03 -07:00
parent 9a62bce03b
commit 965a902474
No known key found for this signature in database
GPG Key ID: 744E147AA52F5B0A
5 changed files with 107 additions and 0 deletions

View File

@ -912,6 +912,13 @@ func (b *Builder) Validate(rt RuntimeConfig) error {
return b.err
}
// Check for errors in the service definitions
for _, s := range rt.Services {
if err := s.Validate(); err != nil {
return fmt.Errorf("service %q: %s", s.Name, err)
}
}
// ----------------------------------------------------------------
// warnings
//

View File

@ -1,5 +1,11 @@
package structs
import (
"fmt"
"github.com/hashicorp/go-multierror"
)
// ServiceDefinition is used to JSON decode the Service definitions. For
// documentation on specific fields see NodeService which is better documented.
type ServiceDefinition struct {
@ -68,6 +74,31 @@ func (s *ServiceDefinition) ConnectManagedProxy() (*ConnectManagedProxy, error)
return p, nil
}
// Validate validates the service definition. This also calls the underlying
// Validate method on the NodeService.
//
// NOTE(mitchellh): This currently only validates fields related to Connect
// and is incomplete with regards to other fields.
func (s *ServiceDefinition) Validate() error {
var result error
if s.Kind == ServiceKindTypical {
if s.Connect != nil && s.Connect.Proxy != nil {
if s.Port == 0 {
result = multierror.Append(result, fmt.Errorf(
"Services with a Connect managed proxy must have a port set"))
}
}
}
// Validate the NodeService which covers a lot
if err := s.NodeService().Validate(); err != nil {
result = multierror.Append(result, err)
}
return result
}
func (s *ServiceDefinition) CheckTypes() (checks CheckTypes, err error) {
if !s.Check.Empty() {
err := s.Check.Validate()

View File

@ -2,10 +2,12 @@ package structs
import (
"fmt"
"strings"
"testing"
"time"
"github.com/pascaldekloe/goe/verify"
"github.com/stretchr/testify/require"
)
func TestAgentStructs_CheckTypes(t *testing.T) {
@ -54,3 +56,55 @@ func TestAgentStructs_CheckTypes(t *testing.T) {
}
}
}
func TestServiceDefinitionValidate(t *testing.T) {
cases := []struct {
Name string
Modify func(*ServiceDefinition)
Err string
}{
{
"valid",
func(x *ServiceDefinition) {},
"",
},
{
"managed proxy with a port set",
func(x *ServiceDefinition) {
x.Port = 8080
x.Connect = &ServiceDefinitionConnect{
Proxy: &ServiceDefinitionConnectProxy{},
}
},
"",
},
{
"managed proxy with no port set",
func(x *ServiceDefinition) {
x.Connect = &ServiceDefinitionConnect{
Proxy: &ServiceDefinitionConnectProxy{},
}
},
"must have a port",
},
}
for _, tc := range cases {
t.Run(tc.Name, func(t *testing.T) {
require := require.New(t)
service := TestServiceDefinition(t)
tc.Modify(service)
err := service.Validate()
t.Logf("error: %s", err)
require.Equal(err != nil, tc.Err != "")
if err == nil {
return
}
require.Contains(strings.ToLower(err.Error()), strings.ToLower(tc.Err))
})
}
}

View File

@ -29,6 +29,14 @@ func TestRegisterRequestProxy(t testing.T) *RegisterRequest {
}
}
// TestNodeService returns a *NodeService representing a valid regular service.
func TestNodeService(t testing.T) *NodeService {
return &NodeService{
Kind: ServiceKindTypical,
Service: "web",
}
}
// TestNodeServiceProxy returns a *NodeService representing a valid
// Connect proxy.
func TestNodeServiceProxy(t testing.T) *NodeService {

View File

@ -4,6 +4,13 @@ import (
"github.com/mitchellh/go-testing-interface"
)
// TestServiceDefinition returns a ServiceDefinition for a typical service.
func TestServiceDefinition(t testing.T) *ServiceDefinition {
return &ServiceDefinition{
Name: "db",
}
}
// TestServiceDefinitionProxy returns a ServiceDefinition for a proxy.
func TestServiceDefinitionProxy(t testing.T) *ServiceDefinition {
return &ServiceDefinition{