github.com/diptanu/nomad@v0.5.7-0.20170516172507-d72e86cbe3d9/command/agent/agent_test.go (about)

     1  package agent
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"log"
     8  	"net"
     9  	"os"
    10  	"strings"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/hashicorp/nomad/helper"
    15  	"github.com/hashicorp/nomad/nomad"
    16  	sconfig "github.com/hashicorp/nomad/nomad/structs/config"
    17  )
    18  
    19  func getPort() int {
    20  	addr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:0")
    21  	if err != nil {
    22  		panic(err)
    23  	}
    24  
    25  	l, err := net.ListenTCP("tcp", addr)
    26  	if err != nil {
    27  		panic(err)
    28  	}
    29  	defer l.Close()
    30  	return l.Addr().(*net.TCPAddr).Port
    31  }
    32  
    33  func tmpDir(t testing.TB) string {
    34  	dir, err := ioutil.TempDir("", "nomad")
    35  	if err != nil {
    36  		t.Fatalf("err: %v", err)
    37  	}
    38  	return dir
    39  }
    40  
    41  func makeAgent(t testing.TB, cb func(*Config)) (string, *Agent) {
    42  	dir := tmpDir(t)
    43  	conf := DevConfig()
    44  
    45  	// Customize the server configuration
    46  	config := nomad.DefaultConfig()
    47  	conf.NomadConfig = config
    48  
    49  	// Set the data_dir
    50  	conf.DataDir = dir
    51  	conf.NomadConfig.DataDir = dir
    52  
    53  	// Bind and set ports
    54  	conf.BindAddr = "127.0.0.1"
    55  	conf.Ports = &Ports{
    56  		HTTP: getPort(),
    57  		RPC:  getPort(),
    58  		Serf: getPort(),
    59  	}
    60  	conf.NodeName = fmt.Sprintf("Node %d", conf.Ports.RPC)
    61  	conf.Consul = sconfig.DefaultConsulConfig()
    62  	conf.Vault.Enabled = new(bool)
    63  
    64  	// Tighten the Serf timing
    65  	config.SerfConfig.MemberlistConfig.SuspicionMult = 2
    66  	config.SerfConfig.MemberlistConfig.RetransmitMult = 2
    67  	config.SerfConfig.MemberlistConfig.ProbeTimeout = 50 * time.Millisecond
    68  	config.SerfConfig.MemberlistConfig.ProbeInterval = 100 * time.Millisecond
    69  	config.SerfConfig.MemberlistConfig.GossipInterval = 100 * time.Millisecond
    70  
    71  	// Tighten the Raft timing
    72  	config.RaftConfig.LeaderLeaseTimeout = 20 * time.Millisecond
    73  	config.RaftConfig.HeartbeatTimeout = 40 * time.Millisecond
    74  	config.RaftConfig.ElectionTimeout = 40 * time.Millisecond
    75  	config.RaftConfig.StartAsLeader = true
    76  	config.RaftTimeout = 500 * time.Millisecond
    77  
    78  	if cb != nil {
    79  		cb(conf)
    80  	}
    81  
    82  	if err := conf.normalizeAddrs(); err != nil {
    83  		t.Fatalf("error normalizing config: %v", err)
    84  	}
    85  	agent, err := NewAgent(conf, os.Stderr)
    86  	if err != nil {
    87  		os.RemoveAll(dir)
    88  		t.Fatalf("err: %v", err)
    89  	}
    90  	return dir, agent
    91  }
    92  
    93  func TestAgent_RPCPing(t *testing.T) {
    94  	dir, agent := makeAgent(t, nil)
    95  	defer os.RemoveAll(dir)
    96  	defer agent.Shutdown()
    97  
    98  	var out struct{}
    99  	if err := agent.RPC("Status.Ping", struct{}{}, &out); err != nil {
   100  		t.Fatalf("err: %v", err)
   101  	}
   102  }
   103  
   104  func TestAgent_ServerConfig(t *testing.T) {
   105  	conf := DefaultConfig()
   106  	conf.DevMode = true // allow localhost for advertise addrs
   107  	a := &Agent{config: conf}
   108  
   109  	conf.AdvertiseAddrs.Serf = "127.0.0.1:4000"
   110  	conf.AdvertiseAddrs.RPC = "127.0.0.1:4001"
   111  	conf.AdvertiseAddrs.HTTP = "10.10.11.1:4005"
   112  
   113  	// Parses the advertise addrs correctly
   114  	if err := conf.normalizeAddrs(); err != nil {
   115  		t.Fatalf("error normalizing config: %v", err)
   116  	}
   117  	out, err := a.serverConfig()
   118  	if err != nil {
   119  		t.Fatalf("err: %s", err)
   120  	}
   121  	serfAddr := out.SerfConfig.MemberlistConfig.AdvertiseAddr
   122  	if serfAddr != "127.0.0.1" {
   123  		t.Fatalf("expect 127.0.0.1, got: %s", serfAddr)
   124  	}
   125  	serfPort := out.SerfConfig.MemberlistConfig.AdvertisePort
   126  	if serfPort != 4000 {
   127  		t.Fatalf("expected 4000, got: %d", serfPort)
   128  	}
   129  
   130  	// Assert addresses weren't changed
   131  	if addr := conf.AdvertiseAddrs.RPC; addr != "127.0.0.1:4001" {
   132  		t.Fatalf("bad rpc advertise addr: %#v", addr)
   133  	}
   134  	if addr := conf.AdvertiseAddrs.HTTP; addr != "10.10.11.1:4005" {
   135  		t.Fatalf("expect 10.11.11.1:4005, got: %v", addr)
   136  	}
   137  	if addr := conf.Addresses.RPC; addr != "0.0.0.0" {
   138  		t.Fatalf("expect 0.0.0.0, got: %v", addr)
   139  	}
   140  
   141  	// Sets up the ports properly
   142  	conf.Addresses.RPC = ""
   143  	conf.Addresses.Serf = ""
   144  	conf.Ports.RPC = 4003
   145  	conf.Ports.Serf = 4004
   146  
   147  	if err := conf.normalizeAddrs(); err != nil {
   148  		t.Fatalf("error normalizing config: %v", err)
   149  	}
   150  	out, err = a.serverConfig()
   151  	if err != nil {
   152  		t.Fatalf("err: %s", err)
   153  	}
   154  	if addr := out.RPCAddr.Port; addr != 4003 {
   155  		t.Fatalf("expect 4003, got: %d", out.RPCAddr.Port)
   156  	}
   157  	if port := out.SerfConfig.MemberlistConfig.BindPort; port != 4004 {
   158  		t.Fatalf("expect 4004, got: %d", port)
   159  	}
   160  
   161  	// Prefers advertise over bind addr
   162  	conf.BindAddr = "127.0.0.3"
   163  	conf.Addresses.HTTP = "127.0.0.2"
   164  	conf.Addresses.RPC = "127.0.0.2"
   165  	conf.Addresses.Serf = "127.0.0.2"
   166  	conf.AdvertiseAddrs.HTTP = "10.0.0.10"
   167  	conf.AdvertiseAddrs.RPC = ""
   168  	conf.AdvertiseAddrs.Serf = "10.0.0.12:4004"
   169  
   170  	if err := conf.normalizeAddrs(); err != nil {
   171  		t.Fatalf("error normalizing config: %v", err)
   172  	}
   173  	out, err = a.serverConfig()
   174  	fmt.Println(conf.Addresses.RPC)
   175  	if err != nil {
   176  		t.Fatalf("err: %s", err)
   177  	}
   178  	if addr := out.RPCAddr.IP.String(); addr != "127.0.0.2" {
   179  		t.Fatalf("expect 127.0.0.2, got: %s", addr)
   180  	}
   181  	if port := out.RPCAddr.Port; port != 4003 {
   182  		t.Fatalf("expect 4647, got: %d", port)
   183  	}
   184  	if addr := out.SerfConfig.MemberlistConfig.BindAddr; addr != "127.0.0.2" {
   185  		t.Fatalf("expect 127.0.0.2, got: %s", addr)
   186  	}
   187  	if port := out.SerfConfig.MemberlistConfig.BindPort; port != 4004 {
   188  		t.Fatalf("expect 4648, got: %d", port)
   189  	}
   190  	if addr := conf.Addresses.HTTP; addr != "127.0.0.2" {
   191  		t.Fatalf("expect 127.0.0.2, got: %s", addr)
   192  	}
   193  	if addr := conf.Addresses.RPC; addr != "127.0.0.2" {
   194  		t.Fatalf("expect 127.0.0.2, got: %s", addr)
   195  	}
   196  	if addr := conf.Addresses.Serf; addr != "127.0.0.2" {
   197  		t.Fatalf("expect 10.0.0.12, got: %s", addr)
   198  	}
   199  	if addr := conf.normalizedAddrs.HTTP; addr != "127.0.0.2:4646" {
   200  		t.Fatalf("expect 127.0.0.2:4646, got: %s", addr)
   201  	}
   202  	if addr := conf.normalizedAddrs.RPC; addr != "127.0.0.2:4003" {
   203  		t.Fatalf("expect 127.0.0.2:4003, got: %s", addr)
   204  	}
   205  	if addr := conf.normalizedAddrs.Serf; addr != "127.0.0.2:4004" {
   206  		t.Fatalf("expect 10.0.0.12:4004, got: %s", addr)
   207  	}
   208  	if addr := conf.AdvertiseAddrs.HTTP; addr != "10.0.0.10:4646" {
   209  		t.Fatalf("expect 10.0.0.10:4646, got: %s", addr)
   210  	}
   211  	if addr := conf.AdvertiseAddrs.RPC; addr != "127.0.0.2:4003" {
   212  		t.Fatalf("expect 127.0.0.2:4003, got: %s", addr)
   213  	}
   214  	if addr := conf.AdvertiseAddrs.Serf; addr != "10.0.0.12:4004" {
   215  		t.Fatalf("expect 10.0.0.12:4004, got: %s", addr)
   216  	}
   217  
   218  	conf.Server.NodeGCThreshold = "42g"
   219  	if err := conf.normalizeAddrs(); err != nil {
   220  		t.Fatalf("error normalizing config: %v", err)
   221  	}
   222  	out, err = a.serverConfig()
   223  	if err == nil || !strings.Contains(err.Error(), "unknown unit") {
   224  		t.Fatalf("expected unknown unit error, got: %#v", err)
   225  	}
   226  
   227  	conf.Server.NodeGCThreshold = "10s"
   228  	if err := conf.normalizeAddrs(); err != nil {
   229  		t.Fatalf("error normalizing config: %v", err)
   230  	}
   231  	out, err = a.serverConfig()
   232  	if threshold := out.NodeGCThreshold; threshold != time.Second*10 {
   233  		t.Fatalf("expect 10s, got: %s", threshold)
   234  	}
   235  
   236  	conf.Server.HeartbeatGrace = "42g"
   237  	if err := conf.normalizeAddrs(); err != nil {
   238  		t.Fatalf("error normalizing config: %v", err)
   239  	}
   240  	out, err = a.serverConfig()
   241  	if err == nil || !strings.Contains(err.Error(), "unknown unit") {
   242  		t.Fatalf("expected unknown unit error, got: %#v", err)
   243  	}
   244  
   245  	conf.Server.HeartbeatGrace = "37s"
   246  	if err := conf.normalizeAddrs(); err != nil {
   247  		t.Fatalf("error normalizing config: %v", err)
   248  	}
   249  	out, err = a.serverConfig()
   250  	if threshold := out.HeartbeatGrace; threshold != time.Second*37 {
   251  		t.Fatalf("expect 37s, got: %s", threshold)
   252  	}
   253  
   254  	// Defaults to the global bind addr
   255  	conf.Addresses.RPC = ""
   256  	conf.Addresses.Serf = ""
   257  	conf.Addresses.HTTP = ""
   258  	conf.AdvertiseAddrs.RPC = ""
   259  	conf.AdvertiseAddrs.HTTP = ""
   260  	conf.AdvertiseAddrs.Serf = ""
   261  	conf.Ports.HTTP = 4646
   262  	conf.Ports.RPC = 4647
   263  	conf.Ports.Serf = 4648
   264  	if err := conf.normalizeAddrs(); err != nil {
   265  		t.Fatalf("error normalizing config: %v", err)
   266  	}
   267  	out, err = a.serverConfig()
   268  	if err != nil {
   269  		t.Fatalf("err: %s", err)
   270  	}
   271  	if addr := out.RPCAddr.IP.String(); addr != "127.0.0.3" {
   272  		t.Fatalf("expect 127.0.0.3, got: %s", addr)
   273  	}
   274  	if addr := out.SerfConfig.MemberlistConfig.BindAddr; addr != "127.0.0.3" {
   275  		t.Fatalf("expect 127.0.0.3, got: %s", addr)
   276  	}
   277  	if addr := conf.Addresses.HTTP; addr != "127.0.0.3" {
   278  		t.Fatalf("expect 127.0.0.3, got: %s", addr)
   279  	}
   280  	if addr := conf.Addresses.RPC; addr != "127.0.0.3" {
   281  		t.Fatalf("expect 127.0.0.3, got: %s", addr)
   282  	}
   283  	if addr := conf.Addresses.Serf; addr != "127.0.0.3" {
   284  		t.Fatalf("expect 127.0.0.3, got: %s", addr)
   285  	}
   286  	if addr := conf.normalizedAddrs.HTTP; addr != "127.0.0.3:4646" {
   287  		t.Fatalf("expect 127.0.0.3:4646, got: %s", addr)
   288  	}
   289  	if addr := conf.normalizedAddrs.RPC; addr != "127.0.0.3:4647" {
   290  		t.Fatalf("expect 127.0.0.3:4647, got: %s", addr)
   291  	}
   292  	if addr := conf.normalizedAddrs.Serf; addr != "127.0.0.3:4648" {
   293  		t.Fatalf("expect 127.0.0.3:4648, got: %s", addr)
   294  	}
   295  
   296  	// Properly handles the bootstrap flags
   297  	conf.Server.BootstrapExpect = 1
   298  	out, err = a.serverConfig()
   299  	if err != nil {
   300  		t.Fatalf("err: %s", err)
   301  	}
   302  	if !out.Bootstrap {
   303  		t.Fatalf("should have set bootstrap mode")
   304  	}
   305  	if out.BootstrapExpect != 0 {
   306  		t.Fatalf("boostrap expect should be 0")
   307  	}
   308  
   309  	conf.Server.BootstrapExpect = 3
   310  	out, err = a.serverConfig()
   311  	if err != nil {
   312  		t.Fatalf("err: %s", err)
   313  	}
   314  	if out.Bootstrap {
   315  		t.Fatalf("bootstrap mode should be disabled")
   316  	}
   317  	if out.BootstrapExpect != 3 {
   318  		t.Fatalf("should have bootstrap-expect = 3")
   319  	}
   320  }
   321  
   322  func TestAgent_ClientConfig(t *testing.T) {
   323  	conf := DefaultConfig()
   324  	conf.Client.Enabled = true
   325  
   326  	// For Clients HTTP and RPC must be set (Serf can be skipped)
   327  	conf.Addresses.HTTP = "169.254.0.1"
   328  	conf.Addresses.RPC = "169.254.0.1"
   329  	conf.Ports.HTTP = 5678
   330  	a := &Agent{config: conf}
   331  
   332  	if err := conf.normalizeAddrs(); err != nil {
   333  		t.Fatalf("error normalizing config: %v", err)
   334  	}
   335  	c, err := a.clientConfig()
   336  	if err != nil {
   337  		t.Fatalf("got err: %v", err)
   338  	}
   339  
   340  	expectedHttpAddr := "169.254.0.1:5678"
   341  	if c.Node.HTTPAddr != expectedHttpAddr {
   342  		t.Fatalf("Expected http addr: %v, got: %v", expectedHttpAddr, c.Node.HTTPAddr)
   343  	}
   344  
   345  	conf = DefaultConfig()
   346  	conf.DevMode = true
   347  	a = &Agent{config: conf}
   348  	conf.Client.Enabled = true
   349  	conf.Addresses.HTTP = "169.254.0.1"
   350  
   351  	if err := conf.normalizeAddrs(); err != nil {
   352  		t.Fatalf("error normalizing config: %v", err)
   353  	}
   354  	c, err = a.clientConfig()
   355  	if err != nil {
   356  		t.Fatalf("got err: %v", err)
   357  	}
   358  
   359  	expectedHttpAddr = "169.254.0.1:4646"
   360  	if c.Node.HTTPAddr != expectedHttpAddr {
   361  		t.Fatalf("Expected http addr: %v, got: %v", expectedHttpAddr, c.Node.HTTPAddr)
   362  	}
   363  }
   364  
   365  // TestAgent_HTTPCheck asserts Agent.agentHTTPCheck properly alters the HTTP
   366  // API health check depending on configuration.
   367  func TestAgent_HTTPCheck(t *testing.T) {
   368  	logger := log.New(ioutil.Discard, "", 0)
   369  	if testing.Verbose() {
   370  		logger = log.New(os.Stdout, "[TestAgent_HTTPCheck] ", log.Lshortfile)
   371  	}
   372  	agent := func() *Agent {
   373  		return &Agent{
   374  			logger: logger,
   375  			config: &Config{
   376  				AdvertiseAddrs:  &AdvertiseAddrs{HTTP: "advertise:4646"},
   377  				normalizedAddrs: &Addresses{HTTP: "normalized:4646"},
   378  				Consul: &sconfig.ConsulConfig{
   379  					ChecksUseAdvertise: helper.BoolToPtr(false),
   380  				},
   381  				TLSConfig: &sconfig.TLSConfig{EnableHTTP: false},
   382  			},
   383  		}
   384  	}
   385  
   386  	t.Run("Plain HTTP Check", func(t *testing.T) {
   387  		a := agent()
   388  		check := a.agentHTTPCheck()
   389  		if check == nil {
   390  			t.Fatalf("expected non-nil check")
   391  		}
   392  		if check.Type != "http" {
   393  			t.Errorf("expected http check not: %q", check.Type)
   394  		}
   395  		if expected := "/v1/agent/servers"; check.Path != expected {
   396  			t.Errorf("expected %q path not: %q", expected, check.Path)
   397  		}
   398  		if check.Protocol != "http" {
   399  			t.Errorf("expected http proto not: %q", check.Protocol)
   400  		}
   401  		if expected := a.config.normalizedAddrs.HTTP; check.PortLabel != expected {
   402  			t.Errorf("expected normalized addr not %q", check.PortLabel)
   403  		}
   404  	})
   405  
   406  	t.Run("Plain HTTP + ChecksUseAdvertise", func(t *testing.T) {
   407  		a := agent()
   408  		a.config.Consul.ChecksUseAdvertise = helper.BoolToPtr(true)
   409  		check := a.agentHTTPCheck()
   410  		if check == nil {
   411  			t.Fatalf("expected non-nil check")
   412  		}
   413  		if expected := a.config.AdvertiseAddrs.HTTP; check.PortLabel != expected {
   414  			t.Errorf("expected advertise addr not %q", check.PortLabel)
   415  		}
   416  	})
   417  
   418  	t.Run("HTTPS + consulSupportsTLSSkipVerify", func(t *testing.T) {
   419  		a := agent()
   420  		a.consulSupportsTLSSkipVerify = true
   421  		a.config.TLSConfig.EnableHTTP = true
   422  
   423  		check := a.agentHTTPCheck()
   424  		if check == nil {
   425  			t.Fatalf("expected non-nil check")
   426  		}
   427  		if !check.TLSSkipVerify {
   428  			t.Errorf("expected tls skip verify")
   429  		}
   430  		if check.Protocol != "https" {
   431  			t.Errorf("expected https not: %q", check.Protocol)
   432  		}
   433  	})
   434  
   435  	t.Run("HTTPS w/o TLSSkipVerify", func(t *testing.T) {
   436  		a := agent()
   437  		a.consulSupportsTLSSkipVerify = false
   438  		a.config.TLSConfig.EnableHTTP = true
   439  
   440  		if check := a.agentHTTPCheck(); check != nil {
   441  			t.Fatalf("expected nil check not: %#v", check)
   442  		}
   443  	})
   444  
   445  	t.Run("HTTPS + VerifyHTTPSClient", func(t *testing.T) {
   446  		a := agent()
   447  		a.consulSupportsTLSSkipVerify = true
   448  		a.config.TLSConfig.EnableHTTP = true
   449  		a.config.TLSConfig.VerifyHTTPSClient = true
   450  
   451  		if check := a.agentHTTPCheck(); check != nil {
   452  			t.Fatalf("expected nil check not: %#v", check)
   453  		}
   454  	})
   455  }
   456  
   457  func TestAgent_ConsulSupportsTLSSkipVerify(t *testing.T) {
   458  	assertSupport := func(expected bool, blob string) {
   459  		self := map[string]map[string]interface{}{}
   460  		if err := json.Unmarshal([]byte("{"+blob+"}"), &self); err != nil {
   461  			t.Fatalf("invalid json: %v", err)
   462  		}
   463  		actual := consulSupportsTLSSkipVerify(self)
   464  		if actual != expected {
   465  			t.Errorf("expected %t but got %t for:\n%s\n", expected, actual, blob)
   466  		}
   467  	}
   468  
   469  	// 0.6.4
   470  	assertSupport(false, `"Member": {
   471          "Addr": "127.0.0.1",
   472          "DelegateCur": 4,
   473          "DelegateMax": 4,
   474          "DelegateMin": 2,
   475          "Name": "rusty",
   476          "Port": 8301,
   477          "ProtocolCur": 2,
   478          "ProtocolMax": 3,
   479          "ProtocolMin": 1,
   480          "Status": 1,
   481          "Tags": {
   482              "build": "0.6.4:26a0ef8c",
   483              "dc": "dc1",
   484              "port": "8300",
   485              "role": "consul",
   486              "vsn": "2",
   487              "vsn_max": "3",
   488              "vsn_min": "1"
   489          }}`)
   490  
   491  	// 0.7.0
   492  	assertSupport(false, `"Member": {
   493          "Addr": "127.0.0.1",
   494          "DelegateCur": 4,
   495          "DelegateMax": 4,
   496          "DelegateMin": 2,
   497          "Name": "rusty",
   498          "Port": 8301,
   499          "ProtocolCur": 2,
   500          "ProtocolMax": 4,
   501          "ProtocolMin": 1,
   502          "Status": 1,
   503          "Tags": {
   504              "build": "0.7.0:'a189091",
   505              "dc": "dc1",
   506              "port": "8300",
   507              "role": "consul",
   508              "vsn": "2",
   509              "vsn_max": "3",
   510              "vsn_min": "2"
   511          }}`)
   512  
   513  	// 0.7.2
   514  	assertSupport(true, `"Member": {
   515          "Addr": "127.0.0.1",
   516          "DelegateCur": 4,
   517          "DelegateMax": 4,
   518          "DelegateMin": 2,
   519          "Name": "rusty",
   520          "Port": 8301,
   521          "ProtocolCur": 2,
   522          "ProtocolMax": 5,
   523          "ProtocolMin": 1,
   524          "Status": 1,
   525          "Tags": {
   526              "build": "0.7.2:'a9afa0c",
   527              "dc": "dc1",
   528              "port": "8300",
   529              "role": "consul",
   530              "vsn": "2",
   531              "vsn_max": "3",
   532              "vsn_min": "2"
   533          }}`)
   534  
   535  	// 0.8.1
   536  	assertSupport(true, `"Member": {
   537          "Addr": "127.0.0.1",
   538          "DelegateCur": 4,
   539          "DelegateMax": 5,
   540          "DelegateMin": 2,
   541          "Name": "rusty",
   542          "Port": 8301,
   543          "ProtocolCur": 2,
   544          "ProtocolMax": 5,
   545          "ProtocolMin": 1,
   546          "Status": 1,
   547          "Tags": {
   548              "build": "0.8.1:'e9ca44d",
   549              "dc": "dc1",
   550              "id": "3ddc1b59-460e-a100-1d5c-ce3972122664",
   551              "port": "8300",
   552              "raft_vsn": "2",
   553              "role": "consul",
   554              "vsn": "2",
   555              "vsn_max": "3",
   556              "vsn_min": "2",
   557              "wan_join_port": "8302"
   558          }}`)
   559  }