Quantcast
Channel: tfindelkind.com
Viewing all articles
Browse latest Browse all 23

Nutanix REST API with Golang/Go Tutorial – Part 3 – Retrieve information about a VM (IP address, vCPU, MEM)

$
0
0

In this part I will focus on retrieving data from the Nutanix REST API. So basically this will show two important parts.

1. How to get data from the API !

2. How to parse the data which is in JSON format within GO !

We will cover these two examples:

  • Retrieve cluster config and settings
  • Retrieve VM configs (vCPU, MEM,IP Address ….)

Retrieve cluster config and settings

The URI “https://192.168.178.130:9440/PrismGateway/services/rest/v1/clusters/”  will retrieve a list of the clusters. Which in my case is only one.

cluster_rest_try

As you can see the data is in JSON format and needs to be parsed if we would like to use it. So there are two ways to do this.

  1. parsing JSON with the help of structs when the structure of the data is known
  2. parsing JSON with generic interface{} based for arbitrary data

For more details on this topic have a read here JSON-AND-GO

Parsing JSON with the help of structs when the structure of the data is known

In this case we got a valid response. This means we do know the structure of the data now. What I prefer is to create a struct which should represent the data within go. To do this it would be great to have a documentation or SDK which defines a representation of all responses. With AOS 5.0 there is a way to use swagger to generate this.

But today we can just create our own struct based on the response. So copy/paste the response to JSON-to-GO will return this struct.

