Merge pull request #10514 from vrothberg/fix-10507
events: support disjunctive filters
This commit is contained in:
commit
52dae693da
|
|
@ -97,18 +97,41 @@ func parseFilter(filter string) (string, string, error) {
|
|||
return filterSplit[0], filterSplit[1], nil
|
||||
}
|
||||
|
||||
func generateEventOptions(filters []string, since, until string) ([]EventFilter, error) {
|
||||
options := make([]EventFilter, 0, len(filters))
|
||||
// applyFilters applies the EventFilter slices in sequence. Filters under the
|
||||
// same key are disjunctive while each key must match (conjuctive).
|
||||
func applyFilters(event *Event, filterMap map[string][]EventFilter) bool {
|
||||
for _, filters := range filterMap {
|
||||
success := false
|
||||
for _, filter := range filters {
|
||||
if filter(event) {
|
||||
success = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !success {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// generateEventFilter parses the specified filters into a filter map that can
|
||||
// later on be used to filter events. Keys are conjunctive, values are
|
||||
// disjunctive.
|
||||
func generateEventFilters(filters []string, since, until string) (map[string][]EventFilter, error) {
|
||||
filterMap := make(map[string][]EventFilter)
|
||||
for _, filter := range filters {
|
||||
key, val, err := parseFilter(filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
funcFilter, err := generateEventFilter(key, val)
|
||||
filterFunc, err := generateEventFilter(key, val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
options = append(options, funcFilter)
|
||||
filterSlice := filterMap[key]
|
||||
filterSlice = append(filterSlice, filterFunc)
|
||||
filterMap[key] = filterSlice
|
||||
}
|
||||
|
||||
if len(since) > 0 {
|
||||
|
|
@ -116,7 +139,8 @@ func generateEventOptions(filters []string, since, until string) ([]EventFilter,
|
|||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "unable to convert since time of %s", since)
|
||||
}
|
||||
options = append(options, generateEventSinceOption(timeSince))
|
||||
filterFunc := generateEventSinceOption(timeSince)
|
||||
filterMap["since"] = []EventFilter{filterFunc}
|
||||
}
|
||||
|
||||
if len(until) > 0 {
|
||||
|
|
@ -124,7 +148,8 @@ func generateEventOptions(filters []string, since, until string) ([]EventFilter,
|
|||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "unable to convert until time of %s", until)
|
||||
}
|
||||
options = append(options, generateEventUntilOption(timeUntil))
|
||||
filterFunc := generateEventUntilOption(timeUntil)
|
||||
filterMap["until"] = []EventFilter{filterFunc}
|
||||
}
|
||||
return options, nil
|
||||
return filterMap, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,9 +69,9 @@ func (e EventJournalD) Write(ee Event) error {
|
|||
// Read reads events from the journal and sends qualified events to the event channel
|
||||
func (e EventJournalD) Read(ctx context.Context, options ReadOptions) error {
|
||||
defer close(options.EventChannel)
|
||||
eventOptions, err := generateEventOptions(options.Filters, options.Since, options.Until)
|
||||
filterMap, err := generateEventFilters(options.Filters, options.Since, options.Until)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to generate event options")
|
||||
return errors.Wrapf(err, "failed to parse event filters")
|
||||
}
|
||||
var untilTime time.Time
|
||||
if len(options.Until) > 0 {
|
||||
|
|
@ -159,11 +159,7 @@ func (e EventJournalD) Read(ctx context.Context, options ReadOptions) error {
|
|||
}
|
||||
continue
|
||||
}
|
||||
include := true
|
||||
for _, filter := range eventOptions {
|
||||
include = include && filter(newEvent)
|
||||
}
|
||||
if include {
|
||||
if applyFilters(newEvent, filterMap) {
|
||||
options.EventChannel <- newEvent
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,9 +44,9 @@ func (e EventLogFile) Write(ee Event) error {
|
|||
// Reads from the log file
|
||||
func (e EventLogFile) Read(ctx context.Context, options ReadOptions) error {
|
||||
defer close(options.EventChannel)
|
||||
eventOptions, err := generateEventOptions(options.Filters, options.Since, options.Until)
|
||||
filterMap, err := generateEventFilters(options.Filters, options.Since, options.Until)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to generate event options")
|
||||
return errors.Wrapf(err, "failed to parse event filters")
|
||||
}
|
||||
t, err := e.getTail(options)
|
||||
if err != nil {
|
||||
|
|
@ -92,11 +92,7 @@ func (e EventLogFile) Read(ctx context.Context, options ReadOptions) error {
|
|||
default:
|
||||
return errors.Errorf("event type %s is not valid in %s", event.Type.String(), e.options.LogFilePath)
|
||||
}
|
||||
include := true
|
||||
for _, filter := range eventOptions {
|
||||
include = include && filter(event)
|
||||
}
|
||||
if include && copy {
|
||||
if copy && applyFilters(event, filterMap) {
|
||||
options.EventChannel <- event
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,3 +61,32 @@ load helpers
|
|||
.*image remove $imageID $tag.*" \
|
||||
"podman events"
|
||||
}
|
||||
|
||||
function _events_disjunctive_filters() {
|
||||
local backend=$1
|
||||
|
||||
# Regression test for #10507: make sure that filters with the same key are
|
||||
# applied in disjunction.
|
||||
t0=$(date --iso-8601=seconds)
|
||||
run_podman $backend run --name foo --rm $IMAGE ls
|
||||
run_podman $backend run --name bar --rm $IMAGE ls
|
||||
run_podman $backend events --stream=false --since=$t0 --filter container=foo --filter container=bar --filter event=start
|
||||
is "$output" ".* container start .* name=foo.*
|
||||
.* container start .* name=bar.*"
|
||||
}
|
||||
|
||||
@test "events with disjunctive filters - file" {
|
||||
skip_if_remote "remote does not support --events-backend"
|
||||
_events_disjunctive_filters --events-backend=file
|
||||
}
|
||||
|
||||
@test "events with disjunctive filters - journald" {
|
||||
skip_if_remote "remote does not support --events-backend"
|
||||
_events_disjunctive_filters --events-backend=journald
|
||||
}
|
||||
|
||||
@test "events with disjunctive filters - default" {
|
||||
# NOTE: the last event for bar doesn't show up reliably.
|
||||
skip_if_remote "FIXME #10529: remote events lose data"
|
||||
_events_disjunctive_filters ""
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue