github.com/zoomfoo/nomad@v0.8.5-0.20180907175415-f28fd3a1a056/nomad/fsm_test.go (about)

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