filter events by labels

adding the ability to filter evens by the container labels.  this requires that container labels be added to the events data being recorded and subsequently read.

Signed-off-by: baude <bbaude@redhat.com>
This commit is contained in:
baude 2020-10-21 11:59:35 -05:00
parent 51fa8ded9f
commit c593e49701
7 changed files with 83 additions and 2 deletions

View File

@ -86,6 +86,7 @@ filters are supported:
* container=name_or_id
* event=event_status (described above)
* image=name_or_id
* label=key=value
* pod=name_or_id
* volume=name_or_id
* type=event_type (described above)

View File

@ -26,6 +26,12 @@ func (c *Container) newContainerEvent(status events.Status) {
e.Name = c.Name()
e.Image = c.config.RootfsImageName
e.Type = events.Container
e.Details = events.Details{
ID: e.ID,
Attributes: c.Labels(),
}
if err := c.runtime.eventer.Write(e); err != nil {
logrus.Errorf("unable to write pod event: %q", err)
}

View File

@ -36,6 +36,18 @@ type Event struct {
Time time.Time
// Type of event that occurred
Type Type
Details
}
// Details describes specifics about certain events, specifically around
// container events
type Details struct {
// ID is the event ID
ID string
// Attributes can be used to describe specifics about the event
// in the case of a container event, labels for example
Attributes map[string]string
}
// EventerOptions describe options that need to be passed to create

View File

@ -69,7 +69,14 @@ func (e *Event) ToHumanReadable() string {
var humanFormat string
switch e.Type {
case Container, Pod:
humanFormat = fmt.Sprintf("%s %s %s %s (image=%s, name=%s)", e.Time, e.Type, e.Status, e.ID, e.Image, e.Name)
humanFormat = fmt.Sprintf("%s %s %s %s (image=%s, name=%s", e.Time, e.Type, e.Status, e.ID, e.Image, e.Name)
// check if the container has labels and add it to the output
if len(e.Attributes) > 0 {
for k, v := range e.Attributes {
humanFormat += fmt.Sprintf(", %s=%s", k, v)
}
}
humanFormat += ")"
case Image:
humanFormat = fmt.Sprintf("%s %s %s %s %s", e.Time, e.Type, e.Status, e.ID, e.Name)
case System:

View File

@ -55,6 +55,24 @@ func generateEventFilter(filter, filterValue string) (func(e *Event) bool, error
return func(e *Event) bool {
return string(e.Type) == filterValue
}, nil
case "LABEL":
return func(e *Event) bool {
var found bool
// iterate labels and see if we match a key and value
for eventKey, eventValue := range e.Attributes {
filterValueSplit := strings.SplitN(filterValue, "=", 2)
// if the filter isn't right, just return false
if len(filterValueSplit) < 2 {
return false
}
if eventKey == filterValueSplit[0] && eventValue == filterValueSplit[1] {
found = true
break
}
}
return found
}, nil
}
return nil, errors.Errorf("%s is an invalid filter", filter)
}
@ -74,7 +92,7 @@ func generateEventUntilOption(timeUntil time.Time) func(e *Event) bool {
func parseFilter(filter string) (string, string, error) {
filterSplit := strings.SplitN(filter, "=", 2)
if len(filterSplit) == 1 {
if len(filterSplit) != 2 {
return "", "", errors.Errorf("%s is an invalid filter", filter)
}
return filterSplit[0], filterSplit[1], nil

View File

@ -4,6 +4,7 @@ package events
import (
"context"
"encoding/json"
"strconv"
"time"
@ -46,6 +47,15 @@ func (e EventJournalD) Write(ee Event) error {
if ee.ContainerExitCode != 0 {
m["PODMAN_EXIT_CODE"] = strconv.Itoa(ee.ContainerExitCode)
}
// If we have container labels, we need to convert them to a string so they
// can be recorded with the event
if len(ee.Details.Attributes) > 0 {
b, err := json.Marshal(ee.Details.Attributes)
if err != nil {
return err
}
m["PODMAN_LABELS"] = string(b)
}
case Volume:
m["PODMAN_NAME"] = ee.Name
}
@ -174,6 +184,19 @@ func newEventFromJournalEntry(entry *sdjournal.JournalEntry) (*Event, error) { /
newEvent.ContainerExitCode = intCode
}
}
// we need to check for the presence of labels recorded to a container event
if stringLabels, ok := entry.Fields["PODMAN_LABELS"]; ok && len(stringLabels) > 0 {
labels := make(map[string]string, 0)
if err := json.Unmarshal([]byte(stringLabels), &labels); err != nil {
return nil, err
}
// if we have labels, add them to the event
if len(labels) > 0 {
newEvent.Details = Details{Attributes: labels}
}
}
case Image:
newEvent.ID = entry.Fields["PODMAN_ID"]
}

View File

@ -0,0 +1,14 @@
#!/usr/bin/env bats -*- bats -*-
#
# tests for podman events functionality
#
load helpers
@test "events with a filter by label" {
skip_if_remote "Need to talk to Ed on why this is failing on remote"
rand=$(random_string 30)
run_podman 0 run --label foo=bar --name test-$rand --rm $IMAGE ls
run_podman 0 events --filter type=container --filter container=test-$rand --filter label=foo=bar --filter event=start --stream=false
is "$output" ".*foo=bar" "check for label event on container with label"
}