github.com/vmware/govmomi@v0.51.0/event/processor.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 event 6 7 import ( 8 "context" 9 "fmt" 10 11 "github.com/vmware/govmomi/property" 12 "github.com/vmware/govmomi/view" 13 "github.com/vmware/govmomi/vim25/types" 14 ) 15 16 type tailInfo struct { 17 t *eventTailer 18 obj types.ManagedObjectReference 19 collector *HistoryCollector 20 } 21 22 type eventProcessor struct { 23 mgr Manager 24 pageSize int32 25 kind []string 26 tailers map[types.ManagedObjectReference]*tailInfo // tailers by collector ref 27 callback func(types.ManagedObjectReference, []types.BaseEvent) error 28 } 29 30 func newEventProcessor(mgr Manager, pageSize int32, callback func(types.ManagedObjectReference, []types.BaseEvent) error, kind []string) *eventProcessor { 31 return &eventProcessor{ 32 mgr: mgr, 33 tailers: make(map[types.ManagedObjectReference]*tailInfo), 34 callback: callback, 35 pageSize: pageSize, 36 kind: kind, 37 } 38 } 39 40 func (p *eventProcessor) addObject(ctx context.Context, obj types.ManagedObjectReference) error { 41 filter := types.EventFilterSpec{ 42 Entity: &types.EventFilterSpecByEntity{ 43 Entity: obj, 44 Recursion: types.EventFilterSpecRecursionOptionAll, 45 }, 46 EventTypeId: p.kind, 47 } 48 49 collector, err := p.mgr.CreateCollectorForEvents(ctx, filter) 50 if err != nil { 51 return fmt.Errorf("[%#v] %s", obj, err) 52 } 53 54 err = collector.SetPageSize(ctx, p.pageSize) 55 if err != nil { 56 return err 57 } 58 59 p.tailers[collector.Reference()] = &tailInfo{ 60 t: newEventTailer(), 61 obj: obj, 62 collector: collector, 63 } 64 65 return nil 66 } 67 68 func (p *eventProcessor) destroy() { 69 for _, info := range p.tailers { 70 _ = info.collector.Destroy(context.Background()) 71 } 72 } 73 74 func (p *eventProcessor) run(ctx context.Context, tail bool) error { 75 if len(p.tailers) == 0 { 76 return nil 77 } 78 79 var collectors []types.ManagedObjectReference 80 for ref := range p.tailers { 81 collectors = append(collectors, ref) 82 } 83 84 c := property.DefaultCollector(p.mgr.Client()) 85 props := []string{"latestPage"} 86 87 if len(collectors) == 1 { 88 // only one object to follow, don't bother creating a view 89 return property.Wait(ctx, c, collectors[0], props, func(pc []types.PropertyChange) bool { 90 if err := p.process(collectors[0], pc); err != nil { 91 return false 92 } 93 94 return !tail 95 }) 96 } 97 98 // create and populate a ListView 99 m := view.NewManager(p.mgr.Client()) 100 101 list, err := m.CreateListView(ctx, collectors) 102 if err != nil { 103 return err 104 } 105 106 defer func() { 107 _ = list.Destroy(context.Background()) 108 }() 109 110 ref := list.Reference() 111 filter := new(property.WaitFilter).Add(ref, collectors[0].Type, props, list.TraversalSpec()) 112 113 return property.WaitForUpdates(ctx, c, filter, func(updates []types.ObjectUpdate) bool { 114 for _, update := range updates { 115 if err := p.process(update.Obj, update.ChangeSet); err != nil { 116 return false 117 } 118 } 119 120 return !tail 121 }) 122 } 123 124 func (p *eventProcessor) process(c types.ManagedObjectReference, pc []types.PropertyChange) error { 125 t := p.tailers[c] 126 if t == nil { 127 return fmt.Errorf("unknown collector %s", c.String()) 128 } 129 130 for _, u := range pc { 131 evs := t.t.newEvents(u.Val.(types.ArrayOfEvent).Event) 132 if len(evs) == 0 { 133 continue 134 } 135 136 if err := p.callback(t.obj, evs); err != nil { 137 return err 138 } 139 } 140 141 return nil 142 } 143 144 const invalidKey = int32(-1) 145 146 type eventTailer struct { 147 lastKey int32 148 } 149 150 func newEventTailer() *eventTailer { 151 return &eventTailer{ 152 lastKey: invalidKey, 153 } 154 } 155 156 func (t *eventTailer) newEvents(evs []types.BaseEvent) []types.BaseEvent { 157 var ret []types.BaseEvent 158 if t.lastKey == invalidKey { 159 ret = evs 160 } else { 161 found := false 162 for i := range evs { 163 if evs[i].GetEvent().Key != t.lastKey { 164 continue 165 } 166 167 found = true 168 ret = evs[:i] 169 break 170 } 171 172 if !found { 173 ret = evs 174 } 175 } 176 177 if len(ret) > 0 { 178 t.lastKey = ret[0].GetEvent().Key 179 } 180 181 return ret 182 }