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

     1  package dispatcher
     2  
     3  import (
     4  	"context"
     5  	"crypto/tls"
     6  	"encoding/json"
     7  	"errors"
     8  	"fmt"
     9  	"io/ioutil"
    10  	"net"
    11  	"net/http"
    12  	"net/http/httptest"
    13  	"sync"
    14  	"testing"
    15  	"time"
    16  
    17  	"google.golang.org/grpc"
    18  	"google.golang.org/grpc/codes"
    19  	"google.golang.org/grpc/credentials"
    20  
    21  	"github.com/docker/docker/pkg/plugingetter"
    22  	"github.com/docker/docker/pkg/plugins"
    23  	"github.com/docker/go-events"
    24  	"github.com/docker/swarmkit/api"
    25  	"github.com/docker/swarmkit/ca"
    26  	cautils "github.com/docker/swarmkit/ca/testutils"
    27  	"github.com/docker/swarmkit/identity"
    28  	"github.com/docker/swarmkit/manager/drivers"
    29  	"github.com/docker/swarmkit/manager/state/store"
    30  	"github.com/docker/swarmkit/testutils"
    31  	digest "github.com/opencontainers/go-digest"
    32  	"github.com/stretchr/testify/assert"
    33  	"github.com/stretchr/testify/require"
    34  )
    35  
    36  type grpcDispatcher struct {
    37  	Clients          []api.DispatcherClient
    38  	SecurityConfigs  []*ca.SecurityConfig
    39  	Store            *store.MemoryStore
    40  	grpcServer       *grpc.Server
    41  	dispatcherServer *Dispatcher
    42  	conns            []*grpc.ClientConn
    43  	testCA           *cautils.TestCA
    44  	testCluster      *testCluster
    45  	PluginGetter     *mockPluginGetter
    46  }
    47  
    48  func (gd *grpcDispatcher) Close() {
    49  	// Close the client connection.
    50  	for _, conn := range gd.conns {
    51  		conn.Close()
    52  	}
    53  	gd.dispatcherServer.Stop()
    54  	gd.grpcServer.Stop()
    55  	gd.PluginGetter.Close()
    56  	gd.testCA.Stop()
    57  }
    58  
    59  type testCluster struct {
    60  	mu            sync.Mutex
    61  	addr          string
    62  	store         *store.MemoryStore
    63  	subscriptions map[string]chan events.Event
    64  	peers         []*api.Peer
    65  	members       map[uint64]*api.RaftMember
    66  }
    67  
    68  func newTestCluster(addr string, s *store.MemoryStore) *testCluster {
    69  	return &testCluster{
    70  		addr:          addr,
    71  		store:         s,
    72  		subscriptions: make(map[string]chan events.Event),
    73  		peers: []*api.Peer{
    74  			{
    75  				Addr:   addr,
    76  				NodeID: "1",
    77  			},
    78  		},
    79  		members: map[uint64]*api.RaftMember{
    80  			1: {
    81  				NodeID: "1",
    82  				Addr:   addr,
    83  			},
    84  		},
    85  	}
    86  }
    87  
    88  func (t *testCluster) GetMemberlist() map[uint64]*api.RaftMember {
    89  	t.mu.Lock()
    90  	defer t.mu.Unlock()
    91  	return t.members
    92  }
    93  
    94  func (t *testCluster) SubscribePeers() (chan events.Event, func()) {
    95  	t.mu.Lock()
    96  	defer t.mu.Unlock()
    97  	ch := make(chan events.Event, 1)
    98  	id := identity.NewID()
    99  	t.subscriptions[id] = ch
   100  	ch <- t.peers
   101  	return ch, func() {
   102  		t.mu.Lock()
   103  		defer t.mu.Unlock()
   104  		delete(t.subscriptions, id)
   105  		close(ch)
   106  	}
   107  }
   108  
   109  func (t *testCluster) addMember(addr string) {
   110  	t.mu.Lock()
   111  	defer t.mu.Unlock()
   112  	id := uint64(len(t.members) + 1)
   113  	strID := fmt.Sprintf("%d", id)
   114  	t.members[id] = &api.RaftMember{
   115  		NodeID: strID,
   116  		Addr:   addr,
   117  	}
   118  	t.peers = append(t.peers, &api.Peer{
   119  		Addr:   addr,
   120  		NodeID: strID,
   121  	})
   122  	for _, ch := range t.subscriptions {
   123  		ch <- t.peers
   124  	}
   125  }
   126  
   127  func (t *testCluster) MemoryStore() *store.MemoryStore {
   128  	return t.store
   129  }
   130  
   131  func startDispatcher(t *testing.T, c *Config) *grpcDispatcher {
   132  	t.Helper()
   133  
   134  	l, err := net.Listen("tcp", "127.0.0.1:0")
   135  	assert.NoError(t, err)
   136  
   137  	tca := cautils.NewTestCA(t)
   138  	tca.CAServer.Stop() // there is no need for the CA server to be running
   139  	agentSecurityConfig1, err := tca.NewNodeConfig(ca.WorkerRole)
   140  	assert.NoError(t, err)
   141  
   142  	agentSecurityConfig2, err := tca.NewNodeConfig(ca.WorkerRole)
   143  	assert.NoError(t, err)
   144  
   145  	managerSecurityConfig, err := tca.NewNodeConfig(ca.ManagerRole)
   146  	assert.NoError(t, err)
   147  
   148  	serverOpts := []grpc.ServerOption{grpc.Creds(managerSecurityConfig.ServerTLSCreds)}
   149  
   150  	s := grpc.NewServer(serverOpts...)
   151  	tc := newTestCluster(l.Addr().String(), tca.MemoryStore)
   152  	driverGetter := &mockPluginGetter{}
   153  	d := New()
   154  	d.Init(tc, c, drivers.New(driverGetter), managerSecurityConfig)
   155  	authorize := func(ctx context.Context, roles []string) error {
   156  		_, err := ca.AuthorizeForwardedRoleAndOrg(ctx, roles, []string{ca.ManagerRole}, tca.Organization, nil)
   157  		return err
   158  	}
   159  	authenticatedDispatcherAPI := api.NewAuthenticatedWrapperDispatcherServer(d, authorize)
   160  
   161  	api.RegisterDispatcherServer(s, authenticatedDispatcherAPI)
   162  	go func() {
   163  		// Serve will always return an error (even when properly stopped).
   164  		// Explicitly ignore it.
   165  		_ = s.Serve(l)
   166  	}()
   167  	go d.Run(context.Background())
   168  	err = testutils.PollFuncWithTimeout(nil, func() error {
   169  		d.mu.Lock()
   170  		defer d.mu.Unlock()
   171  		if !d.isRunning() {
   172  			return fmt.Errorf("dispatcher is not running")
   173  		}
   174  		return nil
   175  	}, 5*time.Second)
   176  	assert.NoError(t, err)
   177  
   178  	clientOpts := []grpc.DialOption{grpc.WithTimeout(10 * time.Second)}
   179  	clientOpts1 := append(clientOpts, grpc.WithTransportCredentials(agentSecurityConfig1.ClientTLSCreds))
   180  	clientOpts2 := append(clientOpts, grpc.WithTransportCredentials(agentSecurityConfig2.ClientTLSCreds))
   181  	clientOpts3 := append(clientOpts, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{InsecureSkipVerify: true})))
   182  
   183  	conn1, err := grpc.Dial(l.Addr().String(), clientOpts1...)
   184  	assert.NoError(t, err)
   185  
   186  	conn2, err := grpc.Dial(l.Addr().String(), clientOpts2...)
   187  	assert.NoError(t, err)
   188  
   189  	conn3, err := grpc.Dial(l.Addr().String(), clientOpts3...)
   190  	assert.NoError(t, err)
   191  
   192  	clients := []api.DispatcherClient{api.NewDispatcherClient(conn1), api.NewDispatcherClient(conn2), api.NewDispatcherClient(conn3)}
   193  	securityConfigs := []*ca.SecurityConfig{agentSecurityConfig1, agentSecurityConfig2, managerSecurityConfig}
   194  	conns := []*grpc.ClientConn{conn1, conn2, conn3}
   195  	return &grpcDispatcher{
   196  		Clients:          clients,
   197  		SecurityConfigs:  securityConfigs,
   198  		Store:            tc.MemoryStore(),
   199  		dispatcherServer: d,
   200  		conns:            conns,
   201  		grpcServer:       s,
   202  		testCA:           tca,
   203  		testCluster:      tc,
   204  		PluginGetter:     driverGetter,
   205  	}
   206  }
   207  
   208  func TestRegisterTwice(t *testing.T) {
   209  	cfg := DefaultConfig()
   210  	cfg.RateLimitPeriod = 0
   211  	gd := startDispatcher(t, cfg)
   212  	defer gd.Close()
   213  
   214  	var expectedSessionID string
   215  	{
   216  		stream, err := gd.Clients[0].Session(context.Background(), &api.SessionRequest{})
   217  		assert.NoError(t, err)
   218  		msg, err := stream.Recv()
   219  		assert.NoError(t, err)
   220  		assert.NotEmpty(t, msg.SessionID)
   221  		expectedSessionID = msg.SessionID
   222  		stream.CloseSend()
   223  	}
   224  	{
   225  		stream, err := gd.Clients[0].Session(context.Background(), &api.SessionRequest{})
   226  		assert.NoError(t, err)
   227  		msg, err := stream.Recv()
   228  
   229  		assert.NoError(t, err)
   230  		// session should be different!
   231  		assert.NotEqual(t, msg.SessionID, expectedSessionID)
   232  		stream.CloseSend()
   233  	}
   234  }
   235  
   236  func TestRegisterExceedRateLimit(t *testing.T) {
   237  	t.Parallel()
   238  
   239  	gd := startDispatcher(t, DefaultConfig())
   240  	defer gd.Close()
   241  
   242  	for i := 0; i < 3; i++ {
   243  		stream, err := gd.Clients[0].Session(context.Background(), &api.SessionRequest{})
   244  		assert.NoError(t, err)
   245  		msg, err := stream.Recv()
   246  		assert.NoError(t, err)
   247  		assert.NotEmpty(t, msg.SessionID)
   248  		stream.CloseSend()
   249  	}
   250  	{
   251  		stream, err := gd.Clients[0].Session(context.Background(), &api.SessionRequest{})
   252  		defer stream.CloseSend()
   253  		assert.NoError(t, err)
   254  		_, err = stream.Recv()
   255  		assert.Error(t, err)
   256  		assert.Equal(t, codes.Unavailable, testutils.ErrorCode(err), err.Error())
   257  	}
   258  }
   259  
   260  func TestRegisterNoCert(t *testing.T) {
   261  	gd := startDispatcher(t, DefaultConfig())
   262  	defer gd.Close()
   263  
   264  	// This client has no certificates, this should fail
   265  	stream, err := gd.Clients[2].Session(context.Background(), &api.SessionRequest{})
   266  	assert.NoError(t, err)
   267  	defer stream.CloseSend()
   268  	resp, err := stream.Recv()
   269  	assert.Nil(t, resp)
   270  	assert.EqualError(t, err, "rpc error: code = PermissionDenied desc = Permission denied: unauthorized peer role: rpc error: code = PermissionDenied desc = no client certificates in request")
   271  }
   272  
   273  func TestHeartbeat(t *testing.T) {
   274  	cfg := DefaultConfig()
   275  	cfg.HeartbeatPeriod = 500 * time.Millisecond
   276  	cfg.HeartbeatEpsilon = 0
   277  	gd := startDispatcher(t, DefaultConfig())
   278  	defer gd.Close()
   279  
   280  	var expectedSessionID string
   281  	{
   282  		stream, err := gd.Clients[0].Session(context.Background(), &api.SessionRequest{})
   283  		assert.NoError(t, err)
   284  		defer stream.CloseSend()
   285  
   286  		resp, err := stream.Recv()
   287  		assert.NoError(t, err)
   288  		assert.NotEmpty(t, resp.SessionID)
   289  		expectedSessionID = resp.SessionID
   290  	}
   291  	time.Sleep(250 * time.Millisecond)
   292  
   293  	{
   294  		// heartbeat without correct SessionID should fail
   295  		resp, err := gd.Clients[0].Heartbeat(context.Background(), &api.HeartbeatRequest{})
   296  		assert.Nil(t, resp)
   297  		assert.Error(t, err)
   298  		assert.Equal(t, testutils.ErrorCode(err), codes.InvalidArgument)
   299  	}
   300  
   301  	resp, err := gd.Clients[0].Heartbeat(context.Background(), &api.HeartbeatRequest{SessionID: expectedSessionID})
   302  	assert.NoError(t, err)
   303  	assert.NotZero(t, resp.Period)
   304  	time.Sleep(300 * time.Millisecond)
   305  
   306  	gd.Store.View(func(readTx store.ReadTx) {
   307  		storeNodes, err := store.FindNodes(readTx, store.All)
   308  		assert.NoError(t, err)
   309  		assert.NotEmpty(t, storeNodes)
   310  		found := false
   311  		for _, node := range storeNodes {
   312  			if node.ID == gd.SecurityConfigs[0].ClientTLSCreds.NodeID() {
   313  				found = true
   314  				assert.Equal(t, api.NodeStatus_READY, node.Status.State)
   315  			}
   316  		}
   317  		assert.True(t, found)
   318  	})
   319  }
   320  
   321  func TestHeartbeatNoCert(t *testing.T) {
   322  	gd := startDispatcher(t, DefaultConfig())
   323  	defer gd.Close()
   324  
   325  	// heartbeat without correct SessionID should fail
   326  	resp, err := gd.Clients[2].Heartbeat(context.Background(), &api.HeartbeatRequest{})
   327  	assert.Nil(t, resp)
   328  	assert.EqualError(t, err, "rpc error: code = PermissionDenied desc = Permission denied: unauthorized peer role: rpc error: code = PermissionDenied desc = no client certificates in request")
   329  }
   330  
   331  func TestHeartbeatTimeout(t *testing.T) {
   332  	t.Parallel()
   333  
   334  	cfg := DefaultConfig()
   335  	cfg.HeartbeatPeriod = 100 * time.Millisecond
   336  	cfg.HeartbeatEpsilon = 0
   337  	gd := startDispatcher(t, cfg)
   338  	defer gd.Close()
   339  
   340  	var expectedSessionID string
   341  	{
   342  		stream, err := gd.Clients[0].Session(context.Background(), &api.SessionRequest{})
   343  		assert.NoError(t, err)
   344  		resp, err := stream.Recv()
   345  		assert.NoError(t, err)
   346  		assert.NotEmpty(t, resp.SessionID)
   347  		expectedSessionID = resp.SessionID
   348  
   349  	}
   350  
   351  	assert.NoError(t, testutils.PollFunc(nil, func() error {
   352  		var storeNode *api.Node
   353  		gd.Store.View(func(readTx store.ReadTx) {
   354  			storeNode = store.GetNode(readTx, gd.SecurityConfigs[0].ClientTLSCreds.NodeID())
   355  		})
   356  		if storeNode == nil {
   357  			return errors.New("node not found")
   358  		}
   359  		if storeNode.Status.State != api.NodeStatus_DOWN {
   360  			return errors.New("node is not down")
   361  		}
   362  		return nil
   363  	}))
   364  
   365  	// check that node is deregistered
   366  	resp, err := gd.Clients[0].Heartbeat(context.Background(), &api.HeartbeatRequest{SessionID: expectedSessionID})
   367  	assert.Nil(t, resp)
   368  	assert.Error(t, err)
   369  	assert.Equal(t, testutils.ErrorDesc(err), ErrNodeNotRegistered.Error())
   370  }
   371  
   372  func TestHeartbeatUnregistered(t *testing.T) {
   373  	gd := startDispatcher(t, DefaultConfig())
   374  	defer gd.Close()
   375  	resp, err := gd.Clients[0].Heartbeat(context.Background(), &api.HeartbeatRequest{})
   376  	assert.Nil(t, resp)
   377  	assert.Error(t, err)
   378  	assert.Equal(t, ErrSessionInvalid.Error(), testutils.ErrorDesc(err))
   379  }
   380  
   381  // If the session ID is not sent as part of the Assignments request, an error is returned to the stream
   382  func TestAssignmentsErrorsIfNoSessionID(t *testing.T) {
   383  	t.Parallel()
   384  
   385  	gd := startDispatcher(t, DefaultConfig())
   386  	defer gd.Close()
   387  
   388  	// without correct SessionID should fail
   389  	stream, err := gd.Clients[0].Assignments(context.Background(), &api.AssignmentsRequest{})
   390  	assert.NoError(t, err)
   391  	assert.NotNil(t, stream)
   392  	defer stream.CloseSend()
   393  
   394  	resp, err := stream.Recv()
   395  	assert.Nil(t, resp)
   396  	assert.Error(t, err)
   397  	assert.Equal(t, testutils.ErrorCode(err), codes.InvalidArgument)
   398  }
   399  
   400  func TestAssignmentsSecretDriver(t *testing.T) {
   401  	t.Parallel()
   402  
   403  	const (
   404  		secretDriver                 = "secret-driver"
   405  		existingSecretName           = "existing-secret"
   406  		doNotReuseExistingSecretName = "do-not-reuse-existing-secret"
   407  		errSecretName                = "err-secret"
   408  		serviceName                  = "service-name"
   409  		serviceHostname              = "service-hostname"
   410  		serviceEndpointMode          = 2
   411  	)
   412  	secretValue := []byte("custom-secret-value")
   413  	doNotReuseSecretValue := []byte("custom-do-not-reuse-secret-value")
   414  	serviceLabels := map[string]string{
   415  		"label-name": "label-value",
   416  	}
   417  
   418  	portConfig := drivers.PortConfig{Name: "port", PublishMode: 5, TargetPort: 80, Protocol: 10, PublishedPort: 8080}
   419  
   420  	responses := map[string]*drivers.SecretsProviderResponse{
   421  		existingSecretName:           {Value: secretValue},
   422  		doNotReuseExistingSecretName: {Value: doNotReuseSecretValue, DoNotReuse: true},
   423  		errSecretName:                {Err: "Error from driver"},
   424  	}
   425  
   426  	mux := http.NewServeMux()
   427  	mux.HandleFunc(drivers.SecretsProviderAPI, func(w http.ResponseWriter, r *http.Request) {
   428  		defer r.Body.Close()
   429  		body, err := ioutil.ReadAll(r.Body)
   430  		var request drivers.SecretsProviderRequest
   431  		assert.NoError(t, err)
   432  		assert.NoError(t, json.Unmarshal(body, &request))
   433  		response := responses[request.SecretName]
   434  		assert.Equal(t, serviceName, request.ServiceName)
   435  		assert.Equal(t, serviceHostname, request.ServiceHostname)
   436  		assert.Equal(t, int32(serviceEndpointMode), request.ServiceEndpointSpec.Mode)
   437  		assert.Len(t, request.ServiceEndpointSpec.Ports, 1)
   438  		assert.EqualValues(t, portConfig, request.ServiceEndpointSpec.Ports[0])
   439  		assert.EqualValues(t, serviceLabels, request.ServiceLabels)
   440  		assert.NotNil(t, response)
   441  		resp, err := json.Marshal(response)
   442  		assert.NoError(t, err)
   443  		w.Write(resp)
   444  	})
   445  
   446  	gd := startDispatcher(t, DefaultConfig())
   447  	defer gd.Close()
   448  	assert.NoError(t, gd.PluginGetter.SetupPlugin(secretDriver, mux))
   449  
   450  	expectedSessionID, nodeID := getSessionAndNodeID(t, gd.Clients[0])
   451  
   452  	secret := &api.Secret{
   453  		ID: "driverSecret",
   454  		Spec: api.SecretSpec{
   455  			Annotations: api.Annotations{Name: existingSecretName},
   456  			Driver:      &api.Driver{Name: secretDriver},
   457  		},
   458  	}
   459  	doNotReuseSecret := &api.Secret{
   460  		ID: "driverDoNotReuseSecret",
   461  		Spec: api.SecretSpec{
   462  			Annotations: api.Annotations{Name: doNotReuseExistingSecretName},
   463  			Driver:      &api.Driver{Name: secretDriver},
   464  		},
   465  	}
   466  	errSecret := &api.Secret{
   467  		ID: "driverErrSecret",
   468  		Spec: api.SecretSpec{
   469  			Annotations: api.Annotations{Name: errSecretName},
   470  			Driver:      &api.Driver{Name: secretDriver},
   471  		},
   472  	}
   473  	config := &api.Config{
   474  		ID: "config",
   475  		Spec: api.ConfigSpec{
   476  			Data: []byte("config"),
   477  		},
   478  	}
   479  	spec := taskSpecFromDependencies(secret, doNotReuseSecret, errSecret, config)
   480  	spec.GetContainer().Hostname = serviceHostname
   481  	task := &api.Task{
   482  		NodeID:       nodeID,
   483  		ID:           "secretTask",
   484  		Status:       api.TaskStatus{State: api.TaskStateReady},
   485  		DesiredState: api.TaskStateNew,
   486  		Spec:         spec,
   487  		Endpoint: &api.Endpoint{
   488  			Spec: &api.EndpointSpec{
   489  				Mode: serviceEndpointMode,
   490  				Ports: []*api.PortConfig{
   491  					{
   492  						Name:          portConfig.Name,
   493  						PublishedPort: portConfig.PublishedPort,
   494  						Protocol:      api.PortConfig_Protocol(portConfig.Protocol),
   495  						TargetPort:    portConfig.TargetPort,
   496  						PublishMode:   api.PortConfig_PublishMode(portConfig.PublishMode),
   497  					},
   498  				},
   499  			},
   500  		},
   501  		ServiceAnnotations: api.Annotations{
   502  			Name:   serviceName,
   503  			Labels: serviceLabels,
   504  		},
   505  	}
   506  
   507  	err := gd.Store.Update(func(tx store.Tx) error {
   508  		assert.NoError(t, store.CreateSecret(tx, secret))
   509  		assert.NoError(t, store.CreateSecret(tx, doNotReuseSecret))
   510  		assert.NoError(t, store.CreateSecret(tx, errSecret))
   511  		assert.NoError(t, store.CreateConfig(tx, config))
   512  		assert.NoError(t, store.CreateTask(tx, task))
   513  		return nil
   514  	})
   515  	assert.NoError(t, err)
   516  
   517  	stream, err := gd.Clients[0].Assignments(context.Background(), &api.AssignmentsRequest{SessionID: expectedSessionID})
   518  	assert.NoError(t, err)
   519  	defer stream.CloseSend()
   520  
   521  	resp, err := stream.Recv()
   522  	assert.NoError(t, err)
   523  
   524  	_, _, secretChanges := splitChanges(resp.Changes)
   525  	assert.Len(t, secretChanges, 2)
   526  	for _, s := range secretChanges {
   527  		if s.ID == "driverSecret" {
   528  			assert.Equal(t, secretValue, s.Spec.Data)
   529  		} else if s.ID == "driverDoNotReuseSecret" {
   530  			assert.Fail(t, "Secret with DoNotReuse==true should not retain its original ID in the assignment", "%s != %s", "driverDoNotReuseSecret", s.ID)
   531  		} else {
   532  			taskSpecificID := fmt.Sprintf("%s.%s", "driverDoNotReuseSecret", task.ID)
   533  			assert.Equal(t, taskSpecificID, s.ID)
   534  			assert.Equal(t, doNotReuseSecretValue, s.Spec.Data)
   535  		}
   536  	}
   537  }
   538  
   539  // When connecting to a dispatcher to get Assignments, if there are tasks already in the store,
   540  // Assignments will send down any existing node tasks > ASSIGNED, and any secrets
   541  // for said tasks that are <= RUNNING (if the secrets exist)
   542  func TestAssignmentsInitialNodeTasks(t *testing.T) {
   543  	t.Parallel()
   544  	testFuncs := []taskGeneratorFunc{
   545  		makeTasksAndDependenciesWithResourceReferences,
   546  		makeTasksAndDependenciesNoResourceReferences,
   547  		makeTasksAndDependenciesOnlyResourceReferences,
   548  		makeTasksAndDependenciesWithRedundantReferences,
   549  	}
   550  	for _, testFunc := range testFuncs {
   551  		testAssignmentsInitialNodeTasksWithGivenTasks(t, testFunc)
   552  	}
   553  }
   554  
   555  func testAssignmentsInitialNodeTasksWithGivenTasks(t *testing.T, genTasks taskGeneratorFunc) {
   556  	gd := startDispatcher(t, DefaultConfig())
   557  	defer gd.Close()
   558  
   559  	expectedSessionID, nodeID := getSessionAndNodeID(t, gd.Clients[0])
   560  
   561  	// create the relevant secrets and tasks
   562  	secrets, configs, resourceRefs, tasks := genTasks(t, nodeID)
   563  	err := gd.Store.Update(func(tx store.Tx) error {
   564  		for _, secret := range secrets {
   565  			assert.NoError(t, store.CreateSecret(tx, secret))
   566  		}
   567  		for _, config := range configs {
   568  			assert.NoError(t, store.CreateConfig(tx, config))
   569  		}
   570  		// make dummy secrets and configs for resourceRefs
   571  		for _, resourceRef := range resourceRefs {
   572  			assert.NoError(t, makeMockResource(tx, resourceRef))
   573  		}
   574  
   575  		for _, task := range tasks {
   576  			assert.NoError(t, store.CreateTask(tx, task))
   577  		}
   578  		return nil
   579  	})
   580  	assert.NoError(t, err)
   581  
   582  	stream, err := gd.Clients[0].Assignments(context.Background(), &api.AssignmentsRequest{SessionID: expectedSessionID})
   583  	assert.NoError(t, err)
   584  	defer stream.CloseSend()
   585  
   586  	time.Sleep(100 * time.Millisecond)
   587  
   588  	// check the initial task and secret stream
   589  	resp, err := stream.Recv()
   590  	assert.NoError(t, err)
   591  
   592  	assignedToRunningTasks := filterTasks(tasks, func(s api.TaskState) bool {
   593  		return s >= api.TaskStateAssigned && s <= api.TaskStateRunning
   594  	})
   595  	pastRunningTasks := filterTasks(tasks, func(s api.TaskState) bool {
   596  		return s > api.TaskStateRunning
   597  	})
   598  	atLeastAssignedTasks := filterTasks(tasks, func(s api.TaskState) bool {
   599  		return s >= api.TaskStateAssigned
   600  	})
   601  
   602  	// dispatcher sends dependencies for all tasks >= ASSIGNED and <= RUNNING
   603  	referencedSecrets, referencedConfigs := getResourcesFromReferences(gd, resourceRefs)
   604  	secrets = append(secrets, referencedSecrets...)
   605  	configs = append(configs, referencedConfigs...)
   606  	updatedSecrets, updatedConfigs := filterDependencies(secrets, configs, assignedToRunningTasks, nil)
   607  	verifyChanges(t, resp.Changes, []changeExpectations{
   608  		{
   609  			action:  api.AssignmentChange_AssignmentActionUpdate,
   610  			tasks:   atLeastAssignedTasks, // dispatcher sends task updates for all tasks >= ASSIGNED
   611  			secrets: updatedSecrets,
   612  			configs: updatedConfigs,
   613  		},
   614  	})
   615  
   616  	// updating all the tasks will attempt to remove all the secrets for the tasks that are in state > running
   617  	err = gd.Store.Update(func(tx store.Tx) error {
   618  		for _, task := range tasks {
   619  			assert.NoError(t, store.UpdateTask(tx, task))
   620  		}
   621  		return nil
   622  
   623  	})
   624  	assert.NoError(t, err)
   625  
   626  	resp, err = stream.Recv()
   627  	assert.NoError(t, err)
   628  
   629  	// dependencies for tasks > RUNNING are removed, but only if they are not currently being used
   630  	// by a task >= ASSIGNED and <= RUNNING
   631  	updatedSecrets, updatedConfigs = filterDependencies(secrets, configs, pastRunningTasks, assignedToRunningTasks)
   632  	verifyChanges(t, resp.Changes, []changeExpectations{
   633  		{
   634  			// ASSIGNED tasks are always sent down even if they haven't changed
   635  			action: api.AssignmentChange_AssignmentActionUpdate,
   636  			tasks:  filterTasks(tasks, func(s api.TaskState) bool { return s == api.TaskStateAssigned }),
   637  		},
   638  		{
   639  			action:  api.AssignmentChange_AssignmentActionRemove,
   640  			secrets: updatedSecrets,
   641  			configs: updatedConfigs,
   642  		},
   643  	})
   644  
   645  	// deleting the tasks removes all the secrets for every single task, no matter
   646  	// what state it's in
   647  	err = gd.Store.Update(func(tx store.Tx) error {
   648  		for _, task := range tasks {
   649  			assert.NoError(t, store.DeleteTask(tx, task.ID))
   650  		}
   651  		return nil
   652  	})
   653  	assert.NoError(t, err)
   654  
   655  	resp, err = stream.Recv()
   656  	assert.NoError(t, err)
   657  
   658  	// tasks >= ASSIGNED and their dependencies have all been removed;
   659  	// task < ASSIGNED and their dependencies were never sent in the first place, so don't need to be removed
   660  	updatedSecrets, updatedConfigs = filterDependencies(secrets, configs, atLeastAssignedTasks, nil)
   661  	verifyChanges(t, resp.Changes, []changeExpectations{
   662  		{
   663  			action:  api.AssignmentChange_AssignmentActionRemove,
   664  			tasks:   atLeastAssignedTasks,
   665  			secrets: updatedSecrets,
   666  			configs: updatedConfigs,
   667  		},
   668  	})
   669  }
   670  
   671  func mockNumberedConfig(i int) *api.Config {
   672  	return &api.Config{
   673  		ID: fmt.Sprintf("IDconfig%d", i),
   674  		Spec: api.ConfigSpec{
   675  			Annotations: api.Annotations{
   676  				Name: fmt.Sprintf("config%d", i),
   677  			},
   678  			Data: []byte(fmt.Sprintf("config%d", i)),
   679  		},
   680  	}
   681  }
   682  
   683  func mockNumberedSecret(i int) *api.Secret {
   684  	return &api.Secret{
   685  		ID: fmt.Sprintf("IDsecret%d", i),
   686  		Spec: api.SecretSpec{
   687  			Annotations: api.Annotations{
   688  				Name: fmt.Sprintf("secret%d", i),
   689  			},
   690  			Data: []byte(fmt.Sprintf("secret%d", i)),
   691  		},
   692  	}
   693  }
   694  
   695  func mockNumberedReadyTask(i int, nodeID string, taskState api.TaskState, spec api.TaskSpec) *api.Task {
   696  	return &api.Task{
   697  		NodeID:       nodeID,
   698  		ID:           fmt.Sprintf("testTask%d", i),
   699  		Status:       api.TaskStatus{State: taskState},
   700  		DesiredState: api.TaskStateReady,
   701  		Spec:         spec,
   702  	}
   703  }
   704  
   705  func makeMockResource(tx store.Tx, resourceRef *api.ResourceReference) error {
   706  	switch resourceRef.ResourceType {
   707  	case api.ResourceType_SECRET:
   708  		dummySecret := &api.Secret{
   709  			ID: resourceRef.ResourceID,
   710  			Spec: api.SecretSpec{
   711  				Annotations: api.Annotations{
   712  					Name: fmt.Sprintf("dummy_secret_%s", resourceRef.ResourceID),
   713  				},
   714  				Data: []byte(fmt.Sprintf("secret_%s", resourceRef.ResourceID)),
   715  			},
   716  		}
   717  		if store.GetSecret(tx, dummySecret.ID) == nil {
   718  			return store.CreateSecret(tx, dummySecret)
   719  		}
   720  		// the resource already exists
   721  		return nil
   722  	case api.ResourceType_CONFIG:
   723  		dummyConfig := &api.Config{
   724  			ID: resourceRef.ResourceID,
   725  			Spec: api.ConfigSpec{
   726  				Annotations: api.Annotations{
   727  					Name: fmt.Sprintf("dummy_config_%s", resourceRef.ResourceID),
   728  				},
   729  				Data: []byte(fmt.Sprintf("config_%s", resourceRef.ResourceID)),
   730  			},
   731  		}
   732  		if store.GetConfig(tx, dummyConfig.ID) == nil {
   733  			return store.CreateConfig(tx, dummyConfig)
   734  		}
   735  		// the resource already exists
   736  		return nil
   737  	default:
   738  		return fmt.Errorf("unsupported mock resource type")
   739  	}
   740  }
   741  
   742  // When connecting to a dispatcher with no tasks or assignments, when tasks are updated, assignments will send down
   743  // tasks > ASSIGNED, and any secrets for said tasks that are <= RUNNING (but only if the secrets/configs exist - if
   744  // they don't, even if they are referenced, the task is still sent down)
   745  func TestAssignmentsAddingTasks(t *testing.T) {
   746  	t.Parallel()
   747  	testFuncs := []taskGeneratorFunc{
   748  		makeTasksAndDependenciesWithResourceReferences,
   749  		makeTasksAndDependenciesNoResourceReferences,
   750  		makeTasksAndDependenciesOnlyResourceReferences,
   751  		makeTasksAndDependenciesWithRedundantReferences,
   752  	}
   753  	for _, testFunc := range testFuncs {
   754  		testAssignmentsAddingTasksWithGivenTasks(t, testFunc)
   755  	}
   756  }
   757  
   758  func testAssignmentsAddingTasksWithGivenTasks(t *testing.T, genTasks taskGeneratorFunc) {
   759  	gd := startDispatcher(t, DefaultConfig())
   760  	defer gd.Close()
   761  
   762  	expectedSessionID, nodeID := getSessionAndNodeID(t, gd.Clients[0])
   763  
   764  	stream, err := gd.Clients[0].Assignments(context.Background(), &api.AssignmentsRequest{SessionID: expectedSessionID})
   765  	assert.NoError(t, err)
   766  	defer stream.CloseSend()
   767  
   768  	time.Sleep(100 * time.Millisecond)
   769  
   770  	// There are no initial tasks or secrets
   771  	resp, err := stream.Recv()
   772  	assert.NoError(t, err)
   773  	assert.Empty(t, resp.Changes)
   774  
   775  	// create the relevant secrets, configs, and tasks and update the tasks
   776  	secrets, configs, resourceRefs, tasks := genTasks(t, nodeID)
   777  	var createdSecrets []*api.Secret
   778  	var createdConfigs []*api.Config
   779  	if len(secrets) > 0 {
   780  		createdSecrets = secrets[:len(secrets)-1]
   781  	}
   782  	if len(configs) > 0 {
   783  		createdConfigs = configs[:len(configs)-1]
   784  	}
   785  	err = gd.Store.Update(func(tx store.Tx) error {
   786  		for _, secret := range createdSecrets {
   787  			if store.GetSecret(tx, secret.ID) == nil {
   788  				assert.NoError(t, store.CreateSecret(tx, secret))
   789  			}
   790  		}
   791  		for _, config := range createdConfigs {
   792  			if store.GetConfig(tx, config.ID) == nil {
   793  				assert.NoError(t, store.CreateConfig(tx, config))
   794  			}
   795  		}
   796  		// make dummy secrets and configs for resourceRefs
   797  		for _, resourceRef := range resourceRefs {
   798  			assert.NoError(t, makeMockResource(tx, resourceRef))
   799  		}
   800  
   801  		for _, task := range tasks {
   802  			assert.NoError(t, store.CreateTask(tx, task))
   803  		}
   804  		return nil
   805  	})
   806  	assert.NoError(t, err)
   807  
   808  	// Nothing happens until we update.  Updating all the tasks will send updates for all the tasks >= ASSIGNED,
   809  	// and secrets for all the tasks >= ASSIGNED and <= RUNNING.
   810  	err = gd.Store.Update(func(tx store.Tx) error {
   811  		for _, task := range tasks {
   812  			assert.NoError(t, store.UpdateTask(tx, task))
   813  		}
   814  		return nil
   815  
   816  	})
   817  	assert.NoError(t, err)
   818  
   819  	resp, err = stream.Recv()
   820  	assert.NoError(t, err)
   821  
   822  	assignedToRunningTasks := filterTasks(tasks, func(s api.TaskState) bool {
   823  		return s >= api.TaskStateAssigned && s <= api.TaskStateRunning
   824  	})
   825  	atLeastAssignedTasks := filterTasks(tasks, func(s api.TaskState) bool {
   826  		return s >= api.TaskStateAssigned
   827  	})
   828  
   829  	// dispatcher sends dependencies for all tasks >= ASSIGNED and <= RUNNING, but only if they exist in
   830  	// the store - if a dependency is referenced by a task but does not exist, that's fine, it just won't be
   831  	// included in the changes
   832  	referencedSecrets, referencedConfigs := getResourcesFromReferences(gd, resourceRefs)
   833  	createdSecrets = append(createdSecrets, referencedSecrets...)
   834  	createdConfigs = append(createdConfigs, referencedConfigs...)
   835  	updatedSecrets, updatedConfigs := filterDependencies(createdSecrets, createdConfigs, assignedToRunningTasks, nil)
   836  	verifyChanges(t, resp.Changes, []changeExpectations{
   837  		{
   838  			action:  api.AssignmentChange_AssignmentActionUpdate,
   839  			tasks:   atLeastAssignedTasks, // dispatcher sends task updates for all tasks >= ASSIGNED
   840  			secrets: updatedSecrets,
   841  			configs: updatedConfigs,
   842  		},
   843  	})
   844  
   845  	// deleting the tasks removes all the secrets for every single task, no matter
   846  	// what state it's in
   847  	err = gd.Store.Update(func(tx store.Tx) error {
   848  		for _, task := range tasks {
   849  			assert.NoError(t, store.DeleteTask(tx, task.ID))
   850  		}
   851  		return nil
   852  
   853  	})
   854  	assert.NoError(t, err)
   855  
   856  	resp, err = stream.Recv()
   857  	assert.NoError(t, err)
   858  
   859  	// tasks >= ASSIGNED and their dependencies have all been removed, even if they don't exist in the store;
   860  	// task < ASSIGNED and their dependencies were never sent in the first place, so don't need to be removed
   861  	secrets = append(secrets, referencedSecrets...)
   862  	configs = append(configs, referencedConfigs...)
   863  	updatedSecrets, updatedConfigs = filterDependencies(secrets, configs, atLeastAssignedTasks, nil)
   864  	verifyChanges(t, resp.Changes, []changeExpectations{
   865  		{
   866  			action:  api.AssignmentChange_AssignmentActionRemove,
   867  			tasks:   atLeastAssignedTasks,
   868  			secrets: updatedSecrets,
   869  			configs: updatedConfigs,
   870  		},
   871  	})
   872  }
   873  
   874  // If a secret or config is updated or deleted, even if it's for an existing task, no changes will be sent down
   875  func TestAssignmentsDependencyUpdateAndDeletion(t *testing.T) {
   876  	t.Parallel()
   877  	testFuncs := []taskGeneratorFunc{
   878  		makeTasksAndDependenciesWithResourceReferences,
   879  		makeTasksAndDependenciesNoResourceReferences,
   880  		makeTasksAndDependenciesOnlyResourceReferences,
   881  		makeTasksAndDependenciesWithRedundantReferences,
   882  	}
   883  	for _, testFunc := range testFuncs {
   884  		testAssignmentsDependencyUpdateAndDeletionWithGivenTasks(t, testFunc)
   885  	}
   886  }
   887  
   888  func testAssignmentsDependencyUpdateAndDeletionWithGivenTasks(t *testing.T, genTasks taskGeneratorFunc) {
   889  	gd := startDispatcher(t, DefaultConfig())
   890  	defer gd.Close()
   891  
   892  	expectedSessionID, nodeID := getSessionAndNodeID(t, gd.Clients[0])
   893  
   894  	// create the relevant secrets and tasks
   895  	secrets, configs, resourceRefs, tasks := genTasks(t, nodeID)
   896  	err := gd.Store.Update(func(tx store.Tx) error {
   897  		for _, secret := range secrets {
   898  			if store.GetSecret(tx, secret.ID) == nil {
   899  				assert.NoError(t, store.CreateSecret(tx, secret))
   900  			}
   901  		}
   902  		for _, config := range configs {
   903  			if store.GetConfig(tx, config.ID) == nil {
   904  				assert.NoError(t, store.CreateConfig(tx, config))
   905  			}
   906  		}
   907  		// make dummy secrets and configs for resourceRefs
   908  		for _, resourceRef := range resourceRefs {
   909  			assert.NoError(t, makeMockResource(tx, resourceRef))
   910  		}
   911  
   912  		for _, task := range tasks {
   913  			assert.NoError(t, store.CreateTask(tx, task))
   914  		}
   915  		return nil
   916  	})
   917  	assert.NoError(t, err)
   918  
   919  	stream, err := gd.Clients[0].Assignments(context.Background(), &api.AssignmentsRequest{SessionID: expectedSessionID})
   920  	assert.NoError(t, err)
   921  	defer stream.CloseSend()
   922  
   923  	time.Sleep(100 * time.Millisecond)
   924  
   925  	// check the initial task and secret stream
   926  	resp, err := stream.Recv()
   927  	assert.NoError(t, err)
   928  
   929  	assignedToRunningTasks := filterTasks(tasks, func(s api.TaskState) bool {
   930  		return s >= api.TaskStateAssigned && s <= api.TaskStateRunning
   931  	})
   932  	atLeastAssignedTasks := filterTasks(tasks, func(s api.TaskState) bool {
   933  		return s >= api.TaskStateAssigned
   934  	})
   935  
   936  	// dispatcher sends dependencies for all tasks >= ASSIGNED and <= RUNNING
   937  	referencedSecrets, referencedConfigs := getResourcesFromReferences(gd, resourceRefs)
   938  	secrets = append(secrets, referencedSecrets...)
   939  	configs = append(configs, referencedConfigs...)
   940  	updatedSecrets, updatedConfigs := filterDependencies(secrets, configs, assignedToRunningTasks, nil)
   941  	verifyChanges(t, resp.Changes, []changeExpectations{
   942  		{
   943  			action:  api.AssignmentChange_AssignmentActionUpdate,
   944  			tasks:   atLeastAssignedTasks, // dispatcher sends task updates for all tasks >= ASSIGNED
   945  			secrets: updatedSecrets,
   946  			configs: updatedConfigs,
   947  		},
   948  	})
   949  
   950  	// updating secrets and configs, used by tasks or not, do not cause any changes
   951  	uniqueSecrets := uniquifySecrets(secrets)
   952  	uniqueConfigs := uniquifyConfigs(configs)
   953  	assert.NoError(t, gd.Store.Update(func(tx store.Tx) error {
   954  		for _, s := range uniqueSecrets {
   955  			s.Spec.Data = []byte("new secret data")
   956  			if err := store.UpdateSecret(tx, s); err != nil {
   957  				return err
   958  			}
   959  		}
   960  		for _, c := range uniqueConfigs {
   961  			c.Spec.Data = []byte("new config data")
   962  			if err := store.UpdateConfig(tx, c); err != nil {
   963  				return err
   964  			}
   965  		}
   966  		return nil
   967  	}))
   968  
   969  	recvChan := make(chan struct{})
   970  	go func() {
   971  		_, _ = stream.Recv()
   972  		recvChan <- struct{}{}
   973  	}()
   974  
   975  	select {
   976  	case <-recvChan:
   977  		assert.Fail(t, "secret update should not trigger dispatcher update")
   978  	case <-time.After(250 * time.Millisecond):
   979  	}
   980  
   981  	// deleting secrets and configs, used by tasks or not, do not cause any changes
   982  	err = gd.Store.Update(func(tx store.Tx) error {
   983  		for _, secret := range uniqueSecrets {
   984  			assert.NoError(t, store.DeleteSecret(tx, secret.ID))
   985  		}
   986  		for _, config := range uniqueConfigs {
   987  			assert.NoError(t, store.DeleteConfig(tx, config.ID))
   988  		}
   989  		return nil
   990  	})
   991  	assert.NoError(t, err)
   992  
   993  	select {
   994  	case <-recvChan:
   995  		assert.Fail(t, "secret delete should not trigger dispatcher update")
   996  	case <-time.After(250 * time.Millisecond):
   997  	}
   998  }
   999  
  1000  func TestTasksStatusChange(t *testing.T) {
  1001  	t.Parallel()
  1002  
  1003  	gd := startDispatcher(t, DefaultConfig())
  1004  	defer gd.Close()
  1005  
  1006  	var expectedSessionID string
  1007  	var nodeID string
  1008  	{
  1009  		stream, err := gd.Clients[0].Session(context.Background(), &api.SessionRequest{})
  1010  		assert.NoError(t, err)
  1011  		defer stream.CloseSend()
  1012  		resp, err := stream.Recv()
  1013  		assert.NoError(t, err)
  1014  		assert.NotEmpty(t, resp.SessionID)
  1015  		expectedSessionID = resp.SessionID
  1016  		nodeID = resp.Node.ID
  1017  	}
  1018  
  1019  	testTask1 := &api.Task{
  1020  		NodeID:       nodeID,
  1021  		ID:           "testTask1",
  1022  		Status:       api.TaskStatus{State: api.TaskStateAssigned},
  1023  		DesiredState: api.TaskStateReady,
  1024  	}
  1025  	testTask2 := &api.Task{
  1026  		NodeID:       nodeID,
  1027  		ID:           "testTask2",
  1028  		Status:       api.TaskStatus{State: api.TaskStateAssigned},
  1029  		DesiredState: api.TaskStateReady,
  1030  	}
  1031  
  1032  	stream, err := gd.Clients[0].Assignments(context.Background(), &api.AssignmentsRequest{SessionID: expectedSessionID})
  1033  	assert.NoError(t, err)
  1034  
  1035  	time.Sleep(100 * time.Millisecond)
  1036  
  1037  	resp, err := stream.Recv()
  1038  	assert.NoError(t, err)
  1039  	// initially no tasks
  1040  	assert.Equal(t, 0, len(resp.Changes))
  1041  
  1042  	// Creating the tasks will not create an event for assignments
  1043  	err = gd.Store.Update(func(tx store.Tx) error {
  1044  		assert.NoError(t, store.CreateTask(tx, testTask1))
  1045  		assert.NoError(t, store.CreateTask(tx, testTask2))
  1046  		return nil
  1047  	})
  1048  	assert.NoError(t, err)
  1049  	err = gd.Store.Update(func(tx store.Tx) error {
  1050  		assert.NoError(t, store.UpdateTask(tx, testTask1))
  1051  		assert.NoError(t, store.UpdateTask(tx, testTask2))
  1052  		return nil
  1053  	})
  1054  	assert.NoError(t, err)
  1055  
  1056  	resp, err = stream.Recv()
  1057  	assert.NoError(t, err)
  1058  
  1059  	verifyChanges(t, resp.Changes, []changeExpectations{
  1060  		{
  1061  			action: api.AssignmentChange_AssignmentActionUpdate,
  1062  			tasks:  []*api.Task{testTask1, testTask2},
  1063  		},
  1064  	})
  1065  
  1066  	assert.NoError(t, gd.Store.Update(func(tx store.Tx) error {
  1067  		task := store.GetTask(tx, testTask1.ID)
  1068  		if task == nil {
  1069  			return errors.New("no task")
  1070  		}
  1071  		task.NodeID = nodeID
  1072  		// only Status is changed for task1
  1073  		task.Status = api.TaskStatus{State: api.TaskStateFailed, Err: "1234"}
  1074  		task.DesiredState = api.TaskStateReady
  1075  		return store.UpdateTask(tx, task)
  1076  	}))
  1077  
  1078  	// dispatcher shouldn't send snapshot for this update
  1079  	recvChan := make(chan struct{})
  1080  	go func() {
  1081  		_, _ = stream.Recv()
  1082  		recvChan <- struct{}{}
  1083  	}()
  1084  
  1085  	select {
  1086  	case <-recvChan:
  1087  		assert.Fail(t, "task.Status update should not trigger dispatcher update")
  1088  	case <-time.After(250 * time.Millisecond):
  1089  	}
  1090  }
  1091  
  1092  func TestTasksBatch(t *testing.T) {
  1093  	gd := startDispatcher(t, DefaultConfig())
  1094  	defer gd.Close()
  1095  
  1096  	var expectedSessionID string
  1097  	var nodeID string
  1098  	{
  1099  		stream, err := gd.Clients[0].Session(context.Background(), &api.SessionRequest{})
  1100  		assert.NoError(t, err)
  1101  		defer stream.CloseSend()
  1102  		resp, err := stream.Recv()
  1103  		assert.NoError(t, err)
  1104  		assert.NotEmpty(t, resp.SessionID)
  1105  		expectedSessionID = resp.SessionID
  1106  		nodeID = resp.Node.ID
  1107  	}
  1108  
  1109  	testTask1 := &api.Task{
  1110  		NodeID: nodeID,
  1111  		ID:     "testTask1",
  1112  		Status: api.TaskStatus{State: api.TaskStateAssigned},
  1113  	}
  1114  	testTask2 := &api.Task{
  1115  		NodeID: nodeID,
  1116  		ID:     "testTask2",
  1117  		Status: api.TaskStatus{State: api.TaskStateAssigned},
  1118  	}
  1119  
  1120  	stream, err := gd.Clients[0].Assignments(context.Background(), &api.AssignmentsRequest{SessionID: expectedSessionID})
  1121  	assert.NoError(t, err)
  1122  
  1123  	resp, err := stream.Recv()
  1124  	assert.NoError(t, err)
  1125  	// initially no tasks
  1126  	assert.Equal(t, 0, len(resp.Changes))
  1127  
  1128  	// Create, Update and Delete tasks.
  1129  	err = gd.Store.Update(func(tx store.Tx) error {
  1130  		assert.NoError(t, store.CreateTask(tx, testTask1))
  1131  		assert.NoError(t, store.CreateTask(tx, testTask2))
  1132  		return nil
  1133  	})
  1134  	assert.NoError(t, err)
  1135  	err = gd.Store.Update(func(tx store.Tx) error {
  1136  		assert.NoError(t, store.UpdateTask(tx, testTask1))
  1137  		assert.NoError(t, store.UpdateTask(tx, testTask2))
  1138  		return nil
  1139  	})
  1140  	assert.NoError(t, err)
  1141  
  1142  	err = gd.Store.Update(func(tx store.Tx) error {
  1143  		assert.NoError(t, store.DeleteTask(tx, testTask1.ID))
  1144  		assert.NoError(t, store.DeleteTask(tx, testTask2.ID))
  1145  		return nil
  1146  	})
  1147  	assert.NoError(t, err)
  1148  
  1149  	resp, err = stream.Recv()
  1150  	assert.NoError(t, err)
  1151  
  1152  	// all tasks have been deleted
  1153  	verifyChanges(t, resp.Changes, []changeExpectations{
  1154  		{
  1155  			action: api.AssignmentChange_AssignmentActionRemove,
  1156  			tasks:  []*api.Task{testTask1, testTask2},
  1157  		},
  1158  	})
  1159  }
  1160  
  1161  func TestTasksNoCert(t *testing.T) {
  1162  	gd := startDispatcher(t, DefaultConfig())
  1163  	defer gd.Close()
  1164  
  1165  	stream, err := gd.Clients[2].Assignments(context.Background(), &api.AssignmentsRequest{})
  1166  	assert.NoError(t, err)
  1167  	assert.NotNil(t, stream)
  1168  	resp, err := stream.Recv()
  1169  	assert.Nil(t, resp)
  1170  	assert.EqualError(t, err, "rpc error: code = PermissionDenied desc = Permission denied: unauthorized peer role: rpc error: code = PermissionDenied desc = no client certificates in request")
  1171  }
  1172  
  1173  func TestTaskUpdate(t *testing.T) {
  1174  	gd := startDispatcher(t, DefaultConfig())
  1175  	defer gd.Close()
  1176  
  1177  	var (
  1178  		expectedSessionID string
  1179  		nodeID            string
  1180  	)
  1181  	{
  1182  		stream, err := gd.Clients[0].Session(context.Background(), &api.SessionRequest{})
  1183  		assert.NoError(t, err)
  1184  		defer stream.CloseSend()
  1185  		resp, err := stream.Recv()
  1186  		assert.NoError(t, err)
  1187  		assert.NotEmpty(t, resp.SessionID)
  1188  		expectedSessionID = resp.SessionID
  1189  		nodeID = resp.Node.ID
  1190  
  1191  	}
  1192  	// testTask1 and testTask2 are advanced from NEW to ASSIGNED.
  1193  	testTask1 := &api.Task{
  1194  		ID:     "testTask1",
  1195  		NodeID: nodeID,
  1196  	}
  1197  	testTask2 := &api.Task{
  1198  		ID:     "testTask2",
  1199  		NodeID: nodeID,
  1200  	}
  1201  	// testTask3 is used to confirm that status updates for a task not
  1202  	// assigned to the node sending the update are rejected.
  1203  	testTask3 := &api.Task{
  1204  		ID:     "testTask3",
  1205  		NodeID: "differentnode",
  1206  	}
  1207  	// testTask4 is used to confirm that a task's state is not allowed to
  1208  	// move backwards.
  1209  	testTask4 := &api.Task{
  1210  		ID:     "testTask4",
  1211  		NodeID: nodeID,
  1212  		Status: api.TaskStatus{
  1213  			State: api.TaskStateShutdown,
  1214  		},
  1215  	}
  1216  	err := gd.Store.Update(func(tx store.Tx) error {
  1217  		assert.NoError(t, store.CreateTask(tx, testTask1))
  1218  		assert.NoError(t, store.CreateTask(tx, testTask2))
  1219  		assert.NoError(t, store.CreateTask(tx, testTask3))
  1220  		assert.NoError(t, store.CreateTask(tx, testTask4))
  1221  		return nil
  1222  	})
  1223  	assert.NoError(t, err)
  1224  
  1225  	testTask1.Status = api.TaskStatus{State: api.TaskStateAssigned}
  1226  	testTask2.Status = api.TaskStatus{State: api.TaskStateAssigned}
  1227  	testTask3.Status = api.TaskStatus{State: api.TaskStateAssigned}
  1228  	testTask4.Status = api.TaskStatus{State: api.TaskStateRunning}
  1229  	updReq := &api.UpdateTaskStatusRequest{
  1230  		Updates: []*api.UpdateTaskStatusRequest_TaskStatusUpdate{
  1231  			{
  1232  				TaskID: testTask1.ID,
  1233  				Status: &testTask1.Status,
  1234  			},
  1235  			{
  1236  				TaskID: testTask2.ID,
  1237  				Status: &testTask2.Status,
  1238  			},
  1239  			{
  1240  				TaskID: testTask4.ID,
  1241  				Status: &testTask4.Status,
  1242  			},
  1243  		},
  1244  	}
  1245  
  1246  	{
  1247  		// without correct SessionID should fail
  1248  		resp, err := gd.Clients[0].UpdateTaskStatus(context.Background(), updReq)
  1249  		assert.Nil(t, resp)
  1250  		assert.Error(t, err)
  1251  		assert.Equal(t, testutils.ErrorCode(err), codes.InvalidArgument)
  1252  	}
  1253  
  1254  	updReq.SessionID = expectedSessionID
  1255  	_, err = gd.Clients[0].UpdateTaskStatus(context.Background(), updReq)
  1256  	assert.NoError(t, err)
  1257  
  1258  	{
  1259  		// updating a task not assigned to us should fail
  1260  		updReq.Updates = []*api.UpdateTaskStatusRequest_TaskStatusUpdate{
  1261  			{
  1262  				TaskID: testTask3.ID,
  1263  				Status: &testTask3.Status,
  1264  			},
  1265  		}
  1266  
  1267  		resp, err := gd.Clients[0].UpdateTaskStatus(context.Background(), updReq)
  1268  		assert.Nil(t, resp)
  1269  		assert.Error(t, err)
  1270  		assert.Equal(t, testutils.ErrorCode(err), codes.PermissionDenied)
  1271  	}
  1272  
  1273  	gd.dispatcherServer.processUpdates(context.Background())
  1274  
  1275  	gd.Store.View(func(readTx store.ReadTx) {
  1276  		storeTask1 := store.GetTask(readTx, testTask1.ID)
  1277  		assert.NotNil(t, storeTask1)
  1278  		storeTask2 := store.GetTask(readTx, testTask2.ID)
  1279  		assert.NotNil(t, storeTask2)
  1280  		assert.Equal(t, storeTask1.Status.State, api.TaskStateAssigned)
  1281  		assert.Equal(t, storeTask2.Status.State, api.TaskStateAssigned)
  1282  
  1283  		storeTask3 := store.GetTask(readTx, testTask3.ID)
  1284  		assert.NotNil(t, storeTask3)
  1285  		assert.Equal(t, storeTask3.Status.State, api.TaskStateNew)
  1286  
  1287  		// The update to task4's state should be ignored because it
  1288  		// would have moved backwards.
  1289  		storeTask4 := store.GetTask(readTx, testTask4.ID)
  1290  		assert.NotNil(t, storeTask4)
  1291  		assert.Equal(t, storeTask4.Status.State, api.TaskStateShutdown)
  1292  	})
  1293  
  1294  }
  1295  
  1296  func TestTaskUpdateNoCert(t *testing.T) {
  1297  	gd := startDispatcher(t, DefaultConfig())
  1298  	defer gd.Close()
  1299  
  1300  	testTask1 := &api.Task{
  1301  		ID: "testTask1",
  1302  	}
  1303  	err := gd.Store.Update(func(tx store.Tx) error {
  1304  		assert.NoError(t, store.CreateTask(tx, testTask1))
  1305  		return nil
  1306  	})
  1307  	assert.NoError(t, err)
  1308  
  1309  	testTask1.Status = api.TaskStatus{State: api.TaskStateAssigned}
  1310  	updReq := &api.UpdateTaskStatusRequest{
  1311  		Updates: []*api.UpdateTaskStatusRequest_TaskStatusUpdate{
  1312  			{
  1313  				TaskID: testTask1.ID,
  1314  				Status: &testTask1.Status,
  1315  			},
  1316  		},
  1317  	}
  1318  	// without correct SessionID should fail
  1319  	resp, err := gd.Clients[2].UpdateTaskStatus(context.Background(), updReq)
  1320  	assert.Nil(t, resp)
  1321  	assert.Error(t, err)
  1322  	assert.EqualError(t, err, "rpc error: code = PermissionDenied desc = Permission denied: unauthorized peer role: rpc error: code = PermissionDenied desc = no client certificates in request")
  1323  }
  1324  
  1325  func TestSession(t *testing.T) {
  1326  	gd := startDispatcher(t, DefaultConfig())
  1327  	defer gd.Close()
  1328  
  1329  	stream, err := gd.Clients[0].Session(context.Background(), &api.SessionRequest{})
  1330  	assert.NoError(t, err)
  1331  	stream.CloseSend()
  1332  	resp, err := stream.Recv()
  1333  	assert.NoError(t, err)
  1334  	assert.NotEmpty(t, resp.SessionID)
  1335  	assert.Equal(t, 1, len(resp.Managers))
  1336  }
  1337  
  1338  func TestSessionNoCert(t *testing.T) {
  1339  	gd := startDispatcher(t, DefaultConfig())
  1340  	defer gd.Close()
  1341  
  1342  	stream, err := gd.Clients[2].Session(context.Background(), &api.SessionRequest{})
  1343  	assert.NoError(t, err)
  1344  	msg, err := stream.Recv()
  1345  	assert.Nil(t, msg)
  1346  	assert.EqualError(t, err, "rpc error: code = PermissionDenied desc = Permission denied: unauthorized peer role: rpc error: code = PermissionDenied desc = no client certificates in request")
  1347  }
  1348  
  1349  func getSessionAndNodeID(t *testing.T, c api.DispatcherClient) (string, string) {
  1350  	stream, err := c.Session(context.Background(), &api.SessionRequest{})
  1351  	assert.NoError(t, err)
  1352  	defer stream.CloseSend()
  1353  	resp, err := stream.Recv()
  1354  	assert.NoError(t, err)
  1355  	assert.NotEmpty(t, resp.SessionID)
  1356  	return resp.SessionID, resp.Node.ID
  1357  }
  1358  
  1359  type idAndAction struct {
  1360  	id     string
  1361  	action api.AssignmentChange_AssignmentAction
  1362  }
  1363  
  1364  func splitChanges(changes []*api.AssignmentChange) (map[idAndAction]*api.Task, map[idAndAction]*api.Config, map[idAndAction]*api.Secret) {
  1365  	tasks := make(map[idAndAction]*api.Task)
  1366  	secrets := make(map[idAndAction]*api.Secret)
  1367  	configs := make(map[idAndAction]*api.Config)
  1368  	for _, change := range changes {
  1369  		task := change.Assignment.GetTask()
  1370  		if task != nil {
  1371  			tasks[idAndAction{id: task.ID, action: change.Action}] = task
  1372  		}
  1373  		secret := change.Assignment.GetSecret()
  1374  		if secret != nil {
  1375  			secrets[idAndAction{id: secret.ID, action: change.Action}] = secret
  1376  		}
  1377  		config := change.Assignment.GetConfig()
  1378  		if config != nil {
  1379  			configs[idAndAction{id: config.ID, action: change.Action}] = config
  1380  		}
  1381  	}
  1382  
  1383  	return tasks, configs, secrets
  1384  }
  1385  
  1386  type changeExpectations struct {
  1387  	tasks   []*api.Task
  1388  	secrets []*api.Secret
  1389  	configs []*api.Config
  1390  	action  api.AssignmentChange_AssignmentAction
  1391  }
  1392  
  1393  // Ensures that the changes contain the following actions for the following tasks/secrets/configs
  1394  func verifyChanges(t *testing.T, changes []*api.AssignmentChange, expectations []changeExpectations) {
  1395  	taskChanges, configChanges, secretChanges := splitChanges(changes)
  1396  
  1397  	var expectedTasks, expectedSecrets, expectedConfigs int
  1398  	for _, c := range expectations {
  1399  		for _, task := range c.tasks {
  1400  			expectedTasks++
  1401  			index := idAndAction{id: task.ID, action: c.action}
  1402  			require.NotNil(t, taskChanges[index], "missing task change %v", index)
  1403  		}
  1404  
  1405  		for _, secret := range c.secrets {
  1406  			expectedSecrets++
  1407  			index := idAndAction{id: secret.ID, action: c.action}
  1408  			require.NotNil(t, secretChanges[index], "missing secret change %v", index)
  1409  		}
  1410  
  1411  		for _, config := range c.configs {
  1412  			expectedConfigs++
  1413  			index := idAndAction{id: config.ID, action: c.action}
  1414  			require.NotNil(t, configChanges[index], "missing config change %v", index)
  1415  		}
  1416  	}
  1417  
  1418  	require.Len(t, taskChanges, expectedTasks)
  1419  	require.Len(t, secretChanges, expectedSecrets)
  1420  	require.Len(t, configChanges, expectedConfigs)
  1421  	require.Len(t, changes, expectedTasks+expectedSecrets+expectedConfigs)
  1422  }
  1423  
  1424  // filter all tasks by task state, which is given by a function because it's hard to take a range of constants
  1425  func filterTasks(tasks []*api.Task, include func(api.TaskState) bool) []*api.Task {
  1426  	var result []*api.Task
  1427  	for _, t := range tasks {
  1428  		if include(t.Status.State) {
  1429  			result = append(result, t)
  1430  		}
  1431  	}
  1432  	return result
  1433  }
  1434  
  1435  func getResourcesFromReferences(gd *grpcDispatcher, resourceRefs []*api.ResourceReference) ([]*api.Secret, []*api.Config) {
  1436  	var (
  1437  		referencedSecrets []*api.Secret
  1438  		referencedConfigs []*api.Config
  1439  	)
  1440  	for _, ref := range resourceRefs {
  1441  		switch ref.ResourceType {
  1442  		case api.ResourceType_SECRET:
  1443  			gd.Store.View(func(readTx store.ReadTx) {
  1444  				referencedSecrets = append(referencedSecrets, store.GetSecret(readTx, ref.ResourceID))
  1445  			})
  1446  		case api.ResourceType_CONFIG:
  1447  			gd.Store.View(func(readTx store.ReadTx) {
  1448  				referencedConfigs = append(referencedConfigs, store.GetConfig(readTx, ref.ResourceID))
  1449  			})
  1450  		}
  1451  	}
  1452  	return referencedSecrets, referencedConfigs
  1453  }
  1454  
  1455  // filters all dependencies (secrets, configs); dependencies should be in `inTasks`, but not be in `notInTasks``
  1456  func filterDependencies(secrets []*api.Secret, configs []*api.Config, inTasks, notInTasks []*api.Task) ([]*api.Secret, []*api.Config) {
  1457  	var (
  1458  		wantSecrets, wantConfigs = make(map[string]struct{}), make(map[string]struct{})
  1459  		filteredSecrets          []*api.Secret
  1460  		filteredConfigs          []*api.Config
  1461  	)
  1462  	for _, t := range inTasks {
  1463  		for _, s := range t.Spec.GetContainer().Secrets {
  1464  			wantSecrets[s.SecretID] = struct{}{}
  1465  		}
  1466  		for _, s := range t.Spec.GetContainer().Configs {
  1467  			wantConfigs[s.ConfigID] = struct{}{}
  1468  		}
  1469  		for _, ref := range t.Spec.ResourceReferences {
  1470  			switch ref.ResourceType {
  1471  			case api.ResourceType_SECRET:
  1472  				wantSecrets[ref.ResourceID] = struct{}{}
  1473  			case api.ResourceType_CONFIG:
  1474  				wantConfigs[ref.ResourceID] = struct{}{}
  1475  			}
  1476  		}
  1477  	}
  1478  	for _, t := range notInTasks {
  1479  		for _, s := range t.Spec.GetContainer().Secrets {
  1480  			delete(wantSecrets, s.SecretID)
  1481  		}
  1482  		for _, s := range t.Spec.GetContainer().Configs {
  1483  			delete(wantConfigs, s.ConfigID)
  1484  		}
  1485  		for _, ref := range t.Spec.ResourceReferences {
  1486  			switch ref.ResourceType {
  1487  			case api.ResourceType_SECRET:
  1488  				delete(wantSecrets, ref.ResourceID)
  1489  			case api.ResourceType_CONFIG:
  1490  				delete(wantConfigs, ref.ResourceID)
  1491  			}
  1492  		}
  1493  	}
  1494  	for _, s := range secrets {
  1495  		if _, ok := wantSecrets[s.ID]; ok {
  1496  			filteredSecrets = append(filteredSecrets, s)
  1497  		}
  1498  	}
  1499  	for _, c := range configs {
  1500  		if _, ok := wantConfigs[c.ID]; ok {
  1501  			filteredConfigs = append(filteredConfigs, c)
  1502  		}
  1503  	}
  1504  	return uniquifySecrets(filteredSecrets), uniquifyConfigs(filteredConfigs)
  1505  }
  1506  
  1507  func uniquifySecrets(secrets []*api.Secret) []*api.Secret {
  1508  	uniqueSecrets := make(map[string]struct{})
  1509  	var finalSecrets []*api.Secret
  1510  	for _, secret := range secrets {
  1511  		if _, ok := uniqueSecrets[secret.ID]; !ok {
  1512  			uniqueSecrets[secret.ID] = struct{}{}
  1513  			finalSecrets = append(finalSecrets, secret)
  1514  		}
  1515  	}
  1516  	return finalSecrets
  1517  }
  1518  
  1519  func uniquifyConfigs(configs []*api.Config) []*api.Config {
  1520  	uniqueConfigs := make(map[string]struct{})
  1521  	var finalConfigs []*api.Config
  1522  	for _, config := range configs {
  1523  		if _, ok := uniqueConfigs[config.ID]; !ok {
  1524  			uniqueConfigs[config.ID] = struct{}{}
  1525  			finalConfigs = append(finalConfigs, config)
  1526  		}
  1527  	}
  1528  	return finalConfigs
  1529  }
  1530  
  1531  type taskGeneratorFunc func(t *testing.T, nodeID string) ([]*api.Secret, []*api.Config, []*api.ResourceReference, []*api.Task)
  1532  
  1533  // Creates 1 task for every possible task state, so there are 12 tasks, ID=0-11 inclusive.
  1534  // Creates 1 secret and 1 config for every single task state + 1, so there are 13 secrets, 13 configs, ID=0-12 inclusive
  1535  // Creates 1 secret and 1 config per task by resource reference so there are an additional of each eventually created
  1536  // For each task, the dependencies assigned to it are: secret, secret12, config, config12, resourceRefSecret, resourceRefConfig
  1537  func makeTasksAndDependenciesWithResourceReferences(t *testing.T, nodeID string) ([]*api.Secret, []*api.Config, []*api.ResourceReference, []*api.Task) {
  1538  	var (
  1539  		secrets      []*api.Secret
  1540  		configs      []*api.Config
  1541  		resourceRefs []*api.ResourceReference
  1542  		tasks        []*api.Task
  1543  	)
  1544  	for i := 0; i <= len(taskStatesInOrder); i++ {
  1545  		secrets = append(secrets, mockNumberedSecret(i))
  1546  		configs = append(configs, mockNumberedConfig(i))
  1547  
  1548  		resourceRefs = append(resourceRefs, &api.ResourceReference{
  1549  			ResourceID:   fmt.Sprintf("IDresourceRefSecret%d", i),
  1550  			ResourceType: api.ResourceType_SECRET,
  1551  		}, &api.ResourceReference{
  1552  			ResourceID:   fmt.Sprintf("IDresourceRefConfig%d", i),
  1553  			ResourceType: api.ResourceType_CONFIG,
  1554  		})
  1555  	}
  1556  
  1557  	for i, taskState := range taskStatesInOrder {
  1558  		spec := taskSpecFromDependencies(secrets[i], secrets[len(secrets)-1], configs[i], configs[len(configs)-1], resourceRefs[2*i], resourceRefs[2*i+1])
  1559  		tasks = append(tasks, mockNumberedReadyTask(i, nodeID, taskState, spec))
  1560  	}
  1561  	return secrets, configs, resourceRefs, tasks
  1562  }
  1563  
  1564  // Creates 1 task for every possible task state, so there are 12 tasks, ID=0-11 inclusive.
  1565  // Creates 1 secret and 1 config for every single task state + 1, so there are 13 secrets, 13 configs, ID=0-12 inclusive
  1566  // For each task, the dependencies assigned to it are: secret<i>, secret12, config<i>, config12.
  1567  // There are no ResourceReferences in these TaskSpecs
  1568  func makeTasksAndDependenciesNoResourceReferences(t *testing.T, nodeID string) ([]*api.Secret, []*api.Config, []*api.ResourceReference, []*api.Task) {
  1569  	var (
  1570  		secrets      []*api.Secret
  1571  		configs      []*api.Config
  1572  		resourceRefs []*api.ResourceReference
  1573  		tasks        []*api.Task
  1574  	)
  1575  	for i := 0; i <= len(taskStatesInOrder); i++ {
  1576  		secrets = append(secrets, mockNumberedSecret(i))
  1577  		configs = append(configs, mockNumberedConfig(i))
  1578  	}
  1579  	for i, taskState := range taskStatesInOrder {
  1580  		spec := taskSpecFromDependencies(secrets[i], secrets[len(secrets)-1], configs[i], configs[len(configs)-1])
  1581  		tasks = append(tasks, mockNumberedReadyTask(i, nodeID, taskState, spec))
  1582  	}
  1583  	return secrets, configs, resourceRefs, tasks
  1584  }
  1585  
  1586  // Creates 1 secret and 1 config per task by resource reference
  1587  // For each task, the dependencies assigned to it are: resourceRefSecret<i>, resourceRefConfig<i>,.
  1588  func makeTasksAndDependenciesOnlyResourceReferences(t *testing.T, nodeID string) ([]*api.Secret, []*api.Config, []*api.ResourceReference, []*api.Task) {
  1589  	var (
  1590  		secrets      []*api.Secret
  1591  		configs      []*api.Config
  1592  		resourceRefs []*api.ResourceReference
  1593  		tasks        []*api.Task
  1594  	)
  1595  	for i := 0; i <= len(taskStatesInOrder); i++ {
  1596  		resourceRefs = append(resourceRefs, &api.ResourceReference{
  1597  			ResourceID:   fmt.Sprintf("IDresourceRefSecret%d", i),
  1598  			ResourceType: api.ResourceType_SECRET,
  1599  		}, &api.ResourceReference{
  1600  			ResourceID:   fmt.Sprintf("IDresourceRefConfig%d", i),
  1601  			ResourceType: api.ResourceType_CONFIG,
  1602  		})
  1603  	}
  1604  	for i, taskState := range taskStatesInOrder {
  1605  		spec := taskSpecFromDependencies(resourceRefs[2*i], resourceRefs[2*i+1])
  1606  		tasks = append(tasks, mockNumberedReadyTask(i, nodeID, taskState, spec))
  1607  	}
  1608  	return secrets, configs, resourceRefs, tasks
  1609  }
  1610  
  1611  // Creates 1 task for every possible task state, so there are 12 tasks, ID=0-11 inclusive.
  1612  // Creates 1 secret and 1 config for every single task state + 1, so there are 13 secrets, 13 configs, ID=0-12 inclusive
  1613  // Creates 1 secret and 1 config per task by resource reference, however they point to existing ID=0-12 secrets and configs so they are not created
  1614  // For each task, the dependencies assigned to it are: secret<i>, secret12, config<i>, config12.
  1615  func makeTasksAndDependenciesWithRedundantReferences(t *testing.T, nodeID string) ([]*api.Secret, []*api.Config, []*api.ResourceReference, []*api.Task) {
  1616  	var (
  1617  		secrets      []*api.Secret
  1618  		configs      []*api.Config
  1619  		resourceRefs []*api.ResourceReference
  1620  		tasks        []*api.Task
  1621  	)
  1622  	for i := 0; i <= len(taskStatesInOrder); i++ {
  1623  		secrets = append(secrets, mockNumberedSecret(i))
  1624  		configs = append(configs, mockNumberedConfig(i))
  1625  
  1626  		// Note that the IDs here will match the original secret and config reference IDs
  1627  		resourceRefs = append(resourceRefs, &api.ResourceReference{
  1628  			ResourceID:   fmt.Sprintf("IDsecret%d", i),
  1629  			ResourceType: api.ResourceType_SECRET,
  1630  		}, &api.ResourceReference{
  1631  			ResourceID:   fmt.Sprintf("IDconfig%d", i),
  1632  			ResourceType: api.ResourceType_CONFIG,
  1633  		})
  1634  	}
  1635  
  1636  	for i, taskState := range taskStatesInOrder {
  1637  		spec := taskSpecFromDependencies(secrets[i], secrets[len(secrets)-1], configs[i], configs[len(configs)-1], resourceRefs[2*i], resourceRefs[2*i+1])
  1638  		tasks = append(tasks, mockNumberedReadyTask(i, nodeID, taskState, spec))
  1639  	}
  1640  	return secrets, configs, resourceRefs, tasks
  1641  }
  1642  
  1643  func taskSpecFromDependencies(dependencies ...interface{}) api.TaskSpec {
  1644  	var secretRefs []*api.SecretReference
  1645  	var configRefs []*api.ConfigReference
  1646  	var resourceRefs []api.ResourceReference
  1647  	for _, d := range dependencies {
  1648  		switch v := d.(type) {
  1649  		case *api.Secret:
  1650  			secretRefs = append(secretRefs, &api.SecretReference{
  1651  				SecretName: v.Spec.Annotations.Name,
  1652  				SecretID:   v.ID,
  1653  				Target: &api.SecretReference_File{
  1654  					File: &api.FileTarget{
  1655  						Name: "target.txt",
  1656  						UID:  "0",
  1657  						GID:  "0",
  1658  						Mode: 0666,
  1659  					},
  1660  				},
  1661  			})
  1662  		case *api.Config:
  1663  			configRefs = append(configRefs, &api.ConfigReference{
  1664  				ConfigName: v.Spec.Annotations.Name,
  1665  				ConfigID:   v.ID,
  1666  				Target: &api.ConfigReference_File{
  1667  					File: &api.FileTarget{
  1668  						Name: "target.txt",
  1669  						UID:  "0",
  1670  						GID:  "0",
  1671  						Mode: 0666,
  1672  					},
  1673  				},
  1674  			})
  1675  		case *api.ResourceReference:
  1676  			resourceRefs = append(resourceRefs, api.ResourceReference{
  1677  				ResourceID:   v.ResourceID,
  1678  				ResourceType: v.ResourceType,
  1679  			})
  1680  		default:
  1681  			panic("unexpected dependency type")
  1682  		}
  1683  	}
  1684  	return api.TaskSpec{
  1685  		ResourceReferences: resourceRefs,
  1686  		Runtime: &api.TaskSpec_Container{
  1687  			Container: &api.ContainerSpec{
  1688  				Secrets: secretRefs,
  1689  				Configs: configRefs,
  1690  			},
  1691  		},
  1692  	}
  1693  }
  1694  
  1695  var taskStatesInOrder = []api.TaskState{
  1696  	api.TaskStateNew,
  1697  	api.TaskStatePending,
  1698  	api.TaskStateAssigned,
  1699  	api.TaskStateAccepted,
  1700  	api.TaskStatePreparing,
  1701  	api.TaskStateReady,
  1702  	api.TaskStateStarting,
  1703  	api.TaskStateRunning,
  1704  	api.TaskStateCompleted,
  1705  	api.TaskStateShutdown,
  1706  	api.TaskStateFailed,
  1707  	api.TaskStateRejected,
  1708  }
  1709  
  1710  // Ensure we test the old Tasks() API for backwards compat
  1711  
  1712  func TestOldTasks(t *testing.T) {
  1713  	t.Parallel()
  1714  
  1715  	gd := startDispatcher(t, DefaultConfig())
  1716  	defer gd.Close()
  1717  
  1718  	var expectedSessionID string
  1719  	var nodeID string
  1720  	{
  1721  		stream, err := gd.Clients[0].Session(context.Background(), &api.SessionRequest{})
  1722  		assert.NoError(t, err)
  1723  		defer stream.CloseSend()
  1724  		resp, err := stream.Recv()
  1725  		assert.NoError(t, err)
  1726  		assert.NotEmpty(t, resp.SessionID)
  1727  		expectedSessionID = resp.SessionID
  1728  		nodeID = resp.Node.ID
  1729  	}
  1730  
  1731  	testTask1 := &api.Task{
  1732  		NodeID:       nodeID,
  1733  		ID:           "testTask1",
  1734  		Status:       api.TaskStatus{State: api.TaskStateAssigned},
  1735  		DesiredState: api.TaskStateReady,
  1736  	}
  1737  	testTask2 := &api.Task{
  1738  		NodeID:       nodeID,
  1739  		ID:           "testTask2",
  1740  		Status:       api.TaskStatus{State: api.TaskStateAssigned},
  1741  		DesiredState: api.TaskStateReady,
  1742  	}
  1743  
  1744  	{
  1745  		// without correct SessionID should fail
  1746  		stream, err := gd.Clients[0].Tasks(context.Background(), &api.TasksRequest{})
  1747  		assert.NoError(t, err)
  1748  		assert.NotNil(t, stream)
  1749  		resp, err := stream.Recv()
  1750  		assert.Nil(t, resp)
  1751  		assert.Error(t, err)
  1752  		assert.Equal(t, testutils.ErrorCode(err), codes.InvalidArgument)
  1753  	}
  1754  
  1755  	stream, err := gd.Clients[0].Tasks(context.Background(), &api.TasksRequest{SessionID: expectedSessionID})
  1756  	assert.NoError(t, err)
  1757  
  1758  	time.Sleep(100 * time.Millisecond)
  1759  
  1760  	resp, err := stream.Recv()
  1761  	assert.NoError(t, err)
  1762  	// initially no tasks
  1763  	assert.Equal(t, 0, len(resp.Tasks))
  1764  
  1765  	err = gd.Store.Update(func(tx store.Tx) error {
  1766  		assert.NoError(t, store.CreateTask(tx, testTask1))
  1767  		assert.NoError(t, store.CreateTask(tx, testTask2))
  1768  		return nil
  1769  	})
  1770  	assert.NoError(t, err)
  1771  
  1772  	resp, err = stream.Recv()
  1773  	assert.NoError(t, err)
  1774  	assert.Equal(t, len(resp.Tasks), 2)
  1775  	assert.True(t, resp.Tasks[0].ID == "testTask1" && resp.Tasks[1].ID == "testTask2" || resp.Tasks[0].ID == "testTask2" && resp.Tasks[1].ID == "testTask1")
  1776  
  1777  	assert.NoError(t, gd.Store.Update(func(tx store.Tx) error {
  1778  		task := store.GetTask(tx, testTask1.ID)
  1779  		if task == nil {
  1780  			return errors.New("no task")
  1781  		}
  1782  		task.NodeID = nodeID
  1783  		task.Status = api.TaskStatus{State: api.TaskStateAssigned}
  1784  		task.DesiredState = api.TaskStateRunning
  1785  		return store.UpdateTask(tx, task)
  1786  	}))
  1787  
  1788  	resp, err = stream.Recv()
  1789  	assert.NoError(t, err)
  1790  	assert.Equal(t, len(resp.Tasks), 2)
  1791  	for _, task := range resp.Tasks {
  1792  		if task.ID == "testTask1" {
  1793  			assert.Equal(t, task.DesiredState, api.TaskStateRunning)
  1794  		}
  1795  	}
  1796  
  1797  	err = gd.Store.Update(func(tx store.Tx) error {
  1798  		assert.NoError(t, store.DeleteTask(tx, testTask1.ID))
  1799  		assert.NoError(t, store.DeleteTask(tx, testTask2.ID))
  1800  		return nil
  1801  	})
  1802  	assert.NoError(t, err)
  1803  
  1804  	resp, err = stream.Recv()
  1805  	assert.NoError(t, err)
  1806  	assert.Equal(t, len(resp.Tasks), 0)
  1807  }
  1808  
  1809  func TestOldTasksStatusChange(t *testing.T) {
  1810  	t.Parallel()
  1811  
  1812  	gd := startDispatcher(t, DefaultConfig())
  1813  	defer gd.Close()
  1814  
  1815  	var expectedSessionID string
  1816  	var nodeID string
  1817  	{
  1818  		stream, err := gd.Clients[0].Session(context.Background(), &api.SessionRequest{})
  1819  		assert.NoError(t, err)
  1820  		defer stream.CloseSend()
  1821  		resp, err := stream.Recv()
  1822  		assert.NoError(t, err)
  1823  		assert.NotEmpty(t, resp.SessionID)
  1824  		expectedSessionID = resp.SessionID
  1825  		nodeID = resp.Node.ID
  1826  	}
  1827  
  1828  	testTask1 := &api.Task{
  1829  		NodeID:       nodeID,
  1830  		ID:           "testTask1",
  1831  		Status:       api.TaskStatus{State: api.TaskStateAssigned},
  1832  		DesiredState: api.TaskStateReady,
  1833  	}
  1834  	testTask2 := &api.Task{
  1835  		NodeID:       nodeID,
  1836  		ID:           "testTask2",
  1837  		Status:       api.TaskStatus{State: api.TaskStateAssigned},
  1838  		DesiredState: api.TaskStateReady,
  1839  	}
  1840  
  1841  	{
  1842  		// without correct SessionID should fail
  1843  		stream, err := gd.Clients[0].Tasks(context.Background(), &api.TasksRequest{})
  1844  		assert.NoError(t, err)
  1845  		assert.NotNil(t, stream)
  1846  		resp, err := stream.Recv()
  1847  		assert.Nil(t, resp)
  1848  		assert.Error(t, err)
  1849  		assert.Equal(t, testutils.ErrorCode(err), codes.InvalidArgument)
  1850  	}
  1851  
  1852  	stream, err := gd.Clients[0].Tasks(context.Background(), &api.TasksRequest{SessionID: expectedSessionID})
  1853  	assert.NoError(t, err)
  1854  
  1855  	time.Sleep(100 * time.Millisecond)
  1856  
  1857  	resp, err := stream.Recv()
  1858  	assert.NoError(t, err)
  1859  	// initially no tasks
  1860  	assert.Equal(t, 0, len(resp.Tasks))
  1861  
  1862  	err = gd.Store.Update(func(tx store.Tx) error {
  1863  		assert.NoError(t, store.CreateTask(tx, testTask1))
  1864  		assert.NoError(t, store.CreateTask(tx, testTask2))
  1865  		return nil
  1866  	})
  1867  	assert.NoError(t, err)
  1868  
  1869  	resp, err = stream.Recv()
  1870  	assert.NoError(t, err)
  1871  	assert.Equal(t, len(resp.Tasks), 2)
  1872  	assert.True(t, resp.Tasks[0].ID == "testTask1" && resp.Tasks[1].ID == "testTask2" || resp.Tasks[0].ID == "testTask2" && resp.Tasks[1].ID == "testTask1")
  1873  
  1874  	assert.NoError(t, gd.Store.Update(func(tx store.Tx) error {
  1875  		task := store.GetTask(tx, testTask1.ID)
  1876  		if task == nil {
  1877  			return errors.New("no task")
  1878  		}
  1879  		task.NodeID = nodeID
  1880  		// only Status is changed for task1
  1881  		task.Status = api.TaskStatus{State: api.TaskStateFailed, Err: "1234"}
  1882  		task.DesiredState = api.TaskStateReady
  1883  		return store.UpdateTask(tx, task)
  1884  	}))
  1885  
  1886  	// dispatcher shouldn't send snapshot for this update
  1887  	recvChan := make(chan struct{})
  1888  	go func() {
  1889  		_, _ = stream.Recv()
  1890  		recvChan <- struct{}{}
  1891  	}()
  1892  
  1893  	select {
  1894  	case <-recvChan:
  1895  		assert.Fail(t, "task.Status update should not trigger dispatcher update")
  1896  	case <-time.After(250 * time.Millisecond):
  1897  	}
  1898  }
  1899  
  1900  func TestOldTasksBatch(t *testing.T) {
  1901  	gd := startDispatcher(t, DefaultConfig())
  1902  	defer gd.Close()
  1903  
  1904  	var expectedSessionID string
  1905  	var nodeID string
  1906  	{
  1907  		stream, err := gd.Clients[0].Session(context.Background(), &api.SessionRequest{})
  1908  		assert.NoError(t, err)
  1909  		defer stream.CloseSend()
  1910  		resp, err := stream.Recv()
  1911  		assert.NoError(t, err)
  1912  		assert.NotEmpty(t, resp.SessionID)
  1913  		expectedSessionID = resp.SessionID
  1914  		nodeID = resp.Node.ID
  1915  	}
  1916  
  1917  	testTask1 := &api.Task{
  1918  		NodeID: nodeID,
  1919  		ID:     "testTask1",
  1920  		Status: api.TaskStatus{State: api.TaskStateAssigned},
  1921  	}
  1922  	testTask2 := &api.Task{
  1923  		NodeID: nodeID,
  1924  		ID:     "testTask2",
  1925  		Status: api.TaskStatus{State: api.TaskStateAssigned},
  1926  	}
  1927  
  1928  	stream, err := gd.Clients[0].Tasks(context.Background(), &api.TasksRequest{SessionID: expectedSessionID})
  1929  	assert.NoError(t, err)
  1930  
  1931  	resp, err := stream.Recv()
  1932  	assert.NoError(t, err)
  1933  	// initially no tasks
  1934  	assert.Equal(t, 0, len(resp.Tasks))
  1935  
  1936  	err = gd.Store.Update(func(tx store.Tx) error {
  1937  		assert.NoError(t, store.CreateTask(tx, testTask1))
  1938  		assert.NoError(t, store.CreateTask(tx, testTask2))
  1939  		return nil
  1940  	})
  1941  	assert.NoError(t, err)
  1942  
  1943  	err = gd.Store.Update(func(tx store.Tx) error {
  1944  		assert.NoError(t, store.DeleteTask(tx, testTask1.ID))
  1945  		assert.NoError(t, store.DeleteTask(tx, testTask2.ID))
  1946  		return nil
  1947  	})
  1948  	assert.NoError(t, err)
  1949  
  1950  	resp, err = stream.Recv()
  1951  	assert.NoError(t, err)
  1952  	// all tasks have been deleted
  1953  	assert.Equal(t, len(resp.Tasks), 0)
  1954  }
  1955  
  1956  func TestOldTasksNoCert(t *testing.T) {
  1957  	gd := startDispatcher(t, DefaultConfig())
  1958  	defer gd.Close()
  1959  
  1960  	stream, err := gd.Clients[2].Tasks(context.Background(), &api.TasksRequest{})
  1961  	assert.NoError(t, err)
  1962  	assert.NotNil(t, stream)
  1963  	resp, err := stream.Recv()
  1964  	assert.Nil(t, resp)
  1965  	assert.EqualError(t, err, "rpc error: code = PermissionDenied desc = Permission denied: unauthorized peer role: rpc error: code = PermissionDenied desc = no client certificates in request")
  1966  }
  1967  
  1968  func TestClusterUpdatesSendMessages(t *testing.T) {
  1969  	cfg := DefaultConfig()
  1970  	cfg.RateLimitPeriod = 0
  1971  	gd := startDispatcher(t, cfg)
  1972  	defer gd.Close()
  1973  
  1974  	stream, err := gd.Clients[0].Session(context.Background(), &api.SessionRequest{})
  1975  	require.NoError(t, err)
  1976  	defer stream.CloseSend()
  1977  
  1978  	var msg *api.SessionMessage
  1979  	{
  1980  		msg, err = stream.Recv()
  1981  		require.NoError(t, err)
  1982  		require.NotEmpty(t, msg.SessionID)
  1983  		require.NotNil(t, msg.Node)
  1984  		require.Len(t, msg.Managers, 1)
  1985  		require.Empty(t, msg.NetworkBootstrapKeys)
  1986  		require.Equal(t, gd.testCA.RootCA.Certs, msg.RootCA)
  1987  	}
  1988  
  1989  	// changing the network bootstrap keys results in a new message with updated keys
  1990  	expected := msg.Copy()
  1991  	expected.NetworkBootstrapKeys = []*api.EncryptionKey{
  1992  		{Key: []byte("network key1")},
  1993  		{Key: []byte("network key2")},
  1994  	}
  1995  	require.NoError(t, gd.Store.Update(func(tx store.Tx) error {
  1996  		cluster := store.GetCluster(tx, gd.testCA.Organization)
  1997  		if cluster == nil {
  1998  			return errors.New("no cluster")
  1999  		}
  2000  		cluster.NetworkBootstrapKeys = expected.NetworkBootstrapKeys
  2001  		return store.UpdateCluster(tx, cluster)
  2002  	}))
  2003  	time.Sleep(100 * time.Millisecond)
  2004  	{
  2005  		msg, err = stream.Recv()
  2006  		require.NoError(t, err)
  2007  		require.Equal(t, expected, msg)
  2008  	}
  2009  
  2010  	// changing the peers results in a new message with updated managers
  2011  	gd.testCluster.addMember("1.1.1.1")
  2012  	time.Sleep(100 * time.Millisecond)
  2013  	{
  2014  		msg, err = stream.Recv()
  2015  		require.NoError(t, err)
  2016  		require.Len(t, msg.Managers, 2)
  2017  		expected.Managers = msg.Managers
  2018  		require.Equal(t, expected, msg)
  2019  	}
  2020  
  2021  	// changing the rootCA cert and has in the cluster results in a new message with an updated cert
  2022  	expected = msg.Copy()
  2023  	expected.RootCA = cautils.ECDSA256SHA256Cert
  2024  	require.NoError(t, gd.Store.Update(func(tx store.Tx) error {
  2025  		cluster := store.GetCluster(tx, gd.testCA.Organization)
  2026  		if cluster == nil {
  2027  			return errors.New("no cluster")
  2028  		}
  2029  		cluster.RootCA.CACert = cautils.ECDSA256SHA256Cert
  2030  		cluster.RootCA.CACertHash = digest.FromBytes(cautils.ECDSA256SHA256Cert).String()
  2031  		return store.UpdateCluster(tx, cluster)
  2032  	}))
  2033  	time.Sleep(100 * time.Millisecond)
  2034  	{
  2035  		msg, err = stream.Recv()
  2036  		require.NoError(t, err)
  2037  		require.Equal(t, expected, msg)
  2038  	}
  2039  }
  2040  
  2041  // mockPluginGetter enables mocking the server plugin getter with customized plugins
  2042  type mockPluginGetter struct {
  2043  	addr   string
  2044  	server *httptest.Server
  2045  	name   string
  2046  	plugin plugingetter.CompatPlugin
  2047  }
  2048  
  2049  // SetupPlugin setup a new plugin - the same plugin wil always return in all calls
  2050  func (m *mockPluginGetter) SetupPlugin(name string, handler http.Handler) error {
  2051  	m.server = httptest.NewServer(handler)
  2052  	client, err := plugins.NewClient(m.server.URL, nil)
  2053  	if err != nil {
  2054  		return err
  2055  	}
  2056  	m.plugin = NewMockPlugin(m.name, client)
  2057  	m.name = name
  2058  	return nil
  2059  }
  2060  
  2061  // Close closes the mock plugin getter
  2062  func (m *mockPluginGetter) Close() {
  2063  	if m.server == nil {
  2064  		return
  2065  	}
  2066  	m.server.Close()
  2067  }
  2068  
  2069  func (m *mockPluginGetter) Get(name, capability string, mode int) (plugingetter.CompatPlugin, error) {
  2070  	if name != m.name {
  2071  		return nil, fmt.Errorf("plugin with name %s not defined", name)
  2072  	}
  2073  	return m.plugin, nil
  2074  }
  2075  func (m *mockPluginGetter) GetAllByCap(capability string) ([]plugingetter.CompatPlugin, error) {
  2076  	return nil, nil
  2077  }
  2078  func (m *mockPluginGetter) GetAllManagedPluginsByCap(capability string) []plugingetter.CompatPlugin {
  2079  	return nil
  2080  }
  2081  func (m *mockPluginGetter) Handle(capability string, callback func(string, *plugins.Client)) {
  2082  }
  2083  
  2084  // MockPlugin mocks a v2 docker plugin
  2085  type MockPlugin struct {
  2086  	client *plugins.Client
  2087  	name   string
  2088  }
  2089  
  2090  // NewMockPlugin creates a new v2 plugin fake (returns the specified client and name for all calls)
  2091  func NewMockPlugin(name string, client *plugins.Client) *MockPlugin {
  2092  	return &MockPlugin{name: name, client: client}
  2093  }
  2094  
  2095  func (m *MockPlugin) Client() *plugins.Client {
  2096  	return m.client
  2097  }
  2098  func (m *MockPlugin) Name() string {
  2099  	return m.name
  2100  }
  2101  func (m *MockPlugin) ScopedPath(_ string) string {
  2102  	return ""
  2103  }
  2104  func (m *MockPlugin) BasePath() string {
  2105  	return ""
  2106  
  2107  }
  2108  func (m *MockPlugin) IsV1() bool {
  2109  	return false
  2110  }