github.com/hernad/nomad@v1.6.112/nomad/fsm_test.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package nomad
     5  
     6  import (
     7  	"bytes"
     8  	"context"
     9  	"fmt"
    10  	"reflect"
    11  	"strings"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/google/go-cmp/cmp"
    16  	"github.com/google/go-cmp/cmp/cmpopts"
    17  	memdb "github.com/hashicorp/go-memdb"
    18  	"github.com/hashicorp/raft"
    19  	"github.com/kr/pretty"
    20  	"github.com/shoenig/test/must"
    21  	"github.com/stretchr/testify/assert"
    22  	"github.com/stretchr/testify/require"
    23  
    24  	"github.com/hernad/nomad/ci"
    25  	"github.com/hernad/nomad/helper/pointer"
    26  	"github.com/hernad/nomad/helper/testlog"
    27  	"github.com/hernad/nomad/helper/uuid"
    28  	"github.com/hernad/nomad/nomad/mock"
    29  	"github.com/hernad/nomad/nomad/state"
    30  	"github.com/hernad/nomad/nomad/stream"
    31  	"github.com/hernad/nomad/nomad/structs"
    32  	"github.com/hernad/nomad/testutil"
    33  )
    34  
    35  type MockSink struct {
    36  	*bytes.Buffer
    37  	cancel bool
    38  }
    39  
    40  func (m *MockSink) ID() string {
    41  	return "Mock"
    42  }
    43  
    44  func (m *MockSink) Cancel() error {
    45  	m.cancel = true
    46  	return nil
    47  }
    48  
    49  func (m *MockSink) Close() error {
    50  	return nil
    51  }
    52  
    53  func testStateStore(t *testing.T) *state.StateStore {
    54  	return state.TestStateStore(t)
    55  }
    56  
    57  func testFSM(t *testing.T) *nomadFSM {
    58  	broker := testBroker(t, 0)
    59  	dispatcher, _ := testPeriodicDispatcher(t)
    60  	logger := testlog.HCLogger(t)
    61  	fsmConfig := &FSMConfig{
    62  		EvalBroker:        broker,
    63  		Periodic:          dispatcher,
    64  		Blocked:           NewBlockedEvals(broker, logger),
    65  		Logger:            logger,
    66  		Region:            "global",
    67  		EnableEventBroker: true,
    68  		EventBufferSize:   100,
    69  	}
    70  	fsm, err := NewFSM(fsmConfig)
    71  	if err != nil {
    72  		t.Fatalf("err: %v", err)
    73  	}
    74  	if fsm == nil {
    75  		t.Fatalf("missing fsm")
    76  	}
    77  	return fsm
    78  }
    79  
    80  func makeLog(buf []byte) *raft.Log {
    81  	return &raft.Log{
    82  		Index: 1,
    83  		Term:  1,
    84  		Type:  raft.LogCommand,
    85  		Data:  buf,
    86  	}
    87  }
    88  
    89  func TestFSM_UpsertNodeEvents(t *testing.T) {
    90  	ci.Parallel(t)
    91  	require := require.New(t)
    92  	fsm := testFSM(t)
    93  	state := fsm.State()
    94  
    95  	node := mock.Node()
    96  
    97  	err := state.UpsertNode(structs.MsgTypeTestSetup, 1000, node)
    98  	if err != nil {
    99  		t.Fatalf("err: %v", err)
   100  	}
   101  
   102  	nodeEvent := &structs.NodeEvent{
   103  		Message:   "Heartbeating failed",
   104  		Subsystem: "Heartbeat",
   105  		Timestamp: time.Now(),
   106  	}
   107  
   108  	nodeEvents := []*structs.NodeEvent{nodeEvent}
   109  	allEvents := map[string][]*structs.NodeEvent{node.ID: nodeEvents}
   110  
   111  	req := structs.EmitNodeEventsRequest{
   112  		NodeEvents:   allEvents,
   113  		WriteRequest: structs.WriteRequest{Region: "global"},
   114  	}
   115  	buf, err := structs.Encode(structs.UpsertNodeEventsType, req)
   116  	require.Nil(err)
   117  
   118  	// the response in this case will be an error
   119  	resp := fsm.Apply(makeLog(buf))
   120  	require.Nil(resp)
   121  
   122  	ws := memdb.NewWatchSet()
   123  	out, err := state.NodeByID(ws, node.ID)
   124  	require.Nil(err)
   125  
   126  	require.Equal(2, len(out.Events))
   127  
   128  	first := out.Events[1]
   129  	require.Equal(uint64(1), first.CreateIndex)
   130  	require.Equal("Heartbeating failed", first.Message)
   131  }
   132  
   133  func TestFSM_UpsertNode(t *testing.T) {
   134  	ci.Parallel(t)
   135  	fsm := testFSM(t)
   136  	fsm.blockedEvals.SetEnabled(true)
   137  
   138  	node := mock.Node()
   139  
   140  	// Mark an eval as blocked.
   141  	eval := mock.Eval()
   142  	eval.ClassEligibility = map[string]bool{node.ComputedClass: true}
   143  	fsm.blockedEvals.Block(eval)
   144  
   145  	req := structs.NodeRegisterRequest{
   146  		Node: node,
   147  	}
   148  	buf, err := structs.Encode(structs.NodeRegisterRequestType, req)
   149  	if err != nil {
   150  		t.Fatalf("err: %v", err)
   151  	}
   152  
   153  	resp := fsm.Apply(makeLog(buf))
   154  	if resp != nil {
   155  		t.Fatalf("resp: %v", resp)
   156  	}
   157  
   158  	// Verify we are registered
   159  	ws := memdb.NewWatchSet()
   160  	n, err := fsm.State().NodeByID(ws, req.Node.ID)
   161  	if err != nil {
   162  		t.Fatalf("err: %v", err)
   163  	}
   164  	if n == nil {
   165  		t.Fatalf("not found!")
   166  	}
   167  	if n.CreateIndex != 1 {
   168  		t.Fatalf("bad index: %d", node.CreateIndex)
   169  	}
   170  
   171  	tt := fsm.TimeTable()
   172  	index := tt.NearestIndex(time.Now().UTC())
   173  	if index != 1 {
   174  		t.Fatalf("bad: %d", index)
   175  	}
   176  
   177  	// Verify the eval was unblocked.
   178  	testutil.WaitForResult(func() (bool, error) {
   179  		bStats := fsm.blockedEvals.Stats()
   180  		if bStats.TotalBlocked != 0 {
   181  			return false, fmt.Errorf("bad: %#v", bStats)
   182  		}
   183  		return true, nil
   184  	}, func(err error) {
   185  		t.Fatalf("err: %s", err)
   186  	})
   187  
   188  }
   189  
   190  func TestFSM_UpsertNode_Canonicalize(t *testing.T) {
   191  	ci.Parallel(t)
   192  	require := require.New(t)
   193  
   194  	fsm := testFSM(t)
   195  	fsm.blockedEvals.SetEnabled(true)
   196  
   197  	// Setup a node without eligibility, ensure that upsert/canonicalize put it back
   198  	node := mock.Node()
   199  	node.SchedulingEligibility = ""
   200  
   201  	req := structs.NodeRegisterRequest{
   202  		Node: node,
   203  	}
   204  	buf, err := structs.Encode(structs.NodeRegisterRequestType, req)
   205  	require.Nil(err)
   206  
   207  	require.Nil(fsm.Apply(makeLog(buf)))
   208  
   209  	// Verify we are registered
   210  	n, err := fsm.State().NodeByID(nil, req.Node.ID)
   211  	require.Nil(err)
   212  	require.NotNil(n)
   213  	require.EqualValues(1, n.CreateIndex)
   214  	require.Equal(structs.NodeSchedulingEligible, n.SchedulingEligibility)
   215  }
   216  
   217  func TestFSM_UpsertNode_Canonicalize_Ineligible(t *testing.T) {
   218  	ci.Parallel(t)
   219  	require := require.New(t)
   220  
   221  	fsm := testFSM(t)
   222  	fsm.blockedEvals.SetEnabled(true)
   223  
   224  	// Setup a node without eligibility, ensure that upsert/canonicalize put it back
   225  	node := mock.DrainNode()
   226  	node.SchedulingEligibility = ""
   227  
   228  	req := structs.NodeRegisterRequest{
   229  		Node: node,
   230  	}
   231  	buf, err := structs.Encode(structs.NodeRegisterRequestType, req)
   232  	require.Nil(err)
   233  
   234  	require.Nil(fsm.Apply(makeLog(buf)))
   235  
   236  	// Verify we are registered
   237  	n, err := fsm.State().NodeByID(nil, req.Node.ID)
   238  	require.Nil(err)
   239  	require.NotNil(n)
   240  	require.EqualValues(1, n.CreateIndex)
   241  	require.Equal(structs.NodeSchedulingIneligible, n.SchedulingEligibility)
   242  }
   243  
   244  func TestFSM_UpsertNode_NodePool(t *testing.T) {
   245  	ci.Parallel(t)
   246  
   247  	testCases := []struct {
   248  		name       string
   249  		setupReqFn func(*structs.NodeRegisterRequest)
   250  		validateFn func(*testing.T, *structs.Node, *structs.NodePool)
   251  	}{
   252  		{
   253  			name: "node with empty node pool is placed in defualt",
   254  			setupReqFn: func(req *structs.NodeRegisterRequest) {
   255  				req.Node.NodePool = ""
   256  			},
   257  			validateFn: func(t *testing.T, node *structs.Node, pool *structs.NodePool) {
   258  				must.Eq(t, structs.NodePoolDefault, node.NodePool)
   259  				must.Eq(t, 1, pool.ModifyIndex)
   260  			},
   261  		},
   262  		{
   263  			name: "create new node pool with node",
   264  			setupReqFn: func(req *structs.NodeRegisterRequest) {
   265  				req.Node.NodePool = "new"
   266  				req.CreateNodePool = true
   267  			},
   268  			validateFn: func(t *testing.T, node *structs.Node, pool *structs.NodePool) {
   269  				must.NotNil(t, pool)
   270  				must.Eq(t, "new", pool.Name)
   271  				must.Eq(t, pool.Name, node.NodePool)
   272  				must.Eq(t, node.ModifyIndex, pool.CreateIndex)
   273  			},
   274  		},
   275  		{
   276  			name: "don't create new node pool with node",
   277  			setupReqFn: func(req *structs.NodeRegisterRequest) {
   278  				req.Node.NodePool = "new"
   279  				req.CreateNodePool = false
   280  			},
   281  			validateFn: func(t *testing.T, node *structs.Node, pool *structs.NodePool) {
   282  				must.Nil(t, pool)
   283  				must.Eq(t, "new", node.NodePool)
   284  			},
   285  		},
   286  	}
   287  
   288  	for _, tc := range testCases {
   289  		t.Run(tc.name, func(t *testing.T) {
   290  			fsm := testFSM(t)
   291  
   292  			node := mock.Node()
   293  			req := structs.NodeRegisterRequest{
   294  				Node: node,
   295  			}
   296  			if tc.setupReqFn != nil {
   297  				tc.setupReqFn(&req)
   298  			}
   299  			buf, err := structs.Encode(structs.NodeRegisterRequestType, req)
   300  			must.NoError(t, err)
   301  
   302  			resp := fsm.Apply(makeLog(buf))
   303  			must.Nil(t, resp)
   304  
   305  			// Snapshot the state.
   306  			s := fsm.State()
   307  
   308  			gotNode, err := s.NodeByID(nil, node.ID)
   309  			must.NoError(t, err)
   310  
   311  			gotPool, err := s.NodePoolByName(nil, gotNode.NodePool)
   312  			must.NoError(t, err)
   313  
   314  			if tc.validateFn != nil {
   315  				tc.validateFn(t, gotNode, gotPool)
   316  			}
   317  		})
   318  	}
   319  }
   320  
   321  func TestFSM_DeregisterNode(t *testing.T) {
   322  	ci.Parallel(t)
   323  	fsm := testFSM(t)
   324  
   325  	node := mock.Node()
   326  	req := structs.NodeRegisterRequest{
   327  		Node: node,
   328  	}
   329  	buf, err := structs.Encode(structs.NodeRegisterRequestType, req)
   330  	if err != nil {
   331  		t.Fatalf("err: %v", err)
   332  	}
   333  
   334  	resp := fsm.Apply(makeLog(buf))
   335  	if resp != nil {
   336  		t.Fatalf("resp: %v", resp)
   337  	}
   338  
   339  	req2 := structs.NodeBatchDeregisterRequest{
   340  		NodeIDs: []string{node.ID},
   341  	}
   342  	buf, err = structs.Encode(structs.NodeBatchDeregisterRequestType, req2)
   343  	if err != nil {
   344  		t.Fatalf("err: %v", err)
   345  	}
   346  
   347  	resp = fsm.Apply(makeLog(buf))
   348  	if resp != nil {
   349  		t.Fatalf("resp: %v", resp)
   350  	}
   351  
   352  	// Verify we are NOT registered
   353  	ws := memdb.NewWatchSet()
   354  	node, err = fsm.State().NodeByID(ws, req.Node.ID)
   355  	if err != nil {
   356  		t.Fatalf("err: %v", err)
   357  	}
   358  	if node != nil {
   359  		t.Fatalf("node found!")
   360  	}
   361  }
   362  
   363  func TestFSM_UpdateNodeStatus(t *testing.T) {
   364  	ci.Parallel(t)
   365  	require := require.New(t)
   366  	fsm := testFSM(t)
   367  	fsm.blockedEvals.SetEnabled(true)
   368  
   369  	node := mock.Node()
   370  	req := structs.NodeRegisterRequest{
   371  		Node: node,
   372  	}
   373  	buf, err := structs.Encode(structs.NodeRegisterRequestType, req)
   374  	require.NoError(err)
   375  
   376  	resp := fsm.Apply(makeLog(buf))
   377  	require.Nil(resp)
   378  
   379  	// Mark an eval as blocked.
   380  	eval := mock.Eval()
   381  	eval.ClassEligibility = map[string]bool{node.ComputedClass: true}
   382  	fsm.blockedEvals.Block(eval)
   383  
   384  	event := &structs.NodeEvent{
   385  		Message:   "Node ready foo",
   386  		Subsystem: structs.NodeEventSubsystemCluster,
   387  		Timestamp: time.Now(),
   388  	}
   389  	req2 := structs.NodeUpdateStatusRequest{
   390  		NodeID:    node.ID,
   391  		Status:    structs.NodeStatusReady,
   392  		NodeEvent: event,
   393  	}
   394  	buf, err = structs.Encode(structs.NodeUpdateStatusRequestType, req2)
   395  	require.NoError(err)
   396  
   397  	resp = fsm.Apply(makeLog(buf))
   398  	require.Nil(resp)
   399  
   400  	// Verify the status is ready.
   401  	ws := memdb.NewWatchSet()
   402  	node, err = fsm.State().NodeByID(ws, req.Node.ID)
   403  	require.NoError(err)
   404  	require.Equal(structs.NodeStatusReady, node.Status)
   405  	require.Len(node.Events, 2)
   406  	require.Equal(event.Message, node.Events[1].Message)
   407  
   408  	// Verify the eval was unblocked.
   409  	testutil.WaitForResult(func() (bool, error) {
   410  		bStats := fsm.blockedEvals.Stats()
   411  		if bStats.TotalBlocked != 0 {
   412  			return false, fmt.Errorf("bad: %#v", bStats)
   413  		}
   414  		return true, nil
   415  	}, func(err error) {
   416  		t.Fatalf("err: %s", err)
   417  	})
   418  }
   419  
   420  func TestFSM_BatchUpdateNodeDrain(t *testing.T) {
   421  	ci.Parallel(t)
   422  	require := require.New(t)
   423  	fsm := testFSM(t)
   424  
   425  	node := mock.Node()
   426  	req := structs.NodeRegisterRequest{
   427  		Node: node,
   428  	}
   429  	buf, err := structs.Encode(structs.NodeRegisterRequestType, req)
   430  	require.Nil(err)
   431  
   432  	resp := fsm.Apply(makeLog(buf))
   433  	require.Nil(resp)
   434  
   435  	strategy := &structs.DrainStrategy{
   436  		DrainSpec: structs.DrainSpec{
   437  			Deadline: 10 * time.Second,
   438  		},
   439  	}
   440  	event := &structs.NodeEvent{
   441  		Message:   "Drain strategy enabled",
   442  		Subsystem: structs.NodeEventSubsystemDrain,
   443  		Timestamp: time.Now(),
   444  	}
   445  	req2 := structs.BatchNodeUpdateDrainRequest{
   446  		Updates: map[string]*structs.DrainUpdate{
   447  			node.ID: {
   448  				DrainStrategy: strategy,
   449  			},
   450  		},
   451  		NodeEvents: map[string]*structs.NodeEvent{
   452  			node.ID: event,
   453  		},
   454  	}
   455  	buf, err = structs.Encode(structs.BatchNodeUpdateDrainRequestType, req2)
   456  	require.Nil(err)
   457  
   458  	resp = fsm.Apply(makeLog(buf))
   459  	require.Nil(resp)
   460  
   461  	// Verify drain is set
   462  	ws := memdb.NewWatchSet()
   463  	node, err = fsm.State().NodeByID(ws, req.Node.ID)
   464  	require.Nil(err)
   465  	require.Equal(node.DrainStrategy, strategy)
   466  	require.Len(node.Events, 2)
   467  }
   468  
   469  func TestFSM_UpdateNodeDrain(t *testing.T) {
   470  	ci.Parallel(t)
   471  	require := require.New(t)
   472  	fsm := testFSM(t)
   473  
   474  	node := mock.Node()
   475  	req := structs.NodeRegisterRequest{
   476  		Node: node,
   477  	}
   478  	buf, err := structs.Encode(structs.NodeRegisterRequestType, req)
   479  	require.Nil(err)
   480  
   481  	resp := fsm.Apply(makeLog(buf))
   482  	require.Nil(resp)
   483  
   484  	strategy := &structs.DrainStrategy{
   485  		DrainSpec: structs.DrainSpec{
   486  			Deadline: 10 * time.Second,
   487  		},
   488  	}
   489  	req2 := structs.NodeUpdateDrainRequest{
   490  		NodeID:        node.ID,
   491  		DrainStrategy: strategy,
   492  		NodeEvent: &structs.NodeEvent{
   493  			Message:   "Drain strategy enabled",
   494  			Subsystem: structs.NodeEventSubsystemDrain,
   495  			Timestamp: time.Now(),
   496  		},
   497  	}
   498  	buf, err = structs.Encode(structs.NodeUpdateDrainRequestType, req2)
   499  	require.Nil(err)
   500  
   501  	resp = fsm.Apply(makeLog(buf))
   502  	require.Nil(resp)
   503  
   504  	// Verify we are NOT registered
   505  	ws := memdb.NewWatchSet()
   506  	node, err = fsm.State().NodeByID(ws, req.Node.ID)
   507  	require.Nil(err)
   508  	require.Equal(node.DrainStrategy, strategy)
   509  	require.Len(node.Events, 2)
   510  }
   511  
   512  func TestFSM_UpdateNodeEligibility(t *testing.T) {
   513  	ci.Parallel(t)
   514  	require := require.New(t)
   515  	fsm := testFSM(t)
   516  
   517  	node := mock.Node()
   518  	req := structs.NodeRegisterRequest{
   519  		Node: node,
   520  	}
   521  	buf, err := structs.Encode(structs.NodeRegisterRequestType, req)
   522  	require.Nil(err)
   523  
   524  	resp := fsm.Apply(makeLog(buf))
   525  	require.Nil(resp)
   526  
   527  	event := &structs.NodeEvent{
   528  		Message:   "Node marked as ineligible",
   529  		Subsystem: structs.NodeEventSubsystemCluster,
   530  		Timestamp: time.Now(),
   531  	}
   532  
   533  	// Set the eligibility
   534  	req2 := structs.NodeUpdateEligibilityRequest{
   535  		NodeID:      node.ID,
   536  		Eligibility: structs.NodeSchedulingIneligible,
   537  		NodeEvent:   event,
   538  	}
   539  	buf, err = structs.Encode(structs.NodeUpdateEligibilityRequestType, req2)
   540  	require.Nil(err)
   541  
   542  	resp = fsm.Apply(makeLog(buf))
   543  	require.Nil(resp)
   544  
   545  	// Lookup the node and check
   546  	node, err = fsm.State().NodeByID(nil, req.Node.ID)
   547  	require.Nil(err)
   548  	require.Equal(node.SchedulingEligibility, structs.NodeSchedulingIneligible)
   549  	require.Len(node.Events, 2)
   550  	require.Equal(event.Message, node.Events[1].Message)
   551  
   552  	// Update the drain
   553  	strategy := &structs.DrainStrategy{
   554  		DrainSpec: structs.DrainSpec{
   555  			Deadline: 10 * time.Second,
   556  		},
   557  	}
   558  	req3 := structs.NodeUpdateDrainRequest{
   559  		NodeID:        node.ID,
   560  		DrainStrategy: strategy,
   561  	}
   562  	buf, err = structs.Encode(structs.NodeUpdateDrainRequestType, req3)
   563  	require.Nil(err)
   564  	resp = fsm.Apply(makeLog(buf))
   565  	require.Nil(resp)
   566  
   567  	// Try forcing eligibility
   568  	req4 := structs.NodeUpdateEligibilityRequest{
   569  		NodeID:      node.ID,
   570  		Eligibility: structs.NodeSchedulingEligible,
   571  	}
   572  	buf, err = structs.Encode(structs.NodeUpdateEligibilityRequestType, req4)
   573  	require.Nil(err)
   574  
   575  	resp = fsm.Apply(makeLog(buf))
   576  	require.NotNil(resp)
   577  	err, ok := resp.(error)
   578  	require.True(ok)
   579  	require.Contains(err.Error(), "draining")
   580  }
   581  
   582  func TestFSM_UpdateNodeEligibility_Unblock(t *testing.T) {
   583  	ci.Parallel(t)
   584  	require := require.New(t)
   585  	fsm := testFSM(t)
   586  
   587  	node := mock.Node()
   588  	req := structs.NodeRegisterRequest{
   589  		Node: node,
   590  	}
   591  	buf, err := structs.Encode(structs.NodeRegisterRequestType, req)
   592  	require.Nil(err)
   593  
   594  	resp := fsm.Apply(makeLog(buf))
   595  	require.Nil(resp)
   596  
   597  	// Set the eligibility
   598  	req2 := structs.NodeUpdateEligibilityRequest{
   599  		NodeID:      node.ID,
   600  		Eligibility: structs.NodeSchedulingIneligible,
   601  	}
   602  	buf, err = structs.Encode(structs.NodeUpdateEligibilityRequestType, req2)
   603  	require.Nil(err)
   604  
   605  	resp = fsm.Apply(makeLog(buf))
   606  	require.Nil(resp)
   607  
   608  	// Mark an eval as blocked.
   609  	eval := mock.Eval()
   610  	eval.ClassEligibility = map[string]bool{node.ComputedClass: true}
   611  	fsm.blockedEvals.Block(eval)
   612  
   613  	// Set eligible
   614  	req4 := structs.NodeUpdateEligibilityRequest{
   615  		NodeID:      node.ID,
   616  		Eligibility: structs.NodeSchedulingEligible,
   617  	}
   618  	buf, err = structs.Encode(structs.NodeUpdateEligibilityRequestType, req4)
   619  	require.Nil(err)
   620  
   621  	resp = fsm.Apply(makeLog(buf))
   622  	require.Nil(resp)
   623  
   624  	// Verify the eval was unblocked.
   625  	testutil.WaitForResult(func() (bool, error) {
   626  		bStats := fsm.blockedEvals.Stats()
   627  		if bStats.TotalBlocked != 0 {
   628  			return false, fmt.Errorf("bad: %#v", bStats)
   629  		}
   630  		return true, nil
   631  	}, func(err error) {
   632  		t.Fatalf("err: %s", err)
   633  	})
   634  }
   635  
   636  func TestFSM_NodePoolDelete(t *testing.T) {
   637  	ci.Parallel(t)
   638  
   639  	// Create FSM and populate state.
   640  	fsm := testFSM(t)
   641  	pools := []*structs.NodePool{
   642  		mock.NodePool(),
   643  		mock.NodePool(),
   644  		mock.NodePool(),
   645  		mock.NodePool(),
   646  	}
   647  	err := fsm.State().UpsertNodePools(structs.MsgTypeTestSetup, 1000, pools)
   648  	must.NoError(t, err)
   649  
   650  	// Delete some of the node pools.
   651  	req := structs.NodePoolDeleteRequest{
   652  		Names: []string{pools[0].Name, pools[1].Name},
   653  	}
   654  	buf, err := structs.Encode(structs.NodePoolDeleteRequestType, req)
   655  	must.NoError(t, err)
   656  
   657  	resp := fsm.Apply(makeLog(buf))
   658  	must.Nil(t, resp)
   659  
   660  	// Verify selected node pools were deleted.
   661  	ws := memdb.NewWatchSet()
   662  	for i, pool := range pools {
   663  		got, err := fsm.State().NodePoolByName(ws, pool.Name)
   664  		must.NoError(t, err)
   665  
   666  		switch i {
   667  		// Node pools 0 and 1 were deleted.
   668  		case 0, 1:
   669  			must.Nil(t, got)
   670  		default:
   671  			must.NotNil(t, got)
   672  		}
   673  	}
   674  }
   675  
   676  func TestFSM_NodePoolUpsert(t *testing.T) {
   677  	ci.Parallel(t)
   678  
   679  	// Create FSM and create some node pools.
   680  	fsm := testFSM(t)
   681  	pools := []*structs.NodePool{
   682  		mock.NodePool(),
   683  		mock.NodePool(),
   684  		mock.NodePool(),
   685  	}
   686  	req := structs.NodePoolUpsertRequest{
   687  		NodePools: pools,
   688  	}
   689  	buf, err := structs.Encode(structs.NodePoolUpsertRequestType, req)
   690  	must.NoError(t, err)
   691  
   692  	resp := fsm.Apply(makeLog(buf))
   693  	must.Nil(t, resp)
   694  
   695  	// Verify node pools were created.
   696  	ws := memdb.NewWatchSet()
   697  	for _, pool := range pools {
   698  		got, err := fsm.State().NodePoolByName(ws, pool.Name)
   699  
   700  		must.NoError(t, err)
   701  		must.Eq(t, pool, got, must.Cmp(cmpopts.IgnoreFields(
   702  			structs.NodePool{},
   703  			"CreateIndex",
   704  			"ModifyIndex",
   705  		)))
   706  	}
   707  
   708  	// Update one of the node pools.
   709  	updatedPool := pools[0].Copy()
   710  	updatedPool.Description = "updated"
   711  	updatedPool.Meta = map[string]string{
   712  		"update": "true",
   713  	}
   714  
   715  	req = structs.NodePoolUpsertRequest{
   716  		NodePools: []*structs.NodePool{updatedPool},
   717  	}
   718  	buf, err = structs.Encode(structs.NodePoolUpsertRequestType, req)
   719  	must.NoError(t, err)
   720  
   721  	resp = fsm.Apply(makeLog(buf))
   722  	must.Nil(t, resp)
   723  
   724  	// Verify node pool was updated.
   725  	ws = memdb.NewWatchSet()
   726  	got, err := fsm.State().NodePoolByName(ws, updatedPool.Name)
   727  	must.NoError(t, err)
   728  	must.Eq(t, updatedPool, got, must.Cmp(cmpopts.IgnoreFields(
   729  		structs.NodePool{},
   730  		"CreateIndex",
   731  		"ModifyIndex",
   732  	)))
   733  }
   734  
   735  func TestFSM_RegisterJob(t *testing.T) {
   736  	ci.Parallel(t)
   737  	fsm := testFSM(t)
   738  
   739  	job := mock.PeriodicJob()
   740  	req := structs.JobRegisterRequest{
   741  		Job: job,
   742  		WriteRequest: structs.WriteRequest{
   743  			Namespace: job.Namespace,
   744  		},
   745  	}
   746  	buf, err := structs.Encode(structs.JobRegisterRequestType, req)
   747  	if err != nil {
   748  		t.Fatalf("err: %v", err)
   749  	}
   750  
   751  	resp := fsm.Apply(makeLog(buf))
   752  	if resp != nil {
   753  		t.Fatalf("resp: %v", resp)
   754  	}
   755  
   756  	// Verify we are registered
   757  	ws := memdb.NewWatchSet()
   758  	jobOut, err := fsm.State().JobByID(ws, req.Namespace, req.Job.ID)
   759  	if err != nil {
   760  		t.Fatalf("err: %v", err)
   761  	}
   762  	if jobOut == nil {
   763  		t.Fatalf("not found!")
   764  	}
   765  	if jobOut.CreateIndex != 1 {
   766  		t.Fatalf("bad index: %d", jobOut.CreateIndex)
   767  	}
   768  
   769  	// Verify it was added to the periodic runner.
   770  	tuple := structs.NamespacedID{
   771  		ID:        job.ID,
   772  		Namespace: job.Namespace,
   773  	}
   774  	if _, ok := fsm.periodicDispatcher.tracked[tuple]; !ok {
   775  		t.Fatal("job not added to periodic runner")
   776  	}
   777  
   778  	// Verify the launch time was tracked.
   779  	launchOut, err := fsm.State().PeriodicLaunchByID(ws, req.Namespace, req.Job.ID)
   780  	if err != nil {
   781  		t.Fatalf("err: %v", err)
   782  	}
   783  	if launchOut == nil {
   784  		t.Fatalf("not found!")
   785  	}
   786  	if launchOut.Launch.IsZero() {
   787  		t.Fatalf("bad launch time: %v", launchOut.Launch)
   788  	}
   789  }
   790  
   791  func TestFSM_RegisterPeriodicJob_NonLeader(t *testing.T) {
   792  	ci.Parallel(t)
   793  	fsm := testFSM(t)
   794  
   795  	// Disable the dispatcher
   796  	fsm.periodicDispatcher.SetEnabled(false)
   797  
   798  	job := mock.PeriodicJob()
   799  	req := structs.JobRegisterRequest{
   800  		Job: job,
   801  		WriteRequest: structs.WriteRequest{
   802  			Namespace: job.Namespace,
   803  		},
   804  	}
   805  	buf, err := structs.Encode(structs.JobRegisterRequestType, req)
   806  	if err != nil {
   807  		t.Fatalf("err: %v", err)
   808  	}
   809  
   810  	resp := fsm.Apply(makeLog(buf))
   811  	if resp != nil {
   812  		t.Fatalf("resp: %v", resp)
   813  	}
   814  
   815  	// Verify we are registered
   816  	ws := memdb.NewWatchSet()
   817  	jobOut, err := fsm.State().JobByID(ws, req.Namespace, req.Job.ID)
   818  	if err != nil {
   819  		t.Fatalf("err: %v", err)
   820  	}
   821  	if jobOut == nil {
   822  		t.Fatalf("not found!")
   823  	}
   824  	if jobOut.CreateIndex != 1 {
   825  		t.Fatalf("bad index: %d", jobOut.CreateIndex)
   826  	}
   827  
   828  	// Verify it wasn't added to the periodic runner.
   829  	tuple := structs.NamespacedID{
   830  		ID:        job.ID,
   831  		Namespace: job.Namespace,
   832  	}
   833  	if _, ok := fsm.periodicDispatcher.tracked[tuple]; ok {
   834  		t.Fatal("job added to periodic runner")
   835  	}
   836  
   837  	// Verify the launch time was tracked.
   838  	launchOut, err := fsm.State().PeriodicLaunchByID(ws, req.Namespace, req.Job.ID)
   839  	if err != nil {
   840  		t.Fatalf("err: %v", err)
   841  	}
   842  	if launchOut == nil {
   843  		t.Fatalf("not found!")
   844  	}
   845  	if launchOut.Launch.IsZero() {
   846  		t.Fatalf("bad launch time: %v", launchOut.Launch)
   847  	}
   848  }
   849  
   850  func TestFSM_RegisterJob_BadNamespace(t *testing.T) {
   851  	ci.Parallel(t)
   852  	fsm := testFSM(t)
   853  
   854  	job := mock.Job()
   855  	job.Namespace = "foo"
   856  	req := structs.JobRegisterRequest{
   857  		Job: job,
   858  		WriteRequest: structs.WriteRequest{
   859  			Namespace: job.Namespace,
   860  		},
   861  	}
   862  	buf, err := structs.Encode(structs.JobRegisterRequestType, req)
   863  	if err != nil {
   864  		t.Fatalf("err: %v", err)
   865  	}
   866  
   867  	resp := fsm.Apply(makeLog(buf))
   868  	if resp == nil {
   869  		t.Fatalf("no resp: %v", resp)
   870  	}
   871  	err, ok := resp.(error)
   872  	if !ok {
   873  		t.Fatalf("resp not of error type: %T %v", resp, resp)
   874  	}
   875  	if !strings.Contains(err.Error(), "nonexistent namespace") {
   876  		t.Fatalf("bad error: %v", err)
   877  	}
   878  
   879  	// Verify we are not registered
   880  	ws := memdb.NewWatchSet()
   881  	jobOut, err := fsm.State().JobByID(ws, req.Namespace, req.Job.ID)
   882  	if err != nil {
   883  		t.Fatalf("err: %v", err)
   884  	}
   885  	if jobOut != nil {
   886  		t.Fatalf("job found!")
   887  	}
   888  }
   889  
   890  func TestFSM_DeregisterJob_Error(t *testing.T) {
   891  	ci.Parallel(t)
   892  	fsm := testFSM(t)
   893  
   894  	job := mock.Job()
   895  
   896  	deregReq := structs.JobDeregisterRequest{
   897  		JobID: job.ID,
   898  		Purge: true,
   899  		WriteRequest: structs.WriteRequest{
   900  			Namespace: job.Namespace,
   901  		},
   902  	}
   903  	buf, err := structs.Encode(structs.JobDeregisterRequestType, deregReq)
   904  	require.NoError(t, err)
   905  
   906  	resp := fsm.Apply(makeLog(buf))
   907  	require.NotNil(t, resp)
   908  	respErr, ok := resp.(error)
   909  	require.Truef(t, ok, "expected response to be an error but found: %T", resp)
   910  	require.Error(t, respErr)
   911  }
   912  
   913  func TestFSM_DeregisterJob_Purge(t *testing.T) {
   914  	ci.Parallel(t)
   915  	fsm := testFSM(t)
   916  
   917  	job := mock.PeriodicJob()
   918  	req := structs.JobRegisterRequest{
   919  		Job: job,
   920  		WriteRequest: structs.WriteRequest{
   921  			Namespace: job.Namespace,
   922  		},
   923  	}
   924  	buf, err := structs.Encode(structs.JobRegisterRequestType, req)
   925  	if err != nil {
   926  		t.Fatalf("err: %v", err)
   927  	}
   928  
   929  	resp := fsm.Apply(makeLog(buf))
   930  	if resp != nil {
   931  		t.Fatalf("resp: %v", resp)
   932  	}
   933  
   934  	req2 := structs.JobDeregisterRequest{
   935  		JobID: job.ID,
   936  		Purge: true,
   937  		WriteRequest: structs.WriteRequest{
   938  			Namespace: job.Namespace,
   939  		},
   940  	}
   941  	buf, err = structs.Encode(structs.JobDeregisterRequestType, req2)
   942  	if err != nil {
   943  		t.Fatalf("err: %v", err)
   944  	}
   945  
   946  	resp = fsm.Apply(makeLog(buf))
   947  	if resp != nil {
   948  		t.Fatalf("resp: %v", resp)
   949  	}
   950  
   951  	// Verify we are NOT registered
   952  	ws := memdb.NewWatchSet()
   953  	jobOut, err := fsm.State().JobByID(ws, req.Namespace, req.Job.ID)
   954  	if err != nil {
   955  		t.Fatalf("err: %v", err)
   956  	}
   957  	if jobOut != nil {
   958  		t.Fatalf("job found!")
   959  	}
   960  
   961  	// Verify it was removed from the periodic runner.
   962  	tuple := structs.NamespacedID{
   963  		ID:        job.ID,
   964  		Namespace: job.Namespace,
   965  	}
   966  	if _, ok := fsm.periodicDispatcher.tracked[tuple]; ok {
   967  		t.Fatal("job not removed from periodic runner")
   968  	}
   969  
   970  	// Verify it was removed from the periodic launch table.
   971  	launchOut, err := fsm.State().PeriodicLaunchByID(ws, req.Namespace, req.Job.ID)
   972  	if err != nil {
   973  		t.Fatalf("err: %v", err)
   974  	}
   975  	if launchOut != nil {
   976  		t.Fatalf("launch found!")
   977  	}
   978  }
   979  
   980  func TestFSM_DeregisterJob_NoPurge(t *testing.T) {
   981  	ci.Parallel(t)
   982  	fsm := testFSM(t)
   983  
   984  	job := mock.PeriodicJob()
   985  	req := structs.JobRegisterRequest{
   986  		Job: job,
   987  		WriteRequest: structs.WriteRequest{
   988  			Namespace: job.Namespace,
   989  		},
   990  	}
   991  	buf, err := structs.Encode(structs.JobRegisterRequestType, req)
   992  	if err != nil {
   993  		t.Fatalf("err: %v", err)
   994  	}
   995  
   996  	resp := fsm.Apply(makeLog(buf))
   997  	if resp != nil {
   998  		t.Fatalf("resp: %v", resp)
   999  	}
  1000  
  1001  	req2 := structs.JobDeregisterRequest{
  1002  		JobID: job.ID,
  1003  		Purge: false,
  1004  		WriteRequest: structs.WriteRequest{
  1005  			Namespace: job.Namespace,
  1006  		},
  1007  	}
  1008  	buf, err = structs.Encode(structs.JobDeregisterRequestType, req2)
  1009  	if err != nil {
  1010  		t.Fatalf("err: %v", err)
  1011  	}
  1012  
  1013  	resp = fsm.Apply(makeLog(buf))
  1014  	if resp != nil {
  1015  		t.Fatalf("resp: %v", resp)
  1016  	}
  1017  
  1018  	// Verify we are NOT registered
  1019  	ws := memdb.NewWatchSet()
  1020  	jobOut, err := fsm.State().JobByID(ws, req.Namespace, req.Job.ID)
  1021  	if err != nil {
  1022  		t.Fatalf("err: %v", err)
  1023  	}
  1024  	if jobOut == nil {
  1025  		t.Fatalf("job not found!")
  1026  	}
  1027  	if !jobOut.Stop {
  1028  		t.Fatalf("job not stopped found!")
  1029  	}
  1030  
  1031  	// Verify it was removed from the periodic runner.
  1032  	tuple := structs.NamespacedID{
  1033  		ID:        job.ID,
  1034  		Namespace: job.Namespace,
  1035  	}
  1036  	if _, ok := fsm.periodicDispatcher.tracked[tuple]; ok {
  1037  		t.Fatal("job not removed from periodic runner")
  1038  	}
  1039  
  1040  	// Verify it was removed from the periodic launch table.
  1041  	launchOut, err := fsm.State().PeriodicLaunchByID(ws, req.Namespace, req.Job.ID)
  1042  	if err != nil {
  1043  		t.Fatalf("err: %v", err)
  1044  	}
  1045  	if launchOut == nil {
  1046  		t.Fatalf("launch not found!")
  1047  	}
  1048  }
  1049  
  1050  func TestFSM_BatchDeregisterJob(t *testing.T) {
  1051  	ci.Parallel(t)
  1052  	require := require.New(t)
  1053  	fsm := testFSM(t)
  1054  
  1055  	job := mock.PeriodicJob()
  1056  	req := structs.JobRegisterRequest{
  1057  		Job: job,
  1058  		WriteRequest: structs.WriteRequest{
  1059  			Namespace: job.Namespace,
  1060  		},
  1061  	}
  1062  	buf, err := structs.Encode(structs.JobRegisterRequestType, req)
  1063  	require.Nil(err)
  1064  	resp := fsm.Apply(makeLog(buf))
  1065  	require.Nil(resp)
  1066  
  1067  	job2 := mock.Job()
  1068  	req2 := structs.JobRegisterRequest{
  1069  		Job: job2,
  1070  		WriteRequest: structs.WriteRequest{
  1071  			Namespace: job2.Namespace,
  1072  		},
  1073  	}
  1074  
  1075  	buf, err = structs.Encode(structs.JobRegisterRequestType, req2)
  1076  	require.Nil(err)
  1077  	resp = fsm.Apply(makeLog(buf))
  1078  	require.Nil(resp)
  1079  
  1080  	req3 := structs.JobBatchDeregisterRequest{
  1081  		Jobs: map[structs.NamespacedID]*structs.JobDeregisterOptions{
  1082  			{
  1083  				ID:        job.ID,
  1084  				Namespace: job.Namespace,
  1085  			}: {},
  1086  			{
  1087  				ID:        job2.ID,
  1088  				Namespace: job2.Namespace,
  1089  			}: {
  1090  				Purge: true,
  1091  			},
  1092  		},
  1093  		WriteRequest: structs.WriteRequest{
  1094  			Namespace: job.Namespace,
  1095  		},
  1096  	}
  1097  	buf, err = structs.Encode(structs.JobBatchDeregisterRequestType, req3)
  1098  	require.Nil(err)
  1099  
  1100  	resp = fsm.Apply(makeLog(buf))
  1101  	require.Nil(resp)
  1102  
  1103  	// Verify we are NOT registered
  1104  	ws := memdb.NewWatchSet()
  1105  	jobOut, err := fsm.State().JobByID(ws, req.Namespace, req.Job.ID)
  1106  	require.Nil(err)
  1107  	require.NotNil(jobOut)
  1108  	require.True(jobOut.Stop)
  1109  
  1110  	// Verify it was removed from the periodic runner.
  1111  	tuple := structs.NamespacedID{
  1112  		ID:        job.ID,
  1113  		Namespace: job.Namespace,
  1114  	}
  1115  	require.NotContains(fsm.periodicDispatcher.tracked, tuple)
  1116  
  1117  	// Verify it was not removed from the periodic launch table.
  1118  	launchOut, err := fsm.State().PeriodicLaunchByID(ws, job.Namespace, job.ID)
  1119  	require.Nil(err)
  1120  	require.NotNil(launchOut)
  1121  
  1122  	// Verify the other jbo was purged
  1123  	jobOut2, err := fsm.State().JobByID(ws, job2.Namespace, job2.ID)
  1124  	require.Nil(err)
  1125  	require.Nil(jobOut2)
  1126  }
  1127  
  1128  func TestFSM_UpdateEval(t *testing.T) {
  1129  	ci.Parallel(t)
  1130  	fsm := testFSM(t)
  1131  	fsm.evalBroker.SetEnabled(true)
  1132  
  1133  	req := structs.EvalUpdateRequest{
  1134  		Evals: []*structs.Evaluation{mock.Eval()},
  1135  	}
  1136  	buf, err := structs.Encode(structs.EvalUpdateRequestType, req)
  1137  	if err != nil {
  1138  		t.Fatalf("err: %v", err)
  1139  	}
  1140  
  1141  	resp := fsm.Apply(makeLog(buf))
  1142  	if resp != nil {
  1143  		t.Fatalf("resp: %v", resp)
  1144  	}
  1145  
  1146  	// Verify we are registered
  1147  	ws := memdb.NewWatchSet()
  1148  	eval, err := fsm.State().EvalByID(ws, req.Evals[0].ID)
  1149  	if err != nil {
  1150  		t.Fatalf("err: %v", err)
  1151  	}
  1152  	if eval == nil {
  1153  		t.Fatalf("not found!")
  1154  	}
  1155  	if eval.CreateIndex != 1 {
  1156  		t.Fatalf("bad index: %d", eval.CreateIndex)
  1157  	}
  1158  
  1159  	// Verify enqueued
  1160  	stats := fsm.evalBroker.Stats()
  1161  	if stats.TotalReady != 1 {
  1162  		t.Fatalf("bad: %#v %#v", stats, eval)
  1163  	}
  1164  }
  1165  
  1166  func TestFSM_UpdateEval_Blocked(t *testing.T) {
  1167  	ci.Parallel(t)
  1168  	fsm := testFSM(t)
  1169  	fsm.evalBroker.SetEnabled(true)
  1170  	fsm.blockedEvals.SetEnabled(true)
  1171  
  1172  	// Create a blocked eval.
  1173  	eval := mock.Eval()
  1174  	eval.Status = structs.EvalStatusBlocked
  1175  
  1176  	req := structs.EvalUpdateRequest{
  1177  		Evals: []*structs.Evaluation{eval},
  1178  	}
  1179  	buf, err := structs.Encode(structs.EvalUpdateRequestType, req)
  1180  	if err != nil {
  1181  		t.Fatalf("err: %v", err)
  1182  	}
  1183  
  1184  	resp := fsm.Apply(makeLog(buf))
  1185  	if resp != nil {
  1186  		t.Fatalf("resp: %v", resp)
  1187  	}
  1188  
  1189  	// Verify we are registered
  1190  	ws := memdb.NewWatchSet()
  1191  	out, err := fsm.State().EvalByID(ws, eval.ID)
  1192  	if err != nil {
  1193  		t.Fatalf("err: %v", err)
  1194  	}
  1195  	if out == nil {
  1196  		t.Fatalf("not found!")
  1197  	}
  1198  	if out.CreateIndex != 1 {
  1199  		t.Fatalf("bad index: %d", out.CreateIndex)
  1200  	}
  1201  
  1202  	// Verify the eval wasn't enqueued
  1203  	stats := fsm.evalBroker.Stats()
  1204  	if stats.TotalReady != 0 {
  1205  		t.Fatalf("bad: %#v %#v", stats, out)
  1206  	}
  1207  
  1208  	// Verify the eval was added to the blocked tracker.
  1209  	bStats := fsm.blockedEvals.Stats()
  1210  	if bStats.TotalBlocked != 1 {
  1211  		t.Fatalf("bad: %#v %#v", bStats, out)
  1212  	}
  1213  }
  1214  
  1215  func TestFSM_UpdateEval_Untrack(t *testing.T) {
  1216  	ci.Parallel(t)
  1217  	fsm := testFSM(t)
  1218  	fsm.evalBroker.SetEnabled(true)
  1219  	fsm.blockedEvals.SetEnabled(true)
  1220  
  1221  	// Mark an eval as blocked.
  1222  	bEval := mock.Eval()
  1223  	bEval.ClassEligibility = map[string]bool{"v1:123": true}
  1224  	fsm.blockedEvals.Block(bEval)
  1225  
  1226  	// Create a successful eval for the same job
  1227  	eval := mock.Eval()
  1228  	eval.JobID = bEval.JobID
  1229  	eval.Status = structs.EvalStatusComplete
  1230  
  1231  	req := structs.EvalUpdateRequest{
  1232  		Evals: []*structs.Evaluation{eval},
  1233  	}
  1234  	buf, err := structs.Encode(structs.EvalUpdateRequestType, req)
  1235  	if err != nil {
  1236  		t.Fatalf("err: %v", err)
  1237  	}
  1238  
  1239  	resp := fsm.Apply(makeLog(buf))
  1240  	if resp != nil {
  1241  		t.Fatalf("resp: %v", resp)
  1242  	}
  1243  
  1244  	// Verify we are registered
  1245  	ws := memdb.NewWatchSet()
  1246  	out, err := fsm.State().EvalByID(ws, eval.ID)
  1247  	if err != nil {
  1248  		t.Fatalf("err: %v", err)
  1249  	}
  1250  	if out == nil {
  1251  		t.Fatalf("not found!")
  1252  	}
  1253  	if out.CreateIndex != 1 {
  1254  		t.Fatalf("bad index: %d", out.CreateIndex)
  1255  	}
  1256  
  1257  	// Verify the eval wasn't enqueued
  1258  	stats := fsm.evalBroker.Stats()
  1259  	if stats.TotalReady != 0 {
  1260  		t.Fatalf("bad: %#v %#v", stats, out)
  1261  	}
  1262  
  1263  	// Verify the eval was untracked in the blocked tracker.
  1264  	bStats := fsm.blockedEvals.Stats()
  1265  	if bStats.TotalBlocked != 0 {
  1266  		t.Fatalf("bad: %#v %#v", bStats, out)
  1267  	}
  1268  }
  1269  
  1270  func TestFSM_UpdateEval_NoUntrack(t *testing.T) {
  1271  	ci.Parallel(t)
  1272  	fsm := testFSM(t)
  1273  	fsm.evalBroker.SetEnabled(true)
  1274  	fsm.blockedEvals.SetEnabled(true)
  1275  
  1276  	// Mark an eval as blocked.
  1277  	bEval := mock.Eval()
  1278  	bEval.ClassEligibility = map[string]bool{"v1:123": true}
  1279  	fsm.blockedEvals.Block(bEval)
  1280  
  1281  	// Create a successful eval for the same job but with placement failures
  1282  	eval := mock.Eval()
  1283  	eval.JobID = bEval.JobID
  1284  	eval.Status = structs.EvalStatusComplete
  1285  	eval.FailedTGAllocs = make(map[string]*structs.AllocMetric)
  1286  	eval.FailedTGAllocs["test"] = new(structs.AllocMetric)
  1287  
  1288  	req := structs.EvalUpdateRequest{
  1289  		Evals: []*structs.Evaluation{eval},
  1290  	}
  1291  	buf, err := structs.Encode(structs.EvalUpdateRequestType, req)
  1292  	if err != nil {
  1293  		t.Fatalf("err: %v", err)
  1294  	}
  1295  
  1296  	resp := fsm.Apply(makeLog(buf))
  1297  	if resp != nil {
  1298  		t.Fatalf("resp: %v", resp)
  1299  	}
  1300  
  1301  	// Verify we are registered
  1302  	ws := memdb.NewWatchSet()
  1303  	out, err := fsm.State().EvalByID(ws, eval.ID)
  1304  	if err != nil {
  1305  		t.Fatalf("err: %v", err)
  1306  	}
  1307  	if out == nil {
  1308  		t.Fatalf("not found!")
  1309  	}
  1310  	if out.CreateIndex != 1 {
  1311  		t.Fatalf("bad index: %d", out.CreateIndex)
  1312  	}
  1313  
  1314  	// Verify the eval wasn't enqueued
  1315  	stats := fsm.evalBroker.Stats()
  1316  	if stats.TotalReady != 0 {
  1317  		t.Fatalf("bad: %#v %#v", stats, out)
  1318  	}
  1319  
  1320  	// Verify the eval was not untracked in the blocked tracker.
  1321  	bStats := fsm.blockedEvals.Stats()
  1322  	if bStats.TotalBlocked != 1 {
  1323  		t.Fatalf("bad: %#v %#v", bStats, out)
  1324  	}
  1325  }
  1326  
  1327  func TestFSM_DeleteEval(t *testing.T) {
  1328  	ci.Parallel(t)
  1329  	fsm := testFSM(t)
  1330  
  1331  	eval := mock.Eval()
  1332  	req := structs.EvalUpdateRequest{
  1333  		Evals: []*structs.Evaluation{eval},
  1334  	}
  1335  	buf, err := structs.Encode(structs.EvalUpdateRequestType, req)
  1336  	if err != nil {
  1337  		t.Fatalf("err: %v", err)
  1338  	}
  1339  
  1340  	resp := fsm.Apply(makeLog(buf))
  1341  	if resp != nil {
  1342  		t.Fatalf("resp: %v", resp)
  1343  	}
  1344  
  1345  	req2 := structs.EvalReapRequest{
  1346  		Evals: []string{eval.ID},
  1347  	}
  1348  	buf, err = structs.Encode(structs.EvalDeleteRequestType, req2)
  1349  	if err != nil {
  1350  		t.Fatalf("err: %v", err)
  1351  	}
  1352  
  1353  	resp = fsm.Apply(makeLog(buf))
  1354  	if resp != nil {
  1355  		t.Fatalf("resp: %v", resp)
  1356  	}
  1357  
  1358  	// Verify we are NOT registered
  1359  	ws := memdb.NewWatchSet()
  1360  	eval, err = fsm.State().EvalByID(ws, req.Evals[0].ID)
  1361  	if err != nil {
  1362  		t.Fatalf("err: %v", err)
  1363  	}
  1364  	if eval != nil {
  1365  		t.Fatalf("eval found!")
  1366  	}
  1367  }
  1368  
  1369  func TestFSM_UpdateAllocFromClient_Unblock(t *testing.T) {
  1370  	ci.Parallel(t)
  1371  	fsm := testFSM(t)
  1372  	fsm.blockedEvals.SetEnabled(true)
  1373  	state := fsm.State()
  1374  
  1375  	node := mock.Node()
  1376  	state.UpsertNode(structs.MsgTypeTestSetup, 1, node)
  1377  
  1378  	// Mark an eval as blocked.
  1379  	eval := mock.Eval()
  1380  	eval.ClassEligibility = map[string]bool{node.ComputedClass: true}
  1381  	fsm.blockedEvals.Block(eval)
  1382  
  1383  	bStats := fsm.blockedEvals.Stats()
  1384  	if bStats.TotalBlocked != 1 {
  1385  		t.Fatalf("bad: %#v", bStats)
  1386  	}
  1387  
  1388  	// Create a completed eval
  1389  	alloc := mock.Alloc()
  1390  	alloc.NodeID = node.ID
  1391  	alloc2 := mock.Alloc()
  1392  	alloc2.NodeID = node.ID
  1393  	state.UpsertJobSummary(8, mock.JobSummary(alloc.JobID))
  1394  	state.UpsertJobSummary(9, mock.JobSummary(alloc2.JobID))
  1395  	state.UpsertAllocs(structs.MsgTypeTestSetup, 10, []*structs.Allocation{alloc, alloc2})
  1396  
  1397  	clientAlloc := new(structs.Allocation)
  1398  	*clientAlloc = *alloc
  1399  	clientAlloc.ClientStatus = structs.AllocClientStatusComplete
  1400  	update2 := &structs.Allocation{
  1401  		ID:           alloc2.ID,
  1402  		NodeID:       alloc2.NodeID,
  1403  		ClientStatus: structs.AllocClientStatusRunning,
  1404  	}
  1405  
  1406  	req := structs.AllocUpdateRequest{
  1407  		Alloc: []*structs.Allocation{clientAlloc, update2},
  1408  	}
  1409  	buf, err := structs.Encode(structs.AllocClientUpdateRequestType, req)
  1410  	if err != nil {
  1411  		t.Fatalf("err: %v", err)
  1412  	}
  1413  
  1414  	resp := fsm.Apply(makeLog(buf))
  1415  	if resp != nil {
  1416  		t.Fatalf("resp: %v", resp)
  1417  	}
  1418  
  1419  	// Verify we are updated
  1420  	ws := memdb.NewWatchSet()
  1421  	out, err := fsm.State().AllocByID(ws, alloc.ID)
  1422  	if err != nil {
  1423  		t.Fatalf("err: %v", err)
  1424  	}
  1425  	clientAlloc.CreateIndex = out.CreateIndex
  1426  	clientAlloc.ModifyIndex = out.ModifyIndex
  1427  	if !reflect.DeepEqual(clientAlloc, out) {
  1428  		t.Fatalf("bad: %#v %#v", clientAlloc, out)
  1429  	}
  1430  
  1431  	out, err = fsm.State().AllocByID(ws, alloc2.ID)
  1432  	if err != nil {
  1433  		t.Fatalf("err: %v", err)
  1434  	}
  1435  	alloc2.CreateIndex = out.CreateIndex
  1436  	alloc2.ModifyIndex = out.ModifyIndex
  1437  	alloc2.ClientStatus = structs.AllocClientStatusRunning
  1438  	alloc2.TaskStates = nil
  1439  	if !reflect.DeepEqual(alloc2, out) {
  1440  		t.Fatalf("bad: %#v %#v", alloc2, out)
  1441  	}
  1442  
  1443  	// Verify the eval was unblocked.
  1444  	testutil.WaitForResult(func() (bool, error) {
  1445  		bStats = fsm.blockedEvals.Stats()
  1446  		if bStats.TotalBlocked != 0 {
  1447  			return false, fmt.Errorf("bad: %#v %#v", bStats, out)
  1448  		}
  1449  		return true, nil
  1450  	}, func(err error) {
  1451  		t.Fatalf("err: %s", err)
  1452  	})
  1453  }
  1454  
  1455  func TestFSM_UpdateAllocFromClient(t *testing.T) {
  1456  	ci.Parallel(t)
  1457  	fsm := testFSM(t)
  1458  	state := fsm.State()
  1459  	require := require.New(t)
  1460  
  1461  	alloc := mock.Alloc()
  1462  	state.UpsertJobSummary(9, mock.JobSummary(alloc.JobID))
  1463  	state.UpsertAllocs(structs.MsgTypeTestSetup, 10, []*structs.Allocation{alloc})
  1464  
  1465  	clientAlloc := new(structs.Allocation)
  1466  	*clientAlloc = *alloc
  1467  	clientAlloc.ClientStatus = structs.AllocClientStatusFailed
  1468  
  1469  	eval := mock.Eval()
  1470  	eval.JobID = alloc.JobID
  1471  	eval.TriggeredBy = structs.EvalTriggerRetryFailedAlloc
  1472  	eval.Type = alloc.Job.Type
  1473  
  1474  	req := structs.AllocUpdateRequest{
  1475  		Alloc: []*structs.Allocation{clientAlloc},
  1476  		Evals: []*structs.Evaluation{eval},
  1477  	}
  1478  	buf, err := structs.Encode(structs.AllocClientUpdateRequestType, req)
  1479  	require.Nil(err)
  1480  
  1481  	resp := fsm.Apply(makeLog(buf))
  1482  	require.Nil(resp)
  1483  
  1484  	// Verify we are registered
  1485  	ws := memdb.NewWatchSet()
  1486  	out, err := fsm.State().AllocByID(ws, alloc.ID)
  1487  	require.Nil(err)
  1488  	clientAlloc.CreateIndex = out.CreateIndex
  1489  	clientAlloc.ModifyIndex = out.ModifyIndex
  1490  	require.Equal(clientAlloc, out)
  1491  
  1492  	// Verify eval was inserted
  1493  	ws = memdb.NewWatchSet()
  1494  	evals, err := fsm.State().EvalsByJob(ws, eval.Namespace, eval.JobID)
  1495  	require.Nil(err)
  1496  	require.Equal(1, len(evals))
  1497  	res := evals[0]
  1498  	eval.CreateIndex = res.CreateIndex
  1499  	eval.ModifyIndex = res.ModifyIndex
  1500  	require.Equal(eval, res)
  1501  }
  1502  
  1503  func TestFSM_UpdateAllocDesiredTransition(t *testing.T) {
  1504  	ci.Parallel(t)
  1505  	fsm := testFSM(t)
  1506  	state := fsm.State()
  1507  	require := require.New(t)
  1508  
  1509  	alloc := mock.Alloc()
  1510  	alloc2 := mock.Alloc()
  1511  	alloc2.Job = alloc.Job
  1512  	alloc2.JobID = alloc.JobID
  1513  	state.UpsertJobSummary(9, mock.JobSummary(alloc.JobID))
  1514  	state.UpsertAllocs(structs.MsgTypeTestSetup, 10, []*structs.Allocation{alloc, alloc2})
  1515  
  1516  	t1 := &structs.DesiredTransition{
  1517  		Migrate: pointer.Of(true),
  1518  	}
  1519  
  1520  	eval := &structs.Evaluation{
  1521  		ID:             uuid.Generate(),
  1522  		Namespace:      alloc.Namespace,
  1523  		Priority:       alloc.Job.Priority,
  1524  		Type:           alloc.Job.Type,
  1525  		TriggeredBy:    structs.EvalTriggerNodeDrain,
  1526  		JobID:          alloc.Job.ID,
  1527  		JobModifyIndex: alloc.Job.ModifyIndex,
  1528  		Status:         structs.EvalStatusPending,
  1529  	}
  1530  	req := structs.AllocUpdateDesiredTransitionRequest{
  1531  		Allocs: map[string]*structs.DesiredTransition{
  1532  			alloc.ID:  t1,
  1533  			alloc2.ID: t1,
  1534  		},
  1535  		Evals: []*structs.Evaluation{eval},
  1536  	}
  1537  	buf, err := structs.Encode(structs.AllocUpdateDesiredTransitionRequestType, req)
  1538  	require.Nil(err)
  1539  
  1540  	resp := fsm.Apply(makeLog(buf))
  1541  	require.Nil(resp)
  1542  
  1543  	// Verify we are registered
  1544  	ws := memdb.NewWatchSet()
  1545  	out1, err := fsm.State().AllocByID(ws, alloc.ID)
  1546  	require.Nil(err)
  1547  	out2, err := fsm.State().AllocByID(ws, alloc2.ID)
  1548  	require.Nil(err)
  1549  	evalOut, err := fsm.State().EvalByID(ws, eval.ID)
  1550  	require.Nil(err)
  1551  	require.NotNil(evalOut)
  1552  	require.Equal(eval.ID, evalOut.ID)
  1553  
  1554  	require.NotNil(out1.DesiredTransition.Migrate)
  1555  	require.NotNil(out2.DesiredTransition.Migrate)
  1556  	require.True(*out1.DesiredTransition.Migrate)
  1557  	require.True(*out2.DesiredTransition.Migrate)
  1558  }
  1559  
  1560  func TestFSM_UpsertVaultAccessor(t *testing.T) {
  1561  	ci.Parallel(t)
  1562  	fsm := testFSM(t)
  1563  	fsm.blockedEvals.SetEnabled(true)
  1564  
  1565  	va := mock.VaultAccessor()
  1566  	va2 := mock.VaultAccessor()
  1567  	req := structs.VaultAccessorsRequest{
  1568  		Accessors: []*structs.VaultAccessor{va, va2},
  1569  	}
  1570  	buf, err := structs.Encode(structs.VaultAccessorRegisterRequestType, req)
  1571  	if err != nil {
  1572  		t.Fatalf("err: %v", err)
  1573  	}
  1574  
  1575  	resp := fsm.Apply(makeLog(buf))
  1576  	if resp != nil {
  1577  		t.Fatalf("resp: %v", resp)
  1578  	}
  1579  
  1580  	// Verify we are registered
  1581  	ws := memdb.NewWatchSet()
  1582  	out1, err := fsm.State().VaultAccessor(ws, va.Accessor)
  1583  	if err != nil {
  1584  		t.Fatalf("err: %v", err)
  1585  	}
  1586  	if out1 == nil {
  1587  		t.Fatalf("not found!")
  1588  	}
  1589  	if out1.CreateIndex != 1 {
  1590  		t.Fatalf("bad index: %d", out1.CreateIndex)
  1591  	}
  1592  	out2, err := fsm.State().VaultAccessor(ws, va2.Accessor)
  1593  	if err != nil {
  1594  		t.Fatalf("err: %v", err)
  1595  	}
  1596  	if out2 == nil {
  1597  		t.Fatalf("not found!")
  1598  	}
  1599  	if out1.CreateIndex != 1 {
  1600  		t.Fatalf("bad index: %d", out2.CreateIndex)
  1601  	}
  1602  
  1603  	tt := fsm.TimeTable()
  1604  	index := tt.NearestIndex(time.Now().UTC())
  1605  	if index != 1 {
  1606  		t.Fatalf("bad: %d", index)
  1607  	}
  1608  }
  1609  
  1610  func TestFSM_DeregisterVaultAccessor(t *testing.T) {
  1611  	ci.Parallel(t)
  1612  	fsm := testFSM(t)
  1613  	fsm.blockedEvals.SetEnabled(true)
  1614  
  1615  	va := mock.VaultAccessor()
  1616  	va2 := mock.VaultAccessor()
  1617  	accessors := []*structs.VaultAccessor{va, va2}
  1618  
  1619  	// Insert the accessors
  1620  	if err := fsm.State().UpsertVaultAccessor(1000, accessors); err != nil {
  1621  		t.Fatalf("bad: %v", err)
  1622  	}
  1623  
  1624  	req := structs.VaultAccessorsRequest{
  1625  		Accessors: accessors,
  1626  	}
  1627  	buf, err := structs.Encode(structs.VaultAccessorDeregisterRequestType, req)
  1628  	if err != nil {
  1629  		t.Fatalf("err: %v", err)
  1630  	}
  1631  
  1632  	resp := fsm.Apply(makeLog(buf))
  1633  	if resp != nil {
  1634  		t.Fatalf("resp: %v", resp)
  1635  	}
  1636  
  1637  	ws := memdb.NewWatchSet()
  1638  	out1, err := fsm.State().VaultAccessor(ws, va.Accessor)
  1639  	if err != nil {
  1640  		t.Fatalf("err: %v", err)
  1641  	}
  1642  	if out1 != nil {
  1643  		t.Fatalf("not deleted!")
  1644  	}
  1645  
  1646  	tt := fsm.TimeTable()
  1647  	index := tt.NearestIndex(time.Now().UTC())
  1648  	if index != 1 {
  1649  		t.Fatalf("bad: %d", index)
  1650  	}
  1651  }
  1652  
  1653  func TestFSM_UpsertSITokenAccessor(t *testing.T) {
  1654  	ci.Parallel(t)
  1655  	r := require.New(t)
  1656  
  1657  	fsm := testFSM(t)
  1658  	fsm.blockedEvals.SetEnabled(true)
  1659  
  1660  	a1 := mock.SITokenAccessor()
  1661  	a2 := mock.SITokenAccessor()
  1662  	request := structs.SITokenAccessorsRequest{
  1663  		Accessors: []*structs.SITokenAccessor{a1, a2},
  1664  	}
  1665  	buf, err := structs.Encode(structs.ServiceIdentityAccessorRegisterRequestType, request)
  1666  	r.NoError(err)
  1667  
  1668  	response := fsm.Apply(makeLog(buf))
  1669  	r.Nil(response)
  1670  
  1671  	// Verify the accessors got registered
  1672  	ws := memdb.NewWatchSet()
  1673  	result1, err := fsm.State().SITokenAccessor(ws, a1.AccessorID)
  1674  	r.NoError(err)
  1675  	r.NotNil(result1)
  1676  	r.Equal(uint64(1), result1.CreateIndex)
  1677  
  1678  	result2, err := fsm.State().SITokenAccessor(ws, a2.AccessorID)
  1679  	r.NoError(err)
  1680  	r.NotNil(result2)
  1681  	r.Equal(uint64(1), result2.CreateIndex)
  1682  
  1683  	tt := fsm.TimeTable()
  1684  	latestIndex := tt.NearestIndex(time.Now())
  1685  	r.Equal(uint64(1), latestIndex)
  1686  }
  1687  
  1688  func TestFSM_DeregisterSITokenAccessor(t *testing.T) {
  1689  	ci.Parallel(t)
  1690  	r := require.New(t)
  1691  
  1692  	fsm := testFSM(t)
  1693  	fsm.blockedEvals.SetEnabled(true)
  1694  
  1695  	a1 := mock.SITokenAccessor()
  1696  	a2 := mock.SITokenAccessor()
  1697  	accessors := []*structs.SITokenAccessor{a1, a2}
  1698  	var err error
  1699  
  1700  	// Insert the accessors
  1701  	err = fsm.State().UpsertSITokenAccessors(1000, accessors)
  1702  	r.NoError(err)
  1703  
  1704  	request := structs.SITokenAccessorsRequest{Accessors: accessors}
  1705  	buf, err := structs.Encode(structs.ServiceIdentityAccessorDeregisterRequestType, request)
  1706  	r.NoError(err)
  1707  
  1708  	response := fsm.Apply(makeLog(buf))
  1709  	r.Nil(response)
  1710  
  1711  	ws := memdb.NewWatchSet()
  1712  
  1713  	result1, err := fsm.State().SITokenAccessor(ws, a1.AccessorID)
  1714  	r.NoError(err)
  1715  	r.Nil(result1) // should have been deleted
  1716  
  1717  	result2, err := fsm.State().SITokenAccessor(ws, a2.AccessorID)
  1718  	r.NoError(err)
  1719  	r.Nil(result2) // should have been deleted
  1720  
  1721  	tt := fsm.TimeTable()
  1722  	latestIndex := tt.NearestIndex(time.Now())
  1723  	r.Equal(uint64(1), latestIndex)
  1724  }
  1725  
  1726  func TestFSM_ApplyPlanResults(t *testing.T) {
  1727  	ci.Parallel(t)
  1728  	fsm := testFSM(t)
  1729  	fsm.evalBroker.SetEnabled(true)
  1730  	// Create the request and create a deployment
  1731  	alloc := mock.Alloc()
  1732  	alloc.Resources = &structs.Resources{} // COMPAT(0.11): Remove in 0.11, used to bypass resource creation in state store
  1733  	job := alloc.Job
  1734  	alloc.Job = nil
  1735  
  1736  	d := mock.Deployment()
  1737  	d.JobID = job.ID
  1738  	d.JobModifyIndex = job.ModifyIndex
  1739  	d.JobVersion = job.Version
  1740  
  1741  	alloc.DeploymentID = d.ID
  1742  
  1743  	eval := mock.Eval()
  1744  	eval.JobID = job.ID
  1745  	fsm.State().UpsertEvals(structs.MsgTypeTestSetup, 1, []*structs.Evaluation{eval})
  1746  
  1747  	fsm.State().UpsertJobSummary(1, mock.JobSummary(alloc.JobID))
  1748  
  1749  	// set up preempted jobs and allocs
  1750  	job1 := mock.Job()
  1751  	job2 := mock.Job()
  1752  
  1753  	alloc1 := mock.Alloc()
  1754  	alloc1.Job = job1
  1755  	alloc1.JobID = job1.ID
  1756  	alloc1.PreemptedByAllocation = alloc.ID
  1757  
  1758  	alloc2 := mock.Alloc()
  1759  	alloc2.Job = job2
  1760  	alloc2.JobID = job2.ID
  1761  	alloc2.PreemptedByAllocation = alloc.ID
  1762  
  1763  	fsm.State().UpsertAllocs(structs.MsgTypeTestSetup, 1, []*structs.Allocation{alloc1, alloc2})
  1764  
  1765  	// evals for preempted jobs
  1766  	eval1 := mock.Eval()
  1767  	eval1.JobID = job1.ID
  1768  
  1769  	eval2 := mock.Eval()
  1770  	eval2.JobID = job2.ID
  1771  
  1772  	req := structs.ApplyPlanResultsRequest{
  1773  		AllocUpdateRequest: structs.AllocUpdateRequest{
  1774  			Job:   job,
  1775  			Alloc: []*structs.Allocation{alloc},
  1776  		},
  1777  		Deployment:      d,
  1778  		EvalID:          eval.ID,
  1779  		NodePreemptions: []*structs.Allocation{alloc1, alloc2},
  1780  		PreemptionEvals: []*structs.Evaluation{eval1, eval2},
  1781  	}
  1782  	buf, err := structs.Encode(structs.ApplyPlanResultsRequestType, req)
  1783  	if err != nil {
  1784  		t.Fatalf("err: %v", err)
  1785  	}
  1786  
  1787  	resp := fsm.Apply(makeLog(buf))
  1788  	if resp != nil {
  1789  		t.Fatalf("resp: %v", resp)
  1790  	}
  1791  
  1792  	// Verify the allocation is registered
  1793  	ws := memdb.NewWatchSet()
  1794  	assert := assert.New(t)
  1795  	out, err := fsm.State().AllocByID(ws, alloc.ID)
  1796  	assert.Nil(err)
  1797  	alloc.CreateIndex = out.CreateIndex
  1798  	alloc.ModifyIndex = out.ModifyIndex
  1799  	alloc.AllocModifyIndex = out.AllocModifyIndex
  1800  
  1801  	// Job should be re-attached
  1802  	alloc.Job = job
  1803  	assert.Equal(alloc, out)
  1804  
  1805  	// Verify that evals for preempted jobs have been created
  1806  	e1, err := fsm.State().EvalByID(ws, eval1.ID)
  1807  	require := require.New(t)
  1808  	require.Nil(err)
  1809  	require.NotNil(e1)
  1810  
  1811  	e2, err := fsm.State().EvalByID(ws, eval2.ID)
  1812  	require.Nil(err)
  1813  	require.NotNil(e2)
  1814  
  1815  	// Verify that eval broker has both evals
  1816  	_, ok := fsm.evalBroker.evals[e1.ID]
  1817  	require.True(ok)
  1818  
  1819  	_, ok = fsm.evalBroker.evals[e1.ID]
  1820  	require.True(ok)
  1821  
  1822  	dout, err := fsm.State().DeploymentByID(ws, d.ID)
  1823  	assert.Nil(err)
  1824  	tg, ok := dout.TaskGroups[alloc.TaskGroup]
  1825  	assert.True(ok)
  1826  	assert.NotNil(tg)
  1827  	assert.Equal(1, tg.PlacedAllocs)
  1828  
  1829  	// Ensure that the original job is used
  1830  	evictAlloc := alloc.Copy()
  1831  	job = mock.Job()
  1832  	job.Priority = 123
  1833  	eval = mock.Eval()
  1834  	eval.JobID = job.ID
  1835  
  1836  	fsm.State().UpsertEvals(structs.MsgTypeTestSetup, 2, []*structs.Evaluation{eval})
  1837  
  1838  	evictAlloc.Job = nil
  1839  	evictAlloc.DesiredStatus = structs.AllocDesiredStatusEvict
  1840  	req2 := structs.ApplyPlanResultsRequest{
  1841  		AllocUpdateRequest: structs.AllocUpdateRequest{
  1842  			Job:   job,
  1843  			Alloc: []*structs.Allocation{evictAlloc},
  1844  		},
  1845  		EvalID: eval.ID,
  1846  	}
  1847  	buf, err = structs.Encode(structs.ApplyPlanResultsRequestType, req2)
  1848  	assert.Nil(err)
  1849  
  1850  	log := makeLog(buf)
  1851  	//set the index to something other than 1
  1852  	log.Index = 25
  1853  	resp = fsm.Apply(log)
  1854  	assert.Nil(resp)
  1855  
  1856  	// Verify we are evicted
  1857  	out, err = fsm.State().AllocByID(ws, alloc.ID)
  1858  	assert.Nil(err)
  1859  	assert.Equal(structs.AllocDesiredStatusEvict, out.DesiredStatus)
  1860  	assert.NotNil(out.Job)
  1861  	assert.NotEqual(123, out.Job.Priority)
  1862  
  1863  	evalOut, err := fsm.State().EvalByID(ws, eval.ID)
  1864  	assert.Nil(err)
  1865  	assert.Equal(log.Index, evalOut.ModifyIndex)
  1866  
  1867  }
  1868  
  1869  func TestFSM_DeploymentStatusUpdate(t *testing.T) {
  1870  	ci.Parallel(t)
  1871  	fsm := testFSM(t)
  1872  	fsm.evalBroker.SetEnabled(true)
  1873  	state := fsm.State()
  1874  
  1875  	// Upsert a deployment
  1876  	d := mock.Deployment()
  1877  	if err := state.UpsertDeployment(1, d); err != nil {
  1878  		t.Fatalf("bad: %v", err)
  1879  	}
  1880  
  1881  	// Create a request to update the deployment, create an eval and job
  1882  	e := mock.Eval()
  1883  	j := mock.Job()
  1884  	status, desc := structs.DeploymentStatusFailed, "foo"
  1885  	req := &structs.DeploymentStatusUpdateRequest{
  1886  		DeploymentUpdate: &structs.DeploymentStatusUpdate{
  1887  			DeploymentID:      d.ID,
  1888  			Status:            status,
  1889  			StatusDescription: desc,
  1890  		},
  1891  		Job:  j,
  1892  		Eval: e,
  1893  	}
  1894  	buf, err := structs.Encode(structs.DeploymentStatusUpdateRequestType, req)
  1895  	if err != nil {
  1896  		t.Fatalf("err: %v", err)
  1897  	}
  1898  	resp := fsm.Apply(makeLog(buf))
  1899  	if resp != nil {
  1900  		t.Fatalf("resp: %v", resp)
  1901  	}
  1902  
  1903  	// Check that the status was updated properly
  1904  	ws := memdb.NewWatchSet()
  1905  	dout, err := state.DeploymentByID(ws, d.ID)
  1906  	if err != nil {
  1907  		t.Fatalf("bad: %v", err)
  1908  	}
  1909  	if dout.Status != status || dout.StatusDescription != desc {
  1910  		t.Fatalf("bad: %#v", dout)
  1911  	}
  1912  
  1913  	// Check that the evaluation was created
  1914  	eout, _ := state.EvalByID(ws, e.ID)
  1915  	if err != nil {
  1916  		t.Fatalf("bad: %v", err)
  1917  	}
  1918  	if eout == nil {
  1919  		t.Fatalf("bad: %#v", eout)
  1920  	}
  1921  
  1922  	// Check that the job was created
  1923  	jout, _ := state.JobByID(ws, j.Namespace, j.ID)
  1924  	if err != nil {
  1925  		t.Fatalf("bad: %v", err)
  1926  	}
  1927  	if jout == nil {
  1928  		t.Fatalf("bad: %#v", jout)
  1929  	}
  1930  
  1931  	// Assert the eval was enqueued
  1932  	stats := fsm.evalBroker.Stats()
  1933  	if stats.TotalReady != 1 {
  1934  		t.Fatalf("bad: %#v %#v", stats, e)
  1935  	}
  1936  }
  1937  
  1938  func TestFSM_JobStabilityUpdate(t *testing.T) {
  1939  	ci.Parallel(t)
  1940  	fsm := testFSM(t)
  1941  	fsm.evalBroker.SetEnabled(true)
  1942  	state := fsm.State()
  1943  
  1944  	// Upsert a deployment
  1945  	job := mock.Job()
  1946  	if err := state.UpsertJob(structs.MsgTypeTestSetup, 1, nil, job); err != nil {
  1947  		t.Fatalf("bad: %v", err)
  1948  	}
  1949  
  1950  	// Create a request to update the job to stable
  1951  	req := &structs.JobStabilityRequest{
  1952  		JobID:      job.ID,
  1953  		JobVersion: job.Version,
  1954  		Stable:     true,
  1955  		WriteRequest: structs.WriteRequest{
  1956  			Namespace: job.Namespace,
  1957  		},
  1958  	}
  1959  	buf, err := structs.Encode(structs.JobStabilityRequestType, req)
  1960  	if err != nil {
  1961  		t.Fatalf("err: %v", err)
  1962  	}
  1963  	resp := fsm.Apply(makeLog(buf))
  1964  	if resp != nil {
  1965  		t.Fatalf("resp: %v", resp)
  1966  	}
  1967  
  1968  	// Check that the stability was updated properly
  1969  	ws := memdb.NewWatchSet()
  1970  	jout, _ := state.JobByIDAndVersion(ws, job.Namespace, job.ID, job.Version)
  1971  	if err != nil {
  1972  		t.Fatalf("bad: %v", err)
  1973  	}
  1974  	if jout == nil || !jout.Stable {
  1975  		t.Fatalf("bad: %#v", jout)
  1976  	}
  1977  }
  1978  
  1979  func TestFSM_DeploymentPromotion(t *testing.T) {
  1980  	ci.Parallel(t)
  1981  	fsm := testFSM(t)
  1982  	fsm.evalBroker.SetEnabled(true)
  1983  	state := fsm.State()
  1984  
  1985  	// Create a job with two task groups
  1986  	j := mock.Job()
  1987  	tg1 := j.TaskGroups[0]
  1988  	tg2 := tg1.Copy()
  1989  	tg2.Name = "foo"
  1990  	j.TaskGroups = append(j.TaskGroups, tg2)
  1991  	if err := state.UpsertJob(structs.MsgTypeTestSetup, 1, nil, j); err != nil {
  1992  		t.Fatalf("bad: %v", err)
  1993  	}
  1994  
  1995  	// Create a deployment
  1996  	d := mock.Deployment()
  1997  	d.JobID = j.ID
  1998  	d.TaskGroups = map[string]*structs.DeploymentState{
  1999  		"web": {
  2000  			DesiredTotal:    10,
  2001  			DesiredCanaries: 1,
  2002  		},
  2003  		"foo": {
  2004  			DesiredTotal:    10,
  2005  			DesiredCanaries: 1,
  2006  		},
  2007  	}
  2008  	if err := state.UpsertDeployment(2, d); err != nil {
  2009  		t.Fatalf("bad: %v", err)
  2010  	}
  2011  
  2012  	// Create a set of allocations
  2013  	c1 := mock.Alloc()
  2014  	c1.JobID = j.ID
  2015  	c1.DeploymentID = d.ID
  2016  	d.TaskGroups[c1.TaskGroup].PlacedCanaries = append(d.TaskGroups[c1.TaskGroup].PlacedCanaries, c1.ID)
  2017  	c1.DeploymentStatus = &structs.AllocDeploymentStatus{
  2018  		Healthy: pointer.Of(true),
  2019  	}
  2020  	c2 := mock.Alloc()
  2021  	c2.JobID = j.ID
  2022  	c2.DeploymentID = d.ID
  2023  	d.TaskGroups[c2.TaskGroup].PlacedCanaries = append(d.TaskGroups[c2.TaskGroup].PlacedCanaries, c2.ID)
  2024  	c2.TaskGroup = tg2.Name
  2025  	c2.DeploymentStatus = &structs.AllocDeploymentStatus{
  2026  		Healthy: pointer.Of(true),
  2027  	}
  2028  
  2029  	if err := state.UpsertAllocs(structs.MsgTypeTestSetup, 3, []*structs.Allocation{c1, c2}); err != nil {
  2030  		t.Fatalf("err: %v", err)
  2031  	}
  2032  
  2033  	// Create an eval
  2034  	e := mock.Eval()
  2035  
  2036  	// Promote the canaries
  2037  	req := &structs.ApplyDeploymentPromoteRequest{
  2038  		DeploymentPromoteRequest: structs.DeploymentPromoteRequest{
  2039  			DeploymentID: d.ID,
  2040  			All:          true,
  2041  		},
  2042  		Eval: e,
  2043  	}
  2044  	buf, err := structs.Encode(structs.DeploymentPromoteRequestType, req)
  2045  	if err != nil {
  2046  		t.Fatalf("err: %v", err)
  2047  	}
  2048  	resp := fsm.Apply(makeLog(buf))
  2049  	if resp != nil {
  2050  		t.Fatalf("resp: %v", resp)
  2051  	}
  2052  
  2053  	// Check that the status per task group was updated properly
  2054  	ws := memdb.NewWatchSet()
  2055  	dout, err := state.DeploymentByID(ws, d.ID)
  2056  	if err != nil {
  2057  		t.Fatalf("bad: %v", err)
  2058  	}
  2059  	if len(dout.TaskGroups) != 2 {
  2060  		t.Fatalf("bad: %#v", dout.TaskGroups)
  2061  	}
  2062  	for tg, state := range dout.TaskGroups {
  2063  		if !state.Promoted {
  2064  			t.Fatalf("bad: group %q not promoted %#v", tg, state)
  2065  		}
  2066  	}
  2067  
  2068  	// Check that the evaluation was created
  2069  	eout, _ := state.EvalByID(ws, e.ID)
  2070  	if err != nil {
  2071  		t.Fatalf("bad: %v", err)
  2072  	}
  2073  	if eout == nil {
  2074  		t.Fatalf("bad: %#v", eout)
  2075  	}
  2076  
  2077  	// Assert the eval was enqueued
  2078  	stats := fsm.evalBroker.Stats()
  2079  	if stats.TotalReady != 1 {
  2080  		t.Fatalf("bad: %#v %#v", stats, e)
  2081  	}
  2082  }
  2083  
  2084  func TestFSM_DeploymentAllocHealth(t *testing.T) {
  2085  	ci.Parallel(t)
  2086  	fsm := testFSM(t)
  2087  	fsm.evalBroker.SetEnabled(true)
  2088  	state := fsm.State()
  2089  
  2090  	// Insert a deployment
  2091  	d := mock.Deployment()
  2092  	if err := state.UpsertDeployment(1, d); err != nil {
  2093  		t.Fatalf("bad: %v", err)
  2094  	}
  2095  
  2096  	// Insert two allocations
  2097  	a1 := mock.Alloc()
  2098  	a1.DeploymentID = d.ID
  2099  	a2 := mock.Alloc()
  2100  	a2.DeploymentID = d.ID
  2101  	if err := state.UpsertAllocs(structs.MsgTypeTestSetup, 2, []*structs.Allocation{a1, a2}); err != nil {
  2102  		t.Fatalf("bad: %v", err)
  2103  	}
  2104  
  2105  	// Create a job to roll back to
  2106  	j := mock.Job()
  2107  
  2108  	// Create an eval that should be upserted
  2109  	e := mock.Eval()
  2110  
  2111  	// Create a status update for the deployment
  2112  	status, desc := structs.DeploymentStatusFailed, "foo"
  2113  	u := &structs.DeploymentStatusUpdate{
  2114  		DeploymentID:      d.ID,
  2115  		Status:            status,
  2116  		StatusDescription: desc,
  2117  	}
  2118  
  2119  	// Set health against the deployment
  2120  	req := &structs.ApplyDeploymentAllocHealthRequest{
  2121  		DeploymentAllocHealthRequest: structs.DeploymentAllocHealthRequest{
  2122  			DeploymentID:           d.ID,
  2123  			HealthyAllocationIDs:   []string{a1.ID},
  2124  			UnhealthyAllocationIDs: []string{a2.ID},
  2125  		},
  2126  		Job:              j,
  2127  		Eval:             e,
  2128  		DeploymentUpdate: u,
  2129  	}
  2130  	buf, err := structs.Encode(structs.DeploymentAllocHealthRequestType, req)
  2131  	if err != nil {
  2132  		t.Fatalf("err: %v", err)
  2133  	}
  2134  	resp := fsm.Apply(makeLog(buf))
  2135  	if resp != nil {
  2136  		t.Fatalf("resp: %v", resp)
  2137  	}
  2138  
  2139  	// Check that the status was updated properly
  2140  	ws := memdb.NewWatchSet()
  2141  	dout, err := state.DeploymentByID(ws, d.ID)
  2142  	if err != nil {
  2143  		t.Fatalf("bad: %v", err)
  2144  	}
  2145  	if dout.Status != status || dout.StatusDescription != desc {
  2146  		t.Fatalf("bad: %#v", dout)
  2147  	}
  2148  
  2149  	// Check that the evaluation was created
  2150  	eout, _ := state.EvalByID(ws, e.ID)
  2151  	if err != nil {
  2152  		t.Fatalf("bad: %v", err)
  2153  	}
  2154  	if eout == nil {
  2155  		t.Fatalf("bad: %#v", eout)
  2156  	}
  2157  
  2158  	// Check that the job was created
  2159  	jout, _ := state.JobByID(ws, j.Namespace, j.ID)
  2160  	if err != nil {
  2161  		t.Fatalf("bad: %v", err)
  2162  	}
  2163  	if jout == nil {
  2164  		t.Fatalf("bad: %#v", jout)
  2165  	}
  2166  
  2167  	// Check the status of the allocs
  2168  	out1, err := state.AllocByID(ws, a1.ID)
  2169  	if err != nil {
  2170  		t.Fatalf("err: %v", err)
  2171  	}
  2172  	out2, err := state.AllocByID(ws, a2.ID)
  2173  	if err != nil {
  2174  		t.Fatalf("err: %v", err)
  2175  	}
  2176  
  2177  	if !out1.DeploymentStatus.IsHealthy() {
  2178  		t.Fatalf("bad: alloc %q not healthy", out1.ID)
  2179  	}
  2180  	if !out2.DeploymentStatus.IsUnhealthy() {
  2181  		t.Fatalf("bad: alloc %q not unhealthy", out2.ID)
  2182  	}
  2183  
  2184  	// Assert the eval was enqueued
  2185  	stats := fsm.evalBroker.Stats()
  2186  	if stats.TotalReady != 1 {
  2187  		t.Fatalf("bad: %#v %#v", stats, e)
  2188  	}
  2189  }
  2190  
  2191  func TestFSM_DeleteDeployment(t *testing.T) {
  2192  	ci.Parallel(t)
  2193  	fsm := testFSM(t)
  2194  	state := fsm.State()
  2195  
  2196  	// Upsert a deployments
  2197  	d := mock.Deployment()
  2198  	if err := state.UpsertDeployment(1, d); err != nil {
  2199  		t.Fatalf("bad: %v", err)
  2200  	}
  2201  
  2202  	req := structs.DeploymentDeleteRequest{
  2203  		Deployments: []string{d.ID},
  2204  	}
  2205  	buf, err := structs.Encode(structs.DeploymentDeleteRequestType, req)
  2206  	if err != nil {
  2207  		t.Fatalf("err: %v", err)
  2208  	}
  2209  
  2210  	resp := fsm.Apply(makeLog(buf))
  2211  	if resp != nil {
  2212  		t.Fatalf("resp: %v", resp)
  2213  	}
  2214  
  2215  	// Verify we are NOT registered
  2216  	ws := memdb.NewWatchSet()
  2217  	deployment, err := state.DeploymentByID(ws, d.ID)
  2218  	if err != nil {
  2219  		t.Fatalf("err: %v", err)
  2220  	}
  2221  	if deployment != nil {
  2222  		t.Fatalf("deployment found!")
  2223  	}
  2224  }
  2225  
  2226  func TestFSM_UpsertACLPolicies(t *testing.T) {
  2227  	ci.Parallel(t)
  2228  	fsm := testFSM(t)
  2229  
  2230  	policy := mock.ACLPolicy()
  2231  	req := structs.ACLPolicyUpsertRequest{
  2232  		Policies: []*structs.ACLPolicy{policy},
  2233  	}
  2234  	buf, err := structs.Encode(structs.ACLPolicyUpsertRequestType, req)
  2235  	if err != nil {
  2236  		t.Fatalf("err: %v", err)
  2237  	}
  2238  
  2239  	resp := fsm.Apply(makeLog(buf))
  2240  	if resp != nil {
  2241  		t.Fatalf("resp: %v", resp)
  2242  	}
  2243  
  2244  	// Verify we are registered
  2245  	ws := memdb.NewWatchSet()
  2246  	out, err := fsm.State().ACLPolicyByName(ws, policy.Name)
  2247  	assert.Nil(t, err)
  2248  	assert.NotNil(t, out)
  2249  }
  2250  
  2251  func TestFSM_DeleteACLPolicies(t *testing.T) {
  2252  	ci.Parallel(t)
  2253  	fsm := testFSM(t)
  2254  
  2255  	policy := mock.ACLPolicy()
  2256  	err := fsm.State().UpsertACLPolicies(structs.MsgTypeTestSetup, 1000, []*structs.ACLPolicy{policy})
  2257  	assert.Nil(t, err)
  2258  
  2259  	req := structs.ACLPolicyDeleteRequest{
  2260  		Names: []string{policy.Name},
  2261  	}
  2262  	buf, err := structs.Encode(structs.ACLPolicyDeleteRequestType, req)
  2263  	if err != nil {
  2264  		t.Fatalf("err: %v", err)
  2265  	}
  2266  
  2267  	resp := fsm.Apply(makeLog(buf))
  2268  	if resp != nil {
  2269  		t.Fatalf("resp: %v", resp)
  2270  	}
  2271  
  2272  	// Verify we are NOT registered
  2273  	ws := memdb.NewWatchSet()
  2274  	out, err := fsm.State().ACLPolicyByName(ws, policy.Name)
  2275  	assert.Nil(t, err)
  2276  	assert.Nil(t, out)
  2277  }
  2278  
  2279  func TestFSM_BootstrapACLTokens(t *testing.T) {
  2280  	ci.Parallel(t)
  2281  	fsm := testFSM(t)
  2282  
  2283  	token := mock.ACLToken()
  2284  	req := structs.ACLTokenBootstrapRequest{
  2285  		Token: token,
  2286  	}
  2287  	buf, err := structs.Encode(structs.ACLTokenBootstrapRequestType, req)
  2288  	if err != nil {
  2289  		t.Fatalf("err: %v", err)
  2290  	}
  2291  
  2292  	resp := fsm.Apply(makeLog(buf))
  2293  	if resp != nil {
  2294  		t.Fatalf("resp: %v", resp)
  2295  	}
  2296  
  2297  	// Verify we are registered
  2298  	out, err := fsm.State().ACLTokenByAccessorID(nil, token.AccessorID)
  2299  	assert.Nil(t, err)
  2300  	assert.NotNil(t, out)
  2301  
  2302  	// Test with reset
  2303  	token2 := mock.ACLToken()
  2304  	req = structs.ACLTokenBootstrapRequest{
  2305  		Token:      token2,
  2306  		ResetIndex: out.CreateIndex,
  2307  	}
  2308  	buf, err = structs.Encode(structs.ACLTokenBootstrapRequestType, req)
  2309  	if err != nil {
  2310  		t.Fatalf("err: %v", err)
  2311  	}
  2312  
  2313  	resp = fsm.Apply(makeLog(buf))
  2314  	if resp != nil {
  2315  		t.Fatalf("resp: %v", resp)
  2316  	}
  2317  
  2318  	// Verify we are registered
  2319  	out2, err := fsm.State().ACLTokenByAccessorID(nil, token2.AccessorID)
  2320  	assert.Nil(t, err)
  2321  	assert.NotNil(t, out2)
  2322  }
  2323  
  2324  func TestFSM_UpsertACLTokens(t *testing.T) {
  2325  	ci.Parallel(t)
  2326  	fsm := testFSM(t)
  2327  
  2328  	token := mock.ACLToken()
  2329  	req := structs.ACLTokenUpsertRequest{
  2330  		Tokens: []*structs.ACLToken{token},
  2331  	}
  2332  	buf, err := structs.Encode(structs.ACLTokenUpsertRequestType, req)
  2333  	if err != nil {
  2334  		t.Fatalf("err: %v", err)
  2335  	}
  2336  
  2337  	resp := fsm.Apply(makeLog(buf))
  2338  	if resp != nil {
  2339  		t.Fatalf("resp: %v", resp)
  2340  	}
  2341  
  2342  	// Verify we are registered
  2343  	ws := memdb.NewWatchSet()
  2344  	out, err := fsm.State().ACLTokenByAccessorID(ws, token.AccessorID)
  2345  	assert.Nil(t, err)
  2346  	assert.NotNil(t, out)
  2347  }
  2348  
  2349  func TestFSM_DeleteACLTokens(t *testing.T) {
  2350  	ci.Parallel(t)
  2351  	fsm := testFSM(t)
  2352  
  2353  	token := mock.ACLToken()
  2354  	err := fsm.State().UpsertACLTokens(structs.MsgTypeTestSetup, 1000, []*structs.ACLToken{token})
  2355  	assert.Nil(t, err)
  2356  
  2357  	req := structs.ACLTokenDeleteRequest{
  2358  		AccessorIDs: []string{token.AccessorID},
  2359  	}
  2360  	buf, err := structs.Encode(structs.ACLTokenDeleteRequestType, req)
  2361  	if err != nil {
  2362  		t.Fatalf("err: %v", err)
  2363  	}
  2364  
  2365  	resp := fsm.Apply(makeLog(buf))
  2366  	if resp != nil {
  2367  		t.Fatalf("resp: %v", resp)
  2368  	}
  2369  
  2370  	// Verify we are NOT registered
  2371  	ws := memdb.NewWatchSet()
  2372  	out, err := fsm.State().ACLTokenByAccessorID(ws, token.AccessorID)
  2373  	assert.Nil(t, err)
  2374  	assert.Nil(t, out)
  2375  }
  2376  
  2377  func testSnapshotRestore(t *testing.T, fsm *nomadFSM) *nomadFSM {
  2378  	// Snapshot
  2379  	snap, err := fsm.Snapshot()
  2380  	if err != nil {
  2381  		t.Fatalf("err: %v", err)
  2382  	}
  2383  	defer snap.Release()
  2384  
  2385  	// Persist
  2386  	buf := bytes.NewBuffer(nil)
  2387  	sink := &MockSink{buf, false}
  2388  	if err := snap.Persist(sink); err != nil {
  2389  		t.Fatalf("err: %v", err)
  2390  	}
  2391  
  2392  	// Try to restore on a new FSM
  2393  	fsm2 := testFSM(t)
  2394  	snap, err = fsm2.Snapshot()
  2395  	if err != nil {
  2396  		t.Fatalf("err: %v", err)
  2397  	}
  2398  	defer snap.Release()
  2399  
  2400  	abandonCh := fsm2.State().AbandonCh()
  2401  
  2402  	// Do a restore
  2403  	if err := fsm2.Restore(sink); err != nil {
  2404  		t.Fatalf("err: %v", err)
  2405  	}
  2406  
  2407  	select {
  2408  	case <-abandonCh:
  2409  	default:
  2410  		t.Fatalf("bad")
  2411  	}
  2412  
  2413  	return fsm2
  2414  }
  2415  
  2416  func TestFSM_SnapshotRestore_Nodes(t *testing.T) {
  2417  	ci.Parallel(t)
  2418  	// Add some state
  2419  	fsm := testFSM(t)
  2420  	state := fsm.State()
  2421  	node := mock.Node()
  2422  	state.UpsertNode(structs.MsgTypeTestSetup, 1000, node)
  2423  
  2424  	// Verify the contents
  2425  	fsm2 := testSnapshotRestore(t, fsm)
  2426  	state2 := fsm2.State()
  2427  	out, _ := state2.NodeByID(nil, node.ID)
  2428  	if !reflect.DeepEqual(node, out) {
  2429  		t.Fatalf("bad: \n%#v\n%#v", out, node)
  2430  	}
  2431  }
  2432  
  2433  func TestFSM_SnapshotRestore_NodePools(t *testing.T) {
  2434  	ci.Parallel(t)
  2435  
  2436  	// Add some state
  2437  	fsm := testFSM(t)
  2438  	state := fsm.State()
  2439  	pool := mock.NodePool()
  2440  	state.UpsertNodePools(structs.MsgTypeTestSetup, 1000, []*structs.NodePool{pool})
  2441  
  2442  	// Verify the contents
  2443  	fsm2 := testSnapshotRestore(t, fsm)
  2444  	state2 := fsm2.State()
  2445  	out, _ := state2.NodePoolByName(nil, pool.Name)
  2446  	must.Eq(t, pool, out)
  2447  }
  2448  
  2449  func TestFSM_SnapshotRestore_Jobs(t *testing.T) {
  2450  	ci.Parallel(t)
  2451  	// Add some state
  2452  	fsm := testFSM(t)
  2453  	state := fsm.State()
  2454  	job1 := mock.Job()
  2455  	state.UpsertJob(structs.MsgTypeTestSetup, 1000, nil, job1)
  2456  	job2 := mock.Job()
  2457  	state.UpsertJob(structs.MsgTypeTestSetup, 1001, nil, job2)
  2458  
  2459  	// Verify the contents
  2460  	ws := memdb.NewWatchSet()
  2461  	fsm2 := testSnapshotRestore(t, fsm)
  2462  	state2 := fsm2.State()
  2463  	out1, _ := state2.JobByID(ws, job1.Namespace, job1.ID)
  2464  	out2, _ := state2.JobByID(ws, job2.Namespace, job2.ID)
  2465  	if !reflect.DeepEqual(job1, out1) {
  2466  		t.Fatalf("bad: \n%#v\n%#v", out1, job1)
  2467  	}
  2468  	if !reflect.DeepEqual(job2, out2) {
  2469  		t.Fatalf("bad: \n%#v\n%#v", out2, job2)
  2470  	}
  2471  }
  2472  
  2473  func TestFSM_SnapshotRestore_Evals(t *testing.T) {
  2474  	ci.Parallel(t)
  2475  	// Add some state
  2476  	fsm := testFSM(t)
  2477  	state := fsm.State()
  2478  	eval1 := mock.Eval()
  2479  	state.UpsertEvals(structs.MsgTypeTestSetup, 1000, []*structs.Evaluation{eval1})
  2480  	eval2 := mock.Eval()
  2481  	state.UpsertEvals(structs.MsgTypeTestSetup, 1001, []*structs.Evaluation{eval2})
  2482  
  2483  	// Verify the contents
  2484  	fsm2 := testSnapshotRestore(t, fsm)
  2485  	state2 := fsm2.State()
  2486  	ws := memdb.NewWatchSet()
  2487  	out1, _ := state2.EvalByID(ws, eval1.ID)
  2488  	out2, _ := state2.EvalByID(ws, eval2.ID)
  2489  	if !reflect.DeepEqual(eval1, out1) {
  2490  		t.Fatalf("bad: \n%#v\n%#v", out1, eval1)
  2491  	}
  2492  	if !reflect.DeepEqual(eval2, out2) {
  2493  		t.Fatalf("bad: \n%#v\n%#v", out2, eval2)
  2494  	}
  2495  }
  2496  
  2497  func TestFSM_SnapshotRestore_Allocs(t *testing.T) {
  2498  	ci.Parallel(t)
  2499  	// Add some state
  2500  	fsm := testFSM(t)
  2501  	state := fsm.State()
  2502  	alloc1 := mock.Alloc()
  2503  	alloc2 := mock.Alloc()
  2504  	state.UpsertJobSummary(998, mock.JobSummary(alloc1.JobID))
  2505  	state.UpsertJobSummary(999, mock.JobSummary(alloc2.JobID))
  2506  	state.UpsertAllocs(structs.MsgTypeTestSetup, 1000, []*structs.Allocation{alloc1})
  2507  	state.UpsertAllocs(structs.MsgTypeTestSetup, 1001, []*structs.Allocation{alloc2})
  2508  
  2509  	// Verify the contents
  2510  	fsm2 := testSnapshotRestore(t, fsm)
  2511  	state2 := fsm2.State()
  2512  	ws := memdb.NewWatchSet()
  2513  	out1, _ := state2.AllocByID(ws, alloc1.ID)
  2514  	out2, _ := state2.AllocByID(ws, alloc2.ID)
  2515  	if !reflect.DeepEqual(alloc1, out1) {
  2516  		t.Fatalf("bad: \n%#v\n%#v", out1, alloc1)
  2517  	}
  2518  	if !reflect.DeepEqual(alloc2, out2) {
  2519  		t.Fatalf("bad: \n%#v\n%#v", out2, alloc2)
  2520  	}
  2521  }
  2522  
  2523  func TestFSM_SnapshotRestore_Allocs_Canonicalize(t *testing.T) {
  2524  	ci.Parallel(t)
  2525  	// Add some state
  2526  	fsm := testFSM(t)
  2527  	state := fsm.State()
  2528  	alloc := mock.Alloc()
  2529  
  2530  	// remove old versions to force migration path
  2531  	alloc.AllocatedResources = nil
  2532  
  2533  	state.UpsertJobSummary(998, mock.JobSummary(alloc.JobID))
  2534  	state.UpsertAllocs(structs.MsgTypeTestSetup, 1000, []*structs.Allocation{alloc})
  2535  
  2536  	// Verify the contents
  2537  	fsm2 := testSnapshotRestore(t, fsm)
  2538  	state2 := fsm2.State()
  2539  	ws := memdb.NewWatchSet()
  2540  	out, err := state2.AllocByID(ws, alloc.ID)
  2541  	require.NoError(t, err)
  2542  
  2543  	require.NotNil(t, out.AllocatedResources)
  2544  	require.Contains(t, out.AllocatedResources.Tasks, "web")
  2545  
  2546  	alloc.Canonicalize()
  2547  	require.Equal(t, alloc, out)
  2548  }
  2549  
  2550  func TestFSM_SnapshotRestore_Indexes(t *testing.T) {
  2551  	ci.Parallel(t)
  2552  	// Add some state
  2553  	fsm := testFSM(t)
  2554  	state := fsm.State()
  2555  	node1 := mock.Node()
  2556  	state.UpsertNode(structs.MsgTypeTestSetup, 1000, node1)
  2557  
  2558  	// Verify the contents
  2559  	fsm2 := testSnapshotRestore(t, fsm)
  2560  	state2 := fsm2.State()
  2561  
  2562  	index, err := state2.Index("nodes")
  2563  	if err != nil {
  2564  		t.Fatalf("err: %v", err)
  2565  	}
  2566  	if index != 1000 {
  2567  		t.Fatalf("bad: %d", index)
  2568  	}
  2569  }
  2570  
  2571  func TestFSM_SnapshotRestore_TimeTable(t *testing.T) {
  2572  	ci.Parallel(t)
  2573  	// Add some state
  2574  	fsm := testFSM(t)
  2575  
  2576  	tt := fsm.TimeTable()
  2577  	start := time.Now().UTC()
  2578  	tt.Witness(1000, start)
  2579  	tt.Witness(2000, start.Add(10*time.Minute))
  2580  
  2581  	// Verify the contents
  2582  	fsm2 := testSnapshotRestore(t, fsm)
  2583  
  2584  	tt2 := fsm2.TimeTable()
  2585  	if tt2.NearestTime(1500) != start {
  2586  		t.Fatalf("bad")
  2587  	}
  2588  	if tt2.NearestIndex(start.Add(15*time.Minute)) != 2000 {
  2589  		t.Fatalf("bad")
  2590  	}
  2591  }
  2592  
  2593  func TestFSM_SnapshotRestore_PeriodicLaunches(t *testing.T) {
  2594  	ci.Parallel(t)
  2595  	// Add some state
  2596  	fsm := testFSM(t)
  2597  	state := fsm.State()
  2598  	job1 := mock.Job()
  2599  	launch1 := &structs.PeriodicLaunch{
  2600  		ID:        job1.ID,
  2601  		Namespace: job1.Namespace,
  2602  		Launch:    time.Now(),
  2603  	}
  2604  	state.UpsertPeriodicLaunch(1000, launch1)
  2605  	job2 := mock.Job()
  2606  	launch2 := &structs.PeriodicLaunch{
  2607  		ID:        job2.ID,
  2608  		Namespace: job2.Namespace,
  2609  		Launch:    time.Now(),
  2610  	}
  2611  	state.UpsertPeriodicLaunch(1001, launch2)
  2612  
  2613  	// Verify the contents
  2614  	fsm2 := testSnapshotRestore(t, fsm)
  2615  	state2 := fsm2.State()
  2616  	ws := memdb.NewWatchSet()
  2617  	out1, _ := state2.PeriodicLaunchByID(ws, launch1.Namespace, launch1.ID)
  2618  	out2, _ := state2.PeriodicLaunchByID(ws, launch2.Namespace, launch2.ID)
  2619  
  2620  	if !cmp.Equal(launch1, out1) {
  2621  		t.Fatalf("bad: %v", cmp.Diff(launch1, out1))
  2622  	}
  2623  	if !cmp.Equal(launch2, out2) {
  2624  		t.Fatalf("bad: %v", cmp.Diff(launch2, out2))
  2625  	}
  2626  }
  2627  
  2628  func TestFSM_SnapshotRestore_JobSummary(t *testing.T) {
  2629  	ci.Parallel(t)
  2630  	// Add some state
  2631  	fsm := testFSM(t)
  2632  	state := fsm.State()
  2633  
  2634  	job1 := mock.Job()
  2635  	state.UpsertJob(structs.MsgTypeTestSetup, 1000, nil, job1)
  2636  	ws := memdb.NewWatchSet()
  2637  	js1, _ := state.JobSummaryByID(ws, job1.Namespace, job1.ID)
  2638  
  2639  	job2 := mock.Job()
  2640  	state.UpsertJob(structs.MsgTypeTestSetup, 1001, nil, job2)
  2641  	js2, _ := state.JobSummaryByID(ws, job2.Namespace, job2.ID)
  2642  
  2643  	// Verify the contents
  2644  	fsm2 := testSnapshotRestore(t, fsm)
  2645  	state2 := fsm2.State()
  2646  	out1, _ := state2.JobSummaryByID(ws, job1.Namespace, job1.ID)
  2647  	out2, _ := state2.JobSummaryByID(ws, job2.Namespace, job2.ID)
  2648  	if !reflect.DeepEqual(js1, out1) {
  2649  		t.Fatalf("bad: \n%#v\n%#v", js1, out1)
  2650  	}
  2651  	if !reflect.DeepEqual(js2, out2) {
  2652  		t.Fatalf("bad: \n%#v\n%#v", js2, out2)
  2653  	}
  2654  }
  2655  
  2656  func TestFSM_SnapshotRestore_VaultAccessors(t *testing.T) {
  2657  	ci.Parallel(t)
  2658  	// Add some state
  2659  	fsm := testFSM(t)
  2660  	state := fsm.State()
  2661  	a1 := mock.VaultAccessor()
  2662  	a2 := mock.VaultAccessor()
  2663  	state.UpsertVaultAccessor(1000, []*structs.VaultAccessor{a1, a2})
  2664  
  2665  	// Verify the contents
  2666  	fsm2 := testSnapshotRestore(t, fsm)
  2667  	state2 := fsm2.State()
  2668  	ws := memdb.NewWatchSet()
  2669  	out1, _ := state2.VaultAccessor(ws, a1.Accessor)
  2670  	out2, _ := state2.VaultAccessor(ws, a2.Accessor)
  2671  	if !reflect.DeepEqual(a1, out1) {
  2672  		t.Fatalf("bad: \n%#v\n%#v", out1, a1)
  2673  	}
  2674  	if !reflect.DeepEqual(a2, out2) {
  2675  		t.Fatalf("bad: \n%#v\n%#v", out2, a2)
  2676  	}
  2677  }
  2678  
  2679  func TestFSM_SnapshotRestore_JobVersions(t *testing.T) {
  2680  	ci.Parallel(t)
  2681  	// Add some state
  2682  	fsm := testFSM(t)
  2683  	state := fsm.State()
  2684  	job1 := mock.Job()
  2685  	state.UpsertJob(structs.MsgTypeTestSetup, 1000, nil, job1)
  2686  	job2 := mock.Job()
  2687  	job2.ID = job1.ID
  2688  	state.UpsertJob(structs.MsgTypeTestSetup, 1001, nil, job2)
  2689  
  2690  	// Verify the contents
  2691  	ws := memdb.NewWatchSet()
  2692  	fsm2 := testSnapshotRestore(t, fsm)
  2693  	state2 := fsm2.State()
  2694  	out1, _ := state2.JobByIDAndVersion(ws, job1.Namespace, job1.ID, job1.Version)
  2695  	out2, _ := state2.JobByIDAndVersion(ws, job2.Namespace, job2.ID, job2.Version)
  2696  	if !reflect.DeepEqual(job1, out1) {
  2697  		t.Fatalf("bad: \n%#v\n%#v", out1, job1)
  2698  	}
  2699  	if !reflect.DeepEqual(job2, out2) {
  2700  		t.Fatalf("bad: \n%#v\n%#v", out2, job2)
  2701  	}
  2702  	if job2.Version != 1 {
  2703  		t.Fatalf("bad: \n%#v\n%#v", 1, job2)
  2704  	}
  2705  }
  2706  
  2707  func TestFSM_SnapshotRestore_Deployments(t *testing.T) {
  2708  	ci.Parallel(t)
  2709  	// Add some state
  2710  	fsm := testFSM(t)
  2711  	state := fsm.State()
  2712  	d1 := mock.Deployment()
  2713  	d2 := mock.Deployment()
  2714  
  2715  	j := mock.Job()
  2716  	d1.JobID = j.ID
  2717  	d2.JobID = j.ID
  2718  
  2719  	state.UpsertJob(structs.MsgTypeTestSetup, 999, nil, j)
  2720  	state.UpsertDeployment(1000, d1)
  2721  	state.UpsertDeployment(1001, d2)
  2722  
  2723  	// Verify the contents
  2724  	fsm2 := testSnapshotRestore(t, fsm)
  2725  	state2 := fsm2.State()
  2726  	ws := memdb.NewWatchSet()
  2727  	out1, _ := state2.DeploymentByID(ws, d1.ID)
  2728  	out2, _ := state2.DeploymentByID(ws, d2.ID)
  2729  	if !reflect.DeepEqual(d1, out1) {
  2730  		t.Fatalf("bad: \n%#v\n%#v", out1, d1)
  2731  	}
  2732  	if !reflect.DeepEqual(d2, out2) {
  2733  		t.Fatalf("bad: \n%#v\n%#v", out2, d2)
  2734  	}
  2735  }
  2736  
  2737  func TestFSM_SnapshotRestore_ACLPolicy(t *testing.T) {
  2738  	ci.Parallel(t)
  2739  	// Add some state
  2740  	fsm := testFSM(t)
  2741  	state := fsm.State()
  2742  	p1 := mock.ACLPolicy()
  2743  	p2 := mock.ACLPolicy()
  2744  	state.UpsertACLPolicies(structs.MsgTypeTestSetup, 1000, []*structs.ACLPolicy{p1, p2})
  2745  
  2746  	// Verify the contents
  2747  	fsm2 := testSnapshotRestore(t, fsm)
  2748  	state2 := fsm2.State()
  2749  	ws := memdb.NewWatchSet()
  2750  	out1, _ := state2.ACLPolicyByName(ws, p1.Name)
  2751  	out2, _ := state2.ACLPolicyByName(ws, p2.Name)
  2752  	assert.Equal(t, p1, out1)
  2753  	assert.Equal(t, p2, out2)
  2754  }
  2755  
  2756  func TestFSM_SnapshotRestore_ACLTokens(t *testing.T) {
  2757  	ci.Parallel(t)
  2758  	// Add some state
  2759  	fsm := testFSM(t)
  2760  	state := fsm.State()
  2761  	tk1 := mock.ACLToken()
  2762  	tk2 := mock.ACLToken()
  2763  	state.UpsertACLTokens(structs.MsgTypeTestSetup, 1000, []*structs.ACLToken{tk1, tk2})
  2764  
  2765  	// Verify the contents
  2766  	fsm2 := testSnapshotRestore(t, fsm)
  2767  	state2 := fsm2.State()
  2768  	ws := memdb.NewWatchSet()
  2769  	out1, _ := state2.ACLTokenByAccessorID(ws, tk1.AccessorID)
  2770  	out2, _ := state2.ACLTokenByAccessorID(ws, tk2.AccessorID)
  2771  	assert.Equal(t, tk1, out1)
  2772  	assert.Equal(t, tk2, out2)
  2773  }
  2774  
  2775  func TestFSM_SnapshotRestore_SchedulerConfiguration(t *testing.T) {
  2776  	ci.Parallel(t)
  2777  	// Add some state
  2778  	fsm := testFSM(t)
  2779  	state := fsm.State()
  2780  	schedConfig := &structs.SchedulerConfiguration{
  2781  		SchedulerAlgorithm: "spread",
  2782  		PreemptionConfig: structs.PreemptionConfig{
  2783  			SystemSchedulerEnabled: true,
  2784  		},
  2785  	}
  2786  	state.SchedulerSetConfig(1000, schedConfig)
  2787  
  2788  	// Verify the contents
  2789  	require := require.New(t)
  2790  	fsm2 := testSnapshotRestore(t, fsm)
  2791  	state2 := fsm2.State()
  2792  	index, out, err := state2.SchedulerConfig()
  2793  	require.Nil(err)
  2794  	require.EqualValues(1000, index)
  2795  	require.Equal(schedConfig, out)
  2796  }
  2797  
  2798  func TestFSM_SnapshotRestore_ClusterMetadata(t *testing.T) {
  2799  	ci.Parallel(t)
  2800  
  2801  	fsm := testFSM(t)
  2802  	state := fsm.State()
  2803  	clusterID := "12345678-1234-1234-1234-1234567890"
  2804  	now := time.Now().UnixNano()
  2805  	meta := &structs.ClusterMetadata{ClusterID: clusterID, CreateTime: now}
  2806  	state.ClusterSetMetadata(1000, meta)
  2807  
  2808  	// Verify the contents
  2809  	require := require.New(t)
  2810  	fsm2 := testSnapshotRestore(t, fsm)
  2811  	state2 := fsm2.State()
  2812  	out, err := state2.ClusterMetadata(memdb.NewWatchSet())
  2813  	require.NoError(err)
  2814  	require.Equal(clusterID, out.ClusterID)
  2815  }
  2816  
  2817  func TestFSM_SnapshotRestore_ServiceRegistrations(t *testing.T) {
  2818  	ci.Parallel(t)
  2819  
  2820  	// Create our initial FSM which will be snapshotted.
  2821  	fsm := testFSM(t)
  2822  	testState := fsm.State()
  2823  
  2824  	// Generate and upsert some service registrations.
  2825  	serviceRegs := mock.ServiceRegistrations()
  2826  	require.NoError(t, testState.UpsertServiceRegistrations(structs.MsgTypeTestSetup, 10, serviceRegs))
  2827  
  2828  	// Perform a snapshot restore.
  2829  	restoredFSM := testSnapshotRestore(t, fsm)
  2830  	restoredState := restoredFSM.State()
  2831  
  2832  	// List the service registrations from restored state and ensure everything
  2833  	// is as expected.
  2834  	iter, err := restoredState.GetServiceRegistrations(memdb.NewWatchSet())
  2835  	require.NoError(t, err)
  2836  
  2837  	var restoredRegs []*structs.ServiceRegistration
  2838  
  2839  	for raw := iter.Next(); raw != nil; raw = iter.Next() {
  2840  		restoredRegs = append(restoredRegs, raw.(*structs.ServiceRegistration))
  2841  	}
  2842  	require.ElementsMatch(t, restoredRegs, serviceRegs)
  2843  }
  2844  
  2845  func TestFSM_SnapshotRestore_ACLRoles(t *testing.T) {
  2846  	ci.Parallel(t)
  2847  
  2848  	// Create our initial FSM which will be snapshotted.
  2849  	fsm := testFSM(t)
  2850  	testState := fsm.State()
  2851  
  2852  	// Create the policies our ACL roles wants to link to.
  2853  	policy1 := mock.ACLPolicy()
  2854  	policy1.Name = "mocked-test-policy-1"
  2855  	policy2 := mock.ACLPolicy()
  2856  	policy2.Name = "mocked-test-policy-2"
  2857  
  2858  	require.NoError(t, testState.UpsertACLPolicies(
  2859  		structs.MsgTypeTestSetup, 10, []*structs.ACLPolicy{policy1, policy2}))
  2860  
  2861  	// Generate and upsert some ACL roles.
  2862  	aclRoles := []*structs.ACLRole{mock.ACLRole(), mock.ACLRole()}
  2863  	require.NoError(t, testState.UpsertACLRoles(structs.MsgTypeTestSetup, 10, aclRoles, false))
  2864  
  2865  	// Perform a snapshot restore.
  2866  	restoredFSM := testSnapshotRestore(t, fsm)
  2867  	restoredState := restoredFSM.State()
  2868  
  2869  	// List the ACL roles from restored state and ensure everything is as
  2870  	// expected.
  2871  	iter, err := restoredState.GetACLRoles(memdb.NewWatchSet())
  2872  	require.NoError(t, err)
  2873  
  2874  	var restoredACLRoles []*structs.ACLRole
  2875  
  2876  	for raw := iter.Next(); raw != nil; raw = iter.Next() {
  2877  		restoredACLRoles = append(restoredACLRoles, raw.(*structs.ACLRole))
  2878  	}
  2879  	require.ElementsMatch(t, restoredACLRoles, aclRoles)
  2880  }
  2881  
  2882  func TestFSM_SnapshotRestore_ACLAuthMethods(t *testing.T) {
  2883  	ci.Parallel(t)
  2884  
  2885  	// Create our initial FSM which will be snapshotted.
  2886  	fsm := testFSM(t)
  2887  	testState := fsm.State()
  2888  
  2889  	// Generate and upsert some ACL auth methods.
  2890  	authMethods := []*structs.ACLAuthMethod{mock.ACLOIDCAuthMethod(), mock.ACLOIDCAuthMethod()}
  2891  	must.NoError(t, testState.UpsertACLAuthMethods(10, authMethods))
  2892  
  2893  	// Perform a snapshot restore.
  2894  	restoredFSM := testSnapshotRestore(t, fsm)
  2895  	restoredState := restoredFSM.State()
  2896  
  2897  	// List the ACL auth methods from restored state and ensure everything is as
  2898  	// expected.
  2899  	iter, err := restoredState.GetACLAuthMethods(memdb.NewWatchSet())
  2900  	must.NoError(t, err)
  2901  
  2902  	var restoredACLAuthMethods []*structs.ACLAuthMethod
  2903  	for raw := iter.Next(); raw != nil; raw = iter.Next() {
  2904  		restoredACLAuthMethods = append(restoredACLAuthMethods, raw.(*structs.ACLAuthMethod))
  2905  	}
  2906  	must.SliceContainsAll(t, restoredACLAuthMethods, authMethods)
  2907  }
  2908  
  2909  func TestFSM_SnapshotRestore_ACLBindingRules(t *testing.T) {
  2910  	ci.Parallel(t)
  2911  
  2912  	// Create our initial FSM which will be snapshotted.
  2913  	fsm := testFSM(t)
  2914  	testState := fsm.State()
  2915  
  2916  	// Generate a some mocked ACL binding rules for testing and upsert these
  2917  	// straight into state.
  2918  	mockedACLBindingRoles := []*structs.ACLBindingRule{mock.ACLBindingRule(), mock.ACLBindingRule()}
  2919  	must.NoError(t, testState.UpsertACLBindingRules(10, mockedACLBindingRoles, true))
  2920  
  2921  	// Perform a snapshot restore.
  2922  	restoredFSM := testSnapshotRestore(t, fsm)
  2923  	restoredState := restoredFSM.State()
  2924  
  2925  	// List the ACL binding rules from restored state and ensure everything is
  2926  	// as expected.
  2927  	iter, err := restoredState.GetACLBindingRules(memdb.NewWatchSet())
  2928  	must.NoError(t, err)
  2929  
  2930  	var restoredACLBindingRules []*structs.ACLBindingRule
  2931  
  2932  	for raw := iter.Next(); raw != nil; raw = iter.Next() {
  2933  		restoredACLBindingRules = append(restoredACLBindingRules, raw.(*structs.ACLBindingRule))
  2934  	}
  2935  	must.SliceContainsAll(t, restoredACLBindingRules, mockedACLBindingRoles)
  2936  }
  2937  
  2938  func TestFSM_ReconcileSummaries(t *testing.T) {
  2939  	ci.Parallel(t)
  2940  	// Add some state
  2941  	fsm := testFSM(t)
  2942  	state := fsm.State()
  2943  
  2944  	// Add a node
  2945  	node := mock.Node()
  2946  	require.NoError(t, state.UpsertNode(structs.MsgTypeTestSetup, 800, node))
  2947  
  2948  	// Make a job so that none of the tasks can be placed
  2949  	job1 := mock.Job()
  2950  	job1.TaskGroups[0].Tasks[0].Resources.CPU = 5000
  2951  	require.NoError(t, state.UpsertJob(structs.MsgTypeTestSetup, 1000, nil, job1))
  2952  
  2953  	// make a job which can make partial progress
  2954  	alloc := mock.Alloc()
  2955  	alloc.NodeID = node.ID
  2956  	require.NoError(t, state.UpsertJob(structs.MsgTypeTestSetup, 1010, nil, alloc.Job))
  2957  	require.NoError(t, state.UpsertAllocs(structs.MsgTypeTestSetup, 1011, []*structs.Allocation{alloc}))
  2958  
  2959  	// Delete the summaries
  2960  	require.NoError(t, state.DeleteJobSummary(1030, job1.Namespace, job1.ID))
  2961  	require.NoError(t, state.DeleteJobSummary(1040, alloc.Namespace, alloc.Job.ID))
  2962  
  2963  	req := structs.GenericRequest{}
  2964  	buf, err := structs.Encode(structs.ReconcileJobSummariesRequestType, req)
  2965  	if err != nil {
  2966  		t.Fatalf("err: %v", err)
  2967  	}
  2968  
  2969  	resp := fsm.Apply(makeLog(buf))
  2970  	if resp != nil {
  2971  		t.Fatalf("resp: %v", resp)
  2972  	}
  2973  
  2974  	ws := memdb.NewWatchSet()
  2975  	out1, err := state.JobSummaryByID(ws, job1.Namespace, job1.ID)
  2976  	require.NoError(t, err)
  2977  
  2978  	expected := structs.JobSummary{
  2979  		JobID:     job1.ID,
  2980  		Namespace: job1.Namespace,
  2981  		Summary: map[string]structs.TaskGroupSummary{
  2982  			"web": {
  2983  				Queued: 10,
  2984  			},
  2985  		},
  2986  		CreateIndex: 1000,
  2987  		ModifyIndex: out1.ModifyIndex,
  2988  	}
  2989  	if !reflect.DeepEqual(&expected, out1) {
  2990  		t.Fatalf("expected: %#v, actual: %#v", &expected, out1)
  2991  	}
  2992  
  2993  	// This exercises the code path which adds the allocations made by the
  2994  	// planner and the number of unplaced allocations in the reconcile summaries
  2995  	// codepath
  2996  	out2, err := state.JobSummaryByID(ws, alloc.Namespace, alloc.Job.ID)
  2997  	require.NoError(t, err)
  2998  
  2999  	expected = structs.JobSummary{
  3000  		JobID:     alloc.Job.ID,
  3001  		Namespace: alloc.Job.Namespace,
  3002  		Summary: map[string]structs.TaskGroupSummary{
  3003  			"web": {
  3004  				Queued:   9,
  3005  				Starting: 1,
  3006  			},
  3007  		},
  3008  		CreateIndex: 1010,
  3009  		ModifyIndex: out2.ModifyIndex,
  3010  	}
  3011  	if !reflect.DeepEqual(&expected, out2) {
  3012  		t.Fatalf("Diff % #v", pretty.Diff(&expected, out2))
  3013  	}
  3014  }
  3015  
  3016  // COMPAT: Remove in 0.11
  3017  func TestFSM_ReconcileParentJobSummary(t *testing.T) {
  3018  	// This test exercises code to handle https://github.com/hernad/nomad/issues/3886
  3019  	ci.Parallel(t)
  3020  
  3021  	require := require.New(t)
  3022  	// Add some state
  3023  	fsm := testFSM(t)
  3024  	state := fsm.State()
  3025  
  3026  	// Add a node
  3027  	node := mock.Node()
  3028  	state.UpsertNode(structs.MsgTypeTestSetup, 800, node)
  3029  
  3030  	// Make a parameterized job
  3031  	job1 := mock.BatchJob()
  3032  	job1.ID = "test"
  3033  	job1.ParameterizedJob = &structs.ParameterizedJobConfig{
  3034  		Payload: "random",
  3035  	}
  3036  	job1.TaskGroups[0].Count = 1
  3037  	state.UpsertJob(structs.MsgTypeTestSetup, 1000, nil, job1)
  3038  
  3039  	// Make a child job
  3040  	childJob := job1.Copy()
  3041  	childJob.ID = job1.ID + "dispatch-23423423"
  3042  	childJob.ParentID = job1.ID
  3043  	childJob.Dispatched = true
  3044  	childJob.Status = structs.JobStatusRunning
  3045  
  3046  	// Create an alloc for child job
  3047  	alloc := mock.Alloc()
  3048  	alloc.NodeID = node.ID
  3049  	alloc.Job = childJob
  3050  	alloc.JobID = childJob.ID
  3051  	alloc.ClientStatus = structs.AllocClientStatusRunning
  3052  
  3053  	state.UpsertJob(structs.MsgTypeTestSetup, 1010, nil, childJob)
  3054  	state.UpsertAllocs(structs.MsgTypeTestSetup, 1011, []*structs.Allocation{alloc})
  3055  
  3056  	// Make the summary incorrect in the state store
  3057  	summary, err := state.JobSummaryByID(nil, job1.Namespace, job1.ID)
  3058  	require.Nil(err)
  3059  
  3060  	summary.Children = nil
  3061  	summary.Summary = make(map[string]structs.TaskGroupSummary)
  3062  	summary.Summary["web"] = structs.TaskGroupSummary{
  3063  		Queued: 1,
  3064  	}
  3065  
  3066  	req := structs.GenericRequest{}
  3067  	buf, err := structs.Encode(structs.ReconcileJobSummariesRequestType, req)
  3068  	require.Nil(err)
  3069  
  3070  	resp := fsm.Apply(makeLog(buf))
  3071  	require.Nil(resp)
  3072  
  3073  	ws := memdb.NewWatchSet()
  3074  	out1, _ := state.JobSummaryByID(ws, job1.Namespace, job1.ID)
  3075  	expected := structs.JobSummary{
  3076  		JobID:       job1.ID,
  3077  		Namespace:   job1.Namespace,
  3078  		Summary:     make(map[string]structs.TaskGroupSummary),
  3079  		CreateIndex: 1000,
  3080  		ModifyIndex: out1.ModifyIndex,
  3081  		Children: &structs.JobChildrenSummary{
  3082  			Running: 1,
  3083  		},
  3084  	}
  3085  	require.Equal(&expected, out1)
  3086  }
  3087  
  3088  func TestFSM_LeakedDeployments(t *testing.T) {
  3089  	ci.Parallel(t)
  3090  	require := require.New(t)
  3091  
  3092  	// Add some state
  3093  	fsm := testFSM(t)
  3094  	state := fsm.State()
  3095  	d := mock.Deployment()
  3096  	require.NoError(state.UpsertDeployment(1000, d))
  3097  
  3098  	// Verify the contents
  3099  	fsm2 := testSnapshotRestore(t, fsm)
  3100  	state2 := fsm2.State()
  3101  	out, _ := state2.DeploymentByID(nil, d.ID)
  3102  	require.NotNil(out)
  3103  	require.Equal(structs.DeploymentStatusCancelled, out.Status)
  3104  }
  3105  
  3106  func TestFSM_Autopilot(t *testing.T) {
  3107  	ci.Parallel(t)
  3108  	fsm := testFSM(t)
  3109  
  3110  	// Set the autopilot config using a request.
  3111  	req := structs.AutopilotSetConfigRequest{
  3112  		Datacenter: "dc1",
  3113  		Config: structs.AutopilotConfig{
  3114  			CleanupDeadServers:   true,
  3115  			LastContactThreshold: 10 * time.Second,
  3116  			MaxTrailingLogs:      300,
  3117  			MinQuorum:            3,
  3118  		},
  3119  	}
  3120  	buf, err := structs.Encode(structs.AutopilotRequestType, req)
  3121  	if err != nil {
  3122  		t.Fatalf("err: %v", err)
  3123  	}
  3124  	resp := fsm.Apply(makeLog(buf))
  3125  	if _, ok := resp.(error); ok {
  3126  		t.Fatalf("bad: %v", resp)
  3127  	}
  3128  
  3129  	// Verify key is set directly in the state store.
  3130  	_, config, err := fsm.state.AutopilotConfig()
  3131  	if err != nil {
  3132  		t.Fatalf("err: %v", err)
  3133  	}
  3134  	if config.CleanupDeadServers != req.Config.CleanupDeadServers {
  3135  		t.Fatalf("bad: %v", config.CleanupDeadServers)
  3136  	}
  3137  	if config.LastContactThreshold != req.Config.LastContactThreshold {
  3138  		t.Fatalf("bad: %v", config.LastContactThreshold)
  3139  	}
  3140  	if config.MaxTrailingLogs != req.Config.MaxTrailingLogs {
  3141  		t.Fatalf("bad: %v", config.MaxTrailingLogs)
  3142  	}
  3143  	if config.MinQuorum != req.Config.MinQuorum {
  3144  		t.Fatalf("bad: %v", config.MinQuorum)
  3145  	}
  3146  
  3147  	// Now use CAS and provide an old index
  3148  	req.CAS = true
  3149  	req.Config.CleanupDeadServers = false
  3150  	req.Config.ModifyIndex = config.ModifyIndex - 1
  3151  	buf, err = structs.Encode(structs.AutopilotRequestType, req)
  3152  	if err != nil {
  3153  		t.Fatalf("err: %v", err)
  3154  	}
  3155  	resp = fsm.Apply(makeLog(buf))
  3156  	if _, ok := resp.(error); ok {
  3157  		t.Fatalf("bad: %v", resp)
  3158  	}
  3159  
  3160  	_, config, err = fsm.state.AutopilotConfig()
  3161  	if err != nil {
  3162  		t.Fatalf("err: %v", err)
  3163  	}
  3164  	if !config.CleanupDeadServers {
  3165  		t.Fatalf("bad: %v", config.CleanupDeadServers)
  3166  	}
  3167  }
  3168  
  3169  func TestFSM_SchedulerConfig(t *testing.T) {
  3170  	ci.Parallel(t)
  3171  	fsm := testFSM(t)
  3172  
  3173  	require := require.New(t)
  3174  
  3175  	// Set the scheduler config using a request.
  3176  	req := structs.SchedulerSetConfigRequest{
  3177  		Config: structs.SchedulerConfiguration{
  3178  			PreemptionConfig: structs.PreemptionConfig{
  3179  				SystemSchedulerEnabled: true,
  3180  				BatchSchedulerEnabled:  true,
  3181  			},
  3182  		},
  3183  	}
  3184  	buf, err := structs.Encode(structs.SchedulerConfigRequestType, req)
  3185  	require.Nil(err)
  3186  
  3187  	resp := fsm.Apply(makeLog(buf))
  3188  	if _, ok := resp.(error); ok {
  3189  		t.Fatalf("bad: %v", resp)
  3190  	}
  3191  
  3192  	// Verify key is set directly in the state store.
  3193  	_, config, err := fsm.state.SchedulerConfig()
  3194  	require.Nil(err)
  3195  
  3196  	require.Equal(config.PreemptionConfig.SystemSchedulerEnabled, req.Config.PreemptionConfig.SystemSchedulerEnabled)
  3197  	require.Equal(config.PreemptionConfig.BatchSchedulerEnabled, req.Config.PreemptionConfig.BatchSchedulerEnabled)
  3198  
  3199  	// Now use CAS and provide an old index
  3200  	req.CAS = true
  3201  	req.Config.PreemptionConfig = structs.PreemptionConfig{SystemSchedulerEnabled: false, BatchSchedulerEnabled: false}
  3202  	req.Config.ModifyIndex = config.ModifyIndex - 1
  3203  	buf, err = structs.Encode(structs.SchedulerConfigRequestType, req)
  3204  	require.Nil(err)
  3205  
  3206  	resp = fsm.Apply(makeLog(buf))
  3207  	if _, ok := resp.(error); ok {
  3208  		t.Fatalf("bad: %v", resp)
  3209  	}
  3210  
  3211  	_, config, err = fsm.state.SchedulerConfig()
  3212  	require.Nil(err)
  3213  	// Verify that preemption is still enabled
  3214  	require.True(config.PreemptionConfig.SystemSchedulerEnabled)
  3215  	require.True(config.PreemptionConfig.BatchSchedulerEnabled)
  3216  }
  3217  
  3218  func TestFSM_ClusterMetadata(t *testing.T) {
  3219  	ci.Parallel(t)
  3220  	r := require.New(t)
  3221  
  3222  	fsm := testFSM(t)
  3223  	clusterID := "12345678-1234-1234-1234-1234567890"
  3224  	now := time.Now().UnixNano()
  3225  	meta := structs.ClusterMetadata{
  3226  		ClusterID:  clusterID,
  3227  		CreateTime: now,
  3228  	}
  3229  	buf, err := structs.Encode(structs.ClusterMetadataRequestType, meta)
  3230  	r.NoError(err)
  3231  
  3232  	result := fsm.Apply(makeLog(buf))
  3233  	r.Nil(result)
  3234  
  3235  	// Verify the clusterID is set directly in the state store
  3236  	ws := memdb.NewWatchSet()
  3237  	storedMetadata, err := fsm.state.ClusterMetadata(ws)
  3238  	r.NoError(err)
  3239  	r.Equal(clusterID, storedMetadata.ClusterID)
  3240  
  3241  	// Assert cluster ID cannot be overwritten and is not regenerated
  3242  	erroneous := structs.ClusterMetadata{
  3243  		ClusterID: "99999999-9999-9999-9999-9999999999",
  3244  	}
  3245  	buf, err = structs.Encode(structs.ClusterMetadataRequestType, erroneous)
  3246  	r.NoError(err)
  3247  
  3248  	result = fsm.Apply(makeLog(buf))
  3249  	r.Error(result.(error))
  3250  
  3251  	storedMetadata, err = fsm.state.ClusterMetadata(ws)
  3252  	r.NoError(err)
  3253  	r.Equal(clusterID, storedMetadata.ClusterID)
  3254  	r.Equal(now, storedMetadata.CreateTime)
  3255  }
  3256  
  3257  func TestFSM_UpsertNamespaces(t *testing.T) {
  3258  	assert := assert.New(t)
  3259  	ci.Parallel(t)
  3260  	fsm := testFSM(t)
  3261  
  3262  	ns1 := mock.Namespace()
  3263  	ns2 := mock.Namespace()
  3264  	req := structs.NamespaceUpsertRequest{
  3265  		Namespaces: []*structs.Namespace{ns1, ns2},
  3266  	}
  3267  	buf, err := structs.Encode(structs.NamespaceUpsertRequestType, req)
  3268  	assert.Nil(err)
  3269  	assert.Nil(fsm.Apply(makeLog(buf)))
  3270  
  3271  	// Verify we are registered
  3272  	ws := memdb.NewWatchSet()
  3273  	out, err := fsm.State().NamespaceByName(ws, ns1.Name)
  3274  	assert.Nil(err)
  3275  	assert.NotNil(out)
  3276  
  3277  	out, err = fsm.State().NamespaceByName(ws, ns2.Name)
  3278  	assert.Nil(err)
  3279  	assert.NotNil(out)
  3280  }
  3281  
  3282  func TestFSM_DeleteNamespaces(t *testing.T) {
  3283  	assert := assert.New(t)
  3284  	ci.Parallel(t)
  3285  	fsm := testFSM(t)
  3286  
  3287  	ns1 := mock.Namespace()
  3288  	ns2 := mock.Namespace()
  3289  	assert.Nil(fsm.State().UpsertNamespaces(1000, []*structs.Namespace{ns1, ns2}))
  3290  
  3291  	req := structs.NamespaceDeleteRequest{
  3292  		Namespaces: []string{ns1.Name, ns2.Name},
  3293  	}
  3294  	buf, err := structs.Encode(structs.NamespaceDeleteRequestType, req)
  3295  	assert.Nil(err)
  3296  	assert.Nil(fsm.Apply(makeLog(buf)))
  3297  
  3298  	// Verify we are NOT registered
  3299  	ws := memdb.NewWatchSet()
  3300  	out, err := fsm.State().NamespaceByName(ws, ns1.Name)
  3301  	assert.Nil(err)
  3302  	assert.Nil(out)
  3303  
  3304  	out, err = fsm.State().NamespaceByName(ws, ns2.Name)
  3305  	assert.Nil(err)
  3306  	assert.Nil(out)
  3307  }
  3308  
  3309  func TestFSM_SnapshotRestore_Namespaces(t *testing.T) {
  3310  	ci.Parallel(t)
  3311  	// Add some state
  3312  	fsm := testFSM(t)
  3313  	state := fsm.State()
  3314  	ns1 := mock.Namespace()
  3315  	ns2 := mock.Namespace()
  3316  	state.UpsertNamespaces(1000, []*structs.Namespace{ns1, ns2})
  3317  
  3318  	// Verify the contents
  3319  	fsm2 := testSnapshotRestore(t, fsm)
  3320  	state2 := fsm2.State()
  3321  	ws := memdb.NewWatchSet()
  3322  	out1, _ := state2.NamespaceByName(ws, ns1.Name)
  3323  	out2, _ := state2.NamespaceByName(ws, ns2.Name)
  3324  	if !reflect.DeepEqual(ns1, out1) {
  3325  		t.Fatalf("bad: \n%#v\n%#v", out1, ns1)
  3326  	}
  3327  	if !reflect.DeepEqual(ns2, out2) {
  3328  		t.Fatalf("bad: \n%#v\n%#v", out2, ns2)
  3329  	}
  3330  }
  3331  
  3332  func TestFSM_UpsertServiceRegistrations(t *testing.T) {
  3333  	ci.Parallel(t)
  3334  	fsm := testFSM(t)
  3335  
  3336  	// Generate our test service registrations.
  3337  	services := mock.ServiceRegistrations()
  3338  
  3339  	// Build and apply our message.
  3340  	req := structs.ServiceRegistrationUpsertRequest{Services: services}
  3341  	buf, err := structs.Encode(structs.ServiceRegistrationUpsertRequestType, req)
  3342  	assert.Nil(t, err)
  3343  	assert.Nil(t, fsm.Apply(makeLog(buf)))
  3344  
  3345  	// Check that both services are found within state.
  3346  	ws := memdb.NewWatchSet()
  3347  	out, err := fsm.State().GetServiceRegistrationByID(ws, services[0].Namespace, services[0].ID)
  3348  	assert.Nil(t, err)
  3349  	assert.NotNil(t, out)
  3350  
  3351  	out, err = fsm.State().GetServiceRegistrationByID(ws, services[1].Namespace, services[1].ID)
  3352  	assert.Nil(t, err)
  3353  	assert.NotNil(t, out)
  3354  }
  3355  
  3356  func TestFSM_DeleteServiceRegistrationsByID(t *testing.T) {
  3357  	ci.Parallel(t)
  3358  	fsm := testFSM(t)
  3359  
  3360  	// Generate our test service registrations.
  3361  	services := mock.ServiceRegistrations()
  3362  
  3363  	// Upsert the services.
  3364  	assert.NoError(t, fsm.State().UpsertServiceRegistrations(structs.MsgTypeTestSetup, uint64(10), services))
  3365  
  3366  	// Build and apply our message.
  3367  	req := structs.ServiceRegistrationDeleteByIDRequest{ID: services[0].ID}
  3368  	buf, err := structs.Encode(structs.ServiceRegistrationDeleteByIDRequestType, req)
  3369  	assert.Nil(t, err)
  3370  	assert.Nil(t, fsm.Apply(makeLog(buf)))
  3371  
  3372  	// Check that the service has been deleted, whilst the other is still
  3373  	// available.
  3374  	ws := memdb.NewWatchSet()
  3375  	out, err := fsm.State().GetServiceRegistrationByID(ws, services[0].Namespace, services[0].ID)
  3376  	assert.Nil(t, err)
  3377  	assert.Nil(t, out)
  3378  
  3379  	out, err = fsm.State().GetServiceRegistrationByID(ws, services[1].Namespace, services[1].ID)
  3380  	assert.Nil(t, err)
  3381  	assert.NotNil(t, out)
  3382  }
  3383  
  3384  func TestFSM_DeleteServiceRegistrationsByNodeID(t *testing.T) {
  3385  	ci.Parallel(t)
  3386  	fsm := testFSM(t)
  3387  
  3388  	// Generate our test service registrations. Set them both to have the same
  3389  	// node ID.
  3390  	services := mock.ServiceRegistrations()
  3391  	services[1].NodeID = services[0].NodeID
  3392  
  3393  	// Upsert the services.
  3394  	assert.NoError(t, fsm.State().UpsertServiceRegistrations(structs.MsgTypeTestSetup, uint64(10), services))
  3395  
  3396  	// Build and apply our message.
  3397  	req := structs.ServiceRegistrationDeleteByNodeIDRequest{NodeID: services[0].NodeID}
  3398  	buf, err := structs.Encode(structs.ServiceRegistrationDeleteByNodeIDRequestType, req)
  3399  	assert.Nil(t, err)
  3400  	assert.Nil(t, fsm.Apply(makeLog(buf)))
  3401  
  3402  	// Check both services have been removed.
  3403  	ws := memdb.NewWatchSet()
  3404  	out, err := fsm.State().GetServiceRegistrationByID(ws, services[0].Namespace, services[0].ID)
  3405  	assert.Nil(t, err)
  3406  	assert.Nil(t, out)
  3407  
  3408  	out, err = fsm.State().GetServiceRegistrationByID(ws, services[1].Namespace, services[1].ID)
  3409  	assert.Nil(t, err)
  3410  	assert.Nil(t, out)
  3411  }
  3412  
  3413  func TestFSM_SnapshotRestore_Variables(t *testing.T) {
  3414  	ci.Parallel(t)
  3415  
  3416  	// Create our initial FSM which will be snapshotted.
  3417  	fsm := testFSM(t)
  3418  	testState := fsm.State()
  3419  
  3420  	// Generate and upsert some variables.
  3421  	msvs := mock.VariablesEncrypted(3, 3)
  3422  	svs := msvs.List()
  3423  
  3424  	for _, sv := range svs {
  3425  		setResp := testState.VarSet(10, &structs.VarApplyStateRequest{
  3426  			Op:  structs.VarOpSet,
  3427  			Var: sv,
  3428  		})
  3429  		require.NoError(t, setResp.Error)
  3430  	}
  3431  
  3432  	// Update the mock variables data with the actual create information
  3433  	iter, err := testState.Variables(memdb.NewWatchSet())
  3434  	require.NoError(t, err)
  3435  
  3436  	for raw := iter.Next(); raw != nil; raw = iter.Next() {
  3437  		sv := raw.(*structs.VariableEncrypted)
  3438  		msvs[sv.Path].CreateIndex = sv.CreateIndex
  3439  		msvs[sv.Path].CreateTime = sv.CreateTime
  3440  		msvs[sv.Path].ModifyIndex = sv.ModifyIndex
  3441  		msvs[sv.Path].ModifyTime = sv.ModifyTime
  3442  	}
  3443  	svs = msvs.List()
  3444  
  3445  	// List the variables from restored state and ensure everything
  3446  	// is as expected.
  3447  
  3448  	// Perform a snapshot restore.
  3449  	restoredFSM := testSnapshotRestore(t, fsm)
  3450  	restoredState := restoredFSM.State()
  3451  
  3452  	// List the variables from restored state and ensure everything
  3453  	// is as expected.
  3454  	iter, err = restoredState.Variables(memdb.NewWatchSet())
  3455  	require.NoError(t, err)
  3456  
  3457  	var restoredSVs []*structs.VariableEncrypted
  3458  
  3459  	for raw := iter.Next(); raw != nil; raw = iter.Next() {
  3460  		restoredSVs = append(restoredSVs, raw.(*structs.VariableEncrypted))
  3461  	}
  3462  	require.ElementsMatch(t, restoredSVs, svs)
  3463  }
  3464  
  3465  func TestFSM_ApplyACLRolesUpsert(t *testing.T) {
  3466  	ci.Parallel(t)
  3467  	fsm := testFSM(t)
  3468  
  3469  	// Create the policies our ACL roles wants to link to.
  3470  	policy1 := mock.ACLPolicy()
  3471  	policy1.Name = "mocked-test-policy-1"
  3472  	policy2 := mock.ACLPolicy()
  3473  	policy2.Name = "mocked-test-policy-2"
  3474  
  3475  	require.NoError(t, fsm.State().UpsertACLPolicies(
  3476  		structs.MsgTypeTestSetup, 10, []*structs.ACLPolicy{policy1, policy2}))
  3477  
  3478  	// Generate the upsert request and apply the change.
  3479  	req := structs.ACLRolesUpsertRequest{
  3480  		ACLRoles: []*structs.ACLRole{mock.ACLRole(), mock.ACLRole()},
  3481  	}
  3482  	buf, err := structs.Encode(structs.ACLRolesUpsertRequestType, req)
  3483  	require.NoError(t, err)
  3484  	require.Nil(t, fsm.Apply(makeLog(buf)))
  3485  
  3486  	// Read out both ACL roles and perform an equality check using the hash.
  3487  	ws := memdb.NewWatchSet()
  3488  	out, err := fsm.State().GetACLRoleByName(ws, req.ACLRoles[0].Name)
  3489  	require.NoError(t, err)
  3490  	require.Equal(t, req.ACLRoles[0].Hash, out.Hash)
  3491  
  3492  	out, err = fsm.State().GetACLRoleByName(ws, req.ACLRoles[1].Name)
  3493  	require.NoError(t, err)
  3494  	require.Equal(t, req.ACLRoles[1].Hash, out.Hash)
  3495  }
  3496  
  3497  func TestFSM_ApplyACLRolesDeleteByID(t *testing.T) {
  3498  	ci.Parallel(t)
  3499  	fsm := testFSM(t)
  3500  
  3501  	// Create the policies our ACL roles wants to link to.
  3502  	policy1 := mock.ACLPolicy()
  3503  	policy1.Name = "mocked-test-policy-1"
  3504  	policy2 := mock.ACLPolicy()
  3505  	policy2.Name = "mocked-test-policy-2"
  3506  
  3507  	require.NoError(t, fsm.State().UpsertACLPolicies(
  3508  		structs.MsgTypeTestSetup, 10, []*structs.ACLPolicy{policy1, policy2}))
  3509  
  3510  	// Generate and upsert two ACL roles.
  3511  	aclRoles := []*structs.ACLRole{mock.ACLRole(), mock.ACLRole()}
  3512  	require.NoError(t, fsm.State().UpsertACLRoles(structs.MsgTypeTestSetup, 10, aclRoles, false))
  3513  
  3514  	// Build and apply our message.
  3515  	req := structs.ACLRolesDeleteByIDRequest{ACLRoleIDs: []string{aclRoles[0].ID, aclRoles[1].ID}}
  3516  	buf, err := structs.Encode(structs.ACLRolesDeleteByIDRequestType, req)
  3517  	require.NoError(t, err)
  3518  	require.Nil(t, fsm.Apply(makeLog(buf)))
  3519  
  3520  	// List all ACL roles within state to ensure both have been removed.
  3521  	ws := memdb.NewWatchSet()
  3522  	iter, err := fsm.State().GetACLRoles(ws)
  3523  	require.NoError(t, err)
  3524  
  3525  	var count int
  3526  	for raw := iter.Next(); raw != nil; raw = iter.Next() {
  3527  		count++
  3528  	}
  3529  	require.Equal(t, 0, count)
  3530  }
  3531  
  3532  func TestFSM_ACLEvents(t *testing.T) {
  3533  	ci.Parallel(t)
  3534  
  3535  	cases := []struct {
  3536  		desc     string
  3537  		setupfn  func(t *testing.T, fsm *nomadFSM)
  3538  		raftReq  func(t *testing.T) []byte
  3539  		reqTopic structs.Topic
  3540  		eventfn  func(t *testing.T, e []structs.Event)
  3541  	}{
  3542  		{
  3543  			desc: "ACLToken upserted",
  3544  			raftReq: func(t *testing.T) []byte {
  3545  				req := structs.ACLTokenUpsertRequest{
  3546  					Tokens: []*structs.ACLToken{mock.ACLToken()},
  3547  				}
  3548  				buf, err := structs.Encode(structs.ACLTokenUpsertRequestType, req)
  3549  				require.NoError(t, err)
  3550  				return buf
  3551  			},
  3552  			reqTopic: structs.TopicACLToken,
  3553  			eventfn: func(t *testing.T, e []structs.Event) {
  3554  				require.Len(t, e, 1)
  3555  				require.Equal(t, e[0].Topic, structs.TopicACLToken)
  3556  				require.Empty(t, e[0].Payload.(*structs.ACLTokenEvent).ACLToken.SecretID)
  3557  				require.Equal(t, e[0].Type, structs.TypeACLTokenUpserted)
  3558  			},
  3559  		},
  3560  		{
  3561  			desc: "ACLToken deleted",
  3562  			setupfn: func(t *testing.T, fsm *nomadFSM) {
  3563  				token := mock.ACLToken()
  3564  				token.SecretID = "26be01d3-df3a-45e9-9f49-4487a3dc3496"
  3565  				token.AccessorID = "b971acba-bbe5-4274-bdfa-8bb1f542a8c1"
  3566  
  3567  				require.NoError(t,
  3568  					fsm.State().UpsertACLTokens(
  3569  						structs.MsgTypeTestSetup, 10, []*structs.ACLToken{token}))
  3570  			},
  3571  			raftReq: func(t *testing.T) []byte {
  3572  				req := structs.ACLTokenDeleteRequest{
  3573  					AccessorIDs: []string{"b971acba-bbe5-4274-bdfa-8bb1f542a8c1"},
  3574  				}
  3575  				buf, err := structs.Encode(structs.ACLTokenDeleteRequestType, req)
  3576  				require.NoError(t, err)
  3577  				return buf
  3578  			},
  3579  			reqTopic: structs.TopicACLToken,
  3580  			eventfn: func(t *testing.T, e []structs.Event) {
  3581  				require.Len(t, e, 1)
  3582  				require.Equal(t, e[0].Topic, structs.TopicACLToken)
  3583  				require.Empty(t, e[0].Payload.(*structs.ACLTokenEvent).ACLToken.SecretID)
  3584  				require.Equal(t, e[0].Type, structs.TypeACLTokenDeleted)
  3585  			},
  3586  		},
  3587  		{
  3588  			desc: "ACLPolicy upserted",
  3589  			raftReq: func(t *testing.T) []byte {
  3590  				req := structs.ACLPolicyUpsertRequest{
  3591  					Policies: []*structs.ACLPolicy{mock.ACLPolicy()},
  3592  				}
  3593  				buf, err := structs.Encode(structs.ACLPolicyUpsertRequestType, req)
  3594  				require.NoError(t, err)
  3595  				return buf
  3596  			},
  3597  			reqTopic: structs.TopicACLPolicy,
  3598  			eventfn: func(t *testing.T, e []structs.Event) {
  3599  				require.Len(t, e, 1)
  3600  				require.Equal(t, e[0].Topic, structs.TopicACLPolicy)
  3601  				require.Equal(t, e[0].Type, structs.TypeACLPolicyUpserted)
  3602  			},
  3603  		},
  3604  		{
  3605  			desc: "ACLPolicy deleted",
  3606  			setupfn: func(t *testing.T, fsm *nomadFSM) {
  3607  				policy := mock.ACLPolicy()
  3608  				policy.Name = "some-policy"
  3609  
  3610  				require.NoError(t,
  3611  					fsm.State().UpsertACLPolicies(
  3612  						structs.MsgTypeTestSetup, 10, []*structs.ACLPolicy{policy}))
  3613  			},
  3614  			raftReq: func(t *testing.T) []byte {
  3615  				req := structs.ACLPolicyDeleteRequest{
  3616  					Names: []string{"some-policy"},
  3617  				}
  3618  				buf, err := structs.Encode(structs.ACLPolicyDeleteRequestType, req)
  3619  				require.NoError(t, err)
  3620  				return buf
  3621  			},
  3622  			reqTopic: structs.TopicACLPolicy,
  3623  			eventfn: func(t *testing.T, e []structs.Event) {
  3624  				require.Len(t, e, 1)
  3625  				require.Equal(t, e[0].Topic, structs.TopicACLPolicy)
  3626  				require.Equal(t, e[0].Type, structs.TypeACLPolicyDeleted)
  3627  			},
  3628  		},
  3629  	}
  3630  
  3631  	for _, tc := range cases {
  3632  		t.Run(tc.desc, func(t *testing.T) {
  3633  			fsm := testFSM(t)
  3634  
  3635  			// Setup any state necessary
  3636  			if tc.setupfn != nil {
  3637  				tc.setupfn(t, fsm)
  3638  			}
  3639  
  3640  			// Apply the log
  3641  			resp := fsm.Apply(makeLog(tc.raftReq(t)))
  3642  			require.Nil(t, resp)
  3643  
  3644  			broker, err := fsm.State().EventBroker()
  3645  			require.NoError(t, err)
  3646  
  3647  			subReq := &stream.SubscribeRequest{
  3648  				Topics: map[structs.Topic][]string{
  3649  					tc.reqTopic: {"*"},
  3650  				},
  3651  				Namespace: "default",
  3652  			}
  3653  
  3654  			sub, err := broker.Subscribe(subReq)
  3655  			require.NoError(t, err)
  3656  
  3657  			var events []structs.Event
  3658  
  3659  			testutil.WaitForResult(func() (bool, error) {
  3660  				out, err := sub.NextNoBlock()
  3661  				require.NoError(t, err)
  3662  
  3663  				if out == nil {
  3664  					return false, fmt.Errorf("expected events got nil")
  3665  				}
  3666  
  3667  				events = out
  3668  				return true, nil
  3669  			}, func(err error) {
  3670  				require.Fail(t, err.Error())
  3671  			})
  3672  
  3673  			tc.eventfn(t, events)
  3674  		})
  3675  	}
  3676  }
  3677  
  3678  // TestFSM_EventBroker_JobRegisterFSMEvents asserts that only a single job
  3679  // register event is emitted when registering a job
  3680  func TestFSM_EventBroker_JobRegisterFSMEvents(t *testing.T) {
  3681  	ci.Parallel(t)
  3682  	fsm := testFSM(t)
  3683  
  3684  	job := mock.Job()
  3685  	eval := mock.Eval()
  3686  	eval.JobID = job.ID
  3687  
  3688  	req := structs.JobRegisterRequest{
  3689  		Job:  job,
  3690  		Eval: eval,
  3691  	}
  3692  	buf, err := structs.Encode(structs.JobRegisterRequestType, req)
  3693  	require.NoError(t, err)
  3694  
  3695  	resp := fsm.Apply(makeLog(buf))
  3696  	require.Nil(t, resp)
  3697  
  3698  	broker, err := fsm.State().EventBroker()
  3699  	require.NoError(t, err)
  3700  
  3701  	subReq := &stream.SubscribeRequest{
  3702  		Topics: map[structs.Topic][]string{
  3703  			structs.TopicJob: {"*"},
  3704  		},
  3705  		Namespace: "default",
  3706  	}
  3707  
  3708  	sub, err := broker.Subscribe(subReq)
  3709  	require.NoError(t, err)
  3710  
  3711  	ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(500*time.Millisecond))
  3712  	defer cancel()
  3713  
  3714  	// consume the queue
  3715  	var events []structs.Event
  3716  	for {
  3717  		out, err := sub.Next(ctx)
  3718  		if len(out.Events) == 0 {
  3719  			break
  3720  		}
  3721  
  3722  		// consume the queue until the deadline has exceeded or until we've
  3723  		// received more events than  expected
  3724  		if err == context.DeadlineExceeded || len(events) > 1 {
  3725  			break
  3726  		}
  3727  
  3728  		events = append(events, out.Events...)
  3729  	}
  3730  
  3731  	require.Len(t, events, 1)
  3732  	require.Equal(t, structs.TypeJobRegistered, events[0].Type)
  3733  }
  3734  
  3735  func TestFSM_UpsertACLAuthMethods(t *testing.T) {
  3736  	ci.Parallel(t)
  3737  	fsm := testFSM(t)
  3738  
  3739  	am1 := mock.ACLOIDCAuthMethod()
  3740  	am2 := mock.ACLOIDCAuthMethod()
  3741  	req := structs.ACLAuthMethodUpsertRequest{
  3742  		AuthMethods: []*structs.ACLAuthMethod{am1, am2},
  3743  	}
  3744  	buf, err := structs.Encode(structs.ACLAuthMethodsUpsertRequestType, req)
  3745  	must.Nil(t, err)
  3746  	must.Nil(t, fsm.Apply(makeLog(buf)))
  3747  
  3748  	// Verify we are registered
  3749  	ws := memdb.NewWatchSet()
  3750  	out, err := fsm.State().GetACLAuthMethodByName(ws, am1.Name)
  3751  	must.Nil(t, err)
  3752  	must.NotNil(t, out)
  3753  
  3754  	out, err = fsm.State().GetACLAuthMethodByName(ws, am2.Name)
  3755  	must.Nil(t, err)
  3756  	must.NotNil(t, out)
  3757  }
  3758  
  3759  func TestFSM_DeleteACLAuthMethods(t *testing.T) {
  3760  	ci.Parallel(t)
  3761  	fsm := testFSM(t)
  3762  
  3763  	am1 := mock.ACLOIDCAuthMethod()
  3764  	am2 := mock.ACLOIDCAuthMethod()
  3765  	must.Nil(t, fsm.State().UpsertACLAuthMethods(1000, []*structs.ACLAuthMethod{am1, am2}))
  3766  
  3767  	req := structs.ACLAuthMethodDeleteRequest{
  3768  		Names: []string{am1.Name, am2.Name},
  3769  	}
  3770  	buf, err := structs.Encode(structs.ACLAuthMethodsDeleteRequestType, req)
  3771  	must.Nil(t, err)
  3772  	must.Nil(t, fsm.Apply(makeLog(buf)))
  3773  
  3774  	// Verify we are NOT registered
  3775  	ws := memdb.NewWatchSet()
  3776  	out, err := fsm.State().GetACLAuthMethodByName(ws, am1.Name)
  3777  	must.Nil(t, err)
  3778  	must.Nil(t, out)
  3779  
  3780  	out, err = fsm.State().GetACLAuthMethodByName(ws, am2.Name)
  3781  	must.Nil(t, err)
  3782  	must.Nil(t, out)
  3783  }
  3784  
  3785  func TestFSM_UpsertACLBindingRules(t *testing.T) {
  3786  	ci.Parallel(t)
  3787  	fsm := testFSM(t)
  3788  
  3789  	// Create an auth method and upsert so the binding rules can link to this.
  3790  	authMethod := mock.ACLOIDCAuthMethod()
  3791  	must.NoError(t, fsm.state.UpsertACLAuthMethods(10, []*structs.ACLAuthMethod{authMethod}))
  3792  
  3793  	aclBindingRule1 := mock.ACLBindingRule()
  3794  	aclBindingRule1.AuthMethod = authMethod.Name
  3795  	aclBindingRule2 := mock.ACLBindingRule()
  3796  	aclBindingRule2.AuthMethod = authMethod.Name
  3797  
  3798  	req := structs.ACLBindingRulesUpsertRequest{
  3799  		ACLBindingRules: []*structs.ACLBindingRule{aclBindingRule1, aclBindingRule2},
  3800  	}
  3801  	buf, err := structs.Encode(structs.ACLBindingRulesUpsertRequestType, req)
  3802  	must.NoError(t, err)
  3803  	must.Nil(t, fsm.Apply(makeLog(buf)))
  3804  
  3805  	// Ensure the ACL binding rules have been upserted correctly.
  3806  	ws := memdb.NewWatchSet()
  3807  	out, err := fsm.State().GetACLBindingRule(ws, aclBindingRule1.ID)
  3808  	must.Nil(t, err)
  3809  	must.Eq(t, aclBindingRule1, out)
  3810  
  3811  	out, err = fsm.State().GetACLBindingRule(ws, aclBindingRule2.ID)
  3812  	must.Nil(t, err)
  3813  	must.Eq(t, aclBindingRule2, out)
  3814  }
  3815  
  3816  func TestFSM_DeleteACLBindingRules(t *testing.T) {
  3817  	ci.Parallel(t)
  3818  	fsm := testFSM(t)
  3819  
  3820  	aclBindingRule1 := mock.ACLBindingRule()
  3821  	aclBindingRule2 := mock.ACLBindingRule()
  3822  	must.NoError(t, fsm.State().UpsertACLBindingRules(
  3823  		10, []*structs.ACLBindingRule{aclBindingRule1, aclBindingRule2}, true))
  3824  
  3825  	req := structs.ACLBindingRulesDeleteRequest{
  3826  		ACLBindingRuleIDs: []string{aclBindingRule1.ID, aclBindingRule2.ID},
  3827  	}
  3828  	buf, err := structs.Encode(structs.ACLBindingRulesDeleteRequestType, req)
  3829  	must.NoError(t, err)
  3830  	must.Nil(t, fsm.Apply(makeLog(buf)))
  3831  
  3832  	// Ensure neither ACL binding rule is now found.
  3833  	ws := memdb.NewWatchSet()
  3834  	out, err := fsm.State().GetACLBindingRule(ws, aclBindingRule1.ID)
  3835  	must.NoError(t, err)
  3836  	must.Nil(t, out)
  3837  
  3838  	out, err = fsm.State().GetACLBindingRule(ws, aclBindingRule2.ID)
  3839  	must.NoError(t, err)
  3840  	must.Nil(t, out)
  3841  }