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 <matthew.heon@pm.me>
This commit is contained in:
Matthew Heon 2022-08-24 13:27:17 -04:00
parent 08993516a9
commit 6ee582315b
7 changed files with 32 additions and 5 deletions

View File

@ -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{

View File

@ -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

View File

@ -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 {

View File

@ -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"]

View File

@ -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(),

View File

@ -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 \

View File

@ -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")