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

     1  package manager
     2  
     3  import (
     4  	"errors"
     5  	"testing"
     6  
     7  	"github.com/docker/swarmkit/api"
     8  	cautils "github.com/docker/swarmkit/ca/testutils"
     9  	raftutils "github.com/docker/swarmkit/manager/state/raft/testutils"
    10  	"github.com/docker/swarmkit/manager/state/store"
    11  	"github.com/docker/swarmkit/testutils"
    12  	"github.com/stretchr/testify/require"
    13  )
    14  
    15  // While roleManager is running, if a node is demoted, it is removed from the raft cluster.  If a node is
    16  // promoted, it is not added to the cluster but its observed role will change to manager.
    17  func TestRoleManagerRemovesDemotedNodesAndAddsPromotedNodes(t *testing.T) {
    18  	t.Parallel()
    19  
    20  	tc := cautils.NewTestCA(t)
    21  	defer tc.Stop()
    22  
    23  	nodes, fc := raftutils.NewRaftCluster(t, tc)
    24  	defer raftutils.TeardownCluster(nodes)
    25  
    26  	// nodes is not a list, but a map.  The IDs are 1, 2, 3
    27  	require.Len(t, nodes[1].GetMemberlist(), 3)
    28  
    29  	// create node objects in the memory store
    30  	for _, node := range nodes {
    31  		s := raftutils.Leader(nodes).MemoryStore()
    32  		// Create a new node object
    33  		require.NoError(t, s.Update(func(tx store.Tx) error {
    34  			return store.CreateNode(tx, &api.Node{
    35  				Role: api.NodeRoleManager,
    36  				ID:   node.SecurityConfig.ClientTLSCreds.NodeID(),
    37  				Spec: api.NodeSpec{
    38  					DesiredRole:  api.NodeRoleManager,
    39  					Membership:   api.NodeMembershipAccepted,
    40  					Availability: api.NodeAvailabilityActive,
    41  				},
    42  			})
    43  		}))
    44  	}
    45  
    46  	lead := raftutils.Leader(nodes)
    47  	var nonLead *raftutils.TestNode
    48  	for _, n := range nodes {
    49  		if n != lead {
    50  			nonLead = n
    51  			break
    52  		}
    53  	}
    54  	rm := newRoleManager(lead.MemoryStore(), lead.Node)
    55  	rm.clocksource = fc
    56  	go rm.Run(tc.Context)
    57  	defer rm.Stop()
    58  
    59  	// demote the node
    60  	require.NoError(t, lead.MemoryStore().Update(func(tx store.Tx) error {
    61  		n := store.GetNode(tx, nonLead.SecurityConfig.ClientTLSCreds.NodeID())
    62  		n.Spec.DesiredRole = api.NodeRoleWorker
    63  		return store.UpdateNode(tx, n)
    64  	}))
    65  	require.NoError(t, testutils.PollFuncWithTimeout(fc, func() error {
    66  		memberlist := lead.GetMemberlist()
    67  		if len(memberlist) != 2 {
    68  			return errors.New("raft node hasn't been removed yet")
    69  		}
    70  		for _, m := range memberlist {
    71  			if m.NodeID == nonLead.SecurityConfig.ClientTLSCreds.NodeID() {
    72  				return errors.New("wrong member was removed")
    73  			}
    74  		}
    75  		// use Update just because it returns an error
    76  		return lead.MemoryStore().Update(func(tx store.Tx) error {
    77  			if n := store.GetNode(tx, nonLead.SecurityConfig.ClientTLSCreds.NodeID()); n.Role != api.NodeRoleWorker {
    78  				return errors.New("raft node hasn't been marked as a worker yet")
    79  			}
    80  			return nil
    81  		})
    82  	}, roleReconcileInterval/2))
    83  
    84  	// now promote the node
    85  	require.NoError(t, lead.MemoryStore().Update(func(tx store.Tx) error {
    86  		n := store.GetNode(tx, nonLead.SecurityConfig.ClientTLSCreds.NodeID())
    87  		n.Spec.DesiredRole = api.NodeRoleManager
    88  		return store.UpdateNode(tx, n)
    89  	}))
    90  	require.NoError(t, testutils.PollFuncWithTimeout(fc, func() error {
    91  		if len(lead.GetMemberlist()) != 2 {
    92  			return errors.New("raft nodes in membership should not have changed")
    93  		}
    94  		// use Update just because it returns an error
    95  		return lead.MemoryStore().Update(func(tx store.Tx) error {
    96  			if n := store.GetNode(tx, nonLead.SecurityConfig.ClientTLSCreds.NodeID()); n.Role != api.NodeRoleManager {
    97  				return errors.New("raft node hasn't been marked as a manager yet")
    98  			}
    99  			return nil
   100  		})
   101  	}, roleReconcileInterval/2))
   102  }
   103  
   104  // If a node was demoted before the roleManager starts up, roleManger will remove
   105  // the node from the cluster membership.
   106  func TestRoleManagerRemovesDemotedNodesOnStartup(t *testing.T) {
   107  	t.Parallel()
   108  
   109  	tc := cautils.NewTestCA(t)
   110  	defer tc.Stop()
   111  
   112  	nodes, fc := raftutils.NewRaftCluster(t, tc)
   113  	defer raftutils.TeardownCluster(nodes)
   114  
   115  	// nodes is not a list, but a map.  The IDs are 1, 2, 3
   116  	require.Len(t, nodes[1].GetMemberlist(), 3)
   117  
   118  	// create node objects in the memory store
   119  	for i, node := range nodes {
   120  		s := raftutils.Leader(nodes).MemoryStore()
   121  		desired := api.NodeRoleManager
   122  		if i == 3 {
   123  			desired = api.NodeRoleWorker
   124  		}
   125  		// Create a new node object
   126  		require.NoError(t, s.Update(func(tx store.Tx) error {
   127  			return store.CreateNode(tx, &api.Node{
   128  				Role: api.NodeRoleManager,
   129  				ID:   node.SecurityConfig.ClientTLSCreds.NodeID(),
   130  				Spec: api.NodeSpec{
   131  					DesiredRole:  desired,
   132  					Membership:   api.NodeMembershipAccepted,
   133  					Availability: api.NodeAvailabilityActive,
   134  				},
   135  			})
   136  		}))
   137  	}
   138  	demoted := nodes[3]
   139  
   140  	lead := raftutils.Leader(nodes)
   141  	rm := newRoleManager(lead.MemoryStore(), lead.Node)
   142  	rm.clocksource = fc
   143  	go rm.Run(tc.Context)
   144  	defer rm.Stop()
   145  
   146  	require.NoError(t, testutils.PollFuncWithTimeout(fc, func() error {
   147  		memberlist := lead.GetMemberlist()
   148  		if len(memberlist) != 2 {
   149  			return errors.New("raft node hasn't been removed yet")
   150  		}
   151  		for _, m := range memberlist {
   152  			if m.NodeID == demoted.SecurityConfig.ClientTLSCreds.NodeID() {
   153  				return errors.New("wrong member was removed")
   154  			}
   155  		}
   156  		// use Update just because it returns an error
   157  		return lead.MemoryStore().Update(func(tx store.Tx) error {
   158  			if n := store.GetNode(tx, demoted.SecurityConfig.ClientTLSCreds.NodeID()); n.Role != api.NodeRoleWorker {
   159  				return errors.New("raft node hasn't been marked as a worker yet")
   160  			}
   161  			return nil
   162  		})
   163  	}, roleReconcileInterval/2))
   164  }
   165  
   166  // While roleManager is running, if a node is deleted, it is removed from the raft cluster.
   167  func TestRoleManagerRemovesDeletedNodes(t *testing.T) {
   168  	t.Parallel()
   169  
   170  	tc := cautils.NewTestCA(t)
   171  	defer tc.Stop()
   172  
   173  	nodes, fc := raftutils.NewRaftCluster(t, tc)
   174  	defer raftutils.TeardownCluster(nodes)
   175  
   176  	// nodes is not a list, but a map.  The IDs are 1, 2, 3
   177  	require.Len(t, nodes[1].GetMemberlist(), 3)
   178  
   179  	// create node objects in the memory store
   180  	for _, node := range nodes {
   181  		s := raftutils.Leader(nodes).MemoryStore()
   182  		// Create a new node object
   183  		require.NoError(t, s.Update(func(tx store.Tx) error {
   184  			return store.CreateNode(tx, &api.Node{
   185  				Role: api.NodeRoleManager,
   186  				ID:   node.SecurityConfig.ClientTLSCreds.NodeID(),
   187  				Spec: api.NodeSpec{
   188  					DesiredRole:  api.NodeRoleManager,
   189  					Membership:   api.NodeMembershipAccepted,
   190  					Availability: api.NodeAvailabilityActive,
   191  				},
   192  			})
   193  		}))
   194  	}
   195  
   196  	lead := raftutils.Leader(nodes)
   197  	var nonLead *raftutils.TestNode
   198  	for _, n := range nodes {
   199  		if n != lead {
   200  			nonLead = n
   201  			break
   202  		}
   203  	}
   204  	rm := newRoleManager(lead.MemoryStore(), lead.Node)
   205  	rm.clocksource = fc
   206  	go rm.Run(tc.Context)
   207  	defer rm.Stop()
   208  
   209  	// delete the node
   210  	require.NoError(t, lead.MemoryStore().Update(func(tx store.Tx) error {
   211  		return store.DeleteNode(tx, nonLead.SecurityConfig.ClientTLSCreds.NodeID())
   212  	}))
   213  	require.NoError(t, testutils.PollFuncWithTimeout(fc, func() error {
   214  		memberlist := lead.GetMemberlist()
   215  		if len(memberlist) != 2 {
   216  			return errors.New("raft node hasn't been removed yet")
   217  		}
   218  		for _, m := range memberlist {
   219  			if m.NodeID == nonLead.SecurityConfig.ClientTLSCreds.NodeID() {
   220  				return errors.New("wrong member was removed")
   221  			}
   222  		}
   223  		return nil
   224  	}, roleReconcileInterval/2))
   225  
   226  }
   227  
   228  // If a node was removed before the roleManager starts up, roleManger will remove
   229  // the node from the cluster membership.
   230  func TestRoleManagerRemovesDeletedNodesOnStartup(t *testing.T) {
   231  	t.Parallel()
   232  
   233  	tc := cautils.NewTestCA(t)
   234  	defer tc.Stop()
   235  
   236  	nodes, fc := raftutils.NewRaftCluster(t, tc)
   237  	defer raftutils.TeardownCluster(nodes)
   238  
   239  	// nodes is not a list, but a map.  The IDs are 1, 2, 3
   240  	require.Len(t, nodes[1].GetMemberlist(), 3)
   241  
   242  	// create node objects in the memory store
   243  	for i, node := range nodes {
   244  		s := raftutils.Leader(nodes).MemoryStore()
   245  		if i == 3 {
   246  			continue
   247  		}
   248  		// Create a new node object
   249  		require.NoError(t, s.Update(func(tx store.Tx) error {
   250  			return store.CreateNode(tx, &api.Node{
   251  				Role: api.NodeRoleManager,
   252  				ID:   node.SecurityConfig.ClientTLSCreds.NodeID(),
   253  				Spec: api.NodeSpec{
   254  					DesiredRole:  api.NodeRoleManager,
   255  					Membership:   api.NodeMembershipAccepted,
   256  					Availability: api.NodeAvailabilityActive,
   257  				},
   258  			})
   259  		}))
   260  	}
   261  
   262  	lead := raftutils.Leader(nodes)
   263  	rm := newRoleManager(lead.MemoryStore(), lead.Node)
   264  	rm.clocksource = fc
   265  	go rm.Run(tc.Context)
   266  	defer rm.Stop()
   267  
   268  	require.NoError(t, testutils.PollFuncWithTimeout(fc, func() error {
   269  		memberlist := lead.GetMemberlist()
   270  		if len(memberlist) != 2 {
   271  			return errors.New("raft node hasn't been removed yet")
   272  		}
   273  		for _, m := range memberlist {
   274  			if m.NodeID == nodes[3].SecurityConfig.ClientTLSCreds.NodeID() {
   275  				return errors.New("wrong member was removed")
   276  			}
   277  		}
   278  		return nil
   279  	}, roleReconcileInterval/2))
   280  }