Esempio n. 1
0
// RemoveSecret removes the secret referenced by `RemoveSecretRequest.ID`.
// - Returns `InvalidArgument` if `RemoveSecretRequest.ID` is empty.
// - Returns `NotFound` if the a secret named `RemoveSecretRequest.ID` is not found.
// - Returns `SecretInUse` if the secret is currently in use
// - Returns an error if the deletion fails.
func (s *Server) RemoveSecret(ctx context.Context, request *api.RemoveSecretRequest) (*api.RemoveSecretResponse, error) {
	if request.SecretID == "" {
		return nil, grpc.Errorf(codes.InvalidArgument, "secret ID must be provided")
	}

	err := s.store.Update(func(tx store.Tx) error {
		// Check if the secret exists
		secret := store.GetSecret(tx, request.SecretID)
		if secret == nil {
			return grpc.Errorf(codes.NotFound, "could not find secret %s", request.SecretID)
		}

		// Check if any services currently reference this secret, return error if so
		services, err := store.FindServices(tx, store.ByReferencedSecretID(request.SecretID))
		if err != nil {
			return grpc.Errorf(codes.Internal, "could not find services using secret %s: %v", request.SecretID, err)
		}

		if len(services) != 0 {
			serviceNames := make([]string, 0, len(services))
			for _, service := range services {
				serviceNames = append(serviceNames, service.Spec.Annotations.Name)
			}

			secretName := secret.Spec.Annotations.Name
			serviceNameStr := strings.Join(serviceNames, ", ")
			serviceStr := "services"
			if len(serviceNames) == 1 {
				serviceStr = "service"
			}

			return grpc.Errorf(codes.InvalidArgument, "secret '%s' is in use by the following %s: %v", secretName, serviceStr, serviceNameStr)
		}

		return store.DeleteSecret(tx, request.SecretID)
	})
	switch err {
	case store.ErrNotExist:
		return nil, grpc.Errorf(codes.NotFound, "secret %s not found", request.SecretID)
	case nil:
		log.G(ctx).WithFields(logrus.Fields{
			"secret.ID": request.SecretID,
			"method":    "RemoveSecret",
		}).Debugf("secret removed")

		return &api.RemoveSecretResponse{}, nil
	default:
		return nil, err
	}
}
Esempio n. 2
0
// RemoveSecret removes the secret referenced by `RemoveSecretRequest.ID`.
// - Returns `InvalidArgument` if `RemoveSecretRequest.ID` is empty.
// - Returns `NotFound` if the a secret named `RemoveSecretRequest.ID` is not found.
// - Returns an error if the deletion fails.
func (s *Server) RemoveSecret(ctx context.Context, request *api.RemoveSecretRequest) (*api.RemoveSecretResponse, error) {
	if request.SecretID == "" {
		return nil, grpc.Errorf(codes.InvalidArgument, "secret ID must be provided")
	}

	err := s.store.Update(func(tx store.Tx) error {
		return store.DeleteSecret(tx, request.SecretID)
	})
	switch err {
	case store.ErrNotExist:
		return nil, grpc.Errorf(codes.NotFound, "secret %s not found", request.SecretID)
	case nil:
		return &api.RemoveSecretResponse{}, nil
	default:
		return nil, err
	}
}
Esempio n. 3
0
// RemoveSecret removes the secret referenced by `RemoveSecretRequest.ID`.
// - Returns `InvalidArgument` if `RemoveSecretRequest.ID` is empty.
// - Returns `NotFound` if the a secret named `RemoveSecretRequest.ID` is not found.
// - Returns an error if the deletion fails.
func (s *Server) RemoveSecret(ctx context.Context, request *api.RemoveSecretRequest) (*api.RemoveSecretResponse, error) {
	if request.SecretID == "" {
		return nil, grpc.Errorf(codes.InvalidArgument, "secret ID must be provided")
	}

	err := s.store.Update(func(tx store.Tx) error {
		return store.DeleteSecret(tx, request.SecretID)
	})
	switch err {
	case store.ErrNotExist:
		return nil, grpc.Errorf(codes.NotFound, "secret %s not found", request.SecretID)
	case nil:
		log.G(ctx).WithFields(logrus.Fields{
			"secret.ID": request.SecretID,
			"method":    "RemoveSecret",
		}).Debugf("secret removed")

		return &api.RemoveSecretResponse{}, nil
	default:
		return nil, err
	}
}
Esempio n. 4
0
// If a secret is updated or deleted, even if it's for an existing task, no changes will be sent down
func TestAssignmentsSecretUpdateAndDeletion(t *testing.T) {
	t.Parallel()

	gd, err := startDispatcher(DefaultConfig())
	assert.NoError(t, err)
	defer gd.Close()

	expectedSessionID, nodeID := getSessionAndNodeID(t, gd.Clients[0])

	// create the relevant secrets and tasks
	secrets, tasks := makeTasksAndSecrets(t, nodeID)
	err = gd.Store.Update(func(tx store.Tx) error {
		for _, secret := range secrets[:len(secrets)-1] {
			assert.NoError(t, store.CreateSecret(tx, secret))
		}
		for _, task := range tasks {
			assert.NoError(t, store.CreateTask(tx, task))
		}
		return nil
	})
	assert.NoError(t, err)

	stream, err := gd.Clients[0].Assignments(context.Background(), &api.AssignmentsRequest{SessionID: expectedSessionID})
	assert.NoError(t, err)
	defer stream.CloseSend()

	time.Sleep(100 * time.Millisecond)

	// check the initial task and secret stream
	resp, err := stream.Recv()
	assert.NoError(t, err)

	// FIXME(aaronl): This is hard to maintain.
	assert.Equal(t, 16, len(resp.Changes))
	taskChanges, secretChanges := collectTasksAndSecrets(resp.Changes)
	assert.Len(t, taskChanges, 10) // 10 types of task states >= assigned, 2 types < assigned
	for _, task := range tasks[2:] {
		assert.NotNil(t, taskChanges[idAndAction{id: task.ID, action: api.AssignmentChange_AssignmentActionUpdate}])
	}
	assert.Len(t, secretChanges, 6) // 6 types of task states between assigned and running inclusive
	for _, secret := range secrets[2:8] {
		assert.NotNil(t, secretChanges[idAndAction{id: secret.ID, action: api.AssignmentChange_AssignmentActionUpdate}])
	}

	// updating secrets, used by tasks or not, do not cause any changes
	err = gd.Store.Update(func(tx store.Tx) error {
		for _, secret := range secrets[:len(secrets)-2] {
			secret.Spec.Data = []byte("new secret data")
			assert.NoError(t, store.UpdateSecret(tx, secret))
		}
		return nil
	})
	assert.NoError(t, err)

	recvChan := make(chan struct{})
	go func() {
		_, _ = stream.Recv()
		recvChan <- struct{}{}
	}()

	select {
	case <-recvChan:
		assert.Fail(t, "secret update should not trigger dispatcher update")
	case <-time.After(250 * time.Millisecond):
	}

	// deleting secrets, used by tasks or not, do not cause any changes
	err = gd.Store.Update(func(tx store.Tx) error {
		for _, secret := range secrets[:len(secrets)-2] {
			assert.NoError(t, store.DeleteSecret(tx, secret.ID))
		}
		return nil
	})
	assert.NoError(t, err)

	select {
	case <-recvChan:
		assert.Fail(t, "secret delete should not trigger dispatcher update")
	case <-time.After(250 * time.Millisecond):
	}
}