diff --git a/libpod/events.go b/libpod/events.go index 6189ee895a..f446ee8cb0 100644 --- a/libpod/events.go +++ b/libpod/events.go @@ -136,6 +136,19 @@ func (c *Container) newExecDiedEvent(sessionID string, exitCode int) { } } +// newNetworkEvent creates a new event based on a network create/remove +func (r *Runtime) NewNetworkEvent(status events.Status, netName, netID, netDriver string) { + e := events.NewEvent(status) + e.Network = netName + e.ID = netID + e.Attributes = make(map[string]string) + e.Attributes["driver"] = netDriver + e.Type = events.Network + if err := r.eventer.Write(e); err != nil { + logrus.Errorf("Unable to write network event: %q", err) + } +} + // newNetworkEvent creates a new event based on a network connect/disconnect func (c *Container) newNetworkEvent(status events.Status, netName string) { e := events.NewEvent(status) diff --git a/libpod/events/events.go b/libpod/events/events.go index 084be84cab..16ebbb51c8 100644 --- a/libpod/events/events.go +++ b/libpod/events/events.go @@ -89,7 +89,13 @@ func (e *Event) ToHumanReadable(truncate bool) string { } humanFormat += ")" case Network: - humanFormat = fmt.Sprintf("%s %s %s %s (container=%s, name=%s)", e.Time, e.Type, e.Status, id, id, e.Network) + if e.Status == Create || e.Status == Remove { + if netdriver, exists := e.Attributes["driver"]; exists { + humanFormat = fmt.Sprintf("%s %s %s %s (name=%s, type=%s)", e.Time, e.Type, e.Status, e.ID, e.Network, netdriver) + } + } else { + humanFormat = fmt.Sprintf("%s %s %s %s (container=%s, name=%s)", e.Time, e.Type, e.Status, id, id, e.Network) + } case Image: humanFormat = fmt.Sprintf("%s %s %s %s %s", e.Time, e.Type, e.Status, id, e.Name) if e.Error != "" { diff --git a/pkg/domain/infra/abi/network.go b/pkg/domain/infra/abi/network.go index 5dc3963ba1..ee99c8127b 100644 --- a/pkg/domain/infra/abi/network.go +++ b/pkg/domain/infra/abi/network.go @@ -14,6 +14,7 @@ import ( "github.com/containers/common/libnetwork/types" netutil "github.com/containers/common/libnetwork/util" "github.com/containers/podman/v5/libpod/define" + "github.com/containers/podman/v5/libpod/events" "github.com/containers/podman/v5/pkg/domain/entities" ) @@ -127,7 +128,6 @@ func (ic *ContainerEngine) NetworkReload(ctx context.Context, names []string, op func (ic *ContainerEngine) NetworkRm(ctx context.Context, namesOrIds []string, options entities.NetworkRmOptions) ([]*entities.NetworkRmReport, error) { reports := make([]*entities.NetworkRmReport, 0, len(namesOrIds)) - for _, name := range namesOrIds { report := entities.NetworkRmReport{Name: name} containers, err := ic.Libpod.GetAllContainers() @@ -164,9 +164,16 @@ func (ic *ContainerEngine) NetworkRm(ctx context.Context, namesOrIds []string, o } } } + net, err := ic.Libpod.Network().NetworkInspect(name) + if err != nil && !errors.Is(err, define.ErrNoSuchNetwork) { + return reports, err + } if err := ic.Libpod.Network().NetworkRemove(name); err != nil { report.Err = err } + if len(net.Name) != 0 { + ic.Libpod.NewNetworkEvent(events.Remove, net.Name, net.ID, net.Driver) + } reports = append(reports, &report) } return reports, nil @@ -180,6 +187,7 @@ func (ic *ContainerEngine) NetworkCreate(ctx context.Context, network types.Netw if err != nil { return nil, err } + ic.Libpod.NewNetworkEvent(events.Create, network.Name, network.ID, network.Driver) return &network, nil } diff --git a/test/e2e/events_test.go b/test/e2e/events_test.go index d612c1343f..c86ef9e78b 100644 --- a/test/e2e/events_test.go +++ b/test/e2e/events_test.go @@ -242,7 +242,8 @@ var _ = Describe("Podman events", func() { It("podman events network connection", func() { network := stringid.GenerateRandomID() - result := podmanTest.Podman([]string{"create", "--network", "bridge", ALPINE, "top"}) + networkDriver := "bridge" + result := podmanTest.Podman([]string{"create", "--network", networkDriver, ALPINE, "top"}) result.WaitWithDefaultTimeout() Expect(result).Should(ExitCleanly()) ctrID := result.OutputToString() @@ -259,11 +260,16 @@ var _ = Describe("Podman events", func() { result.WaitWithDefaultTimeout() Expect(result).Should(ExitCleanly()) + result = podmanTest.Podman([]string{"network", "rm", network}) + result.WaitWithDefaultTimeout() + Expect(result).Should(ExitCleanly()) + result = podmanTest.Podman([]string{"events", "--stream=false", "--since", "30s"}) result.WaitWithDefaultTimeout() Expect(result).Should(ExitCleanly()) eventDetails := fmt.Sprintf(" %s (container=%s, name=%s)", ctrID, ctrID, network) + networkCreateRemoveDetails := fmt.Sprintf("(name=%s, type=%s)", network, networkDriver) // Workaround for #23634, event order not guaranteed when remote. // Although the issue is closed, the bug is a real one. It seems // unlikely ever to be fixed. @@ -274,9 +280,11 @@ var _ = Describe("Podman events", func() { Expect(lines).To(MatchRegexp(" network connect .* network disconnect ")) } else { lines := result.OutputToStringArray() - Expect(lines).To(HaveLen(5)) - Expect(lines[3]).To(ContainSubstring("network connect" + eventDetails)) - Expect(lines[4]).To(ContainSubstring("network disconnect" + eventDetails)) + Expect(lines).To(HaveLen(7)) + Expect(lines[3]).To(And(ContainSubstring("network create"), ContainSubstring(networkCreateRemoveDetails))) + Expect(lines[4]).To(ContainSubstring("network connect" + eventDetails)) + Expect(lines[5]).To(ContainSubstring("network disconnect" + eventDetails)) + Expect(lines[6]).To(And(ContainSubstring("network remove"), ContainSubstring(networkCreateRemoveDetails))) } })