github.com/bigcommerce/nomad@v0.9.3-bc/nomad/serf_test.go (about) 1 package nomad 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "path" 8 "strings" 9 "testing" 10 "time" 11 12 "github.com/hashicorp/nomad/testutil" 13 "github.com/hashicorp/serf/serf" 14 ) 15 16 func TestNomad_JoinPeer(t *testing.T) { 17 t.Parallel() 18 s1 := TestServer(t, nil) 19 defer s1.Shutdown() 20 s2 := TestServer(t, func(c *Config) { 21 c.Region = "region2" 22 }) 23 defer s2.Shutdown() 24 TestJoin(t, s1, s2) 25 26 testutil.WaitForResult(func() (bool, error) { 27 if members := s1.Members(); len(members) != 2 { 28 return false, fmt.Errorf("bad: %#v", members) 29 } 30 if members := s2.Members(); len(members) != 2 { 31 return false, fmt.Errorf("bad: %#v", members) 32 } 33 return true, nil 34 }, func(err error) { 35 t.Fatalf("err: %v", err) 36 }) 37 38 testutil.WaitForResult(func() (bool, error) { 39 if len(s1.peers) != 2 { 40 return false, fmt.Errorf("bad: %#v", s1.peers) 41 } 42 if len(s2.peers) != 2 { 43 return false, fmt.Errorf("bad: %#v", s2.peers) 44 } 45 if len(s1.localPeers) != 1 { 46 return false, fmt.Errorf("bad: %#v", s1.localPeers) 47 } 48 if len(s2.localPeers) != 1 { 49 return false, fmt.Errorf("bad: %#v", s2.localPeers) 50 } 51 return true, nil 52 }, func(err error) { 53 t.Fatalf("err: %v", err) 54 }) 55 } 56 57 func TestNomad_RemovePeer(t *testing.T) { 58 t.Parallel() 59 s1 := TestServer(t, nil) 60 defer s1.Shutdown() 61 s2 := TestServer(t, func(c *Config) { 62 c.Region = "region2" 63 }) 64 defer s2.Shutdown() 65 TestJoin(t, s1, s2) 66 67 testutil.WaitForResult(func() (bool, error) { 68 if members := s1.Members(); len(members) != 2 { 69 return false, fmt.Errorf("bad: %#v", members) 70 } 71 if members := s2.Members(); len(members) != 2 { 72 return false, fmt.Errorf("bad: %#v", members) 73 } 74 return true, nil 75 }, func(err error) { 76 t.Fatalf("err: %v", err) 77 }) 78 79 // Leave immediately 80 s2.Leave() 81 s2.Shutdown() 82 83 testutil.WaitForResult(func() (bool, error) { 84 if len(s1.peers) != 1 { 85 return false, fmt.Errorf("bad: %#v", s1.peers) 86 } 87 if len(s2.peers) != 1 { 88 return false, fmt.Errorf("bad: %#v", s2.peers) 89 } 90 return true, nil 91 }, func(err error) { 92 t.Fatalf("err: %v", err) 93 }) 94 } 95 96 func TestNomad_ReapPeer(t *testing.T) { 97 t.Parallel() 98 dir := tmpDir(t) 99 defer os.RemoveAll(dir) 100 s1 := TestServer(t, func(c *Config) { 101 c.NodeName = "node1" 102 c.BootstrapExpect = 3 103 c.DevMode = false 104 c.DevDisableBootstrap = true 105 c.DataDir = path.Join(dir, "node1") 106 }) 107 defer s1.Shutdown() 108 s2 := TestServer(t, func(c *Config) { 109 c.NodeName = "node2" 110 c.BootstrapExpect = 3 111 c.DevMode = false 112 c.DevDisableBootstrap = true 113 c.DataDir = path.Join(dir, "node2") 114 }) 115 defer s2.Shutdown() 116 s3 := TestServer(t, func(c *Config) { 117 c.NodeName = "node3" 118 c.BootstrapExpect = 3 119 c.DevMode = false 120 c.DevDisableBootstrap = true 121 c.DataDir = path.Join(dir, "node3") 122 }) 123 defer s3.Shutdown() 124 TestJoin(t, s1, s2, s3) 125 126 testutil.WaitForResult(func() (bool, error) { 127 // Retry the join to decrease flakiness 128 TestJoin(t, s1, s2, s3) 129 if members := s1.Members(); len(members) != 3 { 130 return false, fmt.Errorf("bad s1: %#v", members) 131 } 132 if members := s2.Members(); len(members) != 3 { 133 return false, fmt.Errorf("bad s2: %#v", members) 134 } 135 if members := s3.Members(); len(members) != 3 { 136 return false, fmt.Errorf("bad s3: %#v", members) 137 } 138 return true, nil 139 }, func(err error) { 140 t.Fatalf("err: %v", err) 141 }) 142 143 testutil.WaitForLeader(t, s1.RPC) 144 145 // Simulate a reap 146 mems := s1.Members() 147 var s2mem serf.Member 148 for _, m := range mems { 149 if strings.Contains(m.Name, s2.config.NodeName) { 150 s2mem = m 151 s2mem.Status = StatusReap 152 break 153 } 154 } 155 156 // Shutdown and then send the reap 157 s2.Shutdown() 158 s1.reconcileCh <- s2mem 159 s2.reconcileCh <- s2mem 160 s3.reconcileCh <- s2mem 161 162 testutil.WaitForResult(func() (bool, error) { 163 if len(s1.peers["global"]) != 2 { 164 return false, fmt.Errorf("bad: %#v", s1.peers["global"]) 165 } 166 peers, err := s1.numPeers() 167 if err != nil { 168 return false, fmt.Errorf("numPeers() failed: %v", err) 169 } 170 if peers != 2 { 171 return false, fmt.Errorf("bad: %#v", peers) 172 } 173 174 if len(s3.peers["global"]) != 2 { 175 return false, fmt.Errorf("bad: %#v", s1.peers["global"]) 176 } 177 peers, err = s3.numPeers() 178 if err != nil { 179 return false, fmt.Errorf("numPeers() failed: %v", err) 180 } 181 if peers != 2 { 182 return false, fmt.Errorf("bad: %#v", peers) 183 } 184 return true, nil 185 }, func(err error) { 186 t.Fatalf("err: %v", err) 187 }) 188 } 189 190 func TestNomad_BootstrapExpect(t *testing.T) { 191 t.Parallel() 192 dir := tmpDir(t) 193 defer os.RemoveAll(dir) 194 195 s1 := TestServer(t, func(c *Config) { 196 c.BootstrapExpect = 3 197 c.DevMode = false 198 c.DevDisableBootstrap = true 199 c.DataDir = path.Join(dir, "node1") 200 }) 201 defer s1.Shutdown() 202 s2 := TestServer(t, func(c *Config) { 203 c.BootstrapExpect = 3 204 c.DevMode = false 205 c.DevDisableBootstrap = true 206 c.DataDir = path.Join(dir, "node2") 207 }) 208 defer s2.Shutdown() 209 s3 := TestServer(t, func(c *Config) { 210 c.BootstrapExpect = 3 211 c.DevMode = false 212 c.DevDisableBootstrap = true 213 c.DataDir = path.Join(dir, "node3") 214 }) 215 defer s3.Shutdown() 216 TestJoin(t, s1, s2, s3) 217 218 testutil.WaitForResult(func() (bool, error) { 219 // Retry the join to decrease flakiness 220 TestJoin(t, s1, s2, s3) 221 peers, err := s1.numPeers() 222 if err != nil { 223 return false, err 224 } 225 if peers != 3 { 226 return false, fmt.Errorf("bad: %#v", peers) 227 } 228 peers, err = s2.numPeers() 229 if err != nil { 230 return false, err 231 } 232 if peers != 3 { 233 return false, fmt.Errorf("bad: %#v", peers) 234 } 235 peers, err = s3.numPeers() 236 if err != nil { 237 return false, err 238 } 239 if peers != 3 { 240 return false, fmt.Errorf("bad: %#v", peers) 241 } 242 if len(s1.localPeers) != 3 { 243 return false, fmt.Errorf("bad: %#v", s1.localPeers) 244 } 245 if len(s2.localPeers) != 3 { 246 return false, fmt.Errorf("bad: %#v", s2.localPeers) 247 } 248 if len(s3.localPeers) != 3 { 249 return false, fmt.Errorf("bad: %#v", s3.localPeers) 250 } 251 return true, nil 252 }, func(err error) { 253 t.Fatalf("err: %v", err) 254 }) 255 256 // Join a fourth server after quorum has already been formed and ensure 257 // there is no election 258 s4 := TestServer(t, func(c *Config) { 259 c.BootstrapExpect = 3 260 c.DevMode = false 261 c.DevDisableBootstrap = true 262 c.DataDir = path.Join(dir, "node4") 263 }) 264 defer s4.Shutdown() 265 266 // Make sure a leader is elected, grab the current term and then add in 267 // the fourth server. 268 testutil.WaitForLeader(t, s1.RPC) 269 termBefore := s1.raft.Stats()["last_log_term"] 270 271 var addresses []string 272 for _, s := range []*Server{s1, s2, s3} { 273 addr := fmt.Sprintf("127.0.0.1:%d", s.config.SerfConfig.MemberlistConfig.BindPort) 274 addresses = append(addresses, addr) 275 } 276 if _, err := s4.Join(addresses); err != nil { 277 t.Fatalf("err: %v", err) 278 } 279 280 // Wait for the new server to see itself added to the cluster. 281 var p4 int 282 testutil.WaitForResult(func() (bool, error) { 283 // Retry join to reduce flakiness 284 if _, err := s4.Join(addresses); err != nil { 285 t.Fatalf("err: %v", err) 286 } 287 p4, _ = s4.numPeers() 288 return p4 == 4, errors.New(fmt.Sprintf("%d", p4)) 289 }, func(err error) { 290 t.Fatalf("should have 4 peers: %v", err) 291 }) 292 293 // Make sure there's still a leader and that the term didn't change, 294 // so we know an election didn't occur. 295 testutil.WaitForLeader(t, s1.RPC) 296 termAfter := s1.raft.Stats()["last_log_term"] 297 if termAfter != termBefore { 298 t.Fatalf("looks like an election took place") 299 } 300 } 301 302 func TestNomad_BootstrapExpect_NonVoter(t *testing.T) { 303 t.Parallel() 304 dir := tmpDir(t) 305 defer os.RemoveAll(dir) 306 307 s1 := TestServer(t, func(c *Config) { 308 c.BootstrapExpect = 2 309 c.DevMode = false 310 c.DevDisableBootstrap = true 311 c.DataDir = path.Join(dir, "node1") 312 c.NonVoter = true 313 }) 314 defer s1.Shutdown() 315 s2 := TestServer(t, func(c *Config) { 316 c.BootstrapExpect = 2 317 c.DevMode = false 318 c.DevDisableBootstrap = true 319 c.DataDir = path.Join(dir, "node2") 320 c.NonVoter = true 321 }) 322 defer s2.Shutdown() 323 s3 := TestServer(t, func(c *Config) { 324 c.BootstrapExpect = 2 325 c.DevMode = false 326 c.DevDisableBootstrap = true 327 c.DataDir = path.Join(dir, "node3") 328 }) 329 defer s3.Shutdown() 330 TestJoin(t, s1, s2, s3) 331 332 // Assert that we do not bootstrap 333 testutil.AssertUntil(testutil.Timeout(time.Second), func() (bool, error) { 334 _, p := s1.getLeader() 335 if p != nil { 336 return false, fmt.Errorf("leader %v", p) 337 } 338 339 return true, nil 340 }, func(err error) { 341 t.Fatalf("should not have leader: %v", err) 342 }) 343 344 // Add the fourth server that is a voter 345 s4 := TestServer(t, func(c *Config) { 346 c.BootstrapExpect = 2 347 c.DevMode = false 348 c.DevDisableBootstrap = true 349 c.DataDir = path.Join(dir, "node4") 350 }) 351 defer s4.Shutdown() 352 TestJoin(t, s1, s2, s3, s4) 353 354 testutil.WaitForResult(func() (bool, error) { 355 // Retry the join to decrease flakiness 356 TestJoin(t, s1, s2, s3, s4) 357 peers, err := s1.numPeers() 358 if err != nil { 359 return false, err 360 } 361 if peers != 4 { 362 return false, fmt.Errorf("bad: %#v", peers) 363 } 364 peers, err = s2.numPeers() 365 if err != nil { 366 return false, err 367 } 368 if peers != 4 { 369 return false, fmt.Errorf("bad: %#v", peers) 370 } 371 peers, err = s3.numPeers() 372 if err != nil { 373 return false, err 374 } 375 if peers != 4 { 376 return false, fmt.Errorf("bad: %#v", peers) 377 } 378 peers, err = s4.numPeers() 379 if err != nil { 380 return false, err 381 } 382 if peers != 4 { 383 return false, fmt.Errorf("bad: %#v", peers) 384 } 385 386 if len(s1.localPeers) != 4 { 387 return false, fmt.Errorf("bad: %#v", s1.localPeers) 388 } 389 if len(s2.localPeers) != 4 { 390 return false, fmt.Errorf("bad: %#v", s2.localPeers) 391 } 392 if len(s3.localPeers) != 4 { 393 return false, fmt.Errorf("bad: %#v", s3.localPeers) 394 } 395 if len(s4.localPeers) != 4 { 396 return false, fmt.Errorf("bad: %#v", s3.localPeers) 397 } 398 399 _, p := s1.getLeader() 400 if p == nil { 401 return false, fmt.Errorf("no leader") 402 } 403 return true, nil 404 }, func(err error) { 405 t.Fatalf("err: %v", err) 406 }) 407 408 } 409 410 func TestNomad_BadExpect(t *testing.T) { 411 t.Parallel() 412 s1 := TestServer(t, func(c *Config) { 413 c.BootstrapExpect = 2 414 c.DevDisableBootstrap = true 415 }) 416 defer s1.Shutdown() 417 s2 := TestServer(t, func(c *Config) { 418 c.BootstrapExpect = 3 419 c.DevDisableBootstrap = true 420 }) 421 defer s2.Shutdown() 422 servers := []*Server{s1, s2} 423 TestJoin(t, s1, s2) 424 425 // Serf members should update 426 testutil.WaitForResult(func() (bool, error) { 427 for _, s := range servers { 428 members := s.Members() 429 if len(members) != 2 { 430 return false, fmt.Errorf("%d", len(members)) 431 } 432 } 433 return true, nil 434 }, func(err error) { 435 t.Fatalf("should have 2 peers: %v", err) 436 }) 437 438 // should still have no peers (because s2 is in expect=2 mode) 439 testutil.WaitForResult(func() (bool, error) { 440 for _, s := range servers { 441 p, _ := s.numPeers() 442 if p != 1 { 443 return false, fmt.Errorf("%d", p) 444 } 445 } 446 return true, nil 447 }, func(err error) { 448 t.Fatalf("should have 0 peers: %v", err) 449 }) 450 }