github.com/google/cadvisor@v0.49.1/events/handler.go (about)

     1  // Copyright 2015 Google Inc. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package events
    16  
    17  import (
    18  	"errors"
    19  	"sort"
    20  	"strings"
    21  	"sync"
    22  	"time"
    23  
    24  	info "github.com/google/cadvisor/info/v1"
    25  	"github.com/google/cadvisor/utils"
    26  
    27  	"k8s.io/klog/v2"
    28  )
    29  
    30  type byTimestamp []*info.Event
    31  
    32  // functions necessary to implement the sort interface on the Events struct
    33  func (e byTimestamp) Len() int {
    34  	return len(e)
    35  }
    36  
    37  func (e byTimestamp) Swap(i, j int) {
    38  	e[i], e[j] = e[j], e[i]
    39  }
    40  
    41  func (e byTimestamp) Less(i, j int) bool {
    42  	return e[i].Timestamp.Before(e[j].Timestamp)
    43  }
    44  
    45  type EventChannel struct {
    46  	// Watch ID. Can be used by the caller to request cancellation of watch events.
    47  	watchID int
    48  	// Channel on which the caller can receive watch events.
    49  	channel chan *info.Event
    50  }
    51  
    52  // Request holds a set of parameters by which Event objects may be screened.
    53  // The caller may want events that occurred within a specific timeframe
    54  // or of a certain type, which may be specified in the *Request object
    55  // they pass to an EventManager function
    56  type Request struct {
    57  	// events falling before StartTime do not satisfy the request. StartTime
    58  	// must be left blank in calls to WatchEvents
    59  	StartTime time.Time
    60  	// events falling after EndTime do not satisfy the request. EndTime
    61  	// must be left blank in calls to WatchEvents
    62  	EndTime time.Time
    63  	// EventType is a map that specifies the type(s) of events wanted
    64  	EventType map[info.EventType]bool
    65  	// allows the caller to put a limit on how many
    66  	// events to receive. If there are more events than MaxEventsReturned
    67  	// then the most chronologically recent events in the time period
    68  	// specified are returned. Must be >= 1
    69  	MaxEventsReturned int
    70  	// the absolute container name for which the event occurred
    71  	ContainerName string
    72  	// if IncludeSubcontainers is false, only events occurring in the specific
    73  	// container, and not the subcontainers, will be returned
    74  	IncludeSubcontainers bool
    75  }
    76  
    77  // EventManager is implemented by Events. It provides two ways to monitor
    78  // events and one way to add events
    79  type EventManager interface {
    80  	// WatchEvents() allows a caller to register for receiving events based on the specified request.
    81  	// On successful registration, an EventChannel object is returned.
    82  	WatchEvents(request *Request) (*EventChannel, error)
    83  	// GetEvents() returns all detected events based on the filters specified in request.
    84  	GetEvents(request *Request) ([]*info.Event, error)
    85  	// AddEvent allows the caller to add an event to an EventManager
    86  	// object
    87  	AddEvent(event *info.Event) error
    88  	// Cancels a previously requested watch event.
    89  	StopWatch(watchID int)
    90  }
    91  
    92  // events provides an implementation for the EventManager interface.
    93  type events struct {
    94  	// eventStore holds the events by event type.
    95  	eventStore map[info.EventType]*utils.TimedStore
    96  	// map of registered watchers keyed by watch id.
    97  	watchers map[int]*watch
    98  	// lock guarding the eventStore.
    99  	eventsLock sync.RWMutex
   100  	// lock guarding watchers.
   101  	watcherLock sync.RWMutex
   102  	// last allocated watch id.
   103  	lastID int
   104  	// Event storage policy.
   105  	storagePolicy StoragePolicy
   106  }
   107  
   108  // initialized by a call to WatchEvents(), a watch struct will then be added
   109  // to the events slice of *watch objects. When AddEvent() finds an event that
   110  // satisfies the request parameter of a watch object in events.watchers,
   111  // it will send that event out over the watch object's channel. The caller that
   112  // called WatchEvents will receive the event over the channel provided to
   113  // WatchEvents
   114  type watch struct {
   115  	// request parameters passed in by the caller of WatchEvents()
   116  	request *Request
   117  	// a channel used to send event back to the caller.
   118  	eventChannel *EventChannel
   119  }
   120  
   121  func NewEventChannel(watchID int) *EventChannel {
   122  	return &EventChannel{
   123  		watchID: watchID,
   124  		channel: make(chan *info.Event, 10),
   125  	}
   126  }
   127  
   128  // Policy specifying how many events to store.
   129  // MaxAge is the max duration for which to keep events.
   130  // MaxNumEvents is the max number of events to keep (-1 for no limit).
   131  type StoragePolicy struct {
   132  	// Defaults limites, used if a per-event limit is not set.
   133  	DefaultMaxAge       time.Duration
   134  	DefaultMaxNumEvents int
   135  
   136  	// Per-event type limits.
   137  	PerTypeMaxAge       map[info.EventType]time.Duration
   138  	PerTypeMaxNumEvents map[info.EventType]int
   139  }
   140  
   141  func DefaultStoragePolicy() StoragePolicy {
   142  	return StoragePolicy{
   143  		DefaultMaxAge:       24 * time.Hour,
   144  		DefaultMaxNumEvents: 100000,
   145  		PerTypeMaxAge:       make(map[info.EventType]time.Duration),
   146  		PerTypeMaxNumEvents: make(map[info.EventType]int),
   147  	}
   148  }
   149  
   150  // returns a pointer to an initialized Events object.
   151  func NewEventManager(storagePolicy StoragePolicy) EventManager {
   152  	return &events{
   153  		eventStore:    make(map[info.EventType]*utils.TimedStore),
   154  		watchers:      make(map[int]*watch),
   155  		storagePolicy: storagePolicy,
   156  	}
   157  }
   158  
   159  // returns a pointer to an initialized Request object
   160  func NewRequest() *Request {
   161  	return &Request{
   162  		EventType:            map[info.EventType]bool{},
   163  		IncludeSubcontainers: false,
   164  		MaxEventsReturned:    10,
   165  	}
   166  }
   167  
   168  // returns a pointer to an initialized watch object
   169  func newWatch(request *Request, eventChannel *EventChannel) *watch {
   170  	return &watch{
   171  		request:      request,
   172  		eventChannel: eventChannel,
   173  	}
   174  }
   175  
   176  func (ch *EventChannel) GetChannel() chan *info.Event {
   177  	return ch.channel
   178  }
   179  
   180  func (ch *EventChannel) GetWatchId() int {
   181  	return ch.watchID
   182  }
   183  
   184  // sorts and returns up to the last MaxEventsReturned chronological elements
   185  func getMaxEventsReturned(request *Request, eSlice []*info.Event) []*info.Event {
   186  	sort.Sort(byTimestamp(eSlice))
   187  	n := request.MaxEventsReturned
   188  	if n >= len(eSlice) || n <= 0 {
   189  		return eSlice
   190  	}
   191  	return eSlice[len(eSlice)-n:]
   192  }
   193  
   194  // If the request wants all subcontainers, this returns if the request's
   195  // container path is a prefix of the event container path.  Otherwise,
   196  // it checks that the container paths of the event and request are
   197  // equivalent
   198  func isSubcontainer(request *Request, event *info.Event) bool {
   199  	if request.IncludeSubcontainers {
   200  		return request.ContainerName == "/" || strings.HasPrefix(event.ContainerName+"/", request.ContainerName+"/")
   201  	}
   202  	return event.ContainerName == request.ContainerName
   203  }
   204  
   205  // determines if an event occurs within the time set in the request object and is the right type
   206  func checkIfEventSatisfiesRequest(request *Request, event *info.Event) bool {
   207  	startTime := request.StartTime
   208  	endTime := request.EndTime
   209  	eventTime := event.Timestamp
   210  	if !startTime.IsZero() {
   211  		if startTime.After(eventTime) {
   212  			return false
   213  		}
   214  	}
   215  	if !endTime.IsZero() {
   216  		if endTime.Before(eventTime) {
   217  			return false
   218  		}
   219  	}
   220  	if !request.EventType[event.EventType] {
   221  		return false
   222  	}
   223  	if request.ContainerName != "" {
   224  		return isSubcontainer(request, event)
   225  	}
   226  	return true
   227  }
   228  
   229  // method of Events object that screens Event objects found in the eventStore
   230  // attribute and if they fit the parameters passed by the Request object,
   231  // adds it to a slice of *Event objects that is returned. If both MaxEventsReturned
   232  // and StartTime/EndTime are specified in the request object, then only
   233  // up to the most recent MaxEventsReturned events in that time range are returned.
   234  func (e *events) GetEvents(request *Request) ([]*info.Event, error) {
   235  	returnEventList := []*info.Event{}
   236  	e.eventsLock.RLock()
   237  	defer e.eventsLock.RUnlock()
   238  	for eventType, fetch := range request.EventType {
   239  		if !fetch {
   240  			continue
   241  		}
   242  		evs, ok := e.eventStore[eventType]
   243  		if !ok {
   244  			continue
   245  		}
   246  
   247  		res := evs.InTimeRange(request.StartTime, request.EndTime, request.MaxEventsReturned)
   248  		for _, in := range res {
   249  			e := in.(*info.Event)
   250  			if checkIfEventSatisfiesRequest(request, e) {
   251  				returnEventList = append(returnEventList, e)
   252  			}
   253  		}
   254  	}
   255  	returnEventList = getMaxEventsReturned(request, returnEventList)
   256  	return returnEventList, nil
   257  }
   258  
   259  // method of Events object that maintains an *Event channel passed by the user.
   260  // When an event is added by AddEvents that satisfies the parameters in the passed
   261  // Request object it is fed to the channel. The StartTime and EndTime of the watch
   262  // request should be uninitialized because the purpose is to watch indefinitely
   263  // for events that will happen in the future
   264  func (e *events) WatchEvents(request *Request) (*EventChannel, error) {
   265  	if !request.StartTime.IsZero() || !request.EndTime.IsZero() {
   266  		return nil, errors.New(
   267  			"for a call to watch, request.StartTime and request.EndTime must be uninitialized")
   268  	}
   269  	e.watcherLock.Lock()
   270  	defer e.watcherLock.Unlock()
   271  	newID := e.lastID + 1
   272  	returnEventChannel := NewEventChannel(newID)
   273  	newWatcher := newWatch(request, returnEventChannel)
   274  	e.watchers[newID] = newWatcher
   275  	e.lastID = newID
   276  	return returnEventChannel, nil
   277  }
   278  
   279  // helper function to update the event manager's eventStore
   280  func (e *events) updateEventStore(event *info.Event) {
   281  	e.eventsLock.Lock()
   282  	defer e.eventsLock.Unlock()
   283  	if _, ok := e.eventStore[event.EventType]; !ok {
   284  		maxNumEvents := e.storagePolicy.DefaultMaxNumEvents
   285  		if numEvents, ok := e.storagePolicy.PerTypeMaxNumEvents[event.EventType]; ok {
   286  			maxNumEvents = numEvents
   287  		}
   288  		if maxNumEvents == 0 {
   289  			// Event storage is disabled for event.EventType
   290  			return
   291  		}
   292  
   293  		maxAge := e.storagePolicy.DefaultMaxAge
   294  		if age, ok := e.storagePolicy.PerTypeMaxAge[event.EventType]; ok {
   295  			maxAge = age
   296  		}
   297  
   298  		e.eventStore[event.EventType] = utils.NewTimedStore(maxAge, maxNumEvents)
   299  	}
   300  	e.eventStore[event.EventType].Add(event.Timestamp, event)
   301  }
   302  
   303  func (e *events) findValidWatchers(event *info.Event) []*watch {
   304  	watchesToSend := make([]*watch, 0)
   305  	for _, watcher := range e.watchers {
   306  		watchRequest := watcher.request
   307  		if checkIfEventSatisfiesRequest(watchRequest, event) {
   308  			watchesToSend = append(watchesToSend, watcher)
   309  		}
   310  	}
   311  	return watchesToSend
   312  }
   313  
   314  // method of Events object that adds the argument Event object to the
   315  // eventStore. It also feeds the event to a set of watch channels
   316  // held by the manager if it satisfies the request keys of the channels
   317  func (e *events) AddEvent(event *info.Event) error {
   318  	e.updateEventStore(event)
   319  	e.watcherLock.RLock()
   320  	defer e.watcherLock.RUnlock()
   321  	watchesToSend := e.findValidWatchers(event)
   322  	for _, watchObject := range watchesToSend {
   323  		watchObject.eventChannel.GetChannel() <- event
   324  	}
   325  	klog.V(4).Infof("Added event %v", event)
   326  	return nil
   327  }
   328  
   329  // Removes a watch instance from the EventManager's watchers map
   330  func (e *events) StopWatch(watchID int) {
   331  	e.watcherLock.Lock()
   332  	defer e.watcherLock.Unlock()
   333  	_, ok := e.watchers[watchID]
   334  	if !ok {
   335  		klog.Errorf("Could not find watcher instance %v", watchID)
   336  	}
   337  	close(e.watchers[watchID].eventChannel.GetChannel())
   338  	delete(e.watchers, watchID)
   339  }