github.com/jrxfive/nomad@v0.6.1-0.20170802162750-1fef470e89bf/client/client_test.go (about)

     1  package client
     2  
     3  import (
     4  	"archive/tar"
     5  	"bytes"
     6  	"fmt"
     7  	"io"
     8  	"io/ioutil"
     9  	"log"
    10  	"math/rand"
    11  	"net"
    12  	"os"
    13  	"path/filepath"
    14  	"testing"
    15  	"time"
    16  
    17  	memdb "github.com/hashicorp/go-memdb"
    18  	"github.com/hashicorp/nomad/client/config"
    19  	"github.com/hashicorp/nomad/client/fingerprint"
    20  	"github.com/hashicorp/nomad/command/agent/consul"
    21  	"github.com/hashicorp/nomad/helper"
    22  	"github.com/hashicorp/nomad/nomad"
    23  	"github.com/hashicorp/nomad/nomad/mock"
    24  	"github.com/hashicorp/nomad/nomad/structs"
    25  	nconfig "github.com/hashicorp/nomad/nomad/structs/config"
    26  	"github.com/hashicorp/nomad/testutil"
    27  	"github.com/mitchellh/hashstructure"
    28  
    29  	ctestutil "github.com/hashicorp/nomad/client/testutil"
    30  )
    31  
    32  func getPort() int {
    33  	return 1030 + int(rand.Int31n(6440))
    34  }
    35  
    36  func testServer(t *testing.T, cb func(*nomad.Config)) (*nomad.Server, string) {
    37  	// Setup the default settings
    38  	config := nomad.DefaultConfig()
    39  	config.VaultConfig.Enabled = helper.BoolToPtr(false)
    40  	config.Build = "unittest"
    41  	config.DevMode = true
    42  
    43  	// Tighten the Serf timing
    44  	config.SerfConfig.MemberlistConfig.BindAddr = "127.0.0.1"
    45  	config.SerfConfig.MemberlistConfig.SuspicionMult = 2
    46  	config.SerfConfig.MemberlistConfig.RetransmitMult = 2
    47  	config.SerfConfig.MemberlistConfig.ProbeTimeout = 50 * time.Millisecond
    48  	config.SerfConfig.MemberlistConfig.ProbeInterval = 100 * time.Millisecond
    49  	config.SerfConfig.MemberlistConfig.GossipInterval = 100 * time.Millisecond
    50  
    51  	// Tighten the Raft timing
    52  	config.RaftConfig.LeaderLeaseTimeout = 20 * time.Millisecond
    53  	config.RaftConfig.HeartbeatTimeout = 40 * time.Millisecond
    54  	config.RaftConfig.ElectionTimeout = 40 * time.Millisecond
    55  	config.RaftConfig.StartAsLeader = true
    56  	config.RaftTimeout = 500 * time.Millisecond
    57  
    58  	logger := log.New(config.LogOutput, "", log.LstdFlags)
    59  	catalog := consul.NewMockCatalog(logger)
    60  
    61  	// Invoke the callback if any
    62  	if cb != nil {
    63  		cb(config)
    64  	}
    65  
    66  	for i := 10; i >= 0; i-- {
    67  		config.RPCAddr = &net.TCPAddr{
    68  			IP:   []byte{127, 0, 0, 1},
    69  			Port: getPort(),
    70  		}
    71  		config.NodeName = fmt.Sprintf("Node %d", config.RPCAddr.Port)
    72  		config.SerfConfig.MemberlistConfig.BindPort = getPort()
    73  
    74  		// Create server
    75  		server, err := nomad.NewServer(config, catalog, logger)
    76  		if err == nil {
    77  			return server, config.RPCAddr.String()
    78  		} else if i == 0 {
    79  			t.Fatalf("err: %v", err)
    80  		} else {
    81  			wait := time.Duration(rand.Int31n(2000)) * time.Millisecond
    82  			time.Sleep(wait)
    83  		}
    84  	}
    85  	return nil, ""
    86  }
    87  
    88  func testClient(t *testing.T, cb func(c *config.Config)) *Client {
    89  	conf := config.DefaultConfig()
    90  	conf.VaultConfig.Enabled = helper.BoolToPtr(false)
    91  	conf.DevMode = true
    92  	conf.Node = &structs.Node{
    93  		Reserved: &structs.Resources{
    94  			DiskMB: 0,
    95  		},
    96  	}
    97  
    98  	// Tighten the fingerprinter timeouts
    99  	if conf.Options == nil {
   100  		conf.Options = make(map[string]string)
   101  	}
   102  	conf.Options[fingerprint.TightenNetworkTimeoutsConfig] = "true"
   103  
   104  	if cb != nil {
   105  		cb(conf)
   106  	}
   107  
   108  	logger := log.New(conf.LogOutput, "", log.LstdFlags)
   109  	catalog := consul.NewMockCatalog(logger)
   110  	mockService := newMockConsulServiceClient()
   111  	mockService.logger = logger
   112  	client, err := NewClient(conf, catalog, mockService, logger)
   113  	if err != nil {
   114  		t.Fatalf("err: %v", err)
   115  	}
   116  	return client
   117  }
   118  
   119  func TestClient_StartStop(t *testing.T) {
   120  	t.Parallel()
   121  	client := testClient(t, nil)
   122  	if err := client.Shutdown(); err != nil {
   123  		t.Fatalf("err: %v", err)
   124  	}
   125  }
   126  
   127  func TestClient_RPC(t *testing.T) {
   128  	t.Parallel()
   129  	s1, addr := testServer(t, nil)
   130  	defer s1.Shutdown()
   131  
   132  	c1 := testClient(t, func(c *config.Config) {
   133  		c.Servers = []string{addr}
   134  	})
   135  	defer c1.Shutdown()
   136  
   137  	// RPC should succeed
   138  	testutil.WaitForResult(func() (bool, error) {
   139  		var out struct{}
   140  		err := c1.RPC("Status.Ping", struct{}{}, &out)
   141  		return err == nil, err
   142  	}, func(err error) {
   143  		t.Fatalf("err: %v", err)
   144  	})
   145  }
   146  
   147  func TestClient_RPC_Passthrough(t *testing.T) {
   148  	t.Parallel()
   149  	s1, _ := testServer(t, nil)
   150  	defer s1.Shutdown()
   151  
   152  	c1 := testClient(t, func(c *config.Config) {
   153  		c.RPCHandler = s1
   154  	})
   155  	defer c1.Shutdown()
   156  
   157  	// RPC should succeed
   158  	testutil.WaitForResult(func() (bool, error) {
   159  		var out struct{}
   160  		err := c1.RPC("Status.Ping", struct{}{}, &out)
   161  		return err == nil, err
   162  	}, func(err error) {
   163  		t.Fatalf("err: %v", err)
   164  	})
   165  }
   166  
   167  func TestClient_Fingerprint(t *testing.T) {
   168  	t.Parallel()
   169  	c := testClient(t, nil)
   170  	defer c.Shutdown()
   171  
   172  	// Ensure kernel and arch are always present
   173  	node := c.Node()
   174  	if node.Attributes["kernel.name"] == "" {
   175  		t.Fatalf("missing kernel.name")
   176  	}
   177  	if node.Attributes["cpu.arch"] == "" {
   178  		t.Fatalf("missing cpu arch")
   179  	}
   180  }
   181  
   182  func TestClient_HasNodeChanged(t *testing.T) {
   183  	t.Parallel()
   184  	c := testClient(t, nil)
   185  	defer c.Shutdown()
   186  
   187  	node := c.Node()
   188  	attrHash, err := hashstructure.Hash(node.Attributes, nil)
   189  	if err != nil {
   190  		c.logger.Printf("[DEBUG] client: unable to calculate node attributes hash: %v", err)
   191  	}
   192  	// Calculate node meta map hash
   193  	metaHash, err := hashstructure.Hash(node.Meta, nil)
   194  	if err != nil {
   195  		c.logger.Printf("[DEBUG] client: unable to calculate node meta hash: %v", err)
   196  	}
   197  	if changed, _, _ := c.hasNodeChanged(attrHash, metaHash); changed {
   198  		t.Fatalf("Unexpected hash change.")
   199  	}
   200  
   201  	// Change node attribute
   202  	node.Attributes["arch"] = "xyz_86"
   203  	if changed, newAttrHash, _ := c.hasNodeChanged(attrHash, metaHash); !changed {
   204  		t.Fatalf("Expected hash change in attributes: %d vs %d", attrHash, newAttrHash)
   205  	}
   206  
   207  	// Change node meta map
   208  	node.Meta["foo"] = "bar"
   209  	if changed, _, newMetaHash := c.hasNodeChanged(attrHash, metaHash); !changed {
   210  		t.Fatalf("Expected hash change in meta map: %d vs %d", metaHash, newMetaHash)
   211  	}
   212  }
   213  
   214  func TestClient_Fingerprint_InWhitelist(t *testing.T) {
   215  	t.Parallel()
   216  	c := testClient(t, func(c *config.Config) {
   217  		if c.Options == nil {
   218  			c.Options = make(map[string]string)
   219  		}
   220  
   221  		// Weird spacing to test trimming. Whitelist all modules expect cpu.
   222  		c.Options["fingerprint.whitelist"] = "  arch, consul,cpu,env_aws,env_gce,host,memory,network,storage,foo,bar	"
   223  	})
   224  	defer c.Shutdown()
   225  
   226  	node := c.Node()
   227  	if node.Attributes["cpu.frequency"] == "" {
   228  		t.Fatalf("missing cpu fingerprint module")
   229  	}
   230  }
   231  
   232  func TestClient_Fingerprint_InBlacklist(t *testing.T) {
   233  	t.Parallel()
   234  	c := testClient(t, func(c *config.Config) {
   235  		if c.Options == nil {
   236  			c.Options = make(map[string]string)
   237  		}
   238  
   239  		// Weird spacing to test trimming. Blacklist cpu.
   240  		c.Options["fingerprint.blacklist"] = "  cpu	"
   241  	})
   242  	defer c.Shutdown()
   243  
   244  	node := c.Node()
   245  	if node.Attributes["cpu.frequency"] != "" {
   246  		t.Fatalf("cpu fingerprint module loaded despite blacklisting")
   247  	}
   248  }
   249  
   250  func TestClient_Fingerprint_OutOfWhitelist(t *testing.T) {
   251  	t.Parallel()
   252  	c := testClient(t, func(c *config.Config) {
   253  		if c.Options == nil {
   254  			c.Options = make(map[string]string)
   255  		}
   256  
   257  		c.Options["fingerprint.whitelist"] = "arch,consul,env_aws,env_gce,host,memory,network,storage,foo,bar"
   258  	})
   259  	defer c.Shutdown()
   260  
   261  	node := c.Node()
   262  	if node.Attributes["cpu.frequency"] != "" {
   263  		t.Fatalf("found cpu fingerprint module")
   264  	}
   265  }
   266  
   267  func TestClient_Fingerprint_WhitelistBlacklistCombination(t *testing.T) {
   268  	t.Parallel()
   269  	c := testClient(t, func(c *config.Config) {
   270  		if c.Options == nil {
   271  			c.Options = make(map[string]string)
   272  		}
   273  
   274  		// With both white- and blacklist, should return the set difference of modules (arch, cpu)
   275  		c.Options["fingerprint.whitelist"] = "arch,memory,cpu"
   276  		c.Options["fingerprint.blacklist"] = "memory,nomad"
   277  	})
   278  	defer c.Shutdown()
   279  
   280  	node := c.Node()
   281  	// Check expected modules are present
   282  	if node.Attributes["cpu.frequency"] == "" {
   283  		t.Fatalf("missing cpu fingerprint module")
   284  	}
   285  	if node.Attributes["cpu.arch"] == "" {
   286  		t.Fatalf("missing arch fingerprint module")
   287  	}
   288  	// Check remainder _not_ present
   289  	if node.Attributes["memory.totalbytes"] != "" {
   290  		t.Fatalf("found memory fingerprint module")
   291  	}
   292  	if node.Attributes["nomad.version"] != "" {
   293  		t.Fatalf("found nomad fingerprint module")
   294  	}
   295  }
   296  
   297  func TestClient_Drivers_InWhitelist(t *testing.T) {
   298  	t.Parallel()
   299  	c := testClient(t, func(c *config.Config) {
   300  		if c.Options == nil {
   301  			c.Options = make(map[string]string)
   302  		}
   303  
   304  		// Weird spacing to test trimming
   305  		c.Options["driver.raw_exec.enable"] = "1"
   306  		c.Options["driver.whitelist"] = "   raw_exec ,  foo	"
   307  	})
   308  	defer c.Shutdown()
   309  
   310  	node := c.Node()
   311  	if node.Attributes["driver.raw_exec"] == "" {
   312  		t.Fatalf("missing raw_exec driver")
   313  	}
   314  }
   315  
   316  func TestClient_Drivers_InBlacklist(t *testing.T) {
   317  	t.Parallel()
   318  	c := testClient(t, func(c *config.Config) {
   319  		if c.Options == nil {
   320  			c.Options = make(map[string]string)
   321  		}
   322  
   323  		// Weird spacing to test trimming
   324  		c.Options["driver.raw_exec.enable"] = "1"
   325  		c.Options["driver.blacklist"] = "   raw_exec ,  foo	"
   326  	})
   327  	defer c.Shutdown()
   328  
   329  	node := c.Node()
   330  	if node.Attributes["driver.raw_exec"] != "" {
   331  		t.Fatalf("raw_exec driver loaded despite blacklist")
   332  	}
   333  }
   334  
   335  func TestClient_Drivers_OutOfWhitelist(t *testing.T) {
   336  	t.Parallel()
   337  	c := testClient(t, func(c *config.Config) {
   338  		if c.Options == nil {
   339  			c.Options = make(map[string]string)
   340  		}
   341  
   342  		c.Options["driver.whitelist"] = "foo,bar,baz"
   343  	})
   344  	defer c.Shutdown()
   345  
   346  	node := c.Node()
   347  	if node.Attributes["driver.exec"] != "" {
   348  		t.Fatalf("found exec driver")
   349  	}
   350  }
   351  
   352  func TestClient_Drivers_WhitelistBlacklistCombination(t *testing.T) {
   353  	t.Parallel()
   354  	c := testClient(t, func(c *config.Config) {
   355  		if c.Options == nil {
   356  			c.Options = make(map[string]string)
   357  		}
   358  
   359  		// Expected output is set difference (raw_exec)
   360  		c.Options["driver.whitelist"] = "raw_exec,exec"
   361  		c.Options["driver.blacklist"] = "exec"
   362  	})
   363  	defer c.Shutdown()
   364  
   365  	node := c.Node()
   366  	// Check expected present
   367  	if node.Attributes["driver.raw_exec"] == "" {
   368  		t.Fatalf("missing raw_exec driver")
   369  	}
   370  	// Check expected absent
   371  	if node.Attributes["driver.exec"] != "" {
   372  		t.Fatalf("exec driver loaded despite blacklist")
   373  	}
   374  }
   375  
   376  // TestClient_MixedTLS asserts that when a server is running with TLS enabled
   377  // it will reject any RPC connections from clients that lack TLS. See #2525
   378  func TestClient_MixedTLS(t *testing.T) {
   379  	t.Parallel()
   380  	const (
   381  		cafile  = "../helper/tlsutil/testdata/ca.pem"
   382  		foocert = "../helper/tlsutil/testdata/nomad-foo.pem"
   383  		fookey  = "../helper/tlsutil/testdata/nomad-foo-key.pem"
   384  	)
   385  	s1, addr := testServer(t, func(c *nomad.Config) {
   386  		c.TLSConfig = &nconfig.TLSConfig{
   387  			EnableHTTP:           true,
   388  			EnableRPC:            true,
   389  			VerifyServerHostname: true,
   390  			CAFile:               cafile,
   391  			CertFile:             foocert,
   392  			KeyFile:              fookey,
   393  		}
   394  	})
   395  	defer s1.Shutdown()
   396  	testutil.WaitForLeader(t, s1.RPC)
   397  
   398  	c1 := testClient(t, func(c *config.Config) {
   399  		c.Servers = []string{addr}
   400  	})
   401  	defer c1.Shutdown()
   402  
   403  	req := structs.NodeSpecificRequest{
   404  		NodeID:       c1.Node().ID,
   405  		QueryOptions: structs.QueryOptions{Region: "global"},
   406  	}
   407  	var out structs.SingleNodeResponse
   408  	testutil.AssertUntil(100*time.Millisecond,
   409  		func() (bool, error) {
   410  			err := c1.RPC("Node.GetNode", &req, &out)
   411  			if err == nil {
   412  				return false, fmt.Errorf("client RPC succeeded when it should have failed:\n%+v", out)
   413  			}
   414  			return true, nil
   415  		},
   416  		func(err error) {
   417  			t.Fatalf(err.Error())
   418  		},
   419  	)
   420  }
   421  
   422  // TestClient_BadTLS asserts that when a client and server are running with TLS
   423  // enabled -- but their certificates are signed by different CAs -- they're
   424  // unable to communicate.
   425  func TestClient_BadTLS(t *testing.T) {
   426  	t.Parallel()
   427  	const (
   428  		cafile  = "../helper/tlsutil/testdata/ca.pem"
   429  		foocert = "../helper/tlsutil/testdata/nomad-foo.pem"
   430  		fookey  = "../helper/tlsutil/testdata/nomad-foo-key.pem"
   431  		badca   = "../helper/tlsutil/testdata/ca-bad.pem"
   432  		badcert = "../helper/tlsutil/testdata/nomad-bad.pem"
   433  		badkey  = "../helper/tlsutil/testdata/nomad-bad-key.pem"
   434  	)
   435  	s1, addr := testServer(t, func(c *nomad.Config) {
   436  		c.TLSConfig = &nconfig.TLSConfig{
   437  			EnableHTTP:           true,
   438  			EnableRPC:            true,
   439  			VerifyServerHostname: true,
   440  			CAFile:               cafile,
   441  			CertFile:             foocert,
   442  			KeyFile:              fookey,
   443  		}
   444  	})
   445  	defer s1.Shutdown()
   446  	testutil.WaitForLeader(t, s1.RPC)
   447  
   448  	c1 := testClient(t, func(c *config.Config) {
   449  		c.Servers = []string{addr}
   450  		c.TLSConfig = &nconfig.TLSConfig{
   451  			EnableHTTP:           true,
   452  			EnableRPC:            true,
   453  			VerifyServerHostname: true,
   454  			CAFile:               badca,
   455  			CertFile:             badcert,
   456  			KeyFile:              badkey,
   457  		}
   458  	})
   459  	defer c1.Shutdown()
   460  
   461  	req := structs.NodeSpecificRequest{
   462  		NodeID:       c1.Node().ID,
   463  		QueryOptions: structs.QueryOptions{Region: "global"},
   464  	}
   465  	var out structs.SingleNodeResponse
   466  	testutil.AssertUntil(100*time.Millisecond,
   467  		func() (bool, error) {
   468  			err := c1.RPC("Node.GetNode", &req, &out)
   469  			if err == nil {
   470  				return false, fmt.Errorf("client RPC succeeded when it should have failed:\n%+v", out)
   471  			}
   472  			return true, nil
   473  		},
   474  		func(err error) {
   475  			t.Fatalf(err.Error())
   476  		},
   477  	)
   478  }
   479  
   480  func TestClient_Register(t *testing.T) {
   481  	t.Parallel()
   482  	s1, _ := testServer(t, nil)
   483  	defer s1.Shutdown()
   484  	testutil.WaitForLeader(t, s1.RPC)
   485  
   486  	c1 := testClient(t, func(c *config.Config) {
   487  		c.RPCHandler = s1
   488  	})
   489  	defer c1.Shutdown()
   490  
   491  	req := structs.NodeSpecificRequest{
   492  		NodeID:       c1.Node().ID,
   493  		QueryOptions: structs.QueryOptions{Region: "global"},
   494  	}
   495  	var out structs.SingleNodeResponse
   496  
   497  	// Register should succeed
   498  	testutil.WaitForResult(func() (bool, error) {
   499  		err := s1.RPC("Node.GetNode", &req, &out)
   500  		if err != nil {
   501  			return false, err
   502  		}
   503  		if out.Node == nil {
   504  			return false, fmt.Errorf("missing reg")
   505  		}
   506  		return out.Node.ID == req.NodeID, nil
   507  	}, func(err error) {
   508  		t.Fatalf("err: %v", err)
   509  	})
   510  }
   511  
   512  func TestClient_Heartbeat(t *testing.T) {
   513  	t.Parallel()
   514  	s1, _ := testServer(t, func(c *nomad.Config) {
   515  		c.MinHeartbeatTTL = 50 * time.Millisecond
   516  	})
   517  	defer s1.Shutdown()
   518  	testutil.WaitForLeader(t, s1.RPC)
   519  
   520  	c1 := testClient(t, func(c *config.Config) {
   521  		c.RPCHandler = s1
   522  	})
   523  	defer c1.Shutdown()
   524  
   525  	req := structs.NodeSpecificRequest{
   526  		NodeID:       c1.Node().ID,
   527  		QueryOptions: structs.QueryOptions{Region: "global"},
   528  	}
   529  	var out structs.SingleNodeResponse
   530  
   531  	// Register should succeed
   532  	testutil.WaitForResult(func() (bool, error) {
   533  		err := s1.RPC("Node.GetNode", &req, &out)
   534  		if err != nil {
   535  			return false, err
   536  		}
   537  		if out.Node == nil {
   538  			return false, fmt.Errorf("missing reg")
   539  		}
   540  		return out.Node.Status == structs.NodeStatusReady, nil
   541  	}, func(err error) {
   542  		t.Fatalf("err: %v", err)
   543  	})
   544  }
   545  
   546  func TestClient_UpdateAllocStatus(t *testing.T) {
   547  	t.Parallel()
   548  	s1, _ := testServer(t, nil)
   549  	defer s1.Shutdown()
   550  	testutil.WaitForLeader(t, s1.RPC)
   551  
   552  	c1 := testClient(t, func(c *config.Config) {
   553  		c.RPCHandler = s1
   554  	})
   555  	defer c1.Shutdown()
   556  
   557  	// Wait til the node is ready
   558  	waitTilNodeReady(c1, t)
   559  
   560  	job := mock.Job()
   561  	alloc := mock.Alloc()
   562  	alloc.NodeID = c1.Node().ID
   563  	alloc.Job = job
   564  	alloc.JobID = job.ID
   565  	originalStatus := "foo"
   566  	alloc.ClientStatus = originalStatus
   567  
   568  	// Insert at zero so they are pulled
   569  	state := s1.State()
   570  	if err := state.UpsertJob(0, job); err != nil {
   571  		t.Fatal(err)
   572  	}
   573  	if err := state.UpsertJobSummary(100, mock.JobSummary(alloc.JobID)); err != nil {
   574  		t.Fatal(err)
   575  	}
   576  	state.UpsertAllocs(101, []*structs.Allocation{alloc})
   577  
   578  	testutil.WaitForResult(func() (bool, error) {
   579  		ws := memdb.NewWatchSet()
   580  		out, err := state.AllocByID(ws, alloc.ID)
   581  		if err != nil {
   582  			return false, err
   583  		}
   584  		if out == nil {
   585  			return false, fmt.Errorf("no such alloc")
   586  		}
   587  		if out.ClientStatus == originalStatus {
   588  			return false, fmt.Errorf("Alloc client status not updated; got %v", out.ClientStatus)
   589  		}
   590  		return true, nil
   591  	}, func(err error) {
   592  		t.Fatalf("err: %v", err)
   593  	})
   594  }
   595  
   596  func TestClient_WatchAllocs(t *testing.T) {
   597  	t.Parallel()
   598  	ctestutil.ExecCompatible(t)
   599  	s1, _ := testServer(t, nil)
   600  	defer s1.Shutdown()
   601  	testutil.WaitForLeader(t, s1.RPC)
   602  
   603  	c1 := testClient(t, func(c *config.Config) {
   604  		c.RPCHandler = s1
   605  	})
   606  	defer c1.Shutdown()
   607  
   608  	// Wait til the node is ready
   609  	waitTilNodeReady(c1, t)
   610  
   611  	// Create mock allocations
   612  	job := mock.Job()
   613  	alloc1 := mock.Alloc()
   614  	alloc1.JobID = job.ID
   615  	alloc1.Job = job
   616  	alloc1.NodeID = c1.Node().ID
   617  	alloc2 := mock.Alloc()
   618  	alloc2.NodeID = c1.Node().ID
   619  	alloc2.JobID = job.ID
   620  	alloc2.Job = job
   621  
   622  	// Insert at zero so they are pulled
   623  	state := s1.State()
   624  	if err := state.UpsertJob(100, job); err != nil {
   625  		t.Fatal(err)
   626  	}
   627  	if err := state.UpsertJobSummary(101, mock.JobSummary(alloc1.JobID)); err != nil {
   628  		t.Fatal(err)
   629  	}
   630  	err := state.UpsertAllocs(102, []*structs.Allocation{alloc1, alloc2})
   631  	if err != nil {
   632  		t.Fatalf("err: %v", err)
   633  	}
   634  
   635  	// Both allocations should get registered
   636  	testutil.WaitForResult(func() (bool, error) {
   637  		c1.allocLock.RLock()
   638  		num := len(c1.allocs)
   639  		c1.allocLock.RUnlock()
   640  		return num == 2, nil
   641  	}, func(err error) {
   642  		t.Fatalf("err: %v", err)
   643  	})
   644  
   645  	// Delete one allocation
   646  	err = state.DeleteEval(103, nil, []string{alloc1.ID})
   647  	if err != nil {
   648  		t.Fatalf("err: %v", err)
   649  	}
   650  
   651  	// Update the other allocation. Have to make a copy because the allocs are
   652  	// shared in memory in the test and the modify index would be updated in the
   653  	// alloc runner.
   654  	alloc2_2 := new(structs.Allocation)
   655  	*alloc2_2 = *alloc2
   656  	alloc2_2.DesiredStatus = structs.AllocDesiredStatusStop
   657  	err = state.UpsertAllocs(104, []*structs.Allocation{alloc2_2})
   658  	if err != nil {
   659  		t.Fatalf("err: %v", err)
   660  	}
   661  
   662  	// One allocations should get de-registered
   663  	testutil.WaitForResult(func() (bool, error) {
   664  		c1.allocLock.RLock()
   665  		num := len(c1.allocs)
   666  		c1.allocLock.RUnlock()
   667  		return num == 1, nil
   668  	}, func(err error) {
   669  		t.Fatalf("err: %v", err)
   670  	})
   671  
   672  	// One allocations should get updated
   673  	testutil.WaitForResult(func() (bool, error) {
   674  		c1.allocLock.RLock()
   675  		ar := c1.allocs[alloc2.ID]
   676  		c1.allocLock.RUnlock()
   677  		return ar.Alloc().DesiredStatus == structs.AllocDesiredStatusStop, nil
   678  	}, func(err error) {
   679  		t.Fatalf("err: %v", err)
   680  	})
   681  }
   682  
   683  func waitTilNodeReady(client *Client, t *testing.T) {
   684  	testutil.WaitForResult(func() (bool, error) {
   685  		n := client.Node()
   686  		if n.Status != structs.NodeStatusReady {
   687  			return false, fmt.Errorf("node not registered")
   688  		}
   689  		return true, nil
   690  	}, func(err error) {
   691  		t.Fatalf("err: %v", err)
   692  	})
   693  }
   694  
   695  func TestClient_SaveRestoreState(t *testing.T) {
   696  	t.Parallel()
   697  	ctestutil.ExecCompatible(t)
   698  	s1, _ := testServer(t, nil)
   699  	defer s1.Shutdown()
   700  	testutil.WaitForLeader(t, s1.RPC)
   701  
   702  	c1 := testClient(t, func(c *config.Config) {
   703  		c.DevMode = false
   704  		c.RPCHandler = s1
   705  	})
   706  	defer c1.Shutdown()
   707  
   708  	// Wait til the node is ready
   709  	waitTilNodeReady(c1, t)
   710  
   711  	// Create mock allocations
   712  	job := mock.Job()
   713  	alloc1 := mock.Alloc()
   714  	alloc1.NodeID = c1.Node().ID
   715  	alloc1.Job = job
   716  	alloc1.JobID = job.ID
   717  	alloc1.Job.TaskGroups[0].Tasks[0].Driver = "mock_driver"
   718  	task := alloc1.Job.TaskGroups[0].Tasks[0]
   719  	task.Config["run_for"] = "10s"
   720  
   721  	state := s1.State()
   722  	if err := state.UpsertJob(100, job); err != nil {
   723  		t.Fatal(err)
   724  	}
   725  	if err := state.UpsertJobSummary(101, mock.JobSummary(alloc1.JobID)); err != nil {
   726  		t.Fatal(err)
   727  	}
   728  	if err := state.UpsertAllocs(102, []*structs.Allocation{alloc1}); err != nil {
   729  		t.Fatalf("err: %v", err)
   730  	}
   731  
   732  	// Allocations should get registered
   733  	testutil.WaitForResult(func() (bool, error) {
   734  		c1.allocLock.RLock()
   735  		ar := c1.allocs[alloc1.ID]
   736  		c1.allocLock.RUnlock()
   737  		if ar == nil {
   738  			return false, fmt.Errorf("nil alloc runner")
   739  		}
   740  		if ar.Alloc().ClientStatus != structs.AllocClientStatusRunning {
   741  			return false, fmt.Errorf("client status: got %v; want %v", ar.Alloc().ClientStatus, structs.AllocClientStatusRunning)
   742  		}
   743  		return true, nil
   744  	}, func(err error) {
   745  		t.Fatalf("err: %v", err)
   746  	})
   747  
   748  	// Shutdown the client, saves state
   749  	if err := c1.Shutdown(); err != nil {
   750  		t.Fatalf("err: %v", err)
   751  	}
   752  
   753  	// Create a new client
   754  	logger := log.New(c1.config.LogOutput, "", log.LstdFlags)
   755  	catalog := consul.NewMockCatalog(logger)
   756  	mockService := newMockConsulServiceClient()
   757  	mockService.logger = logger
   758  	c2, err := NewClient(c1.config, catalog, mockService, logger)
   759  	if err != nil {
   760  		t.Fatalf("err: %v", err)
   761  	}
   762  	defer c2.Shutdown()
   763  
   764  	// Ensure the allocation is running
   765  	testutil.WaitForResult(func() (bool, error) {
   766  		c2.allocLock.RLock()
   767  		ar := c2.allocs[alloc1.ID]
   768  		c2.allocLock.RUnlock()
   769  		status := ar.Alloc().ClientStatus
   770  		alive := status == structs.AllocClientStatusRunning || status == structs.AllocClientStatusPending
   771  		if !alive {
   772  			return false, fmt.Errorf("incorrect client status: %#v", ar.Alloc())
   773  		}
   774  		return true, nil
   775  	}, func(err error) {
   776  		t.Fatalf("err: %v", err)
   777  	})
   778  
   779  	// Destroy all the allocations
   780  	for _, ar := range c2.getAllocRunners() {
   781  		ar.Destroy()
   782  	}
   783  
   784  	for _, ar := range c2.getAllocRunners() {
   785  		<-ar.WaitCh()
   786  	}
   787  }
   788  
   789  func TestClient_Init(t *testing.T) {
   790  	t.Parallel()
   791  	dir, err := ioutil.TempDir("", "nomad")
   792  	if err != nil {
   793  		t.Fatalf("err: %s", err)
   794  	}
   795  	defer os.RemoveAll(dir)
   796  	allocDir := filepath.Join(dir, "alloc")
   797  
   798  	client := &Client{
   799  		config: &config.Config{
   800  			AllocDir: allocDir,
   801  		},
   802  		logger: log.New(os.Stderr, "", log.LstdFlags),
   803  	}
   804  	if err := client.init(); err != nil {
   805  		t.Fatalf("err: %s", err)
   806  	}
   807  
   808  	if _, err := os.Stat(allocDir); err != nil {
   809  		t.Fatalf("err: %s", err)
   810  	}
   811  }
   812  
   813  func TestClient_BlockedAllocations(t *testing.T) {
   814  	t.Parallel()
   815  	s1, _ := testServer(t, nil)
   816  	defer s1.Shutdown()
   817  	testutil.WaitForLeader(t, s1.RPC)
   818  
   819  	c1 := testClient(t, func(c *config.Config) {
   820  		c.RPCHandler = s1
   821  	})
   822  	defer c1.Shutdown()
   823  
   824  	// Wait for the node to be ready
   825  	state := s1.State()
   826  	testutil.WaitForResult(func() (bool, error) {
   827  		ws := memdb.NewWatchSet()
   828  		out, err := state.NodeByID(ws, c1.Node().ID)
   829  		if err != nil {
   830  			return false, err
   831  		}
   832  		if out == nil || out.Status != structs.NodeStatusReady {
   833  			return false, fmt.Errorf("bad node: %#v", out)
   834  		}
   835  		return true, nil
   836  	}, func(err error) {
   837  		t.Fatalf("err: %v", err)
   838  	})
   839  
   840  	// Add an allocation
   841  	alloc := mock.Alloc()
   842  	alloc.NodeID = c1.Node().ID
   843  	alloc.Job.TaskGroups[0].Tasks[0].Driver = "mock_driver"
   844  	alloc.Job.TaskGroups[0].Tasks[0].Config = map[string]interface{}{
   845  		"kill_after":  "1s",
   846  		"run_for":     "100s",
   847  		"exit_code":   0,
   848  		"exit_signal": 0,
   849  		"exit_err":    "",
   850  	}
   851  
   852  	state.UpsertJobSummary(99, mock.JobSummary(alloc.JobID))
   853  	state.UpsertAllocs(100, []*structs.Allocation{alloc})
   854  
   855  	// Wait until the client downloads and starts the allocation
   856  	testutil.WaitForResult(func() (bool, error) {
   857  		ws := memdb.NewWatchSet()
   858  		out, err := state.AllocByID(ws, alloc.ID)
   859  		if err != nil {
   860  			return false, err
   861  		}
   862  		if out == nil || out.ClientStatus != structs.AllocClientStatusRunning {
   863  			return false, fmt.Errorf("bad alloc: %#v", out)
   864  		}
   865  		return true, nil
   866  	}, func(err error) {
   867  		t.Fatalf("err: %v", err)
   868  	})
   869  
   870  	// Add a new chained alloc
   871  	alloc2 := alloc.Copy()
   872  	alloc2.ID = structs.GenerateUUID()
   873  	alloc2.Job = alloc.Job
   874  	alloc2.JobID = alloc.JobID
   875  	alloc2.PreviousAllocation = alloc.ID
   876  	if err := state.UpsertAllocs(200, []*structs.Allocation{alloc2}); err != nil {
   877  		t.Fatalf("err: %v", err)
   878  	}
   879  
   880  	// Enusre that the chained allocation is being tracked as blocked
   881  	testutil.WaitForResult(func() (bool, error) {
   882  		alloc, ok := c1.blockedAllocations[alloc2.PreviousAllocation]
   883  		if ok && alloc.ID == alloc2.ID {
   884  			return true, nil
   885  		}
   886  		return false, fmt.Errorf("no blocked allocations")
   887  	}, func(err error) {
   888  		t.Fatalf("err: %v", err)
   889  	})
   890  
   891  	// Change the desired state of the parent alloc to stop
   892  	alloc1 := alloc.Copy()
   893  	alloc1.DesiredStatus = structs.AllocDesiredStatusStop
   894  	if err := state.UpsertAllocs(300, []*structs.Allocation{alloc1}); err != nil {
   895  		t.Fatalf("err: %v", err)
   896  	}
   897  
   898  	// Ensure that there are no blocked allocations
   899  	testutil.WaitForResult(func() (bool, error) {
   900  		_, ok := c1.blockedAllocations[alloc2.PreviousAllocation]
   901  		if ok {
   902  			return false, fmt.Errorf("blocked evals present")
   903  		}
   904  		return true, nil
   905  	}, func(err error) {
   906  		t.Fatalf("err: %v", err)
   907  	})
   908  
   909  	// Destroy all the allocations
   910  	for _, ar := range c1.getAllocRunners() {
   911  		ar.Destroy()
   912  	}
   913  
   914  	for _, ar := range c1.getAllocRunners() {
   915  		<-ar.WaitCh()
   916  	}
   917  }
   918  
   919  func TestClient_UnarchiveAllocDir(t *testing.T) {
   920  	t.Parallel()
   921  	dir, err := ioutil.TempDir("", "")
   922  	if err != nil {
   923  		t.Fatalf("err: %v", err)
   924  	}
   925  	defer os.RemoveAll(dir)
   926  
   927  	if err := os.Mkdir(filepath.Join(dir, "foo"), 0777); err != nil {
   928  		t.Fatalf("err: %v", err)
   929  	}
   930  	dirInfo, err := os.Stat(filepath.Join(dir, "foo"))
   931  	if err != nil {
   932  		t.Fatalf("err: %v", err)
   933  	}
   934  	f, err := os.Create(filepath.Join(dir, "foo", "bar"))
   935  	if err != nil {
   936  		t.Fatalf("err: %v", err)
   937  	}
   938  	if _, err := f.WriteString("foo"); err != nil {
   939  		t.Fatalf("err: %v", err)
   940  	}
   941  	if err := f.Chmod(0644); err != nil {
   942  		t.Fatalf("err: %v", err)
   943  	}
   944  	fInfo, err := f.Stat()
   945  	if err != nil {
   946  		t.Fatalf("err: %v", err)
   947  	}
   948  	f.Close()
   949  	if err := os.Symlink("bar", filepath.Join(dir, "foo", "baz")); err != nil {
   950  		t.Fatalf("err: %v", err)
   951  	}
   952  	linkInfo, err := os.Lstat(filepath.Join(dir, "foo", "baz"))
   953  	if err != nil {
   954  		t.Fatalf("err: %v", err)
   955  	}
   956  
   957  	buf := new(bytes.Buffer)
   958  	tw := tar.NewWriter(buf)
   959  
   960  	walkFn := func(path string, fileInfo os.FileInfo, err error) error {
   961  		// Include the path of the file name relative to the alloc dir
   962  		// so that we can put the files in the right directories
   963  		link := ""
   964  		if fileInfo.Mode()&os.ModeSymlink != 0 {
   965  			target, err := os.Readlink(path)
   966  			if err != nil {
   967  				return fmt.Errorf("error reading symlink: %v", err)
   968  			}
   969  			link = target
   970  		}
   971  		hdr, err := tar.FileInfoHeader(fileInfo, link)
   972  		if err != nil {
   973  			return fmt.Errorf("error creating file header: %v", err)
   974  		}
   975  		hdr.Name = fileInfo.Name()
   976  		tw.WriteHeader(hdr)
   977  
   978  		// If it's a directory or symlink we just write the header into the tar
   979  		if fileInfo.IsDir() || (fileInfo.Mode()&os.ModeSymlink != 0) {
   980  			return nil
   981  		}
   982  
   983  		// Write the file into the archive
   984  		file, err := os.Open(path)
   985  		if err != nil {
   986  			return err
   987  		}
   988  		defer file.Close()
   989  
   990  		if _, err := io.Copy(tw, file); err != nil {
   991  			return err
   992  		}
   993  
   994  		return nil
   995  	}
   996  
   997  	if err := filepath.Walk(dir, walkFn); err != nil {
   998  		t.Fatalf("err: %v", err)
   999  	}
  1000  	tw.Close()
  1001  
  1002  	dir1, err := ioutil.TempDir("", "")
  1003  	if err != nil {
  1004  		t.Fatalf("err: %v", err)
  1005  	}
  1006  	defer os.RemoveAll(dir1)
  1007  
  1008  	c1 := testClient(t, func(c *config.Config) {
  1009  		c.RPCHandler = nil
  1010  	})
  1011  	defer c1.Shutdown()
  1012  
  1013  	rc := ioutil.NopCloser(buf)
  1014  
  1015  	c1.migratingAllocs["123"] = newMigrateAllocCtrl(mock.Alloc())
  1016  	if err := c1.unarchiveAllocDir(rc, "123", dir1); err != nil {
  1017  		t.Fatalf("err: %v", err)
  1018  	}
  1019  
  1020  	// Ensure foo is present
  1021  	fi, err := os.Stat(filepath.Join(dir1, "foo"))
  1022  	if err != nil {
  1023  		t.Fatalf("err: %v", err)
  1024  	}
  1025  	if fi.Mode() != dirInfo.Mode() {
  1026  		t.Fatalf("mode: %v", fi.Mode())
  1027  	}
  1028  
  1029  	fi1, err := os.Stat(filepath.Join(dir1, "bar"))
  1030  	if err != nil {
  1031  		t.Fatalf("err: %v", err)
  1032  	}
  1033  	if fi1.Mode() != fInfo.Mode() {
  1034  		t.Fatalf("mode: %v", fi1.Mode())
  1035  	}
  1036  
  1037  	fi2, err := os.Lstat(filepath.Join(dir1, "baz"))
  1038  	if err != nil {
  1039  		t.Fatalf("err: %v", err)
  1040  	}
  1041  	if fi2.Mode() != linkInfo.Mode() {
  1042  		t.Fatalf("mode: %v", fi2.Mode())
  1043  	}
  1044  }