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

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