github.com/zoomfoo/nomad@v0.8.5-0.20180907175415-f28fd3a1a056/nomad/client_alloc_endpoint_test.go (about)

     1  package nomad
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	msgpackrpc "github.com/hashicorp/net-rpc-msgpackrpc"
     8  	"github.com/hashicorp/nomad/acl"
     9  	"github.com/hashicorp/nomad/client"
    10  	"github.com/hashicorp/nomad/client/config"
    11  	cstructs "github.com/hashicorp/nomad/client/structs"
    12  	"github.com/hashicorp/nomad/helper/uuid"
    13  	"github.com/hashicorp/nomad/nomad/mock"
    14  	"github.com/hashicorp/nomad/nomad/structs"
    15  	"github.com/hashicorp/nomad/testutil"
    16  	"github.com/stretchr/testify/require"
    17  )
    18  
    19  func TestClientAllocations_GarbageCollectAll_Local(t *testing.T) {
    20  	t.Parallel()
    21  	require := require.New(t)
    22  
    23  	// Start a server and client
    24  	s := TestServer(t, nil)
    25  	defer s.Shutdown()
    26  	codec := rpcClient(t, s)
    27  	testutil.WaitForLeader(t, s.RPC)
    28  
    29  	c := client.TestClient(t, func(c *config.Config) {
    30  		c.Servers = []string{s.config.RPCAddr.String()}
    31  	})
    32  	defer c.Shutdown()
    33  
    34  	testutil.WaitForResult(func() (bool, error) {
    35  		nodes := s.connectedNodes()
    36  		return len(nodes) == 1, nil
    37  	}, func(err error) {
    38  		t.Fatalf("should have a clients")
    39  	})
    40  
    41  	// Make the request without having a node-id
    42  	req := &structs.NodeSpecificRequest{
    43  		QueryOptions: structs.QueryOptions{Region: "global"},
    44  	}
    45  
    46  	// Fetch the response
    47  	var resp structs.GenericResponse
    48  	err := msgpackrpc.CallWithCodec(codec, "ClientAllocations.GarbageCollectAll", req, &resp)
    49  	require.NotNil(err)
    50  	require.Contains(err.Error(), "missing")
    51  
    52  	// Fetch the response setting the node id
    53  	req.NodeID = c.NodeID()
    54  	var resp2 structs.GenericResponse
    55  	err = msgpackrpc.CallWithCodec(codec, "ClientAllocations.GarbageCollectAll", req, &resp2)
    56  	require.Nil(err)
    57  }
    58  
    59  func TestClientAllocations_GarbageCollectAll_Local_ACL(t *testing.T) {
    60  	t.Parallel()
    61  	require := require.New(t)
    62  
    63  	// Start a server
    64  	s, root := TestACLServer(t, nil)
    65  	defer s.Shutdown()
    66  	codec := rpcClient(t, s)
    67  	testutil.WaitForLeader(t, s.RPC)
    68  
    69  	// Create a bad token
    70  	policyBad := mock.NamespacePolicy("other", "", []string{acl.NamespaceCapabilityReadFS})
    71  	tokenBad := mock.CreatePolicyAndToken(t, s.State(), 1005, "invalid", policyBad)
    72  
    73  	policyGood := mock.NodePolicy(acl.PolicyWrite)
    74  	tokenGood := mock.CreatePolicyAndToken(t, s.State(), 1009, "valid2", policyGood)
    75  
    76  	cases := []struct {
    77  		Name          string
    78  		Token         string
    79  		ExpectedError string
    80  	}{
    81  		{
    82  			Name:          "bad token",
    83  			Token:         tokenBad.SecretID,
    84  			ExpectedError: structs.ErrPermissionDenied.Error(),
    85  		},
    86  		{
    87  			Name:          "good token",
    88  			Token:         tokenGood.SecretID,
    89  			ExpectedError: "Unknown node",
    90  		},
    91  		{
    92  			Name:          "root token",
    93  			Token:         root.SecretID,
    94  			ExpectedError: "Unknown node",
    95  		},
    96  	}
    97  
    98  	for _, c := range cases {
    99  		t.Run(c.Name, func(t *testing.T) {
   100  
   101  			// Make the request without having a node-id
   102  			req := &structs.NodeSpecificRequest{
   103  				NodeID: uuid.Generate(),
   104  				QueryOptions: structs.QueryOptions{
   105  					AuthToken: c.Token,
   106  					Region:    "global",
   107  				},
   108  			}
   109  
   110  			// Fetch the response
   111  			var resp structs.GenericResponse
   112  			err := msgpackrpc.CallWithCodec(codec, "ClientAllocations.GarbageCollectAll", req, &resp)
   113  			require.NotNil(err)
   114  			require.Contains(err.Error(), c.ExpectedError)
   115  		})
   116  	}
   117  }
   118  
   119  func TestClientAllocations_GarbageCollectAll_NoNode(t *testing.T) {
   120  	t.Parallel()
   121  	require := require.New(t)
   122  
   123  	// Start a server and client
   124  	s := TestServer(t, nil)
   125  	defer s.Shutdown()
   126  	codec := rpcClient(t, s)
   127  	testutil.WaitForLeader(t, s.RPC)
   128  
   129  	// Make the request without having a node-id
   130  	req := &structs.NodeSpecificRequest{
   131  		NodeID:       uuid.Generate(),
   132  		QueryOptions: structs.QueryOptions{Region: "global"},
   133  	}
   134  
   135  	// Fetch the response
   136  	var resp structs.GenericResponse
   137  	err := msgpackrpc.CallWithCodec(codec, "ClientAllocations.GarbageCollectAll", req, &resp)
   138  	require.NotNil(err)
   139  	require.Contains(err.Error(), "Unknown node")
   140  }
   141  
   142  func TestClientAllocations_GarbageCollectAll_OldNode(t *testing.T) {
   143  	t.Parallel()
   144  	require := require.New(t)
   145  
   146  	// Start a server and fake an old client
   147  	s := TestServer(t, nil)
   148  	defer s.Shutdown()
   149  	state := s.State()
   150  	codec := rpcClient(t, s)
   151  	testutil.WaitForLeader(t, s.RPC)
   152  
   153  	// Test for an old version error
   154  	node := mock.Node()
   155  	node.Attributes["nomad.version"] = "0.7.1"
   156  	require.Nil(state.UpsertNode(1005, node))
   157  
   158  	req := &structs.NodeSpecificRequest{
   159  		NodeID:       node.ID,
   160  		QueryOptions: structs.QueryOptions{Region: "global"},
   161  	}
   162  
   163  	var resp structs.GenericResponse
   164  	err := msgpackrpc.CallWithCodec(codec, "ClientAllocations.GarbageCollectAll", req, &resp)
   165  	require.True(structs.IsErrNodeLacksRpc(err))
   166  
   167  	// Test for a missing version error
   168  	delete(node.Attributes, "nomad.version")
   169  	require.Nil(state.UpsertNode(1006, node))
   170  
   171  	err = msgpackrpc.CallWithCodec(codec, "ClientAllocations.GarbageCollectAll", req, &resp)
   172  	require.True(structs.IsErrUnknownNomadVersion(err))
   173  }
   174  
   175  func TestClientAllocations_GarbageCollectAll_Remote(t *testing.T) {
   176  	t.Parallel()
   177  	require := require.New(t)
   178  
   179  	// Start a server and client
   180  	s1 := TestServer(t, nil)
   181  	defer s1.Shutdown()
   182  	s2 := TestServer(t, func(c *Config) {
   183  		c.DevDisableBootstrap = true
   184  	})
   185  	defer s2.Shutdown()
   186  	TestJoin(t, s1, s2)
   187  	testutil.WaitForLeader(t, s1.RPC)
   188  	testutil.WaitForLeader(t, s2.RPC)
   189  	codec := rpcClient(t, s2)
   190  
   191  	c := client.TestClient(t, func(c *config.Config) {
   192  		c.Servers = []string{s2.config.RPCAddr.String()}
   193  		c.GCDiskUsageThreshold = 100.0
   194  	})
   195  	defer c.Shutdown()
   196  
   197  	testutil.WaitForResult(func() (bool, error) {
   198  		nodes := s2.connectedNodes()
   199  		return len(nodes) == 1, nil
   200  	}, func(err error) {
   201  		t.Fatalf("should have a clients")
   202  	})
   203  
   204  	// Force remove the connection locally in case it exists
   205  	s1.nodeConnsLock.Lock()
   206  	delete(s1.nodeConns, c.NodeID())
   207  	s1.nodeConnsLock.Unlock()
   208  
   209  	// Make the request
   210  	req := &structs.NodeSpecificRequest{
   211  		NodeID:       c.NodeID(),
   212  		QueryOptions: structs.QueryOptions{Region: "global"},
   213  	}
   214  
   215  	// Fetch the response
   216  	var resp cstructs.ClientStatsResponse
   217  	err := msgpackrpc.CallWithCodec(codec, "ClientAllocations.GarbageCollectAll", req, &resp)
   218  	require.Nil(err)
   219  }
   220  
   221  func TestClientAllocations_GarbageCollect_OldNode(t *testing.T) {
   222  	t.Parallel()
   223  	require := require.New(t)
   224  
   225  	// Start a server and fake an old client
   226  	s := TestServer(t, nil)
   227  	defer s.Shutdown()
   228  	state := s.State()
   229  	codec := rpcClient(t, s)
   230  	testutil.WaitForLeader(t, s.RPC)
   231  
   232  	// Test for an old version error
   233  	node := mock.Node()
   234  	node.Attributes["nomad.version"] = "0.7.1"
   235  	require.Nil(state.UpsertNode(1005, node))
   236  
   237  	alloc := mock.Alloc()
   238  	alloc.NodeID = node.ID
   239  	require.Nil(state.UpsertAllocs(1006, []*structs.Allocation{alloc}))
   240  
   241  	req := &structs.AllocSpecificRequest{
   242  		AllocID: alloc.ID,
   243  		QueryOptions: structs.QueryOptions{
   244  			Region:    "global",
   245  			Namespace: structs.DefaultNamespace,
   246  		},
   247  	}
   248  
   249  	var resp structs.GenericResponse
   250  	err := msgpackrpc.CallWithCodec(codec, "ClientAllocations.GarbageCollect", req, &resp)
   251  	require.True(structs.IsErrNodeLacksRpc(err), err.Error())
   252  
   253  	// Test for a missing version error
   254  	delete(node.Attributes, "nomad.version")
   255  	require.Nil(state.UpsertNode(1007, node))
   256  
   257  	err = msgpackrpc.CallWithCodec(codec, "ClientAllocations.GarbageCollect", req, &resp)
   258  	require.True(structs.IsErrUnknownNomadVersion(err), err.Error())
   259  }
   260  
   261  func TestClientAllocations_GarbageCollect_Local(t *testing.T) {
   262  	t.Parallel()
   263  	require := require.New(t)
   264  
   265  	// Start a server and client
   266  	s := TestServer(t, nil)
   267  	defer s.Shutdown()
   268  	codec := rpcClient(t, s)
   269  	testutil.WaitForLeader(t, s.RPC)
   270  
   271  	c := client.TestClient(t, func(c *config.Config) {
   272  		c.Servers = []string{s.config.RPCAddr.String()}
   273  		c.GCDiskUsageThreshold = 100.0
   274  	})
   275  	defer c.Shutdown()
   276  
   277  	// Force an allocation onto the node
   278  	a := mock.Alloc()
   279  	a.Job.Type = structs.JobTypeBatch
   280  	a.NodeID = c.NodeID()
   281  	a.Job.TaskGroups[0].Count = 1
   282  	a.Job.TaskGroups[0].Tasks[0] = &structs.Task{
   283  		Name:   "web",
   284  		Driver: "mock_driver",
   285  		Config: map[string]interface{}{
   286  			"run_for": "2s",
   287  		},
   288  		LogConfig: structs.DefaultLogConfig(),
   289  		Resources: &structs.Resources{
   290  			CPU:      500,
   291  			MemoryMB: 256,
   292  		},
   293  	}
   294  
   295  	testutil.WaitForResult(func() (bool, error) {
   296  		nodes := s.connectedNodes()
   297  		return len(nodes) == 1, nil
   298  	}, func(err error) {
   299  		t.Fatalf("should have a clients")
   300  	})
   301  
   302  	// Upsert the allocation
   303  	state := s.State()
   304  	require.Nil(state.UpsertJob(999, a.Job))
   305  	require.Nil(state.UpsertAllocs(1003, []*structs.Allocation{a}))
   306  
   307  	// Wait for the client to run the allocation
   308  	testutil.WaitForResult(func() (bool, error) {
   309  		alloc, err := state.AllocByID(nil, a.ID)
   310  		if err != nil {
   311  			return false, err
   312  		}
   313  		if alloc == nil {
   314  			return false, fmt.Errorf("unknown alloc")
   315  		}
   316  		if alloc.ClientStatus != structs.AllocClientStatusComplete {
   317  			return false, fmt.Errorf("alloc client status: %v", alloc.ClientStatus)
   318  		}
   319  
   320  		return true, nil
   321  	}, func(err error) {
   322  		t.Fatalf("Alloc on node %q not finished: %v", c.NodeID(), err)
   323  	})
   324  
   325  	// Make the request without having an alloc id
   326  	req := &structs.AllocSpecificRequest{
   327  		QueryOptions: structs.QueryOptions{Region: "global"},
   328  	}
   329  
   330  	// Fetch the response
   331  	var resp structs.GenericResponse
   332  	err := msgpackrpc.CallWithCodec(codec, "ClientAllocations.GarbageCollect", req, &resp)
   333  	require.NotNil(err)
   334  	require.Contains(err.Error(), "missing")
   335  
   336  	// Fetch the response setting the node id
   337  	req.AllocID = a.ID
   338  	var resp2 structs.GenericResponse
   339  	err = msgpackrpc.CallWithCodec(codec, "ClientAllocations.GarbageCollect", req, &resp2)
   340  	require.Nil(err)
   341  }
   342  
   343  func TestClientAllocations_GarbageCollect_Local_ACL(t *testing.T) {
   344  	t.Parallel()
   345  	require := require.New(t)
   346  
   347  	// Start a server
   348  	s, root := TestACLServer(t, nil)
   349  	defer s.Shutdown()
   350  	codec := rpcClient(t, s)
   351  	testutil.WaitForLeader(t, s.RPC)
   352  
   353  	// Create a bad token
   354  	policyBad := mock.NamespacePolicy("other", "", []string{acl.NamespaceCapabilityReadFS})
   355  	tokenBad := mock.CreatePolicyAndToken(t, s.State(), 1005, "invalid", policyBad)
   356  
   357  	policyGood := mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilitySubmitJob})
   358  	tokenGood := mock.CreatePolicyAndToken(t, s.State(), 1009, "valid2", policyGood)
   359  
   360  	cases := []struct {
   361  		Name          string
   362  		Token         string
   363  		ExpectedError string
   364  	}{
   365  		{
   366  			Name:          "bad token",
   367  			Token:         tokenBad.SecretID,
   368  			ExpectedError: structs.ErrPermissionDenied.Error(),
   369  		},
   370  		{
   371  			Name:          "good token",
   372  			Token:         tokenGood.SecretID,
   373  			ExpectedError: structs.ErrUnknownAllocationPrefix,
   374  		},
   375  		{
   376  			Name:          "root token",
   377  			Token:         root.SecretID,
   378  			ExpectedError: structs.ErrUnknownAllocationPrefix,
   379  		},
   380  	}
   381  
   382  	for _, c := range cases {
   383  		t.Run(c.Name, func(t *testing.T) {
   384  
   385  			// Make the request without having a node-id
   386  			req := &structs.AllocSpecificRequest{
   387  				AllocID: uuid.Generate(),
   388  				QueryOptions: structs.QueryOptions{
   389  					AuthToken: c.Token,
   390  					Region:    "global",
   391  					Namespace: structs.DefaultNamespace,
   392  				},
   393  			}
   394  
   395  			// Fetch the response
   396  			var resp structs.GenericResponse
   397  			err := msgpackrpc.CallWithCodec(codec, "ClientAllocations.GarbageCollect", req, &resp)
   398  			require.NotNil(err)
   399  			require.Contains(err.Error(), c.ExpectedError)
   400  		})
   401  	}
   402  }
   403  
   404  func TestClientAllocations_GarbageCollect_Remote(t *testing.T) {
   405  	t.Parallel()
   406  	require := require.New(t)
   407  
   408  	// Start a server and client
   409  	s1 := TestServer(t, nil)
   410  	defer s1.Shutdown()
   411  	s2 := TestServer(t, func(c *Config) {
   412  		c.DevDisableBootstrap = true
   413  	})
   414  	defer s2.Shutdown()
   415  	TestJoin(t, s1, s2)
   416  	testutil.WaitForLeader(t, s1.RPC)
   417  	testutil.WaitForLeader(t, s2.RPC)
   418  	codec := rpcClient(t, s2)
   419  
   420  	c := client.TestClient(t, func(c *config.Config) {
   421  		c.Servers = []string{s2.config.RPCAddr.String()}
   422  		c.GCDiskUsageThreshold = 100.0
   423  	})
   424  	defer c.Shutdown()
   425  
   426  	// Force an allocation onto the node
   427  	a := mock.Alloc()
   428  	a.Job.Type = structs.JobTypeBatch
   429  	a.NodeID = c.NodeID()
   430  	a.Job.TaskGroups[0].Count = 1
   431  	a.Job.TaskGroups[0].Tasks[0] = &structs.Task{
   432  		Name:   "web",
   433  		Driver: "mock_driver",
   434  		Config: map[string]interface{}{
   435  			"run_for": "2s",
   436  		},
   437  		LogConfig: structs.DefaultLogConfig(),
   438  		Resources: &structs.Resources{
   439  			CPU:      500,
   440  			MemoryMB: 256,
   441  		},
   442  	}
   443  	testutil.WaitForResult(func() (bool, error) {
   444  		nodes := s2.connectedNodes()
   445  		return len(nodes) == 1, nil
   446  	}, func(err error) {
   447  		t.Fatalf("should have a clients")
   448  	})
   449  
   450  	// Upsert the allocation
   451  	state1 := s1.State()
   452  	state2 := s2.State()
   453  	require.Nil(state1.UpsertJob(999, a.Job))
   454  	require.Nil(state1.UpsertAllocs(1003, []*structs.Allocation{a}))
   455  	require.Nil(state2.UpsertJob(999, a.Job))
   456  	require.Nil(state2.UpsertAllocs(1003, []*structs.Allocation{a}))
   457  
   458  	// Wait for the client to run the allocation
   459  	testutil.WaitForResult(func() (bool, error) {
   460  		alloc, err := state2.AllocByID(nil, a.ID)
   461  		if err != nil {
   462  			return false, err
   463  		}
   464  		if alloc == nil {
   465  			return false, fmt.Errorf("unknown alloc")
   466  		}
   467  		if alloc.ClientStatus != structs.AllocClientStatusComplete {
   468  			return false, fmt.Errorf("alloc client status: %v", alloc.ClientStatus)
   469  		}
   470  
   471  		return true, nil
   472  	}, func(err error) {
   473  		t.Fatalf("Alloc on node %q not finished: %v", c.NodeID(), err)
   474  	})
   475  
   476  	// Force remove the connection locally in case it exists
   477  	s1.nodeConnsLock.Lock()
   478  	delete(s1.nodeConns, c.NodeID())
   479  	s1.nodeConnsLock.Unlock()
   480  
   481  	// Make the request
   482  	req := &structs.AllocSpecificRequest{
   483  		AllocID:      a.ID,
   484  		QueryOptions: structs.QueryOptions{Region: "global"},
   485  	}
   486  
   487  	// Fetch the response
   488  	var resp cstructs.ClientStatsResponse
   489  	err := msgpackrpc.CallWithCodec(codec, "ClientAllocations.GarbageCollect", req, &resp)
   490  	require.Nil(err)
   491  }
   492  
   493  func TestClientAllocations_Stats_OldNode(t *testing.T) {
   494  	t.Parallel()
   495  	require := require.New(t)
   496  
   497  	// Start a server and fake an old client
   498  	s := TestServer(t, nil)
   499  	defer s.Shutdown()
   500  	state := s.State()
   501  	codec := rpcClient(t, s)
   502  	testutil.WaitForLeader(t, s.RPC)
   503  
   504  	// Test for an old version error
   505  	node := mock.Node()
   506  	node.Attributes["nomad.version"] = "0.7.1"
   507  	require.Nil(state.UpsertNode(1005, node))
   508  
   509  	alloc := mock.Alloc()
   510  	alloc.NodeID = node.ID
   511  	require.Nil(state.UpsertAllocs(1006, []*structs.Allocation{alloc}))
   512  
   513  	req := &structs.AllocSpecificRequest{
   514  		AllocID: alloc.ID,
   515  		QueryOptions: structs.QueryOptions{
   516  			Region: "global",
   517  		},
   518  	}
   519  
   520  	var resp structs.GenericResponse
   521  	err := msgpackrpc.CallWithCodec(codec, "ClientAllocations.Stats", req, &resp)
   522  	require.True(structs.IsErrNodeLacksRpc(err), err.Error())
   523  
   524  	// Test for a missing version error
   525  	delete(node.Attributes, "nomad.version")
   526  	require.Nil(state.UpsertNode(1007, node))
   527  
   528  	err = msgpackrpc.CallWithCodec(codec, "ClientAllocations.Stats", req, &resp)
   529  	require.True(structs.IsErrUnknownNomadVersion(err), err.Error())
   530  }
   531  
   532  func TestClientAllocations_Stats_Local(t *testing.T) {
   533  	t.Parallel()
   534  	require := require.New(t)
   535  
   536  	// Start a server and client
   537  	s := TestServer(t, nil)
   538  	defer s.Shutdown()
   539  	codec := rpcClient(t, s)
   540  	testutil.WaitForLeader(t, s.RPC)
   541  
   542  	c := client.TestClient(t, func(c *config.Config) {
   543  		c.Servers = []string{s.config.RPCAddr.String()}
   544  	})
   545  	defer c.Shutdown()
   546  
   547  	// Force an allocation onto the node
   548  	a := mock.Alloc()
   549  	a.Job.Type = structs.JobTypeBatch
   550  	a.NodeID = c.NodeID()
   551  	a.Job.TaskGroups[0].Count = 1
   552  	a.Job.TaskGroups[0].Tasks[0] = &structs.Task{
   553  		Name:   "web",
   554  		Driver: "mock_driver",
   555  		Config: map[string]interface{}{
   556  			"run_for": "2s",
   557  		},
   558  		LogConfig: structs.DefaultLogConfig(),
   559  		Resources: &structs.Resources{
   560  			CPU:      500,
   561  			MemoryMB: 256,
   562  		},
   563  	}
   564  
   565  	testutil.WaitForResult(func() (bool, error) {
   566  		nodes := s.connectedNodes()
   567  		return len(nodes) == 1, nil
   568  	}, func(err error) {
   569  		t.Fatalf("should have a clients")
   570  	})
   571  
   572  	// Upsert the allocation
   573  	state := s.State()
   574  	require.Nil(state.UpsertJob(999, a.Job))
   575  	require.Nil(state.UpsertAllocs(1003, []*structs.Allocation{a}))
   576  
   577  	// Wait for the client to run the allocation
   578  	testutil.WaitForResult(func() (bool, error) {
   579  		alloc, err := state.AllocByID(nil, a.ID)
   580  		if err != nil {
   581  			return false, err
   582  		}
   583  		if alloc == nil {
   584  			return false, fmt.Errorf("unknown alloc")
   585  		}
   586  		if alloc.ClientStatus != structs.AllocClientStatusComplete {
   587  			return false, fmt.Errorf("alloc client status: %v", alloc.ClientStatus)
   588  		}
   589  
   590  		return true, nil
   591  	}, func(err error) {
   592  		t.Fatalf("Alloc on node %q not finished: %v", c.NodeID(), err)
   593  	})
   594  
   595  	// Make the request without having an alloc id
   596  	req := &structs.AllocSpecificRequest{
   597  		QueryOptions: structs.QueryOptions{Region: "global"},
   598  	}
   599  
   600  	// Fetch the response
   601  	var resp cstructs.AllocStatsResponse
   602  	err := msgpackrpc.CallWithCodec(codec, "ClientAllocations.Stats", req, &resp)
   603  	require.NotNil(err)
   604  	require.Contains(err.Error(), "missing")
   605  
   606  	// Fetch the response setting the node id
   607  	req.AllocID = a.ID
   608  	var resp2 cstructs.AllocStatsResponse
   609  	err = msgpackrpc.CallWithCodec(codec, "ClientAllocations.Stats", req, &resp2)
   610  	require.Nil(err)
   611  	require.NotNil(resp2.Stats)
   612  }
   613  
   614  func TestClientAllocations_Stats_Local_ACL(t *testing.T) {
   615  	t.Parallel()
   616  	require := require.New(t)
   617  
   618  	// Start a server
   619  	s, root := TestACLServer(t, nil)
   620  	defer s.Shutdown()
   621  	codec := rpcClient(t, s)
   622  	testutil.WaitForLeader(t, s.RPC)
   623  
   624  	// Create a bad token
   625  	policyBad := mock.NamespacePolicy("other", "", []string{acl.NamespaceCapabilityReadFS})
   626  	tokenBad := mock.CreatePolicyAndToken(t, s.State(), 1005, "invalid", policyBad)
   627  
   628  	policyGood := mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilityReadJob})
   629  	tokenGood := mock.CreatePolicyAndToken(t, s.State(), 1009, "valid2", policyGood)
   630  
   631  	cases := []struct {
   632  		Name          string
   633  		Token         string
   634  		ExpectedError string
   635  	}{
   636  		{
   637  			Name:          "bad token",
   638  			Token:         tokenBad.SecretID,
   639  			ExpectedError: structs.ErrPermissionDenied.Error(),
   640  		},
   641  		{
   642  			Name:          "good token",
   643  			Token:         tokenGood.SecretID,
   644  			ExpectedError: structs.ErrUnknownAllocationPrefix,
   645  		},
   646  		{
   647  			Name:          "root token",
   648  			Token:         root.SecretID,
   649  			ExpectedError: structs.ErrUnknownAllocationPrefix,
   650  		},
   651  	}
   652  
   653  	for _, c := range cases {
   654  		t.Run(c.Name, func(t *testing.T) {
   655  
   656  			// Make the request without having a node-id
   657  			req := &structs.AllocSpecificRequest{
   658  				AllocID: uuid.Generate(),
   659  				QueryOptions: structs.QueryOptions{
   660  					AuthToken: c.Token,
   661  					Region:    "global",
   662  					Namespace: structs.DefaultNamespace,
   663  				},
   664  			}
   665  
   666  			// Fetch the response
   667  			var resp cstructs.AllocStatsResponse
   668  			err := msgpackrpc.CallWithCodec(codec, "ClientAllocations.Stats", req, &resp)
   669  			require.NotNil(err)
   670  			require.Contains(err.Error(), c.ExpectedError)
   671  		})
   672  	}
   673  }
   674  
   675  func TestClientAllocations_Stats_Remote(t *testing.T) {
   676  	t.Parallel()
   677  	require := require.New(t)
   678  
   679  	// Start a server and client
   680  	s1 := TestServer(t, nil)
   681  	defer s1.Shutdown()
   682  	s2 := TestServer(t, func(c *Config) {
   683  		c.DevDisableBootstrap = true
   684  	})
   685  	defer s2.Shutdown()
   686  	TestJoin(t, s1, s2)
   687  	testutil.WaitForLeader(t, s1.RPC)
   688  	testutil.WaitForLeader(t, s2.RPC)
   689  	codec := rpcClient(t, s2)
   690  
   691  	c := client.TestClient(t, func(c *config.Config) {
   692  		c.Servers = []string{s2.config.RPCAddr.String()}
   693  	})
   694  	defer c.Shutdown()
   695  
   696  	// Force an allocation onto the node
   697  	a := mock.Alloc()
   698  	a.Job.Type = structs.JobTypeBatch
   699  	a.NodeID = c.NodeID()
   700  	a.Job.TaskGroups[0].Count = 1
   701  	a.Job.TaskGroups[0].Tasks[0] = &structs.Task{
   702  		Name:   "web",
   703  		Driver: "mock_driver",
   704  		Config: map[string]interface{}{
   705  			"run_for": "2s",
   706  		},
   707  		LogConfig: structs.DefaultLogConfig(),
   708  		Resources: &structs.Resources{
   709  			CPU:      500,
   710  			MemoryMB: 256,
   711  		},
   712  	}
   713  	testutil.WaitForResult(func() (bool, error) {
   714  		nodes := s2.connectedNodes()
   715  		return len(nodes) == 1, nil
   716  	}, func(err error) {
   717  		t.Fatalf("should have a clients")
   718  	})
   719  
   720  	// Upsert the allocation
   721  	state1 := s1.State()
   722  	state2 := s2.State()
   723  	require.Nil(state1.UpsertJob(999, a.Job))
   724  	require.Nil(state1.UpsertAllocs(1003, []*structs.Allocation{a}))
   725  	require.Nil(state2.UpsertJob(999, a.Job))
   726  	require.Nil(state2.UpsertAllocs(1003, []*structs.Allocation{a}))
   727  
   728  	// Wait for the client to run the allocation
   729  	testutil.WaitForResult(func() (bool, error) {
   730  		alloc, err := state2.AllocByID(nil, a.ID)
   731  		if err != nil {
   732  			return false, err
   733  		}
   734  		if alloc == nil {
   735  			return false, fmt.Errorf("unknown alloc")
   736  		}
   737  		if alloc.ClientStatus != structs.AllocClientStatusComplete {
   738  			return false, fmt.Errorf("alloc client status: %v", alloc.ClientStatus)
   739  		}
   740  
   741  		return true, nil
   742  	}, func(err error) {
   743  		t.Fatalf("Alloc on node %q not finished: %v", c.NodeID(), err)
   744  	})
   745  
   746  	// Force remove the connection locally in case it exists
   747  	s1.nodeConnsLock.Lock()
   748  	delete(s1.nodeConns, c.NodeID())
   749  	s1.nodeConnsLock.Unlock()
   750  
   751  	// Make the request
   752  	req := &structs.AllocSpecificRequest{
   753  		AllocID:      a.ID,
   754  		QueryOptions: structs.QueryOptions{Region: "global"},
   755  	}
   756  
   757  	// Fetch the response
   758  	var resp cstructs.AllocStatsResponse
   759  	err := msgpackrpc.CallWithCodec(codec, "ClientAllocations.Stats", req, &resp)
   760  	require.Nil(err)
   761  	require.NotNil(resp.Stats)
   762  }