github.com/vmware/govmomi@v0.37.2/govc/events/command.go (about)

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