Merge pull request #16530 from dnephin/filter_events_by_label

Filter events by labels
This commit is contained in:
Antonio Murdaca
2015-10-04 20:36:42 +02:00
9 changed files with 246 additions and 85 deletions
+15 -2
View File
@@ -23,16 +23,29 @@ func BoolValueOrDefault(r *http.Request, k string, d bool) bool {
return BoolValue(r, k)
}
// Int64ValueOrZero parses a form value into a int64 type.
// Int64ValueOrZero parses a form value into an int64 type.
// It returns 0 if the parsing fails.
func Int64ValueOrZero(r *http.Request, k string) int64 {
val, err := strconv.ParseInt(r.FormValue(k), 10, 64)
val, err := Int64ValueOrDefault(r, k, 0)
if err != nil {
return 0
}
return val
}
// Int64ValueOrDefault parses a form value into an int64 type. If there is an
// error, returns the error. If there is no value returns the default value.
func Int64ValueOrDefault(r *http.Request, field string, def int64) (int64, error) {
if r.Form.Get(field) != "" {
value, err := strconv.ParseInt(r.Form.Get(field), 10, 64)
if err != nil {
return value, err
}
return value, nil
}
return def, nil
}
// ArchiveOptions stores archive information for different operations.
type ArchiveOptions struct {
Name string
+35
View File
@@ -68,3 +68,38 @@ func TestInt64ValueOrZero(t *testing.T) {
}
}
}
func TestInt64ValueOrDefault(t *testing.T) {
cases := map[string]int64{
"": -1,
"-1": -1,
"42": 42,
}
for c, e := range cases {
v := url.Values{}
v.Set("test", c)
r, _ := http.NewRequest("POST", "", nil)
r.Form = v
a, err := Int64ValueOrDefault(r, "test", -1)
if a != e {
t.Fatalf("Value: %s, expected: %v, actual: %v", c, e, a)
}
if err != nil {
t.Fatalf("Error should be nil, but received: %s", err)
}
}
}
func TestInt64ValueOrDefaultWithError(t *testing.T) {
v := url.Values{}
v.Set("test", "invalid")
r, _ := http.NewRequest("POST", "", nil)
r.Form = v
_, err := Int64ValueOrDefault(r, "test", -1)
if err == nil {
t.Fatalf("Expected an error.")
}
}
+31 -72
View File
@@ -4,8 +4,6 @@ import (
"encoding/json"
"net/http"
"runtime"
"strconv"
"strings"
"time"
"github.com/Sirupsen/logrus"
@@ -54,26 +52,27 @@ func (s *router) getInfo(ctx context.Context, w http.ResponseWriter, r *http.Req
return httputils.WriteJSON(w, http.StatusOK, info)
}
func buildOutputEncoder(w http.ResponseWriter) *json.Encoder {
w.Header().Set("Content-Type", "application/json")
outStream := ioutils.NewWriteFlusher(w)
// 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)
return json.NewEncoder(outStream)
}
func (s *router) getEvents(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := httputils.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
since, err := httputils.Int64ValueOrDefault(r, "since", -1)
if err != nil {
return err
}
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
until, err := httputils.Int64ValueOrDefault(r, "until", -1)
if err != nil {
return err
}
timer := time.NewTimer(0)
@@ -88,70 +87,30 @@ func (s *router) getEvents(ctx context.Context, w http.ResponseWriter, r *http.R
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
}
enc := buildOutputEncoder(w)
d := s.daemon
es := d.EventsService
w.Header().Set("Content-Type", "application/json")
outStream := ioutils.NewWriteFlusher(w)
// 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)
enc := json.NewEncoder(outStream)
getContainerID := func(cn string) string {
c, err := d.Get(cn)
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()
defer es.Evict(l)
eventFilter := d.GetEventFilter(ef)
handleEvent := func(ev *jsonmessage.JSONMessage) error {
if eventFilter.Include(ev) {
if err := enc.Encode(ev); err != nil {
return err
}
}
return nil
}
if since == -1 {
current = nil
}
defer es.Evict(l)
for _, ev := range current {
if ev.Time < since {
continue
}
if err := sendEvent(ev); err != nil {
if err := handleEvent(ev); err != nil {
return err
}
}
@@ -168,7 +127,7 @@ func (s *router) getEvents(ctx context.Context, w http.ResponseWriter, r *http.R
if !ok {
continue
}
if err := sendEvent(jev); err != nil {
if err := handleEvent(jev); err != nil {
return err
}
case <-timer.C: