Listing all vCenter performance metrics with govmomi

In the past I wrote about how to List all vCenter performance counters with PowerCLI. In this post I’ll show how to do the same in Go with govmomi and compare the performance between the two.  I created the PowerCLI version of the script to gather vSphere performance counter information that I needed while creating the script in Gathering real-time vSphere performance metrics in parallel using PowerCLI. My goal is to create a Go version of this script using govmomi.

The code can be found at on github.

The performance counters are the same since it’s running against the same version of vCenter and can be found here.

You can also look at the vSphere performance counters through the vCenter mob by going to https://vcenter/mob/ and selecting content and then PerfMgr.

2016-09-26_22-16-56.png

2016-09-26_22-17-15.png

2016-09-26_22-17-34.png

If you’re not familiar with the vSphere API (like me), the mob can be a create place to explore and learn.

Code

The performance relevant pieces are highlighted towards the end.


package main

import (
        "context"
        "encoding/csv"
        "flag"
        "fmt"
        "log"
        "net/url"
        "os"
        "strings"

        "github.com/vmware/govmomi"
        "github.com/vmware/govmomi/vim25/mo"
)

// GetEnvString returns string from environment variable.
func GetEnvString(v string, def string) string {
        r := os.Getenv(v)
        if r == "" {
                return def
        }

        return r
}

// GetEnvBool returns boolean from environment variable.
func GetEnvBool(v string, def bool) bool {
        r := os.Getenv(v)
        if r == "" {
                return def
        }

        switch strings.ToLower(r[0:1]) {
        case "t", "y", "1":
                return true
        }

        return false
}

const (
        envURL      = "GOVMOMI_URL"
        envUserName = "GOVMOMI_USERNAME"
        envPassword = "GOVMOMI_PASSWORD"
        envInsecure = "GOVMOMI_INSECURE"
)

var urlDescription = fmt.Sprintf("ESX or vCenter URL [%s]", envURL)
var urlFlag = flag.String("url", GetEnvString(envURL, "https://username:password@host/sdk"), urlDescription)

var insecureDescription = fmt.Sprintf("Don't verify the server's certificate chain [%s]", envInsecure)
var insecureFlag = flag.Bool("insecure", GetEnvBool(envInsecure, false), insecureDescription)

func processOverride(u *url.URL) {
        envUsername := os.Getenv(envUserName)
        envPassword := os.Getenv(envPassword)

        // Override username if provided
        if envUsername != "" {
                var password string
                var ok bool

                if u.User != nil {
                        password, ok = u.User.Password()
                }

                if ok {
                        u.User = url.UserPassword(envUsername, password)
                } else {
                        u.User = url.User(envUsername)
                }
        }

        // Override password if provided
        if envPassword != "" {
                var username string

                if u.User != nil {
                        username = u.User.Username()
                }

                u.User = url.UserPassword(username, envPassword)
                        }
}

func exit(err error) {
        fmt.Fprintf(os.Stderr, "Error: %s\n", err)
        os.Exit(1)
}

func main() {
        ctx, cancel := context.WithCancel(context.Background())
        defer cancel()

        flag.Parse()

        // Parse URL from string
        u, err := url.Parse(*urlFlag)
        if err != nil {
                exit(err)
        }

        fmt.Println("u:", u)

        // Override username and/or password as required
        processOverride(u)

        // Connect and log in to ESX or vCenter
        client, err := govmomi.NewClient(ctx, u, *insecureFlag)
        if err != nil {
                exit(err)
        }

        if client.IsVC() {
                fmt.Println("connected to vCenter")
        } else {
                fmt.Println("connected to ESXi host")
        }

        var perfManager mo.PerformanceManager
        err = client.RetrieveOne(ctx, *client.ServiceContent.PerfManager, nil, &perfManager)
        perfCounters := perfManager.PerfCounter

        counterDetails := make([][]string, 0)

        for _, perfCounter := range perfCounters {
                groupInfo := perfCounter.GroupInfo.GetElementDescription()
                nameInfo := perfCounter.NameInfo.GetElementDescription()

                fullName := groupInfo.Key + "." + nameInfo.Key + "." + fmt.Sprint(perfCounter.RollupType)
                counterDetails = append(counterDetails, []string{fullName, fmt.Sprint(perfCounter.Level), nameInfo.Summary})
        }

        outputFile, err := os.Create("performanceCounters.csv")
        csvWriter := csv.NewWriter(outputFile)
        csvWriter.WriteAll(counterDetails)

        if err := csvWriter.Error(); err != nil {
                log.Fatalln("error writing csv:", err)
        }
}

Performance Results

This is hardly scientific, but here are the times it took to run the Go and Powershell versions of the script. I measured the runs three times and used the Powershell measure-command.

Ubuntu 14.04.5 LTS
go 1.7.1 776 ms
PowerCLI alpha for Linux 2259 ms
Windows 10
go 1.7.1 1746 ms
PowerCLI 6.0 Release 1 build 2548067 1639 ms
Advertisements