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