github.com/quite/nomad@v0.8.6/command/agent/alloc_endpoint_test.go (about)

     1  package agent
     2  
     3  import (
     4  	"archive/tar"
     5  	"fmt"
     6  	"io"
     7  	"io/ioutil"
     8  	"net/http"
     9  	"net/http/httptest"
    10  	"os"
    11  	"reflect"
    12  	"strings"
    13  	"testing"
    14  
    15  	"github.com/golang/snappy"
    16  	"github.com/hashicorp/nomad/acl"
    17  	"github.com/hashicorp/nomad/client/allocdir"
    18  	"github.com/hashicorp/nomad/helper"
    19  	"github.com/hashicorp/nomad/helper/uuid"
    20  	"github.com/hashicorp/nomad/nomad/mock"
    21  	"github.com/hashicorp/nomad/nomad/structs"
    22  	"github.com/hashicorp/nomad/testutil"
    23  	"github.com/stretchr/testify/require"
    24  )
    25  
    26  func TestHTTP_AllocsList(t *testing.T) {
    27  	t.Parallel()
    28  	httpTest(t, nil, func(s *TestAgent) {
    29  		// Directly manipulate the state
    30  		state := s.Agent.server.State()
    31  		alloc1 := mock.Alloc()
    32  		testEvent := structs.NewTaskEvent(structs.TaskSiblingFailed)
    33  		var events1 []*structs.TaskEvent
    34  		events1 = append(events1, testEvent)
    35  		taskState := &structs.TaskState{Events: events1}
    36  		alloc1.TaskStates = make(map[string]*structs.TaskState)
    37  		alloc1.TaskStates["test"] = taskState
    38  
    39  		alloc2 := mock.Alloc()
    40  		alloc2.TaskStates = make(map[string]*structs.TaskState)
    41  		alloc2.TaskStates["test"] = taskState
    42  
    43  		state.UpsertJobSummary(998, mock.JobSummary(alloc1.JobID))
    44  		state.UpsertJobSummary(999, mock.JobSummary(alloc2.JobID))
    45  		err := state.UpsertAllocs(1000,
    46  			[]*structs.Allocation{alloc1, alloc2})
    47  		if err != nil {
    48  			t.Fatalf("err: %v", err)
    49  		}
    50  
    51  		// Make the HTTP request
    52  		req, err := http.NewRequest("GET", "/v1/allocations", nil)
    53  		if err != nil {
    54  			t.Fatalf("err: %v", err)
    55  		}
    56  		respW := httptest.NewRecorder()
    57  
    58  		// Make the request
    59  		obj, err := s.Server.AllocsRequest(respW, req)
    60  		if err != nil {
    61  			t.Fatalf("err: %v", err)
    62  		}
    63  
    64  		// Check for the index
    65  		if respW.HeaderMap.Get("X-Nomad-Index") == "" {
    66  			t.Fatalf("missing index")
    67  		}
    68  		if respW.HeaderMap.Get("X-Nomad-KnownLeader") != "true" {
    69  			t.Fatalf("missing known leader")
    70  		}
    71  		if respW.HeaderMap.Get("X-Nomad-LastContact") == "" {
    72  			t.Fatalf("missing last contact")
    73  		}
    74  
    75  		// Check the alloc
    76  		allocs := obj.([]*structs.AllocListStub)
    77  		if len(allocs) != 2 {
    78  			t.Fatalf("bad: %#v", allocs)
    79  		}
    80  		expectedMsg := "Task's sibling failed"
    81  		displayMsg1 := allocs[0].TaskStates["test"].Events[0].DisplayMessage
    82  		require.Equal(t, expectedMsg, displayMsg1, "DisplayMessage should be set")
    83  		displayMsg2 := allocs[0].TaskStates["test"].Events[0].DisplayMessage
    84  		require.Equal(t, expectedMsg, displayMsg2, "DisplayMessage should be set")
    85  	})
    86  }
    87  
    88  func TestHTTP_AllocsPrefixList(t *testing.T) {
    89  	t.Parallel()
    90  	httpTest(t, nil, func(s *TestAgent) {
    91  		// Directly manipulate the state
    92  		state := s.Agent.server.State()
    93  
    94  		alloc1 := mock.Alloc()
    95  		alloc1.ID = "aaaaaaaa-e8f7-fd38-c855-ab94ceb89706"
    96  		alloc2 := mock.Alloc()
    97  		alloc2.ID = "aaabbbbb-e8f7-fd38-c855-ab94ceb89706"
    98  
    99  		testEvent := structs.NewTaskEvent(structs.TaskSiblingFailed)
   100  		var events1 []*structs.TaskEvent
   101  		events1 = append(events1, testEvent)
   102  		taskState := &structs.TaskState{Events: events1}
   103  		alloc2.TaskStates = make(map[string]*structs.TaskState)
   104  		alloc2.TaskStates["test"] = taskState
   105  
   106  		summary1 := mock.JobSummary(alloc1.JobID)
   107  		summary2 := mock.JobSummary(alloc2.JobID)
   108  		if err := state.UpsertJobSummary(998, summary1); err != nil {
   109  			t.Fatal(err)
   110  		}
   111  		if err := state.UpsertJobSummary(999, summary2); err != nil {
   112  			t.Fatal(err)
   113  		}
   114  		if err := state.UpsertAllocs(1000,
   115  			[]*structs.Allocation{alloc1, alloc2}); err != nil {
   116  			t.Fatalf("err: %v", err)
   117  		}
   118  
   119  		// Make the HTTP request
   120  		req, err := http.NewRequest("GET", "/v1/allocations?prefix=aaab", nil)
   121  		if err != nil {
   122  			t.Fatalf("err: %v", err)
   123  		}
   124  		respW := httptest.NewRecorder()
   125  
   126  		// Make the request
   127  		obj, err := s.Server.AllocsRequest(respW, req)
   128  		if err != nil {
   129  			t.Fatalf("err: %v", err)
   130  		}
   131  
   132  		// Check for the index
   133  		if respW.HeaderMap.Get("X-Nomad-Index") == "" {
   134  			t.Fatalf("missing index")
   135  		}
   136  		if respW.HeaderMap.Get("X-Nomad-KnownLeader") != "true" {
   137  			t.Fatalf("missing known leader")
   138  		}
   139  		if respW.HeaderMap.Get("X-Nomad-LastContact") == "" {
   140  			t.Fatalf("missing last contact")
   141  		}
   142  
   143  		// Check the alloc
   144  		n := obj.([]*structs.AllocListStub)
   145  		if len(n) != 1 {
   146  			t.Fatalf("bad: %#v", n)
   147  		}
   148  
   149  		// Check the identifier
   150  		if n[0].ID != alloc2.ID {
   151  			t.Fatalf("expected alloc ID: %v, Actual: %v", alloc2.ID, n[0].ID)
   152  		}
   153  		expectedMsg := "Task's sibling failed"
   154  		displayMsg1 := n[0].TaskStates["test"].Events[0].DisplayMessage
   155  		require.Equal(t, expectedMsg, displayMsg1, "DisplayMessage should be set")
   156  
   157  	})
   158  }
   159  
   160  func TestHTTP_AllocQuery(t *testing.T) {
   161  	t.Parallel()
   162  	httpTest(t, nil, func(s *TestAgent) {
   163  		// Directly manipulate the state
   164  		state := s.Agent.server.State()
   165  		alloc := mock.Alloc()
   166  		if err := state.UpsertJobSummary(999, mock.JobSummary(alloc.JobID)); err != nil {
   167  			t.Fatal(err)
   168  		}
   169  		err := state.UpsertAllocs(1000,
   170  			[]*structs.Allocation{alloc})
   171  		if err != nil {
   172  			t.Fatalf("err: %v", err)
   173  		}
   174  
   175  		// Make the HTTP request
   176  		req, err := http.NewRequest("GET", "/v1/allocation/"+alloc.ID, nil)
   177  		if err != nil {
   178  			t.Fatalf("err: %v", err)
   179  		}
   180  		respW := httptest.NewRecorder()
   181  
   182  		// Make the request
   183  		obj, err := s.Server.AllocSpecificRequest(respW, req)
   184  		if err != nil {
   185  			t.Fatalf("err: %v", err)
   186  		}
   187  
   188  		// Check for the index
   189  		if respW.HeaderMap.Get("X-Nomad-Index") == "" {
   190  			t.Fatalf("missing index")
   191  		}
   192  		if respW.HeaderMap.Get("X-Nomad-KnownLeader") != "true" {
   193  			t.Fatalf("missing known leader")
   194  		}
   195  		if respW.HeaderMap.Get("X-Nomad-LastContact") == "" {
   196  			t.Fatalf("missing last contact")
   197  		}
   198  
   199  		// Check the job
   200  		a := obj.(*structs.Allocation)
   201  		if a.ID != alloc.ID {
   202  			t.Fatalf("bad: %#v", a)
   203  		}
   204  	})
   205  }
   206  
   207  func TestHTTP_AllocQuery_Payload(t *testing.T) {
   208  	t.Parallel()
   209  	httpTest(t, nil, func(s *TestAgent) {
   210  		// Directly manipulate the state
   211  		state := s.Agent.server.State()
   212  		alloc := mock.Alloc()
   213  		if err := state.UpsertJobSummary(999, mock.JobSummary(alloc.JobID)); err != nil {
   214  			t.Fatal(err)
   215  		}
   216  
   217  		// Insert Payload compressed
   218  		expected := []byte("hello world")
   219  		compressed := snappy.Encode(nil, expected)
   220  		alloc.Job.Payload = compressed
   221  
   222  		err := state.UpsertAllocs(1000, []*structs.Allocation{alloc})
   223  		if err != nil {
   224  			t.Fatalf("err: %v", err)
   225  		}
   226  
   227  		// Make the HTTP request
   228  		req, err := http.NewRequest("GET", "/v1/allocation/"+alloc.ID, nil)
   229  		if err != nil {
   230  			t.Fatalf("err: %v", err)
   231  		}
   232  		respW := httptest.NewRecorder()
   233  
   234  		// Make the request
   235  		obj, err := s.Server.AllocSpecificRequest(respW, req)
   236  		if err != nil {
   237  			t.Fatalf("err: %v", err)
   238  		}
   239  
   240  		// Check for the index
   241  		if respW.HeaderMap.Get("X-Nomad-Index") == "" {
   242  			t.Fatalf("missing index")
   243  		}
   244  		if respW.HeaderMap.Get("X-Nomad-KnownLeader") != "true" {
   245  			t.Fatalf("missing known leader")
   246  		}
   247  		if respW.HeaderMap.Get("X-Nomad-LastContact") == "" {
   248  			t.Fatalf("missing last contact")
   249  		}
   250  
   251  		// Check the job
   252  		a := obj.(*structs.Allocation)
   253  		if a.ID != alloc.ID {
   254  			t.Fatalf("bad: %#v", a)
   255  		}
   256  
   257  		// Check the payload is decompressed
   258  		if !reflect.DeepEqual(a.Job.Payload, expected) {
   259  			t.Fatalf("Payload not decompressed properly; got %#v; want %#v", a.Job.Payload, expected)
   260  		}
   261  	})
   262  }
   263  
   264  func TestHTTP_AllocStats(t *testing.T) {
   265  	t.Parallel()
   266  	require := require.New(t)
   267  
   268  	httpTest(t, nil, func(s *TestAgent) {
   269  		// Local node, local resp
   270  		{
   271  			// Make the HTTP request
   272  			req, err := http.NewRequest("GET", fmt.Sprintf("/v1/client/allocation/%s/stats", uuid.Generate()), nil)
   273  			if err != nil {
   274  				t.Fatalf("err: %v", err)
   275  			}
   276  			respW := httptest.NewRecorder()
   277  
   278  			// Make the request
   279  			_, err = s.Server.ClientAllocRequest(respW, req)
   280  			require.NotNil(err)
   281  			require.True(structs.IsErrUnknownAllocation(err))
   282  		}
   283  
   284  		// Local node, server resp
   285  		{
   286  			srv := s.server
   287  			s.server = nil
   288  
   289  			req, err := http.NewRequest("GET", fmt.Sprintf("/v1/client/allocation/%s/stats", uuid.Generate()), nil)
   290  			require.Nil(err)
   291  
   292  			respW := httptest.NewRecorder()
   293  			_, err = s.Server.ClientAllocRequest(respW, req)
   294  			require.NotNil(err)
   295  			require.True(structs.IsErrUnknownAllocation(err))
   296  
   297  			s.server = srv
   298  		}
   299  
   300  		// no client, server resp
   301  		{
   302  			c := s.client
   303  			s.client = nil
   304  
   305  			testutil.WaitForResult(func() (bool, error) {
   306  				n, err := s.server.State().NodeByID(nil, c.NodeID())
   307  				if err != nil {
   308  					return false, err
   309  				}
   310  				return n != nil, nil
   311  			}, func(err error) {
   312  				t.Fatalf("should have client: %v", err)
   313  			})
   314  
   315  			req, err := http.NewRequest("GET", fmt.Sprintf("/v1/client/allocation/%s/stats", uuid.Generate()), nil)
   316  			require.Nil(err)
   317  
   318  			respW := httptest.NewRecorder()
   319  			_, err = s.Server.ClientAllocRequest(respW, req)
   320  			require.NotNil(err)
   321  			require.True(structs.IsErrUnknownAllocation(err))
   322  
   323  			s.client = c
   324  		}
   325  	})
   326  }
   327  
   328  func TestHTTP_AllocStats_ACL(t *testing.T) {
   329  	t.Parallel()
   330  	require := require.New(t)
   331  
   332  	httpACLTest(t, nil, func(s *TestAgent) {
   333  		state := s.Agent.server.State()
   334  
   335  		// Make the HTTP request
   336  		req, err := http.NewRequest("GET", fmt.Sprintf("/v1/client/allocation/%s/stats", uuid.Generate()), nil)
   337  		if err != nil {
   338  			t.Fatalf("err: %v", err)
   339  		}
   340  
   341  		// Try request without a token and expect failure
   342  		{
   343  			respW := httptest.NewRecorder()
   344  			_, err := s.Server.ClientAllocRequest(respW, req)
   345  			require.NotNil(err)
   346  			require.Equal(err.Error(), structs.ErrPermissionDenied.Error())
   347  		}
   348  
   349  		// Try request with an invalid token and expect failure
   350  		{
   351  			respW := httptest.NewRecorder()
   352  			token := mock.CreatePolicyAndToken(t, state, 1005, "invalid", mock.NodePolicy(acl.PolicyWrite))
   353  			setToken(req, token)
   354  			_, err := s.Server.ClientAllocRequest(respW, req)
   355  			require.NotNil(err)
   356  			require.Equal(err.Error(), structs.ErrPermissionDenied.Error())
   357  		}
   358  
   359  		// Try request with a valid token
   360  		// Still returns an error because the alloc does not exist
   361  		{
   362  			respW := httptest.NewRecorder()
   363  			policy := mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilityReadJob})
   364  			token := mock.CreatePolicyAndToken(t, state, 1007, "valid", policy)
   365  			setToken(req, token)
   366  			_, err := s.Server.ClientAllocRequest(respW, req)
   367  			require.NotNil(err)
   368  			require.True(structs.IsErrUnknownAllocation(err))
   369  		}
   370  
   371  		// Try request with a management token
   372  		// Still returns an error because the alloc does not exist
   373  		{
   374  			respW := httptest.NewRecorder()
   375  			setToken(req, s.RootToken)
   376  			_, err := s.Server.ClientAllocRequest(respW, req)
   377  			require.NotNil(err)
   378  			require.True(structs.IsErrUnknownAllocation(err))
   379  		}
   380  	})
   381  }
   382  
   383  func TestHTTP_AllocSnapshot(t *testing.T) {
   384  	t.Parallel()
   385  	httpTest(t, nil, func(s *TestAgent) {
   386  		// Make the HTTP request
   387  		req, err := http.NewRequest("GET", "/v1/client/allocation/123/snapshot", nil)
   388  		if err != nil {
   389  			t.Fatalf("err: %v", err)
   390  		}
   391  		respW := httptest.NewRecorder()
   392  
   393  		// Make the request
   394  		_, err = s.Server.ClientAllocRequest(respW, req)
   395  		if !strings.Contains(err.Error(), allocNotFoundErr) {
   396  			t.Fatalf("err: %v", err)
   397  		}
   398  	})
   399  }
   400  
   401  func TestHTTP_AllocSnapshot_WithMigrateToken(t *testing.T) {
   402  	t.Parallel()
   403  	require := require.New(t)
   404  	httpACLTest(t, nil, func(s *TestAgent) {
   405  		// Request without a token fails
   406  		req, err := http.NewRequest("GET", "/v1/client/allocation/123/snapshot", nil)
   407  		require.Nil(err)
   408  
   409  		// Make the unauthorized request
   410  		respW := httptest.NewRecorder()
   411  		_, err = s.Server.ClientAllocRequest(respW, req)
   412  		require.NotNil(err)
   413  		require.EqualError(err, structs.ErrPermissionDenied.Error())
   414  
   415  		// Create an allocation
   416  		alloc := mock.Alloc()
   417  
   418  		validMigrateToken, err := structs.GenerateMigrateToken(alloc.ID, s.Agent.Client().Node().SecretID)
   419  		require.Nil(err)
   420  
   421  		// Request with a token succeeds
   422  		url := fmt.Sprintf("/v1/client/allocation/%s/snapshot", alloc.ID)
   423  		req, err = http.NewRequest("GET", url, nil)
   424  		require.Nil(err)
   425  
   426  		req.Header.Set("X-Nomad-Token", validMigrateToken)
   427  
   428  		// Make the unauthorized request
   429  		respW = httptest.NewRecorder()
   430  		_, err = s.Server.ClientAllocRequest(respW, req)
   431  		require.NotContains(err.Error(), structs.ErrPermissionDenied.Error())
   432  	})
   433  }
   434  
   435  // TestHTTP_AllocSnapshot_Atomic ensures that when a client encounters an error
   436  // snapshotting a valid tar is not returned.
   437  func TestHTTP_AllocSnapshot_Atomic(t *testing.T) {
   438  	t.Parallel()
   439  	httpTest(t, func(c *Config) {
   440  		// Disable the schedulers
   441  		c.Server.NumSchedulers = helper.IntToPtr(0)
   442  	}, func(s *TestAgent) {
   443  		// Create an alloc
   444  		state := s.server.State()
   445  		alloc := mock.Alloc()
   446  		alloc.Job.TaskGroups[0].Tasks[0].Driver = "mock_driver"
   447  		alloc.Job.TaskGroups[0].Tasks[0].Config["run_for"] = "30s"
   448  		alloc.NodeID = s.client.NodeID()
   449  		state.UpsertJobSummary(998, mock.JobSummary(alloc.JobID))
   450  		if err := state.UpsertAllocs(1000, []*structs.Allocation{alloc.Copy()}); err != nil {
   451  			t.Fatalf("error upserting alloc: %v", err)
   452  		}
   453  
   454  		// Wait for the client to run it
   455  		testutil.WaitForResult(func() (bool, error) {
   456  			if _, err := s.client.GetClientAlloc(alloc.ID); err != nil {
   457  				return false, err
   458  			}
   459  
   460  			serverAlloc, err := state.AllocByID(nil, alloc.ID)
   461  			if err != nil {
   462  				return false, err
   463  			}
   464  
   465  			return serverAlloc.ClientStatus == structs.AllocClientStatusRunning, fmt.Errorf(serverAlloc.ClientStatus)
   466  		}, func(err error) {
   467  			t.Fatalf("client not running alloc: %v", err)
   468  		})
   469  
   470  		// Now write to its shared dir
   471  		allocDirI, err := s.client.GetAllocFS(alloc.ID)
   472  		if err != nil {
   473  			t.Fatalf("unable to find alloc dir: %v", err)
   474  		}
   475  		allocDir := allocDirI.(*allocdir.AllocDir)
   476  
   477  		// Remove the task dir to break Snapshot
   478  		os.RemoveAll(allocDir.TaskDirs["web"].LocalDir)
   479  
   480  		// require Snapshot fails
   481  		if err := allocDir.Snapshot(ioutil.Discard); err != nil {
   482  			s.logger.Printf("[DEBUG] agent.test: snapshot returned error: %v", err)
   483  		} else {
   484  			t.Errorf("expected Snapshot() to fail but it did not")
   485  		}
   486  
   487  		// Make the HTTP request to ensure the Snapshot error is
   488  		// propagated through to the HTTP layer. Since the tar is
   489  		// streamed over a 200 HTTP response the only way to signal an
   490  		// error is by writing a marker file.
   491  		respW := httptest.NewRecorder()
   492  		req, err := http.NewRequest("GET", fmt.Sprintf("/v1/client/allocation/%s/snapshot", alloc.ID), nil)
   493  		if err != nil {
   494  			t.Fatalf("err: %v", err)
   495  		}
   496  
   497  		// Make the request via the mux to make sure the error returned
   498  		// by Snapshot is properly propagated via HTTP
   499  		s.Server.mux.ServeHTTP(respW, req)
   500  		resp := respW.Result()
   501  		r := tar.NewReader(resp.Body)
   502  		errorFilename := allocdir.SnapshotErrorFilename(alloc.ID)
   503  		markerFound := false
   504  		markerContents := ""
   505  		for {
   506  			header, err := r.Next()
   507  			if err != nil {
   508  				if err != io.EOF {
   509  					// Huh, I wonder how a non-EOF error can happen?
   510  					t.Errorf("Unexpected error while streaming: %v", err)
   511  				}
   512  				break
   513  			}
   514  
   515  			if markerFound {
   516  				// No more files should be found after the failure marker
   517  				t.Errorf("Next file found after error marker: %s", header.Name)
   518  				break
   519  			}
   520  
   521  			if header.Name == errorFilename {
   522  				// Found it!
   523  				markerFound = true
   524  				buf := make([]byte, int(header.Size))
   525  				if _, err := r.Read(buf); err != nil && err != io.EOF {
   526  					t.Errorf("Unexpected error reading error marker %s: %v", errorFilename, err)
   527  				} else {
   528  					markerContents = string(buf)
   529  				}
   530  			}
   531  		}
   532  
   533  		if !markerFound {
   534  			t.Fatalf("marker file %s not written; bad tar will be treated as good!", errorFilename)
   535  		}
   536  		if markerContents == "" {
   537  			t.Fatalf("marker file %s empty", markerContents)
   538  		} else {
   539  			t.Logf("EXPECTED snapshot error: %s", markerContents)
   540  		}
   541  	})
   542  }
   543  
   544  func TestHTTP_AllocGC(t *testing.T) {
   545  	t.Parallel()
   546  	require := require.New(t)
   547  	path := fmt.Sprintf("/v1/client/allocation/%s/gc", uuid.Generate())
   548  	httpTest(t, nil, func(s *TestAgent) {
   549  		// Local node, local resp
   550  		{
   551  			req, err := http.NewRequest("GET", path, nil)
   552  			if err != nil {
   553  				t.Fatalf("err: %v", err)
   554  			}
   555  
   556  			respW := httptest.NewRecorder()
   557  			_, err = s.Server.ClientAllocRequest(respW, req)
   558  			if !structs.IsErrUnknownAllocation(err) {
   559  				t.Fatalf("unexpected err: %v", err)
   560  			}
   561  		}
   562  
   563  		// Local node, server resp
   564  		{
   565  			srv := s.server
   566  			s.server = nil
   567  
   568  			req, err := http.NewRequest("GET", path, nil)
   569  			if err != nil {
   570  				t.Fatalf("err: %v", err)
   571  			}
   572  
   573  			respW := httptest.NewRecorder()
   574  			_, err = s.Server.ClientAllocRequest(respW, req)
   575  			if !structs.IsErrUnknownAllocation(err) {
   576  				t.Fatalf("unexpected err: %v", err)
   577  			}
   578  
   579  			s.server = srv
   580  		}
   581  
   582  		// no client, server resp
   583  		{
   584  			c := s.client
   585  			s.client = nil
   586  
   587  			testutil.WaitForResult(func() (bool, error) {
   588  				n, err := s.server.State().NodeByID(nil, c.NodeID())
   589  				if err != nil {
   590  					return false, err
   591  				}
   592  				return n != nil, nil
   593  			}, func(err error) {
   594  				t.Fatalf("should have client: %v", err)
   595  			})
   596  
   597  			req, err := http.NewRequest("GET", path, nil)
   598  			if err != nil {
   599  				t.Fatalf("err: %v", err)
   600  			}
   601  
   602  			respW := httptest.NewRecorder()
   603  			_, err = s.Server.ClientAllocRequest(respW, req)
   604  			require.NotNil(err)
   605  			if !structs.IsErrUnknownAllocation(err) {
   606  				t.Fatalf("unexpected err: %v", err)
   607  			}
   608  
   609  			s.client = c
   610  		}
   611  	})
   612  }
   613  
   614  func TestHTTP_AllocGC_ACL(t *testing.T) {
   615  	t.Parallel()
   616  	require := require.New(t)
   617  	path := fmt.Sprintf("/v1/client/allocation/%s/gc", uuid.Generate())
   618  
   619  	httpACLTest(t, nil, func(s *TestAgent) {
   620  		state := s.Agent.server.State()
   621  
   622  		// Make the HTTP request
   623  		req, err := http.NewRequest("GET", path, nil)
   624  		if err != nil {
   625  			t.Fatalf("err: %v", err)
   626  		}
   627  
   628  		// Try request without a token and expect failure
   629  		{
   630  			respW := httptest.NewRecorder()
   631  			_, err := s.Server.ClientAllocRequest(respW, req)
   632  			require.NotNil(err)
   633  			require.Equal(err.Error(), structs.ErrPermissionDenied.Error())
   634  		}
   635  
   636  		// Try request with an invalid token and expect failure
   637  		{
   638  			respW := httptest.NewRecorder()
   639  			token := mock.CreatePolicyAndToken(t, state, 1005, "invalid", mock.NodePolicy(acl.PolicyWrite))
   640  			setToken(req, token)
   641  			_, err := s.Server.ClientAllocRequest(respW, req)
   642  			require.NotNil(err)
   643  			require.Equal(err.Error(), structs.ErrPermissionDenied.Error())
   644  		}
   645  
   646  		// Try request with a valid token
   647  		// Still returns an error because the alloc does not exist
   648  		{
   649  			respW := httptest.NewRecorder()
   650  			policy := mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilitySubmitJob})
   651  			token := mock.CreatePolicyAndToken(t, state, 1007, "valid", policy)
   652  			setToken(req, token)
   653  			_, err := s.Server.ClientAllocRequest(respW, req)
   654  			require.NotNil(err)
   655  			require.True(structs.IsErrUnknownAllocation(err))
   656  		}
   657  
   658  		// Try request with a management token
   659  		// Still returns an error because the alloc does not exist
   660  		{
   661  			respW := httptest.NewRecorder()
   662  			setToken(req, s.RootToken)
   663  			_, err := s.Server.ClientAllocRequest(respW, req)
   664  			require.NotNil(err)
   665  			require.True(structs.IsErrUnknownAllocation(err))
   666  		}
   667  	})
   668  }
   669  
   670  func TestHTTP_AllocAllGC(t *testing.T) {
   671  	t.Parallel()
   672  	require := require.New(t)
   673  	httpTest(t, nil, func(s *TestAgent) {
   674  		// Local node, local resp
   675  		{
   676  			req, err := http.NewRequest("GET", "/v1/client/gc", nil)
   677  			if err != nil {
   678  				t.Fatalf("err: %v", err)
   679  			}
   680  
   681  			respW := httptest.NewRecorder()
   682  			_, err = s.Server.ClientGCRequest(respW, req)
   683  			if err != nil {
   684  				t.Fatalf("unexpected err: %v", err)
   685  			}
   686  		}
   687  
   688  		// Local node, server resp
   689  		{
   690  			srv := s.server
   691  			s.server = nil
   692  
   693  			req, err := http.NewRequest("GET", fmt.Sprintf("/v1/client/gc?node_id=%s", uuid.Generate()), nil)
   694  			require.Nil(err)
   695  
   696  			respW := httptest.NewRecorder()
   697  			_, err = s.Server.ClientGCRequest(respW, req)
   698  			require.NotNil(err)
   699  			require.Contains(err.Error(), "Unknown node")
   700  
   701  			s.server = srv
   702  		}
   703  
   704  		// client stats from server, should not error
   705  		{
   706  			c := s.client
   707  			s.client = nil
   708  
   709  			testutil.WaitForResult(func() (bool, error) {
   710  				n, err := s.server.State().NodeByID(nil, c.NodeID())
   711  				if err != nil {
   712  					return false, err
   713  				}
   714  				return n != nil, nil
   715  			}, func(err error) {
   716  				t.Fatalf("should have client: %v", err)
   717  			})
   718  
   719  			req, err := http.NewRequest("GET", fmt.Sprintf("/v1/client/gc?node_id=%s", c.NodeID()), nil)
   720  			require.Nil(err)
   721  
   722  			respW := httptest.NewRecorder()
   723  			_, err = s.Server.ClientGCRequest(respW, req)
   724  			require.Nil(err)
   725  
   726  			s.client = c
   727  		}
   728  	})
   729  
   730  }
   731  
   732  func TestHTTP_AllocAllGC_ACL(t *testing.T) {
   733  	t.Parallel()
   734  	require := require.New(t)
   735  	httpACLTest(t, nil, func(s *TestAgent) {
   736  		state := s.Agent.server.State()
   737  
   738  		// Make the HTTP request
   739  		req, err := http.NewRequest("GET", "/v1/client/gc", nil)
   740  		require.Nil(err)
   741  
   742  		// Try request without a token and expect failure
   743  		{
   744  			respW := httptest.NewRecorder()
   745  			_, err := s.Server.ClientGCRequest(respW, req)
   746  			require.NotNil(err)
   747  			require.Equal(err.Error(), structs.ErrPermissionDenied.Error())
   748  		}
   749  
   750  		// Try request with an invalid token and expect failure
   751  		{
   752  			respW := httptest.NewRecorder()
   753  			token := mock.CreatePolicyAndToken(t, state, 1005, "invalid", mock.NodePolicy(acl.PolicyRead))
   754  			setToken(req, token)
   755  			_, err := s.Server.ClientGCRequest(respW, req)
   756  			require.NotNil(err)
   757  			require.Equal(err.Error(), structs.ErrPermissionDenied.Error())
   758  		}
   759  
   760  		// Try request with a valid token
   761  		{
   762  			respW := httptest.NewRecorder()
   763  			token := mock.CreatePolicyAndToken(t, state, 1007, "valid", mock.NodePolicy(acl.PolicyWrite))
   764  			setToken(req, token)
   765  			_, err := s.Server.ClientGCRequest(respW, req)
   766  			require.Nil(err)
   767  			require.Equal(http.StatusOK, respW.Code)
   768  		}
   769  
   770  		// Try request with a management token
   771  		{
   772  			respW := httptest.NewRecorder()
   773  			setToken(req, s.RootToken)
   774  			_, err := s.Server.ClientGCRequest(respW, req)
   775  			require.Nil(err)
   776  			require.Equal(http.StatusOK, respW.Code)
   777  		}
   778  	})
   779  }