github.com/manicqin/nomad@v0.9.5/nomad/fsm_test.go (about)

     1  package nomad
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"reflect"
     7  	"strings"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/google/go-cmp/cmp"
    12  	memdb "github.com/hashicorp/go-memdb"
    13  	"github.com/hashicorp/nomad/helper"
    14  	"github.com/hashicorp/nomad/helper/testlog"
    15  	"github.com/hashicorp/nomad/helper/uuid"
    16  	"github.com/hashicorp/nomad/nomad/mock"
    17  	"github.com/hashicorp/nomad/nomad/state"
    18  	"github.com/hashicorp/nomad/nomad/structs"
    19  	"github.com/hashicorp/nomad/testutil"
    20  	"github.com/hashicorp/raft"
    21  	"github.com/kr/pretty"
    22  	"github.com/stretchr/testify/assert"
    23  	"github.com/stretchr/testify/require"
    24  )
    25  
    26  type MockSink struct {
    27  	*bytes.Buffer
    28  	cancel bool
    29  }
    30  
    31  func (m *MockSink) ID() string {
    32  	return "Mock"
    33  }
    34  
    35  func (m *MockSink) Cancel() error {
    36  	m.cancel = true
    37  	return nil
    38  }
    39  
    40  func (m *MockSink) Close() error {
    41  	return nil
    42  }
    43  
    44  func testStateStore(t *testing.T) *state.StateStore {
    45  	return state.TestStateStore(t)
    46  }
    47  
    48  func testFSM(t *testing.T) *nomadFSM {
    49  	broker := testBroker(t, 0)
    50  	dispatcher, _ := testPeriodicDispatcher(t)
    51  	logger := testlog.HCLogger(t)
    52  	fsmConfig := &FSMConfig{
    53  		EvalBroker: broker,
    54  		Periodic:   dispatcher,
    55  		Blocked:    NewBlockedEvals(broker, logger),
    56  		Logger:     logger,
    57  		Region:     "global",
    58  	}
    59  	fsm, err := NewFSM(fsmConfig)
    60  	if err != nil {
    61  		t.Fatalf("err: %v", err)
    62  	}
    63  	if fsm == nil {
    64  		t.Fatalf("missing fsm")
    65  	}
    66  	state.TestInitState(t, fsm.state)
    67  	return fsm
    68  }
    69  
    70  func makeLog(buf []byte) *raft.Log {
    71  	return &raft.Log{
    72  		Index: 1,
    73  		Term:  1,
    74  		Type:  raft.LogCommand,
    75  		Data:  buf,
    76  	}
    77  }
    78  
    79  func TestFSM_UpsertNodeEvents(t *testing.T) {
    80  	t.Parallel()
    81  	require := require.New(t)
    82  	fsm := testFSM(t)
    83  	state := fsm.State()
    84  
    85  	node := mock.Node()
    86  
    87  	err := state.UpsertNode(1000, node)
    88  	if err != nil {
    89  		t.Fatalf("err: %v", err)
    90  	}
    91  
    92  	nodeEvent := &structs.NodeEvent{
    93  		Message:   "Heartbeating failed",
    94  		Subsystem: "Heartbeat",
    95  		Timestamp: time.Now(),
    96  	}
    97  
    98  	nodeEvents := []*structs.NodeEvent{nodeEvent}
    99  	allEvents := map[string][]*structs.NodeEvent{node.ID: nodeEvents}
   100  
   101  	req := structs.EmitNodeEventsRequest{
   102  		NodeEvents:   allEvents,
   103  		WriteRequest: structs.WriteRequest{Region: "global"},
   104  	}
   105  	buf, err := structs.Encode(structs.UpsertNodeEventsType, req)
   106  	require.Nil(err)
   107  
   108  	// the response in this case will be an error
   109  	resp := fsm.Apply(makeLog(buf))
   110  	require.Nil(resp)
   111  
   112  	ws := memdb.NewWatchSet()
   113  	out, err := state.NodeByID(ws, node.ID)
   114  	require.Nil(err)
   115  
   116  	require.Equal(2, len(out.Events))
   117  
   118  	first := out.Events[1]
   119  	require.Equal(uint64(1), first.CreateIndex)
   120  	require.Equal("Heartbeating failed", first.Message)
   121  }
   122  
   123  func TestFSM_UpsertNode(t *testing.T) {
   124  	t.Parallel()
   125  	fsm := testFSM(t)
   126  	fsm.blockedEvals.SetEnabled(true)
   127  
   128  	node := mock.Node()
   129  
   130  	// Mark an eval as blocked.
   131  	eval := mock.Eval()
   132  	eval.ClassEligibility = map[string]bool{node.ComputedClass: true}
   133  	fsm.blockedEvals.Block(eval)
   134  
   135  	req := structs.NodeRegisterRequest{
   136  		Node: node,
   137  	}
   138  	buf, err := structs.Encode(structs.NodeRegisterRequestType, req)
   139  	if err != nil {
   140  		t.Fatalf("err: %v", err)
   141  	}
   142  
   143  	resp := fsm.Apply(makeLog(buf))
   144  	if resp != nil {
   145  		t.Fatalf("resp: %v", resp)
   146  	}
   147  
   148  	// Verify we are registered
   149  	ws := memdb.NewWatchSet()
   150  	n, err := fsm.State().NodeByID(ws, req.Node.ID)
   151  	if err != nil {
   152  		t.Fatalf("err: %v", err)
   153  	}
   154  	if n == nil {
   155  		t.Fatalf("not found!")
   156  	}
   157  	if n.CreateIndex != 1 {
   158  		t.Fatalf("bad index: %d", node.CreateIndex)
   159  	}
   160  
   161  	tt := fsm.TimeTable()
   162  	index := tt.NearestIndex(time.Now().UTC())
   163  	if index != 1 {
   164  		t.Fatalf("bad: %d", index)
   165  	}
   166  
   167  	// Verify the eval was unblocked.
   168  	testutil.WaitForResult(func() (bool, error) {
   169  		bStats := fsm.blockedEvals.Stats()
   170  		if bStats.TotalBlocked != 0 {
   171  			return false, fmt.Errorf("bad: %#v", bStats)
   172  		}
   173  		return true, nil
   174  	}, func(err error) {
   175  		t.Fatalf("err: %s", err)
   176  	})
   177  
   178  }
   179  
   180  func TestFSM_UpsertNode_Canonicalize(t *testing.T) {
   181  	t.Parallel()
   182  	require := require.New(t)
   183  
   184  	fsm := testFSM(t)
   185  	fsm.blockedEvals.SetEnabled(true)
   186  
   187  	// Setup a node without eligiblity
   188  	node := mock.Node()
   189  	node.SchedulingEligibility = ""
   190  
   191  	req := structs.NodeRegisterRequest{
   192  		Node: node,
   193  	}
   194  	buf, err := structs.Encode(structs.NodeRegisterRequestType, req)
   195  	require.Nil(err)
   196  
   197  	resp := fsm.Apply(makeLog(buf))
   198  	require.Nil(resp)
   199  
   200  	// Verify we are registered
   201  	ws := memdb.NewWatchSet()
   202  	n, err := fsm.State().NodeByID(ws, req.Node.ID)
   203  	require.Nil(err)
   204  	require.NotNil(n)
   205  	require.EqualValues(1, n.CreateIndex)
   206  	require.Equal(structs.NodeSchedulingEligible, n.SchedulingEligibility)
   207  }
   208  
   209  func TestFSM_DeregisterNode(t *testing.T) {
   210  	t.Parallel()
   211  	fsm := testFSM(t)
   212  
   213  	node := mock.Node()
   214  	req := structs.NodeRegisterRequest{
   215  		Node: node,
   216  	}
   217  	buf, err := structs.Encode(structs.NodeRegisterRequestType, req)
   218  	if err != nil {
   219  		t.Fatalf("err: %v", err)
   220  	}
   221  
   222  	resp := fsm.Apply(makeLog(buf))
   223  	if resp != nil {
   224  		t.Fatalf("resp: %v", resp)
   225  	}
   226  
   227  	req2 := structs.NodeBatchDeregisterRequest{
   228  		NodeIDs: []string{node.ID},
   229  	}
   230  	buf, err = structs.Encode(structs.NodeBatchDeregisterRequestType, req2)
   231  	if err != nil {
   232  		t.Fatalf("err: %v", err)
   233  	}
   234  
   235  	resp = fsm.Apply(makeLog(buf))
   236  	if resp != nil {
   237  		t.Fatalf("resp: %v", resp)
   238  	}
   239  
   240  	// Verify we are NOT registered
   241  	ws := memdb.NewWatchSet()
   242  	node, err = fsm.State().NodeByID(ws, req.Node.ID)
   243  	if err != nil {
   244  		t.Fatalf("err: %v", err)
   245  	}
   246  	if node != nil {
   247  		t.Fatalf("node found!")
   248  	}
   249  }
   250  
   251  func TestFSM_UpdateNodeStatus(t *testing.T) {
   252  	t.Parallel()
   253  	require := require.New(t)
   254  	fsm := testFSM(t)
   255  	fsm.blockedEvals.SetEnabled(true)
   256  
   257  	node := mock.Node()
   258  	req := structs.NodeRegisterRequest{
   259  		Node: node,
   260  	}
   261  	buf, err := structs.Encode(structs.NodeRegisterRequestType, req)
   262  	require.NoError(err)
   263  
   264  	resp := fsm.Apply(makeLog(buf))
   265  	require.Nil(resp)
   266  
   267  	// Mark an eval as blocked.
   268  	eval := mock.Eval()
   269  	eval.ClassEligibility = map[string]bool{node.ComputedClass: true}
   270  	fsm.blockedEvals.Block(eval)
   271  
   272  	event := &structs.NodeEvent{
   273  		Message:   "Node ready foo",
   274  		Subsystem: structs.NodeEventSubsystemCluster,
   275  		Timestamp: time.Now(),
   276  	}
   277  	req2 := structs.NodeUpdateStatusRequest{
   278  		NodeID:    node.ID,
   279  		Status:    structs.NodeStatusReady,
   280  		NodeEvent: event,
   281  	}
   282  	buf, err = structs.Encode(structs.NodeUpdateStatusRequestType, req2)
   283  	require.NoError(err)
   284  
   285  	resp = fsm.Apply(makeLog(buf))
   286  	require.Nil(resp)
   287  
   288  	// Verify the status is ready.
   289  	ws := memdb.NewWatchSet()
   290  	node, err = fsm.State().NodeByID(ws, req.Node.ID)
   291  	require.NoError(err)
   292  	require.Equal(structs.NodeStatusReady, node.Status)
   293  	require.Len(node.Events, 2)
   294  	require.Equal(event.Message, node.Events[1].Message)
   295  
   296  	// Verify the eval was unblocked.
   297  	testutil.WaitForResult(func() (bool, error) {
   298  		bStats := fsm.blockedEvals.Stats()
   299  		if bStats.TotalBlocked != 0 {
   300  			return false, fmt.Errorf("bad: %#v", bStats)
   301  		}
   302  		return true, nil
   303  	}, func(err error) {
   304  		t.Fatalf("err: %s", err)
   305  	})
   306  }
   307  
   308  func TestFSM_BatchUpdateNodeDrain(t *testing.T) {
   309  	t.Parallel()
   310  	require := require.New(t)
   311  	fsm := testFSM(t)
   312  
   313  	node := mock.Node()
   314  	req := structs.NodeRegisterRequest{
   315  		Node: node,
   316  	}
   317  	buf, err := structs.Encode(structs.NodeRegisterRequestType, req)
   318  	require.Nil(err)
   319  
   320  	resp := fsm.Apply(makeLog(buf))
   321  	require.Nil(resp)
   322  
   323  	strategy := &structs.DrainStrategy{
   324  		DrainSpec: structs.DrainSpec{
   325  			Deadline: 10 * time.Second,
   326  		},
   327  	}
   328  	event := &structs.NodeEvent{
   329  		Message:   "Drain strategy enabled",
   330  		Subsystem: structs.NodeEventSubsystemDrain,
   331  		Timestamp: time.Now(),
   332  	}
   333  	req2 := structs.BatchNodeUpdateDrainRequest{
   334  		Updates: map[string]*structs.DrainUpdate{
   335  			node.ID: {
   336  				DrainStrategy: strategy,
   337  			},
   338  		},
   339  		NodeEvents: map[string]*structs.NodeEvent{
   340  			node.ID: event,
   341  		},
   342  	}
   343  	buf, err = structs.Encode(structs.BatchNodeUpdateDrainRequestType, req2)
   344  	require.Nil(err)
   345  
   346  	resp = fsm.Apply(makeLog(buf))
   347  	require.Nil(resp)
   348  
   349  	// Verify drain is set
   350  	ws := memdb.NewWatchSet()
   351  	node, err = fsm.State().NodeByID(ws, req.Node.ID)
   352  	require.Nil(err)
   353  	require.True(node.Drain)
   354  	require.Equal(node.DrainStrategy, strategy)
   355  	require.Len(node.Events, 2)
   356  }
   357  
   358  func TestFSM_UpdateNodeDrain(t *testing.T) {
   359  	t.Parallel()
   360  	require := require.New(t)
   361  	fsm := testFSM(t)
   362  
   363  	node := mock.Node()
   364  	req := structs.NodeRegisterRequest{
   365  		Node: node,
   366  	}
   367  	buf, err := structs.Encode(structs.NodeRegisterRequestType, req)
   368  	require.Nil(err)
   369  
   370  	resp := fsm.Apply(makeLog(buf))
   371  	require.Nil(resp)
   372  
   373  	strategy := &structs.DrainStrategy{
   374  		DrainSpec: structs.DrainSpec{
   375  			Deadline: 10 * time.Second,
   376  		},
   377  	}
   378  	req2 := structs.NodeUpdateDrainRequest{
   379  		NodeID:        node.ID,
   380  		DrainStrategy: strategy,
   381  		NodeEvent: &structs.NodeEvent{
   382  			Message:   "Drain strategy enabled",
   383  			Subsystem: structs.NodeEventSubsystemDrain,
   384  			Timestamp: time.Now(),
   385  		},
   386  	}
   387  	buf, err = structs.Encode(structs.NodeUpdateDrainRequestType, req2)
   388  	require.Nil(err)
   389  
   390  	resp = fsm.Apply(makeLog(buf))
   391  	require.Nil(resp)
   392  
   393  	// Verify we are NOT registered
   394  	ws := memdb.NewWatchSet()
   395  	node, err = fsm.State().NodeByID(ws, req.Node.ID)
   396  	require.Nil(err)
   397  	require.True(node.Drain)
   398  	require.Equal(node.DrainStrategy, strategy)
   399  	require.Len(node.Events, 2)
   400  }
   401  
   402  func TestFSM_UpdateNodeDrain_Pre08_Compatibility(t *testing.T) {
   403  	t.Parallel()
   404  	require := require.New(t)
   405  	fsm := testFSM(t)
   406  
   407  	// Force a node into the state store without eligiblity
   408  	node := mock.Node()
   409  	node.SchedulingEligibility = ""
   410  	require.Nil(fsm.State().UpsertNode(1, node))
   411  
   412  	// Do an old style drain
   413  	req := structs.NodeUpdateDrainRequest{
   414  		NodeID: node.ID,
   415  		Drain:  true,
   416  	}
   417  	buf, err := structs.Encode(structs.NodeUpdateDrainRequestType, req)
   418  	require.Nil(err)
   419  
   420  	resp := fsm.Apply(makeLog(buf))
   421  	require.Nil(resp)
   422  
   423  	// Verify we have upgraded to a force drain
   424  	ws := memdb.NewWatchSet()
   425  	node, err = fsm.State().NodeByID(ws, req.NodeID)
   426  	require.Nil(err)
   427  	require.True(node.Drain)
   428  
   429  	expected := &structs.DrainStrategy{
   430  		DrainSpec: structs.DrainSpec{
   431  			Deadline: -1 * time.Second,
   432  		},
   433  	}
   434  	require.Equal(expected, node.DrainStrategy)
   435  }
   436  
   437  func TestFSM_UpdateNodeEligibility(t *testing.T) {
   438  	t.Parallel()
   439  	require := require.New(t)
   440  	fsm := testFSM(t)
   441  
   442  	node := mock.Node()
   443  	req := structs.NodeRegisterRequest{
   444  		Node: node,
   445  	}
   446  	buf, err := structs.Encode(structs.NodeRegisterRequestType, req)
   447  	require.Nil(err)
   448  
   449  	resp := fsm.Apply(makeLog(buf))
   450  	require.Nil(resp)
   451  
   452  	event := &structs.NodeEvent{
   453  		Message:   "Node marked as ineligible",
   454  		Subsystem: structs.NodeEventSubsystemCluster,
   455  		Timestamp: time.Now(),
   456  	}
   457  
   458  	// Set the eligibility
   459  	req2 := structs.NodeUpdateEligibilityRequest{
   460  		NodeID:      node.ID,
   461  		Eligibility: structs.NodeSchedulingIneligible,
   462  		NodeEvent:   event,
   463  	}
   464  	buf, err = structs.Encode(structs.NodeUpdateEligibilityRequestType, req2)
   465  	require.Nil(err)
   466  
   467  	resp = fsm.Apply(makeLog(buf))
   468  	require.Nil(resp)
   469  
   470  	// Lookup the node and check
   471  	node, err = fsm.State().NodeByID(nil, req.Node.ID)
   472  	require.Nil(err)
   473  	require.Equal(node.SchedulingEligibility, structs.NodeSchedulingIneligible)
   474  	require.Len(node.Events, 2)
   475  	require.Equal(event.Message, node.Events[1].Message)
   476  
   477  	// Update the drain
   478  	strategy := &structs.DrainStrategy{
   479  		DrainSpec: structs.DrainSpec{
   480  			Deadline: 10 * time.Second,
   481  		},
   482  	}
   483  	req3 := structs.NodeUpdateDrainRequest{
   484  		NodeID:        node.ID,
   485  		DrainStrategy: strategy,
   486  	}
   487  	buf, err = structs.Encode(structs.NodeUpdateDrainRequestType, req3)
   488  	require.Nil(err)
   489  	resp = fsm.Apply(makeLog(buf))
   490  	require.Nil(resp)
   491  
   492  	// Try forcing eligibility
   493  	req4 := structs.NodeUpdateEligibilityRequest{
   494  		NodeID:      node.ID,
   495  		Eligibility: structs.NodeSchedulingEligible,
   496  	}
   497  	buf, err = structs.Encode(structs.NodeUpdateEligibilityRequestType, req4)
   498  	require.Nil(err)
   499  
   500  	resp = fsm.Apply(makeLog(buf))
   501  	require.NotNil(resp)
   502  	err, ok := resp.(error)
   503  	require.True(ok)
   504  	require.Contains(err.Error(), "draining")
   505  }
   506  
   507  func TestFSM_UpdateNodeEligibility_Unblock(t *testing.T) {
   508  	t.Parallel()
   509  	require := require.New(t)
   510  	fsm := testFSM(t)
   511  
   512  	node := mock.Node()
   513  	req := structs.NodeRegisterRequest{
   514  		Node: node,
   515  	}
   516  	buf, err := structs.Encode(structs.NodeRegisterRequestType, req)
   517  	require.Nil(err)
   518  
   519  	resp := fsm.Apply(makeLog(buf))
   520  	require.Nil(resp)
   521  
   522  	// Set the eligibility
   523  	req2 := structs.NodeUpdateEligibilityRequest{
   524  		NodeID:      node.ID,
   525  		Eligibility: structs.NodeSchedulingIneligible,
   526  	}
   527  	buf, err = structs.Encode(structs.NodeUpdateEligibilityRequestType, req2)
   528  	require.Nil(err)
   529  
   530  	resp = fsm.Apply(makeLog(buf))
   531  	require.Nil(resp)
   532  
   533  	// Mark an eval as blocked.
   534  	eval := mock.Eval()
   535  	eval.ClassEligibility = map[string]bool{node.ComputedClass: true}
   536  	fsm.blockedEvals.Block(eval)
   537  
   538  	// Set eligible
   539  	req4 := structs.NodeUpdateEligibilityRequest{
   540  		NodeID:      node.ID,
   541  		Eligibility: structs.NodeSchedulingEligible,
   542  	}
   543  	buf, err = structs.Encode(structs.NodeUpdateEligibilityRequestType, req4)
   544  	require.Nil(err)
   545  
   546  	resp = fsm.Apply(makeLog(buf))
   547  	require.Nil(resp)
   548  
   549  	// Verify the eval was unblocked.
   550  	testutil.WaitForResult(func() (bool, error) {
   551  		bStats := fsm.blockedEvals.Stats()
   552  		if bStats.TotalBlocked != 0 {
   553  			return false, fmt.Errorf("bad: %#v", bStats)
   554  		}
   555  		return true, nil
   556  	}, func(err error) {
   557  		t.Fatalf("err: %s", err)
   558  	})
   559  }
   560  
   561  func TestFSM_RegisterJob(t *testing.T) {
   562  	t.Parallel()
   563  	fsm := testFSM(t)
   564  
   565  	job := mock.PeriodicJob()
   566  	req := structs.JobRegisterRequest{
   567  		Job: job,
   568  		WriteRequest: structs.WriteRequest{
   569  			Namespace: job.Namespace,
   570  		},
   571  	}
   572  	buf, err := structs.Encode(structs.JobRegisterRequestType, req)
   573  	if err != nil {
   574  		t.Fatalf("err: %v", err)
   575  	}
   576  
   577  	resp := fsm.Apply(makeLog(buf))
   578  	if resp != nil {
   579  		t.Fatalf("resp: %v", resp)
   580  	}
   581  
   582  	// Verify we are registered
   583  	ws := memdb.NewWatchSet()
   584  	jobOut, err := fsm.State().JobByID(ws, req.Namespace, req.Job.ID)
   585  	if err != nil {
   586  		t.Fatalf("err: %v", err)
   587  	}
   588  	if jobOut == nil {
   589  		t.Fatalf("not found!")
   590  	}
   591  	if jobOut.CreateIndex != 1 {
   592  		t.Fatalf("bad index: %d", jobOut.CreateIndex)
   593  	}
   594  
   595  	// Verify it was added to the periodic runner.
   596  	tuple := structs.NamespacedID{
   597  		ID:        job.ID,
   598  		Namespace: job.Namespace,
   599  	}
   600  	if _, ok := fsm.periodicDispatcher.tracked[tuple]; !ok {
   601  		t.Fatal("job not added to periodic runner")
   602  	}
   603  
   604  	// Verify the launch time was tracked.
   605  	launchOut, err := fsm.State().PeriodicLaunchByID(ws, req.Namespace, req.Job.ID)
   606  	if err != nil {
   607  		t.Fatalf("err: %v", err)
   608  	}
   609  	if launchOut == nil {
   610  		t.Fatalf("not found!")
   611  	}
   612  	if launchOut.Launch.IsZero() {
   613  		t.Fatalf("bad launch time: %v", launchOut.Launch)
   614  	}
   615  }
   616  
   617  func TestFSM_RegisterPeriodicJob_NonLeader(t *testing.T) {
   618  	t.Parallel()
   619  	fsm := testFSM(t)
   620  
   621  	// Disable the dispatcher
   622  	fsm.periodicDispatcher.SetEnabled(false)
   623  
   624  	job := mock.PeriodicJob()
   625  	req := structs.JobRegisterRequest{
   626  		Job: job,
   627  		WriteRequest: structs.WriteRequest{
   628  			Namespace: job.Namespace,
   629  		},
   630  	}
   631  	buf, err := structs.Encode(structs.JobRegisterRequestType, req)
   632  	if err != nil {
   633  		t.Fatalf("err: %v", err)
   634  	}
   635  
   636  	resp := fsm.Apply(makeLog(buf))
   637  	if resp != nil {
   638  		t.Fatalf("resp: %v", resp)
   639  	}
   640  
   641  	// Verify we are registered
   642  	ws := memdb.NewWatchSet()
   643  	jobOut, err := fsm.State().JobByID(ws, req.Namespace, req.Job.ID)
   644  	if err != nil {
   645  		t.Fatalf("err: %v", err)
   646  	}
   647  	if jobOut == nil {
   648  		t.Fatalf("not found!")
   649  	}
   650  	if jobOut.CreateIndex != 1 {
   651  		t.Fatalf("bad index: %d", jobOut.CreateIndex)
   652  	}
   653  
   654  	// Verify it wasn't added to the periodic runner.
   655  	tuple := structs.NamespacedID{
   656  		ID:        job.ID,
   657  		Namespace: job.Namespace,
   658  	}
   659  	if _, ok := fsm.periodicDispatcher.tracked[tuple]; ok {
   660  		t.Fatal("job added to periodic runner")
   661  	}
   662  
   663  	// Verify the launch time was tracked.
   664  	launchOut, err := fsm.State().PeriodicLaunchByID(ws, req.Namespace, req.Job.ID)
   665  	if err != nil {
   666  		t.Fatalf("err: %v", err)
   667  	}
   668  	if launchOut == nil {
   669  		t.Fatalf("not found!")
   670  	}
   671  	if launchOut.Launch.IsZero() {
   672  		t.Fatalf("bad launch time: %v", launchOut.Launch)
   673  	}
   674  }
   675  
   676  func TestFSM_RegisterJob_BadNamespace(t *testing.T) {
   677  	t.Parallel()
   678  	fsm := testFSM(t)
   679  
   680  	job := mock.Job()
   681  	job.Namespace = "foo"
   682  	req := structs.JobRegisterRequest{
   683  		Job: job,
   684  		WriteRequest: structs.WriteRequest{
   685  			Namespace: job.Namespace,
   686  		},
   687  	}
   688  	buf, err := structs.Encode(structs.JobRegisterRequestType, req)
   689  	if err != nil {
   690  		t.Fatalf("err: %v", err)
   691  	}
   692  
   693  	resp := fsm.Apply(makeLog(buf))
   694  	if resp == nil {
   695  		t.Fatalf("no resp: %v", resp)
   696  	}
   697  	err, ok := resp.(error)
   698  	if !ok {
   699  		t.Fatalf("resp not of error type: %T %v", resp, resp)
   700  	}
   701  	if !strings.Contains(err.Error(), "nonexistent namespace") {
   702  		t.Fatalf("bad error: %v", err)
   703  	}
   704  
   705  	// Verify we are not registered
   706  	ws := memdb.NewWatchSet()
   707  	jobOut, err := fsm.State().JobByID(ws, req.Namespace, req.Job.ID)
   708  	if err != nil {
   709  		t.Fatalf("err: %v", err)
   710  	}
   711  	if jobOut != nil {
   712  		t.Fatalf("job found!")
   713  	}
   714  }
   715  
   716  func TestFSM_DeregisterJob_Purge(t *testing.T) {
   717  	t.Parallel()
   718  	fsm := testFSM(t)
   719  
   720  	job := mock.PeriodicJob()
   721  	req := structs.JobRegisterRequest{
   722  		Job: job,
   723  		WriteRequest: structs.WriteRequest{
   724  			Namespace: job.Namespace,
   725  		},
   726  	}
   727  	buf, err := structs.Encode(structs.JobRegisterRequestType, req)
   728  	if err != nil {
   729  		t.Fatalf("err: %v", err)
   730  	}
   731  
   732  	resp := fsm.Apply(makeLog(buf))
   733  	if resp != nil {
   734  		t.Fatalf("resp: %v", resp)
   735  	}
   736  
   737  	req2 := structs.JobDeregisterRequest{
   738  		JobID: job.ID,
   739  		Purge: true,
   740  		WriteRequest: structs.WriteRequest{
   741  			Namespace: job.Namespace,
   742  		},
   743  	}
   744  	buf, err = structs.Encode(structs.JobDeregisterRequestType, req2)
   745  	if err != nil {
   746  		t.Fatalf("err: %v", err)
   747  	}
   748  
   749  	resp = fsm.Apply(makeLog(buf))
   750  	if resp != nil {
   751  		t.Fatalf("resp: %v", resp)
   752  	}
   753  
   754  	// Verify we are NOT registered
   755  	ws := memdb.NewWatchSet()
   756  	jobOut, err := fsm.State().JobByID(ws, req.Namespace, req.Job.ID)
   757  	if err != nil {
   758  		t.Fatalf("err: %v", err)
   759  	}
   760  	if jobOut != nil {
   761  		t.Fatalf("job found!")
   762  	}
   763  
   764  	// Verify it was removed from the periodic runner.
   765  	tuple := structs.NamespacedID{
   766  		ID:        job.ID,
   767  		Namespace: job.Namespace,
   768  	}
   769  	if _, ok := fsm.periodicDispatcher.tracked[tuple]; ok {
   770  		t.Fatal("job not removed from periodic runner")
   771  	}
   772  
   773  	// Verify it was removed from the periodic launch table.
   774  	launchOut, err := fsm.State().PeriodicLaunchByID(ws, req.Namespace, req.Job.ID)
   775  	if err != nil {
   776  		t.Fatalf("err: %v", err)
   777  	}
   778  	if launchOut != nil {
   779  		t.Fatalf("launch found!")
   780  	}
   781  }
   782  
   783  func TestFSM_DeregisterJob_NoPurge(t *testing.T) {
   784  	t.Parallel()
   785  	fsm := testFSM(t)
   786  
   787  	job := mock.PeriodicJob()
   788  	req := structs.JobRegisterRequest{
   789  		Job: job,
   790  		WriteRequest: structs.WriteRequest{
   791  			Namespace: job.Namespace,
   792  		},
   793  	}
   794  	buf, err := structs.Encode(structs.JobRegisterRequestType, req)
   795  	if err != nil {
   796  		t.Fatalf("err: %v", err)
   797  	}
   798  
   799  	resp := fsm.Apply(makeLog(buf))
   800  	if resp != nil {
   801  		t.Fatalf("resp: %v", resp)
   802  	}
   803  
   804  	req2 := structs.JobDeregisterRequest{
   805  		JobID: job.ID,
   806  		Purge: false,
   807  		WriteRequest: structs.WriteRequest{
   808  			Namespace: job.Namespace,
   809  		},
   810  	}
   811  	buf, err = structs.Encode(structs.JobDeregisterRequestType, req2)
   812  	if err != nil {
   813  		t.Fatalf("err: %v", err)
   814  	}
   815  
   816  	resp = fsm.Apply(makeLog(buf))
   817  	if resp != nil {
   818  		t.Fatalf("resp: %v", resp)
   819  	}
   820  
   821  	// Verify we are NOT registered
   822  	ws := memdb.NewWatchSet()
   823  	jobOut, err := fsm.State().JobByID(ws, req.Namespace, req.Job.ID)
   824  	if err != nil {
   825  		t.Fatalf("err: %v", err)
   826  	}
   827  	if jobOut == nil {
   828  		t.Fatalf("job not found!")
   829  	}
   830  	if !jobOut.Stop {
   831  		t.Fatalf("job not stopped found!")
   832  	}
   833  
   834  	// Verify it was removed from the periodic runner.
   835  	tuple := structs.NamespacedID{
   836  		ID:        job.ID,
   837  		Namespace: job.Namespace,
   838  	}
   839  	if _, ok := fsm.periodicDispatcher.tracked[tuple]; ok {
   840  		t.Fatal("job not removed from periodic runner")
   841  	}
   842  
   843  	// Verify it was removed from the periodic launch table.
   844  	launchOut, err := fsm.State().PeriodicLaunchByID(ws, req.Namespace, req.Job.ID)
   845  	if err != nil {
   846  		t.Fatalf("err: %v", err)
   847  	}
   848  	if launchOut == nil {
   849  		t.Fatalf("launch not found!")
   850  	}
   851  }
   852  
   853  func TestFSM_BatchDeregisterJob(t *testing.T) {
   854  	t.Parallel()
   855  	require := require.New(t)
   856  	fsm := testFSM(t)
   857  
   858  	job := mock.PeriodicJob()
   859  	req := structs.JobRegisterRequest{
   860  		Job: job,
   861  		WriteRequest: structs.WriteRequest{
   862  			Namespace: job.Namespace,
   863  		},
   864  	}
   865  	buf, err := structs.Encode(structs.JobRegisterRequestType, req)
   866  	require.Nil(err)
   867  	resp := fsm.Apply(makeLog(buf))
   868  	require.Nil(resp)
   869  
   870  	job2 := mock.Job()
   871  	req2 := structs.JobRegisterRequest{
   872  		Job: job2,
   873  		WriteRequest: structs.WriteRequest{
   874  			Namespace: job2.Namespace,
   875  		},
   876  	}
   877  
   878  	buf, err = structs.Encode(structs.JobRegisterRequestType, req2)
   879  	require.Nil(err)
   880  	resp = fsm.Apply(makeLog(buf))
   881  	require.Nil(resp)
   882  
   883  	req3 := structs.JobBatchDeregisterRequest{
   884  		Jobs: map[structs.NamespacedID]*structs.JobDeregisterOptions{
   885  			{
   886  				ID:        job.ID,
   887  				Namespace: job.Namespace,
   888  			}: {},
   889  			{
   890  				ID:        job2.ID,
   891  				Namespace: job2.Namespace,
   892  			}: {
   893  				Purge: true,
   894  			},
   895  		},
   896  		WriteRequest: structs.WriteRequest{
   897  			Namespace: job.Namespace,
   898  		},
   899  	}
   900  	buf, err = structs.Encode(structs.JobBatchDeregisterRequestType, req3)
   901  	require.Nil(err)
   902  
   903  	resp = fsm.Apply(makeLog(buf))
   904  	require.Nil(resp)
   905  
   906  	// Verify we are NOT registered
   907  	ws := memdb.NewWatchSet()
   908  	jobOut, err := fsm.State().JobByID(ws, req.Namespace, req.Job.ID)
   909  	require.Nil(err)
   910  	require.NotNil(jobOut)
   911  	require.True(jobOut.Stop)
   912  
   913  	// Verify it was removed from the periodic runner.
   914  	tuple := structs.NamespacedID{
   915  		ID:        job.ID,
   916  		Namespace: job.Namespace,
   917  	}
   918  	require.NotContains(fsm.periodicDispatcher.tracked, tuple)
   919  
   920  	// Verify it was not removed from the periodic launch table.
   921  	launchOut, err := fsm.State().PeriodicLaunchByID(ws, job.Namespace, job.ID)
   922  	require.Nil(err)
   923  	require.NotNil(launchOut)
   924  
   925  	// Verify the other jbo was purged
   926  	jobOut2, err := fsm.State().JobByID(ws, job2.Namespace, job2.ID)
   927  	require.Nil(err)
   928  	require.Nil(jobOut2)
   929  }
   930  
   931  func TestFSM_UpdateEval(t *testing.T) {
   932  	t.Parallel()
   933  	fsm := testFSM(t)
   934  	fsm.evalBroker.SetEnabled(true)
   935  
   936  	req := structs.EvalUpdateRequest{
   937  		Evals: []*structs.Evaluation{mock.Eval()},
   938  	}
   939  	buf, err := structs.Encode(structs.EvalUpdateRequestType, req)
   940  	if err != nil {
   941  		t.Fatalf("err: %v", err)
   942  	}
   943  
   944  	resp := fsm.Apply(makeLog(buf))
   945  	if resp != nil {
   946  		t.Fatalf("resp: %v", resp)
   947  	}
   948  
   949  	// Verify we are registered
   950  	ws := memdb.NewWatchSet()
   951  	eval, err := fsm.State().EvalByID(ws, req.Evals[0].ID)
   952  	if err != nil {
   953  		t.Fatalf("err: %v", err)
   954  	}
   955  	if eval == nil {
   956  		t.Fatalf("not found!")
   957  	}
   958  	if eval.CreateIndex != 1 {
   959  		t.Fatalf("bad index: %d", eval.CreateIndex)
   960  	}
   961  
   962  	// Verify enqueued
   963  	stats := fsm.evalBroker.Stats()
   964  	if stats.TotalReady != 1 {
   965  		t.Fatalf("bad: %#v %#v", stats, eval)
   966  	}
   967  }
   968  
   969  func TestFSM_UpdateEval_Blocked(t *testing.T) {
   970  	t.Parallel()
   971  	fsm := testFSM(t)
   972  	fsm.evalBroker.SetEnabled(true)
   973  	fsm.blockedEvals.SetEnabled(true)
   974  
   975  	// Create a blocked eval.
   976  	eval := mock.Eval()
   977  	eval.Status = structs.EvalStatusBlocked
   978  
   979  	req := structs.EvalUpdateRequest{
   980  		Evals: []*structs.Evaluation{eval},
   981  	}
   982  	buf, err := structs.Encode(structs.EvalUpdateRequestType, req)
   983  	if err != nil {
   984  		t.Fatalf("err: %v", err)
   985  	}
   986  
   987  	resp := fsm.Apply(makeLog(buf))
   988  	if resp != nil {
   989  		t.Fatalf("resp: %v", resp)
   990  	}
   991  
   992  	// Verify we are registered
   993  	ws := memdb.NewWatchSet()
   994  	out, err := fsm.State().EvalByID(ws, eval.ID)
   995  	if err != nil {
   996  		t.Fatalf("err: %v", err)
   997  	}
   998  	if out == nil {
   999  		t.Fatalf("not found!")
  1000  	}
  1001  	if out.CreateIndex != 1 {
  1002  		t.Fatalf("bad index: %d", out.CreateIndex)
  1003  	}
  1004  
  1005  	// Verify the eval wasn't enqueued
  1006  	stats := fsm.evalBroker.Stats()
  1007  	if stats.TotalReady != 0 {
  1008  		t.Fatalf("bad: %#v %#v", stats, out)
  1009  	}
  1010  
  1011  	// Verify the eval was added to the blocked tracker.
  1012  	bStats := fsm.blockedEvals.Stats()
  1013  	if bStats.TotalBlocked != 1 {
  1014  		t.Fatalf("bad: %#v %#v", bStats, out)
  1015  	}
  1016  }
  1017  
  1018  func TestFSM_UpdateEval_Untrack(t *testing.T) {
  1019  	t.Parallel()
  1020  	fsm := testFSM(t)
  1021  	fsm.evalBroker.SetEnabled(true)
  1022  	fsm.blockedEvals.SetEnabled(true)
  1023  
  1024  	// Mark an eval as blocked.
  1025  	bEval := mock.Eval()
  1026  	bEval.ClassEligibility = map[string]bool{"v1:123": true}
  1027  	fsm.blockedEvals.Block(bEval)
  1028  
  1029  	// Create a successful eval for the same job
  1030  	eval := mock.Eval()
  1031  	eval.JobID = bEval.JobID
  1032  	eval.Status = structs.EvalStatusComplete
  1033  
  1034  	req := structs.EvalUpdateRequest{
  1035  		Evals: []*structs.Evaluation{eval},
  1036  	}
  1037  	buf, err := structs.Encode(structs.EvalUpdateRequestType, req)
  1038  	if err != nil {
  1039  		t.Fatalf("err: %v", err)
  1040  	}
  1041  
  1042  	resp := fsm.Apply(makeLog(buf))
  1043  	if resp != nil {
  1044  		t.Fatalf("resp: %v", resp)
  1045  	}
  1046  
  1047  	// Verify we are registered
  1048  	ws := memdb.NewWatchSet()
  1049  	out, err := fsm.State().EvalByID(ws, eval.ID)
  1050  	if err != nil {
  1051  		t.Fatalf("err: %v", err)
  1052  	}
  1053  	if out == nil {
  1054  		t.Fatalf("not found!")
  1055  	}
  1056  	if out.CreateIndex != 1 {
  1057  		t.Fatalf("bad index: %d", out.CreateIndex)
  1058  	}
  1059  
  1060  	// Verify the eval wasn't enqueued
  1061  	stats := fsm.evalBroker.Stats()
  1062  	if stats.TotalReady != 0 {
  1063  		t.Fatalf("bad: %#v %#v", stats, out)
  1064  	}
  1065  
  1066  	// Verify the eval was untracked in the blocked tracker.
  1067  	bStats := fsm.blockedEvals.Stats()
  1068  	if bStats.TotalBlocked != 0 {
  1069  		t.Fatalf("bad: %#v %#v", bStats, out)
  1070  	}
  1071  }
  1072  
  1073  func TestFSM_UpdateEval_NoUntrack(t *testing.T) {
  1074  	t.Parallel()
  1075  	fsm := testFSM(t)
  1076  	fsm.evalBroker.SetEnabled(true)
  1077  	fsm.blockedEvals.SetEnabled(true)
  1078  
  1079  	// Mark an eval as blocked.
  1080  	bEval := mock.Eval()
  1081  	bEval.ClassEligibility = map[string]bool{"v1:123": true}
  1082  	fsm.blockedEvals.Block(bEval)
  1083  
  1084  	// Create a successful eval for the same job but with placement failures
  1085  	eval := mock.Eval()
  1086  	eval.JobID = bEval.JobID
  1087  	eval.Status = structs.EvalStatusComplete
  1088  	eval.FailedTGAllocs = make(map[string]*structs.AllocMetric)
  1089  	eval.FailedTGAllocs["test"] = new(structs.AllocMetric)
  1090  
  1091  	req := structs.EvalUpdateRequest{
  1092  		Evals: []*structs.Evaluation{eval},
  1093  	}
  1094  	buf, err := structs.Encode(structs.EvalUpdateRequestType, req)
  1095  	if err != nil {
  1096  		t.Fatalf("err: %v", err)
  1097  	}
  1098  
  1099  	resp := fsm.Apply(makeLog(buf))
  1100  	if resp != nil {
  1101  		t.Fatalf("resp: %v", resp)
  1102  	}
  1103  
  1104  	// Verify we are registered
  1105  	ws := memdb.NewWatchSet()
  1106  	out, err := fsm.State().EvalByID(ws, eval.ID)
  1107  	if err != nil {
  1108  		t.Fatalf("err: %v", err)
  1109  	}
  1110  	if out == nil {
  1111  		t.Fatalf("not found!")
  1112  	}
  1113  	if out.CreateIndex != 1 {
  1114  		t.Fatalf("bad index: %d", out.CreateIndex)
  1115  	}
  1116  
  1117  	// Verify the eval wasn't enqueued
  1118  	stats := fsm.evalBroker.Stats()
  1119  	if stats.TotalReady != 0 {
  1120  		t.Fatalf("bad: %#v %#v", stats, out)
  1121  	}
  1122  
  1123  	// Verify the eval was not untracked in the blocked tracker.
  1124  	bStats := fsm.blockedEvals.Stats()
  1125  	if bStats.TotalBlocked != 1 {
  1126  		t.Fatalf("bad: %#v %#v", bStats, out)
  1127  	}
  1128  }
  1129  
  1130  func TestFSM_DeleteEval(t *testing.T) {
  1131  	t.Parallel()
  1132  	fsm := testFSM(t)
  1133  
  1134  	eval := mock.Eval()
  1135  	req := structs.EvalUpdateRequest{
  1136  		Evals: []*structs.Evaluation{eval},
  1137  	}
  1138  	buf, err := structs.Encode(structs.EvalUpdateRequestType, req)
  1139  	if err != nil {
  1140  		t.Fatalf("err: %v", err)
  1141  	}
  1142  
  1143  	resp := fsm.Apply(makeLog(buf))
  1144  	if resp != nil {
  1145  		t.Fatalf("resp: %v", resp)
  1146  	}
  1147  
  1148  	req2 := structs.EvalDeleteRequest{
  1149  		Evals: []string{eval.ID},
  1150  	}
  1151  	buf, err = structs.Encode(structs.EvalDeleteRequestType, req2)
  1152  	if err != nil {
  1153  		t.Fatalf("err: %v", err)
  1154  	}
  1155  
  1156  	resp = fsm.Apply(makeLog(buf))
  1157  	if resp != nil {
  1158  		t.Fatalf("resp: %v", resp)
  1159  	}
  1160  
  1161  	// Verify we are NOT registered
  1162  	ws := memdb.NewWatchSet()
  1163  	eval, err = fsm.State().EvalByID(ws, req.Evals[0].ID)
  1164  	if err != nil {
  1165  		t.Fatalf("err: %v", err)
  1166  	}
  1167  	if eval != nil {
  1168  		t.Fatalf("eval found!")
  1169  	}
  1170  }
  1171  
  1172  func TestFSM_UpsertAllocs(t *testing.T) {
  1173  	t.Parallel()
  1174  	fsm := testFSM(t)
  1175  
  1176  	alloc := mock.Alloc()
  1177  	alloc.Resources = &structs.Resources{} // COMPAT(0.11): Remove in 0.11, used to bypass resource creation in state store
  1178  	fsm.State().UpsertJobSummary(1, mock.JobSummary(alloc.JobID))
  1179  	req := structs.AllocUpdateRequest{
  1180  		Alloc: []*structs.Allocation{alloc},
  1181  	}
  1182  	buf, err := structs.Encode(structs.AllocUpdateRequestType, req)
  1183  	if err != nil {
  1184  		t.Fatalf("err: %v", err)
  1185  	}
  1186  
  1187  	resp := fsm.Apply(makeLog(buf))
  1188  	if resp != nil {
  1189  		t.Fatalf("resp: %v", resp)
  1190  	}
  1191  
  1192  	// Verify we are registered
  1193  	ws := memdb.NewWatchSet()
  1194  	out, err := fsm.State().AllocByID(ws, alloc.ID)
  1195  	if err != nil {
  1196  		t.Fatalf("err: %v", err)
  1197  	}
  1198  	alloc.CreateIndex = out.CreateIndex
  1199  	alloc.ModifyIndex = out.ModifyIndex
  1200  	alloc.AllocModifyIndex = out.AllocModifyIndex
  1201  	if !reflect.DeepEqual(alloc, out) {
  1202  		t.Fatalf("bad: %#v %#v", alloc, out)
  1203  	}
  1204  
  1205  	evictAlloc := new(structs.Allocation)
  1206  	*evictAlloc = *alloc
  1207  	evictAlloc.DesiredStatus = structs.AllocDesiredStatusEvict
  1208  	req2 := structs.AllocUpdateRequest{
  1209  		Alloc: []*structs.Allocation{evictAlloc},
  1210  	}
  1211  	buf, err = structs.Encode(structs.AllocUpdateRequestType, req2)
  1212  	if err != nil {
  1213  		t.Fatalf("err: %v", err)
  1214  	}
  1215  
  1216  	resp = fsm.Apply(makeLog(buf))
  1217  	if resp != nil {
  1218  		t.Fatalf("resp: %v", resp)
  1219  	}
  1220  
  1221  	// Verify we are evicted
  1222  	out, err = fsm.State().AllocByID(ws, alloc.ID)
  1223  	if err != nil {
  1224  		t.Fatalf("err: %v", err)
  1225  	}
  1226  	if out.DesiredStatus != structs.AllocDesiredStatusEvict {
  1227  		t.Fatalf("alloc found!")
  1228  	}
  1229  }
  1230  
  1231  func TestFSM_UpsertAllocs_SharedJob(t *testing.T) {
  1232  	t.Parallel()
  1233  	fsm := testFSM(t)
  1234  
  1235  	alloc := mock.Alloc()
  1236  	alloc.Resources = &structs.Resources{} // COMPAT(0.11): Remove in 0.11, used to bypass resource creation in state store
  1237  	fsm.State().UpsertJobSummary(1, mock.JobSummary(alloc.JobID))
  1238  	job := alloc.Job
  1239  	alloc.Job = nil
  1240  	req := structs.AllocUpdateRequest{
  1241  		Job:   job,
  1242  		Alloc: []*structs.Allocation{alloc},
  1243  	}
  1244  	buf, err := structs.Encode(structs.AllocUpdateRequestType, req)
  1245  	if err != nil {
  1246  		t.Fatalf("err: %v", err)
  1247  	}
  1248  
  1249  	resp := fsm.Apply(makeLog(buf))
  1250  	if resp != nil {
  1251  		t.Fatalf("resp: %v", resp)
  1252  	}
  1253  
  1254  	// Verify we are registered
  1255  	ws := memdb.NewWatchSet()
  1256  	out, err := fsm.State().AllocByID(ws, alloc.ID)
  1257  	if err != nil {
  1258  		t.Fatalf("err: %v", err)
  1259  	}
  1260  	alloc.CreateIndex = out.CreateIndex
  1261  	alloc.ModifyIndex = out.ModifyIndex
  1262  	alloc.AllocModifyIndex = out.AllocModifyIndex
  1263  
  1264  	// Job should be re-attached
  1265  	alloc.Job = job
  1266  	require.Equal(t, alloc, out)
  1267  
  1268  	// Ensure that the original job is used
  1269  	evictAlloc := new(structs.Allocation)
  1270  	*evictAlloc = *alloc
  1271  	job = mock.Job()
  1272  	job.Priority = 123
  1273  
  1274  	evictAlloc.Job = nil
  1275  	evictAlloc.DesiredStatus = structs.AllocDesiredStatusEvict
  1276  	req2 := structs.AllocUpdateRequest{
  1277  		Job:   job,
  1278  		Alloc: []*structs.Allocation{evictAlloc},
  1279  	}
  1280  	buf, err = structs.Encode(structs.AllocUpdateRequestType, req2)
  1281  	if err != nil {
  1282  		t.Fatalf("err: %v", err)
  1283  	}
  1284  
  1285  	resp = fsm.Apply(makeLog(buf))
  1286  	if resp != nil {
  1287  		t.Fatalf("resp: %v", resp)
  1288  	}
  1289  
  1290  	// Verify we are evicted
  1291  	out, err = fsm.State().AllocByID(ws, alloc.ID)
  1292  	if err != nil {
  1293  		t.Fatalf("err: %v", err)
  1294  	}
  1295  	if out.DesiredStatus != structs.AllocDesiredStatusEvict {
  1296  		t.Fatalf("alloc found!")
  1297  	}
  1298  	if out.Job == nil || out.Job.Priority == 123 {
  1299  		t.Fatalf("bad job")
  1300  	}
  1301  }
  1302  
  1303  // COMPAT(0.11): Remove in 0.11
  1304  func TestFSM_UpsertAllocs_StrippedResources(t *testing.T) {
  1305  	t.Parallel()
  1306  	fsm := testFSM(t)
  1307  
  1308  	alloc := mock.Alloc()
  1309  	alloc.Resources = &structs.Resources{
  1310  		CPU:      500,
  1311  		MemoryMB: 256,
  1312  		DiskMB:   150,
  1313  		Networks: []*structs.NetworkResource{
  1314  			{
  1315  				Device:        "eth0",
  1316  				IP:            "192.168.0.100",
  1317  				ReservedPorts: []structs.Port{{Label: "admin", Value: 5000}},
  1318  				MBits:         50,
  1319  				DynamicPorts:  []structs.Port{{Label: "http"}},
  1320  			},
  1321  		},
  1322  	}
  1323  	alloc.TaskResources = map[string]*structs.Resources{
  1324  		"web": {
  1325  			CPU:      500,
  1326  			MemoryMB: 256,
  1327  			Networks: []*structs.NetworkResource{
  1328  				{
  1329  					Device:        "eth0",
  1330  					IP:            "192.168.0.100",
  1331  					ReservedPorts: []structs.Port{{Label: "admin", Value: 5000}},
  1332  					MBits:         50,
  1333  					DynamicPorts:  []structs.Port{{Label: "http", Value: 9876}},
  1334  				},
  1335  			},
  1336  		},
  1337  	}
  1338  	alloc.SharedResources = &structs.Resources{
  1339  		DiskMB: 150,
  1340  	}
  1341  
  1342  	// Need to remove mock dynamic port from alloc as it won't be computed
  1343  	// in this test
  1344  	alloc.TaskResources["web"].Networks[0].DynamicPorts[0].Value = 0
  1345  
  1346  	fsm.State().UpsertJobSummary(1, mock.JobSummary(alloc.JobID))
  1347  	job := alloc.Job
  1348  	origResources := alloc.Resources
  1349  	alloc.Resources = nil
  1350  	req := structs.AllocUpdateRequest{
  1351  		Job:   job,
  1352  		Alloc: []*structs.Allocation{alloc},
  1353  	}
  1354  	buf, err := structs.Encode(structs.AllocUpdateRequestType, req)
  1355  	if err != nil {
  1356  		t.Fatalf("err: %v", err)
  1357  	}
  1358  
  1359  	resp := fsm.Apply(makeLog(buf))
  1360  	if resp != nil {
  1361  		t.Fatalf("resp: %v", resp)
  1362  	}
  1363  
  1364  	// Verify we are registered
  1365  	ws := memdb.NewWatchSet()
  1366  	out, err := fsm.State().AllocByID(ws, alloc.ID)
  1367  	if err != nil {
  1368  		t.Fatalf("err: %v", err)
  1369  	}
  1370  	alloc.CreateIndex = out.CreateIndex
  1371  	alloc.ModifyIndex = out.ModifyIndex
  1372  	alloc.AllocModifyIndex = out.AllocModifyIndex
  1373  
  1374  	// Resources should be recomputed
  1375  	origResources.DiskMB = alloc.Job.TaskGroups[0].EphemeralDisk.SizeMB
  1376  	alloc.Resources = origResources
  1377  	if !reflect.DeepEqual(alloc, out) {
  1378  		t.Fatalf("not equal: % #v", pretty.Diff(alloc, out))
  1379  	}
  1380  }
  1381  
  1382  func TestFSM_UpdateAllocFromClient_Unblock(t *testing.T) {
  1383  	t.Parallel()
  1384  	fsm := testFSM(t)
  1385  	fsm.blockedEvals.SetEnabled(true)
  1386  	state := fsm.State()
  1387  
  1388  	node := mock.Node()
  1389  	state.UpsertNode(1, node)
  1390  
  1391  	// Mark an eval as blocked.
  1392  	eval := mock.Eval()
  1393  	eval.ClassEligibility = map[string]bool{node.ComputedClass: true}
  1394  	fsm.blockedEvals.Block(eval)
  1395  
  1396  	bStats := fsm.blockedEvals.Stats()
  1397  	if bStats.TotalBlocked != 1 {
  1398  		t.Fatalf("bad: %#v", bStats)
  1399  	}
  1400  
  1401  	// Create a completed eval
  1402  	alloc := mock.Alloc()
  1403  	alloc.NodeID = node.ID
  1404  	alloc2 := mock.Alloc()
  1405  	alloc2.NodeID = node.ID
  1406  	state.UpsertJobSummary(8, mock.JobSummary(alloc.JobID))
  1407  	state.UpsertJobSummary(9, mock.JobSummary(alloc2.JobID))
  1408  	state.UpsertAllocs(10, []*structs.Allocation{alloc, alloc2})
  1409  
  1410  	clientAlloc := new(structs.Allocation)
  1411  	*clientAlloc = *alloc
  1412  	clientAlloc.ClientStatus = structs.AllocClientStatusComplete
  1413  	update2 := &structs.Allocation{
  1414  		ID:           alloc2.ID,
  1415  		ClientStatus: structs.AllocClientStatusRunning,
  1416  	}
  1417  
  1418  	req := structs.AllocUpdateRequest{
  1419  		Alloc: []*structs.Allocation{clientAlloc, update2},
  1420  	}
  1421  	buf, err := structs.Encode(structs.AllocClientUpdateRequestType, req)
  1422  	if err != nil {
  1423  		t.Fatalf("err: %v", err)
  1424  	}
  1425  
  1426  	resp := fsm.Apply(makeLog(buf))
  1427  	if resp != nil {
  1428  		t.Fatalf("resp: %v", resp)
  1429  	}
  1430  
  1431  	// Verify we are updated
  1432  	ws := memdb.NewWatchSet()
  1433  	out, err := fsm.State().AllocByID(ws, alloc.ID)
  1434  	if err != nil {
  1435  		t.Fatalf("err: %v", err)
  1436  	}
  1437  	clientAlloc.CreateIndex = out.CreateIndex
  1438  	clientAlloc.ModifyIndex = out.ModifyIndex
  1439  	if !reflect.DeepEqual(clientAlloc, out) {
  1440  		t.Fatalf("bad: %#v %#v", clientAlloc, out)
  1441  	}
  1442  
  1443  	out, err = fsm.State().AllocByID(ws, alloc2.ID)
  1444  	if err != nil {
  1445  		t.Fatalf("err: %v", err)
  1446  	}
  1447  	alloc2.CreateIndex = out.CreateIndex
  1448  	alloc2.ModifyIndex = out.ModifyIndex
  1449  	alloc2.ClientStatus = structs.AllocClientStatusRunning
  1450  	alloc2.TaskStates = nil
  1451  	if !reflect.DeepEqual(alloc2, out) {
  1452  		t.Fatalf("bad: %#v %#v", alloc2, out)
  1453  	}
  1454  
  1455  	// Verify the eval was unblocked.
  1456  	testutil.WaitForResult(func() (bool, error) {
  1457  		bStats = fsm.blockedEvals.Stats()
  1458  		if bStats.TotalBlocked != 0 {
  1459  			return false, fmt.Errorf("bad: %#v %#v", bStats, out)
  1460  		}
  1461  		return true, nil
  1462  	}, func(err error) {
  1463  		t.Fatalf("err: %s", err)
  1464  	})
  1465  }
  1466  
  1467  func TestFSM_UpdateAllocFromClient(t *testing.T) {
  1468  	t.Parallel()
  1469  	fsm := testFSM(t)
  1470  	state := fsm.State()
  1471  	require := require.New(t)
  1472  
  1473  	alloc := mock.Alloc()
  1474  	state.UpsertJobSummary(9, mock.JobSummary(alloc.JobID))
  1475  	state.UpsertAllocs(10, []*structs.Allocation{alloc})
  1476  
  1477  	clientAlloc := new(structs.Allocation)
  1478  	*clientAlloc = *alloc
  1479  	clientAlloc.ClientStatus = structs.AllocClientStatusFailed
  1480  
  1481  	eval := mock.Eval()
  1482  	eval.JobID = alloc.JobID
  1483  	eval.TriggeredBy = structs.EvalTriggerRetryFailedAlloc
  1484  	eval.Type = alloc.Job.Type
  1485  
  1486  	req := structs.AllocUpdateRequest{
  1487  		Alloc: []*structs.Allocation{clientAlloc},
  1488  		Evals: []*structs.Evaluation{eval},
  1489  	}
  1490  	buf, err := structs.Encode(structs.AllocClientUpdateRequestType, req)
  1491  	require.Nil(err)
  1492  
  1493  	resp := fsm.Apply(makeLog(buf))
  1494  	require.Nil(resp)
  1495  
  1496  	// Verify we are registered
  1497  	ws := memdb.NewWatchSet()
  1498  	out, err := fsm.State().AllocByID(ws, alloc.ID)
  1499  	require.Nil(err)
  1500  	clientAlloc.CreateIndex = out.CreateIndex
  1501  	clientAlloc.ModifyIndex = out.ModifyIndex
  1502  	require.Equal(clientAlloc, out)
  1503  
  1504  	// Verify eval was inserted
  1505  	ws = memdb.NewWatchSet()
  1506  	evals, err := fsm.State().EvalsByJob(ws, eval.Namespace, eval.JobID)
  1507  	require.Nil(err)
  1508  	require.Equal(1, len(evals))
  1509  	res := evals[0]
  1510  	eval.CreateIndex = res.CreateIndex
  1511  	eval.ModifyIndex = res.ModifyIndex
  1512  	require.Equal(eval, res)
  1513  }
  1514  
  1515  func TestFSM_UpdateAllocDesiredTransition(t *testing.T) {
  1516  	t.Parallel()
  1517  	fsm := testFSM(t)
  1518  	state := fsm.State()
  1519  	require := require.New(t)
  1520  
  1521  	alloc := mock.Alloc()
  1522  	alloc2 := mock.Alloc()
  1523  	alloc2.Job = alloc.Job
  1524  	alloc2.JobID = alloc.JobID
  1525  	state.UpsertJobSummary(9, mock.JobSummary(alloc.JobID))
  1526  	state.UpsertAllocs(10, []*structs.Allocation{alloc, alloc2})
  1527  
  1528  	t1 := &structs.DesiredTransition{
  1529  		Migrate: helper.BoolToPtr(true),
  1530  	}
  1531  
  1532  	eval := &structs.Evaluation{
  1533  		ID:             uuid.Generate(),
  1534  		Namespace:      alloc.Namespace,
  1535  		Priority:       alloc.Job.Priority,
  1536  		Type:           alloc.Job.Type,
  1537  		TriggeredBy:    structs.EvalTriggerNodeDrain,
  1538  		JobID:          alloc.Job.ID,
  1539  		JobModifyIndex: alloc.Job.ModifyIndex,
  1540  		Status:         structs.EvalStatusPending,
  1541  	}
  1542  	req := structs.AllocUpdateDesiredTransitionRequest{
  1543  		Allocs: map[string]*structs.DesiredTransition{
  1544  			alloc.ID:  t1,
  1545  			alloc2.ID: t1,
  1546  		},
  1547  		Evals: []*structs.Evaluation{eval},
  1548  	}
  1549  	buf, err := structs.Encode(structs.AllocUpdateDesiredTransitionRequestType, req)
  1550  	require.Nil(err)
  1551  
  1552  	resp := fsm.Apply(makeLog(buf))
  1553  	require.Nil(resp)
  1554  
  1555  	// Verify we are registered
  1556  	ws := memdb.NewWatchSet()
  1557  	out1, err := fsm.State().AllocByID(ws, alloc.ID)
  1558  	require.Nil(err)
  1559  	out2, err := fsm.State().AllocByID(ws, alloc2.ID)
  1560  	require.Nil(err)
  1561  	evalOut, err := fsm.State().EvalByID(ws, eval.ID)
  1562  	require.Nil(err)
  1563  	require.NotNil(evalOut)
  1564  	require.Equal(eval.ID, evalOut.ID)
  1565  
  1566  	require.NotNil(out1.DesiredTransition.Migrate)
  1567  	require.NotNil(out2.DesiredTransition.Migrate)
  1568  	require.True(*out1.DesiredTransition.Migrate)
  1569  	require.True(*out2.DesiredTransition.Migrate)
  1570  }
  1571  
  1572  func TestFSM_UpsertVaultAccessor(t *testing.T) {
  1573  	t.Parallel()
  1574  	fsm := testFSM(t)
  1575  	fsm.blockedEvals.SetEnabled(true)
  1576  
  1577  	va := mock.VaultAccessor()
  1578  	va2 := mock.VaultAccessor()
  1579  	req := structs.VaultAccessorsRequest{
  1580  		Accessors: []*structs.VaultAccessor{va, va2},
  1581  	}
  1582  	buf, err := structs.Encode(structs.VaultAccessorRegisterRequestType, req)
  1583  	if err != nil {
  1584  		t.Fatalf("err: %v", err)
  1585  	}
  1586  
  1587  	resp := fsm.Apply(makeLog(buf))
  1588  	if resp != nil {
  1589  		t.Fatalf("resp: %v", resp)
  1590  	}
  1591  
  1592  	// Verify we are registered
  1593  	ws := memdb.NewWatchSet()
  1594  	out1, err := fsm.State().VaultAccessor(ws, va.Accessor)
  1595  	if err != nil {
  1596  		t.Fatalf("err: %v", err)
  1597  	}
  1598  	if out1 == nil {
  1599  		t.Fatalf("not found!")
  1600  	}
  1601  	if out1.CreateIndex != 1 {
  1602  		t.Fatalf("bad index: %d", out1.CreateIndex)
  1603  	}
  1604  	out2, err := fsm.State().VaultAccessor(ws, va2.Accessor)
  1605  	if err != nil {
  1606  		t.Fatalf("err: %v", err)
  1607  	}
  1608  	if out2 == nil {
  1609  		t.Fatalf("not found!")
  1610  	}
  1611  	if out1.CreateIndex != 1 {
  1612  		t.Fatalf("bad index: %d", out2.CreateIndex)
  1613  	}
  1614  
  1615  	tt := fsm.TimeTable()
  1616  	index := tt.NearestIndex(time.Now().UTC())
  1617  	if index != 1 {
  1618  		t.Fatalf("bad: %d", index)
  1619  	}
  1620  }
  1621  
  1622  func TestFSM_DeregisterVaultAccessor(t *testing.T) {
  1623  	t.Parallel()
  1624  	fsm := testFSM(t)
  1625  	fsm.blockedEvals.SetEnabled(true)
  1626  
  1627  	va := mock.VaultAccessor()
  1628  	va2 := mock.VaultAccessor()
  1629  	accessors := []*structs.VaultAccessor{va, va2}
  1630  
  1631  	// Insert the accessors
  1632  	if err := fsm.State().UpsertVaultAccessor(1000, accessors); err != nil {
  1633  		t.Fatalf("bad: %v", err)
  1634  	}
  1635  
  1636  	req := structs.VaultAccessorsRequest{
  1637  		Accessors: accessors,
  1638  	}
  1639  	buf, err := structs.Encode(structs.VaultAccessorDeregisterRequestType, req)
  1640  	if err != nil {
  1641  		t.Fatalf("err: %v", err)
  1642  	}
  1643  
  1644  	resp := fsm.Apply(makeLog(buf))
  1645  	if resp != nil {
  1646  		t.Fatalf("resp: %v", resp)
  1647  	}
  1648  
  1649  	ws := memdb.NewWatchSet()
  1650  	out1, err := fsm.State().VaultAccessor(ws, va.Accessor)
  1651  	if err != nil {
  1652  		t.Fatalf("err: %v", err)
  1653  	}
  1654  	if out1 != nil {
  1655  		t.Fatalf("not deleted!")
  1656  	}
  1657  
  1658  	tt := fsm.TimeTable()
  1659  	index := tt.NearestIndex(time.Now().UTC())
  1660  	if index != 1 {
  1661  		t.Fatalf("bad: %d", index)
  1662  	}
  1663  }
  1664  
  1665  func TestFSM_ApplyPlanResults(t *testing.T) {
  1666  	t.Parallel()
  1667  	fsm := testFSM(t)
  1668  	fsm.evalBroker.SetEnabled(true)
  1669  	// Create the request and create a deployment
  1670  	alloc := mock.Alloc()
  1671  	alloc.Resources = &structs.Resources{} // COMPAT(0.11): Remove in 0.11, used to bypass resource creation in state store
  1672  	job := alloc.Job
  1673  	alloc.Job = nil
  1674  
  1675  	d := mock.Deployment()
  1676  	d.JobID = job.ID
  1677  	d.JobModifyIndex = job.ModifyIndex
  1678  	d.JobVersion = job.Version
  1679  
  1680  	alloc.DeploymentID = d.ID
  1681  
  1682  	eval := mock.Eval()
  1683  	eval.JobID = job.ID
  1684  	fsm.State().UpsertEvals(1, []*structs.Evaluation{eval})
  1685  
  1686  	fsm.State().UpsertJobSummary(1, mock.JobSummary(alloc.JobID))
  1687  
  1688  	// set up preempted jobs and allocs
  1689  	job1 := mock.Job()
  1690  	job2 := mock.Job()
  1691  
  1692  	alloc1 := mock.Alloc()
  1693  	alloc1.Job = job1
  1694  	alloc1.JobID = job1.ID
  1695  	alloc1.PreemptedByAllocation = alloc.ID
  1696  
  1697  	alloc2 := mock.Alloc()
  1698  	alloc2.Job = job2
  1699  	alloc2.JobID = job2.ID
  1700  	alloc2.PreemptedByAllocation = alloc.ID
  1701  
  1702  	fsm.State().UpsertAllocs(1, []*structs.Allocation{alloc1, alloc2})
  1703  
  1704  	// evals for preempted jobs
  1705  	eval1 := mock.Eval()
  1706  	eval1.JobID = job1.ID
  1707  
  1708  	eval2 := mock.Eval()
  1709  	eval2.JobID = job2.ID
  1710  
  1711  	req := structs.ApplyPlanResultsRequest{
  1712  		AllocUpdateRequest: structs.AllocUpdateRequest{
  1713  			Job:   job,
  1714  			Alloc: []*structs.Allocation{alloc},
  1715  		},
  1716  		Deployment:      d,
  1717  		EvalID:          eval.ID,
  1718  		NodePreemptions: []*structs.Allocation{alloc1, alloc2},
  1719  		PreemptionEvals: []*structs.Evaluation{eval1, eval2},
  1720  	}
  1721  	buf, err := structs.Encode(structs.ApplyPlanResultsRequestType, req)
  1722  	if err != nil {
  1723  		t.Fatalf("err: %v", err)
  1724  	}
  1725  
  1726  	resp := fsm.Apply(makeLog(buf))
  1727  	if resp != nil {
  1728  		t.Fatalf("resp: %v", resp)
  1729  	}
  1730  
  1731  	// Verify the allocation is registered
  1732  	ws := memdb.NewWatchSet()
  1733  	assert := assert.New(t)
  1734  	out, err := fsm.State().AllocByID(ws, alloc.ID)
  1735  	assert.Nil(err)
  1736  	alloc.CreateIndex = out.CreateIndex
  1737  	alloc.ModifyIndex = out.ModifyIndex
  1738  	alloc.AllocModifyIndex = out.AllocModifyIndex
  1739  
  1740  	// Job should be re-attached
  1741  	alloc.Job = job
  1742  	assert.Equal(alloc, out)
  1743  
  1744  	// Verify that evals for preempted jobs have been created
  1745  	e1, err := fsm.State().EvalByID(ws, eval1.ID)
  1746  	require := require.New(t)
  1747  	require.Nil(err)
  1748  	require.NotNil(e1)
  1749  
  1750  	e2, err := fsm.State().EvalByID(ws, eval2.ID)
  1751  	require.Nil(err)
  1752  	require.NotNil(e2)
  1753  
  1754  	// Verify that eval broker has both evals
  1755  	_, ok := fsm.evalBroker.evals[e1.ID]
  1756  	require.True(ok)
  1757  
  1758  	_, ok = fsm.evalBroker.evals[e1.ID]
  1759  	require.True(ok)
  1760  
  1761  	dout, err := fsm.State().DeploymentByID(ws, d.ID)
  1762  	assert.Nil(err)
  1763  	tg, ok := dout.TaskGroups[alloc.TaskGroup]
  1764  	assert.True(ok)
  1765  	assert.NotNil(tg)
  1766  	assert.Equal(1, tg.PlacedAllocs)
  1767  
  1768  	// Ensure that the original job is used
  1769  	evictAlloc := alloc.Copy()
  1770  	job = mock.Job()
  1771  	job.Priority = 123
  1772  	eval = mock.Eval()
  1773  	eval.JobID = job.ID
  1774  
  1775  	fsm.State().UpsertEvals(2, []*structs.Evaluation{eval})
  1776  
  1777  	evictAlloc.Job = nil
  1778  	evictAlloc.DesiredStatus = structs.AllocDesiredStatusEvict
  1779  	req2 := structs.ApplyPlanResultsRequest{
  1780  		AllocUpdateRequest: structs.AllocUpdateRequest{
  1781  			Job:   job,
  1782  			Alloc: []*structs.Allocation{evictAlloc},
  1783  		},
  1784  		EvalID: eval.ID,
  1785  	}
  1786  	buf, err = structs.Encode(structs.ApplyPlanResultsRequestType, req2)
  1787  	assert.Nil(err)
  1788  
  1789  	log := makeLog(buf)
  1790  	//set the index to something other than 1
  1791  	log.Index = 25
  1792  	resp = fsm.Apply(log)
  1793  	assert.Nil(resp)
  1794  
  1795  	// Verify we are evicted
  1796  	out, err = fsm.State().AllocByID(ws, alloc.ID)
  1797  	assert.Nil(err)
  1798  	assert.Equal(structs.AllocDesiredStatusEvict, out.DesiredStatus)
  1799  	assert.NotNil(out.Job)
  1800  	assert.NotEqual(123, out.Job.Priority)
  1801  
  1802  	evalOut, err := fsm.State().EvalByID(ws, eval.ID)
  1803  	assert.Nil(err)
  1804  	assert.Equal(log.Index, evalOut.ModifyIndex)
  1805  
  1806  }
  1807  
  1808  func TestFSM_DeploymentStatusUpdate(t *testing.T) {
  1809  	t.Parallel()
  1810  	fsm := testFSM(t)
  1811  	fsm.evalBroker.SetEnabled(true)
  1812  	state := fsm.State()
  1813  
  1814  	// Upsert a deployment
  1815  	d := mock.Deployment()
  1816  	if err := state.UpsertDeployment(1, d); err != nil {
  1817  		t.Fatalf("bad: %v", err)
  1818  	}
  1819  
  1820  	// Create a request to update the deployment, create an eval and job
  1821  	e := mock.Eval()
  1822  	j := mock.Job()
  1823  	status, desc := structs.DeploymentStatusFailed, "foo"
  1824  	req := &structs.DeploymentStatusUpdateRequest{
  1825  		DeploymentUpdate: &structs.DeploymentStatusUpdate{
  1826  			DeploymentID:      d.ID,
  1827  			Status:            status,
  1828  			StatusDescription: desc,
  1829  		},
  1830  		Job:  j,
  1831  		Eval: e,
  1832  	}
  1833  	buf, err := structs.Encode(structs.DeploymentStatusUpdateRequestType, req)
  1834  	if err != nil {
  1835  		t.Fatalf("err: %v", err)
  1836  	}
  1837  	resp := fsm.Apply(makeLog(buf))
  1838  	if resp != nil {
  1839  		t.Fatalf("resp: %v", resp)
  1840  	}
  1841  
  1842  	// Check that the status was updated properly
  1843  	ws := memdb.NewWatchSet()
  1844  	dout, err := state.DeploymentByID(ws, d.ID)
  1845  	if err != nil {
  1846  		t.Fatalf("bad: %v", err)
  1847  	}
  1848  	if dout.Status != status || dout.StatusDescription != desc {
  1849  		t.Fatalf("bad: %#v", dout)
  1850  	}
  1851  
  1852  	// Check that the evaluation was created
  1853  	eout, _ := state.EvalByID(ws, e.ID)
  1854  	if err != nil {
  1855  		t.Fatalf("bad: %v", err)
  1856  	}
  1857  	if eout == nil {
  1858  		t.Fatalf("bad: %#v", eout)
  1859  	}
  1860  
  1861  	// Check that the job was created
  1862  	jout, _ := state.JobByID(ws, j.Namespace, j.ID)
  1863  	if err != nil {
  1864  		t.Fatalf("bad: %v", err)
  1865  	}
  1866  	if jout == nil {
  1867  		t.Fatalf("bad: %#v", jout)
  1868  	}
  1869  
  1870  	// Assert the eval was enqueued
  1871  	stats := fsm.evalBroker.Stats()
  1872  	if stats.TotalReady != 1 {
  1873  		t.Fatalf("bad: %#v %#v", stats, e)
  1874  	}
  1875  }
  1876  
  1877  func TestFSM_JobStabilityUpdate(t *testing.T) {
  1878  	t.Parallel()
  1879  	fsm := testFSM(t)
  1880  	fsm.evalBroker.SetEnabled(true)
  1881  	state := fsm.State()
  1882  
  1883  	// Upsert a deployment
  1884  	job := mock.Job()
  1885  	if err := state.UpsertJob(1, job); err != nil {
  1886  		t.Fatalf("bad: %v", err)
  1887  	}
  1888  
  1889  	// Create a request to update the job to stable
  1890  	req := &structs.JobStabilityRequest{
  1891  		JobID:      job.ID,
  1892  		JobVersion: job.Version,
  1893  		Stable:     true,
  1894  		WriteRequest: structs.WriteRequest{
  1895  			Namespace: job.Namespace,
  1896  		},
  1897  	}
  1898  	buf, err := structs.Encode(structs.JobStabilityRequestType, req)
  1899  	if err != nil {
  1900  		t.Fatalf("err: %v", err)
  1901  	}
  1902  	resp := fsm.Apply(makeLog(buf))
  1903  	if resp != nil {
  1904  		t.Fatalf("resp: %v", resp)
  1905  	}
  1906  
  1907  	// Check that the stability was updated properly
  1908  	ws := memdb.NewWatchSet()
  1909  	jout, _ := state.JobByIDAndVersion(ws, job.Namespace, job.ID, job.Version)
  1910  	if err != nil {
  1911  		t.Fatalf("bad: %v", err)
  1912  	}
  1913  	if jout == nil || !jout.Stable {
  1914  		t.Fatalf("bad: %#v", jout)
  1915  	}
  1916  }
  1917  
  1918  func TestFSM_DeploymentPromotion(t *testing.T) {
  1919  	t.Parallel()
  1920  	fsm := testFSM(t)
  1921  	fsm.evalBroker.SetEnabled(true)
  1922  	state := fsm.State()
  1923  
  1924  	// Create a job with two task groups
  1925  	j := mock.Job()
  1926  	tg1 := j.TaskGroups[0]
  1927  	tg2 := tg1.Copy()
  1928  	tg2.Name = "foo"
  1929  	j.TaskGroups = append(j.TaskGroups, tg2)
  1930  	if err := state.UpsertJob(1, j); err != nil {
  1931  		t.Fatalf("bad: %v", err)
  1932  	}
  1933  
  1934  	// Create a deployment
  1935  	d := mock.Deployment()
  1936  	d.JobID = j.ID
  1937  	d.TaskGroups = map[string]*structs.DeploymentState{
  1938  		"web": {
  1939  			DesiredTotal:    10,
  1940  			DesiredCanaries: 1,
  1941  		},
  1942  		"foo": {
  1943  			DesiredTotal:    10,
  1944  			DesiredCanaries: 1,
  1945  		},
  1946  	}
  1947  	if err := state.UpsertDeployment(2, d); err != nil {
  1948  		t.Fatalf("bad: %v", err)
  1949  	}
  1950  
  1951  	// Create a set of allocations
  1952  	c1 := mock.Alloc()
  1953  	c1.JobID = j.ID
  1954  	c1.DeploymentID = d.ID
  1955  	d.TaskGroups[c1.TaskGroup].PlacedCanaries = append(d.TaskGroups[c1.TaskGroup].PlacedCanaries, c1.ID)
  1956  	c1.DeploymentStatus = &structs.AllocDeploymentStatus{
  1957  		Healthy: helper.BoolToPtr(true),
  1958  	}
  1959  	c2 := mock.Alloc()
  1960  	c2.JobID = j.ID
  1961  	c2.DeploymentID = d.ID
  1962  	d.TaskGroups[c2.TaskGroup].PlacedCanaries = append(d.TaskGroups[c2.TaskGroup].PlacedCanaries, c2.ID)
  1963  	c2.TaskGroup = tg2.Name
  1964  	c2.DeploymentStatus = &structs.AllocDeploymentStatus{
  1965  		Healthy: helper.BoolToPtr(true),
  1966  	}
  1967  
  1968  	if err := state.UpsertAllocs(3, []*structs.Allocation{c1, c2}); err != nil {
  1969  		t.Fatalf("err: %v", err)
  1970  	}
  1971  
  1972  	// Create an eval
  1973  	e := mock.Eval()
  1974  
  1975  	// Promote the canaries
  1976  	req := &structs.ApplyDeploymentPromoteRequest{
  1977  		DeploymentPromoteRequest: structs.DeploymentPromoteRequest{
  1978  			DeploymentID: d.ID,
  1979  			All:          true,
  1980  		},
  1981  		Eval: e,
  1982  	}
  1983  	buf, err := structs.Encode(structs.DeploymentPromoteRequestType, req)
  1984  	if err != nil {
  1985  		t.Fatalf("err: %v", err)
  1986  	}
  1987  	resp := fsm.Apply(makeLog(buf))
  1988  	if resp != nil {
  1989  		t.Fatalf("resp: %v", resp)
  1990  	}
  1991  
  1992  	// Check that the status per task group was updated properly
  1993  	ws := memdb.NewWatchSet()
  1994  	dout, err := state.DeploymentByID(ws, d.ID)
  1995  	if err != nil {
  1996  		t.Fatalf("bad: %v", err)
  1997  	}
  1998  	if len(dout.TaskGroups) != 2 {
  1999  		t.Fatalf("bad: %#v", dout.TaskGroups)
  2000  	}
  2001  	for tg, state := range dout.TaskGroups {
  2002  		if !state.Promoted {
  2003  			t.Fatalf("bad: group %q not promoted %#v", tg, state)
  2004  		}
  2005  	}
  2006  
  2007  	// Check that the evaluation was created
  2008  	eout, _ := state.EvalByID(ws, e.ID)
  2009  	if err != nil {
  2010  		t.Fatalf("bad: %v", err)
  2011  	}
  2012  	if eout == nil {
  2013  		t.Fatalf("bad: %#v", eout)
  2014  	}
  2015  
  2016  	// Assert the eval was enqueued
  2017  	stats := fsm.evalBroker.Stats()
  2018  	if stats.TotalReady != 1 {
  2019  		t.Fatalf("bad: %#v %#v", stats, e)
  2020  	}
  2021  }
  2022  
  2023  func TestFSM_DeploymentAllocHealth(t *testing.T) {
  2024  	t.Parallel()
  2025  	fsm := testFSM(t)
  2026  	fsm.evalBroker.SetEnabled(true)
  2027  	state := fsm.State()
  2028  
  2029  	// Insert a deployment
  2030  	d := mock.Deployment()
  2031  	if err := state.UpsertDeployment(1, d); err != nil {
  2032  		t.Fatalf("bad: %v", err)
  2033  	}
  2034  
  2035  	// Insert two allocations
  2036  	a1 := mock.Alloc()
  2037  	a1.DeploymentID = d.ID
  2038  	a2 := mock.Alloc()
  2039  	a2.DeploymentID = d.ID
  2040  	if err := state.UpsertAllocs(2, []*structs.Allocation{a1, a2}); err != nil {
  2041  		t.Fatalf("bad: %v", err)
  2042  	}
  2043  
  2044  	// Create a job to roll back to
  2045  	j := mock.Job()
  2046  
  2047  	// Create an eval that should be upserted
  2048  	e := mock.Eval()
  2049  
  2050  	// Create a status update for the deployment
  2051  	status, desc := structs.DeploymentStatusFailed, "foo"
  2052  	u := &structs.DeploymentStatusUpdate{
  2053  		DeploymentID:      d.ID,
  2054  		Status:            status,
  2055  		StatusDescription: desc,
  2056  	}
  2057  
  2058  	// Set health against the deployment
  2059  	req := &structs.ApplyDeploymentAllocHealthRequest{
  2060  		DeploymentAllocHealthRequest: structs.DeploymentAllocHealthRequest{
  2061  			DeploymentID:           d.ID,
  2062  			HealthyAllocationIDs:   []string{a1.ID},
  2063  			UnhealthyAllocationIDs: []string{a2.ID},
  2064  		},
  2065  		Job:              j,
  2066  		Eval:             e,
  2067  		DeploymentUpdate: u,
  2068  	}
  2069  	buf, err := structs.Encode(structs.DeploymentAllocHealthRequestType, req)
  2070  	if err != nil {
  2071  		t.Fatalf("err: %v", err)
  2072  	}
  2073  	resp := fsm.Apply(makeLog(buf))
  2074  	if resp != nil {
  2075  		t.Fatalf("resp: %v", resp)
  2076  	}
  2077  
  2078  	// Check that the status was updated properly
  2079  	ws := memdb.NewWatchSet()
  2080  	dout, err := state.DeploymentByID(ws, d.ID)
  2081  	if err != nil {
  2082  		t.Fatalf("bad: %v", err)
  2083  	}
  2084  	if dout.Status != status || dout.StatusDescription != desc {
  2085  		t.Fatalf("bad: %#v", dout)
  2086  	}
  2087  
  2088  	// Check that the evaluation was created
  2089  	eout, _ := state.EvalByID(ws, e.ID)
  2090  	if err != nil {
  2091  		t.Fatalf("bad: %v", err)
  2092  	}
  2093  	if eout == nil {
  2094  		t.Fatalf("bad: %#v", eout)
  2095  	}
  2096  
  2097  	// Check that the job was created
  2098  	jout, _ := state.JobByID(ws, j.Namespace, j.ID)
  2099  	if err != nil {
  2100  		t.Fatalf("bad: %v", err)
  2101  	}
  2102  	if jout == nil {
  2103  		t.Fatalf("bad: %#v", jout)
  2104  	}
  2105  
  2106  	// Check the status of the allocs
  2107  	out1, err := state.AllocByID(ws, a1.ID)
  2108  	if err != nil {
  2109  		t.Fatalf("err: %v", err)
  2110  	}
  2111  	out2, err := state.AllocByID(ws, a2.ID)
  2112  	if err != nil {
  2113  		t.Fatalf("err: %v", err)
  2114  	}
  2115  
  2116  	if !out1.DeploymentStatus.IsHealthy() {
  2117  		t.Fatalf("bad: alloc %q not healthy", out1.ID)
  2118  	}
  2119  	if !out2.DeploymentStatus.IsUnhealthy() {
  2120  		t.Fatalf("bad: alloc %q not unhealthy", out2.ID)
  2121  	}
  2122  
  2123  	// Assert the eval was enqueued
  2124  	stats := fsm.evalBroker.Stats()
  2125  	if stats.TotalReady != 1 {
  2126  		t.Fatalf("bad: %#v %#v", stats, e)
  2127  	}
  2128  }
  2129  
  2130  func TestFSM_DeleteDeployment(t *testing.T) {
  2131  	t.Parallel()
  2132  	fsm := testFSM(t)
  2133  	state := fsm.State()
  2134  
  2135  	// Upsert a deployments
  2136  	d := mock.Deployment()
  2137  	if err := state.UpsertDeployment(1, d); err != nil {
  2138  		t.Fatalf("bad: %v", err)
  2139  	}
  2140  
  2141  	req := structs.DeploymentDeleteRequest{
  2142  		Deployments: []string{d.ID},
  2143  	}
  2144  	buf, err := structs.Encode(structs.DeploymentDeleteRequestType, req)
  2145  	if err != nil {
  2146  		t.Fatalf("err: %v", err)
  2147  	}
  2148  
  2149  	resp := fsm.Apply(makeLog(buf))
  2150  	if resp != nil {
  2151  		t.Fatalf("resp: %v", resp)
  2152  	}
  2153  
  2154  	// Verify we are NOT registered
  2155  	ws := memdb.NewWatchSet()
  2156  	deployment, err := state.DeploymentByID(ws, d.ID)
  2157  	if err != nil {
  2158  		t.Fatalf("err: %v", err)
  2159  	}
  2160  	if deployment != nil {
  2161  		t.Fatalf("deployment found!")
  2162  	}
  2163  }
  2164  
  2165  func TestFSM_UpsertACLPolicies(t *testing.T) {
  2166  	t.Parallel()
  2167  	fsm := testFSM(t)
  2168  
  2169  	policy := mock.ACLPolicy()
  2170  	req := structs.ACLPolicyUpsertRequest{
  2171  		Policies: []*structs.ACLPolicy{policy},
  2172  	}
  2173  	buf, err := structs.Encode(structs.ACLPolicyUpsertRequestType, req)
  2174  	if err != nil {
  2175  		t.Fatalf("err: %v", err)
  2176  	}
  2177  
  2178  	resp := fsm.Apply(makeLog(buf))
  2179  	if resp != nil {
  2180  		t.Fatalf("resp: %v", resp)
  2181  	}
  2182  
  2183  	// Verify we are registered
  2184  	ws := memdb.NewWatchSet()
  2185  	out, err := fsm.State().ACLPolicyByName(ws, policy.Name)
  2186  	assert.Nil(t, err)
  2187  	assert.NotNil(t, out)
  2188  }
  2189  
  2190  func TestFSM_DeleteACLPolicies(t *testing.T) {
  2191  	t.Parallel()
  2192  	fsm := testFSM(t)
  2193  
  2194  	policy := mock.ACLPolicy()
  2195  	err := fsm.State().UpsertACLPolicies(1000, []*structs.ACLPolicy{policy})
  2196  	assert.Nil(t, err)
  2197  
  2198  	req := structs.ACLPolicyDeleteRequest{
  2199  		Names: []string{policy.Name},
  2200  	}
  2201  	buf, err := structs.Encode(structs.ACLPolicyDeleteRequestType, req)
  2202  	if err != nil {
  2203  		t.Fatalf("err: %v", err)
  2204  	}
  2205  
  2206  	resp := fsm.Apply(makeLog(buf))
  2207  	if resp != nil {
  2208  		t.Fatalf("resp: %v", resp)
  2209  	}
  2210  
  2211  	// Verify we are NOT registered
  2212  	ws := memdb.NewWatchSet()
  2213  	out, err := fsm.State().ACLPolicyByName(ws, policy.Name)
  2214  	assert.Nil(t, err)
  2215  	assert.Nil(t, out)
  2216  }
  2217  
  2218  func TestFSM_BootstrapACLTokens(t *testing.T) {
  2219  	t.Parallel()
  2220  	fsm := testFSM(t)
  2221  
  2222  	token := mock.ACLToken()
  2223  	req := structs.ACLTokenBootstrapRequest{
  2224  		Token: token,
  2225  	}
  2226  	buf, err := structs.Encode(structs.ACLTokenBootstrapRequestType, req)
  2227  	if err != nil {
  2228  		t.Fatalf("err: %v", err)
  2229  	}
  2230  
  2231  	resp := fsm.Apply(makeLog(buf))
  2232  	if resp != nil {
  2233  		t.Fatalf("resp: %v", resp)
  2234  	}
  2235  
  2236  	// Verify we are registered
  2237  	out, err := fsm.State().ACLTokenByAccessorID(nil, token.AccessorID)
  2238  	assert.Nil(t, err)
  2239  	assert.NotNil(t, out)
  2240  
  2241  	// Test with reset
  2242  	token2 := mock.ACLToken()
  2243  	req = structs.ACLTokenBootstrapRequest{
  2244  		Token:      token2,
  2245  		ResetIndex: out.CreateIndex,
  2246  	}
  2247  	buf, err = structs.Encode(structs.ACLTokenBootstrapRequestType, req)
  2248  	if err != nil {
  2249  		t.Fatalf("err: %v", err)
  2250  	}
  2251  
  2252  	resp = fsm.Apply(makeLog(buf))
  2253  	if resp != nil {
  2254  		t.Fatalf("resp: %v", resp)
  2255  	}
  2256  
  2257  	// Verify we are registered
  2258  	out2, err := fsm.State().ACLTokenByAccessorID(nil, token2.AccessorID)
  2259  	assert.Nil(t, err)
  2260  	assert.NotNil(t, out2)
  2261  }
  2262  
  2263  func TestFSM_UpsertACLTokens(t *testing.T) {
  2264  	t.Parallel()
  2265  	fsm := testFSM(t)
  2266  
  2267  	token := mock.ACLToken()
  2268  	req := structs.ACLTokenUpsertRequest{
  2269  		Tokens: []*structs.ACLToken{token},
  2270  	}
  2271  	buf, err := structs.Encode(structs.ACLTokenUpsertRequestType, req)
  2272  	if err != nil {
  2273  		t.Fatalf("err: %v", err)
  2274  	}
  2275  
  2276  	resp := fsm.Apply(makeLog(buf))
  2277  	if resp != nil {
  2278  		t.Fatalf("resp: %v", resp)
  2279  	}
  2280  
  2281  	// Verify we are registered
  2282  	ws := memdb.NewWatchSet()
  2283  	out, err := fsm.State().ACLTokenByAccessorID(ws, token.AccessorID)
  2284  	assert.Nil(t, err)
  2285  	assert.NotNil(t, out)
  2286  }
  2287  
  2288  func TestFSM_DeleteACLTokens(t *testing.T) {
  2289  	t.Parallel()
  2290  	fsm := testFSM(t)
  2291  
  2292  	token := mock.ACLToken()
  2293  	err := fsm.State().UpsertACLTokens(1000, []*structs.ACLToken{token})
  2294  	assert.Nil(t, err)
  2295  
  2296  	req := structs.ACLTokenDeleteRequest{
  2297  		AccessorIDs: []string{token.AccessorID},
  2298  	}
  2299  	buf, err := structs.Encode(structs.ACLTokenDeleteRequestType, req)
  2300  	if err != nil {
  2301  		t.Fatalf("err: %v", err)
  2302  	}
  2303  
  2304  	resp := fsm.Apply(makeLog(buf))
  2305  	if resp != nil {
  2306  		t.Fatalf("resp: %v", resp)
  2307  	}
  2308  
  2309  	// Verify we are NOT registered
  2310  	ws := memdb.NewWatchSet()
  2311  	out, err := fsm.State().ACLTokenByAccessorID(ws, token.AccessorID)
  2312  	assert.Nil(t, err)
  2313  	assert.Nil(t, out)
  2314  }
  2315  
  2316  func testSnapshotRestore(t *testing.T, fsm *nomadFSM) *nomadFSM {
  2317  	// Snapshot
  2318  	snap, err := fsm.Snapshot()
  2319  	if err != nil {
  2320  		t.Fatalf("err: %v", err)
  2321  	}
  2322  	defer snap.Release()
  2323  
  2324  	// Persist
  2325  	buf := bytes.NewBuffer(nil)
  2326  	sink := &MockSink{buf, false}
  2327  	if err := snap.Persist(sink); err != nil {
  2328  		t.Fatalf("err: %v", err)
  2329  	}
  2330  
  2331  	// Try to restore on a new FSM
  2332  	fsm2 := testFSM(t)
  2333  	snap, err = fsm2.Snapshot()
  2334  	if err != nil {
  2335  		t.Fatalf("err: %v", err)
  2336  	}
  2337  	defer snap.Release()
  2338  
  2339  	abandonCh := fsm2.State().AbandonCh()
  2340  
  2341  	// Do a restore
  2342  	if err := fsm2.Restore(sink); err != nil {
  2343  		t.Fatalf("err: %v", err)
  2344  	}
  2345  
  2346  	select {
  2347  	case <-abandonCh:
  2348  	default:
  2349  		t.Fatalf("bad")
  2350  	}
  2351  
  2352  	return fsm2
  2353  }
  2354  
  2355  func TestFSM_SnapshotRestore_Nodes(t *testing.T) {
  2356  	t.Parallel()
  2357  	// Add some state
  2358  	fsm := testFSM(t)
  2359  	state := fsm.State()
  2360  	node1 := mock.Node()
  2361  	state.UpsertNode(1000, node1)
  2362  
  2363  	// Upgrade this node
  2364  	node2 := mock.Node()
  2365  	node2.SchedulingEligibility = ""
  2366  	state.UpsertNode(1001, node2)
  2367  
  2368  	// Verify the contents
  2369  	fsm2 := testSnapshotRestore(t, fsm)
  2370  	state2 := fsm2.State()
  2371  	out1, _ := state2.NodeByID(nil, node1.ID)
  2372  	out2, _ := state2.NodeByID(nil, node2.ID)
  2373  	node2.SchedulingEligibility = structs.NodeSchedulingEligible
  2374  	if !reflect.DeepEqual(node1, out1) {
  2375  		t.Fatalf("bad: \n%#v\n%#v", out1, node1)
  2376  	}
  2377  	if !reflect.DeepEqual(node2, out2) {
  2378  		t.Fatalf("bad: \n%#v\n%#v", out2, node2)
  2379  	}
  2380  }
  2381  
  2382  func TestFSM_SnapshotRestore_Jobs(t *testing.T) {
  2383  	t.Parallel()
  2384  	// Add some state
  2385  	fsm := testFSM(t)
  2386  	state := fsm.State()
  2387  	job1 := mock.Job()
  2388  	state.UpsertJob(1000, job1)
  2389  	job2 := mock.Job()
  2390  	state.UpsertJob(1001, job2)
  2391  
  2392  	// Verify the contents
  2393  	ws := memdb.NewWatchSet()
  2394  	fsm2 := testSnapshotRestore(t, fsm)
  2395  	state2 := fsm2.State()
  2396  	out1, _ := state2.JobByID(ws, job1.Namespace, job1.ID)
  2397  	out2, _ := state2.JobByID(ws, job2.Namespace, job2.ID)
  2398  	if !reflect.DeepEqual(job1, out1) {
  2399  		t.Fatalf("bad: \n%#v\n%#v", out1, job1)
  2400  	}
  2401  	if !reflect.DeepEqual(job2, out2) {
  2402  		t.Fatalf("bad: \n%#v\n%#v", out2, job2)
  2403  	}
  2404  }
  2405  
  2406  func TestFSM_SnapshotRestore_Evals(t *testing.T) {
  2407  	t.Parallel()
  2408  	// Add some state
  2409  	fsm := testFSM(t)
  2410  	state := fsm.State()
  2411  	eval1 := mock.Eval()
  2412  	state.UpsertEvals(1000, []*structs.Evaluation{eval1})
  2413  	eval2 := mock.Eval()
  2414  	state.UpsertEvals(1001, []*structs.Evaluation{eval2})
  2415  
  2416  	// Verify the contents
  2417  	fsm2 := testSnapshotRestore(t, fsm)
  2418  	state2 := fsm2.State()
  2419  	ws := memdb.NewWatchSet()
  2420  	out1, _ := state2.EvalByID(ws, eval1.ID)
  2421  	out2, _ := state2.EvalByID(ws, eval2.ID)
  2422  	if !reflect.DeepEqual(eval1, out1) {
  2423  		t.Fatalf("bad: \n%#v\n%#v", out1, eval1)
  2424  	}
  2425  	if !reflect.DeepEqual(eval2, out2) {
  2426  		t.Fatalf("bad: \n%#v\n%#v", out2, eval2)
  2427  	}
  2428  }
  2429  
  2430  func TestFSM_SnapshotRestore_Allocs(t *testing.T) {
  2431  	t.Parallel()
  2432  	// Add some state
  2433  	fsm := testFSM(t)
  2434  	state := fsm.State()
  2435  	alloc1 := mock.Alloc()
  2436  	alloc2 := mock.Alloc()
  2437  	state.UpsertJobSummary(998, mock.JobSummary(alloc1.JobID))
  2438  	state.UpsertJobSummary(999, mock.JobSummary(alloc2.JobID))
  2439  	state.UpsertAllocs(1000, []*structs.Allocation{alloc1})
  2440  	state.UpsertAllocs(1001, []*structs.Allocation{alloc2})
  2441  
  2442  	// Verify the contents
  2443  	fsm2 := testSnapshotRestore(t, fsm)
  2444  	state2 := fsm2.State()
  2445  	ws := memdb.NewWatchSet()
  2446  	out1, _ := state2.AllocByID(ws, alloc1.ID)
  2447  	out2, _ := state2.AllocByID(ws, alloc2.ID)
  2448  	if !reflect.DeepEqual(alloc1, out1) {
  2449  		t.Fatalf("bad: \n%#v\n%#v", out1, alloc1)
  2450  	}
  2451  	if !reflect.DeepEqual(alloc2, out2) {
  2452  		t.Fatalf("bad: \n%#v\n%#v", out2, alloc2)
  2453  	}
  2454  }
  2455  
  2456  func TestFSM_SnapshotRestore_Indexes(t *testing.T) {
  2457  	t.Parallel()
  2458  	// Add some state
  2459  	fsm := testFSM(t)
  2460  	state := fsm.State()
  2461  	node1 := mock.Node()
  2462  	state.UpsertNode(1000, node1)
  2463  
  2464  	// Verify the contents
  2465  	fsm2 := testSnapshotRestore(t, fsm)
  2466  	state2 := fsm2.State()
  2467  
  2468  	index, err := state2.Index("nodes")
  2469  	if err != nil {
  2470  		t.Fatalf("err: %v", err)
  2471  	}
  2472  	if index != 1000 {
  2473  		t.Fatalf("bad: %d", index)
  2474  	}
  2475  }
  2476  
  2477  func TestFSM_SnapshotRestore_TimeTable(t *testing.T) {
  2478  	t.Parallel()
  2479  	// Add some state
  2480  	fsm := testFSM(t)
  2481  
  2482  	tt := fsm.TimeTable()
  2483  	start := time.Now().UTC()
  2484  	tt.Witness(1000, start)
  2485  	tt.Witness(2000, start.Add(10*time.Minute))
  2486  
  2487  	// Verify the contents
  2488  	fsm2 := testSnapshotRestore(t, fsm)
  2489  
  2490  	tt2 := fsm2.TimeTable()
  2491  	if tt2.NearestTime(1500) != start {
  2492  		t.Fatalf("bad")
  2493  	}
  2494  	if tt2.NearestIndex(start.Add(15*time.Minute)) != 2000 {
  2495  		t.Fatalf("bad")
  2496  	}
  2497  }
  2498  
  2499  func TestFSM_SnapshotRestore_PeriodicLaunches(t *testing.T) {
  2500  	t.Parallel()
  2501  	// Add some state
  2502  	fsm := testFSM(t)
  2503  	state := fsm.State()
  2504  	job1 := mock.Job()
  2505  	launch1 := &structs.PeriodicLaunch{
  2506  		ID:        job1.ID,
  2507  		Namespace: job1.Namespace,
  2508  		Launch:    time.Now(),
  2509  	}
  2510  	state.UpsertPeriodicLaunch(1000, launch1)
  2511  	job2 := mock.Job()
  2512  	launch2 := &structs.PeriodicLaunch{
  2513  		ID:        job2.ID,
  2514  		Namespace: job2.Namespace,
  2515  		Launch:    time.Now(),
  2516  	}
  2517  	state.UpsertPeriodicLaunch(1001, launch2)
  2518  
  2519  	// Verify the contents
  2520  	fsm2 := testSnapshotRestore(t, fsm)
  2521  	state2 := fsm2.State()
  2522  	ws := memdb.NewWatchSet()
  2523  	out1, _ := state2.PeriodicLaunchByID(ws, launch1.Namespace, launch1.ID)
  2524  	out2, _ := state2.PeriodicLaunchByID(ws, launch2.Namespace, launch2.ID)
  2525  
  2526  	if !cmp.Equal(launch1, out1) {
  2527  		t.Fatalf("bad: %v", cmp.Diff(launch1, out1))
  2528  	}
  2529  	if !cmp.Equal(launch2, out2) {
  2530  		t.Fatalf("bad: %v", cmp.Diff(launch2, out2))
  2531  	}
  2532  }
  2533  
  2534  func TestFSM_SnapshotRestore_JobSummary(t *testing.T) {
  2535  	t.Parallel()
  2536  	// Add some state
  2537  	fsm := testFSM(t)
  2538  	state := fsm.State()
  2539  
  2540  	job1 := mock.Job()
  2541  	state.UpsertJob(1000, job1)
  2542  	ws := memdb.NewWatchSet()
  2543  	js1, _ := state.JobSummaryByID(ws, job1.Namespace, job1.ID)
  2544  
  2545  	job2 := mock.Job()
  2546  	state.UpsertJob(1001, job2)
  2547  	js2, _ := state.JobSummaryByID(ws, job2.Namespace, job2.ID)
  2548  
  2549  	// Verify the contents
  2550  	fsm2 := testSnapshotRestore(t, fsm)
  2551  	state2 := fsm2.State()
  2552  	out1, _ := state2.JobSummaryByID(ws, job1.Namespace, job1.ID)
  2553  	out2, _ := state2.JobSummaryByID(ws, job2.Namespace, job2.ID)
  2554  	if !reflect.DeepEqual(js1, out1) {
  2555  		t.Fatalf("bad: \n%#v\n%#v", js1, out1)
  2556  	}
  2557  	if !reflect.DeepEqual(js2, out2) {
  2558  		t.Fatalf("bad: \n%#v\n%#v", js2, out2)
  2559  	}
  2560  }
  2561  
  2562  func TestFSM_SnapshotRestore_VaultAccessors(t *testing.T) {
  2563  	t.Parallel()
  2564  	// Add some state
  2565  	fsm := testFSM(t)
  2566  	state := fsm.State()
  2567  	a1 := mock.VaultAccessor()
  2568  	a2 := mock.VaultAccessor()
  2569  	state.UpsertVaultAccessor(1000, []*structs.VaultAccessor{a1, a2})
  2570  
  2571  	// Verify the contents
  2572  	fsm2 := testSnapshotRestore(t, fsm)
  2573  	state2 := fsm2.State()
  2574  	ws := memdb.NewWatchSet()
  2575  	out1, _ := state2.VaultAccessor(ws, a1.Accessor)
  2576  	out2, _ := state2.VaultAccessor(ws, a2.Accessor)
  2577  	if !reflect.DeepEqual(a1, out1) {
  2578  		t.Fatalf("bad: \n%#v\n%#v", out1, a1)
  2579  	}
  2580  	if !reflect.DeepEqual(a2, out2) {
  2581  		t.Fatalf("bad: \n%#v\n%#v", out2, a2)
  2582  	}
  2583  }
  2584  
  2585  func TestFSM_SnapshotRestore_JobVersions(t *testing.T) {
  2586  	t.Parallel()
  2587  	// Add some state
  2588  	fsm := testFSM(t)
  2589  	state := fsm.State()
  2590  	job1 := mock.Job()
  2591  	state.UpsertJob(1000, job1)
  2592  	job2 := mock.Job()
  2593  	job2.ID = job1.ID
  2594  	state.UpsertJob(1001, job2)
  2595  
  2596  	// Verify the contents
  2597  	ws := memdb.NewWatchSet()
  2598  	fsm2 := testSnapshotRestore(t, fsm)
  2599  	state2 := fsm2.State()
  2600  	out1, _ := state2.JobByIDAndVersion(ws, job1.Namespace, job1.ID, job1.Version)
  2601  	out2, _ := state2.JobByIDAndVersion(ws, job2.Namespace, job2.ID, job2.Version)
  2602  	if !reflect.DeepEqual(job1, out1) {
  2603  		t.Fatalf("bad: \n%#v\n%#v", out1, job1)
  2604  	}
  2605  	if !reflect.DeepEqual(job2, out2) {
  2606  		t.Fatalf("bad: \n%#v\n%#v", out2, job2)
  2607  	}
  2608  	if job2.Version != 1 {
  2609  		t.Fatalf("bad: \n%#v\n%#v", 1, job2)
  2610  	}
  2611  }
  2612  
  2613  func TestFSM_SnapshotRestore_Deployments(t *testing.T) {
  2614  	t.Parallel()
  2615  	// Add some state
  2616  	fsm := testFSM(t)
  2617  	state := fsm.State()
  2618  	d1 := mock.Deployment()
  2619  	d2 := mock.Deployment()
  2620  
  2621  	j := mock.Job()
  2622  	d1.JobID = j.ID
  2623  	d2.JobID = j.ID
  2624  
  2625  	state.UpsertJob(999, j)
  2626  	state.UpsertDeployment(1000, d1)
  2627  	state.UpsertDeployment(1001, d2)
  2628  
  2629  	// Verify the contents
  2630  	fsm2 := testSnapshotRestore(t, fsm)
  2631  	state2 := fsm2.State()
  2632  	ws := memdb.NewWatchSet()
  2633  	out1, _ := state2.DeploymentByID(ws, d1.ID)
  2634  	out2, _ := state2.DeploymentByID(ws, d2.ID)
  2635  	if !reflect.DeepEqual(d1, out1) {
  2636  		t.Fatalf("bad: \n%#v\n%#v", out1, d1)
  2637  	}
  2638  	if !reflect.DeepEqual(d2, out2) {
  2639  		t.Fatalf("bad: \n%#v\n%#v", out2, d2)
  2640  	}
  2641  }
  2642  
  2643  func TestFSM_SnapshotRestore_ACLPolicy(t *testing.T) {
  2644  	t.Parallel()
  2645  	// Add some state
  2646  	fsm := testFSM(t)
  2647  	state := fsm.State()
  2648  	p1 := mock.ACLPolicy()
  2649  	p2 := mock.ACLPolicy()
  2650  	state.UpsertACLPolicies(1000, []*structs.ACLPolicy{p1, p2})
  2651  
  2652  	// Verify the contents
  2653  	fsm2 := testSnapshotRestore(t, fsm)
  2654  	state2 := fsm2.State()
  2655  	ws := memdb.NewWatchSet()
  2656  	out1, _ := state2.ACLPolicyByName(ws, p1.Name)
  2657  	out2, _ := state2.ACLPolicyByName(ws, p2.Name)
  2658  	assert.Equal(t, p1, out1)
  2659  	assert.Equal(t, p2, out2)
  2660  }
  2661  
  2662  func TestFSM_SnapshotRestore_ACLTokens(t *testing.T) {
  2663  	t.Parallel()
  2664  	// Add some state
  2665  	fsm := testFSM(t)
  2666  	state := fsm.State()
  2667  	tk1 := mock.ACLToken()
  2668  	tk2 := mock.ACLToken()
  2669  	state.UpsertACLTokens(1000, []*structs.ACLToken{tk1, tk2})
  2670  
  2671  	// Verify the contents
  2672  	fsm2 := testSnapshotRestore(t, fsm)
  2673  	state2 := fsm2.State()
  2674  	ws := memdb.NewWatchSet()
  2675  	out1, _ := state2.ACLTokenByAccessorID(ws, tk1.AccessorID)
  2676  	out2, _ := state2.ACLTokenByAccessorID(ws, tk2.AccessorID)
  2677  	assert.Equal(t, tk1, out1)
  2678  	assert.Equal(t, tk2, out2)
  2679  }
  2680  
  2681  func TestFSM_SnapshotRestore_SchedulerConfiguration(t *testing.T) {
  2682  	t.Parallel()
  2683  	// Add some state
  2684  	fsm := testFSM(t)
  2685  	state := fsm.State()
  2686  	schedConfig := &structs.SchedulerConfiguration{
  2687  		PreemptionConfig: structs.PreemptionConfig{
  2688  			SystemSchedulerEnabled: true,
  2689  		},
  2690  	}
  2691  	state.SchedulerSetConfig(1000, schedConfig)
  2692  
  2693  	// Verify the contents
  2694  	require := require.New(t)
  2695  	fsm2 := testSnapshotRestore(t, fsm)
  2696  	state2 := fsm2.State()
  2697  	index, out, err := state2.SchedulerConfig()
  2698  	require.Nil(err)
  2699  	require.EqualValues(1000, index)
  2700  	require.Equal(schedConfig, out)
  2701  
  2702  }
  2703  
  2704  func TestFSM_ReconcileSummaries(t *testing.T) {
  2705  	t.Parallel()
  2706  	// Add some state
  2707  	fsm := testFSM(t)
  2708  	state := fsm.State()
  2709  
  2710  	// Add a node
  2711  	node := mock.Node()
  2712  	state.UpsertNode(800, node)
  2713  
  2714  	// Make a job so that none of the tasks can be placed
  2715  	job1 := mock.Job()
  2716  	job1.TaskGroups[0].Tasks[0].Resources.CPU = 5000
  2717  	state.UpsertJob(1000, job1)
  2718  
  2719  	// make a job which can make partial progress
  2720  	alloc := mock.Alloc()
  2721  	alloc.NodeID = node.ID
  2722  	state.UpsertJob(1010, alloc.Job)
  2723  	state.UpsertAllocs(1011, []*structs.Allocation{alloc})
  2724  
  2725  	// Delete the summaries
  2726  	state.DeleteJobSummary(1030, job1.Namespace, job1.ID)
  2727  	state.DeleteJobSummary(1040, alloc.Namespace, alloc.Job.ID)
  2728  
  2729  	req := structs.GenericRequest{}
  2730  	buf, err := structs.Encode(structs.ReconcileJobSummariesRequestType, req)
  2731  	if err != nil {
  2732  		t.Fatalf("err: %v", err)
  2733  	}
  2734  
  2735  	resp := fsm.Apply(makeLog(buf))
  2736  	if resp != nil {
  2737  		t.Fatalf("resp: %v", resp)
  2738  	}
  2739  
  2740  	ws := memdb.NewWatchSet()
  2741  	out1, _ := state.JobSummaryByID(ws, job1.Namespace, job1.ID)
  2742  	expected := structs.JobSummary{
  2743  		JobID:     job1.ID,
  2744  		Namespace: job1.Namespace,
  2745  		Summary: map[string]structs.TaskGroupSummary{
  2746  			"web": {
  2747  				Queued: 10,
  2748  			},
  2749  		},
  2750  		CreateIndex: 1000,
  2751  		ModifyIndex: out1.ModifyIndex,
  2752  	}
  2753  	if !reflect.DeepEqual(&expected, out1) {
  2754  		t.Fatalf("expected: %#v, actual: %#v", &expected, out1)
  2755  	}
  2756  
  2757  	// This exercises the code path which adds the allocations made by the
  2758  	// planner and the number of unplaced allocations in the reconcile summaries
  2759  	// codepath
  2760  	out2, _ := state.JobSummaryByID(ws, alloc.Namespace, alloc.Job.ID)
  2761  	expected = structs.JobSummary{
  2762  		JobID:     alloc.Job.ID,
  2763  		Namespace: alloc.Job.Namespace,
  2764  		Summary: map[string]structs.TaskGroupSummary{
  2765  			"web": {
  2766  				Queued:   9,
  2767  				Starting: 1,
  2768  			},
  2769  		},
  2770  		CreateIndex: 1010,
  2771  		ModifyIndex: out2.ModifyIndex,
  2772  	}
  2773  	if !reflect.DeepEqual(&expected, out2) {
  2774  		t.Fatalf("Diff % #v", pretty.Diff(&expected, out2))
  2775  	}
  2776  }
  2777  
  2778  // COMPAT: Remove in 0.11
  2779  func TestFSM_ReconcileParentJobSummary(t *testing.T) {
  2780  	// This test exercises code to handle https://github.com/hashicorp/nomad/issues/3886
  2781  	t.Parallel()
  2782  
  2783  	require := require.New(t)
  2784  	// Add some state
  2785  	fsm := testFSM(t)
  2786  	state := fsm.State()
  2787  
  2788  	// Add a node
  2789  	node := mock.Node()
  2790  	state.UpsertNode(800, node)
  2791  
  2792  	// Make a parameterized job
  2793  	job1 := mock.BatchJob()
  2794  	job1.ID = "test"
  2795  	job1.ParameterizedJob = &structs.ParameterizedJobConfig{
  2796  		Payload: "random",
  2797  	}
  2798  	job1.TaskGroups[0].Count = 1
  2799  	state.UpsertJob(1000, job1)
  2800  
  2801  	// Make a child job
  2802  	childJob := job1.Copy()
  2803  	childJob.ID = job1.ID + "dispatch-23423423"
  2804  	childJob.ParentID = job1.ID
  2805  	childJob.Dispatched = true
  2806  	childJob.Status = structs.JobStatusRunning
  2807  
  2808  	// Create an alloc for child job
  2809  	alloc := mock.Alloc()
  2810  	alloc.NodeID = node.ID
  2811  	alloc.Job = childJob
  2812  	alloc.JobID = childJob.ID
  2813  	alloc.ClientStatus = structs.AllocClientStatusRunning
  2814  
  2815  	state.UpsertJob(1010, childJob)
  2816  	state.UpsertAllocs(1011, []*structs.Allocation{alloc})
  2817  
  2818  	// Make the summary incorrect in the state store
  2819  	summary, err := state.JobSummaryByID(nil, job1.Namespace, job1.ID)
  2820  	require.Nil(err)
  2821  
  2822  	summary.Children = nil
  2823  	summary.Summary = make(map[string]structs.TaskGroupSummary)
  2824  	summary.Summary["web"] = structs.TaskGroupSummary{
  2825  		Queued: 1,
  2826  	}
  2827  
  2828  	req := structs.GenericRequest{}
  2829  	buf, err := structs.Encode(structs.ReconcileJobSummariesRequestType, req)
  2830  	require.Nil(err)
  2831  
  2832  	resp := fsm.Apply(makeLog(buf))
  2833  	require.Nil(resp)
  2834  
  2835  	ws := memdb.NewWatchSet()
  2836  	out1, _ := state.JobSummaryByID(ws, job1.Namespace, job1.ID)
  2837  	expected := structs.JobSummary{
  2838  		JobID:       job1.ID,
  2839  		Namespace:   job1.Namespace,
  2840  		Summary:     make(map[string]structs.TaskGroupSummary),
  2841  		CreateIndex: 1000,
  2842  		ModifyIndex: out1.ModifyIndex,
  2843  		Children: &structs.JobChildrenSummary{
  2844  			Running: 1,
  2845  		},
  2846  	}
  2847  	require.Equal(&expected, out1)
  2848  }
  2849  
  2850  func TestFSM_LeakedDeployments(t *testing.T) {
  2851  	t.Parallel()
  2852  	require := require.New(t)
  2853  
  2854  	// Add some state
  2855  	fsm := testFSM(t)
  2856  	state := fsm.State()
  2857  	d := mock.Deployment()
  2858  	require.NoError(state.UpsertDeployment(1000, d))
  2859  
  2860  	// Verify the contents
  2861  	fsm2 := testSnapshotRestore(t, fsm)
  2862  	state2 := fsm2.State()
  2863  	out, _ := state2.DeploymentByID(nil, d.ID)
  2864  	require.NotNil(out)
  2865  	require.Equal(structs.DeploymentStatusCancelled, out.Status)
  2866  }
  2867  
  2868  func TestFSM_Autopilot(t *testing.T) {
  2869  	t.Parallel()
  2870  	fsm := testFSM(t)
  2871  
  2872  	// Set the autopilot config using a request.
  2873  	req := structs.AutopilotSetConfigRequest{
  2874  		Datacenter: "dc1",
  2875  		Config: structs.AutopilotConfig{
  2876  			CleanupDeadServers:   true,
  2877  			LastContactThreshold: 10 * time.Second,
  2878  			MaxTrailingLogs:      300,
  2879  		},
  2880  	}
  2881  	buf, err := structs.Encode(structs.AutopilotRequestType, req)
  2882  	if err != nil {
  2883  		t.Fatalf("err: %v", err)
  2884  	}
  2885  	resp := fsm.Apply(makeLog(buf))
  2886  	if _, ok := resp.(error); ok {
  2887  		t.Fatalf("bad: %v", resp)
  2888  	}
  2889  
  2890  	// Verify key is set directly in the state store.
  2891  	_, config, err := fsm.state.AutopilotConfig()
  2892  	if err != nil {
  2893  		t.Fatalf("err: %v", err)
  2894  	}
  2895  	if config.CleanupDeadServers != req.Config.CleanupDeadServers {
  2896  		t.Fatalf("bad: %v", config.CleanupDeadServers)
  2897  	}
  2898  	if config.LastContactThreshold != req.Config.LastContactThreshold {
  2899  		t.Fatalf("bad: %v", config.LastContactThreshold)
  2900  	}
  2901  	if config.MaxTrailingLogs != req.Config.MaxTrailingLogs {
  2902  		t.Fatalf("bad: %v", config.MaxTrailingLogs)
  2903  	}
  2904  
  2905  	// Now use CAS and provide an old index
  2906  	req.CAS = true
  2907  	req.Config.CleanupDeadServers = false
  2908  	req.Config.ModifyIndex = config.ModifyIndex - 1
  2909  	buf, err = structs.Encode(structs.AutopilotRequestType, req)
  2910  	if err != nil {
  2911  		t.Fatalf("err: %v", err)
  2912  	}
  2913  	resp = fsm.Apply(makeLog(buf))
  2914  	if _, ok := resp.(error); ok {
  2915  		t.Fatalf("bad: %v", resp)
  2916  	}
  2917  
  2918  	_, config, err = fsm.state.AutopilotConfig()
  2919  	if err != nil {
  2920  		t.Fatalf("err: %v", err)
  2921  	}
  2922  	if !config.CleanupDeadServers {
  2923  		t.Fatalf("bad: %v", config.CleanupDeadServers)
  2924  	}
  2925  }
  2926  
  2927  func TestFSM_SchedulerConfig(t *testing.T) {
  2928  	t.Parallel()
  2929  	fsm := testFSM(t)
  2930  
  2931  	require := require.New(t)
  2932  
  2933  	// Set the scheduler config using a request.
  2934  	req := structs.SchedulerSetConfigRequest{
  2935  		Config: structs.SchedulerConfiguration{
  2936  			PreemptionConfig: structs.PreemptionConfig{
  2937  				SystemSchedulerEnabled: true,
  2938  				BatchSchedulerEnabled:  true,
  2939  			},
  2940  		},
  2941  	}
  2942  	buf, err := structs.Encode(structs.SchedulerConfigRequestType, req)
  2943  	require.Nil(err)
  2944  
  2945  	resp := fsm.Apply(makeLog(buf))
  2946  	if _, ok := resp.(error); ok {
  2947  		t.Fatalf("bad: %v", resp)
  2948  	}
  2949  
  2950  	// Verify key is set directly in the state store.
  2951  	_, config, err := fsm.state.SchedulerConfig()
  2952  	require.Nil(err)
  2953  
  2954  	require.Equal(config.PreemptionConfig.SystemSchedulerEnabled, req.Config.PreemptionConfig.SystemSchedulerEnabled)
  2955  	require.Equal(config.PreemptionConfig.BatchSchedulerEnabled, req.Config.PreemptionConfig.BatchSchedulerEnabled)
  2956  
  2957  	// Now use CAS and provide an old index
  2958  	req.CAS = true
  2959  	req.Config.PreemptionConfig = structs.PreemptionConfig{SystemSchedulerEnabled: false, BatchSchedulerEnabled: false}
  2960  	req.Config.ModifyIndex = config.ModifyIndex - 1
  2961  	buf, err = structs.Encode(structs.SchedulerConfigRequestType, req)
  2962  	require.Nil(err)
  2963  
  2964  	resp = fsm.Apply(makeLog(buf))
  2965  	if _, ok := resp.(error); ok {
  2966  		t.Fatalf("bad: %v", resp)
  2967  	}
  2968  
  2969  	_, config, err = fsm.state.SchedulerConfig()
  2970  	require.Nil(err)
  2971  	// Verify that preemption is still enabled
  2972  	require.True(config.PreemptionConfig.SystemSchedulerEnabled)
  2973  	require.True(config.PreemptionConfig.BatchSchedulerEnabled)
  2974  }