Files
go-events/main.go
Nathan Coad 7da16fc9da
All checks were successful
continuous-integration/drone/push Build is passing
fix entity filter
2023-05-23 12:28:31 +10:00

323 lines
11 KiB
Go

package main
import (
"context"
"flag"
"fmt"
"net/url"
"os"
"strings"
"time"
"github.com/vmware/govmomi"
"github.com/vmware/govmomi/event"
"github.com/vmware/govmomi/view"
"github.com/vmware/govmomi/vim25/methods"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
)
var (
c *govmomi.Client
ctx context.Context
cancel context.CancelFunc
location *time.Location
sha1ver string // sha1 revision used to build the program
buildTime string // when the executable was built
)
func getEvents(eventTypes []string, entities []types.ManagedObjectReference, begin time.Duration, end time.Duration) []types.Event {
var returnEvents []types.Event
// Refer https://github.com/vmware/govmomi/blob/main/examples/events/main.go
now, err := methods.GetCurrentTime(ctx, c) // vCenter server time (UTC)
if err != nil {
fmt.Fprintf(os.Stderr, "Error getting vCenter time: %s\n", err)
os.Exit(1)
} else {
fmt.Printf("vCenter time is '%v'\n", now)
}
m := event.NewManager(c.Client)
root := c.ServiceContent.RootFolder
// configure the event stream filter (begin of stream)
filter := types.EventFilterSpec{
EventTypeId: eventTypes, // only stream specific types, e.g. VmEvent
Entity: &types.EventFilterSpecByEntity{
Entity: root,
Recursion: types.EventFilterSpecRecursionOptionAll,
},
Time: &types.EventFilterSpecByTime{
BeginTime: types.NewTime(now.Add(begin * -1)),
},
}
if len(entities) > 0 {
fmt.Printf("getEvents setting entity '%v' to filter\n", entities[0])
filter.Entity = &types.EventFilterSpecByEntity{
Entity: entities[0],
Recursion: types.EventFilterSpecRecursionOptionAll,
}
}
if end != 0 {
filter.Time.EndTime = types.NewTime(now.Add(end * -1))
}
collector, err := m.CreateCollectorForEvents(ctx, filter)
if err != nil {
fmt.Fprintf(os.Stderr, "Error creating event collector: %s\n", err)
os.Exit(1)
}
defer collector.Destroy(ctx)
for {
events, err := collector.ReadNextEvents(ctx, 100)
if err != nil {
fmt.Fprintf(os.Stderr, "Error reading events: %s\n", err)
}
if len(events) == 0 {
break
}
for i := range events {
event := events[i].GetEvent()
returnEvents = append(returnEvents, *event)
//kind := reflect.TypeOf(events[i]).Elem().Name()
//fmt.Printf("%d [%s] [%s] %s\n", event.Key, event.CreatedTime.In(location).Format(time.ANSIC), kind, event.FullFormattedMessage)
fmt.Printf("%d [%s] %s\n", event.Key, event.CreatedTime.In(location).Format(time.ANSIC), event.FullFormattedMessage)
}
}
return returnEvents
}
func main() {
// Command line flags for the vCenter connection
vURL := flag.String("url", "", "The URL of a vCenter server, eg https://server.domain.example/sdk")
vUser := flag.String("user", "", "The username to use when connecting to vCenter")
vPass := flag.String("password", "", "The password to use when connecting to vCenter")
vTZ := flag.String("tz", "Australia/Sydney", "The timezone to use when converting vCenter UTC times")
vInsecure := flag.Bool("insecure", true, "Allow insecure connections to vCenter")
begin := flag.Duration("b", time.Hour, "Begin time") // default BeginTime is 1h ago
end := flag.Duration("e", 0, "End time")
flag.Parse()
// So we can convert vCenter UTC to our local timezone
location, _ = time.LoadLocation(*vTZ)
fmt.Printf("Starting execution. Built on %s from sha1 %s\n", buildTime, sha1ver)
u, err := url.Parse(*vURL)
if err != nil {
fmt.Fprintf(os.Stderr, "Error parsing url %s : %s\n", *vURL, err)
os.Exit(1)
} else {
if !strings.HasSuffix(u.Path, "/sdk") {
u.Path, _ = url.JoinPath(u.Path, "/sdk")
fmt.Printf("Updated vCenter URL to '%v'\n", u)
}
}
fmt.Printf("Connecting to vCenter %s\n", u)
u.User = url.UserPassword(*vUser, *vPass)
ctx, cancel = context.WithCancel(context.Background())
defer cancel()
// Login to vcenter
c, err = govmomi.NewClient(ctx, u, *vInsecure)
if err != nil {
fmt.Fprintf(os.Stderr, "Logging in error: %s\n", err)
os.Exit(1)
}
defer c.Logout(ctx)
//finder := find.NewFinder(c.Client)
m := view.NewManager(c.Client)
// Create a container view so that we can search vCenter for a VM if we found any failure events
cv, _ := m.CreateContainerView(ctx, c.ServiceContent.RootFolder, []string{"VirtualMachine"}, true)
fmt.Printf("Searching for hostfailure events\n")
hostFailures := getEvents([]string{"com.vmware.vc.HA.DasHostFailedEvent"}, []types.ManagedObjectReference{}, *begin, *end)
if len(hostFailures) > 0 {
fmt.Printf("Found at least one host failure, proceeding with VM restart search\n")
vmFailures := getEvents([]string{"com.vmware.vc.ha.VmRestartedByHAEvent"}, []types.ManagedObjectReference{}, *begin, *end)
for i := range vmFailures {
event := vmFailures[i]
fmt.Printf("Found VM '%s' restarted in cluster '%s'\n", event.Vm.Name, event.ComputeResource.Name)
// Search for the VM
// Specify what properties we want to retrieve
var vms []mo.VirtualMachine
err = cv.Retrieve(ctx, []string{"VirtualMachine"}, []string{"summary", "name"}, &vms)
if err != nil {
fmt.Printf("Failed searching for VM %s : %s\n", event.Vm.Name, err)
} else {
for _, vm := range vms {
if vm.Name == event.Vm.Name {
fmt.Printf("Found corresponding VM with MoRef '%s'\n", vm.Reference())
disconnectedEvents := getEvents([]string{"VmDisconnectedEvent"}, []types.ManagedObjectReference{vm.Reference()}, *begin, *end)
fmt.Printf("Retrieved '%d' corresponding events.\n", len(disconnectedEvents))
}
}
}
/*
// Get a reference to the cluster mentioned in the event
cluster, err := finder.ClusterComputeResource(ctx, vmFailures[i].ComputeResource.Name)
view, _ := m.CreateContainerView(ctx, cluster, []string{"VirtualMachine"}, true)
var vms []mo.VirtualMachine
err = view.Retrieve(ctx, []string{"VirtualMachine"}, []string{}, &vms)
// Specify what properties we want to retrieve
err = v.Retrieve(ctx, []string{"HostSystem"}, []string{"summary", "runtime"}, &hs)
if err != nil {
fmt.Fprintf(os.Stderr, "error: %s\n", err)
os.Exit(1)
}
// Run the actual esxcli command on each host
finder := find.NewFinder(c.Client)
for _, host := range hs {
//fmt.Printf("Host name %s is %s\n", host.Summary.Config.Name, host.Runtime.ConnectionState)
// Make sure that the host is connected before we try running an esxcli command
if host.Runtime.ConnectionState == "connected" {
// Get a reference to the host object so that we can check the ramdisk values
objRef, err := finder.ObjectReference(ctx, host.Reference())
*/
}
}
// Selecting default datacenter
/*
finder := find.NewFinder(c.Client, true)
dc, err := finder.DefaultDatacenter(ctx)
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %s\n", err)
os.Exit(1)
}
//refs := []types.ManagedObjectReference{dc.Reference()}
*/
/*
// Refer https://github.com/vmware/govmomi/blob/main/examples/events/main.go
now, err := methods.GetCurrentTime(ctx, c) // vCenter server time (UTC)
if err != nil {
fmt.Fprintf(os.Stderr, "Error getting vCenter time: %s\n", err)
os.Exit(1)
}
m := event.NewManager(c.Client)
root := c.ServiceContent.RootFolder
// configure the event stream filter (begin of stream)
filter := types.EventFilterSpec{
EventTypeId: []string{"com.vmware.vc.HA.DasHostFailedEvent"}, // only stream specific types, e.g. VmEvent
Entity: &types.EventFilterSpecByEntity{
Entity: root,
Recursion: types.EventFilterSpecRecursionOptionAll,
},
Time: &types.EventFilterSpecByTime{
BeginTime: types.NewTime(now.Add(*begin * -1)),
},
}
if *end != 0 {
filter.Time.EndTime = types.NewTime(now.Add(*end * -1))
}
collector, err := m.CreateCollectorForEvents(ctx, filter)
if err != nil {
fmt.Fprintf(os.Stderr, "Error creating event collector: %s\n", err)
os.Exit(1)
}
defer collector.Destroy(ctx)
for {
events, err := collector.ReadNextEvents(ctx, 100)
if err != nil {
fmt.Fprintf(os.Stderr, "Error reading events: %s\n", err)
}
if len(events) == 0 {
break
}
for i := range events {
event := events[i].GetEvent()
kind := reflect.TypeOf(events[i]).Elem().Name()
fmt.Printf("%d [%s] [%s] %s\n", event.Key, event.CreatedTime.Format(time.ANSIC), kind, event.FullFormattedMessage)
}
}
*/
// **************
// previous code here
/*
// Do a recursive search for all the ESXi hosts (which have a type of HostSystem)
m := view.NewManager(c.Client)
v, _ := m.CreateContainerView(ctx, c.ServiceContent.RootFolder, []string{"HostSystem"}, true)
// Specify what properties we want to retrieve
var hs []mo.HostSystem
err = v.Retrieve(ctx, []string{"HostSystem"}, []string{"summary", "runtime"}, &hs)
if err != nil {
fmt.Fprintf(os.Stderr, "error: %s\n", err)
os.Exit(1)
}
// Run the actual esxcli command on each host
finder := find.NewFinder(c.Client)
for _, host := range hs {
//fmt.Printf("Host name %s is %s\n", host.Summary.Config.Name, host.Runtime.ConnectionState)
// Make sure that the host is connected before we try running an esxcli command
if host.Runtime.ConnectionState == "connected" {
// Get a reference to the host object so that we can check the ramdisk values
objRef, err := finder.ObjectReference(ctx, host.Reference())
if err != nil {
fmt.Fprintf(os.Stderr, "Error getting reference to host : %s\n", err)
continue
}
// Get the HostSystem object
hs, ok := objRef.(*object.HostSystem)
if !ok {
fmt.Fprintf(os.Stderr, "Couldn't find Hostsytem : %s\n", host.Reference())
continue
}
// Get a reference to the esxcli executor
// https://gowalker.org/github.com/dhawalseth/govc-autocomplete/govc/host/esxcli
// https://pkg.go.dev/github.com/vmware/govmomi/govc/host/esxcli
// https://github.com/vmware/govmomi/blob/f4c5c4a58e445ba31393795c7e678fa05fb3452a/govc/host/esxcli/esxcli.go
// https://golang.hotexamples.com/examples/github.com.vmware.govmomi.object/HostSystem/-/golang-hostsystem-class-examples.html
// https://golang.hotexamples.com/examples/github.com.vmware.govmomi.govc.host.esxcli/-/GetFirewallInfo/golang-getfirewallinfo-function-examples.html
e, err := esxcli.NewExecutor(c.Client, hs)
if err != nil {
fmt.Fprintf(os.Stderr, "Error getting esxcli executor: %s\n", err)
continue
}
// Run the desired esxcli command
result, err := e.Run([]string{"system", "visorfs", "ramdisk", "list"})
if err != nil {
fmt.Fprintf(os.Stderr, "Error running esxcli command: %s\n", err)
continue
}
// Print out all the values
for _, values := range result.Values {
fmt.Printf("%s;%s;%s\n", host.Summary.Config.Name, values["RamdiskName"][0], values["Free"][0])
}
}
}
*/
}