github.com/vmware/govmomi@v0.51.0/event/manager.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 "reflect" 11 "sync" 12 13 "github.com/vmware/govmomi/property" 14 "github.com/vmware/govmomi/vim25" 15 "github.com/vmware/govmomi/vim25/methods" 16 "github.com/vmware/govmomi/vim25/mo" 17 "github.com/vmware/govmomi/vim25/types" 18 ) 19 20 type Manager struct { 21 r types.ManagedObjectReference 22 c *vim25.Client 23 24 eventCategory map[string]string 25 eventCategoryMu *sync.Mutex 26 maxObjects int 27 } 28 29 func NewManager(c *vim25.Client) *Manager { 30 m := Manager{ 31 r: c.ServiceContent.EventManager.Reference(), 32 c: c, 33 eventCategory: make(map[string]string), 34 eventCategoryMu: new(sync.Mutex), 35 maxObjects: 10, 36 } 37 38 return &m 39 } 40 41 // Reference returns the event.Manager MOID 42 func (m Manager) Reference() types.ManagedObjectReference { 43 return m.r 44 } 45 46 func (m Manager) Client() *vim25.Client { 47 return m.c 48 } 49 50 func (m Manager) CreateCollectorForEvents(ctx context.Context, filter types.EventFilterSpec) (*HistoryCollector, error) { 51 req := types.CreateCollectorForEvents{ 52 This: m.r, 53 Filter: filter, 54 } 55 56 res, err := methods.CreateCollectorForEvents(ctx, m.c, &req) 57 if err != nil { 58 return nil, err 59 } 60 61 return newHistoryCollector(m.c, res.Returnval), nil 62 } 63 64 func (m Manager) LogUserEvent(ctx context.Context, entity types.ManagedObjectReference, msg string) error { 65 req := types.LogUserEvent{ 66 This: m.r, 67 Entity: entity, 68 Msg: msg, 69 } 70 71 _, err := methods.LogUserEvent(ctx, m.c, &req) 72 if err != nil { 73 return err 74 } 75 76 return nil 77 } 78 79 func (m Manager) PostEvent(ctx context.Context, eventToPost types.BaseEvent, taskInfo ...types.TaskInfo) error { 80 req := types.PostEvent{ 81 This: m.r, 82 EventToPost: eventToPost, 83 } 84 85 if len(taskInfo) == 1 { 86 req.TaskInfo = &taskInfo[0] 87 } 88 89 _, err := methods.PostEvent(ctx, m.c, &req) 90 if err != nil { 91 return err 92 } 93 94 return nil 95 } 96 97 func (m Manager) QueryEvents(ctx context.Context, filter types.EventFilterSpec) ([]types.BaseEvent, error) { 98 req := types.QueryEvents{ 99 This: m.r, 100 Filter: filter, 101 } 102 103 res, err := methods.QueryEvents(ctx, m.c, &req) 104 if err != nil { 105 return nil, err 106 } 107 108 return res.Returnval, nil 109 } 110 111 func (m Manager) RetrieveArgumentDescription(ctx context.Context, eventTypeID string) ([]types.EventArgDesc, error) { 112 req := types.RetrieveArgumentDescription{ 113 This: m.r, 114 EventTypeId: eventTypeID, 115 } 116 117 res, err := methods.RetrieveArgumentDescription(ctx, m.c, &req) 118 if err != nil { 119 return nil, err 120 } 121 122 return res.Returnval, nil 123 } 124 125 func (m Manager) eventCategoryMap(ctx context.Context) (map[string]string, error) { 126 m.eventCategoryMu.Lock() 127 defer m.eventCategoryMu.Unlock() 128 129 if len(m.eventCategory) != 0 { 130 return m.eventCategory, nil 131 } 132 133 var o mo.EventManager 134 135 ps := []string{"description.eventInfo"} 136 err := property.DefaultCollector(m.c).RetrieveOne(ctx, m.r, ps, &o) 137 if err != nil { 138 return nil, err 139 } 140 141 for _, info := range o.Description.EventInfo { 142 m.eventCategory[info.Key] = info.Category 143 } 144 145 return m.eventCategory, nil 146 } 147 148 // EventCategory returns the category for an event, such as "info" or "error" for example. 149 func (m Manager) EventCategory(ctx context.Context, event types.BaseEvent) (string, error) { 150 // Most of the event details are included in the Event.FullFormattedMessage, but the category 151 // is only available via the EventManager description.eventInfo property. The value of this 152 // property is static, so we fetch and once and cache. 153 eventCategory, err := m.eventCategoryMap(ctx) 154 if err != nil { 155 return "", err 156 } 157 158 switch e := event.(type) { 159 case *types.EventEx: 160 if e.Severity == "" { 161 return "info", nil 162 } 163 return e.Severity, nil 164 } 165 166 class := reflect.TypeOf(event).Elem().Name() 167 168 return eventCategory[class], nil 169 } 170 171 // Events gets the events from the specified object(s) and optionanlly tail the 172 // event stream 173 func (m Manager) Events(ctx context.Context, objects []types.ManagedObjectReference, pageSize int32, tail bool, force bool, f func(types.ManagedObjectReference, []types.BaseEvent) error, kind ...string) error { 174 // TODO: deprecated this method and add one that uses a single config struct, so we can extend further without breaking the method signature. 175 if len(objects) >= m.maxObjects && !force { 176 return fmt.Errorf("maximum number of objects to monitor (%d) exceeded, refine search", m.maxObjects) 177 } 178 179 proc := newEventProcessor(m, pageSize, f, kind) 180 for _, o := range objects { 181 proc.addObject(ctx, o) 182 } 183 184 defer proc.destroy() 185 186 return proc.run(ctx, tail) 187 }