From fb14c3192dd50e29f6cebcf3315770c85e88029b Mon Sep 17 00:00:00 2001 From: Paul Holzinger Date: Tue, 19 Aug 2025 18:37:37 +0200 Subject: [PATCH] podman events: show network create/remove event with journald In the journald driver there is a bug where the network event attributes are not preserved. This causes the network driver to be missing and that in turn causes the ToHumanReadable() function to print an empty line. Fix it by making sure we preserve the network driver in the event attributes. Fixes: https://issues.redhat.com/browse/RHEL-109790 Signed-off-by: Paul Holzinger --- libpod/events/journal_linux.go | 59 ++++++++++++++++++++++----------- test/system/500-networking.bats | 12 +++++++ 2 files changed, 51 insertions(+), 20 deletions(-) diff --git a/libpod/events/journal_linux.go b/libpod/events/journal_linux.go index b239242dac..0fc1d6f71e 100644 --- a/libpod/events/journal_linux.go +++ b/libpod/events/journal_linux.go @@ -53,14 +53,8 @@ func (e EventJournalD) Write(ee Event) error { 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 { - b, err := json.Marshal(ee.Details.Attributes) - if err != nil { - return err - } - m["PODMAN_LABELS"] = string(b) + if err := addLabelsToJournal(m, ee.Details.Attributes); err != nil { + return err } if ee.Status == HealthStatus { m["PODMAN_HEALTH_STATUS"] = ee.HealthStatus @@ -75,6 +69,9 @@ func (e EventJournalD) Write(ee Event) error { case Network: m["PODMAN_ID"] = ee.ID m["PODMAN_NETWORK_NAME"] = ee.Network + if err := addLabelsToJournal(m, ee.Details.Attributes); err != nil { + return err + } case Volume: m["PODMAN_NAME"] = ee.Name } @@ -93,6 +90,35 @@ func (e EventJournalD) Write(ee Event) error { return journal.Send(ee.ToHumanReadable(false), prio, m) } +func addLabelsToJournal(journalEntry, eventAttributes map[string]string) error { + // If we have container labels, we need to convert them to a string so they + // can be recorded with the event + if len(eventAttributes) > 0 { + b, err := json.Marshal(eventAttributes) + if err != nil { + return err + } + journalEntry["PODMAN_LABELS"] = string(b) + } + return nil +} + +func getLabelsFromJournal(entry *sdjournal.JournalEntry, event *Event) error { + // 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 err + } + + // if we have labels, add them to the event + if len(labels) > 0 { + event.Attributes = labels + } + } + return nil +} + // Read reads events from the journal and sends qualified events to the event channel func (e EventJournalD) Read(ctx context.Context, options ReadOptions) (retErr error) { filterMap, err := generateEventFilters(options.Filters, options.Since, options.Until) @@ -224,18 +250,8 @@ 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.Attributes = labels - } + if err := getLabelsFromJournal(entry, &newEvent); err != nil { + return nil, err } newEvent.HealthStatus = entry.Fields["PODMAN_HEALTH_STATUS"] if log, ok := entry.Fields["PODMAN_HEALTH_LOG"]; ok { @@ -251,6 +267,9 @@ func newEventFromJournalEntry(entry *sdjournal.JournalEntry) (*Event, error) { case Network: newEvent.ID = entry.Fields["PODMAN_ID"] newEvent.Network = entry.Fields["PODMAN_NETWORK_NAME"] + if err := getLabelsFromJournal(entry, &newEvent); err != nil { + return nil, err + } case Image: newEvent.ID = entry.Fields["PODMAN_ID"] if val, ok := entry.Fields["ERROR"]; ok { diff --git a/test/system/500-networking.bats b/test/system/500-networking.bats index 4b1b297af7..fd07c16939 100644 --- a/test/system/500-networking.bats +++ b/test/system/500-networking.bats @@ -20,6 +20,8 @@ load helpers.network run_podman network ls -n assert "$output" !~ "$heading" "network ls -n shows header anyway" + since=$(date --iso-8601=seconds) + # check deterministic list order local net1=net-a-$(safename) local net2=net-b-$(safename) @@ -28,12 +30,22 @@ load helpers.network run_podman network create $net2 run_podman network create $net3 + # Quick check that we generate events + run_podman events --filter type=network --since $since --stream=false + assert "$output" =~ "network create [0-9a-f]{64} \(name=$net1, type=bridge\)" "network1 create event" + assert "$output" =~ "network create [0-9a-f]{64} \(name=$net2, type=bridge\)" "network2 create event" + assert "$output" =~ "network create [0-9a-f]{64} \(name=$net3, type=bridge\)" "network3 create event" + run_podman network ls --quiet # just check that the order of the created networks is correct # we cannot do an exact match since developer and CI systems could contain more networks is "$output" ".*$net1.*$net2.*$net3.*podman.*" "networks sorted alphabetically" run_podman network rm $net1 $net2 $net3 + run_podman events --filter type=network --since $since --stream=false + assert "$output" =~ "network remove [0-9a-f]{64} \(name=$net1, type=bridge\)" "network1 remove event" + assert "$output" =~ "network remove [0-9a-f]{64} \(name=$net2, type=bridge\)" "network2 remove event" + assert "$output" =~ "network remove [0-9a-f]{64} \(name=$net3, type=bridge\)" "network3 remove event" } # Copied from tsweeney's https://github.com/containers/podman/issues/4827