github.com/vmware/govmomi@v0.37.1/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 }