type AutoGenerated struct {
	Metadata struct {
		GrandTotalEntities int `json:"grandTotalEntities"`
		TotalEntities int `json:"totalEntities"`
		FilterCriteria string `json:"filterCriteria"`
		SortCriteria string `json:"sortCriteria"`
		Page int `json:"page"`
		Count int `json:"count"`
		StartIndex int `json:"startIndex"`
		EndIndex int `json:"endIndex"`
	} `json:"metadata"`
	Entities []struct {
		ID string `json:"id"`
		UUID string `json:"uuid"`
		ClusterIncarnationID int64 `json:"clusterIncarnationId"`
		ClusterUUID string `json:"clusterUuid"`
		Name string `json:"name"`
		ClusterExternalIPAddress string `json:"clusterExternalIPAddress"`
		ClusterExternalDataServicesIPAddress string `json:"clusterExternalDataServicesIPAddress"`
		Timezone string `json:"timezone"`
		SupportVerbosityType string `json:"supportVerbosityType"`
		NumNodes int `json:"numNodes"`
		BlockSerials []string `json:"blockSerials"`
		Version string `json:"version"`
............

We can just use this struct and parse the response to it. You may think: “This will end up with a lot of structs and they are just huge”.  This could be the point where you have a look at the generic interface approach.

I created a simple example which extends the basic authentication part and adds the following:

  1. I am adding a a struct

type clustersGet struct {
Metadata struct {
GrandTotalEntities int `json:"grandTotalEntities"`
TotalEntities int `json:"totalEntities"`
.....

2. Define a GET to receive the cluster info

// Defines the HTTP Request
// send a GET to the NUTANIX API and receives the cluster info
// https://192.168.178.130:9440/PrismGateway/services/rest/v1/clusters
req, err = http.NewRequest("GET", v1_0(NutanixHost)+"/clusters", nil)

3. Send the GET and retrieve the data into bodyText which is an array of bytes ( byte[])

// before the request is send set the HTTP Header key "Authorization" with
// the value of base64 encoded Username and Password
req.Header.Set("Authorization", "Basic "+EncodeCredentials(username, password))

resp, err := httpClient.Do(req)
if err != nil {
log.Fatal(err)
os.Exit(1)
}
defer resp.Body.Close()

// read the data from the resp.body into bodyText
bodyText, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}

Create a variable based on the struct clustersGet

// create a variable based on the struct clusterGet
 var clustersGetResp clustersGet

Making use of json.Unmarshal to parse the data into the variable clusterGetResp and print a few values to std out.

// Parse/Unmarshal JSON into the struct
json.Unmarshal(bodyText, &clustersGetResp)

// Print the parsed data to stdout
println("ID: " + clustersGetResp.Entities[0].ID)
println("Name: " + clustersGetResp.Entities[0].Name)

Retrieve VM config (vCPU, Mem, IP Address….)

In the last example we made use of parsing json into structs. I prefer this way but there is a “simpler way” to achieve the same. Making use of the interface. The aim of this example is to retrieve some information about a specific VM.

So we would like to get the information about a VM called “docker-mac”. BTW: “I am using this VM to demonstrate the integration of Nutanix and docker.”

The first step would be to retrieve the UUID of the VM because the Nutanix REST API makes use of a unique identifier.

Lets get a list of all VMs and extract the UUID for the VM with the name “docker-mac”.

.
req, _ = http.NewRequest("GET", v2_0(NutanixHost)+"/vms", nil)
.
.
.
// create interface
var f interface{}
var uuid string

// Unmarshal into interface f
if err2 := json.Unmarshal(bodyText, &f); err != nil {
	panic(err2)
}

// type assertion to access f´s underlying map[string]interface
m := f.(map[string]interface{})

// the response will include entities which includes the data of the VMs we searching for
e := m["entities"].([]interface{})

// we can iterate through the map and search for the name of the VM
for k := range e {
	t := e[k].(map[string]interface{})
		if t["name"] == "docker-mac" {
		uuid = t["uuid"].(string)
	}
}

 

So we request a list of all VM’s first and then search for the name to get the UUID (Unique Universal ID) of the VM called “docker-mac”

Now we are able to request more info about this specific VM when requesting where bd74362d-2cb0-4d06-a95b-dfb7403c5a01 is the UUID.

/PrismGateway/services/rest/v2.0/vms/bd74362d-2cb0-4d06-a95b-dfb7403c5a01

req, _ = http.NewRequest("GET", v2_0(NutanixHost)+"/vms/"+uuid, nil)
.
.
.
// Unmarshal into interface f
if err2 := json.Unmarshal(bodyText, &f); err != nil {
	panic(err2)
}

m = f.(map[string]interface{})

fmt.Println(m["name"])
fmt.Println(m["memory_mb"])
fmt.Println(m["num_vcpus"])

 

A special case ! Getting the IP Address!

You may have noticed that there is no key/value which shows the IP Address of the VM. So first of all there are two different kind of IPs for a VM. If you are using AHV than you are able to retrieve an IP for a VM from IP pools which are managed by AHV itself. The other maybe more common way is that the VM get an IP via DHCP or it is statically set all without the “knowledge” of Nutanix.

Example!

AHV managed IP

To retrieve the IP when it is managed via the AHV IP pool the way to retrieve the IP Address is as follow. Just add the include_vm_nic_config paramter to the GET request and the NIC details will be included.

Keep an eye on the key “requested_ip_address”

The implementation is a little bit ugly because of the interfaces/mapping etc. but can be done.

req, _ = http.NewRequest("GET", v2_0(NutanixHost)+"/vms/?include_vm_nic_config=true", nil)

// create interface
var f interface{}

// Unmarshal into interface f
if err2 := json.Unmarshal(bodyText, &f); err != nil {
      panic(err2)
}

// type assertion to access f´s underlying map[string]interface
m := f.(map[string]interface{})

// the response will include entities which includes the data of the VMs we searching for
e := m["entities"].([]interface{})

// we can iterate through the map and search for IP of the VM
for k := range e {
	t := e[k].(map[string]interface{})
		fmt.Println(t["name"])
		if t["vm_nics"] != nil {
		n := t["vm_nics"].([]interface{})
			for k2 := range n {
			t2 := n[k2].(map[string]interface{})
				fmt.Println(t2["requested_ip_address"])
			}
		}
	}

 

IP Address of the VM if not managed by AHV

At the moment the v2 of the API is not able to provide the IP. So there is a fallback to the API v1 which just includes the IP. So a simple GET to https://192.168.178.130:9440/PrismGateway/services/rest/v1/vms/ will return all VMs and their IP Addresses.

The implementation is pretty simple because the info is direct at the main level of the VM.

// Defines the HTTP Request
// send a GET to the NUTANIX API v1 and receives the details of all VMs

req, _ = http.NewRequest("GET", v1_0(NutanixHost)+"/vms/", nil)
.
.
.

// Unmarshal into interface f
if err2 := json.Unmarshal(bodyText, &f); err != nil {
	panic(err2)
}

m = f.(map[string]interface{})
	
// the response will include entities which includes the data of the VMs we searching for      
e = m["entities"].([]interface{})

// we can iterate through the map and search for the IP of the VM
for k := range e {
	t := e[k].(map[string]interface{})
	fmt.Print("V1 Workaround: ")
        fmt.Println(t["ipAddresses"])
}

 

The post Nutanix REST API with Golang/Go Tutorial – Part 3 – Retrieve information about a VM (IP address, vCPU, MEM) appeared first on tfindelkind.com.


Viewing all articles
Browse latest Browse all 23

Trending Articles