github.com/vmware/govmomi@v0.51.0/cli/events/command.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 events
     6  
     7  import (
     8  	"context"
     9  	"flag"
    10  	"fmt"
    11  	"io"
    12  	"os"
    13  	"reflect"
    14  	"strings"
    15  	"time"
    16  
    17  	"github.com/vmware/govmomi/cli"
    18  	"github.com/vmware/govmomi/cli/flags"
    19  	"github.com/vmware/govmomi/event"
    20  	"github.com/vmware/govmomi/vim25/types"
    21  )
    22  
    23  type events struct {
    24  	*flags.DatacenterFlag
    25  
    26  	Max   int32
    27  	Tail  bool
    28  	Force bool
    29  	Long  bool
    30  	Kind  kinds
    31  }
    32  
    33  type kinds []string
    34  
    35  func (e *kinds) String() string {
    36  	return fmt.Sprint(*e)
    37  }
    38  
    39  func (e *kinds) Set(value string) error {
    40  	*e = append(*e, value)
    41  	return nil
    42  }
    43  
    44  func init() {
    45  	// initialize with the maximum allowed objects set
    46  	cli.Register("events", &events{})
    47  }
    48  
    49  func (cmd *events) Register(ctx context.Context, f *flag.FlagSet) {
    50  	cmd.DatacenterFlag, ctx = flags.NewDatacenterFlag(ctx)
    51  	cmd.DatacenterFlag.Register(ctx, f)
    52  
    53  	cmd.Max = 25 // default
    54  	f.Var(flags.NewInt32(&cmd.Max), "n", "Output the last N events")
    55  	f.BoolVar(&cmd.Tail, "f", false, "Follow event stream")
    56  	f.BoolVar(&cmd.Force, "force", false, "Disable number objects to monitor limit")
    57  	f.BoolVar(&cmd.Long, "l", false, "Long listing format")
    58  	f.Var(&cmd.Kind, "type", "Include only the specified event types")
    59  }
    60  
    61  func (cmd *events) Description() string {
    62  	return `Display events.
    63  
    64  Examples:
    65    govc events vm/my-vm1 vm/my-vm2
    66    govc events /dc1/vm/* /dc2/vm/*
    67    govc events -type VmPoweredOffEvent -type VmPoweredOnEvent
    68    govc ls -t HostSystem host/* | xargs govc events | grep -i vsan`
    69  }
    70  
    71  func (cmd *events) Usage() string {
    72  	return "[PATH]..."
    73  }
    74  
    75  func (cmd *events) printEvents(ctx context.Context, obj *types.ManagedObjectReference, page []types.BaseEvent, m *event.Manager) error {
    76  	event.Sort(page)
    77  	source := ""
    78  	if obj != nil {
    79  		source = obj.String()
    80  		if !cmd.JSON {
    81  			// print the object reference
    82  			fmt.Fprintf(os.Stdout, "\n==> %s <==\n", source)
    83  		}
    84  	}
    85  	for _, e := range page {
    86  		cat, err := m.EventCategory(ctx, e)
    87  		if err != nil {
    88  			return err
    89  		}
    90  
    91  		event := e.GetEvent()
    92  		r := &record{
    93  			Object:      source,
    94  			CreatedTime: event.CreatedTime,
    95  			Category:    cat,
    96  			Message:     strings.TrimSpace(event.FullFormattedMessage),
    97  			event:       e,
    98  		}
    99  
   100  		if cmd.Long {
   101  			r.Type = reflect.TypeOf(e).Elem().Name()
   102  		}
   103  
   104  		if cmd.Long {
   105  			r.Key = event.Key
   106  		}
   107  
   108  		switch x := e.(type) {
   109  		case *types.TaskEvent:
   110  			// some tasks won't have this information, so just use the event message
   111  			if x.Info.Entity != nil {
   112  				r.Message = fmt.Sprintf("%s (target=%s %s)", r.Message, x.Info.Entity.Type, x.Info.EntityName)
   113  			}
   114  		case *types.EventEx:
   115  			if r.Message == "" {
   116  				r.Message = x.Message
   117  			}
   118  			if x.ObjectId != "" {
   119  				r.Message = fmt.Sprintf("%s (%s)", r.Message, x.ObjectId)
   120  			}
   121  			if cmd.Long {
   122  				r.Type = x.EventTypeId
   123  			}
   124  		}
   125  
   126  		if err = cmd.WriteResult(r); err != nil {
   127  			return err
   128  		}
   129  	}
   130  	return nil
   131  }
   132  
   133  type record struct {
   134  	Object      string    `json:"object,omitempty"`
   135  	Type        string    `json:"type,omitempty"`
   136  	CreatedTime time.Time `json:"createdTime"`
   137  	Category    string    `json:"category"`
   138  	Message     string    `json:"message"`
   139  	Key         int32     `json:"key,omitempty"`
   140  
   141  	event types.BaseEvent
   142  }
   143  
   144  // Dump the raw Event rather than the record struct.
   145  func (r *record) Dump() any {
   146  	return r.event
   147  }
   148  
   149  func (r *record) Write(w io.Writer) error {
   150  	when := r.CreatedTime.Local().Format(time.ANSIC)
   151  	var kind, key string
   152  	if r.Type != "" {
   153  		kind = fmt.Sprintf(" [%s]", r.Type)
   154  	}
   155  	if r.Key != 0 {
   156  		key = fmt.Sprintf(" [%d]", r.Key)
   157  	}
   158  	_, err := fmt.Fprintf(w, "[%s] [%s]%s%s %s\n", when, r.Category, key, kind, r.Message)
   159  	return err
   160  }
   161  
   162  func (cmd *events) Run(ctx context.Context, f *flag.FlagSet) error {
   163  	c, err := cmd.Client()
   164  	if err != nil {
   165  		return err
   166  	}
   167  
   168  	objs, err := cmd.ManagedObjects(ctx, f.Args())
   169  	if err != nil {
   170  		return err
   171  	}
   172  
   173  	m := event.NewManager(c)
   174  
   175  	return cmd.WithCancel(ctx, func(wctx context.Context) error {
   176  		return m.Events(wctx, objs, cmd.Max, cmd.Tail, cmd.Force,
   177  			func(obj types.ManagedObjectReference, ee []types.BaseEvent) error {
   178  				var o *types.ManagedObjectReference
   179  				if len(objs) > 1 {
   180  					o = &obj
   181  				}
   182  
   183  				return cmd.printEvents(ctx, o, ee, m)
   184  			}, cmd.Kind...)
   185  	})
   186  }