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  }