github.com/smithx10/nomad@v0.9.1-rc1/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 = map[string]interface{}{
   448  			"run_for": "30s",
   449  		}
   450  		alloc.NodeID = s.client.NodeID()
   451  		state.UpsertJobSummary(998, mock.JobSummary(alloc.JobID))
   452  		if err := state.UpsertAllocs(1000, []*structs.Allocation{alloc.Copy()}); err != nil {
   453  			t.Fatalf("error upserting alloc: %v", err)
   454  		}
   455  
   456  		// Wait for the client to run it
   457  		testutil.WaitForResult(func() (bool, error) {
   458  			if _, err := s.client.GetAllocState(alloc.ID); err != nil {
   459  				return false, err
   460  			}
   461  
   462  			serverAlloc, err := state.AllocByID(nil, alloc.ID)
   463  			if err != nil {
   464  				return false, err
   465  			}
   466  
   467  			return serverAlloc.ClientStatus == structs.AllocClientStatusRunning, fmt.Errorf(serverAlloc.ClientStatus)
   468  		}, func(err error) {
   469  			t.Fatalf("client not running alloc: %v", err)
   470  		})
   471  
   472  		// Now write to its shared dir
   473  		allocDirI, err := s.client.GetAllocFS(alloc.ID)
   474  		if err != nil {
   475  			t.Fatalf("unable to find alloc dir: %v", err)
   476  		}
   477  		allocDir := allocDirI.(*allocdir.AllocDir)
   478  
   479  		// Remove the task dir to break Snapshot
   480  		os.RemoveAll(allocDir.TaskDirs["web"].LocalDir)
   481  
   482  		// require Snapshot fails
   483  		if err := allocDir.Snapshot(ioutil.Discard); err != nil {
   484  			t.Logf("[DEBUG] agent.test: snapshot returned error: %v", err)
   485  		} else {
   486  			t.Errorf("expected Snapshot() to fail but it did not")
   487  		}
   488  
   489  		// Make the HTTP request to ensure the Snapshot error is
   490  		// propagated through to the HTTP layer. Since the tar is
   491  		// streamed over a 200 HTTP response the only way to signal an
   492  		// error is by writing a marker file.
   493  		respW := httptest.NewRecorder()
   494  		req, err := http.NewRequest("GET", fmt.Sprintf("/v1/client/allocation/%s/snapshot", alloc.ID), nil)
   495  		if err != nil {
   496  			t.Fatalf("err: %v", err)
   497  		}
   498  
   499  		// Make the request via the mux to make sure the error returned
   500  		// by Snapshot is properly propagated via HTTP
   501  		s.Server.mux.ServeHTTP(respW, req)
   502  		resp := respW.Result()
   503  		r := tar.NewReader(resp.Body)
   504  		errorFilename := allocdir.SnapshotErrorFilename(alloc.ID)
   505  		markerFound := false
   506  		markerContents := ""
   507  		for {
   508  			header, err := r.Next()
   509  			if err != nil {
   510  				if err != io.EOF {
   511  					// Huh, I wonder how a non-EOF error can happen?
   512  					t.Errorf("Unexpected error while streaming: %v", err)
   513  				}
   514  				break
   515  			}
   516  
   517  			if markerFound {
   518  				// No more files should be found after the failure marker
   519  				t.Errorf("Next file found after error marker: %s", header.Name)
   520  				break
   521  			}
   522  
   523  			if header.Name == errorFilename {
   524  				// Found it!
   525  				markerFound = true
   526  				buf := make([]byte, int(header.Size))
   527  				if _, err := r.Read(buf); err != nil && err != io.EOF {
   528  					t.Errorf("Unexpected error reading error marker %s: %v", errorFilename, err)
   529  				} else {
   530  					markerContents = string(buf)
   531  				}
   532  			}
   533  		}
   534  
   535  		if !markerFound {
   536  			t.Fatalf("marker file %s not written; bad tar will be treated as good!", errorFilename)
   537  		}
   538  		if markerContents == "" {
   539  			t.Fatalf("marker file %s empty", markerContents)
   540  		} else {
   541  			t.Logf("EXPECTED snapshot error: %s", markerContents)
   542  		}
   543  	})
   544  }
   545  
   546  func TestHTTP_AllocGC(t *testing.T) {
   547  	t.Parallel()
   548  	require := require.New(t)
   549  	path := fmt.Sprintf("/v1/client/allocation/%s/gc", uuid.Generate())
   550  	httpTest(t, nil, func(s *TestAgent) {
   551  		// Local node, local resp
   552  		{
   553  			req, err := http.NewRequest("GET", path, nil)
   554  			if err != nil {
   555  				t.Fatalf("err: %v", err)
   556  			}
   557  
   558  			respW := httptest.NewRecorder()
   559  			_, err = s.Server.ClientAllocRequest(respW, req)
   560  			if !structs.IsErrUnknownAllocation(err) {
   561  				t.Fatalf("unexpected err: %v", err)
   562  			}
   563  		}
   564  
   565  		// Local node, server resp
   566  		{
   567  			srv := s.server
   568  			s.server = nil
   569  
   570  			req, err := http.NewRequest("GET", path, nil)
   571  			if err != nil {
   572  				t.Fatalf("err: %v", err)
   573  			}
   574  
   575  			respW := httptest.NewRecorder()
   576  			_, err = s.Server.ClientAllocRequest(respW, req)
   577  			if !structs.IsErrUnknownAllocation(err) {
   578  				t.Fatalf("unexpected err: %v", err)
   579  			}
   580  
   581  			s.server = srv
   582  		}
   583  
   584  		// no client, server resp
   585  		{
   586  			c := s.client
   587  			s.client = nil
   588  
   589  			testutil.WaitForResult(func() (bool, error) {
   590  				n, err := s.server.State().NodeByID(nil, c.NodeID())
   591  				if err != nil {
   592  					return false, err
   593  				}
   594  				return n != nil, nil
   595  			}, func(err error) {
   596  				t.Fatalf("should have client: %v", err)
   597  			})
   598  
   599  			req, err := http.NewRequest("GET", path, nil)
   600  			if err != nil {
   601  				t.Fatalf("err: %v", err)
   602  			}
   603  
   604  			respW := httptest.NewRecorder()
   605  			_, err = s.Server.ClientAllocRequest(respW, req)
   606  			require.NotNil(err)
   607  			if !structs.IsErrUnknownAllocation(err) {
   608  				t.Fatalf("unexpected err: %v", err)
   609  			}
   610  
   611  			s.client = c
   612  		}
   613  	})
   614  }
   615  
   616  func TestHTTP_AllocGC_ACL(t *testing.T) {
   617  	t.Parallel()
   618  	require := require.New(t)
   619  	path := fmt.Sprintf("/v1/client/allocation/%s/gc", uuid.Generate())
   620  
   621  	httpACLTest(t, nil, func(s *TestAgent) {
   622  		state := s.Agent.server.State()
   623  
   624  		// Make the HTTP request
   625  		req, err := http.NewRequest("GET", path, nil)
   626  		if err != nil {
   627  			t.Fatalf("err: %v", err)
   628  		}
   629  
   630  		// Try request without a token and expect failure
   631  		{
   632  			respW := httptest.NewRecorder()
   633  			_, err := s.Server.ClientAllocRequest(respW, req)
   634  			require.NotNil(err)
   635  			require.Equal(err.Error(), structs.ErrPermissionDenied.Error())
   636  		}
   637  
   638  		// Try request with an invalid token and expect failure
   639  		{
   640  			respW := httptest.NewRecorder()
   641  			token := mock.CreatePolicyAndToken(t, state, 1005, "invalid", mock.NodePolicy(acl.PolicyWrite))
   642  			setToken(req, token)
   643  			_, err := s.Server.ClientAllocRequest(respW, req)
   644  			require.NotNil(err)
   645  			require.Equal(err.Error(), structs.ErrPermissionDenied.Error())
   646  		}
   647  
   648  		// Try request with a valid token
   649  		// Still returns an error because the alloc does not exist
   650  		{
   651  			respW := httptest.NewRecorder()
   652  			policy := mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilitySubmitJob})
   653  			token := mock.CreatePolicyAndToken(t, state, 1007, "valid", policy)
   654  			setToken(req, token)
   655  			_, err := s.Server.ClientAllocRequest(respW, req)
   656  			require.NotNil(err)
   657  			require.True(structs.IsErrUnknownAllocation(err))
   658  		}
   659  
   660  		// Try request with a management token
   661  		// Still returns an error because the alloc does not exist
   662  		{
   663  			respW := httptest.NewRecorder()
   664  			setToken(req, s.RootToken)
   665  			_, err := s.Server.ClientAllocRequest(respW, req)
   666  			require.NotNil(err)
   667  			require.True(structs.IsErrUnknownAllocation(err))
   668  		}
   669  	})
   670  }
   671  
   672  func TestHTTP_AllocAllGC(t *testing.T) {
   673  	t.Parallel()
   674  	require := require.New(t)
   675  	httpTest(t, nil, func(s *TestAgent) {
   676  		// Local node, local resp
   677  		{
   678  			req, err := http.NewRequest("GET", "/v1/client/gc", nil)
   679  			if err != nil {
   680  				t.Fatalf("err: %v", err)
   681  			}
   682  
   683  			respW := httptest.NewRecorder()
   684  			_, err = s.Server.ClientGCRequest(respW, req)
   685  			if err != nil {
   686  				t.Fatalf("unexpected err: %v", err)
   687  			}
   688  		}
   689  
   690  		// Local node, server resp
   691  		{
   692  			srv := s.server
   693  			s.server = nil
   694  
   695  			req, err := http.NewRequest("GET", fmt.Sprintf("/v1/client/gc?node_id=%s", uuid.Generate()), nil)
   696  			require.Nil(err)
   697  
   698  			respW := httptest.NewRecorder()
   699  			_, err = s.Server.ClientGCRequest(respW, req)
   700  			require.NotNil(err)
   701  			require.Contains(err.Error(), "Unknown node")
   702  
   703  			s.server = srv
   704  		}
   705  
   706  		// client stats from server, should not error
   707  		{
   708  			c := s.client
   709  			s.client = nil
   710  
   711  			testutil.WaitForResult(func() (bool, error) {
   712  				n, err := s.server.State().NodeByID(nil, c.NodeID())
   713  				if err != nil {
   714  					return false, err
   715  				}
   716  				return n != nil, nil
   717  			}, func(err error) {
   718  				t.Fatalf("should have client: %v", err)
   719  			})
   720  
   721  			req, err := http.NewRequest("GET", fmt.Sprintf("/v1/client/gc?node_id=%s", c.NodeID()), nil)
   722  			require.Nil(err)
   723  
   724  			respW := httptest.NewRecorder()
   725  			_, err = s.Server.ClientGCRequest(respW, req)
   726  			require.Nil(err)
   727  
   728  			s.client = c
   729  		}
   730  	})
   731  
   732  }
   733  
   734  func TestHTTP_AllocAllGC_ACL(t *testing.T) {
   735  	t.Parallel()
   736  	require := require.New(t)
   737  	httpACLTest(t, nil, func(s *TestAgent) {
   738  		state := s.Agent.server.State()
   739  
   740  		// Make the HTTP request
   741  		req, err := http.NewRequest("GET", "/v1/client/gc", nil)
   742  		require.Nil(err)
   743  
   744  		// Try request without a token and expect failure
   745  		{
   746  			respW := httptest.NewRecorder()
   747  			_, err := s.Server.ClientGCRequest(respW, req)
   748  			require.NotNil(err)
   749  			require.Equal(err.Error(), structs.ErrPermissionDenied.Error())
   750  		}
   751  
   752  		// Try request with an invalid token and expect failure
   753  		{
   754  			respW := httptest.NewRecorder()
   755  			token := mock.CreatePolicyAndToken(t, state, 1005, "invalid", mock.NodePolicy(acl.PolicyRead))
   756  			setToken(req, token)
   757  			_, err := s.Server.ClientGCRequest(respW, req)
   758  			require.NotNil(err)
   759  			require.Equal(err.Error(), structs.ErrPermissionDenied.Error())
   760  		}
   761  
   762  		// Try request with a valid token
   763  		{
   764  			respW := httptest.NewRecorder()
   765  			token := mock.CreatePolicyAndToken(t, state, 1007, "valid", mock.NodePolicy(acl.PolicyWrite))
   766  			setToken(req, token)
   767  			_, err := s.Server.ClientGCRequest(respW, req)
   768  			require.Nil(err)
   769  			require.Equal(http.StatusOK, respW.Code)
   770  		}
   771  
   772  		// Try request with a management token
   773  		{
   774  			respW := httptest.NewRecorder()
   775  			setToken(req, s.RootToken)
   776  			_, err := s.Server.ClientGCRequest(respW, req)
   777  			require.Nil(err)
   778  			require.Equal(http.StatusOK, respW.Code)
   779  		}
   780  	})
   781  }