summaryrefslogtreecommitdiff
path: root/pkg/api
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/api')
-rw-r--r--pkg/api/handlers/compat/containers.go142
-rw-r--r--pkg/api/handlers/compat/containers_logs.go154
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()
+ }
+ }
+ }
+}