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