github.com/ranjib/nomad@v0.1.1-0.20160225204057-97751b02f70b/client/consul_test.go (about)

     1  package client
     2  
     3  import (
     4  	"fmt"
     5  	consul "github.com/hashicorp/consul/api"
     6  	"github.com/hashicorp/nomad/nomad/mock"
     7  	"github.com/hashicorp/nomad/nomad/structs"
     8  	"log"
     9  	"os"
    10  	"reflect"
    11  	"testing"
    12  	"time"
    13  )
    14  
    15  type mockConsulApiClient struct {
    16  	serviceRegisterCallCount   int
    17  	checkRegisterCallCount     int
    18  	checkDeregisterCallCount   int
    19  	serviceDeregisterCallCount int
    20  }
    21  
    22  func (a *mockConsulApiClient) CheckRegister(check *consul.AgentCheckRegistration) error {
    23  	a.checkRegisterCallCount += 1
    24  	return nil
    25  }
    26  
    27  func (a *mockConsulApiClient) CheckDeregister(checkID string) error {
    28  	a.checkDeregisterCallCount += 1
    29  	return nil
    30  }
    31  
    32  func (a *mockConsulApiClient) ServiceRegister(service *consul.AgentServiceRegistration) error {
    33  	a.serviceRegisterCallCount += 1
    34  	return nil
    35  }
    36  
    37  func (a *mockConsulApiClient) ServiceDeregister(serviceID string) error {
    38  	a.serviceDeregisterCallCount += 1
    39  	return nil
    40  }
    41  
    42  func (a *mockConsulApiClient) Services() (map[string]*consul.AgentService, error) {
    43  	return make(map[string]*consul.AgentService), nil
    44  }
    45  
    46  func (a *mockConsulApiClient) Checks() (map[string]*consul.AgentCheck, error) {
    47  	return make(map[string]*consul.AgentCheck), nil
    48  }
    49  
    50  func newConsulService() *ConsulService {
    51  	logger := log.New(os.Stdout, "logger: ", log.Lshortfile)
    52  	c, _ := NewConsulService(&consulServiceConfig{logger, "", "", "", false, false, &structs.Node{}})
    53  	c.client = &mockConsulApiClient{}
    54  	return c
    55  }
    56  
    57  func newTask() *structs.Task {
    58  	var services []*structs.Service
    59  	return &structs.Task{
    60  		Name:     "redis",
    61  		Services: services,
    62  		Resources: &structs.Resources{
    63  			Networks: []*structs.NetworkResource{
    64  				{
    65  					IP:           "10.10.0.1",
    66  					DynamicPorts: []structs.Port{{"db", 20413}},
    67  				},
    68  			},
    69  		},
    70  	}
    71  }
    72  
    73  func TestConsul_MakeChecks(t *testing.T) {
    74  	service := &structs.Service{
    75  		Name: "Bar",
    76  		Checks: []*structs.ServiceCheck{
    77  			{
    78  				Type:     "http",
    79  				Path:     "/foo/bar",
    80  				Interval: 10 * time.Second,
    81  				Timeout:  2 * time.Second,
    82  			},
    83  			{
    84  				Type:     "http",
    85  				Protocol: "https",
    86  				Path:     "/foo/bar",
    87  				Interval: 10 * time.Second,
    88  				Timeout:  2 * time.Second,
    89  			},
    90  			{
    91  				Type:     "tcp",
    92  				Interval: 10 * time.Second,
    93  				Timeout:  2 * time.Second,
    94  			},
    95  		},
    96  	}
    97  
    98  	c := newConsulService()
    99  	serviceID := fmt.Sprintf("%s-1234", structs.NomadConsulPrefix)
   100  
   101  	check1 := c.makeCheck(serviceID, service.Checks[0], "10.10.0.1", 8090)
   102  	check2 := c.makeCheck(serviceID, service.Checks[1], "10.10.0.1", 8090)
   103  	check3 := c.makeCheck(serviceID, service.Checks[2], "10.10.0.1", 8090)
   104  
   105  	if check1.HTTP != "http://10.10.0.1:8090/foo/bar" {
   106  		t.Fatalf("Invalid http url for check: %v", check1.HTTP)
   107  	}
   108  
   109  	if check2.HTTP != "https://10.10.0.1:8090/foo/bar" {
   110  		t.Fatalf("Invalid http url for check: %v", check2.HTTP)
   111  	}
   112  
   113  	if check3.TCP != "10.10.0.1:8090" {
   114  		t.Fatalf("Invalid tcp check: %v", check3.TCP)
   115  	}
   116  }
   117  
   118  func TestConsul_InvalidPortLabelForService(t *testing.T) {
   119  	task := &structs.Task{
   120  		Name:   "foo",
   121  		Driver: "docker",
   122  		Resources: &structs.Resources{
   123  			CPU:      500,
   124  			MemoryMB: 1024,
   125  			DiskMB:   1024,
   126  			IOPS:     10,
   127  			Networks: []*structs.NetworkResource{
   128  				{
   129  					Device: "eth0",
   130  					CIDR:   "255.255.0.0/16",
   131  					MBits:  10,
   132  					ReservedPorts: []structs.Port{
   133  						{
   134  							Label: "http",
   135  							Value: 8080,
   136  						},
   137  						{
   138  							Label: "ssh",
   139  							Value: 2026,
   140  						},
   141  					},
   142  				},
   143  			},
   144  		},
   145  	}
   146  	service := &structs.Service{
   147  		Name:      "foo",
   148  		Tags:      []string{"a", "b"},
   149  		PortLabel: "https",
   150  		Checks:    make([]*structs.ServiceCheck, 0),
   151  	}
   152  
   153  	c := newConsulService()
   154  	if err := c.registerService(service, task, mock.Alloc()); err == nil {
   155  		t.Fatalf("Service should be invalid")
   156  	}
   157  }
   158  
   159  func TestConsul_Services_Deleted_From_Task(t *testing.T) {
   160  	c := newConsulService()
   161  	task := structs.Task{
   162  		Name: "redis",
   163  		Services: []*structs.Service{
   164  			&structs.Service{
   165  				Name:      "example-cache-redis",
   166  				Tags:      []string{"global"},
   167  				PortLabel: "db",
   168  			},
   169  		},
   170  		Resources: &structs.Resources{
   171  			Networks: []*structs.NetworkResource{
   172  				{
   173  					IP:           "10.10.0.1",
   174  					DynamicPorts: []structs.Port{{"db", 20413}},
   175  				},
   176  			},
   177  		},
   178  	}
   179  	c.Register(&task, mock.Alloc())
   180  	if len(c.serviceStates) != 1 {
   181  		t.Fatalf("Expected tracked services: %v, Actual: %v", 1, len(c.serviceStates))
   182  	}
   183  	task.Services = []*structs.Service{}
   184  
   185  	c.performSync()
   186  	if len(c.serviceStates) != 0 {
   187  		t.Fatalf("Expected tracked services: %v, Actual: %v", 0, len(c.serviceStates))
   188  	}
   189  }
   190  
   191  func TestConsul_Service_Should_Be_Re_Reregistered_On_Change(t *testing.T) {
   192  	c := newConsulService()
   193  	task := newTask()
   194  	s1 := structs.Service{
   195  		Name:      "example-cache-redis",
   196  		Tags:      []string{"global"},
   197  		PortLabel: "db",
   198  	}
   199  	task.Services = append(task.Services, &s1)
   200  	alloc := mock.Alloc()
   201  	serviceID := alloc.Services[s1.Name]
   202  	c.Register(task, alloc)
   203  
   204  	s1.Tags = []string{"frontcache"}
   205  
   206  	c.performSync()
   207  
   208  	if len(c.serviceStates) != 1 {
   209  		t.Fatal("We should be tracking one service")
   210  	}
   211  
   212  	if c.serviceStates[serviceID] != s1.Hash() {
   213  		t.Fatalf("Hash is %v, expected %v", c.serviceStates[serviceID], s1.Hash())
   214  	}
   215  }
   216  
   217  func TestConsul_AddCheck_To_Service(t *testing.T) {
   218  	apiClient := &mockConsulApiClient{}
   219  	c := newConsulService()
   220  	c.client = apiClient
   221  	task := newTask()
   222  	var checks []*structs.ServiceCheck
   223  	s1 := structs.Service{
   224  		Name:      "example-cache-redis",
   225  		Tags:      []string{"global"},
   226  		PortLabel: "db",
   227  		Checks:    checks,
   228  	}
   229  	task.Services = append(task.Services, &s1)
   230  	c.Register(task, mock.Alloc())
   231  
   232  	check1 := structs.ServiceCheck{
   233  		Name:     "alive",
   234  		Type:     "tcp",
   235  		Interval: 10 * time.Second,
   236  		Timeout:  5 * time.Second,
   237  	}
   238  
   239  	s1.Checks = append(s1.Checks, &check1)
   240  
   241  	c.performSync()
   242  	if apiClient.checkRegisterCallCount != 1 {
   243  		t.Fatalf("Expected number of check registrations: %v, Actual: %v", 1, apiClient.checkRegisterCallCount)
   244  	}
   245  }
   246  
   247  func TestConsul_ModifyCheck(t *testing.T) {
   248  	apiClient := &mockConsulApiClient{}
   249  	c := newConsulService()
   250  	c.client = apiClient
   251  	task := newTask()
   252  	var checks []*structs.ServiceCheck
   253  	s1 := structs.Service{
   254  		Name:      "example-cache-redis",
   255  		Tags:      []string{"global"},
   256  		PortLabel: "db",
   257  		Checks:    checks,
   258  	}
   259  	task.Services = append(task.Services, &s1)
   260  	c.Register(task, mock.Alloc())
   261  
   262  	check1 := structs.ServiceCheck{
   263  		Name:     "alive",
   264  		Type:     "tcp",
   265  		Interval: 10 * time.Second,
   266  		Timeout:  5 * time.Second,
   267  	}
   268  
   269  	s1.Checks = append(s1.Checks, &check1)
   270  
   271  	c.performSync()
   272  	if apiClient.checkRegisterCallCount != 1 {
   273  		t.Fatalf("Expected number of check registrations: %v, Actual: %v", 1, apiClient.checkRegisterCallCount)
   274  	}
   275  
   276  	check1.Timeout = 2 * time.Second
   277  	c.performSync()
   278  	if apiClient.checkRegisterCallCount != 2 {
   279  		t.Fatalf("Expected number of check registrations: %v, Actual: %v", 2, apiClient.checkRegisterCallCount)
   280  	}
   281  }
   282  
   283  func TestConsul_FilterNomadServicesAndChecks(t *testing.T) {
   284  	c := newConsulService()
   285  	srvs := map[string]*consul.AgentService{
   286  		"foo-bar": {
   287  			ID:      "foo-bar",
   288  			Service: "http-frontend",
   289  			Tags:    []string{"global"},
   290  			Port:    8080,
   291  			Address: "10.10.1.11",
   292  		},
   293  		"nomad-registered-service-2121212": {
   294  			ID:      "nomad-registered-service-2121212",
   295  			Service: "identity-service",
   296  			Tags:    []string{"global"},
   297  			Port:    8080,
   298  			Address: "10.10.1.11",
   299  		},
   300  	}
   301  
   302  	expSrvcs := map[string]*consul.AgentService{
   303  		"nomad-registered-service-2121212": {
   304  			ID:      "nomad-registered-service-2121212",
   305  			Service: "identity-service",
   306  			Tags:    []string{"global"},
   307  			Port:    8080,
   308  			Address: "10.10.1.11",
   309  		},
   310  	}
   311  
   312  	nomadServices := c.filterConsulServices(srvs)
   313  	if !reflect.DeepEqual(expSrvcs, nomadServices) {
   314  		t.Fatalf("Expected: %v, Actual: %v", expSrvcs, nomadServices)
   315  	}
   316  
   317  	nomadServices = c.filterConsulServices(nil)
   318  	if len(nomadServices) != 0 {
   319  		t.Fatalf("Expected number of services: %v, Actual: %v", 0, len(nomadServices))
   320  	}
   321  
   322  	chks := map[string]*consul.AgentCheck{
   323  		"foo-bar-chk": {
   324  			CheckID:   "foo-bar-chk",
   325  			ServiceID: "foo-bar",
   326  			Name:      "alive",
   327  		},
   328  		"212121212": {
   329  			CheckID:   "212121212",
   330  			ServiceID: "nomad-registered-service-2121212",
   331  			Name:      "ping",
   332  		},
   333  	}
   334  
   335  	expChks := map[string]*consul.AgentCheck{
   336  		"212121212": {
   337  			CheckID:   "212121212",
   338  			ServiceID: "nomad-registered-service-2121212",
   339  			Name:      "ping",
   340  		},
   341  	}
   342  
   343  	nomadChecks := c.filterConsulChecks(chks)
   344  	if !reflect.DeepEqual(expChks, nomadChecks) {
   345  		t.Fatalf("Expected: %v, Actual: %v", expChks, nomadChecks)
   346  	}
   347  
   348  	if len(nomadChecks) != 1 {
   349  		t.Fatalf("Expected number of checks: %v, Actual: %v", 1, len(nomadChecks))
   350  	}
   351  
   352  	nomadChecks = c.filterConsulChecks(nil)
   353  	if len(nomadChecks) != 0 {
   354  		t.Fatalf("Expected number of checks: %v, Actual: %v", 0, len(nomadChecks))
   355  	}
   356  
   357  }