github.com/vmware/govmomi@v0.51.0/simulator/event_manager.go (about)

     1  // © Broadcom. All Rights Reserved.
     2  // The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
     3  // SPDX-License-Identifier: Apache-2.0
     4  
     5  package simulator
     6  
     7  import (
     8  	"bytes"
     9  	"container/list"
    10  	"log"
    11  	"reflect"
    12  	"text/template"
    13  	"time"
    14  
    15  	"github.com/vmware/govmomi/simulator/esx"
    16  	"github.com/vmware/govmomi/vim25/methods"
    17  	"github.com/vmware/govmomi/vim25/mo"
    18  	"github.com/vmware/govmomi/vim25/soap"
    19  	"github.com/vmware/govmomi/vim25/types"
    20  )
    21  
    22  var (
    23  	logEvents = false
    24  )
    25  
    26  type EventManager struct {
    27  	mo.EventManager
    28  
    29  	history   *history
    30  	key       int32
    31  	templates map[string]*template.Template
    32  }
    33  
    34  func (m *EventManager) init(r *Registry) {
    35  	if len(m.Description.EventInfo) == 0 {
    36  		m.Description.EventInfo = esx.EventInfo
    37  	}
    38  	if m.MaxCollector == 0 {
    39  		// In real VC this default can be changed via OptionManager "event.maxCollectors"
    40  		m.MaxCollector = maxCollectors
    41  	}
    42  
    43  	m.history = newHistory()
    44  	m.templates = make(map[string]*template.Template)
    45  }
    46  
    47  func (m *EventManager) createCollector(ctx *Context, req *types.CreateCollectorForEvents) (*EventHistoryCollector, *soap.Fault) {
    48  	size, err := validatePageSize(req.Filter.MaxCount)
    49  	if err != nil {
    50  		return nil, err
    51  	}
    52  
    53  	if len(m.history.collectors) >= int(m.MaxCollector) {
    54  		return nil, Fault("Too many event collectors to create", new(types.InvalidState))
    55  	}
    56  
    57  	collector := &EventHistoryCollector{
    58  		HistoryCollector: newHistoryCollector(ctx, m.history, size),
    59  	}
    60  	collector.Filter = req.Filter
    61  
    62  	return collector, nil
    63  }
    64  
    65  func (m *EventManager) CreateCollectorForEvents(ctx *Context, req *types.CreateCollectorForEvents) soap.HasFault {
    66  	body := new(methods.CreateCollectorForEventsBody)
    67  	collector, err := m.createCollector(ctx, req)
    68  	if err != nil {
    69  		body.Fault_ = err
    70  		return body
    71  	}
    72  
    73  	collector.fill = func(x *Context) { m.fillPage(x, collector) }
    74  	collector.fill(ctx)
    75  
    76  	body.Res = &types.CreateCollectorForEventsResponse{
    77  		Returnval: m.history.add(ctx, collector),
    78  	}
    79  
    80  	return body
    81  }
    82  
    83  func (m *EventManager) QueryEvents(ctx *Context, req *types.QueryEvents) soap.HasFault {
    84  	if ctx.Map.IsESX() {
    85  		return &methods.QueryEventsBody{
    86  			Fault_: Fault("", new(types.NotImplemented)),
    87  		}
    88  	}
    89  
    90  	body := new(methods.QueryEventsBody)
    91  	collector, err := m.createCollector(ctx, &types.CreateCollectorForEvents{Filter: req.Filter})
    92  	if err != nil {
    93  		body.Fault_ = err
    94  		return body
    95  	}
    96  
    97  	m.fillPage(ctx, collector)
    98  
    99  	body.Res = &types.QueryEventsResponse{
   100  		Returnval: collector.GetLatestPage(),
   101  	}
   102  
   103  	return body
   104  }
   105  
   106  // formatMessage applies the EventDescriptionEventDetail.FullFormat template to the given event's FullFormattedMessage field.
   107  func (m *EventManager) formatMessage(event types.BaseEvent) {
   108  	id := reflect.ValueOf(event).Elem().Type().Name()
   109  	e := event.GetEvent()
   110  
   111  	t, ok := m.templates[id]
   112  	if !ok {
   113  		for _, info := range m.Description.EventInfo {
   114  			if info.Key == id {
   115  				t = template.Must(template.New(id).Parse(info.FullFormat))
   116  				m.templates[id] = t
   117  				break
   118  			}
   119  		}
   120  	}
   121  
   122  	if t != nil {
   123  		var buf bytes.Buffer
   124  		if err := t.Execute(&buf, event); err != nil {
   125  			log.Print(err)
   126  		}
   127  		e.FullFormattedMessage = buf.String()
   128  	}
   129  
   130  	if logEvents {
   131  		log.Printf("[%s] %s", id, e.FullFormattedMessage)
   132  	}
   133  }
   134  
   135  func (m *EventManager) PostEvent(ctx *Context, req *types.PostEvent) soap.HasFault {
   136  	m.key++
   137  	event := req.EventToPost.GetEvent()
   138  	event.Key = m.key
   139  	event.ChainId = event.Key
   140  	event.CreatedTime = time.Now()
   141  	event.UserName = ctx.Session.UserName
   142  
   143  	m.formatMessage(req.EventToPost)
   144  
   145  	pushHistory(m.history.page, req.EventToPost)
   146  
   147  	for _, hc := range m.history.collectors {
   148  		c := hc.(*EventHistoryCollector)
   149  		ctx.WithLock(c, func() {
   150  			if c.eventMatches(ctx, req.EventToPost) {
   151  				pushHistory(c.page, req.EventToPost)
   152  				ctx.Update(c, []types.PropertyChange{{Name: "latestPage", Val: c.GetLatestPage()}})
   153  			}
   154  		})
   155  	}
   156  
   157  	if m := ctx.Map.AlarmManager(); m != nil {
   158  		ctx.WithLock(m, func() { m.postEvent(ctx, req.EventToPost) })
   159  	}
   160  
   161  	return &methods.PostEventBody{
   162  		Res: new(types.PostEventResponse),
   163  	}
   164  }
   165  
   166  type EventHistoryCollector struct {
   167  	mo.EventHistoryCollector
   168  
   169  	*HistoryCollector
   170  }
   171  
   172  // doEntityEventArgument calls f for each entity argument in the event.
   173  // If f returns true, the iteration stops.
   174  func doEntityEventArgument(event types.BaseEvent, f func(types.ManagedObjectReference, *types.EntityEventArgument) bool) bool {
   175  	e := event.GetEvent()
   176  
   177  	if arg := e.Vm; arg != nil {
   178  		if f(arg.Vm, &arg.EntityEventArgument) {
   179  			return true
   180  		}
   181  	}
   182  
   183  	if arg := e.Host; arg != nil {
   184  		if f(arg.Host, &arg.EntityEventArgument) {
   185  			return true
   186  		}
   187  	}
   188  
   189  	if arg := e.ComputeResource; arg != nil {
   190  		if f(arg.ComputeResource, &arg.EntityEventArgument) {
   191  			return true
   192  		}
   193  	}
   194  
   195  	if arg := e.Ds; arg != nil {
   196  		if f(arg.Datastore, &arg.EntityEventArgument) {
   197  			return true
   198  		}
   199  	}
   200  
   201  	if arg := e.Net; arg != nil {
   202  		if f(arg.Network, &arg.EntityEventArgument) {
   203  			return true
   204  		}
   205  	}
   206  
   207  	if arg := e.Dvs; arg != nil {
   208  		if f(arg.Dvs, &arg.EntityEventArgument) {
   209  			return true
   210  		}
   211  	}
   212  
   213  	if arg := e.Datacenter; arg != nil {
   214  		if f(arg.Datacenter, &arg.EntityEventArgument) {
   215  			return true
   216  		}
   217  	}
   218  
   219  	return false
   220  }
   221  
   222  // eventFilterSelf returns true if self is one of the entity arguments in the event.
   223  func eventFilterSelf(event types.BaseEvent, self types.ManagedObjectReference) bool {
   224  	if x, ok := event.(*types.EventEx); ok {
   225  		if self.Type == x.ObjectType && self.Value == x.ObjectId {
   226  			return true
   227  		}
   228  	}
   229  	return doEntityEventArgument(event, func(ref types.ManagedObjectReference, _ *types.EntityEventArgument) bool {
   230  		return self == ref
   231  	})
   232  }
   233  
   234  // eventFilterChildren returns true if a child of self is one of the entity arguments in the event.
   235  func eventFilterChildren(ctx *Context, root types.ManagedObjectReference, event types.BaseEvent) bool {
   236  	return doEntityEventArgument(event, func(ref types.ManagedObjectReference, _ *types.EntityEventArgument) bool {
   237  		seen := false
   238  
   239  		var match func(types.ManagedObjectReference)
   240  
   241  		match = func(child types.ManagedObjectReference) {
   242  			if child == ref {
   243  				seen = true
   244  				return
   245  			}
   246  
   247  			walk(ctx.Map.Get(child), match)
   248  		}
   249  
   250  		walk(ctx.Map.Get(root), match)
   251  
   252  		return seen
   253  	})
   254  }
   255  
   256  // entityMatches returns true if the spec Entity filter matches the event.
   257  func (c *EventHistoryCollector) entityMatches(ctx *Context, event types.BaseEvent, spec *types.EventFilterSpec) bool {
   258  	e := spec.Entity
   259  	if e == nil {
   260  		return true
   261  	}
   262  
   263  	isRootFolder := c.root == e.Entity
   264  
   265  	switch e.Recursion {
   266  	case types.EventFilterSpecRecursionOptionSelf:
   267  		return isRootFolder || eventFilterSelf(event, e.Entity)
   268  	case types.EventFilterSpecRecursionOptionChildren:
   269  		return eventFilterChildren(ctx, e.Entity, event)
   270  	case types.EventFilterSpecRecursionOptionAll:
   271  		if isRootFolder || eventFilterSelf(event, e.Entity) {
   272  			return true
   273  		}
   274  		return eventFilterChildren(ctx, e.Entity, event)
   275  	}
   276  
   277  	return false
   278  }
   279  
   280  // chainMatches returns true if spec.EventChainId matches the event.
   281  func (c *EventHistoryCollector) chainMatches(_ *Context, event types.BaseEvent, spec *types.EventFilterSpec) bool {
   282  	e := event.GetEvent()
   283  	if spec.EventChainId != 0 {
   284  		if e.ChainId != spec.EventChainId {
   285  			return false
   286  		}
   287  	}
   288  	return true
   289  }
   290  
   291  // typeMatches returns true if one of the spec EventTypeId types matches the event.
   292  func (c *EventHistoryCollector) typeMatches(_ *Context, event types.BaseEvent, spec *types.EventFilterSpec) bool {
   293  	if len(spec.EventTypeId) == 0 {
   294  		return true
   295  	}
   296  
   297  	matches := func(name string) bool {
   298  		for _, id := range spec.EventTypeId {
   299  			if id == name {
   300  				return true
   301  			}
   302  		}
   303  		return false
   304  	}
   305  
   306  	if x, ok := event.(*types.EventEx); ok {
   307  		return matches(x.EventTypeId)
   308  	}
   309  
   310  	kind := reflect.ValueOf(event).Elem().Type()
   311  
   312  	if matches(kind.Name()) {
   313  		return true // concrete type
   314  	}
   315  
   316  	field, ok := kind.FieldByNameFunc(matches)
   317  	if ok {
   318  		return field.Anonymous // base type (embedded field)
   319  	}
   320  	return false
   321  }
   322  
   323  func (c *EventHistoryCollector) timeMatches(_ *Context, event types.BaseEvent, spec *types.EventFilterSpec) bool {
   324  	if spec.Time == nil {
   325  		return true
   326  	}
   327  
   328  	created := event.GetEvent().CreatedTime
   329  
   330  	if begin := spec.Time.BeginTime; begin != nil {
   331  		if created.Before(*begin) {
   332  			return false
   333  		}
   334  	}
   335  
   336  	if end := spec.Time.EndTime; end != nil {
   337  		if created.After(*end) {
   338  			return false
   339  		}
   340  	}
   341  
   342  	return true
   343  }
   344  
   345  // eventMatches returns true one of the filters matches the event.
   346  func (c *EventHistoryCollector) eventMatches(ctx *Context, event types.BaseEvent) bool {
   347  	spec := c.Filter.(types.EventFilterSpec)
   348  
   349  	matchers := []func(*Context, types.BaseEvent, *types.EventFilterSpec) bool{
   350  		c.chainMatches,
   351  		c.typeMatches,
   352  		c.timeMatches,
   353  		c.entityMatches,
   354  		// TODO: spec.UserName, etc
   355  	}
   356  
   357  	for _, match := range matchers {
   358  		if !match(ctx, event, &spec) {
   359  			return false
   360  		}
   361  	}
   362  
   363  	return true
   364  }
   365  
   366  // fillPage copies the manager's latest events into the collector's page with Filter applied.
   367  func (m *EventManager) fillPage(ctx *Context, c *EventHistoryCollector) {
   368  	m.history.Lock()
   369  	defer m.history.Unlock()
   370  
   371  	for e := m.history.page.Front(); e != nil; e = e.Next() {
   372  		event := e.Value.(types.BaseEvent)
   373  		if c.eventMatches(ctx, event) {
   374  			c.page.PushBack(event)
   375  		}
   376  	}
   377  }
   378  
   379  func (c *EventHistoryCollector) ReadNextEvents(ctx *Context, req *types.ReadNextEvents) soap.HasFault {
   380  	body := &methods.ReadNextEventsBody{}
   381  	if req.MaxCount <= 0 {
   382  		body.Fault_ = Fault("", errInvalidArgMaxCount)
   383  		return body
   384  	}
   385  	body.Res = new(types.ReadNextEventsResponse)
   386  
   387  	c.next(req.MaxCount, func(e *list.Element) {
   388  		body.Res.Returnval = append(body.Res.Returnval, e.Value.(types.BaseEvent))
   389  	})
   390  
   391  	return body
   392  }
   393  
   394  func (c *EventHistoryCollector) ReadPreviousEvents(ctx *Context, req *types.ReadPreviousEvents) soap.HasFault {
   395  	body := &methods.ReadPreviousEventsBody{}
   396  	if req.MaxCount <= 0 {
   397  		body.Fault_ = Fault("", errInvalidArgMaxCount)
   398  		return body
   399  	}
   400  	body.Res = new(types.ReadPreviousEventsResponse)
   401  
   402  	c.prev(req.MaxCount, func(e *list.Element) {
   403  		body.Res.Returnval = append(body.Res.Returnval, e.Value.(types.BaseEvent))
   404  	})
   405  
   406  	return body
   407  }
   408  
   409  func (c *EventHistoryCollector) GetLatestPage() []types.BaseEvent {
   410  	var latestPage []types.BaseEvent
   411  
   412  	e := c.page.Back()
   413  	for i := 0; i < c.size; i++ {
   414  		if e == nil {
   415  			break
   416  		}
   417  		latestPage = append(latestPage, e.Value.(types.BaseEvent))
   418  		e = e.Prev()
   419  	}
   420  
   421  	return latestPage
   422  }
   423  
   424  func (c *EventHistoryCollector) Get() mo.Reference {
   425  	clone := *c
   426  
   427  	clone.LatestPage = clone.GetLatestPage()
   428  
   429  	return &clone
   430  }