godep: update vmware/govmomi
This commit is contained in:
386
vendor/github.com/vmware/govmomi/simulator/event_manager.go
generated
vendored
Normal file
386
vendor/github.com/vmware/govmomi/simulator/event_manager.go
generated
vendored
Normal file
@@ -0,0 +1,386 @@
|
||||
/*
|
||||
Copyright (c) 2018 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package simulator
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"container/ring"
|
||||
"log"
|
||||
"reflect"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/simulator/esx"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
var (
|
||||
maxPageSize = 1000
|
||||
logEvents = false
|
||||
)
|
||||
|
||||
type EventManager struct {
|
||||
mo.EventManager
|
||||
|
||||
root types.ManagedObjectReference
|
||||
page *ring.Ring
|
||||
key int32
|
||||
collectors map[types.ManagedObjectReference]*EventHistoryCollector
|
||||
templates map[string]*template.Template
|
||||
}
|
||||
|
||||
func NewEventManager(ref types.ManagedObjectReference) object.Reference {
|
||||
return &EventManager{
|
||||
EventManager: mo.EventManager{
|
||||
Self: ref,
|
||||
Description: types.EventDescription{
|
||||
EventInfo: esx.EventInfo,
|
||||
},
|
||||
MaxCollector: 1000,
|
||||
},
|
||||
root: Map.content().RootFolder,
|
||||
page: ring.New(maxPageSize),
|
||||
collectors: make(map[types.ManagedObjectReference]*EventHistoryCollector),
|
||||
templates: make(map[string]*template.Template),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *EventManager) CreateCollectorForEvents(ctx *Context, req *types.CreateCollectorForEvents) soap.HasFault {
|
||||
body := new(methods.CreateCollectorForEventsBody)
|
||||
size, err := validatePageSize(req.Filter.MaxCount)
|
||||
if err != nil {
|
||||
body.Fault_ = err
|
||||
return body
|
||||
}
|
||||
|
||||
if len(m.collectors) >= int(m.MaxCollector) {
|
||||
body.Fault_ = Fault("Too many event collectors to create", new(types.InvalidState))
|
||||
return body
|
||||
}
|
||||
|
||||
collector := &EventHistoryCollector{
|
||||
m: m,
|
||||
page: ring.New(size),
|
||||
}
|
||||
collector.Filter = req.Filter
|
||||
collector.fillPage(size)
|
||||
|
||||
ref := ctx.Session.Put(collector).Reference()
|
||||
m.collectors[ref] = collector
|
||||
|
||||
body.Res = &types.CreateCollectorForEventsResponse{
|
||||
Returnval: ref,
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
// formatMessage applies the EventDescriptionEventDetail.FullFormat template to the given event's FullFormattedMessage field.
|
||||
func (m *EventManager) formatMessage(event types.BaseEvent) {
|
||||
id := reflect.ValueOf(event).Elem().Type().Name()
|
||||
e := event.GetEvent()
|
||||
|
||||
t, ok := m.templates[id]
|
||||
if !ok {
|
||||
for _, info := range m.Description.EventInfo {
|
||||
if info.Key == id {
|
||||
t = template.Must(template.New(id).Parse(info.FullFormat))
|
||||
m.templates[id] = t
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := t.Execute(&buf, event); err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
e.FullFormattedMessage = buf.String()
|
||||
|
||||
if logEvents {
|
||||
log.Printf("[%s] %s", id, e.FullFormattedMessage)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *EventManager) PostEvent(ctx *Context, req *types.PostEvent) soap.HasFault {
|
||||
m.key++
|
||||
event := req.EventToPost.GetEvent()
|
||||
event.Key = m.key
|
||||
event.ChainId = event.Key
|
||||
event.CreatedTime = time.Now()
|
||||
event.UserName = ctx.Session.UserName
|
||||
|
||||
m.page = m.page.Next()
|
||||
m.page.Value = req.EventToPost
|
||||
m.formatMessage(req.EventToPost)
|
||||
|
||||
for _, c := range m.collectors {
|
||||
if c.eventMatches(req.EventToPost) {
|
||||
c.page = c.page.Next()
|
||||
c.page.Value = event
|
||||
}
|
||||
}
|
||||
|
||||
return &methods.PostEventBody{
|
||||
Res: new(types.PostEventResponse),
|
||||
}
|
||||
}
|
||||
|
||||
type EventHistoryCollector struct {
|
||||
mo.EventHistoryCollector
|
||||
|
||||
m *EventManager
|
||||
page *ring.Ring
|
||||
}
|
||||
|
||||
// doEntityEventArgument calls f for each entity argument in the event.
|
||||
// If f returns true, the iteration stops.
|
||||
func doEntityEventArgument(event types.BaseEvent, f func(types.ManagedObjectReference, *types.EntityEventArgument) bool) bool {
|
||||
e := event.GetEvent()
|
||||
|
||||
if arg := e.Vm; arg != nil {
|
||||
if f(arg.Vm, &arg.EntityEventArgument) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if arg := e.Host; arg != nil {
|
||||
if f(arg.Host, &arg.EntityEventArgument) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if arg := e.ComputeResource; arg != nil {
|
||||
if f(arg.ComputeResource, &arg.EntityEventArgument) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if arg := e.Ds; arg != nil {
|
||||
if f(arg.Datastore, &arg.EntityEventArgument) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if arg := e.Net; arg != nil {
|
||||
if f(arg.Network, &arg.EntityEventArgument) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if arg := e.Dvs; arg != nil {
|
||||
if f(arg.Dvs, &arg.EntityEventArgument) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if arg := e.Datacenter; arg != nil {
|
||||
if f(arg.Datacenter, &arg.EntityEventArgument) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// eventFilterSelf returns true if self is one of the entity arguments in the event.
|
||||
func eventFilterSelf(event types.BaseEvent, self types.ManagedObjectReference) bool {
|
||||
return doEntityEventArgument(event, func(ref types.ManagedObjectReference, _ *types.EntityEventArgument) bool {
|
||||
return self == ref
|
||||
})
|
||||
}
|
||||
|
||||
// eventFilterChildren returns true if a child of self is one of the entity arguments in the event.
|
||||
func eventFilterChildren(event types.BaseEvent, self types.ManagedObjectReference) bool {
|
||||
return doEntityEventArgument(event, func(ref types.ManagedObjectReference, _ *types.EntityEventArgument) bool {
|
||||
seen := false
|
||||
|
||||
var match func(types.ManagedObjectReference)
|
||||
|
||||
match = func(child types.ManagedObjectReference) {
|
||||
if child == self {
|
||||
seen = true
|
||||
return
|
||||
}
|
||||
|
||||
walk(child, match)
|
||||
}
|
||||
|
||||
walk(ref, match)
|
||||
|
||||
return seen
|
||||
})
|
||||
}
|
||||
|
||||
// entityMatches returns true if the spec Entity filter matches the event.
|
||||
func (c *EventHistoryCollector) entityMatches(event types.BaseEvent, spec *types.EventFilterSpec) bool {
|
||||
e := spec.Entity
|
||||
if e == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
isRootFolder := c.m.root == e.Entity
|
||||
|
||||
switch e.Recursion {
|
||||
case types.EventFilterSpecRecursionOptionSelf:
|
||||
return isRootFolder || eventFilterSelf(event, e.Entity)
|
||||
case types.EventFilterSpecRecursionOptionChildren:
|
||||
return eventFilterChildren(event, e.Entity)
|
||||
case types.EventFilterSpecRecursionOptionAll:
|
||||
if isRootFolder || eventFilterSelf(event, e.Entity) {
|
||||
return true
|
||||
}
|
||||
return eventFilterChildren(event, e.Entity)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// typeMatches returns true if one of the spec EventTypeId types matches the event.
|
||||
func (c *EventHistoryCollector) typeMatches(event types.BaseEvent, spec *types.EventFilterSpec) bool {
|
||||
if len(spec.EventTypeId) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
matches := func(name string) bool {
|
||||
for _, id := range spec.EventTypeId {
|
||||
if id == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
kind := reflect.ValueOf(event).Elem().Type()
|
||||
|
||||
if matches(kind.Name()) {
|
||||
return true // concrete type
|
||||
}
|
||||
|
||||
field, ok := kind.FieldByNameFunc(matches)
|
||||
if ok {
|
||||
return field.Anonymous // base type (embedded field)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// eventMatches returns true one of the filters matches the event.
|
||||
func (c *EventHistoryCollector) eventMatches(event types.BaseEvent) bool {
|
||||
spec := c.Filter.(types.EventFilterSpec)
|
||||
|
||||
if !c.typeMatches(event, &spec) {
|
||||
return false
|
||||
}
|
||||
|
||||
// TODO: spec.Time, spec.UserName, etc
|
||||
|
||||
return c.entityMatches(event, &spec)
|
||||
}
|
||||
|
||||
// filePage copies the manager's latest events into the collector's page with Filter applied.
|
||||
func (c *EventHistoryCollector) fillPage(size int) {
|
||||
l := c.page.Len()
|
||||
delta := size - l
|
||||
|
||||
if delta < 0 {
|
||||
// Shrink ring size
|
||||
c.page = c.page.Unlink(-delta)
|
||||
return
|
||||
}
|
||||
|
||||
matches := 0
|
||||
mpage := c.m.page
|
||||
page := c.page
|
||||
|
||||
if delta != 0 {
|
||||
// Grow ring size
|
||||
c.page = c.page.Link(ring.New(delta))
|
||||
}
|
||||
|
||||
for i := 0; i < maxPageSize; i++ {
|
||||
event, ok := mpage.Value.(types.BaseEvent)
|
||||
mpage = mpage.Prev()
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if c.eventMatches(event) {
|
||||
page.Value = event
|
||||
page = page.Prev()
|
||||
matches++
|
||||
if matches == size {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func validatePageSize(count int32) (int, *soap.Fault) {
|
||||
size := int(count)
|
||||
|
||||
if size == 0 {
|
||||
size = 10 // defaultPageSize
|
||||
} else if size < 0 || size > maxPageSize {
|
||||
return -1, Fault("", &types.InvalidArgument{InvalidProperty: "maxCount"})
|
||||
}
|
||||
|
||||
return size, nil
|
||||
}
|
||||
|
||||
func (c *EventHistoryCollector) SetCollectorPageSize(ctx *Context, req *types.SetCollectorPageSize) soap.HasFault {
|
||||
body := new(methods.SetCollectorPageSizeBody)
|
||||
size, err := validatePageSize(req.MaxCount)
|
||||
if err != nil {
|
||||
body.Fault_ = err
|
||||
return body
|
||||
}
|
||||
|
||||
ctx.WithLock(c.m, func() {
|
||||
c.fillPage(size)
|
||||
})
|
||||
|
||||
body.Res = new(types.SetCollectorPageSizeResponse)
|
||||
return body
|
||||
}
|
||||
|
||||
func (c *EventHistoryCollector) DestroyCollector(ctx *Context, req *types.DestroyCollector) soap.HasFault {
|
||||
ctx.Session.Remove(req.This)
|
||||
|
||||
ctx.WithLock(c.m, func() {
|
||||
delete(c.m.collectors, req.This)
|
||||
})
|
||||
|
||||
return &methods.DestroyCollectorBody{
|
||||
Res: new(types.DestroyCollectorResponse),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *EventHistoryCollector) Get() mo.Reference {
|
||||
clone := *c
|
||||
|
||||
c.page.Do(func(val interface{}) {
|
||||
if val == nil {
|
||||
return
|
||||
}
|
||||
clone.LatestPage = append(clone.LatestPage, val.(types.BaseEvent))
|
||||
})
|
||||
|
||||
return &clone
|
||||
}
|
||||
Reference in New Issue
Block a user