mirror of https://github.com/containers/podman.git
				
				
				
			
		
			
				
	
	
		
			258 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			258 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			Go
		
	
	
	
//go:build !remote
 | 
						|
 | 
						|
package libpod
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"fmt"
 | 
						|
	"path/filepath"
 | 
						|
 | 
						|
	"github.com/containers/podman/v5/libpod/define"
 | 
						|
	"github.com/containers/podman/v5/libpod/events"
 | 
						|
	"github.com/sirupsen/logrus"
 | 
						|
)
 | 
						|
 | 
						|
// newEventer returns an eventer that can be used to read/write events
 | 
						|
func (r *Runtime) newEventer() (events.Eventer, error) {
 | 
						|
	if r.config.Engine.EventsLogFilePath == "" {
 | 
						|
		// default, use path under tmpdir when none was explicitly set by the user
 | 
						|
		r.config.Engine.EventsLogFilePath = filepath.Join(r.config.Engine.TmpDir, "events", "events.log")
 | 
						|
	}
 | 
						|
	options := events.EventerOptions{
 | 
						|
		EventerType:    r.config.Engine.EventsLogger,
 | 
						|
		LogFilePath:    r.config.Engine.EventsLogFilePath,
 | 
						|
		LogFileMaxSize: r.config.Engine.EventsLogMaxSize(),
 | 
						|
	}
 | 
						|
	return events.NewEventer(options)
 | 
						|
}
 | 
						|
 | 
						|
// newContainerEvent creates a new event based on a container
 | 
						|
