11
"github.com/containers/podman/v5/libpod/events"
12
"github.com/sirupsen/logrus"
15
// newEventer returns an eventer that can be used to read/write events
16
func (r *Runtime) newEventer() (events.Eventer, error) {
17
if r.config.Engine.EventsLogFilePath == "" {
18
// default, use path under tmpdir when none was explicitly set by the user
19
r.config.Engine.EventsLogFilePath = filepath.Join(r.config.Engine.TmpDir, "events", "events.log")
21
options := events.EventerOptions{
22
EventerType: r.config.Engine.EventsLogger,
23
LogFilePath: r.config.Engine.EventsLogFilePath,
24
LogFileMaxSize: r.config.Engine.EventsLogMaxSize(),
26
return events.NewEventer(options)
29
// newContainerEvent creates a new event based on a container
30
func (c *Container) newContainerEvent(status events.Status) {
31
if err := c.newContainerEventWithInspectData(status, "", false); err != nil {
32
logrus.Errorf("Unable to write container event: %v", err)
36
// newContainerHealthCheckEvent creates a new healthcheck event with the given status
37
func (c *Container) newContainerHealthCheckEvent(healthStatus string) {
38
if err := c.newContainerEventWithInspectData(events.HealthStatus, healthStatus, false); err != nil {
39
logrus.Errorf("Unable to write container event: %v", err)
43
// newContainerEventWithInspectData creates a new event and sets the
44
// ContainerInspectData field if inspectData is set.
45
func (c *Container) newContainerEventWithInspectData(status events.Status, healthStatus string, inspectData bool) error {
46
e := events.NewEvent(status)
49
e.Image = c.config.RootfsImageName
50
e.Type = events.Container
51
e.HealthStatus = healthStatus
53
e.Details = events.Details{
55
Attributes: c.Labels(),
60
data, err := c.inspectLocked(true)
64
rawData, err := json.Marshal(data)
68
e.Details.ContainerInspectData = string(rawData)
72
return fmt.Errorf("adding inspect data to container-create event: %v", err)
76
if status == events.Remove {
77
exitCode, err := c.runtime.state.GetContainerExitCode(c.ID())
79
intExitCode := int(exitCode)
80
e.ContainerExitCode = &intExitCode
84
return c.runtime.eventer.Write(e)
87
// newContainerExitedEvent creates a new event for a container's death
88
func (c *Container) newContainerExitedEvent(exitCode int32) {
89
e := events.NewEvent(events.Exited)
92
e.Image = c.config.RootfsImageName
93
e.Type = events.Container
95
intExitCode := int(exitCode)
96
e.ContainerExitCode = &intExitCode
98
e.Details = events.Details{
99
Attributes: c.Labels(),
102
if err := c.runtime.eventer.Write(e); err != nil {
103
logrus.Errorf("Unable to write container exited event: %q", err)
107
// newExecDiedEvent creates a new event for an exec session's death
108
func (c *Container) newExecDiedEvent(sessionID string, exitCode int) {
109
e := events.NewEvent(events.ExecDied)
112
e.Image = c.config.RootfsImageName
113
e.Type = events.Container
114
intExitCode := exitCode
115
e.ContainerExitCode = &intExitCode
116
e.Attributes = make(map[string]string)
117
e.Attributes["execID"] = sessionID
119
e.Details = events.Details{
120
Attributes: c.Labels(),
123
if err := c.runtime.eventer.Write(e); err != nil {
124
logrus.Errorf("Unable to write exec died event: %q", err)
128
// newNetworkEvent creates a new event based on a network connect/disconnect
129
func (c *Container) newNetworkEvent(status events.Status, netName string) {
130
e := events.NewEvent(status)
133
e.Type = events.Network
135
if err := c.runtime.eventer.Write(e); err != nil {
136
logrus.Errorf("Unable to write pod event: %q", err)
140
// newPodEvent creates a new event for a libpod pod
141
func (p *Pod) newPodEvent(status events.Status) {
142
e := events.NewEvent(status)
146
if err := p.runtime.eventer.Write(e); err != nil {
147
logrus.Errorf("Unable to write pod event: %q", err)
151
// NewSystemEvent creates a new event for libpod as a whole.
152
func (r *Runtime) NewSystemEvent(status events.Status) {
153
e := events.NewEvent(status)
154
e.Type = events.System
156
if err := r.eventer.Write(e); err != nil {
157
logrus.Errorf("Unable to write system event: %q", err)
161
// newVolumeEvent creates a new event for a libpod volume
162
func (v *Volume) newVolumeEvent(status events.Status) {
163
e := events.NewEvent(status)
165
e.Type = events.Volume
166
if err := v.runtime.eventer.Write(e); err != nil {
167
logrus.Errorf("Unable to write volume event: %q", err)
171
// Events is a wrapper function for everyone to begin tailing the events log
173
func (r *Runtime) Events(ctx context.Context, options events.ReadOptions) error {
174
return r.eventer.Read(ctx, options)
177
// GetEvents reads the event log and returns events based on input filters
178
func (r *Runtime) GetEvents(ctx context.Context, filters []string) ([]*events.Event, error) {
179
eventChannel := make(chan *events.Event)
180
options := events.ReadOptions{
181
EventChannel: eventChannel,
187
logEvents := make([]*events.Event, 0, len(eventChannel))
188
readLock := sync.Mutex{}
191
for e := range eventChannel {
192
logEvents = append(logEvents, e)
197
readErr := r.eventer.Read(ctx, options)
198
readLock.Lock() // Wait for the events to be consumed.
199
return logEvents, readErr
202
// GetLastContainerEvent takes a container name or ID and an event status and returns
203
// the last occurrence of the container event
204
func (r *Runtime) GetLastContainerEvent(ctx context.Context, nameOrID string, containerEvent events.Status) (*events.Event, error) {
205
// FIXME: events should be read in reverse order!
206
// https://github.com/containers/podman/issues/14579
208
// check to make sure the event.Status is valid
209
if _, err := events.StringToStatus(containerEvent.String()); err != nil {
213
fmt.Sprintf("container=%s", nameOrID),
214
fmt.Sprintf("event=%s", containerEvent),
217
containerEvents, err := r.GetEvents(ctx, filters)
221
if len(containerEvents) < 1 {
222
return nil, fmt.Errorf("%s not found: %w", containerEvent.String(), events.ErrEventNotFound)
224
// return the last element in the slice
225
return containerEvents[len(containerEvents)-1], nil
228
// GetExecDiedEvent takes a container name or ID, exec session ID, and returns
229
// that exec session's Died event (if it has already occurred).
230
func (r *Runtime) GetExecDiedEvent(ctx context.Context, nameOrID, execSessionID string) (*events.Event, error) {
232
fmt.Sprintf("container=%s", nameOrID),
235
fmt.Sprintf("label=execID=%s", execSessionID),
238
containerEvents, err := r.GetEvents(ctx, filters)
242
// There *should* only be one event maximum.
243
// But... just in case... let's not blow up if there's more than one.
244
if len(containerEvents) < 1 {
245
return nil, fmt.Errorf("exec died event for session %s (container %s) not found: %w", execSessionID, nameOrID, events.ErrEventNotFound)
247
return containerEvents[len(containerEvents)-1], nil