github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/swarmkit/manager/controlapi/node_test.go (about)

     1  package controlapi
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"testing"
     8  
     9  	"github.com/docker/swarmkit/api"
    10  	cautils "github.com/docker/swarmkit/ca/testutils"
    11  	"github.com/docker/swarmkit/identity"
    12  	raftutils "github.com/docker/swarmkit/manager/state/raft/testutils"
    13  	"github.com/docker/swarmkit/manager/state/store"
    14  	"github.com/docker/swarmkit/testutils"
    15  	"github.com/sirupsen/logrus"
    16  	"github.com/stretchr/testify/assert"
    17  	"github.com/stretchr/testify/require"
    18  	"google.golang.org/grpc/codes"
    19  	"google.golang.org/grpc/grpclog"
    20  )
    21  
    22  func createNode(t *testing.T, ts *testServer, id string, role api.NodeRole, membership api.NodeSpec_Membership, state api.NodeStatus_State) *api.Node {
    23  	node := &api.Node{
    24  		ID: id,
    25  		Spec: api.NodeSpec{
    26  			Membership: membership,
    27  		},
    28  		Status: api.NodeStatus{
    29  			State: state,
    30  		},
    31  		Role: role,
    32  	}
    33  	err := ts.Store.Update(func(tx store.Tx) error {
    34  		return store.CreateNode(tx, node)
    35  	})
    36  	assert.NoError(t, err)
    37  	return node
    38  }
    39  
    40  func TestGetNode(t *testing.T) {
    41  	ts := newTestServer(t)
    42  	defer ts.Stop()
    43  
    44  	_, err := ts.Client.GetNode(context.Background(), &api.GetNodeRequest{})
    45  	assert.Error(t, err)
    46  	assert.Equal(t, codes.InvalidArgument, testutils.ErrorCode(err))
    47  
    48  	_, err = ts.Client.GetNode(context.Background(), &api.GetNodeRequest{NodeID: "invalid"})
    49  	assert.Error(t, err)
    50  	assert.Equal(t, codes.NotFound, testutils.ErrorCode(err))
    51  
    52  	node := createNode(t, ts, "id", api.NodeRoleManager, api.NodeMembershipAccepted, api.NodeStatus_READY)
    53  	r, err := ts.Client.GetNode(context.Background(), &api.GetNodeRequest{NodeID: node.ID})
    54  	assert.NoError(t, err)
    55  	assert.Equal(t, node.ID, r.Node.ID)
    56  }
    57  
    58  func TestListNodes(t *testing.T) {
    59  
    60  	ts := newTestServer(t)
    61  	defer ts.Stop()
    62  	r, err := ts.Client.ListNodes(context.Background(), &api.ListNodesRequest{})
    63  	assert.NoError(t, err)
    64  	assert.Empty(t, r.Nodes)
    65  
    66  	createNode(t, ts, "id1", api.NodeRoleManager, api.NodeMembershipAccepted, api.NodeStatus_READY)
    67  	r, err = ts.Client.ListNodes(context.Background(), &api.ListNodesRequest{})
    68  	assert.NoError(t, err)
    69  	assert.Equal(t, 1, len(r.Nodes))
    70  
    71  	createNode(t, ts, "id2", api.NodeRoleWorker, api.NodeMembershipAccepted, api.NodeStatus_READY)
    72  	createNode(t, ts, "id3", api.NodeRoleWorker, api.NodeMembershipPending, api.NodeStatus_READY)
    73  	r, err = ts.Client.ListNodes(context.Background(), &api.ListNodesRequest{})
    74  	assert.NoError(t, err)
    75  	assert.Equal(t, 3, len(r.Nodes))
    76  
    77  	// List by role.
    78  	r, err = ts.Client.ListNodes(context.Background(),
    79  		&api.ListNodesRequest{
    80  			Filters: &api.ListNodesRequest_Filters{
    81  				Roles: []api.NodeRole{api.NodeRoleManager},
    82  			},
    83  		},
    84  	)
    85  	assert.NoError(t, err)
    86  	assert.Equal(t, 1, len(r.Nodes))
    87  	r, err = ts.Client.ListNodes(context.Background(),
    88  		&api.ListNodesRequest{
    89  			Filters: &api.ListNodesRequest_Filters{
    90  				Roles: []api.NodeRole{api.NodeRoleWorker},
    91  			},
    92  		},
    93  	)
    94  	assert.NoError(t, err)
    95  	assert.Equal(t, 2, len(r.Nodes))
    96  	r, err = ts.Client.ListNodes(context.Background(),
    97  		&api.ListNodesRequest{
    98  			Filters: &api.ListNodesRequest_Filters{
    99  				Roles: []api.NodeRole{api.NodeRoleManager, api.NodeRoleWorker},
   100  			},
   101  		},
   102  	)
   103  	assert.NoError(t, err)
   104  	assert.Equal(t, 3, len(r.Nodes))
   105  
   106  	// List by membership.
   107  	r, err = ts.Client.ListNodes(context.Background(),
   108  		&api.ListNodesRequest{
   109  			Filters: &api.ListNodesRequest_Filters{
   110  				Memberships: []api.NodeSpec_Membership{api.NodeMembershipAccepted},
   111  			},
   112  		},
   113  	)
   114  	assert.NoError(t, err)
   115  	assert.Equal(t, 2, len(r.Nodes))
   116  	r, err = ts.Client.ListNodes(context.Background(),
   117  		&api.ListNodesRequest{
   118  			Filters: &api.ListNodesRequest_Filters{
   119  				Memberships: []api.NodeSpec_Membership{api.NodeMembershipPending},
   120  			},
   121  		},
   122  	)
   123  	assert.NoError(t, err)
   124  	assert.Equal(t, 1, len(r.Nodes))
   125  	r, err = ts.Client.ListNodes(context.Background(),
   126  		&api.ListNodesRequest{
   127  			Filters: &api.ListNodesRequest_Filters{
   128  				Memberships: []api.NodeSpec_Membership{api.NodeMembershipAccepted, api.NodeMembershipPending},
   129  			},
   130  		},
   131  	)
   132  	assert.NoError(t, err)
   133  	assert.Equal(t, 3, len(r.Nodes))
   134  	r, err = ts.Client.ListNodes(context.Background(),
   135  		&api.ListNodesRequest{
   136  			Filters: &api.ListNodesRequest_Filters{
   137  				Roles:       []api.NodeRole{api.NodeRoleWorker},
   138  				Memberships: []api.NodeSpec_Membership{api.NodeMembershipPending},
   139  			},
   140  		},
   141  	)
   142  	assert.NoError(t, err)
   143  	assert.Equal(t, 1, len(r.Nodes))
   144  }
   145  
   146  func TestListNodesWithLabelFilter(t *testing.T) {
   147  	ts := newTestServer(t)
   148  	defer ts.Stop()
   149  
   150  	// satify these test cases:
   151  	// Filtering on engine labels
   152  	// - returns all nodes with matching engine labels
   153  	// - does not return nodes with matching node labels
   154  	// - does not return nodes with non-matching engine labels
   155  	// Filtering on nodes:
   156  	// - returns all nodes with matching node labels
   157  	// - does not return nodes with matching engine labels
   158  	// - does not return nodes with non-matching node labels
   159  
   160  	// we'll need 3 nodes for this test.
   161  	nodes := make([]*api.Node, 3)
   162  	nodes[0] = &api.Node{
   163  		ID: "node0",
   164  		Spec: api.NodeSpec{
   165  			Annotations: api.Annotations{
   166  				Labels: map[string]string{
   167  					"allcommon":  "node",
   168  					"nodelabel1": "shouldmatch",
   169  					"nodelabel2": "unique1",
   170  				},
   171  			},
   172  		},
   173  		Description: &api.NodeDescription{
   174  			Engine: &api.EngineDescription{
   175  				Labels: map[string]string{
   176  					"allcommon":    "engine",
   177  					"enginelabel1": "shouldmatch",
   178  					"enginelabel2": "unique1",
   179  				},
   180  			},
   181  		},
   182  	}
   183  
   184  	nodes[1] = &api.Node{
   185  		ID: "node1",
   186  		Spec: api.NodeSpec{
   187  			Annotations: api.Annotations{
   188  				Labels: map[string]string{
   189  					"allcommon":  "node",
   190  					"nodelabel1": "shouldmatch",
   191  					"nodelabel2": "unique2",
   192  				},
   193  			},
   194  		},
   195  		Description: &api.NodeDescription{
   196  			Engine: &api.EngineDescription{
   197  				Labels: map[string]string{
   198  					"allcommon":    "engine",
   199  					"enginelabel1": "shouldmatch",
   200  					"enginelabel2": "unique2",
   201  				},
   202  			},
   203  		},
   204  	}
   205  	nodes[2] = &api.Node{
   206  		ID: "node2",
   207  		Spec: api.NodeSpec{
   208  			Annotations: api.Annotations{
   209  				Labels: map[string]string{
   210  					"allcommon":  "node",
   211  					"nodelabel1": "shouldnevermatch",
   212  					"nodelabel2": "unique1",
   213  				},
   214  			},
   215  		},
   216  		Description: &api.NodeDescription{
   217  			Engine: &api.EngineDescription{
   218  				Labels: map[string]string{
   219  					"allcommon":    "engine",
   220  					"enginelabel1": "shouldnevermatch",
   221  					"enginelabel2": "unique1",
   222  				},
   223  			},
   224  		},
   225  	}
   226  
   227  	// createNode gives us a bunch of fields we don't care about. instead, do a
   228  	// store update directly
   229  	err := ts.Store.Update(func(tx store.Tx) error {
   230  		for _, node := range nodes {
   231  			if err := store.CreateNode(tx, node); err != nil {
   232  				return err
   233  			}
   234  		}
   235  		return nil
   236  	})
   237  	require.NoError(t, err, "error creating nodes")
   238  
   239  	// now try listing nodes
   240  
   241  	// listing with an empty set of labels should return all nodes
   242  	t.Log("list nodes with no filters")
   243  	r, err := ts.Client.ListNodes(context.Background(), &api.ListNodesRequest{
   244  		Filters: &api.ListNodesRequest_Filters{},
   245  	})
   246  	assert.NoError(t, err)
   247  	assert.Len(t, r.Nodes, 3)
   248  
   249  	t.Log("list nodes with allcommon=engine engine label filter")
   250  	r, err = ts.Client.ListNodes(context.Background(), &api.ListNodesRequest{
   251  		Filters: &api.ListNodesRequest_Filters{
   252  			Labels: map[string]string{"allcommon": "engine"},
   253  		},
   254  	})
   255  	assert.NoError(t, err)
   256  	assert.Len(t, r.Nodes, 3)
   257  
   258  	t.Log("list nodes with allcommon=node engine label filter")
   259  	r, err = ts.Client.ListNodes(context.Background(), &api.ListNodesRequest{
   260  		Filters: &api.ListNodesRequest_Filters{
   261  			Labels: map[string]string{"allcommon": "node"},
   262  		},
   263  	})
   264  	// nothing should be returned; allcommon=engine on engine labels
   265  	assert.NoError(t, err)
   266  	assert.Len(t, r.Nodes, 0)
   267  
   268  	t.Log("list nodes with allcommon=node node filter")
   269  	r, err = ts.Client.ListNodes(context.Background(), &api.ListNodesRequest{
   270  		Filters: &api.ListNodesRequest_Filters{
   271  			NodeLabels: map[string]string{"allcommon": "node"},
   272  		},
   273  	})
   274  	assert.NoError(t, err)
   275  	assert.Len(t, r.Nodes, 3)
   276  
   277  	t.Log("list nodes with allcommon=engine node filter")
   278  	r, err = ts.Client.ListNodes(context.Background(), &api.ListNodesRequest{
   279  		Filters: &api.ListNodesRequest_Filters{
   280  			NodeLabels: map[string]string{"allcommon": "engine"},
   281  		},
   282  	})
   283  	assert.NoError(t, err)
   284  	assert.Len(t, r.Nodes, 0)
   285  
   286  	t.Log("list nodes with nodelabel1=shouldmatch node filter")
   287  	r, err = ts.Client.ListNodes(context.Background(), &api.ListNodesRequest{
   288  		Filters: &api.ListNodesRequest_Filters{
   289  			NodeLabels: map[string]string{"nodelabel1": "shouldmatch"},
   290  		},
   291  	})
   292  	// should only return the first 2 nodes
   293  	assert.NoError(t, err)
   294  	assert.Len(t, r.Nodes, 2)
   295  	assert.Contains(t, r.Nodes, nodes[0])
   296  	assert.Contains(t, r.Nodes, nodes[1])
   297  
   298  	t.Log("list nodes with enginelabel1=shouldmatch engine filter")
   299  	r, err = ts.Client.ListNodes(context.Background(), &api.ListNodesRequest{
   300  		Filters: &api.ListNodesRequest_Filters{
   301  			Labels: map[string]string{"enginelabel1": "shouldmatch"},
   302  		},
   303  	})
   304  	// should only return the first 2 nodes
   305  	assert.NoError(t, err)
   306  	assert.Len(t, r.Nodes, 2)
   307  	assert.Contains(t, r.Nodes, nodes[0])
   308  	assert.Contains(t, r.Nodes, nodes[1])
   309  
   310  	t.Log("list nodes with node two engine filters")
   311  	r, err = ts.Client.ListNodes(context.Background(), &api.ListNodesRequest{
   312  		Filters: &api.ListNodesRequest_Filters{
   313  			Labels: map[string]string{
   314  				"enginelabel1": "shouldmatch",
   315  				"enginelabel2": "unique1",
   316  			},
   317  		},
   318  	})
   319  	// should only return the first node
   320  	assert.NoError(t, err)
   321  	assert.Len(t, r.Nodes, 1)
   322  	assert.Contains(t, r.Nodes, nodes[0])
   323  
   324  	t.Log("list nodes with node two node filters")
   325  	r, err = ts.Client.ListNodes(context.Background(), &api.ListNodesRequest{
   326  		Filters: &api.ListNodesRequest_Filters{
   327  			NodeLabels: map[string]string{
   328  				"nodelabel1": "shouldmatch",
   329  				"nodelabel2": "unique1",
   330  			},
   331  		},
   332  	})
   333  	// should only return the first node
   334  	assert.NoError(t, err)
   335  	assert.Len(t, r.Nodes, 1)
   336  	assert.Contains(t, r.Nodes, nodes[0])
   337  
   338  	t.Log("list nodes with both engine and node filters")
   339  	r, err = ts.Client.ListNodes(context.Background(), &api.ListNodesRequest{
   340  		Filters: &api.ListNodesRequest_Filters{
   341  			// all nodes pass this filter
   342  			Labels: map[string]string{
   343  				"enginelabel1": "",
   344  			},
   345  			// only 0 and 2 pass this filter
   346  			NodeLabels: map[string]string{
   347  				"nodelabel2": "unique1",
   348  			},
   349  		},
   350  	})
   351  	assert.NoError(t, err)
   352  	assert.Len(t, r.Nodes, 2)
   353  	assert.Contains(t, r.Nodes, nodes[0])
   354  	assert.Contains(t, r.Nodes, nodes[2])
   355  }
   356  
   357  func TestRemoveNodes(t *testing.T) {
   358  	ts := newTestServer(t)
   359  	defer ts.Stop()
   360  
   361  	ts.Store.Update(func(tx store.Tx) error {
   362  		store.CreateCluster(tx, &api.Cluster{
   363  			ID: identity.NewID(),
   364  			Spec: api.ClusterSpec{
   365  				Annotations: api.Annotations{
   366  					Name: store.DefaultClusterName,
   367  				},
   368  			},
   369  		})
   370  		return nil
   371  	})
   372  
   373  	r, err := ts.Client.ListNodes(context.Background(), &api.ListNodesRequest{})
   374  	assert.NoError(t, err)
   375  	assert.Empty(t, r.Nodes)
   376  
   377  	createNode(t, ts, "id1", api.NodeRoleManager, api.NodeMembershipAccepted, api.NodeStatus_READY)
   378  	r, err = ts.Client.ListNodes(context.Background(), &api.ListNodesRequest{})
   379  	assert.NoError(t, err)
   380  	assert.Len(t, r.Nodes, 1)
   381  
   382  	createNode(t, ts, "id2", api.NodeRoleWorker, api.NodeMembershipAccepted, api.NodeStatus_READY)
   383  	createNode(t, ts, "id3", api.NodeRoleWorker, api.NodeMembershipPending, api.NodeStatus_UNKNOWN)
   384  	r, err = ts.Client.ListNodes(context.Background(), &api.ListNodesRequest{})
   385  	assert.NoError(t, err)
   386  	assert.Len(t, r.Nodes, 3)
   387  
   388  	// Attempt to remove a ready node without force
   389  	_, err = ts.Client.RemoveNode(context.Background(),
   390  		&api.RemoveNodeRequest{
   391  			NodeID: "id2",
   392  			Force:  false,
   393  		},
   394  	)
   395  	assert.Error(t, err)
   396  
   397  	r, err = ts.Client.ListNodes(context.Background(),
   398  		&api.ListNodesRequest{
   399  			Filters: &api.ListNodesRequest_Filters{
   400  				Roles: []api.NodeRole{api.NodeRoleManager, api.NodeRoleWorker},
   401  			},
   402  		},
   403  	)
   404  	assert.NoError(t, err)
   405  	assert.Len(t, r.Nodes, 3)
   406  
   407  	// Attempt to remove a ready node with force
   408  	_, err = ts.Client.RemoveNode(context.Background(),
   409  		&api.RemoveNodeRequest{
   410  			NodeID: "id2",
   411  			Force:  true,
   412  		},
   413  	)
   414  	assert.NoError(t, err)
   415  
   416  	r, err = ts.Client.ListNodes(context.Background(),
   417  		&api.ListNodesRequest{
   418  			Filters: &api.ListNodesRequest_Filters{
   419  				Roles: []api.NodeRole{api.NodeRoleManager, api.NodeRoleWorker},
   420  			},
   421  		},
   422  	)
   423  	assert.NoError(t, err)
   424  	assert.Len(t, r.Nodes, 2)
   425  
   426  	clusterResp, err := ts.Client.ListClusters(context.Background(), &api.ListClustersRequest{})
   427  	assert.NoError(t, err)
   428  	require.Len(t, clusterResp.Clusters, 1)
   429  	require.Len(t, clusterResp.Clusters[0].BlacklistedCertificates, 1)
   430  	_, ok := clusterResp.Clusters[0].BlacklistedCertificates["id2"]
   431  	assert.True(t, ok)
   432  
   433  	// Attempt to remove a non-ready node without force
   434  	_, err = ts.Client.RemoveNode(context.Background(),
   435  		&api.RemoveNodeRequest{
   436  			NodeID: "id3",
   437  			Force:  false,
   438  		},
   439  	)
   440  	assert.NoError(t, err)
   441  
   442  	r, err = ts.Client.ListNodes(context.Background(),
   443  		&api.ListNodesRequest{
   444  			Filters: &api.ListNodesRequest_Filters{
   445  				Roles: []api.NodeRole{api.NodeRoleManager, api.NodeRoleWorker},
   446  			},
   447  		},
   448  	)
   449  	assert.NoError(t, err)
   450  	assert.Len(t, r.Nodes, 1)
   451  }
   452  
   453  func init() {
   454  	grpclog.SetLoggerV2(grpclog.NewLoggerV2(ioutil.Discard, ioutil.Discard, ioutil.Discard))
   455  	logrus.SetOutput(ioutil.Discard)
   456  }
   457  
   458  func getMap(t *testing.T, nodes []*api.Node) map[uint64]*api.ManagerStatus {
   459  	m := make(map[uint64]*api.ManagerStatus)
   460  	for _, n := range nodes {
   461  		if n.ManagerStatus != nil {
   462  			m[n.ManagerStatus.RaftID] = n.ManagerStatus
   463  		}
   464  	}
   465  	return m
   466  }
   467  
   468  func TestListManagerNodes(t *testing.T) {
   469  	t.Parallel()
   470  
   471  	tc := cautils.NewTestCA(t)
   472  	defer tc.Stop()
   473  	ts := newTestServer(t)
   474  	defer ts.Stop()
   475  
   476  	nodes, clockSource := raftutils.NewRaftCluster(t, tc)
   477  	defer raftutils.TeardownCluster(nodes)
   478  
   479  	// Create a node object for each of the managers
   480  	assert.NoError(t, nodes[1].MemoryStore().Update(func(tx store.Tx) error {
   481  		assert.NoError(t, store.CreateNode(tx, &api.Node{ID: nodes[1].SecurityConfig.ClientTLSCreds.NodeID()}))
   482  		assert.NoError(t, store.CreateNode(tx, &api.Node{ID: nodes[2].SecurityConfig.ClientTLSCreds.NodeID()}))
   483  		assert.NoError(t, store.CreateNode(tx, &api.Node{ID: nodes[3].SecurityConfig.ClientTLSCreds.NodeID()}))
   484  		return nil
   485  	}))
   486  
   487  	// Assign one of the raft node to the test server
   488  	ts.Server.raft = nodes[1].Node
   489  	ts.Server.store = nodes[1].MemoryStore()
   490  
   491  	// There should be 3 reachable managers listed
   492  	r, err := ts.Client.ListNodes(context.Background(), &api.ListNodesRequest{})
   493  	assert.NoError(t, err)
   494  	assert.NotNil(t, r)
   495  	managers := getMap(t, r.Nodes)
   496  	assert.Len(t, ts.Server.raft.GetMemberlist(), 3)
   497  	assert.Len(t, r.Nodes, 3)
   498  
   499  	// Node 1 should be the leader
   500  	for i := 1; i <= 3; i++ {
   501  		if i == 1 {
   502  			assert.True(t, managers[nodes[uint64(i)].Config.ID].Leader)
   503  			continue
   504  		}
   505  		assert.False(t, managers[nodes[uint64(i)].Config.ID].Leader)
   506  	}
   507  
   508  	// All nodes should be reachable
   509  	for i := 1; i <= 3; i++ {
   510  		assert.Equal(t, api.RaftMemberStatus_REACHABLE, managers[nodes[uint64(i)].Config.ID].Reachability)
   511  	}
   512  
   513  	// Add two more nodes to the cluster
   514  	raftutils.AddRaftNode(t, clockSource, nodes, tc)
   515  	raftutils.AddRaftNode(t, clockSource, nodes, tc)
   516  	raftutils.WaitForCluster(t, clockSource, nodes)
   517  
   518  	// Add node entries for these
   519  	assert.NoError(t, nodes[1].MemoryStore().Update(func(tx store.Tx) error {
   520  		assert.NoError(t, store.CreateNode(tx, &api.Node{ID: nodes[4].SecurityConfig.ClientTLSCreds.NodeID()}))
   521  		assert.NoError(t, store.CreateNode(tx, &api.Node{ID: nodes[5].SecurityConfig.ClientTLSCreds.NodeID()}))
   522  		return nil
   523  	}))
   524  
   525  	// There should be 5 reachable managers listed
   526  	r, err = ts.Client.ListNodes(context.Background(), &api.ListNodesRequest{})
   527  	assert.NoError(t, err)
   528  	assert.NotNil(t, r)
   529  	managers = getMap(t, r.Nodes)
   530  	assert.Len(t, ts.Server.raft.GetMemberlist(), 5)
   531  	assert.Len(t, r.Nodes, 5)
   532  	for i := 1; i <= 5; i++ {
   533  		assert.Equal(t, api.RaftMemberStatus_REACHABLE, managers[nodes[uint64(i)].Config.ID].Reachability)
   534  	}
   535  
   536  	// Stops 2 nodes
   537  	nodes[4].Server.Stop()
   538  	nodes[4].ShutdownRaft()
   539  	nodes[5].Server.Stop()
   540  	nodes[5].ShutdownRaft()
   541  
   542  	// Node 4 and Node 5 should be listed as Unreachable
   543  	assert.NoError(t, testutils.PollFunc(clockSource, func() error {
   544  		r, err = ts.Client.ListNodes(context.Background(), &api.ListNodesRequest{})
   545  		if err != nil {
   546  			return err
   547  		}
   548  
   549  		managers = getMap(t, r.Nodes)
   550  
   551  		if len(r.Nodes) != 5 {
   552  			return fmt.Errorf("expected 5 nodes, got %d", len(r.Nodes))
   553  		}
   554  
   555  		if managers[nodes[4].Config.ID].Reachability == api.RaftMemberStatus_REACHABLE {
   556  			return fmt.Errorf("expected node 4 to be unreachable")
   557  		}
   558  
   559  		if managers[nodes[5].Config.ID].Reachability == api.RaftMemberStatus_REACHABLE {
   560  			return fmt.Errorf("expected node 5 to be unreachable")
   561  		}
   562  
   563  		return nil
   564  	}))
   565  
   566  	// Restart the 2 nodes
   567  	nodes[4] = raftutils.RestartNode(t, clockSource, nodes[4], false)
   568  	nodes[5] = raftutils.RestartNode(t, clockSource, nodes[5], false)
   569  	raftutils.WaitForCluster(t, clockSource, nodes)
   570  
   571  	assert.Len(t, ts.Server.raft.GetMemberlist(), 5)
   572  	// All the nodes should be reachable again
   573  	assert.NoError(t, testutils.PollFunc(clockSource, func() error {
   574  		r, err = ts.Client.ListNodes(context.Background(), &api.ListNodesRequest{})
   575  		if err != nil {
   576  			return err
   577  		}
   578  		managers = getMap(t, r.Nodes)
   579  		for i := 1; i <= 5; i++ {
   580  			if managers[nodes[uint64(i)].Config.ID].Reachability != api.RaftMemberStatus_REACHABLE {
   581  				return fmt.Errorf("node %x is unreachable", nodes[uint64(i)].Config.ID)
   582  			}
   583  		}
   584  		return nil
   585  	}))
   586  
   587  	// Stop node 1 (leader)
   588  	nodes[1].Server.Stop()
   589  	nodes[1].ShutdownRaft()
   590  
   591  	newCluster := map[uint64]*raftutils.TestNode{
   592  		2: nodes[2],
   593  		3: nodes[3],
   594  		4: nodes[4],
   595  		5: nodes[5],
   596  	}
   597  
   598  	// Wait for the re-election to occur
   599  	raftutils.WaitForCluster(t, clockSource, newCluster)
   600  
   601  	var leaderNode *raftutils.TestNode
   602  	for _, node := range newCluster {
   603  		if node.IsLeader() {
   604  			leaderNode = node
   605  		}
   606  	}
   607  
   608  	// Switch the raft node used by the server
   609  	ts.Server.raft = leaderNode.Node
   610  
   611  	// Node 1 should not be the leader anymore
   612  	assert.NoError(t, testutils.PollFunc(clockSource, func() error {
   613  		r, err = ts.Client.ListNodes(context.Background(), &api.ListNodesRequest{})
   614  		if err != nil {
   615  			return err
   616  		}
   617  
   618  		managers = getMap(t, r.Nodes)
   619  
   620  		if managers[nodes[1].Config.ID].Leader {
   621  			return fmt.Errorf("expected node 1 not to be the leader")
   622  		}
   623  
   624  		if managers[nodes[1].Config.ID].Reachability == api.RaftMemberStatus_REACHABLE {
   625  			return fmt.Errorf("expected node 1 to be unreachable")
   626  		}
   627  
   628  		return nil
   629  	}))
   630  
   631  	// Restart node 1
   632  	nodes[1].ShutdownRaft()
   633  	nodes[1] = raftutils.RestartNode(t, clockSource, nodes[1], false)
   634  	raftutils.WaitForCluster(t, clockSource, nodes)
   635  
   636  	// Ensure that node 1 is not the leader
   637  	assert.False(t, managers[nodes[uint64(1)].Config.ID].Leader)
   638  
   639  	// Check that another node got the leader status
   640  	var leader uint64
   641  	leaderCount := 0
   642  	for i := 1; i <= 5; i++ {
   643  		if managers[nodes[uint64(i)].Config.ID].Leader {
   644  			leader = nodes[uint64(i)].Config.ID
   645  			leaderCount++
   646  		}
   647  	}
   648  
   649  	// There should be only one leader after node 1 recovery and it
   650  	// should be different than node 1
   651  	assert.Equal(t, 1, leaderCount)
   652  	assert.NotEqual(t, leader, nodes[1].Config.ID)
   653  }
   654  
   655  func TestUpdateNode(t *testing.T) {
   656  	tc := cautils.NewTestCA(t)
   657  	defer tc.Stop()
   658  	ts := newTestServer(t)
   659  	defer ts.Stop()
   660  
   661  	nodes := make(map[uint64]*raftutils.TestNode)
   662  	nodes[1], _ = raftutils.NewInitNode(t, tc, nil)
   663  	defer raftutils.TeardownCluster(nodes)
   664  
   665  	nodeID := nodes[1].SecurityConfig.ClientTLSCreds.NodeID()
   666  
   667  	// Assign one of the raft node to the test server
   668  	ts.Server.raft = nodes[1].Node
   669  	ts.Server.store = nodes[1].MemoryStore()
   670  
   671  	_, err := ts.Client.UpdateNode(context.Background(), &api.UpdateNodeRequest{
   672  		NodeID: nodeID,
   673  		Spec: &api.NodeSpec{
   674  			Availability: api.NodeAvailabilityDrain,
   675  		},
   676  		NodeVersion: &api.Version{},
   677  	})
   678  	assert.Error(t, err)
   679  	assert.Equal(t, codes.NotFound, testutils.ErrorCode(err))
   680  
   681  	// Create a node object for the manager
   682  	assert.NoError(t, nodes[1].MemoryStore().Update(func(tx store.Tx) error {
   683  		assert.NoError(t, store.CreateNode(tx, &api.Node{
   684  			ID: nodes[1].SecurityConfig.ClientTLSCreds.NodeID(),
   685  			Spec: api.NodeSpec{
   686  				Membership: api.NodeMembershipAccepted,
   687  			},
   688  			Role: api.NodeRoleManager,
   689  		}))
   690  		return nil
   691  	}))
   692  
   693  	_, err = ts.Client.UpdateNode(context.Background(), &api.UpdateNodeRequest{})
   694  	assert.Error(t, err)
   695  	assert.Equal(t, codes.InvalidArgument, testutils.ErrorCode(err))
   696  
   697  	_, err = ts.Client.UpdateNode(context.Background(), &api.UpdateNodeRequest{NodeID: "invalid", Spec: &api.NodeSpec{}, NodeVersion: &api.Version{}})
   698  	assert.Error(t, err)
   699  	assert.Equal(t, codes.NotFound, testutils.ErrorCode(err))
   700  
   701  	r, err := ts.Client.GetNode(context.Background(), &api.GetNodeRequest{NodeID: nodeID})
   702  	assert.NoError(t, err)
   703  	if !assert.NotNil(t, r) {
   704  		assert.FailNow(t, "got unexpected nil response from GetNode")
   705  	}
   706  	assert.NotNil(t, r.Node)
   707  
   708  	_, err = ts.Client.UpdateNode(context.Background(), &api.UpdateNodeRequest{NodeID: nodeID})
   709  	assert.Error(t, err)
   710  	assert.Equal(t, codes.InvalidArgument, testutils.ErrorCode(err))
   711  
   712  	spec := r.Node.Spec.Copy()
   713  	spec.Availability = api.NodeAvailabilityDrain
   714  	_, err = ts.Client.UpdateNode(context.Background(), &api.UpdateNodeRequest{
   715  		NodeID: nodeID,
   716  		Spec:   spec,
   717  	})
   718  	assert.Error(t, err)
   719  	assert.Equal(t, codes.InvalidArgument, testutils.ErrorCode(err))
   720  
   721  	_, err = ts.Client.UpdateNode(context.Background(), &api.UpdateNodeRequest{
   722  		NodeID:      nodeID,
   723  		Spec:        spec,
   724  		NodeVersion: &r.Node.Meta.Version,
   725  	})
   726  	assert.NoError(t, err)
   727  
   728  	r, err = ts.Client.GetNode(context.Background(), &api.GetNodeRequest{NodeID: nodeID})
   729  	assert.NoError(t, err)
   730  	if !assert.NotNil(t, r) {
   731  		assert.FailNow(t, "got unexpected nil response from GetNode")
   732  	}
   733  	assert.NotNil(t, r.Node)
   734  	assert.NotNil(t, r.Node.Spec)
   735  	assert.Equal(t, api.NodeAvailabilityDrain, r.Node.Spec.Availability)
   736  
   737  	version := &r.Node.Meta.Version
   738  	_, err = ts.Client.UpdateNode(context.Background(), &api.UpdateNodeRequest{NodeID: nodeID, Spec: &r.Node.Spec, NodeVersion: version})
   739  	assert.NoError(t, err)
   740  
   741  	// Perform an update with the "old" version.
   742  	_, err = ts.Client.UpdateNode(context.Background(), &api.UpdateNodeRequest{NodeID: nodeID, Spec: &r.Node.Spec, NodeVersion: version})
   743  	assert.Error(t, err)
   744  }
   745  
   746  func testUpdateNodeDemote(t *testing.T) {
   747  	tc := cautils.NewTestCA(t)
   748  	defer tc.Stop()
   749  	ts := newTestServer(t)
   750  	defer ts.Stop()
   751  
   752  	nodes, clockSource := raftutils.NewRaftCluster(t, tc)
   753  	defer raftutils.TeardownCluster(nodes)
   754  
   755  	// Assign one of the raft node to the test server
   756  	ts.Server.raft = nodes[1].Node
   757  	ts.Server.store = nodes[1].MemoryStore()
   758  
   759  	// Create a node object for each of the managers
   760  	assert.NoError(t, nodes[1].MemoryStore().Update(func(tx store.Tx) error {
   761  		assert.NoError(t, store.CreateNode(tx, &api.Node{
   762  			ID: nodes[1].SecurityConfig.ClientTLSCreds.NodeID(),
   763  			Spec: api.NodeSpec{
   764  				DesiredRole: api.NodeRoleManager,
   765  				Membership:  api.NodeMembershipAccepted,
   766  			},
   767  			Role: api.NodeRoleManager,
   768  		}))
   769  		assert.NoError(t, store.CreateNode(tx, &api.Node{
   770  			ID: nodes[2].SecurityConfig.ClientTLSCreds.NodeID(),
   771  			Spec: api.NodeSpec{
   772  				DesiredRole: api.NodeRoleManager,
   773  				Membership:  api.NodeMembershipAccepted,
   774  			},
   775  			Role: api.NodeRoleManager,
   776  		}))
   777  		assert.NoError(t, store.CreateNode(tx, &api.Node{
   778  			ID: nodes[3].SecurityConfig.ClientTLSCreds.NodeID(),
   779  			Spec: api.NodeSpec{
   780  				DesiredRole: api.NodeRoleManager,
   781  				Membership:  api.NodeMembershipAccepted,
   782  			},
   783  			Role: api.NodeRoleManager,
   784  		}))
   785  		return nil
   786  	}))
   787  
   788  	// Stop Node 3 (1 node out of 3)
   789  	nodes[3].Server.Stop()
   790  	nodes[3].ShutdownRaft()
   791  
   792  	// Node 3 should be listed as Unreachable
   793  	assert.NoError(t, testutils.PollFunc(clockSource, func() error {
   794  		members := nodes[1].GetMemberlist()
   795  		if len(members) != 3 {
   796  			return fmt.Errorf("expected 3 nodes, got %d", len(members))
   797  		}
   798  		if members[nodes[3].Config.ID].Status.Reachability == api.RaftMemberStatus_REACHABLE {
   799  			return fmt.Errorf("expected node 3 to be unreachable")
   800  		}
   801  		return nil
   802  	}))
   803  
   804  	// Try to demote Node 2, this should fail because of the quorum safeguard
   805  	r, err := ts.Client.GetNode(context.Background(), &api.GetNodeRequest{NodeID: nodes[2].SecurityConfig.ClientTLSCreds.NodeID()})
   806  	assert.NoError(t, err)
   807  	spec := r.Node.Spec.Copy()
   808  	spec.DesiredRole = api.NodeRoleWorker
   809  	version := &r.Node.Meta.Version
   810  	_, err = ts.Client.UpdateNode(context.Background(), &api.UpdateNodeRequest{
   811  		NodeID:      nodes[2].SecurityConfig.ClientTLSCreds.NodeID(),
   812  		Spec:        spec,
   813  		NodeVersion: version,
   814  	})
   815  	assert.Error(t, err)
   816  	assert.Equal(t, codes.FailedPrecondition, testutils.ErrorCode(err))
   817  
   818  	// Restart Node 3
   819  	nodes[3] = raftutils.RestartNode(t, clockSource, nodes[3], false)
   820  	raftutils.WaitForCluster(t, clockSource, nodes)
   821  
   822  	// Node 3 should be listed as Reachable
   823  	assert.NoError(t, testutils.PollFunc(clockSource, func() error {
   824  		members := nodes[1].GetMemberlist()
   825  		if len(members) != 3 {
   826  			return fmt.Errorf("expected 3 nodes, got %d", len(members))
   827  		}
   828  		if members[nodes[3].Config.ID].Status.Reachability == api.RaftMemberStatus_UNREACHABLE {
   829  			return fmt.Errorf("expected node 3 to be reachable")
   830  		}
   831  		return nil
   832  	}))
   833  
   834  	raftMember := ts.Server.raft.GetMemberByNodeID(nodes[3].SecurityConfig.ClientTLSCreds.NodeID())
   835  	assert.NotNil(t, raftMember)
   836  
   837  	// Try to demote Node 3, this should succeed
   838  	r, err = ts.Client.GetNode(context.Background(), &api.GetNodeRequest{NodeID: nodes[3].SecurityConfig.ClientTLSCreds.NodeID()})
   839  	assert.NoError(t, err)
   840  	spec = r.Node.Spec.Copy()
   841  	spec.DesiredRole = api.NodeRoleWorker
   842  	version = &r.Node.Meta.Version
   843  	_, err = ts.Client.UpdateNode(context.Background(), &api.UpdateNodeRequest{
   844  		NodeID:      nodes[3].SecurityConfig.ClientTLSCreds.NodeID(),
   845  		Spec:        spec,
   846  		NodeVersion: version,
   847  	})
   848  	assert.NoError(t, err)
   849  
   850  	newCluster := map[uint64]*raftutils.TestNode{
   851  		1: nodes[1],
   852  		2: nodes[2],
   853  	}
   854  
   855  	ts.Server.raft.RemoveMember(context.Background(), raftMember.RaftID)
   856  
   857  	raftutils.WaitForCluster(t, clockSource, newCluster)
   858  
   859  	// Server should list 2 members
   860  	assert.NoError(t, testutils.PollFunc(clockSource, func() error {
   861  		members := nodes[1].GetMemberlist()
   862  		if len(members) != 2 {
   863  			return fmt.Errorf("expected 2 nodes, got %d", len(members))
   864  		}
   865  		return nil
   866  	}))
   867  
   868  	demoteNode := nodes[2]
   869  	lastNode := nodes[1]
   870  
   871  	raftMember = ts.Server.raft.GetMemberByNodeID(demoteNode.SecurityConfig.ClientTLSCreds.NodeID())
   872  	assert.NotNil(t, raftMember)
   873  
   874  	// Try to demote a Node and scale down to 1
   875  	r, err = ts.Client.GetNode(context.Background(), &api.GetNodeRequest{NodeID: demoteNode.SecurityConfig.ClientTLSCreds.NodeID()})
   876  	assert.NoError(t, err)
   877  	spec = r.Node.Spec.Copy()
   878  	spec.DesiredRole = api.NodeRoleWorker
   879  	version = &r.Node.Meta.Version
   880  	_, err = ts.Client.UpdateNode(context.Background(), &api.UpdateNodeRequest{
   881  		NodeID:      demoteNode.SecurityConfig.ClientTLSCreds.NodeID(),
   882  		Spec:        spec,
   883  		NodeVersion: version,
   884  	})
   885  	assert.NoError(t, err)
   886  
   887  	ts.Server.raft.RemoveMember(context.Background(), raftMember.RaftID)
   888  
   889  	// Update the server
   890  	ts.Server.raft = lastNode.Node
   891  	ts.Server.store = lastNode.MemoryStore()
   892  
   893  	newCluster = map[uint64]*raftutils.TestNode{
   894  		1: lastNode,
   895  	}
   896  
   897  	raftutils.WaitForCluster(t, clockSource, newCluster)
   898  
   899  	assert.NoError(t, testutils.PollFunc(clockSource, func() error {
   900  		members := lastNode.GetMemberlist()
   901  		if len(members) != 1 {
   902  			return fmt.Errorf("expected 1 node, got %d", len(members))
   903  		}
   904  		return nil
   905  	}))
   906  
   907  	// Make sure we can't demote the last manager.
   908  	r, err = ts.Client.GetNode(context.Background(), &api.GetNodeRequest{NodeID: lastNode.SecurityConfig.ClientTLSCreds.NodeID()})
   909  	assert.NoError(t, err)
   910  	spec = r.Node.Spec.Copy()
   911  	spec.DesiredRole = api.NodeRoleWorker
   912  	version = &r.Node.Meta.Version
   913  	_, err = ts.Client.UpdateNode(context.Background(), &api.UpdateNodeRequest{
   914  		NodeID:      lastNode.SecurityConfig.ClientTLSCreds.NodeID(),
   915  		Spec:        spec,
   916  		NodeVersion: version,
   917  	})
   918  	assert.Error(t, err)
   919  	assert.Equal(t, codes.FailedPrecondition, testutils.ErrorCode(err))
   920  
   921  	// Propose a change in the spec and check if the remaining node can still process updates
   922  	r, err = ts.Client.GetNode(context.Background(), &api.GetNodeRequest{NodeID: lastNode.SecurityConfig.ClientTLSCreds.NodeID()})
   923  	assert.NoError(t, err)
   924  	spec = r.Node.Spec.Copy()
   925  	spec.Availability = api.NodeAvailabilityDrain
   926  	version = &r.Node.Meta.Version
   927  	_, err = ts.Client.UpdateNode(context.Background(), &api.UpdateNodeRequest{
   928  		NodeID:      lastNode.SecurityConfig.ClientTLSCreds.NodeID(),
   929  		Spec:        spec,
   930  		NodeVersion: version,
   931  	})
   932  	assert.NoError(t, err)
   933  
   934  	// Get node information and check that the availability is set to drain
   935  	r, err = ts.Client.GetNode(context.Background(), &api.GetNodeRequest{NodeID: lastNode.SecurityConfig.ClientTLSCreds.NodeID()})
   936  	assert.NoError(t, err)
   937  	assert.Equal(t, r.Node.Spec.Availability, api.NodeAvailabilityDrain)
   938  }
   939  
   940  func TestUpdateNodeDemote(t *testing.T) {
   941  	t.Parallel()
   942  	testUpdateNodeDemote(t)
   943  }
   944  
   945  // TestRemoveNodeAttachments tests the unexported orphanNodeTasks
   946  func TestOrphanNodeTasks(t *testing.T) {
   947  	// first, set up a store and all that
   948  	ts := newTestServer(t)
   949  	defer ts.Stop()
   950  
   951  	ts.Store.Update(func(tx store.Tx) error {
   952  		store.CreateCluster(tx, &api.Cluster{
   953  			ID: identity.NewID(),
   954  			Spec: api.ClusterSpec{
   955  				Annotations: api.Annotations{
   956  					Name: store.DefaultClusterName,
   957  				},
   958  			},
   959  		})
   960  		return nil
   961  	})
   962  
   963  	// make sure before we start that our server is in a good (empty) state
   964  	r, err := ts.Client.ListNodes(context.Background(), &api.ListNodesRequest{})
   965  	assert.NoError(t, err)
   966  	assert.Empty(t, r.Nodes)
   967  
   968  	// create a manager
   969  	createNode(t, ts, "id1", api.NodeRoleManager, api.NodeMembershipAccepted, api.NodeStatus_READY)
   970  	r, err = ts.Client.ListNodes(context.Background(), &api.ListNodesRequest{})
   971  	assert.NoError(t, err)
   972  	assert.Len(t, r.Nodes, 1)
   973  
   974  	// create a worker. put it in the DOWN state, which is the state it will be
   975  	// in to remove it anyway
   976  	createNode(t, ts, "id2", api.NodeRoleWorker, api.NodeMembershipAccepted, api.NodeStatus_DOWN)
   977  	r, err = ts.Client.ListNodes(context.Background(), &api.ListNodesRequest{})
   978  	assert.NoError(t, err)
   979  	assert.Len(t, r.Nodes, 2)
   980  
   981  	// create a network we can "attach" to
   982  	err = ts.Store.Update(func(tx store.Tx) error {
   983  		n := &api.Network{
   984  			ID: "net1id",
   985  			Spec: api.NetworkSpec{
   986  				Annotations: api.Annotations{
   987  					Name: "net1name",
   988  				},
   989  				Attachable: true,
   990  			},
   991  		}
   992  		return store.CreateNetwork(tx, n)
   993  	})
   994  	require.NoError(t, err)
   995  
   996  	// create some tasks:
   997  	err = ts.Store.Update(func(tx store.Tx) error {
   998  		// 1.) A network attachment on the node we're gonna remove
   999  		task1 := &api.Task{
  1000  			ID:           "task1",
  1001  			NodeID:       "id2",
  1002  			DesiredState: api.TaskStateRunning,
  1003  			Status: api.TaskStatus{
  1004  				State: api.TaskStateRunning,
  1005  			},
  1006  			Spec: api.TaskSpec{
  1007  				Runtime: &api.TaskSpec_Attachment{
  1008  					Attachment: &api.NetworkAttachmentSpec{
  1009  						ContainerID: "container1",
  1010  					},
  1011  				},
  1012  				Networks: []*api.NetworkAttachmentConfig{
  1013  					{
  1014  						Target:    "net1id",
  1015  						Addresses: []string{}, // just leave this empty, we don't need it
  1016  					},
  1017  				},
  1018  			},
  1019  			// we probably don't care about the rest of the fields.
  1020  		}
  1021  		if err := store.CreateTask(tx, task1); err != nil {
  1022  			return err
  1023  		}
  1024  
  1025  		// 2.) A network attachment on the node we're not going to remove
  1026  		task2 := &api.Task{
  1027  			ID:           "task2",
  1028  			NodeID:       "id1",
  1029  			DesiredState: api.TaskStateRunning,
  1030  			Status: api.TaskStatus{
  1031  				State: api.TaskStateRunning,
  1032  			},
  1033  			Spec: api.TaskSpec{
  1034  				Runtime: &api.TaskSpec_Attachment{
  1035  					Attachment: &api.NetworkAttachmentSpec{
  1036  						ContainerID: "container2",
  1037  					},
  1038  				},
  1039  				Networks: []*api.NetworkAttachmentConfig{
  1040  					{
  1041  						Target:    "net1id",
  1042  						Addresses: []string{}, // just leave this empty, we don't need it
  1043  					},
  1044  				},
  1045  			},
  1046  			// we probably don't care about the rest of the fields.
  1047  		}
  1048  		if err := store.CreateTask(tx, task2); err != nil {
  1049  			return err
  1050  		}
  1051  
  1052  		// 3.) A regular task on the node we're going to remove
  1053  		task3 := &api.Task{
  1054  			ID:           "task3",
  1055  			NodeID:       "id2",
  1056  			DesiredState: api.TaskStateRunning,
  1057  			Status: api.TaskStatus{
  1058  				State: api.TaskStateRunning,
  1059  			},
  1060  			Spec: api.TaskSpec{
  1061  				Runtime: &api.TaskSpec_Container{
  1062  					Container: &api.ContainerSpec{},
  1063  				},
  1064  			},
  1065  		}
  1066  		if err := store.CreateTask(tx, task3); err != nil {
  1067  			return err
  1068  		}
  1069  
  1070  		// 4.) A regular task on the node we're not going to remove
  1071  		task4 := &api.Task{
  1072  			ID:           "task4",
  1073  			NodeID:       "id1",
  1074  			DesiredState: api.TaskStateRunning,
  1075  			Status: api.TaskStatus{
  1076  				State: api.TaskStateRunning,
  1077  			},
  1078  			Spec: api.TaskSpec{
  1079  				Runtime: &api.TaskSpec_Container{
  1080  					Container: &api.ContainerSpec{},
  1081  				},
  1082  			},
  1083  		}
  1084  		if err := store.CreateTask(tx, task4); err != nil {
  1085  			return err
  1086  		}
  1087  
  1088  		// 5.) A regular task that's already in a terminal state on the node,
  1089  		//	   which does not need to be updated.
  1090  		task5 := &api.Task{
  1091  			ID:           "task5",
  1092  			NodeID:       "id2",
  1093  			DesiredState: api.TaskStateRunning,
  1094  			Status: api.TaskStatus{
  1095  				// use TaskStateCompleted, as this is the earliest terminal
  1096  				// state (this ensures we don't actually use <= instead of <)
  1097  				State: api.TaskStateCompleted,
  1098  			},
  1099  			Spec: api.TaskSpec{
  1100  				Runtime: &api.TaskSpec_Container{
  1101  					Container: &api.ContainerSpec{},
  1102  				},
  1103  			},
  1104  		}
  1105  		return store.CreateTask(tx, task5)
  1106  	})
  1107  	require.NoError(t, err)
  1108  
  1109  	// Now, call the function with our nodeID. make sure it returns no error
  1110  	err = ts.Store.Update(func(tx store.Tx) error {
  1111  		return orphanNodeTasks(tx, "id2")
  1112  	})
  1113  	require.NoError(t, err)
  1114  
  1115  	// Now, make sure only tasks 1 and 3, the tasks on the node we're deleting
  1116  	// removed, are removed
  1117  	ts.Store.View(func(tx store.ReadTx) {
  1118  		tasks, err := store.FindTasks(tx, store.All)
  1119  		require.NoError(t, err)
  1120  		require.Len(t, tasks, 5)
  1121  		// and the list should not contain task1 or task2
  1122  		for _, task := range tasks {
  1123  			require.NotNil(t, task)
  1124  			if task.ID == "task1" || task.ID == "task3" {
  1125  				require.Equal(t, task.Status.State, api.TaskStateOrphaned)
  1126  			} else {
  1127  				require.NotEqual(t, task.Status.State, api.TaskStateOrphaned)
  1128  			}
  1129  		}
  1130  	})
  1131  }