github.com/cookieai-jar/moby@v17.12.1-ce-rc2+incompatible/api/server/router/swarm/helpers.go (about)

     1  package swarm
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"net/http"
     7  
     8  	"github.com/docker/docker/api/server/httputils"
     9  	basictypes "github.com/docker/docker/api/types"
    10  	"github.com/docker/docker/api/types/backend"
    11  	"golang.org/x/net/context"
    12  )
    13  
    14  // swarmLogs takes an http response, request, and selector, and writes the logs
    15  // specified by the selector to the response
    16  func (sr *swarmRouter) swarmLogs(ctx context.Context, w io.Writer, r *http.Request, selector *backend.LogSelector) error {
    17  	// Args are validated before the stream starts because when it starts we're
    18  	// sending HTTP 200 by writing an empty chunk of data to tell the client that
    19  	// daemon is going to stream. By sending this initial HTTP 200 we can't report
    20  	// any error after the stream starts (i.e. container not found, wrong parameters)
    21  	// with the appropriate status code.
    22  	stdout, stderr := httputils.BoolValue(r, "stdout"), httputils.BoolValue(r, "stderr")
    23  	if !(stdout || stderr) {
    24  		return fmt.Errorf("Bad parameters: you must choose at least one stream")
    25  	}
    26  
    27  	// there is probably a neater way to manufacture the ContainerLogsOptions
    28  	// struct, probably in the caller, to eliminate the dependency on net/http
    29  	logsConfig := &basictypes.ContainerLogsOptions{
    30  		Follow:     httputils.BoolValue(r, "follow"),
    31  		Timestamps: httputils.BoolValue(r, "timestamps"),
    32  		Since:      r.Form.Get("since"),
    33  		Tail:       r.Form.Get("tail"),
    34  		ShowStdout: stdout,
    35  		ShowStderr: stderr,
    36  		Details:    httputils.BoolValue(r, "details"),
    37  	}
    38  
    39  	tty := false
    40  	// checking for whether logs are TTY involves iterating over every service
    41  	// and task. idk if there is a better way
    42  	for _, service := range selector.Services {
    43  		s, err := sr.backend.GetService(service, false)
    44  		if err != nil {
    45  			// maybe should return some context with this error?
    46  			return err
    47  		}
    48  		tty = (s.Spec.TaskTemplate.ContainerSpec != nil && s.Spec.TaskTemplate.ContainerSpec.TTY) || tty
    49  	}
    50  	for _, task := range selector.Tasks {
    51  		t, err := sr.backend.GetTask(task)
    52  		if err != nil {
    53  			// as above
    54  			return err
    55  		}
    56  		tty = t.Spec.ContainerSpec.TTY || tty
    57  	}
    58  
    59  	msgs, err := sr.backend.ServiceLogs(ctx, selector, logsConfig)
    60  	if err != nil {
    61  		return err
    62  	}
    63  
    64  	httputils.WriteLogStream(ctx, w, msgs, logsConfig, !tty)
    65  	return nil
    66  }