2015-11-18 22:19:58 +00:00
|
|
|
package client
|
|
|
|
|
|
|
|
import (
|
2015-12-14 23:47:01 +00:00
|
|
|
"fmt"
|
2015-11-26 09:03:16 +00:00
|
|
|
consul "github.com/hashicorp/consul/api"
|
2015-12-14 23:47:01 +00:00
|
|
|
"github.com/hashicorp/nomad/nomad/mock"
|
2015-11-18 22:19:58 +00:00
|
|
|
"github.com/hashicorp/nomad/nomad/structs"
|
|
|
|
"log"
|
|
|
|
"os"
|
2015-12-11 22:14:04 +00:00
|
|
|
"reflect"
|
2015-11-18 22:19:58 +00:00
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
2015-11-26 09:03:16 +00:00
|
|
|
type mockConsulApiClient struct {
|
|
|
|
serviceRegisterCallCount int
|
|
|
|
checkRegisterCallCount int
|
|
|
|
checkDeregisterCallCount int
|
|
|
|
serviceDeregisterCallCount int
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *mockConsulApiClient) CheckRegister(check *consul.AgentCheckRegistration) error {
|
|
|
|
a.checkRegisterCallCount += 1
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *mockConsulApiClient) CheckDeregister(checkID string) error {
|
|
|
|
a.checkDeregisterCallCount += 1
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *mockConsulApiClient) ServiceRegister(service *consul.AgentServiceRegistration) error {
|
|
|
|
a.serviceRegisterCallCount += 1
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-12-14 23:57:56 +00:00
|
|
|
func (a *mockConsulApiClient) ServiceDeregister(serviceID string) error {
|
2015-11-26 09:03:16 +00:00
|
|
|
a.serviceDeregisterCallCount += 1
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *mockConsulApiClient) Services() (map[string]*consul.AgentService, error) {
|
|
|
|
return make(map[string]*consul.AgentService), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *mockConsulApiClient) Checks() (map[string]*consul.AgentCheck, error) {
|
|
|
|
return make(map[string]*consul.AgentCheck), nil
|
|
|
|
}
|
|
|
|
|
2015-11-24 20:34:26 +00:00
|
|
|
func newConsulService() *ConsulService {
|
2015-11-18 23:56:34 +00:00
|
|
|
logger := log.New(os.Stdout, "logger: ", log.Lshortfile)
|
2015-12-11 19:02:23 +00:00
|
|
|
c, _ := NewConsulService(&consulServiceConfig{logger, "", "", "", false, false, &structs.Node{}})
|
2015-11-26 09:03:16 +00:00
|
|
|
c.client = &mockConsulApiClient{}
|
2015-11-18 23:56:34 +00:00
|
|
|
return c
|
|
|
|
}
|
|
|
|
|
2015-11-25 19:20:36 +00:00
|
|
|
func newTask() *structs.Task {
|
|
|
|
var services []*structs.Service
|
|
|
|
return &structs.Task{
|
|
|
|
Name: "redis",
|
|
|
|
Services: services,
|
|
|
|
Resources: &structs.Resources{
|
|
|
|
Networks: []*structs.NetworkResource{
|
|
|
|
{
|
|
|
|
IP: "10.10.0.1",
|
|
|
|
DynamicPorts: []structs.Port{{"db", 20413}},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-24 20:34:26 +00:00
|
|
|
func TestConsul_MakeChecks(t *testing.T) {
|
2016-02-19 03:19:25 +00:00
|
|
|
t.Parallel()
|
2015-11-18 22:19:58 +00:00
|
|
|
service := &structs.Service{
|
|
|
|
Name: "Bar",
|
2015-11-26 02:23:47 +00:00
|
|
|
Checks: []*structs.ServiceCheck{
|
2015-11-18 22:19:58 +00:00
|
|
|
{
|
|
|
|
Type: "http",
|
|
|
|
Path: "/foo/bar",
|
|
|
|
Interval: 10 * time.Second,
|
|
|
|
Timeout: 2 * time.Second,
|
|
|
|
},
|
2015-11-18 22:22:46 +00:00
|
|
|
{
|
|
|
|
Type: "http",
|
|
|
|
Protocol: "https",
|
|
|
|
Path: "/foo/bar",
|
|
|
|
Interval: 10 * time.Second,
|
|
|
|
Timeout: 2 * time.Second,
|
|
|
|
},
|
2015-11-18 22:19:58 +00:00
|
|
|
{
|
|
|
|
Type: "tcp",
|
|
|
|
Interval: 10 * time.Second,
|
|
|
|
Timeout: 2 * time.Second,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2015-11-24 20:34:26 +00:00
|
|
|
c := newConsulService()
|
2015-12-14 23:57:56 +00:00
|
|
|
serviceID := fmt.Sprintf("%s-1234", structs.NomadConsulPrefix)
|
2015-11-18 22:19:58 +00:00
|
|
|
|
2015-12-14 23:57:56 +00:00
|
|
|
check1 := c.makeCheck(serviceID, service.Checks[0], "10.10.0.1", 8090)
|
|
|
|
check2 := c.makeCheck(serviceID, service.Checks[1], "10.10.0.1", 8090)
|
|
|
|
check3 := c.makeCheck(serviceID, service.Checks[2], "10.10.0.1", 8090)
|
2015-11-18 22:19:58 +00:00
|
|
|
|
2015-11-26 02:23:47 +00:00
|
|
|
if check1.HTTP != "http://10.10.0.1:8090/foo/bar" {
|
|
|
|
t.Fatalf("Invalid http url for check: %v", check1.HTTP)
|
2015-11-18 22:19:58 +00:00
|
|
|
}
|
|
|
|
|
2015-11-26 02:23:47 +00:00
|
|
|
if check2.HTTP != "https://10.10.0.1:8090/foo/bar" {
|
|
|
|
t.Fatalf("Invalid http url for check: %v", check2.HTTP)
|
2015-11-18 22:22:46 +00:00
|
|
|
}
|
|
|
|
|
2015-11-26 02:23:47 +00:00
|
|
|
if check3.TCP != "10.10.0.1:8090" {
|
|
|
|
t.Fatalf("Invalid tcp check: %v", check3.TCP)
|
2015-11-18 22:19:58 +00:00
|
|
|
}
|
|
|
|
}
|
2015-11-18 23:56:34 +00:00
|
|
|
|
2015-11-24 20:34:26 +00:00
|
|
|
func TestConsul_InvalidPortLabelForService(t *testing.T) {
|
2016-02-19 03:19:25 +00:00
|
|
|
t.Parallel()
|
2015-11-18 23:56:34 +00:00
|
|
|
task := &structs.Task{
|
|
|
|
Name: "foo",
|
|
|
|
Driver: "docker",
|
|
|
|
Resources: &structs.Resources{
|
|
|
|
CPU: 500,
|
|
|
|
MemoryMB: 1024,
|
|
|
|
DiskMB: 1024,
|
|
|
|
IOPS: 10,
|
|
|
|
Networks: []*structs.NetworkResource{
|
|
|
|
{
|
|
|
|
Device: "eth0",
|
|
|
|
CIDR: "255.255.0.0/16",
|
|
|
|
MBits: 10,
|
|
|
|
ReservedPorts: []structs.Port{
|
|
|
|
{
|
|
|
|
Label: "http",
|
|
|
|
Value: 8080,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Label: "ssh",
|
|
|
|
Value: 2026,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
service := &structs.Service{
|
|
|
|
Name: "foo",
|
|
|
|
Tags: []string{"a", "b"},
|
|
|
|
PortLabel: "https",
|
2015-11-26 02:23:47 +00:00
|
|
|
Checks: make([]*structs.ServiceCheck, 0),
|
2015-11-18 23:56:34 +00:00
|
|
|
}
|
|
|
|
|
2015-11-24 20:34:26 +00:00
|
|
|
c := newConsulService()
|
2015-12-14 23:47:01 +00:00
|
|
|
if err := c.registerService(service, task, mock.Alloc()); err == nil {
|
2015-11-18 23:56:34 +00:00
|
|
|
t.Fatalf("Service should be invalid")
|
|
|
|
}
|
|
|
|
}
|
2015-11-24 20:34:26 +00:00
|
|
|
|
2015-11-24 22:37:14 +00:00
|
|
|
func TestConsul_Services_Deleted_From_Task(t *testing.T) {
|
2016-02-19 03:19:25 +00:00
|
|
|
t.Parallel()
|
2015-11-24 22:37:14 +00:00
|
|
|
c := newConsulService()
|
|
|
|
task := structs.Task{
|
2015-11-25 01:33:04 +00:00
|
|
|
Name: "redis",
|
|
|
|
Services: []*structs.Service{
|
|
|
|
&structs.Service{
|
|
|
|
Name: "example-cache-redis",
|
|
|
|
Tags: []string{"global"},
|
|
|
|
PortLabel: "db",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Resources: &structs.Resources{
|
|
|
|
Networks: []*structs.NetworkResource{
|
|
|
|
{
|
|
|
|
IP: "10.10.0.1",
|
|
|
|
DynamicPorts: []structs.Port{{"db", 20413}},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2015-11-24 22:37:14 +00:00
|
|
|
}
|
2015-12-14 23:47:01 +00:00
|
|
|
c.Register(&task, mock.Alloc())
|
2015-11-26 02:23:47 +00:00
|
|
|
if len(c.serviceStates) != 1 {
|
|
|
|
t.Fatalf("Expected tracked services: %v, Actual: %v", 1, len(c.serviceStates))
|
2015-11-25 20:06:14 +00:00
|
|
|
}
|
2015-11-25 01:33:04 +00:00
|
|
|
task.Services = []*structs.Service{}
|
2015-11-24 20:34:26 +00:00
|
|
|
|
2015-11-26 09:03:16 +00:00
|
|
|
c.performSync()
|
2015-11-26 02:23:47 +00:00
|
|
|
if len(c.serviceStates) != 0 {
|
|
|
|
t.Fatalf("Expected tracked services: %v, Actual: %v", 0, len(c.serviceStates))
|
2015-11-24 22:37:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestConsul_Service_Should_Be_Re_Reregistered_On_Change(t *testing.T) {
|
2016-02-19 03:19:25 +00:00
|
|
|
t.Parallel()
|
2015-11-24 22:37:14 +00:00
|
|
|
c := newConsulService()
|
2015-11-25 20:06:14 +00:00
|
|
|
task := newTask()
|
2015-11-24 22:37:14 +00:00
|
|
|
s1 := structs.Service{
|
|
|
|
Name: "example-cache-redis",
|
|
|
|
Tags: []string{"global"},
|
|
|
|
PortLabel: "db",
|
|
|
|
}
|
|
|
|
task.Services = append(task.Services, &s1)
|
2015-12-14 23:47:01 +00:00
|
|
|
alloc := mock.Alloc()
|
|
|
|
serviceID := alloc.Services[s1.Name]
|
|
|
|
c.Register(task, alloc)
|
2015-11-24 22:37:14 +00:00
|
|
|
|
|
|
|
s1.Tags = []string{"frontcache"}
|
|
|
|
|
2015-11-26 09:03:16 +00:00
|
|
|
c.performSync()
|
2015-11-24 22:37:14 +00:00
|
|
|
|
2015-11-26 02:23:47 +00:00
|
|
|
if len(c.serviceStates) != 1 {
|
2015-11-24 22:37:14 +00:00
|
|
|
t.Fatal("We should be tracking one service")
|
|
|
|
}
|
|
|
|
|
2015-12-14 23:47:01 +00:00
|
|
|
if c.serviceStates[serviceID] != s1.Hash() {
|
|
|
|
t.Fatalf("Hash is %v, expected %v", c.serviceStates[serviceID], s1.Hash())
|
2015-11-24 22:37:14 +00:00
|
|
|
}
|
2015-11-24 20:34:26 +00:00
|
|
|
}
|
2015-11-25 19:20:36 +00:00
|
|
|
|
|
|
|
func TestConsul_AddCheck_To_Service(t *testing.T) {
|
2016-02-19 03:19:25 +00:00
|
|
|
t.Parallel()
|
2015-11-26 09:03:16 +00:00
|
|
|
apiClient := &mockConsulApiClient{}
|
2015-11-25 19:20:36 +00:00
|
|
|
c := newConsulService()
|
2015-11-26 09:03:16 +00:00
|
|
|
c.client = apiClient
|
2015-11-25 19:20:36 +00:00
|
|
|
task := newTask()
|
2015-11-26 02:23:47 +00:00
|
|
|
var checks []*structs.ServiceCheck
|
2015-11-25 19:20:36 +00:00
|
|
|
s1 := structs.Service{
|
|
|
|
Name: "example-cache-redis",
|
|
|
|
Tags: []string{"global"},
|
|
|
|
PortLabel: "db",
|
|
|
|
Checks: checks,
|
|
|
|
}
|
|
|
|
task.Services = append(task.Services, &s1)
|
2015-12-14 23:47:01 +00:00
|
|
|
c.Register(task, mock.Alloc())
|
2015-11-25 19:20:36 +00:00
|
|
|
|
|
|
|
check1 := structs.ServiceCheck{
|
|
|
|
Name: "alive",
|
|
|
|
Type: "tcp",
|
|
|
|
Interval: 10 * time.Second,
|
|
|
|
Timeout: 5 * time.Second,
|
|
|
|
}
|
|
|
|
|
2015-11-26 02:23:47 +00:00
|
|
|
s1.Checks = append(s1.Checks, &check1)
|
2015-11-25 19:20:36 +00:00
|
|
|
|
2015-11-26 09:03:16 +00:00
|
|
|
c.performSync()
|
|
|
|
if apiClient.checkRegisterCallCount != 1 {
|
|
|
|
t.Fatalf("Expected number of check registrations: %v, Actual: %v", 1, apiClient.checkRegisterCallCount)
|
2015-11-25 19:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
2015-11-26 02:37:51 +00:00
|
|
|
|
|
|
|
func TestConsul_ModifyCheck(t *testing.T) {
|
2016-02-19 03:19:25 +00:00
|
|
|
t.Parallel()
|
2015-11-26 09:03:16 +00:00
|
|
|
apiClient := &mockConsulApiClient{}
|
2015-11-26 02:37:51 +00:00
|
|
|
c := newConsulService()
|
2015-11-26 09:03:16 +00:00
|
|
|
c.client = apiClient
|
2015-11-26 02:37:51 +00:00
|
|
|
task := newTask()
|
|
|
|
var checks []*structs.ServiceCheck
|
|
|
|
s1 := structs.Service{
|
|
|
|
Name: "example-cache-redis",
|
|
|
|
Tags: []string{"global"},
|
|
|
|
PortLabel: "db",
|
|
|
|
Checks: checks,
|
|
|
|
}
|
|
|
|
task.Services = append(task.Services, &s1)
|
2015-12-14 23:47:01 +00:00
|
|
|
c.Register(task, mock.Alloc())
|
2015-11-26 02:37:51 +00:00
|
|
|
|
|
|
|
check1 := structs.ServiceCheck{
|
|
|
|
Name: "alive",
|
|
|
|
Type: "tcp",
|
|
|
|
Interval: 10 * time.Second,
|
|
|
|
Timeout: 5 * time.Second,
|
|
|
|
}
|
|
|
|
|
|
|
|
s1.Checks = append(s1.Checks, &check1)
|
|
|
|
|
2015-11-26 09:03:16 +00:00
|
|
|
c.performSync()
|
|
|
|
if apiClient.checkRegisterCallCount != 1 {
|
|
|
|
t.Fatalf("Expected number of check registrations: %v, Actual: %v", 1, apiClient.checkRegisterCallCount)
|
2015-11-26 02:37:51 +00:00
|
|
|
}
|
2015-11-26 09:03:16 +00:00
|
|
|
|
2015-11-26 02:37:51 +00:00
|
|
|
check1.Timeout = 2 * time.Second
|
2015-11-26 09:03:16 +00:00
|
|
|
c.performSync()
|
|
|
|
if apiClient.checkRegisterCallCount != 2 {
|
|
|
|
t.Fatalf("Expected number of check registrations: %v, Actual: %v", 2, apiClient.checkRegisterCallCount)
|
2015-11-26 02:37:51 +00:00
|
|
|
}
|
|
|
|
}
|
2015-12-11 18:08:57 +00:00
|
|
|
|
|
|
|
func TestConsul_FilterNomadServicesAndChecks(t *testing.T) {
|
2016-02-19 03:19:25 +00:00
|
|
|
t.Parallel()
|
2015-12-11 18:47:08 +00:00
|
|
|
c := newConsulService()
|
|
|
|
srvs := map[string]*consul.AgentService{
|
|
|
|
"foo-bar": {
|
|
|
|
ID: "foo-bar",
|
|
|
|
Service: "http-frontend",
|
|
|
|
Tags: []string{"global"},
|
|
|
|
Port: 8080,
|
|
|
|
Address: "10.10.1.11",
|
|
|
|
},
|
2015-12-14 19:14:22 +00:00
|
|
|
"nomad-registered-service-2121212": {
|
|
|
|
ID: "nomad-registered-service-2121212",
|
2015-12-11 18:47:08 +00:00
|
|
|
Service: "identity-service",
|
|
|
|
Tags: []string{"global"},
|
|
|
|
Port: 8080,
|
|
|
|
Address: "10.10.1.11",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2015-12-11 22:14:04 +00:00
|
|
|
expSrvcs := map[string]*consul.AgentService{
|
2015-12-14 19:14:22 +00:00
|
|
|
"nomad-registered-service-2121212": {
|
|
|
|
ID: "nomad-registered-service-2121212",
|
2015-12-11 22:14:04 +00:00
|
|
|
Service: "identity-service",
|
|
|
|
Tags: []string{"global"},
|
|
|
|
Port: 8080,
|
|
|
|
Address: "10.10.1.11",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2015-12-11 18:47:08 +00:00
|
|
|
nomadServices := c.filterConsulServices(srvs)
|
2015-12-11 22:14:04 +00:00
|
|
|
if !reflect.DeepEqual(expSrvcs, nomadServices) {
|
|
|
|
t.Fatalf("Expected: %v, Actual: %v", expSrvcs, nomadServices)
|
2015-12-11 18:47:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nomadServices = c.filterConsulServices(nil)
|
|
|
|
if len(nomadServices) != 0 {
|
|
|
|
t.Fatalf("Expected number of services: %v, Actual: %v", 0, len(nomadServices))
|
|
|
|
}
|
|
|
|
|
|
|
|
chks := map[string]*consul.AgentCheck{
|
|
|
|
"foo-bar-chk": {
|
|
|
|
CheckID: "foo-bar-chk",
|
|
|
|
ServiceID: "foo-bar",
|
|
|
|
Name: "alive",
|
|
|
|
},
|
|
|
|
"212121212": {
|
|
|
|
CheckID: "212121212",
|
2015-12-14 19:14:22 +00:00
|
|
|
ServiceID: "nomad-registered-service-2121212",
|
2015-12-11 18:47:08 +00:00
|
|
|
Name: "ping",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2015-12-11 22:14:04 +00:00
|
|
|
expChks := map[string]*consul.AgentCheck{
|
|
|
|
"212121212": {
|
|
|
|
CheckID: "212121212",
|
2015-12-14 19:14:22 +00:00
|
|
|
ServiceID: "nomad-registered-service-2121212",
|
2015-12-11 22:14:04 +00:00
|
|
|
Name: "ping",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2015-12-11 18:47:08 +00:00
|
|
|
nomadChecks := c.filterConsulChecks(chks)
|
2015-12-11 22:14:04 +00:00
|
|
|
if !reflect.DeepEqual(expChks, nomadChecks) {
|
|
|
|
t.Fatalf("Expected: %v, Actual: %v", expChks, nomadChecks)
|
|
|
|
}
|
|
|
|
|
2015-12-11 18:47:08 +00:00
|
|
|
if len(nomadChecks) != 1 {
|
|
|
|
t.Fatalf("Expected number of checks: %v, Actual: %v", 1, len(nomadChecks))
|
|
|
|
}
|
|
|
|
|
|
|
|
nomadChecks = c.filterConsulChecks(nil)
|
|
|
|
if len(nomadChecks) != 0 {
|
|
|
|
t.Fatalf("Expected number of checks: %v, Actual: %v", 0, len(nomadChecks))
|
|
|
|
}
|
|
|
|
|
2015-12-11 18:08:57 +00:00
|
|
|
}
|