func (c *Container) newContainerEvent(status events.Status) {
 | 
						|
	if err := c.newContainerEventWithInspectData(status, define.HealthCheckResults{}, false); err != nil {
 | 
						|
		logrus.Errorf("Unable to write container event: %v", err)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// newContainerHealthCheckEvent creates a new healthcheck event with the given status
 | 
						|
func (c *Container) newContainerHealthCheckEvent(healthCheckResult define.HealthCheckResults) {
 | 
						|
	if err := c.newContainerEventWithInspectData(events.HealthStatus, healthCheckResult, false); err != nil {
 | 
						|
		logrus.Errorf("Unable to write container event: %v", err)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// newContainerEventWithInspectData creates a new event and sets the
 | 
						|
// ContainerInspectData field if inspectData is set.
 | 
						|
func (c *Container) newContainerEventWithInspectData(status events.Status, healthCheckResult define.HealthCheckResults, inspectData bool) error {
 | 
						|
	e := events.NewEvent(status)
 | 
						|
	e.ID = c.ID()
 | 
						|
	e.Name = c.Name()
 | 
						|
	e.Image = c.config.RootfsImageName
 | 
						|
	e.Type = events.Container
 | 
						|
	e.HealthStatus = healthCheckResult.Status
 | 
						|
	if c.HealthCheckLogDestination() == define.HealthCheckEventsLoggerDestination {
 | 
						|
		if len(healthCheckResult.Log) > 0 {
 | 
						|
			logData, err := json.Marshal(healthCheckResult.Log[len(healthCheckResult.Log)-1])
 | 
						|
			if err != nil {
 | 
						|
				return fmt.Errorf("unable to marshall healthcheck log for writing: %w", err)
 | 
						|
			}
 | 
						|
			e.HealthLog = string(logData)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	e.HealthFailingStreak = healthCheckResult.FailingStreak
 | 
						|
 | 
						|
	e.Details = events.Details{
 | 
						|
		PodID:      c.PodID(),
 | 
						|
		Attributes: c.Labels(),
 | 
						|
	}
 | 
						|
 | 
						|
	if inspectData {
 | 
						|
		err := func() error {
 | 
						|
			data, err := c.inspectLocked(true)
 | 
						|
			if err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
			rawData, err := json.Marshal(data)
 | 
						|
			if err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
			e.Details.ContainerInspectData = string(rawData)
 | 
						|
			return nil
 | 
						|
		}()
 | 
						|
		if err != nil {
 | 
						|
			return fmt.Errorf("adding inspect data to container-create event: %v", err)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if status == events.Remove {
 | 
						|
		exitCode, err := c.runtime.state.GetContainerExitCode(c.ID())
 | 
						|
		if err == nil {
 | 
						|
			intExitCode := int(exitCode)
 | 
						|
			e.ContainerExitCode = &intExitCode
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return c.runtime.eventer.Write(e)
 | 
						|
}
 | 
						|
 | 
						|
// newContainerExitedEvent creates a new event for a container's death
 | 
						|
func (c *Container) newContainerExitedEvent(exitCode int32) {
 | 
						|
	e := events.NewEvent(events.Exited)
 | 
						|
	e.ID = c.ID()
 | 
						|
	e.Name = c.Name()
 | 
						|
	e.Image = c.config.RootfsImageName
 | 
						|
	e.Type = events.Container
 | 
						|
	e.PodID = c.PodID()
 | 
						|
	intExitCode := int(exitCode)
 | 
						|
	e.ContainerExitCode = &intExitCode
 | 
						|
 | 
						|
	e.Details = events.Details{
 | 
						|
		Attributes: c.Labels(),
 | 
						|
	}
 | 
						|
 | 
						|
	if err := c.runtime.eventer.Write(e); err != nil {
 | 
						|
		logrus.Errorf("Unable to write container exited event: %q", err)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// newExecDiedEvent creates a new event for an exec session's death
 | 
						|
func (c *Container) newExecDiedEvent(sessionID string, exitCode int) {
 | 
						|
	e := events.NewEvent(events.ExecDied)
 | 
						|
	e.ID = c.ID()
 | 
						|
	e.Name = c.Name()
 | 
						|
	e.Image = c.config.RootfsImageName
 | 
						|
	e.Type = events.Container
 | 
						|
	intExitCode := exitCode
 | 
						|
	e.ContainerExitCode = &intExitCode
 | 
						|
	e.Attributes = make(map[string]string)
 | 
						|
	e.Attributes["execID"] = sessionID
 | 
						|
 | 
						|
	e.Details = events.Details{
 | 
						|
		Attributes: c.Labels(),
 | 
						|
	}
 | 
						|
 | 
						|
	if err := c.runtime.eventer.Write(e); err != nil {
 | 
						|
		logrus.Errorf("Unable to write exec died event: %q", err)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// 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)
 | 
						|
	e.ID = c.ID()
 | 
						|
	e.Name = c.Name()
 | 
						|
	e.Type = events.Network
 | 
						|
	e.Network = netName
 | 
						|
	if err := c.runtime.eventer.Write(e); err != nil {
 | 
						|
		logrus.Errorf("Unable to write pod event: %q", err)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// newPodEvent creates a new event for a libpod pod
 | 
						|
func (p *Pod) newPodEvent(status events.Status) {
 | 
						|
	e := events.NewEvent(status)
 | 
						|
	e.ID = p.ID()
 | 
						|
	e.Name = p.Name()
 | 
						|
	e.Type = events.Pod
 | 
						|
	if err := p.runtime.eventer.Write(e); err != nil {
 | 
						|
		logrus.Errorf("Unable to write pod event: %q", err)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// NewSystemEvent creates a new event for libpod as a whole.
 | 
						|
func (r *Runtime) NewSystemEvent(status events.Status) {
 | 
						|
	e := events.NewEvent(status)
 | 
						|
	e.Type = events.System
 | 
						|
 | 
						|
	if err := r.eventer.Write(e); err != nil {
 | 
						|
		logrus.Errorf("Unable to write system event: %q", err)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// newVolumeEvent creates a new event for a libpod volume
 | 
						|
func (v *Volume) newVolumeEvent(status events.Status) {
 | 
						|
	e := events.NewEvent(status)
 | 
						|
	e.Name = v.Name()
 | 
						|
	e.Type = events.Volume
 | 
						|
	if err := v.runtime.eventer.Write(e); err != nil {
 | 
						|
		logrus.Errorf("Unable to write volume event: %q", err)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// NewSecretEvent creates a new event for a libpod secret
 | 
						|
func (r *Runtime) NewSecretEvent(status events.Status, secretID string) {
 | 
						|
	e := events.NewEvent(status)
 | 
						|
	e.ID = secretID
 | 
						|
	e.Type = events.Secret
 | 
						|
	if err := r.eventer.Write(e); err != nil {
 | 
						|
		logrus.Errorf("Unable to write secret event: %q", err)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Events is a wrapper function for everyone to begin tailing the events log
 | 
						|
// with options
 | 
						|
func (r *Runtime) Events(ctx context.Context, options events.ReadOptions) error {
 | 
						|
	return r.eventer.Read(ctx, options)
 | 
						|
}
 | 
						|
 | 
						|
// GetEvents reads the event log and returns events based on input filters
 | 
						|
func (r *Runtime) GetEvents(ctx context.Context, filters []string) ([]*events.Event, error) {
 | 
						|
	eventChannel := make(chan events.ReadResult)
 | 
						|
	options := events.ReadOptions{
 | 
						|
		EventChannel: eventChannel,
 | 
						|
		Filters:      filters,
 | 
						|
		FromStart:    true,
 | 
						|
		Stream:       false,
 | 
						|
	}
 | 
						|
 | 
						|
	err := r.eventer.Read(ctx, options)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	logEvents := make([]*events.Event, 0, len(eventChannel))
 | 
						|
	for evt := range eventChannel {
 | 
						|
		// we ignore any error here, this is only used on the backup
 | 
						|
		// GetExecDiedEvent() died path as best effort anyway
 | 
						|
		if evt.Error == nil {
 | 
						|
			logEvents = append(logEvents, evt.Event)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return logEvents, nil
 | 
						|
}
 | 
						|
 | 
						|
// GetExecDiedEvent takes a container name or ID, exec session ID, and returns
 | 
						|
// that exec session's Died event (if it has already occurred).
 | 
						|
func (r *Runtime) GetExecDiedEvent(ctx context.Context, nameOrID, execSessionID string) (*events.Event, error) {
 | 
						|
	filters := []string{
 | 
						|
		fmt.Sprintf("container=%s", nameOrID),
 | 
						|
		"event=exec_died",
 | 
						|
		"type=container",
 | 
						|
		fmt.Sprintf("label=execID=%s", execSessionID),
 | 
						|
	}
 | 
						|
 | 
						|
	containerEvents, err := r.GetEvents(ctx, filters)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	// There *should* only be one event maximum.
 | 
						|
	// But... just in case... let's not blow up if there's more than one.
 | 
						|
	if len(containerEvents) < 1 {
 | 
						|
		return nil, fmt.Errorf("exec died event for session %s (container %s) not found: %w", execSessionID, nameOrID, events.ErrEventNotFound)
 | 
						|
	}
 | 
						|
	return containerEvents[len(containerEvents)-1], nil
 | 
						|
}
 |