github.com/containers/podman/v4@v4.9.4/libpod/events/filters.go (about)

     1  package events
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"time"
     7  
     8  	"github.com/containers/podman/v4/pkg/util"
     9  )
    10  
    11  func generateEventFilter(filter, filterValue string) (func(e *Event) bool, error) {
    12  	switch strings.ToUpper(filter) {
    13  	case "CONTAINER":
    14  		return func(e *Event) bool {
    15  			if e.Type != Container {
    16  				return false
    17  			}
    18  			if e.Name == filterValue {
    19  				return true
    20  			}
    21  			return strings.HasPrefix(e.ID, filterValue)
    22  		}, nil
    23  	case "EVENT", "STATUS":
    24  		if filterValue == "die" { // Docker compat
    25  			filterValue = "died"
    26  		}
    27  		return func(e *Event) bool {
    28  			return string(e.Status) == filterValue
    29  		}, nil
    30  	case "IMAGE":
    31  		return func(e *Event) bool {
    32  			if e.Type != Image {
    33  				return false
    34  			}
    35  			if e.Name == filterValue {
    36  				return true
    37  			}
    38  			return strings.HasPrefix(e.ID, filterValue)
    39  		}, nil
    40  	case "POD":
    41  		return func(e *Event) bool {
    42  			if e.Type != Pod {
    43  				return false
    44  			}
    45  			if e.Name == filterValue {
    46  				return true
    47  			}
    48  			return strings.HasPrefix(e.ID, filterValue)
    49  		}, nil
    50  	case "VOLUME":
    51  		return func(e *Event) bool {
    52  			if e.Type != Volume {
    53  				return false
    54  			}
    55  			// Prefix match with name for consistency with docker
    56  			return strings.HasPrefix(e.Name, filterValue)
    57  		}, nil
    58  	case "TYPE":
    59  		return func(e *Event) bool {
    60  			return string(e.Type) == filterValue
    61  		}, nil
    62  
    63  	case "LABEL":
    64  		return func(e *Event) bool {
    65  			var found bool
    66  			// iterate labels and see if we match a key and value
    67  			for eventKey, eventValue := range e.Attributes {
    68  				filterValueSplit := strings.SplitN(filterValue, "=", 2)
    69  				// if the filter isn't right, just return false
    70  				if len(filterValueSplit) < 2 {
    71  					return false
    72  				}
    73  				if eventKey == filterValueSplit[0] && eventValue == filterValueSplit[1] {
    74  					found = true
    75  					break
    76  				}
    77  			}
    78  			return found
    79  		}, nil
    80  	}
    81  	return nil, fmt.Errorf("%s is an invalid filter", filter)
    82  }
    83  
    84  func generateEventSinceOption(timeSince time.Time) func(e *Event) bool {
    85  	return func(e *Event) bool {
    86  		return e.Time.After(timeSince)
    87  	}
    88  }
    89  
    90  func generateEventUntilOption(timeUntil time.Time) func(e *Event) bool {
    91  	return func(e *Event) bool {
    92  		return e.Time.Before(timeUntil)
    93  	}
    94  }
    95  
    96  func parseFilter(filter string) (string, string, error) {
    97  	filterSplit := strings.SplitN(filter, "=", 2)
    98  	if len(filterSplit) != 2 {
    99  		return "", "", fmt.Errorf("%s is an invalid filter", filter)
   100  	}
   101  	return filterSplit[0], filterSplit[1], nil
   102  }
   103  
   104  // applyFilters applies the EventFilter slices in sequence.  Filters under the
   105  // same key are disjunctive while each key must match (conjuctive).
   106  func applyFilters(event *Event, filterMap map[string][]EventFilter) bool {
   107  	for _, filters := range filterMap {
   108  		success := false
   109  		for _, filter := range filters {
   110  			if filter(event) {
   111  				success = true
   112  				break
   113  			}
   114  		}
   115  		if !success {
   116  			return false
   117  		}
   118  	}
   119  	return true
   120  }
   121  
   122  // generateEventFilter parses the specified filters into a filter map that can
   123  // later on be used to filter events.  Keys are conjunctive, values are
   124  // disjunctive.
   125  func generateEventFilters(filters []string, since, until string) (map[string][]EventFilter, error) {
   126  	filterMap := make(map[string][]EventFilter)
   127  	for _, filter := range filters {
   128  		key, val, err := parseFilter(filter)
   129  		if err != nil {
   130  			return nil, err
   131  		}
   132  		filterFunc, err := generateEventFilter(key, val)
   133  		if err != nil {
   134  			return nil, err
   135  		}
   136  		filterSlice := filterMap[key]
   137  		filterSlice = append(filterSlice, filterFunc)
   138  		filterMap[key] = filterSlice
   139  	}
   140  
   141  	if len(since) > 0 {
   142  		timeSince, err := util.ParseInputTime(since, true)
   143  		if err != nil {
   144  			return nil, fmt.Errorf("unable to convert since time of %s: %w", since, err)
   145  		}
   146  		filterFunc := generateEventSinceOption(timeSince)
   147  		filterMap["since"] = []EventFilter{filterFunc}
   148  	}
   149  
   150  	if len(until) > 0 {
   151  		timeUntil, err := util.ParseInputTime(until, false)
   152  		if err != nil {
   153  			return nil, fmt.Errorf("unable to convert until time of %s: %w", until, err)
   154  		}
   155  		filterFunc := generateEventUntilOption(timeUntil)
   156  		filterMap["until"] = []EventFilter{filterFunc}
   157  	}
   158  	return filterMap, nil
   159  }