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 }