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  }