github.com/maier/nomad@v0.4.1-0.20161110003312-a9e3d0b8549d/command/agent/consul/syncer_test.go (about) 1 package consul 2 3 import ( 4 "log" 5 "net" 6 "os" 7 "reflect" 8 "testing" 9 "time" 10 11 "github.com/hashicorp/consul/api" 12 "github.com/hashicorp/nomad/nomad/structs" 13 "github.com/hashicorp/nomad/nomad/structs/config" 14 ) 15 16 const ( 17 allocID = "12" 18 serviceRegPrefix = "test" 19 serviceGroupName = "executor" 20 ) 21 22 var logger = log.New(os.Stdout, "", log.LstdFlags) 23 24 func TestCheckRegistration(t *testing.T) { 25 cs, err := NewSyncer(config.DefaultConsulConfig(), make(chan struct{}), logger) 26 if err != nil { 27 t.Fatalf("Err: %v", err) 28 } 29 30 check1 := structs.ServiceCheck{ 31 Name: "check-foo-1", 32 Type: structs.ServiceCheckTCP, 33 Interval: 30 * time.Second, 34 Timeout: 5 * time.Second, 35 InitialStatus: api.HealthPassing, 36 } 37 check2 := structs.ServiceCheck{ 38 Name: "check1", 39 Type: "tcp", 40 PortLabel: "port2", 41 Interval: 3 * time.Second, 42 Timeout: 1 * time.Second, 43 } 44 check3 := structs.ServiceCheck{ 45 Name: "check3", 46 Type: "http", 47 PortLabel: "port3", 48 Path: "/health?p1=1&p2=2", 49 Interval: 3 * time.Second, 50 Timeout: 1 * time.Second, 51 } 52 service1 := structs.Service{ 53 Name: "foo-1", 54 Tags: []string{"tag1", "tag2"}, 55 PortLabel: "port1", 56 Checks: []*structs.ServiceCheck{ 57 &check1, &check2, 58 }, 59 } 60 task := structs.Task{ 61 Name: "foo", 62 Services: []*structs.Service{&service1}, 63 Resources: &structs.Resources{ 64 Networks: []*structs.NetworkResource{ 65 &structs.NetworkResource{ 66 IP: "10.10.11.5", 67 DynamicPorts: []structs.Port{ 68 structs.Port{ 69 Label: "port1", 70 Value: 20002, 71 }, 72 structs.Port{ 73 Label: "port2", 74 Value: 20003, 75 }, 76 structs.Port{ 77 Label: "port3", 78 Value: 20004, 79 }, 80 }, 81 }, 82 }, 83 }, 84 } 85 cs.SetAddrFinder(task.FindHostAndPortFor) 86 srvReg, _ := cs.createService(&service1, "domain", "key") 87 check1Reg, _ := cs.createCheckReg(&check1, srvReg) 88 check2Reg, _ := cs.createCheckReg(&check2, srvReg) 89 check3Reg, _ := cs.createCheckReg(&check3, srvReg) 90 91 expected := "10.10.11.5:20002" 92 if check1Reg.TCP != expected { 93 t.Fatalf("expected: %v, actual: %v", expected, check1Reg.TCP) 94 } 95 96 expected = "10.10.11.5:20003" 97 if check2Reg.TCP != expected { 98 t.Fatalf("expected: %v, actual: %v", expected, check2Reg.TCP) 99 } 100 101 expected = "http://10.10.11.5:20004/health?p1=1&p2=2" 102 if check3Reg.HTTP != expected { 103 t.Fatalf("expected: %v, actual: %v", expected, check3Reg.HTTP) 104 } 105 106 expected = api.HealthPassing 107 if check1Reg.Status != expected { 108 t.Fatalf("expected: %v, actual: %v", expected, check1Reg.Status) 109 } 110 } 111 112 func TestConsulServiceRegisterServices(t *testing.T) { 113 cs, err := NewSyncer(config.DefaultConsulConfig(), nil, logger) 114 if err != nil { 115 t.Fatalf("Err: %v", err) 116 } 117 defer cs.Shutdown() 118 // Skipping the test if consul isn't present 119 if !cs.consulPresent() { 120 t.Skip("skipping because consul isn't present") 121 } 122 123 service1 := &structs.Service{Name: "foo", Tags: []string{"a", "b"}} 124 service2 := &structs.Service{Name: "foo"} 125 services := map[ServiceKey]*structs.Service{ 126 GenerateServiceKey(service1): service1, 127 GenerateServiceKey(service2): service2, 128 } 129 130 // Call SetServices to update services in consul 131 if err := cs.SetServices(serviceGroupName, services); err != nil { 132 t.Fatalf("error setting services: %v", err) 133 } 134 135 // Manually call SyncServers to cause a synchronous consul update 136 if err := cs.SyncServices(); err != nil { 137 t.Fatalf("error syncing services: %v", err) 138 } 139 140 numservices := len(cs.flattenedServices()) 141 if numservices != 2 { 142 t.Fatalf("expected 2 services but found %d", numservices) 143 } 144 145 numchecks := len(cs.flattenedChecks()) 146 if numchecks != 0 { 147 t.Fatalf("expected 0 checks but found %d", numchecks) 148 } 149 150 // Assert services are in consul 151 agentServices, err := cs.client.Agent().Services() 152 if err != nil { 153 t.Fatalf("error querying consul services: %v", err) 154 } 155 found := 0 156 for id, as := range agentServices { 157 if id == "consul" { 158 found++ 159 continue 160 } 161 if _, ok := services[ServiceKey(as.Service)]; ok { 162 found++ 163 continue 164 } 165 t.Errorf("unexpected service in consul: %s", id) 166 } 167 if found != 3 { 168 t.Fatalf("expected 3 services in consul but found %d:\nconsul: %#v", len(agentServices), agentServices) 169 } 170 171 agentChecks, err := cs.queryChecks() 172 if err != nil { 173 t.Fatalf("error querying consul checks: %v", err) 174 } 175 if len(agentChecks) != numchecks { 176 t.Fatalf("expected %d checks in consul but found %d:\n%#v", numservices, len(agentChecks), agentChecks) 177 } 178 } 179 180 func TestConsulServiceUpdateService(t *testing.T) { 181 cs, err := NewSyncer(config.DefaultConsulConfig(), nil, logger) 182 if err != nil { 183 t.Fatalf("Err: %v", err) 184 } 185 defer cs.Shutdown() 186 // Skipping the test if consul isn't present 187 if !cs.consulPresent() { 188 t.Skip("skipping because consul isn't present") 189 } 190 cs.SetAddrFinder(func(h string) (string, int) { 191 a, pstr, _ := net.SplitHostPort(h) 192 p, _ := net.LookupPort("tcp", pstr) 193 return a, p 194 }) 195 196 service1 := &structs.Service{Name: "foo1", Tags: []string{"a", "b"}} 197 service2 := &structs.Service{Name: "foo2"} 198 services := map[ServiceKey]*structs.Service{ 199 GenerateServiceKey(service1): service1, 200 GenerateServiceKey(service2): service2, 201 } 202 if err := cs.SetServices(serviceGroupName, services); err != nil { 203 t.Fatalf("error setting services: %v", err) 204 } 205 if err := cs.SyncServices(); err != nil { 206 t.Fatalf("error syncing services: %v", err) 207 } 208 209 // Now update both services 210 service1 = &structs.Service{Name: "foo1", Tags: []string{"a", "z"}} 211 service2 = &structs.Service{Name: "foo2", PortLabel: ":8899"} 212 service3 := &structs.Service{Name: "foo3"} 213 services = map[ServiceKey]*structs.Service{ 214 GenerateServiceKey(service1): service1, 215 GenerateServiceKey(service2): service2, 216 GenerateServiceKey(service3): service3, 217 } 218 if err := cs.SetServices(serviceGroupName, services); err != nil { 219 t.Fatalf("error setting services: %v", err) 220 } 221 if err := cs.SyncServices(); err != nil { 222 t.Fatalf("error syncing services: %v", err) 223 } 224 225 agentServices, err := cs.queryAgentServices() 226 if err != nil { 227 t.Fatalf("error querying consul services: %v", err) 228 } 229 if len(agentServices) != 3 { 230 t.Fatalf("expected 3 services in consul but found %d:\n%#v", len(agentServices), agentServices) 231 } 232 consulServices := make(map[string]*api.AgentService, 3) 233 for _, as := range agentServices { 234 consulServices[as.ID] = as 235 } 236 237 found := 0 238 for _, s := range cs.flattenedServices() { 239 // Assert sure changes were applied to internal state 240 switch s.Name { 241 case "foo1": 242 found++ 243 if !reflect.DeepEqual(service1.Tags, s.Tags) { 244 t.Errorf("incorrect tags on foo1:\n expected: %v\n found: %v", service1.Tags, s.Tags) 245 } 246 case "foo2": 247 found++ 248 if s.Address != "" { 249 t.Errorf("expected empty host on foo2 but found %q", s.Address) 250 } 251 if s.Port != 8899 { 252 t.Errorf("expected port 8899 on foo2 but found %d", s.Port) 253 } 254 case "foo3": 255 found++ 256 default: 257 t.Errorf("unexpected service: %s", s.Name) 258 } 259 260 // Assert internal state equals consul's state 261 cs, ok := consulServices[s.ID] 262 if !ok { 263 t.Errorf("service not in consul: %s id: %s", s.Name, s.ID) 264 continue 265 } 266 if !reflect.DeepEqual(s.Tags, cs.Tags) { 267 t.Errorf("mismatched tags in syncer state and consul for %s:\nsyncer: %v\nconsul: %v", s.Name, s.Tags, cs.Tags) 268 } 269 if cs.Port != s.Port { 270 t.Errorf("mismatched port in syncer state and consul for %s\nsyncer: %v\nconsul: %v", s.Name, s.Port, cs.Port) 271 } 272 if cs.Address != s.Address { 273 t.Errorf("mismatched address in syncer state and consul for %s\nsyncer: %v\nconsul: %v", s.Name, s.Address, cs.Address) 274 } 275 } 276 if found != 3 { 277 t.Fatalf("expected 3 services locally but found %d", found) 278 } 279 }