github.com/emate/nomad@v0.8.2-wo-binpacking/nomad/alloc_endpoint_test.go (about)

     1  package nomad
     2  
     3  import (
     4  	"reflect"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/hashicorp/net-rpc-msgpackrpc"
     9  	"github.com/hashicorp/nomad/acl"
    10  	"github.com/hashicorp/nomad/helper"
    11  	"github.com/hashicorp/nomad/helper/uuid"
    12  	"github.com/hashicorp/nomad/nomad/mock"
    13  	"github.com/hashicorp/nomad/nomad/structs"
    14  	"github.com/hashicorp/nomad/testutil"
    15  	"github.com/stretchr/testify/assert"
    16  	"github.com/stretchr/testify/require"
    17  )
    18  
    19  func TestAllocEndpoint_List(t *testing.T) {
    20  	t.Parallel()
    21  	s1 := TestServer(t, nil)
    22  	defer s1.Shutdown()
    23  	codec := rpcClient(t, s1)
    24  	testutil.WaitForLeader(t, s1.RPC)
    25  
    26  	// Create the register request
    27  	alloc := mock.Alloc()
    28  	summary := mock.JobSummary(alloc.JobID)
    29  	state := s1.fsm.State()
    30  
    31  	if err := state.UpsertJobSummary(999, summary); err != nil {
    32  		t.Fatalf("err: %v", err)
    33  	}
    34  	if err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}); err != nil {
    35  		t.Fatalf("err: %v", err)
    36  	}
    37  
    38  	// Lookup the allocations
    39  	get := &structs.AllocListRequest{
    40  		QueryOptions: structs.QueryOptions{
    41  			Region:    "global",
    42  			Namespace: structs.DefaultNamespace,
    43  		},
    44  	}
    45  	var resp structs.AllocListResponse
    46  	if err := msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp); err != nil {
    47  		t.Fatalf("err: %v", err)
    48  	}
    49  	if resp.Index != 1000 {
    50  		t.Fatalf("Bad index: %d %d", resp.Index, 1000)
    51  	}
    52  
    53  	if len(resp.Allocations) != 1 {
    54  		t.Fatalf("bad: %#v", resp.Allocations)
    55  	}
    56  	if resp.Allocations[0].ID != alloc.ID {
    57  		t.Fatalf("bad: %#v", resp.Allocations[0])
    58  	}
    59  
    60  	// Lookup the allocations by prefix
    61  	get = &structs.AllocListRequest{
    62  		QueryOptions: structs.QueryOptions{
    63  			Region:    "global",
    64  			Namespace: structs.DefaultNamespace,
    65  			Prefix:    alloc.ID[:4],
    66  		},
    67  	}
    68  
    69  	var resp2 structs.AllocListResponse
    70  	if err := msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp2); err != nil {
    71  		t.Fatalf("err: %v", err)
    72  	}
    73  	if resp2.Index != 1000 {
    74  		t.Fatalf("Bad index: %d %d", resp2.Index, 1000)
    75  	}
    76  
    77  	if len(resp2.Allocations) != 1 {
    78  		t.Fatalf("bad: %#v", resp2.Allocations)
    79  	}
    80  	if resp2.Allocations[0].ID != alloc.ID {
    81  		t.Fatalf("bad: %#v", resp2.Allocations[0])
    82  	}
    83  }
    84  
    85  func TestAllocEndpoint_List_ACL(t *testing.T) {
    86  	t.Parallel()
    87  	s1, root := TestACLServer(t, nil)
    88  	defer s1.Shutdown()
    89  	codec := rpcClient(t, s1)
    90  	testutil.WaitForLeader(t, s1.RPC)
    91  	assert := assert.New(t)
    92  
    93  	// Create the alloc
    94  	alloc := mock.Alloc()
    95  	allocs := []*structs.Allocation{alloc}
    96  	summary := mock.JobSummary(alloc.JobID)
    97  	state := s1.fsm.State()
    98  
    99  	assert.Nil(state.UpsertJobSummary(999, summary), "UpsertJobSummary")
   100  	assert.Nil(state.UpsertAllocs(1000, allocs), "UpsertAllocs")
   101  
   102  	stubAllocs := []*structs.AllocListStub{alloc.Stub()}
   103  	stubAllocs[0].CreateIndex = 1000
   104  	stubAllocs[0].ModifyIndex = 1000
   105  
   106  	// Create the namespace policy and tokens
   107  	validToken := mock.CreatePolicyAndToken(t, state, 1001, "test-valid",
   108  		mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilityReadJob}))
   109  	invalidToken := mock.CreatePolicyAndToken(t, state, 1003, "test-invalid",
   110  		mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilityListJobs}))
   111  
   112  	// Lookup the allocs without a token and expect failure
   113  	get := &structs.AllocListRequest{
   114  		QueryOptions: structs.QueryOptions{
   115  			Region:    "global",
   116  			Namespace: structs.DefaultNamespace,
   117  		},
   118  	}
   119  	var resp structs.AllocListResponse
   120  	assert.NotNil(msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp), "RPC")
   121  
   122  	// Try with a valid token
   123  	get.AuthToken = validToken.SecretID
   124  	assert.Nil(msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp), "RPC")
   125  	assert.EqualValues(resp.Index, 1000, "resp.Index")
   126  	assert.Equal(stubAllocs, resp.Allocations, "Returned alloc list not equal")
   127  
   128  	// Try with a invalid token
   129  	get.AuthToken = invalidToken.SecretID
   130  	err := msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp)
   131  	assert.NotNil(err, "RPC")
   132  	assert.Equal(err.Error(), structs.ErrPermissionDenied.Error())
   133  
   134  	// Try with a root token
   135  	get.AuthToken = root.SecretID
   136  	assert.Nil(msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp), "RPC")
   137  	assert.EqualValues(resp.Index, 1000, "resp.Index")
   138  	assert.Equal(stubAllocs, resp.Allocations, "Returned alloc list not equal")
   139  }
   140  
   141  func TestAllocEndpoint_List_Blocking(t *testing.T) {
   142  	t.Parallel()
   143  	s1 := TestServer(t, nil)
   144  	defer s1.Shutdown()
   145  	state := s1.fsm.State()
   146  	codec := rpcClient(t, s1)
   147  	testutil.WaitForLeader(t, s1.RPC)
   148  
   149  	// Create the alloc
   150  	alloc := mock.Alloc()
   151  
   152  	summary := mock.JobSummary(alloc.JobID)
   153  	if err := state.UpsertJobSummary(1, summary); err != nil {
   154  		t.Fatalf("err: %v", err)
   155  	}
   156  	// Upsert alloc triggers watches
   157  	time.AfterFunc(100*time.Millisecond, func() {
   158  		if err := state.UpsertAllocs(2, []*structs.Allocation{alloc}); err != nil {
   159  			t.Fatalf("err: %v", err)
   160  		}
   161  	})
   162  
   163  	req := &structs.AllocListRequest{
   164  		QueryOptions: structs.QueryOptions{
   165  			Region:        "global",
   166  			Namespace:     structs.DefaultNamespace,
   167  			MinQueryIndex: 1,
   168  		},
   169  	}
   170  	start := time.Now()
   171  	var resp structs.AllocListResponse
   172  	if err := msgpackrpc.CallWithCodec(codec, "Alloc.List", req, &resp); err != nil {
   173  		t.Fatalf("err: %v", err)
   174  	}
   175  
   176  	if elapsed := time.Since(start); elapsed < 100*time.Millisecond {
   177  		t.Fatalf("should block (returned in %s) %#v", elapsed, resp)
   178  	}
   179  	if resp.Index != 2 {
   180  		t.Fatalf("Bad index: %d %d", resp.Index, 2)
   181  	}
   182  	if len(resp.Allocations) != 1 || resp.Allocations[0].ID != alloc.ID {
   183  		t.Fatalf("bad: %#v", resp.Allocations)
   184  	}
   185  
   186  	// Client updates trigger watches
   187  	alloc2 := mock.Alloc()
   188  	alloc2.ID = alloc.ID
   189  	alloc2.ClientStatus = structs.AllocClientStatusRunning
   190  	time.AfterFunc(100*time.Millisecond, func() {
   191  		state.UpsertJobSummary(3, mock.JobSummary(alloc2.JobID))
   192  		if err := state.UpdateAllocsFromClient(4, []*structs.Allocation{alloc2}); err != nil {
   193  			t.Fatalf("err: %v", err)
   194  		}
   195  	})
   196  
   197  	req.MinQueryIndex = 3
   198  	start = time.Now()
   199  	var resp2 structs.AllocListResponse
   200  	if err := msgpackrpc.CallWithCodec(codec, "Alloc.List", req, &resp2); err != nil {
   201  		t.Fatalf("err: %v", err)
   202  	}
   203  
   204  	if elapsed := time.Since(start); elapsed < 100*time.Millisecond {
   205  		t.Fatalf("should block (returned in %s) %#v", elapsed, resp2)
   206  	}
   207  	if resp2.Index != 4 {
   208  		t.Fatalf("Bad index: %d %d", resp2.Index, 4)
   209  	}
   210  	if len(resp2.Allocations) != 1 || resp.Allocations[0].ID != alloc.ID ||
   211  		resp2.Allocations[0].ClientStatus != structs.AllocClientStatusRunning {
   212  		t.Fatalf("bad: %#v", resp2.Allocations)
   213  	}
   214  }
   215  
   216  func TestAllocEndpoint_GetAlloc(t *testing.T) {
   217  	t.Parallel()
   218  	s1 := TestServer(t, nil)
   219  	defer s1.Shutdown()
   220  	codec := rpcClient(t, s1)
   221  	testutil.WaitForLeader(t, s1.RPC)
   222  
   223  	// Create the register request
   224  	prevAllocID := uuid.Generate()
   225  	alloc := mock.Alloc()
   226  	alloc.RescheduleTracker = &structs.RescheduleTracker{
   227  		Events: []*structs.RescheduleEvent{
   228  			{RescheduleTime: time.Now().UTC().UnixNano(), PrevNodeID: "boom", PrevAllocID: prevAllocID},
   229  		},
   230  	}
   231  	state := s1.fsm.State()
   232  	state.UpsertJobSummary(999, mock.JobSummary(alloc.JobID))
   233  	err := state.UpsertAllocs(1000, []*structs.Allocation{alloc})
   234  	if err != nil {
   235  		t.Fatalf("err: %v", err)
   236  	}
   237  
   238  	// Lookup the alloc
   239  	get := &structs.AllocSpecificRequest{
   240  		AllocID:      alloc.ID,
   241  		QueryOptions: structs.QueryOptions{Region: "global"},
   242  	}
   243  	var resp structs.SingleAllocResponse
   244  	if err := msgpackrpc.CallWithCodec(codec, "Alloc.GetAlloc", get, &resp); err != nil {
   245  		t.Fatalf("err: %v", err)
   246  	}
   247  	if resp.Index != 1000 {
   248  		t.Fatalf("Bad index: %d %d", resp.Index, 1000)
   249  	}
   250  
   251  	if !reflect.DeepEqual(alloc, resp.Alloc) {
   252  		t.Fatalf("bad: %#v", resp.Alloc)
   253  	}
   254  }
   255  
   256  func TestAllocEndpoint_GetAlloc_ACL(t *testing.T) {
   257  	t.Parallel()
   258  	s1, root := TestACLServer(t, nil)
   259  	defer s1.Shutdown()
   260  	codec := rpcClient(t, s1)
   261  	testutil.WaitForLeader(t, s1.RPC)
   262  	assert := assert.New(t)
   263  
   264  	// Create the alloc
   265  	alloc := mock.Alloc()
   266  	allocs := []*structs.Allocation{alloc}
   267  	summary := mock.JobSummary(alloc.JobID)
   268  	state := s1.fsm.State()
   269  
   270  	assert.Nil(state.UpsertJobSummary(999, summary), "UpsertJobSummary")
   271  	assert.Nil(state.UpsertAllocs(1000, allocs), "UpsertAllocs")
   272  
   273  	// Create the namespace policy and tokens
   274  	validToken := mock.CreatePolicyAndToken(t, state, 1001, "test-valid",
   275  		mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilityReadJob}))
   276  	invalidToken := mock.CreatePolicyAndToken(t, state, 1003, "test-invalid",
   277  		mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilityListJobs}))
   278  
   279  	get := &structs.AllocSpecificRequest{
   280  		AllocID:      alloc.ID,
   281  		QueryOptions: structs.QueryOptions{Region: "global"},
   282  	}
   283  
   284  	// Lookup the alloc without a token and expect failure
   285  	{
   286  		var resp structs.SingleAllocResponse
   287  		err := msgpackrpc.CallWithCodec(codec, "Alloc.GetAlloc", get, &resp)
   288  		assert.Equal(structs.ErrPermissionDenied.Error(), err.Error())
   289  	}
   290  
   291  	// Try with a valid ACL token
   292  	{
   293  		get.AuthToken = validToken.SecretID
   294  		var resp structs.SingleAllocResponse
   295  		assert.Nil(msgpackrpc.CallWithCodec(codec, "Alloc.GetAlloc", get, &resp), "RPC")
   296  		assert.EqualValues(resp.Index, 1000, "resp.Index")
   297  		assert.Equal(alloc, resp.Alloc, "Returned alloc not equal")
   298  	}
   299  
   300  	// Try with a valid Node.SecretID
   301  	{
   302  		node := mock.Node()
   303  		assert.Nil(state.UpsertNode(1005, node))
   304  		get.AuthToken = node.SecretID
   305  		var resp structs.SingleAllocResponse
   306  		assert.Nil(msgpackrpc.CallWithCodec(codec, "Alloc.GetAlloc", get, &resp), "RPC")
   307  		assert.EqualValues(resp.Index, 1000, "resp.Index")
   308  		assert.Equal(alloc, resp.Alloc, "Returned alloc not equal")
   309  	}
   310  
   311  	// Try with a invalid token
   312  	{
   313  		get.AuthToken = invalidToken.SecretID
   314  		var resp structs.SingleAllocResponse
   315  		err := msgpackrpc.CallWithCodec(codec, "Alloc.GetAlloc", get, &resp)
   316  		assert.NotNil(err, "RPC")
   317  		assert.Equal(err.Error(), structs.ErrPermissionDenied.Error())
   318  	}
   319  
   320  	// Try with a root token
   321  	{
   322  		get.AuthToken = root.SecretID
   323  		var resp structs.SingleAllocResponse
   324  		assert.Nil(msgpackrpc.CallWithCodec(codec, "Alloc.GetAlloc", get, &resp), "RPC")
   325  		assert.EqualValues(resp.Index, 1000, "resp.Index")
   326  		assert.Equal(alloc, resp.Alloc, "Returned alloc not equal")
   327  	}
   328  }
   329  
   330  func TestAllocEndpoint_GetAlloc_Blocking(t *testing.T) {
   331  	t.Parallel()
   332  	s1 := TestServer(t, nil)
   333  	defer s1.Shutdown()
   334  	state := s1.fsm.State()
   335  	codec := rpcClient(t, s1)
   336  	testutil.WaitForLeader(t, s1.RPC)
   337  
   338  	// Create the allocs
   339  	alloc1 := mock.Alloc()
   340  	alloc2 := mock.Alloc()
   341  
   342  	// First create an unrelated alloc
   343  	time.AfterFunc(100*time.Millisecond, func() {
   344  		state.UpsertJobSummary(99, mock.JobSummary(alloc1.JobID))
   345  		err := state.UpsertAllocs(100, []*structs.Allocation{alloc1})
   346  		if err != nil {
   347  			t.Fatalf("err: %v", err)
   348  		}
   349  	})
   350  
   351  	// Create the alloc we are watching later
   352  	time.AfterFunc(200*time.Millisecond, func() {
   353  		state.UpsertJobSummary(199, mock.JobSummary(alloc2.JobID))
   354  		err := state.UpsertAllocs(200, []*structs.Allocation{alloc2})
   355  		if err != nil {
   356  			t.Fatalf("err: %v", err)
   357  		}
   358  	})
   359  
   360  	// Lookup the allocs
   361  	get := &structs.AllocSpecificRequest{
   362  		AllocID: alloc2.ID,
   363  		QueryOptions: structs.QueryOptions{
   364  			Region:        "global",
   365  			MinQueryIndex: 150,
   366  		},
   367  	}
   368  	var resp structs.SingleAllocResponse
   369  	start := time.Now()
   370  	if err := msgpackrpc.CallWithCodec(codec, "Alloc.GetAlloc", get, &resp); err != nil {
   371  		t.Fatalf("err: %v", err)
   372  	}
   373  
   374  	if elapsed := time.Since(start); elapsed < 200*time.Millisecond {
   375  		t.Fatalf("should block (returned in %s) %#v", elapsed, resp)
   376  	}
   377  	if resp.Index != 200 {
   378  		t.Fatalf("Bad index: %d %d", resp.Index, 200)
   379  	}
   380  	if resp.Alloc == nil || resp.Alloc.ID != alloc2.ID {
   381  		t.Fatalf("bad: %#v", resp.Alloc)
   382  	}
   383  }
   384  
   385  func TestAllocEndpoint_GetAllocs(t *testing.T) {
   386  	t.Parallel()
   387  	s1 := TestServer(t, nil)
   388  	defer s1.Shutdown()
   389  	codec := rpcClient(t, s1)
   390  	testutil.WaitForLeader(t, s1.RPC)
   391  
   392  	// Create the register request
   393  	alloc := mock.Alloc()
   394  	alloc2 := mock.Alloc()
   395  	state := s1.fsm.State()
   396  	state.UpsertJobSummary(998, mock.JobSummary(alloc.JobID))
   397  	state.UpsertJobSummary(999, mock.JobSummary(alloc2.JobID))
   398  	err := state.UpsertAllocs(1000, []*structs.Allocation{alloc, alloc2})
   399  	if err != nil {
   400  		t.Fatalf("err: %v", err)
   401  	}
   402  
   403  	// Lookup the allocs
   404  	get := &structs.AllocsGetRequest{
   405  		AllocIDs: []string{alloc.ID, alloc2.ID},
   406  		QueryOptions: structs.QueryOptions{
   407  			Region: "global",
   408  		},
   409  	}
   410  	var resp structs.AllocsGetResponse
   411  	if err := msgpackrpc.CallWithCodec(codec, "Alloc.GetAllocs", get, &resp); err != nil {
   412  		t.Fatalf("err: %v", err)
   413  	}
   414  	if resp.Index != 1000 {
   415  		t.Fatalf("Bad index: %d %d", resp.Index, 1000)
   416  	}
   417  
   418  	if len(resp.Allocs) != 2 {
   419  		t.Fatalf("bad: %#v", resp.Allocs)
   420  	}
   421  
   422  	// Lookup nonexistent allocs.
   423  	get = &structs.AllocsGetRequest{
   424  		AllocIDs:     []string{"foo"},
   425  		QueryOptions: structs.QueryOptions{Region: "global"},
   426  	}
   427  	if err := msgpackrpc.CallWithCodec(codec, "Alloc.GetAllocs", get, &resp); err == nil {
   428  		t.Fatalf("expect error")
   429  	}
   430  }
   431  
   432  func TestAllocEndpoint_GetAllocs_Blocking(t *testing.T) {
   433  	t.Parallel()
   434  	s1 := TestServer(t, nil)
   435  	defer s1.Shutdown()
   436  	state := s1.fsm.State()
   437  	codec := rpcClient(t, s1)
   438  	testutil.WaitForLeader(t, s1.RPC)
   439  
   440  	// Create the allocs
   441  	alloc1 := mock.Alloc()
   442  	alloc2 := mock.Alloc()
   443  
   444  	// First create an unrelated alloc
   445  	time.AfterFunc(100*time.Millisecond, func() {
   446  		state.UpsertJobSummary(99, mock.JobSummary(alloc1.JobID))
   447  		err := state.UpsertAllocs(100, []*structs.Allocation{alloc1})
   448  		if err != nil {
   449  			t.Fatalf("err: %v", err)
   450  		}
   451  	})
   452  
   453  	// Create the alloc we are watching later
   454  	time.AfterFunc(200*time.Millisecond, func() {
   455  		state.UpsertJobSummary(199, mock.JobSummary(alloc2.JobID))
   456  		err := state.UpsertAllocs(200, []*structs.Allocation{alloc2})
   457  		if err != nil {
   458  			t.Fatalf("err: %v", err)
   459  		}
   460  	})
   461  
   462  	// Lookup the allocs
   463  	get := &structs.AllocsGetRequest{
   464  		AllocIDs: []string{alloc1.ID, alloc2.ID},
   465  		QueryOptions: structs.QueryOptions{
   466  			Region:        "global",
   467  			MinQueryIndex: 150,
   468  		},
   469  	}
   470  	var resp structs.AllocsGetResponse
   471  	start := time.Now()
   472  	if err := msgpackrpc.CallWithCodec(codec, "Alloc.GetAllocs", get, &resp); err != nil {
   473  		t.Fatalf("err: %v", err)
   474  	}
   475  
   476  	if elapsed := time.Since(start); elapsed < 200*time.Millisecond {
   477  		t.Fatalf("should block (returned in %s) %#v", elapsed, resp)
   478  	}
   479  	if resp.Index != 200 {
   480  		t.Fatalf("Bad index: %d %d", resp.Index, 200)
   481  	}
   482  	if len(resp.Allocs) != 2 {
   483  		t.Fatalf("bad: %#v", resp.Allocs)
   484  	}
   485  }
   486  
   487  func TestAllocEndpoint_UpdateDesiredTransition(t *testing.T) {
   488  	t.Parallel()
   489  	require := require.New(t)
   490  
   491  	s1, _ := TestACLServer(t, nil)
   492  	defer s1.Shutdown()
   493  	codec := rpcClient(t, s1)
   494  	testutil.WaitForLeader(t, s1.RPC)
   495  
   496  	// Create the register request
   497  	alloc := mock.Alloc()
   498  	alloc2 := mock.Alloc()
   499  	state := s1.fsm.State()
   500  	require.Nil(state.UpsertJobSummary(998, mock.JobSummary(alloc.JobID)))
   501  	require.Nil(state.UpsertJobSummary(999, mock.JobSummary(alloc2.JobID)))
   502  	require.Nil(state.UpsertAllocs(1000, []*structs.Allocation{alloc, alloc2}))
   503  
   504  	t1 := &structs.DesiredTransition{
   505  		Migrate: helper.BoolToPtr(true),
   506  	}
   507  
   508  	// Update the allocs desired status
   509  	get := &structs.AllocUpdateDesiredTransitionRequest{
   510  		Allocs: map[string]*structs.DesiredTransition{
   511  			alloc.ID:  t1,
   512  			alloc2.ID: t1,
   513  		},
   514  		Evals: []*structs.Evaluation{
   515  			{
   516  				ID:             uuid.Generate(),
   517  				Namespace:      alloc.Namespace,
   518  				Priority:       alloc.Job.Priority,
   519  				Type:           alloc.Job.Type,
   520  				TriggeredBy:    structs.EvalTriggerNodeDrain,
   521  				JobID:          alloc.Job.ID,
   522  				JobModifyIndex: alloc.Job.ModifyIndex,
   523  				Status:         structs.EvalStatusPending,
   524  			},
   525  			{
   526  				ID:             uuid.Generate(),
   527  				Namespace:      alloc2.Namespace,
   528  				Priority:       alloc2.Job.Priority,
   529  				Type:           alloc2.Job.Type,
   530  				TriggeredBy:    structs.EvalTriggerNodeDrain,
   531  				JobID:          alloc2.Job.ID,
   532  				JobModifyIndex: alloc2.Job.ModifyIndex,
   533  				Status:         structs.EvalStatusPending,
   534  			},
   535  		},
   536  		WriteRequest: structs.WriteRequest{
   537  			Region: "global",
   538  		},
   539  	}
   540  
   541  	// Try without permissions
   542  	var resp structs.GenericResponse
   543  	err := msgpackrpc.CallWithCodec(codec, "Alloc.UpdateDesiredTransition", get, &resp)
   544  	require.NotNil(err)
   545  	require.True(structs.IsErrPermissionDenied(err))
   546  
   547  	// Try with permissions
   548  	get.WriteRequest.AuthToken = s1.getLeaderAcl()
   549  	var resp2 structs.GenericResponse
   550  	require.Nil(msgpackrpc.CallWithCodec(codec, "Alloc.UpdateDesiredTransition", get, &resp2))
   551  	require.NotZero(resp2.Index)
   552  
   553  	// Look up the allocations
   554  	out1, err := state.AllocByID(nil, alloc.ID)
   555  	require.Nil(err)
   556  	out2, err := state.AllocByID(nil, alloc.ID)
   557  	require.Nil(err)
   558  	e1, err := state.EvalByID(nil, get.Evals[0].ID)
   559  	require.Nil(err)
   560  	e2, err := state.EvalByID(nil, get.Evals[1].ID)
   561  	require.Nil(err)
   562  
   563  	require.NotNil(out1.DesiredTransition.Migrate)
   564  	require.NotNil(out2.DesiredTransition.Migrate)
   565  	require.NotNil(e1)
   566  	require.NotNil(e2)
   567  	require.True(*out1.DesiredTransition.Migrate)
   568  	require.True(*out2.DesiredTransition.Migrate)
   569  }