Esempio n. 1
0
// Publisher returns a LogPublisher for the given subscription
// as well as a cancel function that should be called when the log stream
// is completed.
func (a *Agent) Publisher(ctx context.Context, subscriptionID string) (exec.LogPublisher, func(), error) {
	// TODO(stevvooe): The level of coordination here is WAY too much for logs.
	// These should only be best effort and really just buffer until a session is
	// ready. Ideally, they would use a separate connection completely.

	var (
		err       error
		publisher api.LogBroker_PublishLogsClient
	)

	err = a.withSession(ctx, func(session *session) error {
		publisher, err = api.NewLogBrokerClient(session.conn.ClientConn).PublishLogs(ctx)
		return err
	})
	if err != nil {
		return nil, nil, err
	}

	return exec.LogPublisherFunc(func(ctx context.Context, message api.LogMessage) error {
			select {
			case <-ctx.Done():
				publisher.CloseSend()
				return ctx.Err()
			default:
			}

			return publisher.Send(&api.PublishLogsMessage{
				SubscriptionID: subscriptionID,
				Messages:       []api.LogMessage{message},
			})
		}), func() {
			publisher.CloseSend()
		}, nil
}
Esempio n. 2
0
func (tpp *testPublisherProvider) Publisher(ctx context.Context, subscriptionID string) (exec.LogPublisher, func(), error) {
	return exec.LogPublisherFunc(func(ctx context.Context, message api.LogMessage) error {
			log.G(ctx).WithFields(logrus.Fields{
				"subscription": subscriptionID,
				"task.id":      message.Context.TaskID,
				"node.id":      message.Context.NodeID,
				"service.id":   message.Context.ServiceID,
			}).Info(message.Data)
			return nil
		}), func() {
		}, nil
}
// TestControllerFlowIntegration simply runs the Controller flow against a docker
// instance to make sure we don't blow up.
//
// This is great for ad-hoc testing while doing development. We can add more
// verification but it solves the problem of not being able to run tasks
// without a swarm setup.
//
// Run with something like this:
//
//	go test -run TestControllerFlowIntegration -test.docker.addr unix:///var/run/docker.sock
//
func TestControllerFlowIntegration(t *testing.T) {
	if dockerTestAddr == "" {
		t.Skip("specify docker address to run integration")
	}

	ctx := context.Background()
	client, err := engineapi.NewClient(dockerTestAddr, "", nil, nil)
	assert.NoError(t, err)
	assert.NotNil(t, client)

	task := &api.Task{
		ID:        "dockerexec-integration-task-id",
		ServiceID: "dockerexec-integration-service-id",
		NodeID:    "dockerexec-integration-node-id",
		ServiceAnnotations: api.Annotations{
			Name: "dockerexec-integration",
		},
		Spec: api.TaskSpec{
			Runtime: &api.TaskSpec_Container{
				Container: &api.ContainerSpec{
					Command: []string{"sh", "-c", "sleep 5; echo hello; echo stderr >&2"},
					Image:   "alpine",
				},
			},
		},
	}

	var receivedLogs bool
	publisher := exec.LogPublisherFunc(func(ctx context.Context, message api.LogMessage) error {
		receivedLogs = true

		switch message.Stream {
		case api.LogStreamStdout:
			assert.Equal(t, "hello\n", string(message.Data))
		case api.LogStreamStderr:
			assert.Equal(t, "stderr\n", string(message.Data))
		}

		t.Log(message)
		return nil
	})

	ctlr, err := newController(client, task, nil)
	assert.NoError(t, err)
	assert.NotNil(t, ctlr)
	assert.NoError(t, ctlr.Prepare(ctx))
	assert.NoError(t, ctlr.Start(ctx))
	assert.NoError(t, ctlr.(exec.ControllerLogs).Logs(ctx, publisher, api.LogSubscriptionOptions{
		Follow: true,
	}))
	assert.NoError(t, ctlr.Wait(ctx))
	assert.True(t, receivedLogs)
	assert.NoError(t, ctlr.Shutdown(ctx))
	assert.NoError(t, ctlr.Remove(ctx))
	assert.NoError(t, ctlr.Close())

	// NOTE(stevvooe): testify has no clue how to correctly do error equality.
	if err := ctlr.Close(); err != exec.ErrControllerClosed {
		t.Fatalf("expected controller to be closed: %v", err)
	}
}