First steps with Govmomi

This guide will assume that there is at least the basic familiarity to install the GO (golang) compiler tools, anyone looking for a start will find pretty much everything they need here -> https://golang.org/doc/install

What is Govmomi

The VMware virtual machine products (vSphere/ vCenter) expose the functionality through an API that is documented here -> (https://www.vmware.com/support/pubs/sdk_pubs.html). The technology that these APIs are exposed through is called SOAP (https://en.wikipedia.org/wiki/SOAP) and can be a little bit of a headache to interact with directly. However to ease the lives of anyone wanting to develop code against this SOAP api, VMware have released SDKs and libraries in a variety of languages (python, Java, .Net etc..). The Govmomi library is a GO package that provides the majority of functionality that an end user needs in order to communicate with the VMware vSphere/vCenter APIs.

Getting govmomi

All of the required source code for the VMware vSphere/vCenter GO SDK can be found on github at the following url -> (https://github.com/vmware/govmomi) as mentioned on the README has the go command for pulling the govmomi package.

go get -u github.com/vmware/govmomi

Note: The -u flag instructs go to pull any named dependencies.

To ensure that the govmomi packages were downloaded correctly we should be able to see all the code source tree by running the following command:

ls -la $(go env GOPATH)/src/github.com/vmware/govmomi

Hello World

Just to check that our environment is working as expected lets quickly create the hello world example to just to verify your GO environment. The following code snipped will create a file called govmomi/example.go which we can then use to ensure that things are working as expected.

The following commands can be copy and pasted into a terminal and will create a local govmomi directory and create the example.go file that we will use for development moving forward.

Hello World source code

1
2
3
4
5
6
7
8
9
10
mkdir govmomi; cd govmomi
cat <<EOF > example.go
package main

import "fmt"

func main() {
fmt.Println("Hello world")
}
EOF

To run the above code we can use the following command go run example.go, and we should see Hello world printed to STDOUT.

Logging into VMware vSphere or vCenter

The following code snippet will extend on our previous example, and will make use of additional packages including the govmomi package to provide our required functionality.

Note: This code uses the url of the vSphere/vCenter instance were trying to interact with. This url will always require the following formatting:

protocol://username:password@hostname/sdk

A correct example would be:

https://administrator@vsphere.local:pass1234@vcenter.devlab.local/sdk

Updated source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package main

import (
"context"
"flag"
"fmt"
"net/url"
"github.com/vmware/govmomi"
)

func main() {
vURL := flag.String("url", "", "The URL of a vCenter server")
flag.Parse()

u, err := url.Parse(*vURL)
if err != nil {
fmt.Printf("Error parsing url %s\n", vURL)
return
}

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

c, err := govmomi.NewClient(ctx, u, true)
if err != nil {
fmt.Printf("Logging in error: %s\n", err.Error())
return
}

fmt.Println("Log in successful")
c.Logout(ctx)
}

To understand this code we will deconstruct the various important sections.

Imports

To provide the required functionality were pulling in a lot more packages, for a bit more understanding I’ve added either the project URL or the godoc location.

Flags

There are a number of different methods a developer could use to pass data into a program, it could even be hardcoded into the code itself (not recommended). The main options for getting data into a simple CLI program are:

  • Read the data from a file
  • Pass data from environment variables
  • Pass data to the program at runtime through command line flags

In our example we will be using flags thats are provided through the standard library and work in a key/value fashion. The key being the name of the flag -url and the value being data we pass to this key https://{...}.

The following two lines taken from the code above will handle the user input from the CLI.

This first line will declare a variable vURL that will be assigned from the flag named url.
vURL := flag.String("url", "", "The URL of a vCenter server")

The second line will parse all of the created flags to ensure that they’re read correctly or assigned their default values etc..
flag.Parse()

URL Parsing

The govmomi client requires a URL object not just a string representation of the vCenter URL. So we will use the net/url library to parse the string taken from the flag -url as done with the line u, err := url.Parse(*vURL)

Context

The two lines around context (explained above) are used to ensure that a state is shared across multiple APIs, functions and goroutines. In our simple example we don’t need to delve into this in two much detail, but if were to imaging that there were multiple operations taking place such as processing some data, logging into vCenter etc.. and one of the operations failed for a reason, the context would be used to share the fact that all of the other operations sharing that context needs cancelling.

Creating a vCenter/vSphere client

At this point in the code we’ve taken the VMware vCenter URL from a CLI flag and we’ve set up a context to handle a shared state, we will now use these in order to create our vCenter client with the line c, err := govmomi.NewClient(ctx, u, true).

Quickly deconstructing this line:

  • c, err - Return the client object c and an error object err (more or err in a second)
  • govmomi.NewClient - Call the function from the govmomi package
  • ctx - Pass in the shared context
  • u - Pass in the “parsed” url (ultimately taken from the -url string)
  • true - A Boolean value true/false that dictates if the client will tolerate an insecure certificate (self-signed)

If the function call doesn’t return an error object then the login was successful so we print a message to STDOUT and call the logout method on the govmomi client object.

Error handling

A lot of functions in GO will typically return more than one variable/object and the majority of them will return an object of type error, we can see this by looking at the returns from the url.Parse() and govmomi.NewClient() function calls. In the event of a function being successful then the function will return nil in the place of an error object. However when things go wrong then a function should create a new error object with the appropriate error details/messaging.

To check if a function has failed the boiler plate code would typically look like:

1
2
3
4
if err != nil {
// Write error message / parse err object
}

Running our code

To run our code is very simple, we have two options we can compile it directly into a binary or run it directly from the source

Build a binary

We will build our code into a program called govmomi with the command go build -o govmomi we can now run our code with the command:

1
2
3
go build -o govmomi
./govmomi -url "https://dan@vsphere.local:CorrectPass@vcenter.devlab.local/sdk"
Log in successful

Run from source

To run directly from the source code we use the go run command as shown below:

1
2
go run example.go -url "https://dan@vsphere.local:CorrectPass@vcenter.devlab.local/sdk"
Log in successful

Next Steps

If everything worked as expected then there should be a success message printed on screen, in the next post we will look at extending our very basic example into something that offers a lot more functionality.

BONUS POINTS

In this example we pass in the URL through the use of flags on the CLI, another user on the same host will be able to find the vCenter URL and credentials by looking at teh list of processes. The use of environment variables will keep that hidden and within a users session.

Think about removing the flag.String and look at os.Genenv :-)

Further reading -> https://golang.org/pkg/os/#example_Getenv

Clearing up

To remove all of the code examples that we created we will just need to remove the govmomi folder we created in the Hello World section.