diff --git a/event/manager.go b/event/manager.go index d3f2da9a7..72cc34350 100644 --- a/event/manager.go +++ b/event/manager.go @@ -169,13 +169,13 @@ func (m Manager) EventCategory(ctx context.Context, event types.BaseEvent) (stri } // Get the events from the specified object(s) and optionanlly tail the event stream -func (m Manager) Events(ctx context.Context, objects []types.ManagedObjectReference, pageSize int32, tail bool, force bool, f func(types.ManagedObjectReference, []types.BaseEvent) error) error { - +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 { + // TODO: deprecated this method and add one that uses a single config struct, so we can extend further without breaking the method signature. if len(objects) >= m.maxObjects && !force { return fmt.Errorf("Maximum number of objects to monitor (%d) exceeded, refine search", m.maxObjects) } - proc := newEventProcessor(m, pageSize, f) + proc := newEventProcessor(m, pageSize, f, kind) for _, o := range objects { proc.addObject(ctx, o) } diff --git a/event/processor.go b/event/processor.go index cc19b7009..b8760a8e4 100644 --- a/event/processor.go +++ b/event/processor.go @@ -34,16 +34,18 @@ type tailInfo struct { type eventProcessor struct { mgr Manager pageSize int32 + kind []string tailers map[types.ManagedObjectReference]*tailInfo // tailers by collector ref callback func(types.ManagedObjectReference, []types.BaseEvent) error } -func newEventProcessor(mgr Manager, pageSize int32, callback func(types.ManagedObjectReference, []types.BaseEvent) error) *eventProcessor { +func newEventProcessor(mgr Manager, pageSize int32, callback func(types.ManagedObjectReference, []types.BaseEvent) error, kind []string) *eventProcessor { return &eventProcessor{ mgr: mgr, tailers: make(map[types.ManagedObjectReference]*tailInfo), callback: callback, pageSize: pageSize, + kind: kind, } } @@ -53,6 +55,7 @@ func (p *eventProcessor) addObject(ctx context.Context, obj types.ManagedObjectR Entity: obj, Recursion: types.EventFilterSpecRecursionOptionAll, }, + EventTypeId: p.kind, } collector, err := p.mgr.CreateCollectorForEvents(ctx, filter) diff --git a/govc/events/command.go b/govc/events/command.go index e57112b85..a96c83454 100644 --- a/govc/events/command.go +++ b/govc/events/command.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2015 VMware, Inc. All Rights Reserved. +Copyright (c) 2015-2017 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. @@ -23,6 +23,7 @@ import ( "fmt" "io" "os" + "reflect" "strings" "time" @@ -40,6 +41,19 @@ type events struct { Max int32 Tail bool Force bool + Long bool + Kind kinds +} + +type kinds []string + +func (e *kinds) String() string { + return fmt.Sprint(*e) +} + +func (e *kinds) Set(value string) error { + *e = append(*e, value) + return nil } func init() { @@ -55,6 +69,8 @@ func (cmd *events) Register(ctx context.Context, f *flag.FlagSet) { f.Var(flags.NewInt32(&cmd.Max), "n", "Output the last N events") f.BoolVar(&cmd.Tail, "f", false, "Follow event stream") f.BoolVar(&cmd.Force, "force", false, "Disable number objects to monitor limit") + f.BoolVar(&cmd.Long, "l", false, "Long listing format") + f.Var(&cmd.Kind, "type", "Include only the specified event types") } func (cmd *events) Description() string { @@ -63,6 +79,7 @@ func (cmd *events) Description() string { Examples: govc events vm/my-vm1 vm/my-vm2 govc events /dc1/vm/* /dc2/vm/* + govc events -type VmPoweredOffEvent -type VmPoweredOnEvent govc ls -t HostSystem host/* | xargs govc events | grep -i vsan` } @@ -101,6 +118,10 @@ func (cmd *events) printEvents(ctx context.Context, obj *types.ManagedObjectRefe Message: strings.TrimSpace(event.FullFormattedMessage), } + if cmd.Long { + r.Type = reflect.TypeOf(e).Elem().Name() + } + // if this is a TaskEvent gather a little more information if t, ok := e.(*types.TaskEvent); ok { // some tasks won't have this information, so just use the event message @@ -118,6 +139,7 @@ func (cmd *events) printEvents(ctx context.Context, obj *types.ManagedObjectRefe type record struct { Object string `json:",omitempty"` + Type string `json:",omitempty"` CreatedTime time.Time Category string Message string @@ -129,8 +151,11 @@ func writeEventAsJSON(w io.Writer, r *record) error { func writeEvent(w io.Writer, r *record) error { when := r.CreatedTime.Local().Format(time.ANSIC) - - _, err := fmt.Fprintf(w, "[%s] [%s] %s\n", when, r.Category, r.Message) + var kind string + if r.Type != "" { + kind = fmt.Sprintf(" [%s]", r.Type) + } + _, err := fmt.Fprintf(w, "[%s] [%s]%s %s\n", when, r.Category, kind, r.Message) return err } @@ -166,7 +191,7 @@ func (cmd *events) Run(ctx context.Context, f *flag.FlagSet) error { return err } return nil - }) + }, cmd.Kind...) if err != nil { return err diff --git a/govc/test/events.bats b/govc/test/events.bats index 5c5145271..4568b46e7 100755 --- a/govc/test/events.bats +++ b/govc/test/events.bats @@ -54,6 +54,21 @@ load test_helper run govc events vm assert_success [ ${#lines[@]} -ge $nevents ] + + run govc events -type VmPoweredOffEvent -type VmPoweredOnEvent "vm/$vm" + [ ${#lines[@]} -eq 0 ] + + run govc vm.power -on "$vm" + assert_success + + run govc events -type VmPoweredOffEvent -type VmPoweredOnEvent "vm/$vm" + [ ${#lines[@]} -eq 1 ] + + run govc vm.power -off "$vm" + assert_success + + run govc events -type VmPoweredOffEvent -type VmPoweredOnEvent "vm/$vm" + [ ${#lines[@]} -eq 2 ] } @test "events json" {