2016-03-23 18:31:04 +00:00
|
|
|
package consul
|
|
|
|
|
|
|
|
import (
|
2016-03-23 23:25:53 +00:00
|
|
|
"fmt"
|
2016-03-23 18:31:04 +00:00
|
|
|
"log"
|
|
|
|
"os"
|
2016-03-23 23:25:53 +00:00
|
|
|
"reflect"
|
2016-03-23 18:31:04 +00:00
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2016-03-23 23:25:53 +00:00
|
|
|
"github.com/hashicorp/go-multierror"
|
2016-03-23 18:31:04 +00:00
|
|
|
"github.com/hashicorp/nomad/nomad/structs"
|
|
|
|
)
|
|
|
|
|
2016-04-12 05:55:19 +00:00
|
|
|
const (
|
|
|
|
allocID = "12"
|
|
|
|
)
|
|
|
|
|
2016-03-24 01:39:17 +00:00
|
|
|
var (
|
|
|
|
logger = log.New(os.Stdout, "", log.LstdFlags)
|
|
|
|
check1 = structs.ServiceCheck{
|
|
|
|
Name: "check-foo-1",
|
|
|
|
Type: structs.ServiceCheckTCP,
|
|
|
|
Interval: 30 * time.Second,
|
|
|
|
Timeout: 5 * time.Second,
|
|
|
|
}
|
|
|
|
service1 = structs.Service{
|
|
|
|
Name: "foo-1",
|
|
|
|
Tags: []string{"tag1", "tag2"},
|
|
|
|
PortLabel: "port1",
|
|
|
|
Checks: []*structs.ServiceCheck{
|
|
|
|
&check1,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
service2 = structs.Service{
|
|
|
|
Name: "foo-2",
|
|
|
|
Tags: []string{"tag1", "tag2"},
|
|
|
|
PortLabel: "port2",
|
|
|
|
}
|
|
|
|
)
|
2016-03-23 18:31:04 +00:00
|
|
|
|
|
|
|
func TestConsulServiceRegisterServices(t *testing.T) {
|
2016-04-12 05:55:19 +00:00
|
|
|
cs, err := NewConsulService(&ConsulConfig{}, logger)
|
2016-03-23 18:31:04 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
2016-03-23 22:36:46 +00:00
|
|
|
// Skipping the test if consul isn't present
|
|
|
|
if !cs.consulPresent() {
|
|
|
|
return
|
|
|
|
}
|
2016-03-24 01:39:17 +00:00
|
|
|
task := mockTask()
|
2016-05-14 07:43:25 +00:00
|
|
|
cs.SetServiceIdentifier(GenerateServiceIdentifier(allocID, task.Name))
|
2016-05-11 20:29:56 +00:00
|
|
|
cs.SetAddrFinder(task.FindHostAndPortFor)
|
|
|
|
if err := cs.SyncServices(task.Services); err != nil {
|
2016-03-23 18:31:04 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
2016-03-23 23:25:53 +00:00
|
|
|
defer cs.Shutdown()
|
2016-03-24 01:39:17 +00:00
|
|
|
|
2016-05-14 07:43:25 +00:00
|
|
|
service1ID := service1.ID(GenerateServiceIdentifier(allocID, task.Name))
|
|
|
|
service2ID := service2.ID(GenerateServiceIdentifier(allocID, task.Name))
|
2016-03-24 01:39:17 +00:00
|
|
|
if err := servicesPresent(t, []string{service1ID, service2ID}, cs); err != nil {
|
2016-03-23 23:25:53 +00:00
|
|
|
t.Fatalf("err : %v", err)
|
2016-03-23 18:31:04 +00:00
|
|
|
}
|
2016-03-24 01:39:17 +00:00
|
|
|
if err := checksPresent(t, []string{check1.Hash(service1ID)}, cs); err != nil {
|
2016-03-23 23:25:53 +00:00
|
|
|
t.Fatalf("err : %v", err)
|
|
|
|
}
|
|
|
|
}
|
2016-03-23 18:31:04 +00:00
|
|
|
|
2016-03-23 23:25:53 +00:00
|
|
|
func TestConsulServiceUpdateService(t *testing.T) {
|
2016-04-12 05:55:19 +00:00
|
|
|
cs, err := NewConsulService(&ConsulConfig{}, logger)
|
2016-03-23 23:25:53 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
|
|
|
// Skipping the test if consul isn't present
|
|
|
|
if !cs.consulPresent() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-03-24 01:39:17 +00:00
|
|
|
task := mockTask()
|
2016-05-14 07:43:25 +00:00
|
|
|
cs.SetServiceIdentifier(GenerateServiceIdentifier(allocID, task.Name))
|
2016-05-11 20:29:56 +00:00
|
|
|
cs.SetAddrFinder(task.FindHostAndPortFor)
|
|
|
|
if err := cs.SyncServices(task.Services); err != nil {
|
2016-03-23 23:25:53 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
defer cs.Shutdown()
|
|
|
|
|
|
|
|
//Update Service defn 1
|
|
|
|
newTags := []string{"tag3"}
|
|
|
|
task.Services[0].Tags = newTags
|
2016-05-11 20:29:56 +00:00
|
|
|
if err := cs.SyncServices(task.Services); err != nil {
|
2016-03-23 18:31:04 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
2016-03-23 23:25:53 +00:00
|
|
|
// Make sure all the services and checks are still present
|
2016-05-14 07:43:25 +00:00
|
|
|
service1ID := service1.ID(GenerateServiceIdentifier(allocID, task.Name))
|
|
|
|
service2ID := service2.ID(GenerateServiceIdentifier(allocID, task.Name))
|
2016-03-24 01:39:17 +00:00
|
|
|
if err := servicesPresent(t, []string{service1ID, service2ID}, cs); err != nil {
|
2016-03-23 23:25:53 +00:00
|
|
|
t.Fatalf("err : %v", err)
|
|
|
|
}
|
2016-03-24 01:39:17 +00:00
|
|
|
if err := checksPresent(t, []string{check1.Hash(service1ID)}, cs); err != nil {
|
2016-03-23 23:25:53 +00:00
|
|
|
t.Fatalf("err : %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// check if service defn 1 has been updated
|
|
|
|
services, err := cs.client.Agent().Services()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("errL: %v", err)
|
|
|
|
}
|
2016-03-24 01:39:17 +00:00
|
|
|
srv, _ := services[service1ID]
|
2016-03-23 23:25:53 +00:00
|
|
|
if !reflect.DeepEqual(srv.Tags, newTags) {
|
|
|
|
t.Fatalf("expected tags: %v, actual: %v", newTags, srv.Tags)
|
2016-03-23 18:31:04 +00:00
|
|
|
}
|
2016-03-23 23:25:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func servicesPresent(t *testing.T, serviceIDs []string, consulService *ConsulService) error {
|
|
|
|
var mErr multierror.Error
|
|
|
|
services, err := consulService.client.Agent().Services()
|
|
|
|
if err != nil {
|
2016-03-23 18:31:04 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
2016-03-23 23:25:53 +00:00
|
|
|
for _, serviceID := range serviceIDs {
|
|
|
|
if _, ok := services[serviceID]; !ok {
|
|
|
|
mErr.Errors = append(mErr.Errors, fmt.Errorf("service ID %q not synced", serviceID))
|
|
|
|
}
|
2016-03-23 18:31:04 +00:00
|
|
|
}
|
2016-03-23 23:25:53 +00:00
|
|
|
return mErr.ErrorOrNil()
|
|
|
|
}
|
|
|
|
|
|
|
|
func checksPresent(t *testing.T, checkIDs []string, consulService *ConsulService) error {
|
|
|
|
var mErr multierror.Error
|
|
|
|
checks, err := consulService.client.Agent().Checks()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
2016-03-23 18:31:04 +00:00
|
|
|
}
|
|
|
|
|
2016-03-23 23:25:53 +00:00
|
|
|
for _, checkID := range checkIDs {
|
|
|
|
if _, ok := checks[checkID]; !ok {
|
|
|
|
mErr.Errors = append(mErr.Errors, fmt.Errorf("check ID %q not synced", checkID))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return mErr.ErrorOrNil()
|
2016-03-23 18:31:04 +00:00
|
|
|
}
|
2016-03-24 01:39:17 +00:00
|
|
|
|
|
|
|
func mockTask() *structs.Task {
|
|
|
|
task := structs.Task{
|
|
|
|
Name: "foo",
|
|
|
|
Services: []*structs.Service{&service1, &service2},
|
|
|
|
Resources: &structs.Resources{
|
|
|
|
Networks: []*structs.NetworkResource{
|
|
|
|
&structs.NetworkResource{
|
|
|
|
IP: "10.10.11.5",
|
|
|
|
DynamicPorts: []structs.Port{
|
|
|
|
structs.Port{
|
|
|
|
Label: "port1",
|
|
|
|
Value: 20002,
|
|
|
|
},
|
|
|
|
structs.Port{
|
|
|
|
Label: "port2",
|
|
|
|
Value: 20003,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
return &task
|
|
|
|
}
|