From 6ee582315bfba8db13541406f6def26ecd8f6aeb Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Wed, 24 Aug 2022 13:27:17 -0400 Subject: [PATCH] Events for containers in pods now include the pod's ID This allows tools like Cockpit to know that the pod in question has also been updated, so they can refresh the list of containers in the pod. Fixes #15408 Signed-off-by: Matthew Heon --- libpod/events.go | 2 ++ libpod/events/config.go | 2 ++ libpod/events/events.go | 8 +++++++- libpod/events/journal_linux.go | 6 +++++- pkg/domain/entities/events.go | 5 ++++- test/apiv2/27-containersEvents.at | 2 +- test/e2e/events_test.go | 12 +++++++++++- 7 files changed, 32 insertions(+), 5 deletions(-) diff --git a/libpod/events.go b/libpod/events.go index 2f97991144..31a857a7dc 100644 --- a/libpod/events.go +++ b/libpod/events.go @@ -34,6 +34,7 @@ func (c *Container) newContainerEvent(status events.Status) { e.Details = events.Details{ ID: e.ID, + PodID: c.PodID(), Attributes: c.Labels(), } @@ -59,6 +60,7 @@ func (c *Container) newContainerExitedEvent(exitCode int32) { e.Name = c.Name() e.Image = c.config.RootfsImageName e.Type = events.Container + e.PodID = c.PodID() e.ContainerExitCode = int(exitCode) e.Details = events.Details{ diff --git a/libpod/events/config.go b/libpod/events/config.go index 4ea45a00e2..28bc87a34e 100644 --- a/libpod/events/config.go +++ b/libpod/events/config.go @@ -50,6 +50,8 @@ type Event struct { type Details struct { // ID is the event ID ID string + // PodID is the ID of the pod associated with the container. + PodID string `json:",omitempty"` // Attributes can be used to describe specifics about the event // in the case of a container event, labels for example Attributes map[string]string diff --git a/libpod/events/events.go b/libpod/events/events.go index 764481e519..2105a3b89f 100644 --- a/libpod/events/events.go +++ b/libpod/events/events.go @@ -76,7 +76,13 @@ func (e *Event) ToHumanReadable(truncate bool) string { } switch e.Type { case Container, Pod: - humanFormat = fmt.Sprintf("%s %s %s %s (image=%s, name=%s, health_status=%s", e.Time, e.Type, e.Status, id, e.Image, e.Name, e.HealthStatus) + humanFormat = fmt.Sprintf("%s %s %s %s (image=%s, name=%s", e.Time, e.Type, e.Status, id, e.Image, e.Name) + if e.PodID != "" { + humanFormat += fmt.Sprintf(", pod_id=%s", e.PodID) + } + if e.HealthStatus != "" { + humanFormat += fmt.Sprintf(", health_status=%s", e.HealthStatus) + } // check if the container has labels and add it to the output if len(e.Attributes) > 0 { for k, v := range e.Attributes { diff --git a/libpod/events/journal_linux.go b/libpod/events/journal_linux.go index 4986502a27..e303a205d7 100644 --- a/libpod/events/journal_linux.go +++ b/libpod/events/journal_linux.go @@ -50,6 +50,9 @@ func (e EventJournalD) Write(ee Event) error { if ee.ContainerExitCode != 0 { m["PODMAN_EXIT_CODE"] = strconv.Itoa(ee.ContainerExitCode) } + if ee.PodID != "" { + m["PODMAN_POD_ID"] = ee.PodID + } // 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 { @@ -161,6 +164,7 @@ func newEventFromJournalEntry(entry *sdjournal.JournalEntry) (*Event, error) { case Container, Pod: newEvent.ID = entry.Fields["PODMAN_ID"] newEvent.Image = entry.Fields["PODMAN_IMAGE"] + newEvent.PodID = entry.Fields["PODMAN_POD_ID"] if code, ok := entry.Fields["PODMAN_EXIT_CODE"]; ok { intCode, err := strconv.Atoi(code) if err != nil { @@ -179,7 +183,7 @@ func newEventFromJournalEntry(entry *sdjournal.JournalEntry) (*Event, error) { // if we have labels, add them to the event if len(labels) > 0 { - newEvent.Details = Details{Attributes: labels} + newEvent.Attributes = labels } } newEvent.HealthStatus = entry.Fields["PODMAN_HEALTH_STATUS"] diff --git a/pkg/domain/entities/events.go b/pkg/domain/entities/events.go index de218b2854..34a6fe0489 100644 --- a/pkg/domain/entities/events.go +++ b/pkg/domain/entities/events.go @@ -14,7 +14,7 @@ type Event struct { // TODO: it would be nice to have full control over the types at some // point and fork such Docker types. dockerEvents.Message - HealthStatus string + HealthStatus string `json:",omitempty"` } // ConvertToLibpodEvent converts an entities event to a libpod one. @@ -34,6 +34,7 @@ func ConvertToLibpodEvent(e Event) *libpodEvents.Event { image := e.Actor.Attributes["image"] name := e.Actor.Attributes["name"] details := e.Actor.Attributes + podID := e.Actor.Attributes["podId"] delete(details, "image") delete(details, "name") delete(details, "containerExitCode") @@ -47,6 +48,7 @@ func ConvertToLibpodEvent(e Event) *libpodEvents.Event { Type: t, HealthStatus: e.HealthStatus, Details: libpodEvents.Details{ + PodID: podID, Attributes: details, }, } @@ -61,6 +63,7 @@ func ConvertToEntitiesEvent(e libpodEvents.Event) *Event { attributes["image"] = e.Image attributes["name"] = e.Name attributes["containerExitCode"] = strconv.Itoa(e.ContainerExitCode) + attributes["podId"] = e.PodID message := dockerEvents.Message{ // Compatibility with clients that still look for deprecated API elements Status: e.Status.String(), diff --git a/test/apiv2/27-containersEvents.at b/test/apiv2/27-containersEvents.at index e0a66e0acb..a5b5b24a31 100644 --- a/test/apiv2/27-containersEvents.at +++ b/test/apiv2/27-containersEvents.at @@ -20,7 +20,7 @@ t GET "libpod/events?stream=false&since=$START" 200 \ t GET "libpod/events?stream=false&since=$START" 200 \ 'select(.status | contains("start")).Action=start' \ - 'select(.status | contains("start")).HealthStatus='\ + 'select(.status | contains("start")).HealthStatus=null'\ # compat api, uses status=die (#12643) t GET "events?stream=false&since=$START" 200 \ diff --git a/test/e2e/events_test.go b/test/e2e/events_test.go index bba42c3f49..c76919581b 100644 --- a/test/e2e/events_test.go +++ b/test/e2e/events_test.go @@ -212,6 +212,16 @@ var _ = Describe("Podman events", func() { Expect(result).Should(Exit(0)) Expect(result.OutputToStringArray()).To(HaveLen(1)) Expect(result.OutputToString()).To(ContainSubstring("create")) + + ctrName := "testCtr" + run := podmanTest.Podman([]string{"create", "--pod", id, "--name", ctrName, ALPINE, "top"}) + run.WaitWithDefaultTimeout() + Expect(run).Should(Exit(0)) + + result2 := podmanTest.Podman([]string{"events", "--stream=false", "--filter", fmt.Sprintf("container=%s", ctrName), "--since", "30s"}) + result2.WaitWithDefaultTimeout() + Expect(result2).Should(Exit(0)) + Expect(result2.OutputToString()).To(ContainSubstring(fmt.Sprintf("pod_id=%s", id))) }) It("podman events health_status generated", func() { @@ -229,7 +239,7 @@ var _ = Describe("Podman events", func() { time.Sleep(1 * time.Second) } - result := podmanTest.Podman([]string{"events", "--stream=false", "--filter", "event=health_status"}) + result := podmanTest.Podman([]string{"events", "--stream=false", "--filter", "event=health_status", "--since", "1m"}) result.WaitWithDefaultTimeout() Expect(result).Should(Exit(0)) Expect(len(result.OutputToStringArray())).To(BeNumerically(">=", 1), "Number of health_status events")