github.com/vmware/govmomi@v0.43.0/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 if m := ctx.Map.AlarmManager(); m != nil { 170 ctx.WithLock(m, func() { m.postEvent(ctx, req.EventToPost) }) 171 } 172 173 return &methods.PostEventBody{ 174 Res: new(types.PostEventResponse), 175 } 176 } 177 178 type EventHistoryCollector struct { 179 mo.EventHistoryCollector 180 181 *HistoryCollector 182 } 183 184 // doEntityEventArgument calls f for each entity argument in the event. 185 // If f returns true, the iteration stops. 186 func doEntityEventArgument(event types.BaseEvent, f func(types.ManagedObjectReference, *types.EntityEventArgument) bool) bool { 187 e := event.GetEvent() 188 189 if arg := e.Vm; arg != nil { 190 if f(arg.Vm, &arg.EntityEventArgument) { 191 return true 192 } 193 } 194 195 if arg := e.Host; arg != nil { 196 if f(arg.Host, &arg.EntityEventArgument) { 197 return true 198 } 199 } 200 201 if arg := e.ComputeResource; arg != nil { 202 if f(arg.ComputeResource, &arg.EntityEventArgument) { 203 return true 204 } 205 } 206 207 if arg := e.Ds; arg != nil { 208 if f(arg.Datastore, &arg.EntityEventArgument) { 209 return true 210 } 211 } 212 213 if arg := e.Net; arg != nil { 214 if f(arg.Network, &arg.EntityEventArgument) { 215 return true 216 } 217 } 218 219 if arg := e.Dvs; arg != nil { 220 if f(arg.Dvs, &arg.EntityEventArgument) { 221 return true 222 } 223 } 224 225 if arg := e.Datacenter; arg != nil { 226 if f(arg.Datacenter, &arg.EntityEventArgument) { 227 return true 228 } 229 } 230 231 return false 232 } 233 234 // eventFilterSelf returns true if self is one of the entity arguments in the event. 235 func eventFilterSelf(event types.BaseEvent, self types.ManagedObjectReference) bool { 236 if x, ok := event.(*types.EventEx); ok { 237 if self.Type == x.ObjectType && self.Value == x.ObjectId { 238 return true 239 } 240 } 241 return doEntityEventArgument(event, func(ref types.ManagedObjectReference, _ *types.EntityEventArgument) bool { 242 return self == ref 243 }) 244 } 245 246 // eventFilterChildren returns true if a child of self is one of the entity arguments in the event. 247 func eventFilterChildren(ctx *Context, root types.ManagedObjectReference, event types.BaseEvent) bool { 248 return doEntityEventArgument(event, func(ref types.ManagedObjectReference, _ *types.EntityEventArgument) bool { 249 seen := false 250 251 var match func(types.ManagedObjectReference) 252 253 match = func(child types.ManagedObjectReference) { 254 if child == ref { 255 seen = true 256 return 257 } 258 259 walk(ctx.Map.Get(child), match) 260 } 261 262 walk(ctx.Map.Get(root), match) 263 264 return seen 265 }) 266 } 267 268 // entityMatches returns true if the spec Entity filter matches the event. 269 func (c *EventHistoryCollector) entityMatches(ctx *Context, event types.BaseEvent, spec *types.EventFilterSpec) bool { 270 e := spec.Entity 271 if e == nil { 272 return true 273 } 274 275 isRootFolder := c.root == e.Entity 276 277 switch e.Recursion { 278 case types.EventFilterSpecRecursionOptionSelf: 279 return isRootFolder || eventFilterSelf(event, e.Entity) 280 case types.EventFilterSpecRecursionOptionChildren: 281 return eventFilterChildren(ctx, e.Entity, event) 282 case types.EventFilterSpecRecursionOptionAll: 283 if isRootFolder || eventFilterSelf(event, e.Entity) { 284 return true 285 } 286 return eventFilterChildren(ctx, e.Entity, event) 287 } 288 289 return false 290 } 291 292 // chainMatches returns true if spec.EventChainId matches the event. 293 func (c *EventHistoryCollector) chainMatches(_ *Context, event types.BaseEvent, spec *types.EventFilterSpec) bool { 294 e := event.GetEvent() 295 if spec.EventChainId != 0 { 296 if e.ChainId != spec.EventChainId { 297 return false 298 } 299 } 300 return true 301 } 302 303 // typeMatches returns true if one of the spec EventTypeId types matches the event. 304 func (c *EventHistoryCollector) typeMatches(_ *Context, event types.BaseEvent, spec *types.EventFilterSpec) bool { 305 if len(spec.EventTypeId) == 0 { 306 return true 307 } 308 309 matches := func(name string) bool { 310 for _, id := range spec.EventTypeId { 311 if id == name { 312 return true 313 } 314 } 315 return false 316 } 317 318 if x, ok := event.(*types.EventEx); ok { 319 return matches(x.EventTypeId) 320 } 321 322 kind := reflect.ValueOf(event).Elem().Type() 323 324 if matches(kind.Name()) { 325 return true // concrete type 326 } 327 328 field, ok := kind.FieldByNameFunc(matches) 329 if ok { 330 return field.Anonymous // base type (embedded field) 331 } 332 return false 333 } 334 335 func (c *EventHistoryCollector) timeMatches(_ *Context, event types.BaseEvent, spec *types.EventFilterSpec) bool { 336 if spec.Time == nil { 337 return true 338 } 339 340 created := event.GetEvent().CreatedTime 341 342 if begin := spec.Time.BeginTime; begin != nil { 343 if created.Before(*begin) { 344 return false 345 } 346 } 347 348 if end := spec.Time.EndTime; end != nil { 349 if created.After(*end) { 350 return false 351 } 352 } 353 354 return true 355 } 356 357 // eventMatches returns true one of the filters matches the event. 358 func (c *EventHistoryCollector) eventMatches(ctx *Context, event types.BaseEvent) bool { 359 spec := c.Filter.(types.EventFilterSpec) 360 361 matchers := []func(*Context, types.BaseEvent, *types.EventFilterSpec) bool{ 362 c.chainMatches, 363 c.typeMatches, 364 c.timeMatches, 365 c.entityMatches, 366 // TODO: spec.UserName, etc 367 } 368 369 for _, match := range matchers { 370 if !match(ctx, event, &spec) { 371 return false 372 } 373 } 374 375 return true 376 } 377 378 // fillPage copies the manager's latest events into the collector's page with Filter applied. 379 func (m *EventManager) fillPage(ctx *Context, c *EventHistoryCollector) { 380 m.history.Lock() 381 defer m.history.Unlock() 382 383 for e := m.history.page.Front(); e != nil; e = e.Next() { 384 event := e.Value.(types.BaseEvent) 385 if c.eventMatches(ctx, event) { 386 c.page.PushBack(event) 387 } 388 } 389 } 390 391 func (c *EventHistoryCollector) ReadNextEvents(ctx *Context, req *types.ReadNextEvents) soap.HasFault { 392 body := &methods.ReadNextEventsBody{} 393 if req.MaxCount <= 0 { 394 body.Fault_ = Fault("", errInvalidArgMaxCount) 395 return body 396 } 397 body.Res = new(types.ReadNextEventsResponse) 398 399 c.next(req.MaxCount, func(e *list.Element) { 400 body.Res.Returnval = append(body.Res.Returnval, e.Value.(types.BaseEvent)) 401 }) 402 403 return body 404 } 405 406 func (c *EventHistoryCollector) ReadPreviousEvents(ctx *Context, req *types.ReadPreviousEvents) soap.HasFault { 407 body := &methods.ReadPreviousEventsBody{} 408 if req.MaxCount <= 0 { 409 body.Fault_ = Fault("", errInvalidArgMaxCount) 410 return body 411 } 412 body.Res = new(types.ReadPreviousEventsResponse) 413 414 c.prev(req.MaxCount, func(e *list.Element) { 415 body.Res.Returnval = append(body.Res.Returnval, e.Value.(types.BaseEvent)) 416 }) 417 418 return body 419 } 420 421 func (c *EventHistoryCollector) GetLatestPage() []types.BaseEvent { 422 var latestPage []types.BaseEvent 423 424 e := c.page.Back() 425 for i := 0; i < c.size; i++ { 426 if e == nil { 427 break 428 } 429 latestPage = append(latestPage, e.Value.(types.BaseEvent)) 430 e = e.Prev() 431 } 432 433 return latestPage 434 } 435 436 func (c *EventHistoryCollector) Get() mo.Reference { 437 clone := *c 438 439 clone.LatestPage = clone.GetLatestPage() 440 441 return &clone 442 }