From 98b0423c7a66c4fb05dd910cd5cc6bb7a9dd2b1d Mon Sep 17 00:00:00 2001 From: Nathan Coad Date: Tue, 23 May 2023 10:42:33 +1000 Subject: [PATCH] first commit --- README.md | 0 go.mod | 11 +++ go.sum | 11 +++ main.go | 242 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 264 insertions(+) create mode 100644 README.md create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..ba332e8 --- /dev/null +++ b/go.mod @@ -0,0 +1,11 @@ +module nathan/go-events + +go 1.19 + +require github.com/vmware/govmomi v0.30.4 + +require ( + github.com/dougm/pretty v0.0.0-20171025230240-2ee9d7453c02 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/rogpeppe/go-internal v1.10.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..7a85820 --- /dev/null +++ b/go.sum @@ -0,0 +1,11 @@ +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/dougm/pretty v0.0.0-20171025230240-2ee9d7453c02 h1:tR3jsKPiO/mb6ntzk/dJlHZtm37CPfVp1C9KIo534+4= +github.com/dougm/pretty v0.0.0-20171025230240-2ee9d7453c02/go.mod h1:7NQ3kWOx2cZOSjtcveTa5nqupVr2s6/83sG+rTlI7uA= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/vmware/govmomi v0.30.4 h1:BCKLoTmiBYRuplv3GxKEMBLtBaJm8PA56vo9bddIpYQ= +github.com/vmware/govmomi v0.30.4/go.mod h1:F7adsVewLNHsW/IIm7ziFURaXDaHEwcc+ym4r3INMdY= diff --git a/main.go b/main.go new file mode 100644 index 0000000..fb15361 --- /dev/null +++ b/main.go @@ -0,0 +1,242 @@ +package main + +import ( + "context" + "flag" + "fmt" + "net/url" + "os" + "reflect" + "time" + + "github.com/vmware/govmomi" + "github.com/vmware/govmomi/event" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/types" +) + +var c *govmomi.Client +var ctx context.Context +var cancel context.CancelFunc + +func exit(err error) { + fmt.Fprintf(os.Stderr, "Error: %s\n", err) + os.Exit(1) +} + +func getEvents(eventTypes []string, 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 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.Format(time.ANSIC), kind, 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") + 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() + + u, err := url.Parse(*vURL) + if err != nil { + fmt.Fprintf(os.Stderr, "Error parsing url %s : %s\n", *vURL, err) + os.Exit(1) + } + + //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) + + getEvents([]string{"com.vmware.vc.HA.DasHostFailedEvent"}, *begin, *end) + + // 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]) + } + } + } + */ +}