moby/daemon/events/filter.go
Derek McGowan 3a1279393f
Use distribution reference
Remove forked reference package. Use normalized named values
everywhere and familiar functions to convert back to familiar
strings for UX and storage compatibility.

Enforce that the source repository in the distribution metadata
is always a normalized string, ignore invalid values which are not.
Update distribution tests to use normalized values.

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
2017-02-07 11:08:37 -08:00

110 lines
3.1 KiB
Go

package events
import (
"github.com/docker/distribution/reference"
"github.com/docker/docker/api/types/events"
"github.com/docker/docker/api/types/filters"
)
// Filter can filter out docker events from a stream
type Filter struct {
filter filters.Args
}
// NewFilter creates a new Filter
func NewFilter(filter filters.Args) *Filter {
return &Filter{filter: filter}
}
// Include returns true when the event ev is included by the filters
func (ef *Filter) Include(ev events.Message) bool {
return ef.matchEvent(ev) &&
ef.filter.ExactMatch("type", ev.Type) &&
ef.matchDaemon(ev) &&
ef.matchContainer(ev) &&
ef.matchPlugin(ev) &&
ef.matchVolume(ev) &&
ef.matchNetwork(ev) &&
ef.matchImage(ev) &&
ef.matchLabels(ev.Actor.Attributes)
}
func (ef *Filter) matchEvent(ev events.Message) bool {
// #25798 if an event filter contains either health_status, exec_create or exec_start without a colon
// Let's to a FuzzyMatch instead of an ExactMatch.
if ef.filterContains("event", map[string]struct{}{"health_status": {}, "exec_create": {}, "exec_start": {}}) {
return ef.filter.FuzzyMatch("event", ev.Action)
}
return ef.filter.ExactMatch("event", ev.Action)
}
func (ef *Filter) filterContains(field string, values map[string]struct{}) bool {
for _, v := range ef.filter.Get(field) {
if _, ok := values[v]; ok {
return true
}
}
return false
}
func (ef *Filter) matchLabels(attributes map[string]string) bool {
if !ef.filter.Include("label") {
return true
}
return ef.filter.MatchKVList("label", attributes)
}
func (ef *Filter) matchDaemon(ev events.Message) bool {
return ef.fuzzyMatchName(ev, events.DaemonEventType)
}
func (ef *Filter) matchContainer(ev events.Message) bool {
return ef.fuzzyMatchName(ev, events.ContainerEventType)
}
func (ef *Filter) matchPlugin(ev events.Message) bool {
return ef.fuzzyMatchName(ev, events.PluginEventType)
}
func (ef *Filter) matchVolume(ev events.Message) bool {
return ef.fuzzyMatchName(ev, events.VolumeEventType)
}
func (ef *Filter) matchNetwork(ev events.Message) bool {
return ef.fuzzyMatchName(ev, events.NetworkEventType)
}
func (ef *Filter) fuzzyMatchName(ev events.Message, eventType string) bool {
return ef.filter.FuzzyMatch(eventType, ev.Actor.ID) ||
ef.filter.FuzzyMatch(eventType, ev.Actor.Attributes["name"])
}
// matchImage matches against both event.Actor.ID (for image events)
// and event.Actor.Attributes["image"] (for container events), so that any container that was created
// from an image will be included in the image events. Also compare both
// against the stripped repo name without any tags.
func (ef *Filter) matchImage(ev events.Message) bool {
id := ev.Actor.ID
nameAttr := "image"
var imageName string
if ev.Type == events.ImageEventType {
nameAttr = "name"
}
if n, ok := ev.Actor.Attributes[nameAttr]; ok {
imageName = n
}
return ef.filter.ExactMatch("image", id) ||
ef.filter.ExactMatch("image", imageName) ||
ef.filter.ExactMatch("image", stripTag(id)) ||
ef.filter.ExactMatch("image", stripTag(imageName))
}
func stripTag(image string) string {
ref, err := reference.ParseNormalizedNamed(image)
if err != nil {
return image
}
return reference.FamiliarName(ref)
}