github.com/AbhinandanKurakure/podman/v3@v3.4.10/libpod/events.go (about)

     1  package libpod
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"sync"
     7  
     8  	"github.com/containers/podman/v3/libpod/events"
     9  	"github.com/pkg/errors"
    10  	"github.com/sirupsen/logrus"
    11  )
    12  
    13  // newEventer returns an eventer that can be used to read/write events
    14  func (r *Runtime) newEventer() (events.Eventer, error) {
    15  	options := events.EventerOptions{
    16  		EventerType: r.config.Engine.EventsLogger,
    17  		LogFilePath: r.config.Engine.EventsLogFilePath,
    18  	}
    19  	return events.NewEventer(options)
    20  }
    21  
    22  // newContainerEvent creates a new event based on a container
    23  func (c *Container) newContainerEvent(status events.Status) {
    24  	e := events.NewEvent(status)
    25  	e.ID = c.ID()
    26  	e.Name = c.Name()
    27  	e.Image = c.config.RootfsImageName
    28  	e.Type = events.Container
    29  
    30  	e.Details = events.Details{
    31  		ID:         e.ID,
    32  		Attributes: c.Labels(),
    33  	}
    34  
    35  	if err := c.runtime.eventer.Write(e); err != nil {
    36  		logrus.Errorf("unable to write pod event: %q", err)
    37  	}
    38  }
    39  
    40  // newContainerExitedEvent creates a new event for a container's death
    41  func (c *Container) newContainerExitedEvent(exitCode int32) {
    42  	e := events.NewEvent(events.Exited)
    43  	e.ID = c.ID()
    44  	e.Name = c.Name()
    45  	e.Image = c.config.RootfsImageName
    46  	e.Type = events.Container
    47  	e.ContainerExitCode = int(exitCode)
    48  	if err := c.runtime.eventer.Write(e); err != nil {
    49  		logrus.Errorf("unable to write container exited event: %q", err)
    50  	}
    51  }
    52  
    53  // newExecDiedEvent creates a new event for an exec session's death
    54  func (c *Container) newExecDiedEvent(sessionID string, exitCode int) {
    55  	e := events.NewEvent(events.ExecDied)
    56  	e.ID = c.ID()
    57  	e.Name = c.Name()
    58  	e.Image = c.config.RootfsImageName
    59  	e.Type = events.Container
    60  	e.ContainerExitCode = exitCode
    61  	e.Attributes = make(map[string]string)
    62  	e.Attributes["execID"] = sessionID
    63  	if err := c.runtime.eventer.Write(e); err != nil {
    64  		logrus.Errorf("unable to write exec died event: %q", err)
    65  	}
    66  }
    67  
    68  // netNetworkEvent creates a new event based on a network connect/disconnect
    69  func (c *Container) newNetworkEvent(status events.Status, netName string) {
    70  	e := events.NewEvent(status)
    71  	e.ID = c.ID()
    72  	e.Name = c.Name()
    73  	e.Type = events.Network
    74  	e.Network = netName
    75  	if err := c.runtime.eventer.Write(e); err != nil {
    76  		logrus.Errorf("unable to write pod event: %q", err)
    77  	}
    78  }
    79  
    80  // newPodEvent creates a new event for a libpod pod
    81  func (p *Pod) newPodEvent(status events.Status) {
    82  	e := events.NewEvent(status)
    83  	e.ID = p.ID()
    84  	e.Name = p.Name()
    85  	e.Type = events.Pod
    86  	if err := p.runtime.eventer.Write(e); err != nil {
    87  		logrus.Errorf("unable to write pod event: %q", err)
    88  	}
    89  }
    90  
    91  // newSystemEvent creates a new event for libpod as a whole.
    92  func (r *Runtime) newSystemEvent(status events.Status) {
    93  	e := events.NewEvent(status)
    94  	e.Type = events.System
    95  
    96  	if err := r.eventer.Write(e); err != nil {
    97  		logrus.Errorf("unable to write system event: %q", err)
    98  	}
    99  }
   100  
   101  // newVolumeEvent creates a new event for a libpod volume
   102  func (v *Volume) newVolumeEvent(status events.Status) {
   103  	e := events.NewEvent(status)
   104  	e.Name = v.Name()
   105  	e.Type = events.Volume
   106  	if err := v.runtime.eventer.Write(e); err != nil {
   107  		logrus.Errorf("unable to write volume event: %q", err)
   108  	}
   109  }
   110  
   111  // Events is a wrapper function for everyone to begin tailing the events log
   112  // with options
   113  func (r *Runtime) Events(ctx context.Context, options events.ReadOptions) error {
   114  	eventer, err := r.newEventer()
   115  	if err != nil {
   116  		return err
   117  	}
   118  	return eventer.Read(ctx, options)
   119  }
   120  
   121  // GetEvents reads the event log and returns events based on input filters
   122  func (r *Runtime) GetEvents(ctx context.Context, filters []string) ([]*events.Event, error) {
   123  	eventChannel := make(chan *events.Event)
   124  	options := events.ReadOptions{
   125  		EventChannel: eventChannel,
   126  		Filters:      filters,
   127  		FromStart:    true,
   128  		Stream:       false,
   129  	}
   130  	eventer, err := r.newEventer()
   131  	if err != nil {
   132  		return nil, err
   133  	}
   134  
   135  	logEvents := make([]*events.Event, 0, len(eventChannel))
   136  	readLock := sync.Mutex{}
   137  	readLock.Lock()
   138  	go func() {
   139  		for e := range eventChannel {
   140  			logEvents = append(logEvents, e)
   141  		}
   142  		readLock.Unlock()
   143  	}()
   144  
   145  	readErr := eventer.Read(ctx, options)
   146  	readLock.Lock() // Wait for the events to be consumed.
   147  	return logEvents, readErr
   148  }
   149  
   150  // GetLastContainerEvent takes a container name or ID and an event status and returns
   151  // the last occurrence of the container event
   152  func (r *Runtime) GetLastContainerEvent(ctx context.Context, nameOrID string, containerEvent events.Status) (*events.Event, error) {
   153  	// check to make sure the event.Status is valid
   154  	if _, err := events.StringToStatus(containerEvent.String()); err != nil {
   155  		return nil, err
   156  	}
   157  	filters := []string{
   158  		fmt.Sprintf("container=%s", nameOrID),
   159  		fmt.Sprintf("event=%s", containerEvent),
   160  		"type=container",
   161  	}
   162  	containerEvents, err := r.GetEvents(ctx, filters)
   163  	if err != nil {
   164  		return nil, err
   165  	}
   166  	if len(containerEvents) < 1 {
   167  		return nil, errors.Wrapf(events.ErrEventNotFound, "%s not found", containerEvent.String())
   168  	}
   169  	// return the last element in the slice
   170  	return containerEvents[len(containerEvents)-1], nil
   171  }
   172  
   173  // GetExecDiedEvent takes a container name or ID, exec session ID, and returns
   174  // that exec session's Died event (if it has already occurred).
   175  func (r *Runtime) GetExecDiedEvent(ctx context.Context, nameOrID, execSessionID string) (*events.Event, error) {
   176  	filters := []string{
   177  		fmt.Sprintf("container=%s", nameOrID),
   178  		"event=exec_died",
   179  		"type=container",
   180  		fmt.Sprintf("label=execID=%s", execSessionID),
   181  	}
   182  
   183  	containerEvents, err := r.GetEvents(ctx, filters)
   184  	if err != nil {
   185  		return nil, err
   186  	}
   187  	// There *should* only be one event maximum.
   188  	// But... just in case... let's not blow up if there's more than one.
   189  	if len(containerEvents) < 1 {
   190  		return nil, errors.Wrapf(events.ErrEventNotFound, "exec died event for session %s (container %s) not found", execSessionID, nameOrID)
   191  	}
   192  	return containerEvents[len(containerEvents)-1], nil
   193  }