2015-07-28 14:35:24 -04:00
|
|
|
package server
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"net/http"
|
|
|
|
"runtime"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/Sirupsen/logrus"
|
|
|
|
"github.com/docker/docker/api"
|
|
|
|
"github.com/docker/docker/api/types"
|
|
|
|
"github.com/docker/docker/autogen/dockerversion"
|
2015-09-09 17:14:09 -04:00
|
|
|
"github.com/docker/docker/context"
|
2015-07-28 14:35:24 -04:00
|
|
|
"github.com/docker/docker/pkg/ioutils"
|
|
|
|
"github.com/docker/docker/pkg/jsonmessage"
|
|
|
|
"github.com/docker/docker/pkg/parsers/filters"
|
|
|
|
"github.com/docker/docker/pkg/parsers/kernel"
|
|
|
|
"github.com/docker/docker/utils"
|
|
|
|
)
|
|
|
|
|
2015-08-31 10:55:51 -04:00
|
|
|
func (s *Server) getVersion(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
2015-07-28 14:35:24 -04:00
|
|
|
v := &types.Version{
|
|
|
|
Version: dockerversion.VERSION,
|
2015-07-23 05:40:54 -04:00
|
|
|
APIVersion: api.Version,
|
2015-07-28 14:35:24 -04:00
|
|
|
GitCommit: dockerversion.GITCOMMIT,
|
|
|
|
GoVersion: runtime.Version(),
|
|
|
|
Os: runtime.GOOS,
|
|
|
|
Arch: runtime.GOARCH,
|
|
|
|
BuildTime: dockerversion.BUILDTIME,
|
|
|
|
}
|
|
|
|
|
2015-09-09 17:14:09 -04:00
|
|
|
version := ctx.Version()
|
2015-08-31 10:55:51 -04:00
|
|
|
|
2015-07-28 14:35:24 -04:00
|
|
|
if version.GreaterThanOrEqualTo("1.19") {
|
|
|
|
v.Experimental = utils.ExperimentalBuild()
|
|
|
|
}
|
|
|
|
|
|
|
|
if kernelVersion, err := kernel.GetKernelVersion(); err == nil {
|
|
|
|
v.KernelVersion = kernelVersion.String()
|
|
|
|
}
|
|
|
|
|
|
|
|
return writeJSON(w, http.StatusOK, v)
|
|
|
|
}
|
|
|
|
|
2015-08-31 10:55:51 -04:00
|
|
|
func (s *Server) getInfo(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
2015-09-29 13:51:40 -04:00
|
|
|
info, err := s.daemon.SystemInfo()
|
2015-07-28 14:35:24 -04:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return writeJSON(w, http.StatusOK, info)
|
|
|
|
}
|
|
|
|
|
2015-08-31 10:55:51 -04:00
|
|
|
func (s *Server) getEvents(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
2015-07-28 14:35:24 -04:00
|
|
|
if err := parseForm(r); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
var since int64 = -1
|
|
|
|
if r.Form.Get("since") != "" {
|
|
|
|
s, err := strconv.ParseInt(r.Form.Get("since"), 10, 64)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
since = s
|
|
|
|
}
|
|
|
|
|
|
|
|
var until int64 = -1
|
|
|
|
if r.Form.Get("until") != "" {
|
|
|
|
u, err := strconv.ParseInt(r.Form.Get("until"), 10, 64)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
until = u
|
|
|
|
}
|
|
|
|
|
|
|
|
timer := time.NewTimer(0)
|
|
|
|
timer.Stop()
|
|
|
|
if until > 0 {
|
|
|
|
dur := time.Unix(until, 0).Sub(time.Now())
|
|
|
|
timer = time.NewTimer(dur)
|
|
|
|
}
|
|
|
|
|
|
|
|
ef, err := filters.FromParam(r.Form.Get("filters"))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
isFiltered := func(field string, filter []string) bool {
|
|
|
|
if len(field) == 0 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if len(filter) == 0 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
for _, v := range filter {
|
|
|
|
if v == field {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if strings.Contains(field, ":") {
|
|
|
|
image := strings.Split(field, ":")
|
|
|
|
if image[0] == v {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
d := s.daemon
|
|
|
|
es := d.EventsService
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
2015-09-19 05:58:43 -04:00
|
|
|
|
2015-07-28 14:35:24 -04:00
|
|
|
outStream := ioutils.NewWriteFlusher(w)
|
2015-09-19 05:58:43 -04:00
|
|
|
// Write an empty chunk of data.
|
|
|
|
// This is to ensure that the HTTP status code is sent immediately,
|
|
|
|
// so that it will not block the receiver.
|
|
|
|
outStream.Write(nil)
|
2015-07-28 14:35:24 -04:00
|
|
|
enc := json.NewEncoder(outStream)
|
|
|
|
|
|
|
|
getContainerID := func(cn string) string {
|
2015-09-29 13:51:40 -04:00
|
|
|
c, err := d.Get(cn)
|
2015-07-28 14:35:24 -04:00
|
|
|
if err != nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
return c.ID
|
|
|
|
}
|
|
|
|
|
|
|
|
sendEvent := func(ev *jsonmessage.JSONMessage) error {
|
|
|
|
//incoming container filter can be name,id or partial id, convert and replace as a full container id
|
|
|
|
for i, cn := range ef["container"] {
|
|
|
|
ef["container"][i] = getContainerID(cn)
|
|
|
|
}
|
|
|
|
|
|
|
|
if isFiltered(ev.Status, ef["event"]) || (isFiltered(ev.ID, ef["image"]) &&
|
|
|
|
isFiltered(ev.From, ef["image"])) || isFiltered(ev.ID, ef["container"]) {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return enc.Encode(ev)
|
|
|
|
}
|
|
|
|
|
|
|
|
current, l := es.Subscribe()
|
|
|
|
if since == -1 {
|
|
|
|
current = nil
|
|
|
|
}
|
|
|
|
defer es.Evict(l)
|
|
|
|
for _, ev := range current {
|
|
|
|
if ev.Time < since {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if err := sendEvent(ev); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var closeNotify <-chan bool
|
|
|
|
if closeNotifier, ok := w.(http.CloseNotifier); ok {
|
|
|
|
closeNotify = closeNotifier.CloseNotify()
|
|
|
|
}
|
|
|
|
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case ev := <-l:
|
|
|
|
jev, ok := ev.(*jsonmessage.JSONMessage)
|
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if err := sendEvent(jev); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
case <-timer.C:
|
|
|
|
return nil
|
|
|
|
case <-closeNotify:
|
|
|
|
logrus.Debug("Client disconnected, stop sending events")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|