diff options
Diffstat (limited to 'pkg/api')
-rw-r--r-- | pkg/api/handlers/compat/containers.go | 142 | ||||
-rw-r--r-- | pkg/api/handlers/compat/containers_logs.go | 154 |
2 files changed, 154 insertions, 142 deletions
diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go index 8ce2180ab..b103e399d 100644 --- a/pkg/api/handlers/compat/containers.go +++ b/pkg/api/handlers/compat/containers.go @@ -1,29 +1,21 @@ package compat import ( - "encoding/binary" "encoding/json" "fmt" - "io" "net/http" - "strconv" "strings" - "sync" - "time" "github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod/define" - "github.com/containers/libpod/libpod/logs" "github.com/containers/libpod/pkg/api/handlers" "github.com/containers/libpod/pkg/api/handlers/utils" "github.com/containers/libpod/pkg/signal" - "github.com/containers/libpod/pkg/util" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/docker/go-connections/nat" "github.com/gorilla/schema" "github.com/pkg/errors" - log "github.com/sirupsen/logrus" ) func RemoveContainer(w http.ResponseWriter, r *http.Request) { @@ -213,140 +205,6 @@ func WaitContainer(w http.ResponseWriter, r *http.Request) { }) } -func LogsFromContainer(w http.ResponseWriter, r *http.Request) { - decoder := r.Context().Value("decoder").(*schema.Decoder) - runtime := r.Context().Value("runtime").(*libpod.Runtime) - - query := struct { - Follow bool `schema:"follow"` - Stdout bool `schema:"stdout"` - Stderr bool `schema:"stderr"` - Since string `schema:"since"` - Until string `schema:"until"` - Timestamps bool `schema:"timestamps"` - Tail string `schema:"tail"` - }{ - Tail: "all", - } - if err := decoder.Decode(&query, r.URL.Query()); err != nil { - utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String())) - return - } - - if !(query.Stdout || query.Stderr) { - msg := fmt.Sprintf("%s: you must choose at least one stream", http.StatusText(http.StatusBadRequest)) - utils.Error(w, msg, http.StatusBadRequest, errors.Errorf("%s for %s", msg, r.URL.String())) - return - } - - name := utils.GetName(r) - ctnr, err := runtime.LookupContainer(name) - if err != nil { - utils.ContainerNotFound(w, name, err) - return - } - - var tail int64 = -1 - if query.Tail != "all" { - tail, err = strconv.ParseInt(query.Tail, 0, 64) - if err != nil { - utils.BadRequest(w, "tail", query.Tail, err) - return - } - } - - var since time.Time - if _, found := r.URL.Query()["since"]; found { - since, err = util.ParseInputTime(query.Since) - if err != nil { - utils.BadRequest(w, "since", query.Since, err) - return - } - } - - var until time.Time - if _, found := r.URL.Query()["until"]; found { - // FIXME: until != since but the logs backend does not yet support until. - since, err = util.ParseInputTime(query.Until) - if err != nil { - utils.BadRequest(w, "until", query.Until, err) - return - } - } - - options := &logs.LogOptions{ - Details: true, - Follow: query.Follow, - Since: since, - Tail: tail, - Timestamps: query.Timestamps, - } - - var wg sync.WaitGroup - options.WaitGroup = &wg - - logChannel := make(chan *logs.LogLine, tail+1) - if err := runtime.Log([]*libpod.Container{ctnr}, options, logChannel); err != nil { - utils.InternalServerError(w, errors.Wrapf(err, "Failed to obtain logs for Container '%s'", name)) - return - } - go func() { - wg.Wait() - close(logChannel) - }() - - w.WriteHeader(http.StatusOK) - - var frame strings.Builder - header := make([]byte, 8) - for ok := true; ok; ok = query.Follow { - for line := range logChannel { - if _, found := r.URL.Query()["until"]; found { - if line.Time.After(until) { - break - } - } - - // Reset buffer we're ready to loop again - frame.Reset() - switch line.Device { - case "stdout": - if !query.Stdout { - continue - } - header[0] = 1 - case "stderr": - if !query.Stderr { - continue - } - header[0] = 2 - default: - // Logging and moving on is the best we can do here. We may have already sent - // a Status and Content-Type to client therefore we can no longer report an error. - log.Infof("unknown Device type '%s' in log file from Container %s", line.Device, ctnr.ID()) - continue - } - - if query.Timestamps { - frame.WriteString(line.Time.Format(time.RFC3339)) - frame.WriteString(" ") - } - frame.WriteString(line.Msg) - - binary.BigEndian.PutUint32(header[4:], uint32(frame.Len())) - if _, err := w.Write(header[0:8]); err != nil { - log.Errorf("unable to write log output header: %q", err) - } - if _, err := io.WriteString(w, frame.String()); err != nil { - log.Errorf("unable to write frame string: %q", err) - } - if flusher, ok := w.(http.Flusher); ok { - flusher.Flush() - } - } - } -} - func LibpodToContainer(l *libpod.Container, sz bool) (*handlers.Container, error) { imageID, imageName := l.Image() diff --git a/pkg/api/handlers/compat/containers_logs.go b/pkg/api/handlers/compat/containers_logs.go new file mode 100644 index 000000000..3b25a3ecc --- /dev/null +++ b/pkg/api/handlers/compat/containers_logs.go @@ -0,0 +1,154 @@ +package compat + +import ( + "encoding/binary" + "fmt" + "io" + "net/http" + "strconv" + "strings" + "sync" + "time" + + "github.com/containers/libpod/libpod" + "github.com/containers/libpod/libpod/logs" + "github.com/containers/libpod/pkg/api/handlers/utils" + "github.com/containers/libpod/pkg/util" + "github.com/gorilla/schema" + "github.com/pkg/errors" + log "github.com/sirupsen/logrus" +) + +func LogsFromContainer(w http.ResponseWriter, r *http.Request) { + decoder := r.Context().Value("decoder").(*schema.Decoder) + runtime := r.Context().Value("runtime").(*libpod.Runtime) + + query := struct { + Follow bool `schema:"follow"` + Stdout bool `schema:"stdout"` + Stderr bool `schema:"stderr"` + Since string `schema:"since"` + Until string `schema:"until"` + Timestamps bool `schema:"timestamps"` + Tail string `schema:"tail"` + }{ + Tail: "all", + } + if err := decoder.Decode(&query, r.URL.Query()); err != nil { + utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String())) + return + } + + if !(query.Stdout || query.Stderr) { + msg := fmt.Sprintf("%s: you must choose at least one stream", http.StatusText(http.StatusBadRequest)) + utils.Error(w, msg, http.StatusBadRequest, errors.Errorf("%s for %s", msg, r.URL.String())) + return + } + + name := utils.GetName(r) + ctnr, err := runtime.LookupContainer(name) + if err != nil { + utils.ContainerNotFound(w, name, err) + return + } + + var tail int64 = -1 + if query.Tail != "all" { + tail, err = strconv.ParseInt(query.Tail, 0, 64) + if err != nil { + utils.BadRequest(w, "tail", query.Tail, err) + return + } + } + + var since time.Time + if _, found := r.URL.Query()["since"]; found { + since, err = util.ParseInputTime(query.Since) + if err != nil { + utils.BadRequest(w, "since", query.Since, err) + return + } + } + + var until time.Time + if _, found := r.URL.Query()["until"]; found { + // FIXME: until != since but the logs backend does not yet support until. + since, err = util.ParseInputTime(query.Until) + if err != nil { + utils.BadRequest(w, "until", query.Until, err) + return + } + } + + options := &logs.LogOptions{ + Details: true, + Follow: query.Follow, + Since: since, + Tail: tail, + Timestamps: query.Timestamps, + } + + var wg sync.WaitGroup + options.WaitGroup = &wg + + logChannel := make(chan *logs.LogLine, tail+1) + if err := runtime.Log([]*libpod.Container{ctnr}, options, logChannel); err != nil { + utils.InternalServerError(w, errors.Wrapf(err, "Failed to obtain logs for Container '%s'", name)) + return + } + go func() { + wg.Wait() + close(logChannel) + }() + + w.WriteHeader(http.StatusOK) + + var frame strings.Builder + header := make([]byte, 8) + for ok := true; ok; ok = query.Follow { + for line := range logChannel { + if _, found := r.URL.Query()["until"]; found { + if line.Time.After(until) { + break + } + } + + // Reset buffer we're ready to loop again + frame.Reset() + switch line.Device { + case "stdout": + if !query.Stdout { + continue + } + header[0] = 1 + case "stderr": + if !query.Stderr { + continue + } + header[0] = 2 + default: + // Logging and moving on is the best we can do here. We may have already sent + // a Status and Content-Type to client therefore we can no longer report an error. + log.Infof("unknown Device type '%s' in log file from Container %s", line.Device, ctnr.ID()) + continue + } + + if query.Timestamps { + frame.WriteString(line.Time.Format(time.RFC3339)) + frame.WriteString(" ") + } + frame.WriteString(line.Msg) + + binary.BigEndian.PutUint32(header[4:], uint32(frame.Len())) + if _, err := w.Write(header[0:8]); err != nil { + log.Errorf("unable to write log output header: %q", err) + } + if _, err := io.WriteString(w, frame.String()); err != nil { + log.Errorf("unable to write frame string: %q", err) + } + if flusher, ok := w.(http.Flusher); ok { + flusher.Flush() + } + } + } +} |