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