diff options
-rw-r--r-- | docs/source/markdown/podman-events.1.md | 1 | ||||
-rw-r--r-- | libpod/events.go | 6 | ||||
-rw-r--r-- | libpod/events/config.go | 12 | ||||
-rw-r--r-- | libpod/events/events.go | 9 | ||||
-rw-r--r-- | libpod/events/filters.go | 20 | ||||
-rw-r--r-- | libpod/events/journal_linux.go | 23 | ||||
-rw-r--r-- | test/system/090-events.bats | 14 |
7 files changed, 83 insertions, 2 deletions
diff --git a/docs/source/markdown/podman-events.1.md b/docs/source/markdown/podman-events.1.md index 0d91cdf17..d0bc3cef8 100644 --- a/docs/source/markdown/podman-events.1.md +++ b/docs/source/markdown/podman-events.1.md @@ -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) diff --git a/libpod/events.go b/libpod/events.go index b519fe324..95317eb01 100644 --- a/libpod/events.go +++ b/libpod/events.go @@ -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) } diff --git a/libpod/events/config.go b/libpod/events/config.go index bb35c03c0..2ec3111fe 100644 --- a/libpod/events/config.go +++ b/libpod/events/config.go @@ -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 diff --git a/libpod/events/events.go b/libpod/events/events.go index 722c9595e..42939d64c 100644 --- a/libpod/events/events.go +++ b/libpod/events/events.go @@ -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: diff --git a/libpod/events/filters.go b/libpod/events/filters.go index 171e2237f..62891d32c 100644 --- a/libpod/events/filters.go +++ b/libpod/events/filters.go @@ -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 diff --git a/libpod/events/journal_linux.go b/libpod/events/journal_linux.go index dc55dbc77..5d17a85b4 100644 --- a/libpod/events/journal_linux.go +++ b/libpod/events/journal_linux.go @@ -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"] } diff --git a/test/system/090-events.bats b/test/system/090-events.bats new file mode 100644 index 000000000..06e28ec3a --- /dev/null +++ b/test/system/090-events.bats @@ -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" +} |