github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/nomad/alloc_endpoint_test.go (about)

     1  package nomad
     2  
     3  import (
     4  	"reflect"
     5  	"testing"
     6  	"time"
     7  
     8  	msgpackrpc "github.com/hashicorp/net-rpc-msgpackrpc"
     9  	"github.com/hashicorp/nomad/acl"
    10  	"github.com/hashicorp/nomad/ci"
    11  	"github.com/hashicorp/nomad/helper/pointer"
    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/assert"
    17  	"github.com/stretchr/testify/require"
    18  )
    19  
    20  func TestAllocEndpoint_List(t *testing.T) {
    21  	ci.Parallel(t)
    22  
    23  	s1, cleanupS1 := TestServer(t, nil)
    24  	defer cleanupS1()
    25  
    26  	codec := rpcClient(t, s1)
    27  	testutil.WaitForLeader(t, s1.RPC)
    28  
    29  	// Create the register request
    30  	alloc := mock.Alloc()
    31  	summary := mock.JobSummary(alloc.JobID)
    32  	state := s1.fsm.State()
    33  
    34  	if err := state.UpsertJobSummary(999, summary); err != nil {
    35  		t.Fatalf("err: %v", err)
    36  	}
    37  	if err := state.UpsertAllocs(structs.MsgTypeTestSetup, 1000, []*structs.Allocation{alloc}); err != nil {
    38  		t.Fatalf("err: %v", err)
    39  	}
    40  
    41  	// Lookup the allocations
    42  	get := &structs.AllocListRequest{
    43  		QueryOptions: structs.QueryOptions{
    44  			Region:    "global",
    45  			Namespace: structs.DefaultNamespace,
    46  		},
    47  	}
    48  	var resp structs.AllocListResponse
    49  	if err := msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp); err != nil {
    50  		t.Fatalf("err: %v", err)
    51  	}
    52  	if resp.Index != 1000 {
    53  		t.Fatalf("Bad index: %d %d", resp.Index, 1000)
    54  	}
    55  
    56  	if len(resp.Allocations) != 1 {
    57  		t.Fatalf("bad: %#v", resp.Allocations)
    58  	}
    59  	if resp.Allocations[0].ID != alloc.ID {
    60  		t.Fatalf("bad: %#v", resp.Allocations[0])
    61  	}
    62  
    63  	// Lookup the allocations by prefix
    64  	get = &structs.AllocListRequest{
    65  		QueryOptions: structs.QueryOptions{
    66  			Region:    "global",
    67  			Namespace: structs.DefaultNamespace,
    68  			Prefix:    alloc.ID[:4],
    69  		},
    70  	}
    71  
    72  	var resp2 structs.AllocListResponse
    73  	require.NoError(t, msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp2))
    74  	require.Equal(t, uint64(1000), resp2.Index)
    75  	require.Len(t, resp2.Allocations, 1)
    76  	require.Equal(t, alloc.ID, resp2.Allocations[0].ID)
    77  
    78  	// Lookup allocations with a filter
    79  	get = &structs.AllocListRequest{
    80  		QueryOptions: structs.QueryOptions{
    81  			Region:    "global",
    82  			Namespace: structs.DefaultNamespace,
    83  			Filter:    "TaskGroup == web",
    84  		},
    85  	}
    86  
    87  	var resp3 structs.AllocListResponse
    88  	require.NoError(t, msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp3))
    89  	require.Equal(t, uint64(1000), resp3.Index)
    90  	require.Len(t, resp3.Allocations, 1)
    91  	require.Equal(t, alloc.ID, resp3.Allocations[0].ID)
    92  }
    93  
    94  func TestAllocEndpoint_List_PaginationFiltering(t *testing.T) {
    95  	ci.Parallel(t)
    96  	s1, _, cleanupS1 := TestACLServer(t, nil)
    97  	defer cleanupS1()
    98  	codec := rpcClient(t, s1)
    99  	testutil.WaitForLeader(t, s1.RPC)
   100  
   101  	// create a set of allocs and field values to filter on. these are in the order
   102  	// that the state store will return them from the iterator (sorted by create
   103  	// index), for ease of writing tests.
   104  	mocks := []struct {
   105  		ids       []string
   106  		namespace string
   107  		group     string
   108  	}{
   109  		{ids: []string{"aaaa1111-3350-4b4b-d185-0e1992ed43e9"}},                           // 0
   110  		{ids: []string{"aaaaaa22-3350-4b4b-d185-0e1992ed43e9"}},                           // 1
   111  		{ids: []string{"aaaaaa33-3350-4b4b-d185-0e1992ed43e9"}, namespace: "non-default"}, // 2
   112  		{ids: []string{"aaaaaaaa-3350-4b4b-d185-0e1992ed43e9"}, group: "bar"},             // 3
   113  		{ids: []string{"aaaaaabb-3350-4b4b-d185-0e1992ed43e9"}, group: "goo"},             // 4
   114  		{ids: []string{"aaaaaacc-3350-4b4b-d185-0e1992ed43e9"}},                           // 5
   115  		{ids: []string{"aaaaaadd-3350-4b4b-d185-0e1992ed43e9"}, group: "bar"},             // 6
   116  		{ids: []string{"aaaaaaee-3350-4b4b-d185-0e1992ed43e9"}, group: "goo"},             // 7
   117  		{ids: []string{"aaaaaaff-3350-4b4b-d185-0e1992ed43e9"}, group: "bar"},             // 8
   118  		{ids: []string{"00000111-3350-4b4b-d185-0e1992ed43e9"}},                           // 9
   119  		{ids: []string{ // 10
   120  			"00000222-3350-4b4b-d185-0e1992ed43e9",
   121  			"00000333-3350-4b4b-d185-0e1992ed43e9",
   122  		}},
   123  		{}, // 11, index missing
   124  		{ids: []string{"bbbb1111-3350-4b4b-d185-0e1992ed43e9"}}, // 12
   125  	}
   126  
   127  	state := s1.fsm.State()
   128  
   129  	require.NoError(t, state.UpsertNamespaces(1099, []*structs.Namespace{
   130  		{Name: "non-default"},
   131  	}))
   132  
   133  	var allocs []*structs.Allocation
   134  	for i, m := range mocks {
   135  		allocsInTx := []*structs.Allocation{}
   136  		for _, id := range m.ids {
   137  			alloc := mock.Alloc()
   138  			alloc.ID = id
   139  			if m.namespace != "" {
   140  				alloc.Namespace = m.namespace
   141  			}
   142  			if m.group != "" {
   143  				alloc.TaskGroup = m.group
   144  			}
   145  			allocs = append(allocs, alloc)
   146  			allocsInTx = append(allocsInTx, alloc)
   147  		}
   148  		// other fields
   149  		index := 1000 + uint64(i)
   150  		require.NoError(t, state.UpsertAllocs(structs.MsgTypeTestSetup, index, allocsInTx))
   151  	}
   152  
   153  	aclToken := mock.CreatePolicyAndToken(t,
   154  		state, 1100, "test-valid-read",
   155  		mock.NamespacePolicy("*", "read", nil),
   156  	).SecretID
   157  
   158  	cases := []struct {
   159  		name         string
   160  		namespace    string
   161  		prefix       string
   162  		nextToken    string
   163  		pageSize     int32
   164  		filter       string
   165  		expIDs       []string
   166  		expNextToken string
   167  		expErr       string
   168  	}{
   169  		{
   170  			name:     "test01 size-2 page-1 ns-default",
   171  			pageSize: 2,
   172  			expIDs: []string{ // first two items
   173  				"aaaa1111-3350-4b4b-d185-0e1992ed43e9",
   174  				"aaaaaa22-3350-4b4b-d185-0e1992ed43e9",
   175  			},
   176  			expNextToken: "1003.aaaaaaaa-3350-4b4b-d185-0e1992ed43e9", // next one in default ns
   177  		},
   178  		{
   179  			name:     "test02 size-2 page-1 ns-default with-prefix",
   180  			prefix:   "aaaa",
   181  			pageSize: 2,
   182  			expIDs: []string{
   183  				"aaaa1111-3350-4b4b-d185-0e1992ed43e9",
   184  				"aaaaaa22-3350-4b4b-d185-0e1992ed43e9",
   185  			},
   186  			expNextToken: "aaaaaaaa-3350-4b4b-d185-0e1992ed43e9",
   187  		},
   188  		{
   189  			name:         "test03 size-2 page-2 ns-default",
   190  			pageSize:     2,
   191  			nextToken:    "1003.aaaaaaaa-3350-4b4b-d185-0e1992ed43e9",
   192  			expNextToken: "1005.aaaaaacc-3350-4b4b-d185-0e1992ed43e9",
   193  			expIDs: []string{
   194  				"aaaaaaaa-3350-4b4b-d185-0e1992ed43e9",
   195  				"aaaaaabb-3350-4b4b-d185-0e1992ed43e9",
   196  			},
   197  		},
   198  		{
   199  			name:         "test04 size-2 page-2 ns-default with prefix",
   200  			prefix:       "aaaa",
   201  			pageSize:     2,
   202  			nextToken:    "aaaaaabb-3350-4b4b-d185-0e1992ed43e9",
   203  			expNextToken: "aaaaaadd-3350-4b4b-d185-0e1992ed43e9",
   204  			expIDs: []string{
   205  				"aaaaaabb-3350-4b4b-d185-0e1992ed43e9",
   206  				"aaaaaacc-3350-4b4b-d185-0e1992ed43e9",
   207  			},
   208  		},
   209  		{
   210  			name:      "test05 go-bexpr filter",
   211  			filter:    `TaskGroup == "goo"`,
   212  			nextToken: "",
   213  			expIDs: []string{
   214  				"aaaaaabb-3350-4b4b-d185-0e1992ed43e9",
   215  				"aaaaaaee-3350-4b4b-d185-0e1992ed43e9",
   216  			},
   217  		},
   218  		{
   219  			name:         "test06 go-bexpr filter with pagination",
   220  			filter:       `TaskGroup == "bar"`,
   221  			pageSize:     2,
   222  			expNextToken: "1008.aaaaaaff-3350-4b4b-d185-0e1992ed43e9",
   223  			expIDs: []string{
   224  				"aaaaaaaa-3350-4b4b-d185-0e1992ed43e9",
   225  				"aaaaaadd-3350-4b4b-d185-0e1992ed43e9",
   226  			},
   227  		},
   228  		{
   229  			name:      "test07 go-bexpr filter namespace",
   230  			namespace: "non-default",
   231  			filter:    `ID contains "aaa"`,
   232  			expIDs: []string{
   233  				"aaaaaa33-3350-4b4b-d185-0e1992ed43e9",
   234  			},
   235  		},
   236  		{
   237  			name:      "test08 go-bexpr wrong namespace",
   238  			namespace: "default",
   239  			filter:    `Namespace == "non-default"`,
   240  			expIDs:    []string(nil),
   241  		},
   242  		{
   243  			name:   "test09 go-bexpr invalid expression",
   244  			filter: `NotValid`,
   245  			expErr: "failed to read filter expression",
   246  		},
   247  		{
   248  			name:   "test10 go-bexpr invalid field",
   249  			filter: `InvalidField == "value"`,
   250  			expErr: "error finding value in datum",
   251  		},
   252  		{
   253  			name:         "test11 non-lexicographic order",
   254  			pageSize:     1,
   255  			nextToken:    "1009.00000111-3350-4b4b-d185-0e1992ed43e9",
   256  			expNextToken: "1010.00000222-3350-4b4b-d185-0e1992ed43e9",
   257  			expIDs: []string{
   258  				"00000111-3350-4b4b-d185-0e1992ed43e9",
   259  			},
   260  		},
   261  		{
   262  			name:         "test12 same index",
   263  			pageSize:     1,
   264  			nextToken:    "1010.00000222-3350-4b4b-d185-0e1992ed43e9",
   265  			expNextToken: "1010.00000333-3350-4b4b-d185-0e1992ed43e9",
   266  			expIDs: []string{
   267  				"00000222-3350-4b4b-d185-0e1992ed43e9",
   268  			},
   269  		},
   270  		{
   271  			name:      "test13 missing index",
   272  			pageSize:  1,
   273  			nextToken: "1011.e9522802-0cd8-4b1d-9c9e-ab3d97938371",
   274  			expIDs: []string{
   275  				"bbbb1111-3350-4b4b-d185-0e1992ed43e9",
   276  			},
   277  		},
   278  	}
   279  
   280  	for _, tc := range cases {
   281  		t.Run(tc.name, func(t *testing.T) {
   282  			var req = &structs.AllocListRequest{
   283  				QueryOptions: structs.QueryOptions{
   284  					Region:    "global",
   285  					Namespace: tc.namespace,
   286  					Prefix:    tc.prefix,
   287  					PerPage:   tc.pageSize,
   288  					NextToken: tc.nextToken,
   289  					Filter:    tc.filter,
   290  				},
   291  				Fields: &structs.AllocStubFields{
   292  					Resources:  false,
   293  					TaskStates: false,
   294  				},
   295  			}
   296  			req.AuthToken = aclToken
   297  			var resp structs.AllocListResponse
   298  			err := msgpackrpc.CallWithCodec(codec, "Alloc.List", req, &resp)
   299  			if tc.expErr == "" {
   300  				require.NoError(t, err)
   301  			} else {
   302  				require.Contains(t, err, tc.expErr)
   303  			}
   304  
   305  			var gotIDs []string
   306  			for _, alloc := range resp.Allocations {
   307  				gotIDs = append(gotIDs, alloc.ID)
   308  			}
   309  			require.Equal(t, tc.expIDs, gotIDs)
   310  			require.Equal(t, tc.expNextToken, resp.QueryMeta.NextToken)
   311  		})
   312  	}
   313  }
   314  
   315  func TestAllocEndpoint_List_order(t *testing.T) {
   316  	ci.Parallel(t)
   317  
   318  	s1, cleanupS1 := TestServer(t, nil)
   319  	defer cleanupS1()
   320  	codec := rpcClient(t, s1)
   321  	testutil.WaitForLeader(t, s1.RPC)
   322  
   323  	// Create register requests
   324  	uuid1 := uuid.Generate()
   325  	alloc1 := mock.Alloc()
   326  	alloc1.ID = uuid1
   327  
   328  	uuid2 := uuid.Generate()
   329  	alloc2 := mock.Alloc()
   330  	alloc2.ID = uuid2
   331  
   332  	uuid3 := uuid.Generate()
   333  	alloc3 := mock.Alloc()
   334  	alloc3.ID = uuid3
   335  
   336  	err := s1.fsm.State().UpsertAllocs(structs.MsgTypeTestSetup, 1000, []*structs.Allocation{alloc1})
   337  	require.NoError(t, err)
   338  
   339  	err = s1.fsm.State().UpsertAllocs(structs.MsgTypeTestSetup, 1001, []*structs.Allocation{alloc2})
   340  	require.NoError(t, err)
   341  
   342  	err = s1.fsm.State().UpsertAllocs(structs.MsgTypeTestSetup, 1002, []*structs.Allocation{alloc3})
   343  	require.NoError(t, err)
   344  
   345  	// update alloc2 again so we can later assert create index order did not change
   346  	err = s1.fsm.State().UpsertAllocs(structs.MsgTypeTestSetup, 1003, []*structs.Allocation{alloc2})
   347  	require.NoError(t, err)
   348  
   349  	t.Run("default", func(t *testing.T) {
   350  		// Lookup the allocations in the default order (oldest first)
   351  		get := &structs.AllocListRequest{
   352  			QueryOptions: structs.QueryOptions{
   353  				Region:    "global",
   354  				Namespace: "*",
   355  			},
   356  		}
   357  
   358  		var resp structs.AllocListResponse
   359  		err = msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp)
   360  		require.NoError(t, err)
   361  		require.Equal(t, uint64(1003), resp.Index)
   362  		require.Len(t, resp.Allocations, 3)
   363  
   364  		// Assert returned order is by CreateIndex (ascending)
   365  		require.Equal(t, uint64(1000), resp.Allocations[0].CreateIndex)
   366  		require.Equal(t, uuid1, resp.Allocations[0].ID)
   367  
   368  		require.Equal(t, uint64(1001), resp.Allocations[1].CreateIndex)
   369  		require.Equal(t, uuid2, resp.Allocations[1].ID)
   370  
   371  		require.Equal(t, uint64(1002), resp.Allocations[2].CreateIndex)
   372  		require.Equal(t, uuid3, resp.Allocations[2].ID)
   373  	})
   374  
   375  	t.Run("reverse", func(t *testing.T) {
   376  		// Lookup the allocations in reverse order (newest first)
   377  		get := &structs.AllocListRequest{
   378  			QueryOptions: structs.QueryOptions{
   379  				Region:    "global",
   380  				Namespace: "*",
   381  				Reverse:   true,
   382  			},
   383  		}
   384  
   385  		var resp structs.AllocListResponse
   386  		err = msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp)
   387  		require.NoError(t, err)
   388  		require.Equal(t, uint64(1003), resp.Index)
   389  		require.Len(t, resp.Allocations, 3)
   390  
   391  		// Assert returned order is by CreateIndex (descending)
   392  		require.Equal(t, uint64(1002), resp.Allocations[0].CreateIndex)
   393  		require.Equal(t, uuid3, resp.Allocations[0].ID)
   394  
   395  		require.Equal(t, uint64(1001), resp.Allocations[1].CreateIndex)
   396  		require.Equal(t, uuid2, resp.Allocations[1].ID)
   397  
   398  		require.Equal(t, uint64(1000), resp.Allocations[2].CreateIndex)
   399  		require.Equal(t, uuid1, resp.Allocations[2].ID)
   400  	})
   401  }
   402  
   403  func TestAllocEndpoint_List_Fields(t *testing.T) {
   404  	ci.Parallel(t)
   405  
   406  	s1, cleanupS1 := TestServer(t, nil)
   407  	defer cleanupS1()
   408  
   409  	codec := rpcClient(t, s1)
   410  	testutil.WaitForLeader(t, s1.RPC)
   411  
   412  	// Create a running alloc
   413  	alloc := mock.Alloc()
   414  	alloc.ClientStatus = structs.AllocClientStatusRunning
   415  	alloc.TaskStates = map[string]*structs.TaskState{
   416  		"web": {
   417  			State:     structs.TaskStateRunning,
   418  			StartedAt: time.Now(),
   419  		},
   420  	}
   421  	summary := mock.JobSummary(alloc.JobID)
   422  	state := s1.fsm.State()
   423  
   424  	require.NoError(t, state.UpsertJobSummary(999, summary))
   425  	require.NoError(t, state.UpsertAllocs(structs.MsgTypeTestSetup, 1000, []*structs.Allocation{alloc}))
   426  
   427  	cases := []struct {
   428  		Name   string
   429  		Fields *structs.AllocStubFields
   430  		Assert func(t *testing.T, allocs []*structs.AllocListStub)
   431  	}{
   432  		{
   433  			Name:   "None",
   434  			Fields: nil,
   435  			Assert: func(t *testing.T, allocs []*structs.AllocListStub) {
   436  				require.Nil(t, allocs[0].AllocatedResources)
   437  				require.Len(t, allocs[0].TaskStates, 1)
   438  			},
   439  		},
   440  		{
   441  			Name:   "Default",
   442  			Fields: structs.NewAllocStubFields(),
   443  			Assert: func(t *testing.T, allocs []*structs.AllocListStub) {
   444  				require.Nil(t, allocs[0].AllocatedResources)
   445  				require.Len(t, allocs[0].TaskStates, 1)
   446  			},
   447  		},
   448  		{
   449  			Name: "Resources",
   450  			Fields: &structs.AllocStubFields{
   451  				Resources:  true,
   452  				TaskStates: false,
   453  			},
   454  			Assert: func(t *testing.T, allocs []*structs.AllocListStub) {
   455  				require.NotNil(t, allocs[0].AllocatedResources)
   456  				require.Len(t, allocs[0].TaskStates, 0)
   457  			},
   458  		},
   459  		{
   460  			Name: "NoTaskStates",
   461  			Fields: &structs.AllocStubFields{
   462  				Resources:  false,
   463  				TaskStates: false,
   464  			},
   465  			Assert: func(t *testing.T, allocs []*structs.AllocListStub) {
   466  				require.Nil(t, allocs[0].AllocatedResources)
   467  				require.Len(t, allocs[0].TaskStates, 0)
   468  			},
   469  		},
   470  		{
   471  			Name: "Both",
   472  			Fields: &structs.AllocStubFields{
   473  				Resources:  true,
   474  				TaskStates: true,
   475  			},
   476  			Assert: func(t *testing.T, allocs []*structs.AllocListStub) {
   477  				require.NotNil(t, allocs[0].AllocatedResources)
   478  				require.Len(t, allocs[0].TaskStates, 1)
   479  			},
   480  		},
   481  	}
   482  
   483  	for i := range cases {
   484  		tc := cases[i]
   485  		t.Run(tc.Name, func(t *testing.T) {
   486  			get := &structs.AllocListRequest{
   487  				QueryOptions: structs.QueryOptions{
   488  					Region:    "global",
   489  					Namespace: structs.DefaultNamespace,
   490  				},
   491  				Fields: tc.Fields,
   492  			}
   493  			var resp structs.AllocListResponse
   494  			require.NoError(t, msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp))
   495  			require.Equal(t, uint64(1000), resp.Index)
   496  			require.Len(t, resp.Allocations, 1)
   497  			require.Equal(t, alloc.ID, resp.Allocations[0].ID)
   498  			tc.Assert(t, resp.Allocations)
   499  		})
   500  	}
   501  
   502  }
   503  
   504  func TestAllocEndpoint_List_ACL(t *testing.T) {
   505  	ci.Parallel(t)
   506  
   507  	s1, root, cleanupS1 := TestACLServer(t, nil)
   508  	defer cleanupS1()
   509  	codec := rpcClient(t, s1)
   510  	testutil.WaitForLeader(t, s1.RPC)
   511  	assert := assert.New(t)
   512  
   513  	// Create the alloc
   514  	alloc := mock.Alloc()
   515  	allocs := []*structs.Allocation{alloc}
   516  	summary := mock.JobSummary(alloc.JobID)
   517  	state := s1.fsm.State()
   518  
   519  	assert.Nil(state.UpsertJobSummary(999, summary), "UpsertJobSummary")
   520  	assert.Nil(state.UpsertAllocs(structs.MsgTypeTestSetup, 1000, allocs), "UpsertAllocs")
   521  
   522  	stubAllocs := []*structs.AllocListStub{alloc.Stub(nil)}
   523  	stubAllocs[0].CreateIndex = 1000
   524  	stubAllocs[0].ModifyIndex = 1000
   525  
   526  	// Create the namespace policy and tokens
   527  	validToken := mock.CreatePolicyAndToken(t, state, 1001, "test-valid",
   528  		mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilityReadJob}))
   529  	invalidToken := mock.CreatePolicyAndToken(t, state, 1003, "test-invalid",
   530  		mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilityListJobs}))
   531  
   532  	// Lookup the allocs without a token and expect failure
   533  	get := &structs.AllocListRequest{
   534  		QueryOptions: structs.QueryOptions{
   535  			Region:    "global",
   536  			Namespace: structs.DefaultNamespace,
   537  		},
   538  	}
   539  	var resp structs.AllocListResponse
   540  	assert.NotNil(msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp), "RPC")
   541  
   542  	// Try with a valid token
   543  	get.AuthToken = validToken.SecretID
   544  	assert.Nil(msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp), "RPC")
   545  	assert.EqualValues(resp.Index, 1000, "resp.Index")
   546  	assert.Equal(stubAllocs, resp.Allocations, "Returned alloc list not equal")
   547  
   548  	// Try with a invalid token
   549  	get.AuthToken = invalidToken.SecretID
   550  	err := msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp)
   551  	assert.NotNil(err, "RPC")
   552  	assert.Equal(err.Error(), structs.ErrPermissionDenied.Error())
   553  
   554  	// Try with a root token
   555  	get.AuthToken = root.SecretID
   556  	assert.Nil(msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp), "RPC")
   557  	assert.EqualValues(resp.Index, 1000, "resp.Index")
   558  	assert.Equal(stubAllocs, resp.Allocations, "Returned alloc list not equal")
   559  }
   560  
   561  func TestAllocEndpoint_List_Blocking(t *testing.T) {
   562  	ci.Parallel(t)
   563  
   564  	s1, cleanupS1 := TestServer(t, nil)
   565  	defer cleanupS1()
   566  	state := s1.fsm.State()
   567  	codec := rpcClient(t, s1)
   568  	testutil.WaitForLeader(t, s1.RPC)
   569  
   570  	// Create the alloc
   571  	alloc := mock.Alloc()
   572  
   573  	summary := mock.JobSummary(alloc.JobID)
   574  	if err := state.UpsertJobSummary(1, summary); err != nil {
   575  		t.Fatalf("err: %v", err)
   576  	}
   577  	// Upsert alloc triggers watches
   578  	time.AfterFunc(100*time.Millisecond, func() {
   579  		if err := state.UpsertAllocs(structs.MsgTypeTestSetup, 2, []*structs.Allocation{alloc}); err != nil {
   580  			t.Fatalf("err: %v", err)
   581  		}
   582  	})
   583  
   584  	req := &structs.AllocListRequest{
   585  		QueryOptions: structs.QueryOptions{
   586  			Region:        "global",
   587  			Namespace:     structs.DefaultNamespace,
   588  			MinQueryIndex: 1,
   589  		},
   590  	}
   591  	start := time.Now()
   592  	var resp structs.AllocListResponse
   593  	if err := msgpackrpc.CallWithCodec(codec, "Alloc.List", req, &resp); err != nil {
   594  		t.Fatalf("err: %v", err)
   595  	}
   596  
   597  	if elapsed := time.Since(start); elapsed < 100*time.Millisecond {
   598  		t.Fatalf("should block (returned in %s) %#v", elapsed, resp)
   599  	}
   600  	if resp.Index != 2 {
   601  		t.Fatalf("Bad index: %d %d", resp.Index, 2)
   602  	}
   603  	if len(resp.Allocations) != 1 || resp.Allocations[0].ID != alloc.ID {
   604  		t.Fatalf("bad: %#v", resp.Allocations)
   605  	}
   606  
   607  	// Client updates trigger watches
   608  	alloc2 := mock.Alloc()
   609  	alloc2.ID = alloc.ID
   610  	alloc2.ClientStatus = structs.AllocClientStatusRunning
   611  	time.AfterFunc(100*time.Millisecond, func() {
   612  		state.UpsertJobSummary(3, mock.JobSummary(alloc2.JobID))
   613  		if err := state.UpdateAllocsFromClient(structs.MsgTypeTestSetup, 4, []*structs.Allocation{alloc2}); err != nil {
   614  			t.Fatalf("err: %v", err)
   615  		}
   616  	})
   617  
   618  	req.MinQueryIndex = 3
   619  	start = time.Now()
   620  	var resp2 structs.AllocListResponse
   621  	if err := msgpackrpc.CallWithCodec(codec, "Alloc.List", req, &resp2); err != nil {
   622  		t.Fatalf("err: %v", err)
   623  	}
   624  
   625  	if elapsed := time.Since(start); elapsed < 100*time.Millisecond {
   626  		t.Fatalf("should block (returned in %s) %#v", elapsed, resp2)
   627  	}
   628  	if resp2.Index != 4 {
   629  		t.Fatalf("Bad index: %d %d", resp2.Index, 4)
   630  	}
   631  	if len(resp2.Allocations) != 1 || resp.Allocations[0].ID != alloc.ID ||
   632  		resp2.Allocations[0].ClientStatus != structs.AllocClientStatusRunning {
   633  		t.Fatalf("bad: %#v", resp2.Allocations)
   634  	}
   635  }
   636  
   637  // TestAllocEndpoint_List_AllNamespaces_OSS asserts that server
   638  // returns all allocations across namespaces.
   639  func TestAllocEndpoint_List_AllNamespaces_OSS(t *testing.T) {
   640  	ci.Parallel(t)
   641  
   642  	s1, cleanupS1 := TestServer(t, nil)
   643  	defer cleanupS1()
   644  	codec := rpcClient(t, s1)
   645  	testutil.WaitForLeader(t, s1.RPC)
   646  	state := s1.fsm.State()
   647  
   648  	// two namespaces
   649  	ns1 := mock.Namespace()
   650  	ns2 := mock.Namespace()
   651  	require.NoError(t, state.UpsertNamespaces(900, []*structs.Namespace{ns1, ns2}))
   652  
   653  	// Create the allocations
   654  	uuid1 := uuid.Generate()
   655  	alloc1 := mock.Alloc()
   656  	alloc1.ID = uuid1
   657  	alloc1.Namespace = ns1.Name
   658  
   659  	uuid2 := uuid.Generate()
   660  	alloc2 := mock.Alloc()
   661  	alloc2.ID = uuid2
   662  	alloc2.Namespace = ns2.Name
   663  
   664  	summary1 := mock.JobSummary(alloc1.JobID)
   665  	summary2 := mock.JobSummary(alloc2.JobID)
   666  
   667  	require.NoError(t, state.UpsertJobSummary(1000, summary1))
   668  	require.NoError(t, state.UpsertJobSummary(1001, summary2))
   669  	require.NoError(t, state.UpsertAllocs(structs.MsgTypeTestSetup, 1002, []*structs.Allocation{alloc1}))
   670  	require.NoError(t, state.UpsertAllocs(structs.MsgTypeTestSetup, 1003, []*structs.Allocation{alloc2}))
   671  
   672  	t.Run("looking up all allocations", func(t *testing.T) {
   673  		get := &structs.AllocListRequest{
   674  			QueryOptions: structs.QueryOptions{
   675  				Region:    "global",
   676  				Namespace: "*",
   677  			},
   678  		}
   679  		var resp structs.AllocListResponse
   680  		require.NoError(t, msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp))
   681  		require.Equal(t, uint64(1003), resp.Index)
   682  		require.Len(t, resp.Allocations, 2)
   683  		require.ElementsMatch(t,
   684  			[]string{resp.Allocations[0].ID, resp.Allocations[1].ID},
   685  			[]string{alloc1.ID, alloc2.ID})
   686  	})
   687  
   688  	t.Run("looking up allocations with prefix", func(t *testing.T) {
   689  		get := &structs.AllocListRequest{
   690  			QueryOptions: structs.QueryOptions{
   691  				Region:    "global",
   692  				Namespace: "*",
   693  				// allocations were constructed above to have non-matching prefix
   694  				Prefix: alloc1.ID[:4],
   695  			},
   696  		}
   697  		var resp structs.AllocListResponse
   698  		require.NoError(t, msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp))
   699  		require.Equal(t, uint64(1003), resp.Index)
   700  		require.Len(t, resp.Allocations, 1)
   701  		require.Equal(t, alloc1.ID, resp.Allocations[0].ID)
   702  		require.Equal(t, alloc1.Namespace, resp.Allocations[0].Namespace)
   703  	})
   704  
   705  	t.Run("looking up allocations with mismatch prefix", func(t *testing.T) {
   706  		get := &structs.AllocListRequest{
   707  			QueryOptions: structs.QueryOptions{
   708  				Region:    "global",
   709  				Namespace: "*",
   710  				Prefix:    "000000", // unlikely to match
   711  			},
   712  		}
   713  		var resp structs.AllocListResponse
   714  		require.NoError(t, msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp))
   715  		require.Equal(t, uint64(1003), resp.Index)
   716  		require.Empty(t, resp.Allocations)
   717  	})
   718  }
   719  
   720  func TestAllocEndpoint_GetAlloc(t *testing.T) {
   721  	ci.Parallel(t)
   722  
   723  	s1, cleanupS1 := TestServer(t, nil)
   724  	defer cleanupS1()
   725  	codec := rpcClient(t, s1)
   726  	testutil.WaitForLeader(t, s1.RPC)
   727  
   728  	// Create the register request
   729  	prevAllocID := uuid.Generate()
   730  	alloc := mock.Alloc()
   731  	alloc.RescheduleTracker = &structs.RescheduleTracker{
   732  		Events: []*structs.RescheduleEvent{
   733  			{RescheduleTime: time.Now().UTC().UnixNano(), PrevNodeID: "boom", PrevAllocID: prevAllocID},
   734  		},
   735  	}
   736  	state := s1.fsm.State()
   737  	state.UpsertJobSummary(999, mock.JobSummary(alloc.JobID))
   738  	err := state.UpsertAllocs(structs.MsgTypeTestSetup, 1000, []*structs.Allocation{alloc})
   739  	if err != nil {
   740  		t.Fatalf("err: %v", err)
   741  	}
   742  
   743  	// Lookup the alloc
   744  	get := &structs.AllocSpecificRequest{
   745  		AllocID:      alloc.ID,
   746  		QueryOptions: structs.QueryOptions{Region: "global"},
   747  	}
   748  	var resp structs.SingleAllocResponse
   749  	if err := msgpackrpc.CallWithCodec(codec, "Alloc.GetAlloc", get, &resp); err != nil {
   750  		t.Fatalf("err: %v", err)
   751  	}
   752  	if resp.Index != 1000 {
   753  		t.Fatalf("Bad index: %d %d", resp.Index, 1000)
   754  	}
   755  
   756  	if !reflect.DeepEqual(alloc, resp.Alloc) {
   757  		t.Fatalf("bad: %#v", resp.Alloc)
   758  	}
   759  }
   760  
   761  func TestAllocEndpoint_GetAlloc_ACL(t *testing.T) {
   762  	ci.Parallel(t)
   763  
   764  	s1, root, cleanupS1 := TestACLServer(t, nil)
   765  	defer cleanupS1()
   766  	codec := rpcClient(t, s1)
   767  	testutil.WaitForLeader(t, s1.RPC)
   768  	assert := assert.New(t)
   769  
   770  	// Create the alloc
   771  	alloc := mock.Alloc()
   772  	allocs := []*structs.Allocation{alloc}
   773  	summary := mock.JobSummary(alloc.JobID)
   774  	state := s1.fsm.State()
   775  
   776  	assert.Nil(state.UpsertJobSummary(999, summary), "UpsertJobSummary")
   777  	assert.Nil(state.UpsertAllocs(structs.MsgTypeTestSetup, 1000, allocs), "UpsertAllocs")
   778  
   779  	// Create the namespace policy and tokens
   780  	validToken := mock.CreatePolicyAndToken(t, state, 1001, "test-valid",
   781  		mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilityReadJob}))
   782  	invalidToken := mock.CreatePolicyAndToken(t, state, 1003, "test-invalid",
   783  		mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilityListJobs}))
   784  
   785  	getReq := func() *structs.AllocSpecificRequest {
   786  		return &structs.AllocSpecificRequest{
   787  			AllocID: alloc.ID,
   788  			QueryOptions: structs.QueryOptions{
   789  				Region: "global",
   790  			},
   791  		}
   792  	}
   793  
   794  	cases := []struct {
   795  		Name string
   796  		F    func(t *testing.T)
   797  	}{
   798  		// Lookup the alloc without a token and expect failure
   799  		{
   800  			Name: "no-token",
   801  			F: func(t *testing.T) {
   802  				var resp structs.SingleAllocResponse
   803  				err := msgpackrpc.CallWithCodec(codec, "Alloc.GetAlloc", getReq(), &resp)
   804  				require.True(t, structs.IsErrUnknownAllocation(err), "expected unknown alloc but found: %v", err)
   805  			},
   806  		},
   807  
   808  		// Try with a valid ACL token
   809  		{
   810  			Name: "valid-token",
   811  			F: func(t *testing.T) {
   812  				get := getReq()
   813  				get.AuthToken = validToken.SecretID
   814  				get.AllocID = alloc.ID
   815  				var resp structs.SingleAllocResponse
   816  				require.NoError(t, msgpackrpc.CallWithCodec(codec, "Alloc.GetAlloc", get, &resp), "RPC")
   817  				require.EqualValues(t, resp.Index, 1000, "resp.Index")
   818  				require.Equal(t, alloc, resp.Alloc, "Returned alloc not equal")
   819  			},
   820  		},
   821  
   822  		// Try with a valid Node.SecretID
   823  		{
   824  			Name: "valid-node-secret",
   825  			F: func(t *testing.T) {
   826  				node := mock.Node()
   827  				assert.Nil(state.UpsertNode(structs.MsgTypeTestSetup, 1005, node))
   828  				get := getReq()
   829  				get.AuthToken = node.SecretID
   830  				get.AllocID = alloc.ID
   831  				var resp structs.SingleAllocResponse
   832  				require.NoError(t, msgpackrpc.CallWithCodec(codec, "Alloc.GetAlloc", get, &resp), "RPC")
   833  				require.EqualValues(t, resp.Index, 1000, "resp.Index")
   834  				require.Equal(t, alloc, resp.Alloc, "Returned alloc not equal")
   835  			},
   836  		},
   837  
   838  		// Try with a invalid token
   839  		{
   840  			Name: "invalid-token",
   841  			F: func(t *testing.T) {
   842  				get := getReq()
   843  				get.AuthToken = invalidToken.SecretID
   844  				get.AllocID = alloc.ID
   845  				var resp structs.SingleAllocResponse
   846  				err := msgpackrpc.CallWithCodec(codec, "Alloc.GetAlloc", get, &resp)
   847  				require.NotNil(t, err, "RPC")
   848  				require.True(t, structs.IsErrUnknownAllocation(err), "expected unknown alloc but found: %v", err)
   849  			},
   850  		},
   851  
   852  		// Try with a root token
   853  		{
   854  			Name: "root-token",
   855  			F: func(t *testing.T) {
   856  				get := getReq()
   857  				get.AuthToken = root.SecretID
   858  				get.AllocID = alloc.ID
   859  				var resp structs.SingleAllocResponse
   860  				require.NoError(t, msgpackrpc.CallWithCodec(codec, "Alloc.GetAlloc", get, &resp), "RPC")
   861  				require.EqualValues(t, resp.Index, 1000, "resp.Index")
   862  				require.Equal(t, alloc, resp.Alloc, "Returned alloc not equal")
   863  			},
   864  		},
   865  	}
   866  
   867  	for _, tc := range cases {
   868  		t.Run(tc.Name, tc.F)
   869  	}
   870  }
   871  
   872  func TestAllocEndpoint_GetAlloc_Blocking(t *testing.T) {
   873  	ci.Parallel(t)
   874  
   875  	s1, cleanupS1 := TestServer(t, nil)
   876  	defer cleanupS1()
   877  	state := s1.fsm.State()
   878  	codec := rpcClient(t, s1)
   879  	testutil.WaitForLeader(t, s1.RPC)
   880  
   881  	// Create the allocs
   882  	alloc1 := mock.Alloc()
   883  	alloc2 := mock.Alloc()
   884  
   885  	// First create an unrelated alloc
   886  	time.AfterFunc(100*time.Millisecond, func() {
   887  		state.UpsertJobSummary(99, mock.JobSummary(alloc1.JobID))
   888  		err := state.UpsertAllocs(structs.MsgTypeTestSetup, 100, []*structs.Allocation{alloc1})
   889  		if err != nil {
   890  			t.Fatalf("err: %v", err)
   891  		}
   892  	})
   893  
   894  	// Create the alloc we are watching later
   895  	time.AfterFunc(200*time.Millisecond, func() {
   896  		state.UpsertJobSummary(199, mock.JobSummary(alloc2.JobID))
   897  		err := state.UpsertAllocs(structs.MsgTypeTestSetup, 200, []*structs.Allocation{alloc2})
   898  		if err != nil {
   899  			t.Fatalf("err: %v", err)
   900  		}
   901  	})
   902  
   903  	// Lookup the allocs
   904  	get := &structs.AllocSpecificRequest{
   905  		AllocID: alloc2.ID,
   906  		QueryOptions: structs.QueryOptions{
   907  			Region:        "global",
   908  			MinQueryIndex: 150,
   909  		},
   910  	}
   911  	var resp structs.SingleAllocResponse
   912  	start := time.Now()
   913  	if err := msgpackrpc.CallWithCodec(codec, "Alloc.GetAlloc", get, &resp); err != nil {
   914  		t.Fatalf("err: %v", err)
   915  	}
   916  
   917  	if elapsed := time.Since(start); elapsed < 200*time.Millisecond {
   918  		t.Fatalf("should block (returned in %s) %#v", elapsed, resp)
   919  	}
   920  	if resp.Index != 200 {
   921  		t.Fatalf("Bad index: %d %d", resp.Index, 200)
   922  	}
   923  	if resp.Alloc == nil || resp.Alloc.ID != alloc2.ID {
   924  		t.Fatalf("bad: %#v", resp.Alloc)
   925  	}
   926  }
   927  
   928  func TestAllocEndpoint_GetAllocs(t *testing.T) {
   929  	ci.Parallel(t)
   930  
   931  	s1, cleanupS1 := TestServer(t, nil)
   932  	defer cleanupS1()
   933  	codec := rpcClient(t, s1)
   934  	testutil.WaitForLeader(t, s1.RPC)
   935  
   936  	// Create the register request
   937  	alloc := mock.Alloc()
   938  	alloc2 := mock.Alloc()
   939  	state := s1.fsm.State()
   940  	state.UpsertJobSummary(998, mock.JobSummary(alloc.JobID))
   941  	state.UpsertJobSummary(999, mock.JobSummary(alloc2.JobID))
   942  	err := state.UpsertAllocs(structs.MsgTypeTestSetup, 1000, []*structs.Allocation{alloc, alloc2})
   943  	if err != nil {
   944  		t.Fatalf("err: %v", err)
   945  	}
   946  
   947  	// Lookup the allocs
   948  	get := &structs.AllocsGetRequest{
   949  		AllocIDs: []string{alloc.ID, alloc2.ID},
   950  		QueryOptions: structs.QueryOptions{
   951  			Region: "global",
   952  		},
   953  	}
   954  	var resp structs.AllocsGetResponse
   955  	if err := msgpackrpc.CallWithCodec(codec, "Alloc.GetAllocs", get, &resp); err != nil {
   956  		t.Fatalf("err: %v", err)
   957  	}
   958  	if resp.Index != 1000 {
   959  		t.Fatalf("Bad index: %d %d", resp.Index, 1000)
   960  	}
   961  
   962  	if len(resp.Allocs) != 2 {
   963  		t.Fatalf("bad: %#v", resp.Allocs)
   964  	}
   965  
   966  	// Lookup nonexistent allocs.
   967  	get = &structs.AllocsGetRequest{
   968  		AllocIDs:     []string{"foo"},
   969  		QueryOptions: structs.QueryOptions{Region: "global"},
   970  	}
   971  	if err := msgpackrpc.CallWithCodec(codec, "Alloc.GetAllocs", get, &resp); err == nil {
   972  		t.Fatalf("expect error")
   973  	}
   974  }
   975  
   976  func TestAllocEndpoint_GetAllocs_Blocking(t *testing.T) {
   977  	ci.Parallel(t)
   978  
   979  	s1, cleanupS1 := TestServer(t, nil)
   980  	defer cleanupS1()
   981  	state := s1.fsm.State()
   982  	codec := rpcClient(t, s1)
   983  	testutil.WaitForLeader(t, s1.RPC)
   984  
   985  	// Create the allocs
   986  	alloc1 := mock.Alloc()
   987  	alloc2 := mock.Alloc()
   988  
   989  	// First create an unrelated alloc
   990  	time.AfterFunc(100*time.Millisecond, func() {
   991  		state.UpsertJobSummary(99, mock.JobSummary(alloc1.JobID))
   992  		err := state.UpsertAllocs(structs.MsgTypeTestSetup, 100, []*structs.Allocation{alloc1})
   993  		if err != nil {
   994  			t.Fatalf("err: %v", err)
   995  		}
   996  	})
   997  
   998  	// Create the alloc we are watching later
   999  	time.AfterFunc(200*time.Millisecond, func() {
  1000  		state.UpsertJobSummary(199, mock.JobSummary(alloc2.JobID))
  1001  		err := state.UpsertAllocs(structs.MsgTypeTestSetup, 200, []*structs.Allocation{alloc2})
  1002  		if err != nil {
  1003  			t.Fatalf("err: %v", err)
  1004  		}
  1005  	})
  1006  
  1007  	// Lookup the allocs
  1008  	get := &structs.AllocsGetRequest{
  1009  		AllocIDs: []string{alloc1.ID, alloc2.ID},
  1010  		QueryOptions: structs.QueryOptions{
  1011  			Region:        "global",
  1012  			MinQueryIndex: 150,
  1013  		},
  1014  	}
  1015  	var resp structs.AllocsGetResponse
  1016  	start := time.Now()
  1017  	if err := msgpackrpc.CallWithCodec(codec, "Alloc.GetAllocs", get, &resp); err != nil {
  1018  		t.Fatalf("err: %v", err)
  1019  	}
  1020  
  1021  	if elapsed := time.Since(start); elapsed < 200*time.Millisecond {
  1022  		t.Fatalf("should block (returned in %s) %#v", elapsed, resp)
  1023  	}
  1024  	if resp.Index != 200 {
  1025  		t.Fatalf("Bad index: %d %d", resp.Index, 200)
  1026  	}
  1027  	if len(resp.Allocs) != 2 {
  1028  		t.Fatalf("bad: %#v", resp.Allocs)
  1029  	}
  1030  }
  1031  
  1032  func TestAllocEndpoint_UpdateDesiredTransition(t *testing.T) {
  1033  	ci.Parallel(t)
  1034  	require := require.New(t)
  1035  
  1036  	s1, _, cleanupS1 := TestACLServer(t, nil)
  1037  	defer cleanupS1()
  1038  	codec := rpcClient(t, s1)
  1039  	testutil.WaitForLeader(t, s1.RPC)
  1040  
  1041  	// Create the register request
  1042  	alloc := mock.Alloc()
  1043  	alloc2 := mock.Alloc()
  1044  	state := s1.fsm.State()
  1045  	require.Nil(state.UpsertJobSummary(998, mock.JobSummary(alloc.JobID)))
  1046  	require.Nil(state.UpsertJobSummary(999, mock.JobSummary(alloc2.JobID)))
  1047  	require.Nil(state.UpsertAllocs(structs.MsgTypeTestSetup, 1000, []*structs.Allocation{alloc, alloc2}))
  1048  
  1049  	t1 := &structs.DesiredTransition{
  1050  		Migrate: pointer.Of(true),
  1051  	}
  1052  
  1053  	// Update the allocs desired status
  1054  	get := &structs.AllocUpdateDesiredTransitionRequest{
  1055  		Allocs: map[string]*structs.DesiredTransition{
  1056  			alloc.ID:  t1,
  1057  			alloc2.ID: t1,
  1058  		},
  1059  		Evals: []*structs.Evaluation{
  1060  			{
  1061  				ID:             uuid.Generate(),
  1062  				Namespace:      alloc.Namespace,
  1063  				Priority:       alloc.Job.Priority,
  1064  				Type:           alloc.Job.Type,
  1065  				TriggeredBy:    structs.EvalTriggerNodeDrain,
  1066  				JobID:          alloc.Job.ID,
  1067  				JobModifyIndex: alloc.Job.ModifyIndex,
  1068  				Status:         structs.EvalStatusPending,
  1069  			},
  1070  			{
  1071  				ID:             uuid.Generate(),
  1072  				Namespace:      alloc2.Namespace,
  1073  				Priority:       alloc2.Job.Priority,
  1074  				Type:           alloc2.Job.Type,
  1075  				TriggeredBy:    structs.EvalTriggerNodeDrain,
  1076  				JobID:          alloc2.Job.ID,
  1077  				JobModifyIndex: alloc2.Job.ModifyIndex,
  1078  				Status:         structs.EvalStatusPending,
  1079  			},
  1080  		},
  1081  		WriteRequest: structs.WriteRequest{
  1082  			Region: "global",
  1083  		},
  1084  	}
  1085  
  1086  	// Try without permissions
  1087  	var resp structs.GenericResponse
  1088  	err := msgpackrpc.CallWithCodec(codec, "Alloc.UpdateDesiredTransition", get, &resp)
  1089  	require.NotNil(err)
  1090  	require.True(structs.IsErrPermissionDenied(err))
  1091  
  1092  	// Try with permissions
  1093  	get.WriteRequest.AuthToken = s1.getLeaderAcl()
  1094  	var resp2 structs.GenericResponse
  1095  	require.Nil(msgpackrpc.CallWithCodec(codec, "Alloc.UpdateDesiredTransition", get, &resp2))
  1096  	require.NotZero(resp2.Index)
  1097  
  1098  	// Look up the allocations
  1099  	out1, err := state.AllocByID(nil, alloc.ID)
  1100  	require.Nil(err)
  1101  	out2, err := state.AllocByID(nil, alloc.ID)
  1102  	require.Nil(err)
  1103  	e1, err := state.EvalByID(nil, get.Evals[0].ID)
  1104  	require.Nil(err)
  1105  	e2, err := state.EvalByID(nil, get.Evals[1].ID)
  1106  	require.Nil(err)
  1107  
  1108  	require.NotNil(out1.DesiredTransition.Migrate)
  1109  	require.NotNil(out2.DesiredTransition.Migrate)
  1110  	require.NotNil(e1)
  1111  	require.NotNil(e2)
  1112  	require.True(*out1.DesiredTransition.Migrate)
  1113  	require.True(*out2.DesiredTransition.Migrate)
  1114  }
  1115  
  1116  func TestAllocEndpoint_Stop_ACL(t *testing.T) {
  1117  	ci.Parallel(t)
  1118  	require := require.New(t)
  1119  
  1120  	s1, _, cleanupS1 := TestACLServer(t, nil)
  1121  	defer cleanupS1()
  1122  	codec := rpcClient(t, s1)
  1123  	testutil.WaitForLeader(t, s1.RPC)
  1124  
  1125  	// Create the register request
  1126  	alloc := mock.Alloc()
  1127  	alloc2 := mock.Alloc()
  1128  	state := s1.fsm.State()
  1129  	require.Nil(state.UpsertJobSummary(998, mock.JobSummary(alloc.JobID)))
  1130  	require.Nil(state.UpsertJobSummary(999, mock.JobSummary(alloc2.JobID)))
  1131  	require.Nil(state.UpsertAllocs(structs.MsgTypeTestSetup, 1000, []*structs.Allocation{alloc, alloc2}))
  1132  
  1133  	req := &structs.AllocStopRequest{
  1134  		AllocID: alloc.ID,
  1135  	}
  1136  	req.Namespace = structs.DefaultNamespace
  1137  	req.Region = alloc.Job.Region
  1138  
  1139  	// Try without permissions
  1140  	var resp structs.AllocStopResponse
  1141  	err := msgpackrpc.CallWithCodec(codec, "Alloc.Stop", req, &resp)
  1142  	require.True(structs.IsErrPermissionDenied(err), "expected permissions error, got: %v", err)
  1143  
  1144  	// Try with management permissions
  1145  	req.WriteRequest.AuthToken = s1.getLeaderAcl()
  1146  	var resp2 structs.AllocStopResponse
  1147  	require.Nil(msgpackrpc.CallWithCodec(codec, "Alloc.Stop", req, &resp2))
  1148  	require.NotZero(resp2.Index)
  1149  
  1150  	// Try with alloc-lifecycle permissions
  1151  	validToken := mock.CreatePolicyAndToken(t, state, 1002, "valid",
  1152  		mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilityAllocLifecycle}))
  1153  	req.WriteRequest.AuthToken = validToken.SecretID
  1154  	req.AllocID = alloc2.ID
  1155  
  1156  	var resp3 structs.AllocStopResponse
  1157  	require.Nil(msgpackrpc.CallWithCodec(codec, "Alloc.Stop", req, &resp3))
  1158  	require.NotZero(resp3.Index)
  1159  
  1160  	// Look up the allocations
  1161  	out1, err := state.AllocByID(nil, alloc.ID)
  1162  	require.Nil(err)
  1163  	out2, err := state.AllocByID(nil, alloc2.ID)
  1164  	require.Nil(err)
  1165  	e1, err := state.EvalByID(nil, resp2.EvalID)
  1166  	require.Nil(err)
  1167  	e2, err := state.EvalByID(nil, resp3.EvalID)
  1168  	require.Nil(err)
  1169  
  1170  	require.NotNil(out1.DesiredTransition.Migrate)
  1171  	require.NotNil(out2.DesiredTransition.Migrate)
  1172  	require.NotNil(e1)
  1173  	require.NotNil(e2)
  1174  	require.True(*out1.DesiredTransition.Migrate)
  1175  	require.True(*out2.DesiredTransition.Migrate)
  1176  }
  1177  
  1178  func TestAllocEndpoint_List_AllNamespaces_ACL_OSS(t *testing.T) {
  1179  	ci.Parallel(t)
  1180  
  1181  	s1, root, cleanupS1 := TestACLServer(t, nil)
  1182  	defer cleanupS1()
  1183  	codec := rpcClient(t, s1)
  1184  	testutil.WaitForLeader(t, s1.RPC)
  1185  	state := s1.fsm.State()
  1186  
  1187  	// two namespaces
  1188  	ns1 := mock.Namespace()
  1189  	ns2 := mock.Namespace()
  1190  	require.NoError(t, state.UpsertNamespaces(900, []*structs.Namespace{ns1, ns2}))
  1191  
  1192  	// Create the allocations
  1193  	alloc1 := mock.Alloc()
  1194  	alloc1.ID = "a" + alloc1.ID[1:]
  1195  	alloc1.Namespace = ns1.Name
  1196  	alloc2 := mock.Alloc()
  1197  	alloc2.ID = "b" + alloc2.ID[1:]
  1198  	alloc2.Namespace = ns2.Name
  1199  	summary1 := mock.JobSummary(alloc1.JobID)
  1200  	summary2 := mock.JobSummary(alloc2.JobID)
  1201  
  1202  	require.NoError(t, state.UpsertJobSummary(999, summary1))
  1203  	require.NoError(t, state.UpsertJobSummary(999, summary2))
  1204  	require.NoError(t, state.UpsertAllocs(structs.MsgTypeTestSetup, 1000, []*structs.Allocation{alloc1, alloc2}))
  1205  	alloc1.CreateIndex = 1000
  1206  	alloc1.ModifyIndex = 1000
  1207  	alloc2.CreateIndex = 1000
  1208  	alloc2.ModifyIndex = 1000
  1209  
  1210  	everythingButReadJob := []string{
  1211  		acl.NamespaceCapabilityDeny,
  1212  		acl.NamespaceCapabilityListJobs,
  1213  		// acl.NamespaceCapabilityReadJob,
  1214  		acl.NamespaceCapabilitySubmitJob,
  1215  		acl.NamespaceCapabilityDispatchJob,
  1216  		acl.NamespaceCapabilityReadLogs,
  1217  		acl.NamespaceCapabilityReadFS,
  1218  		acl.NamespaceCapabilityAllocExec,
  1219  		acl.NamespaceCapabilityAllocNodeExec,
  1220  		acl.NamespaceCapabilityAllocLifecycle,
  1221  		acl.NamespaceCapabilitySentinelOverride,
  1222  		acl.NamespaceCapabilityCSIRegisterPlugin,
  1223  		acl.NamespaceCapabilityCSIWriteVolume,
  1224  		acl.NamespaceCapabilityCSIReadVolume,
  1225  		acl.NamespaceCapabilityCSIListVolume,
  1226  		acl.NamespaceCapabilityCSIMountVolume,
  1227  		acl.NamespaceCapabilityListScalingPolicies,
  1228  		acl.NamespaceCapabilityReadScalingPolicy,
  1229  		acl.NamespaceCapabilityReadJobScaling,
  1230  		acl.NamespaceCapabilityScaleJob,
  1231  		acl.NamespaceCapabilitySubmitRecommendation,
  1232  	}
  1233  
  1234  	ns1token := mock.CreatePolicyAndToken(t, state, 1001, "ns1",
  1235  		mock.NamespacePolicy(ns1.Name, "", []string{acl.NamespaceCapabilityReadJob}))
  1236  	ns1tokenInsufficient := mock.CreatePolicyAndToken(t, state, 1001, "ns1-insufficient",
  1237  		mock.NamespacePolicy(ns1.Name, "", everythingButReadJob))
  1238  	ns2token := mock.CreatePolicyAndToken(t, state, 1001, "ns2",
  1239  		mock.NamespacePolicy(ns2.Name, "", []string{acl.NamespaceCapabilityReadJob}))
  1240  	bothToken := mock.CreatePolicyAndToken(t, state, 1001, "nsBoth",
  1241  		mock.NamespacePolicy(ns1.Name, "", []string{acl.NamespaceCapabilityReadJob})+
  1242  			mock.NamespacePolicy(ns2.Name, "", []string{acl.NamespaceCapabilityReadJob}))
  1243  
  1244  	cases := []struct {
  1245  		Label     string
  1246  		Namespace string
  1247  		Token     string
  1248  		Allocs    []*structs.Allocation
  1249  		Error     bool
  1250  		Message   string
  1251  		Prefix    string
  1252  	}{
  1253  		{
  1254  			Label:     "all namespaces with sufficient token",
  1255  			Namespace: "*",
  1256  			Token:     bothToken.SecretID,
  1257  			Allocs:    []*structs.Allocation{alloc1, alloc2},
  1258  		},
  1259  		{
  1260  			Label:     "all namespaces with root token",
  1261  			Namespace: "*",
  1262  			Token:     root.SecretID,
  1263  			Allocs:    []*structs.Allocation{alloc1, alloc2},
  1264  		},
  1265  		{
  1266  			Label:     "all namespaces with ns1 token",
  1267  			Namespace: "*",
  1268  			Token:     ns1token.SecretID,
  1269  			Allocs:    []*structs.Allocation{alloc1},
  1270  		},
  1271  		{
  1272  			Label:     "all namespaces with ns2 token",
  1273  			Namespace: "*",
  1274  			Token:     ns2token.SecretID,
  1275  			Allocs:    []*structs.Allocation{alloc2},
  1276  		},
  1277  		{
  1278  			Label:     "all namespaces with bad token",
  1279  			Namespace: "*",
  1280  			Token:     uuid.Generate(),
  1281  			Error:     true,
  1282  			Message:   structs.ErrTokenNotFound.Error(),
  1283  		},
  1284  		{
  1285  			Label:     "all namespaces with insufficient token",
  1286  			Namespace: "*",
  1287  			Token:     ns1tokenInsufficient.SecretID,
  1288  			Error:     true,
  1289  			Message:   structs.ErrPermissionDenied.Error(),
  1290  		},
  1291  		{
  1292  			Label:     "ns1 with ns1 token",
  1293  			Namespace: ns1.Name,
  1294  			Token:     ns1token.SecretID,
  1295  			Allocs:    []*structs.Allocation{alloc1},
  1296  		},
  1297  		{
  1298  			Label:     "ns1 with root token",
  1299  			Namespace: ns1.Name,
  1300  			Token:     root.SecretID,
  1301  			Allocs:    []*structs.Allocation{alloc1},
  1302  		},
  1303  		{
  1304  			Label:     "ns1 with ns2 token",
  1305  			Namespace: ns1.Name,
  1306  			Token:     ns2token.SecretID,
  1307  			Error:     true,
  1308  		},
  1309  		{
  1310  			Label:     "ns1 with invalid token",
  1311  			Namespace: ns1.Name,
  1312  			Token:     uuid.Generate(),
  1313  			Error:     true,
  1314  			Message:   structs.ErrTokenNotFound.Error(),
  1315  		},
  1316  		{
  1317  			Label:     "bad namespace with root token",
  1318  			Namespace: uuid.Generate(),
  1319  			Token:     root.SecretID,
  1320  			Allocs:    []*structs.Allocation{},
  1321  		},
  1322  		{
  1323  			Label:     "all namespaces with prefix",
  1324  			Namespace: "*",
  1325  			Prefix:    alloc1.ID[:2],
  1326  			Token:     root.SecretID,
  1327  			Allocs:    []*structs.Allocation{alloc1},
  1328  		},
  1329  	}
  1330  
  1331  	for _, tc := range cases {
  1332  		t.Run(tc.Label, func(t *testing.T) {
  1333  
  1334  			get := &structs.AllocListRequest{
  1335  				QueryOptions: structs.QueryOptions{
  1336  					Region:    "global",
  1337  					Namespace: tc.Namespace,
  1338  					Prefix:    tc.Prefix,
  1339  					AuthToken: tc.Token,
  1340  				},
  1341  			}
  1342  			var resp structs.AllocListResponse
  1343  			err := msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp)
  1344  			if tc.Error {
  1345  				require.Error(t, err)
  1346  				if tc.Message != "" {
  1347  					require.Equal(t, err.Error(), tc.Message)
  1348  				} else {
  1349  					require.Equal(t, err.Error(), structs.ErrPermissionDenied.Error())
  1350  				}
  1351  			} else {
  1352  				require.NoError(t, err)
  1353  				require.Equal(t, uint64(1000), resp.Index)
  1354  				exp := make([]*structs.AllocListStub, len(tc.Allocs))
  1355  				for i, a := range tc.Allocs {
  1356  					exp[i] = a.Stub(nil)
  1357  				}
  1358  				require.ElementsMatch(t, exp, resp.Allocations)
  1359  			}
  1360  		})
  1361  	}
  1362  
  1363  }
  1364  
  1365  func TestAlloc_GetServiceRegistrations(t *testing.T) {
  1366  	ci.Parallel(t)
  1367  
  1368  	// This function is a helper function to set up an allocation and service
  1369  	// which can be queried.
  1370  	correctSetupFn := func(s *Server) (error, string, *structs.ServiceRegistration) {
  1371  		// Generate an upsert an allocation.
  1372  		alloc := mock.Alloc()
  1373  		err := s.State().UpsertAllocs(structs.MsgTypeTestSetup, 10, []*structs.Allocation{alloc})
  1374  		if err != nil {
  1375  			return nil, "", nil
  1376  		}
  1377  
  1378  		// Generate services. Set the allocation ID to the first, so it
  1379  		// matches the allocation. The alloc and first service both
  1380  		// reside in the default namespace.
  1381  		services := mock.ServiceRegistrations()
  1382  		services[0].AllocID = alloc.ID
  1383  		err = s.State().UpsertServiceRegistrations(structs.MsgTypeTestSetup, 20, services)
  1384  
  1385  		return err, alloc.ID, services[0]
  1386  	}
  1387  
  1388  	testCases := []struct {
  1389  		serverFn func(t *testing.T) (*Server, *structs.ACLToken, func())
  1390  		testFn   func(t *testing.T, s *Server, token *structs.ACLToken)
  1391  		name     string
  1392  	}{
  1393  		{
  1394  			serverFn: func(t *testing.T) (*Server, *structs.ACLToken, func()) {
  1395  				server, cleanup := TestServer(t, nil)
  1396  				return server, nil, cleanup
  1397  			},
  1398  			testFn: func(t *testing.T, s *Server, _ *structs.ACLToken) {
  1399  				codec := rpcClient(t, s)
  1400  				testutil.WaitForLeader(t, s.RPC)
  1401  
  1402  				err, allocID, service := correctSetupFn(s)
  1403  				require.NoError(t, err)
  1404  
  1405  				// Perform a lookup on the first service.
  1406  				serviceRegReq := &structs.AllocServiceRegistrationsRequest{
  1407  					AllocID: allocID,
  1408  					QueryOptions: structs.QueryOptions{
  1409  						Namespace: service.Namespace,
  1410  						Region:    s.Region(),
  1411  					},
  1412  				}
  1413  				var serviceRegResp structs.AllocServiceRegistrationsResponse
  1414  				err = msgpackrpc.CallWithCodec(codec, structs.AllocServiceRegistrationsRPCMethod, serviceRegReq, &serviceRegResp)
  1415  				require.NoError(t, err)
  1416  				require.EqualValues(t, uint64(20), serviceRegResp.Index)
  1417  				require.ElementsMatch(t, serviceRegResp.Services, []*structs.ServiceRegistration{service})
  1418  			},
  1419  			name: "ACLs disabled alloc found with regs",
  1420  		},
  1421  		{
  1422  			serverFn: func(t *testing.T) (*Server, *structs.ACLToken, func()) {
  1423  				server, cleanup := TestServer(t, nil)
  1424  				return server, nil, cleanup
  1425  			},
  1426  			testFn: func(t *testing.T, s *Server, _ *structs.ACLToken) {
  1427  				codec := rpcClient(t, s)
  1428  				testutil.WaitForLeader(t, s.RPC)
  1429  
  1430  				// Generate and upsert our services.
  1431  				services := mock.ServiceRegistrations()
  1432  				require.NoError(t, s.State().UpsertServiceRegistrations(structs.MsgTypeTestSetup, 20, services))
  1433  
  1434  				// Perform a lookup on the first service using the allocation
  1435  				// ID. This allocation does not exist within the Nomad state
  1436  				// meaning the service is orphaned or the caller used an
  1437  				// incorrect allocation ID.
  1438  				serviceRegReq := &structs.AllocServiceRegistrationsRequest{
  1439  					AllocID: services[0].AllocID,
  1440  					QueryOptions: structs.QueryOptions{
  1441  						Namespace: services[0].Namespace,
  1442  						Region:    s.Region(),
  1443  					},
  1444  				}
  1445  				var serviceRegResp structs.AllocServiceRegistrationsResponse
  1446  				err := msgpackrpc.CallWithCodec(codec, structs.AllocServiceRegistrationsRPCMethod, serviceRegReq, &serviceRegResp)
  1447  				require.NoError(t, err)
  1448  				require.Nil(t, serviceRegResp.Services)
  1449  			},
  1450  			name: "ACLs disabled alloc not found",
  1451  		},
  1452  		{
  1453  			serverFn: func(t *testing.T) (*Server, *structs.ACLToken, func()) {
  1454  				server, cleanup := TestServer(t, nil)
  1455  				return server, nil, cleanup
  1456  			},
  1457  			testFn: func(t *testing.T, s *Server, _ *structs.ACLToken) {
  1458  				codec := rpcClient(t, s)
  1459  				testutil.WaitForLeader(t, s.RPC)
  1460  
  1461  				err, allocID, _ := correctSetupFn(s)
  1462  				require.NoError(t, err)
  1463  
  1464  				// Perform a lookup on the first service using the allocation
  1465  				// ID but a random namespace. The namespace on the allocation
  1466  				// does therefore not match the request args.
  1467  				serviceRegReq := &structs.AllocServiceRegistrationsRequest{
  1468  					AllocID: allocID,
  1469  					QueryOptions: structs.QueryOptions{
  1470  						Namespace: "platform",
  1471  						Region:    s.Region(),
  1472  					},
  1473  				}
  1474  				var serviceRegResp structs.AllocServiceRegistrationsResponse
  1475  				err = msgpackrpc.CallWithCodec(codec, structs.AllocServiceRegistrationsRPCMethod, serviceRegReq, &serviceRegResp)
  1476  				require.NoError(t, err)
  1477  				require.ElementsMatch(t, serviceRegResp.Services, []*structs.ServiceRegistration{})
  1478  			},
  1479  			name: "ACLs disabled alloc found in different namespace than request",
  1480  		},
  1481  		{
  1482  			serverFn: func(t *testing.T) (*Server, *structs.ACLToken, func()) {
  1483  				server, cleanup := TestServer(t, nil)
  1484  				return server, nil, cleanup
  1485  			},
  1486  			testFn: func(t *testing.T, s *Server, _ *structs.ACLToken) {
  1487  				codec := rpcClient(t, s)
  1488  				testutil.WaitForLeader(t, s.RPC)
  1489  
  1490  				// Generate an upsert an allocation.
  1491  				alloc := mock.Alloc()
  1492  				require.NoError(t, s.State().UpsertAllocs(
  1493  					structs.MsgTypeTestSetup, 10, []*structs.Allocation{alloc}))
  1494  
  1495  				// Perform a lookup using the allocation information.
  1496  				serviceRegReq := &structs.AllocServiceRegistrationsRequest{
  1497  					AllocID: alloc.ID,
  1498  					QueryOptions: structs.QueryOptions{
  1499  						Namespace: alloc.Namespace,
  1500  						Region:    s.Region(),
  1501  					},
  1502  				}
  1503  				var serviceRegResp structs.AllocServiceRegistrationsResponse
  1504  				err := msgpackrpc.CallWithCodec(codec, structs.AllocServiceRegistrationsRPCMethod, serviceRegReq, &serviceRegResp)
  1505  				require.NoError(t, err)
  1506  				require.ElementsMatch(t, serviceRegResp.Services, []*structs.ServiceRegistration{})
  1507  			},
  1508  			name: "ACLs disabled alloc found without regs",
  1509  		},
  1510  		{
  1511  			serverFn: func(t *testing.T) (*Server, *structs.ACLToken, func()) {
  1512  				return TestACLServer(t, nil)
  1513  			},
  1514  			testFn: func(t *testing.T, s *Server, token *structs.ACLToken) {
  1515  				codec := rpcClient(t, s)
  1516  				testutil.WaitForLeader(t, s.RPC)
  1517  
  1518  				err, allocID, service := correctSetupFn(s)
  1519  				require.NoError(t, err)
  1520  
  1521  				// Perform a lookup using the allocation information.
  1522  				serviceRegReq := &structs.AllocServiceRegistrationsRequest{
  1523  					AllocID: allocID,
  1524  					QueryOptions: structs.QueryOptions{
  1525  						Namespace: service.Namespace,
  1526  						Region:    s.Region(),
  1527  						AuthToken: token.SecretID,
  1528  					},
  1529  				}
  1530  				var serviceRegResp structs.AllocServiceRegistrationsResponse
  1531  				err = msgpackrpc.CallWithCodec(codec, structs.AllocServiceRegistrationsRPCMethod, serviceRegReq, &serviceRegResp)
  1532  				require.NoError(t, err)
  1533  				require.ElementsMatch(t, serviceRegResp.Services, []*structs.ServiceRegistration{service})
  1534  			},
  1535  			name: "ACLs enabled use management token",
  1536  		},
  1537  		{
  1538  			serverFn: func(t *testing.T) (*Server, *structs.ACLToken, func()) {
  1539  				return TestACLServer(t, nil)
  1540  			},
  1541  			testFn: func(t *testing.T, s *Server, _ *structs.ACLToken) {
  1542  				codec := rpcClient(t, s)
  1543  				testutil.WaitForLeader(t, s.RPC)
  1544  
  1545  				err, allocID, service := correctSetupFn(s)
  1546  				require.NoError(t, err)
  1547  
  1548  				// Create and policy and grab the auth token.
  1549  				authToken := mock.CreatePolicyAndToken(t, s.State(), 30, "test-node-get-service-reg",
  1550  					mock.NamespacePolicy(service.Namespace, "", []string{acl.NamespaceCapabilityReadJob})).SecretID
  1551  
  1552  				// Perform a lookup using the allocation information.
  1553  				serviceRegReq := &structs.AllocServiceRegistrationsRequest{
  1554  					AllocID: allocID,
  1555  					QueryOptions: structs.QueryOptions{
  1556  						Namespace: service.Namespace,
  1557  						Region:    s.Region(),
  1558  						AuthToken: authToken,
  1559  					},
  1560  				}
  1561  				var serviceRegResp structs.AllocServiceRegistrationsResponse
  1562  				err = msgpackrpc.CallWithCodec(codec, structs.AllocServiceRegistrationsRPCMethod, serviceRegReq, &serviceRegResp)
  1563  				require.NoError(t, err)
  1564  				require.ElementsMatch(t, serviceRegResp.Services, []*structs.ServiceRegistration{service})
  1565  			},
  1566  			name: "ACLs enabled use read-job namespace capability token",
  1567  		},
  1568  		{
  1569  			serverFn: func(t *testing.T) (*Server, *structs.ACLToken, func()) {
  1570  				return TestACLServer(t, nil)
  1571  			},
  1572  			testFn: func(t *testing.T, s *Server, _ *structs.ACLToken) {
  1573  				codec := rpcClient(t, s)
  1574  				testutil.WaitForLeader(t, s.RPC)
  1575  
  1576  				err, allocID, service := correctSetupFn(s)
  1577  				require.NoError(t, err)
  1578  
  1579  				// Create and policy and grab the auth token.
  1580  				authToken := mock.CreatePolicyAndToken(t, s.State(), 30, "test-node-get-service-reg",
  1581  					mock.NamespacePolicy(service.Namespace, "read", nil)).SecretID
  1582  
  1583  				// Perform a lookup using the allocation information.
  1584  				serviceRegReq := &structs.AllocServiceRegistrationsRequest{
  1585  					AllocID: allocID,
  1586  					QueryOptions: structs.QueryOptions{
  1587  						Namespace: service.Namespace,
  1588  						Region:    s.Region(),
  1589  						AuthToken: authToken,
  1590  					},
  1591  				}
  1592  				var serviceRegResp structs.AllocServiceRegistrationsResponse
  1593  				err = msgpackrpc.CallWithCodec(codec, structs.AllocServiceRegistrationsRPCMethod, serviceRegReq, &serviceRegResp)
  1594  				require.NoError(t, err)
  1595  				require.ElementsMatch(t, serviceRegResp.Services, []*structs.ServiceRegistration{service})
  1596  			},
  1597  			name: "ACLs enabled use read namespace policy token",
  1598  		},
  1599  		{
  1600  			serverFn: func(t *testing.T) (*Server, *structs.ACLToken, func()) {
  1601  				return TestACLServer(t, nil)
  1602  			},
  1603  			testFn: func(t *testing.T, s *Server, _ *structs.ACLToken) {
  1604  				codec := rpcClient(t, s)
  1605  				testutil.WaitForLeader(t, s.RPC)
  1606  
  1607  				err, allocID, service := correctSetupFn(s)
  1608  				require.NoError(t, err)
  1609  
  1610  				// Create and policy and grab the auth token.
  1611  				authToken := mock.CreatePolicyAndToken(t, s.State(), 30, "test-node-get-service-reg",
  1612  					mock.NamespacePolicy("ohno", "read", nil)).SecretID
  1613  
  1614  				// Perform a lookup using the allocation information.
  1615  				serviceRegReq := &structs.AllocServiceRegistrationsRequest{
  1616  					AllocID: allocID,
  1617  					QueryOptions: structs.QueryOptions{
  1618  						Namespace: service.Namespace,
  1619  						Region:    s.Region(),
  1620  						AuthToken: authToken,
  1621  					},
  1622  				}
  1623  				var serviceRegResp structs.AllocServiceRegistrationsResponse
  1624  				err = msgpackrpc.CallWithCodec(codec, structs.AllocServiceRegistrationsRPCMethod, serviceRegReq, &serviceRegResp)
  1625  				require.Error(t, err)
  1626  				require.Contains(t, err.Error(), "Permission denied")
  1627  				require.Empty(t, serviceRegResp.Services)
  1628  			},
  1629  			name: "ACLs enabled use read incorrect namespace policy token",
  1630  		},
  1631  		{
  1632  			serverFn: func(t *testing.T) (*Server, *structs.ACLToken, func()) {
  1633  				return TestACLServer(t, nil)
  1634  			},
  1635  			testFn: func(t *testing.T, s *Server, _ *structs.ACLToken) {
  1636  				codec := rpcClient(t, s)
  1637  				testutil.WaitForLeader(t, s.RPC)
  1638  
  1639  				err, allocID, service := correctSetupFn(s)
  1640  				require.NoError(t, err)
  1641  
  1642  				// Create and policy and grab the auth token.
  1643  				authToken := mock.CreatePolicyAndToken(t, s.State(), 30, "test-node-get-service-reg",
  1644  					mock.NamespacePolicy(service.Namespace, "", []string{acl.NamespaceCapabilityReadScalingPolicy})).SecretID
  1645  
  1646  				// Perform a lookup using the allocation information.
  1647  				serviceRegReq := &structs.AllocServiceRegistrationsRequest{
  1648  					AllocID: allocID,
  1649  					QueryOptions: structs.QueryOptions{
  1650  						Namespace: service.Namespace,
  1651  						Region:    s.Region(),
  1652  						AuthToken: authToken,
  1653  					},
  1654  				}
  1655  				var serviceRegResp structs.AllocServiceRegistrationsResponse
  1656  				err = msgpackrpc.CallWithCodec(codec, structs.AllocServiceRegistrationsRPCMethod, serviceRegReq, &serviceRegResp)
  1657  				require.Error(t, err)
  1658  				require.Contains(t, err.Error(), "Permission denied")
  1659  				require.Empty(t, serviceRegResp.Services)
  1660  			},
  1661  			name: "ACLs enabled use incorrect capability",
  1662  		},
  1663  	}
  1664  
  1665  	for _, tc := range testCases {
  1666  		t.Run(tc.name, func(t *testing.T) {
  1667  			server, aclToken, cleanup := tc.serverFn(t)
  1668  			defer cleanup()
  1669  			tc.testFn(t, server, aclToken)
  1670  		})
  1671  	}
  1672  }