Nutanix : REST API Calls Examples


Background

Nutanix platform can be queried out by external application to read/write information to/from the cluster. This can be very handy to connect Nutanix with the external world. This is how Nutanix technology partners are inter-acting with the platform. Example, a platform like Rubrik is making good use of those APIs to perform backups. on the other side, this is how Nutanix instruct vmware to create VMs ...

I've decided to implement a small script to get access to some cluster details and then create a little dashboard in my own flavour. You can consider this as a technology demonstrator.

REST APIs

Nutanix platform is providing powerful APIs. It exists 4 versions of them respectively called API v0.8, v1, v2 and v3. They are all capable of different things. There is an API explorer directly available from Prism Element and you can find all the relevant documentation in-line as well with usage example. Very handy.

To access the API explorer, from Prism Element go to the profile menu and choose REST API Explorer :


This will open a new window where you have access to all API version. By default you should be in API v2 mode.


Let's have a look at the cluster GET operation by clicking it :


Here is the curl syntax and the request URL which are providing us with all the details about the cluster. Do not forget to add a valid username and password and adjust the target IP to the VIP of your cluster. This is an API v1 call. Let's see a quick example from the command prompt.

$ curl -k -u user:password -X GET --header 'Accept: application/json' https://192.168.8.189:9440/PrismGateway/services/rest/v1/cluster/

 
   "id":"000512b5-c10d-xxxx-0000-000000005f0a::24330",
   "uuid":"000512b5-c10d-xxxx-0000-000000005f0a",
   "clusterIncarnationId":1427946xxxx50545,
   "clusterUuid":"000512b5-c10d-xxxx-0000-000000005f0a",
   "name":"BE-NTNX",
   "clusterExternalIPAddress":"192.168.8.189",
   "clusterExternalDataServicesIPAddress":"192.168.8.190",
   "timezone":"Europe/Brussels",
   "supportVerbosityType":"BASIC",
   "operationMode":"Normal",
   "storageType":"mixed",
   "clusterFunctions": 
      "NDFS"
   ],
   "numNodes":3,
   "blockSerials": 
      "15SM1xxxxx29"
   ],
   "version":"5.5.0.6",
   "fullVersion":"el7.3-release-euphrates-5.5.0.6-stable-14bd63735db09b1c9babdaaf48d062723137fc46",
   "targetVersion":"5.5.0.6",
   "externalSubnet":"192.168.8.0/255.255.255.0",
   "internalSubnet":"192.168.5.0/255.255.255.128",
   "nccVersion":"ncc-3.5.0.3",
   "enableLockDown":false,

[...]

   },
   "enforceRackableUnitAwarePlacement":false,
   "disableDegradedNodeMonitoring":true,
   "commonCriteriaMode":false,
   "enableOnDiskDedup":null,
   "managementServers":null
}

To facilitate the reading, I have formatted the JSON output with an online validator.

So, with this easy API call, we have the entire cluster status. Then you can easily imagine a little computation to read the JSON properly and display the data in a nice human readable way.

Another example, see what users are connected on the cluster

$ curl -k -u user:password -X GET --header 'Accept: application/json' https://192.168.8.189:9440/PrismGateway/services/rest/v1/users/logged_in_users

 
   "metadata": 
      "grandTotalEntities":1,
      "totalEntities":1
   },
   "entities": 
       
         "profile": 
            "username":"flhoest",
            "firstName":"Frederic",
            "middleInitial":"",
            "lastName":"Lhoest",
            "emailId":"flhoest@y.com",
            "password":null,
            "locale":"en-US",
            "region":"en-US"
         },
         "loginSessionInfo": 
            "ipInfo": 
               "192.168.3.103": 
                  "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36"
               ],
               "192.168.3.114": 
                  "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36"
               ],
               "192.168.3.182": 
                  "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36"
               ],
               "192.168.3.161": 
                  "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36"
               ],
               "192.168.7.32": 
                  "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36",
                  "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36"
               ]
            }
         }
      }
   ]
}

This is a great way to report cluster information to any external system.

Now, let's create a VM from API calls

To create a VM, we need to pass JSON VM definitions. Such as VM name, memory, CPU, disk, ... You don't need to specify the UUID, it is generated automatically.

Our JSON will look like this : 

{
  "memoryMb": 2048,
  "name": "REST_API_test",
  "numVcpus": 2,
  "vmDisks": [
    {
      "diskAddress": {
        "deviceBus": "IDE",
        "deviceIndex": 0
      },
      "isCdrom": true,
      "isEmpty": true
    }
  ]
}

Simple VM with 2 vCPU, 2 GB RAM and a CD-ROM reader. This is an API v1 call. In a terminal it looks like this :

$ curl -k -u user:password -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' -d '{"memoryMb": 2048,"name": "REST_API_test","numVcpus": 2,"vmDisks": [{"diskAddress": {"deviceBus": "IDE","deviceIndex": 0},"isCdrom": true,"isEmpty": true}]}' https://192.168.8.189:9440/PrismGateway/services/rest/v1/vms/
{"taskUuid":"79fcd7ab-b6c8-49bd-ba54-e6706255e01e"}

The command might be a bit long and complex to read, but usually, nobody will type this, this is all part of scripts and variables. This is only a way to demonstrate how to manipulate REST API calls from the command line. 

The VM has been created and this operation can be seen in the Prism UI :



Deleting the VM we just created only requires to pass the UUID and optionally, we can chose to delete all VM-related snapshots. This is an API v2 call.

$ curl -k -u user:password -X DELETE --header 'Accept: application/json' 'https://192.168.8.189:9440/api/nutanix/v2.0/vms/eeee0d10-2574-4faf-899e-d7cb2e802000/?delete_snapshots=true'
{"task_uuid":"05ea3a32-7230-4e2e-a32a-1edebf0d0407"}

The response from the API server is a task_uuid. It means the task has been queued into the cluster's life and will be processed as soon as possible. You can review the task operation by again using a REST API call to see what the tasks did :

$ curl -k -u user:password -X GET --header 'Accept: application/json' https://192.168.8.189:9440/api/nutanix/v2.0/tasks/05ea3a32-7230-4e2e-a32a-1edebf0d0407?include_subtasks_info=true
{"uuid":"05ea3a32-7230-4e2e-a32a-1edebf0d0407","meta_request":{"method_name":"VmDelete"},"meta_response":{"error_code":0},"create_time_usecs":1522404476424297,"start_time_usecs":1522404476449803,"complete_time_usecs":1522404476708027,"last_updated_time_usecs":1522404476708027,"entity_list":[{"entity_id":"eeee0d10-2574-4faf-899e-d7cb2e802000","entity_type":"VM","entity_name":null}],"operation_type":"VmDelete","message":"","percentage_complete":100,"progress_status":"Succeeded","subtask_uuid_list":["1d64b88a-76bf-458a-8498-389b61f19622"],"subtask_info_list":[{"uuid":"1d64b88a-76bf-458a-8498-389b61f19622","meta_request":{"method_name":"VmDelete"},"meta_response":{"error_code":0},"create_time_usecs":1522404476477615,"start_time_usecs":1522404476511498,"complete_time_usecs":1522404476588338,"last_updated_time_usecs":1522404476588338,"entity_list":[{"entity_id":"eeee0d10-2574-4faf-899e-d7cb2e802000","entity_type":"VM","entity_name":null}],"operation_type":"kVmDelete","message":"","percentage_complete":100,"progress_status":"Succeeded","parent_task_uuid":"05ea3a32-7230-4e2e-a32a-1edebf0d0407","cluster_uuid":"000512b5-c10d-f271-0000-000000005f0a"}],"cluster_uuid":"000512b5-c10d-f271-0000-000000005f0a"}

The formatted response (more readable) is : 

 
   "uuid":"05ea3a32-7230-4e2e-a32a-1edebf0d0407",
   "meta_request": 
      "method_name":"VmDelete"
   },
   "meta_response": 
      "error_code":0
   },
   "create_time_usecs":1522404476424297,
   "start_time_usecs":1522404476449803,
   "complete_time_usecs":1522404476708027,
   "last_updated_time_usecs":1522404476708027,
   "entity_list": 
       
         "entity_id":"eeee0d10-2574-xxxx-899e-d7cb2e802000",
         "entity_type":"VM",
         "entity_name":null
      }
   ],
   "operation_type":"VmDelete",
   "message":"",
   "percentage_complete":100,
   "progress_status":"Succeeded",
   "subtask_uuid_list": 
      "1d64b88a-76bf-xxxx-8498-389b61f19622"
   ],
   "subtask_info_list": 
       
         "uuid":"1d64b88a-76bf-xxxx58a-8498-389b61f19622",
         "meta_request": 
            "method_name":"VmDelete"
         },
         "meta_response": 
            "error_code":0
         },
         "create_time_usecs":1522404476477615,
         "start_time_usecs":1522404476511498,
         "complete_time_usecs":1522404476588338,
         "last_updated_time_usecs":1522404476588338,
         "entity_list": 
             
               "entity_id":"eeee0d10-xxxx-4faf-899e-d7cb2e802000",
               "entity_type":"VM",
               "entity_name":null
            }
         ],
         "operation_type":"kVmDelete",
         "message":"",
         "percentage_complete":100,
         "progress_status":"Succeeded",
         "parent_task_uuid":"05ea3a32-7230-4e2e-a32a-1edebf0d0407",
         "cluster_uuid":"000512b5-xxxx-f271-0000-000000005f0a"
      }
   ],
   "cluster_uuid":"000512b5-xxxx-f271-0000-000000005f0a"
}

It displays the status of the task, it completeness and the result (status).

What about Php scripting ?

Yes, true, php is probably one of my favourite programming languages since this is literally "all terrain" IT languages. I'm creating script for whatever I want in Php. So why not making REST API calls on a Nutanix cluster with Php !

Here is a sample of the last API call above

<?PHP
$clusterIP="192.168.8.189";
$API_CALL="api/nutanix/v2.0/tasks/79fcd7ab-b6c8-49bd-ba54-e6706255e01e?include_subtasks_info=true";
$username="username";
$password="password";
$curl = curl_init();
curl_setopt($curl, CURLOPT_USERPWD, $username.":".$password);
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Accept: application/json'));
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_URL, "https://".$clusterIP.":9440/".$API_CALL);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

$result = curl_exec($curl);
print(curl_error($curl)."\n");

curl_close($curl);
var_dump(json_decode($result));
?>

Once executed it will return the JSON output we are use to : 

$ php -f nxGetInfo.php

object(stdClass)#1 (15) {
  ["uuid"]=>
  string(36) "79fcd7ab-b6c8-49bd-ba54-e6706255e01e"
  ["meta_request"]=>
  object(stdClass)#2 (1) {
    ["method_name"]=>
    string(8) "VmCreate"
  }
  ["meta_response"]=>
  object(stdClass)#3 (1) {
    ["error_code"]=>
    int(0)
  }
  ["create_time_usecs"]=>
  int(1522403890229910)
  ["start_time_usecs"]=>
  int(1522403890260801)
  ["complete_time_usecs"]=>
  int(1522403890493811)
  ["last_updated_time_usecs"]=>
  int(1522403890493811)

[...]

  array(1) {
        [0]=>
        object(stdClass)#8 (3) {
          ["entity_id"]=>
          string(36) "eeee0d10-2574-4faf-899e-d7cb2e802000"
          ["entity_type"]=>
          string(2) "VM"
          ["entity_name"]=>
          NULL
        }
      }
      ["operation_type"]=>
      string(9) "kVmCreate"
      ["message"]=>
      string(0) ""
      ["percentage_complete"]=>
      int(100)
      ["progress_status"]=>
      string(9) "Succeeded"
      ["parent_task_uuid"]=>
      string(36) "79fcd7ab-b6c8-49bd-ba54-e6706255e01e"
      ["cluster_uuid"]=>
      string(36) "000512b5-c10d-f271-0000-000000005f0a"
    }
  }
  ["cluster_uuid"]=>
  string(36) "000512b5-c10d-f271-0000-000000005f0a"
}

Now, a POST example, creating the same VM as the one in the example above in this page

<?PHP
$clusterIP="192.168.8.189";
$API_CALL="/PrismGateway/services/rest/v1/vms/";
$username="username";
$password="password";
$curl = curl_init();
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS,"{  \"memoryMb\": 2048,  \"name\": \"REST_API_test\",  \"numVcpus\": 2,  \"vmDisks\": [    {      \"diskAddress\": {        \"deviceBus\": \"IDE\",        \"deviceIndex\": 0      },      \"isCdrom\": true,      \"isEmpty\": true    }  ]}");
curl_setopt($curl, CURLOPT_USERPWD, $username.":".$password);
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_URL, "https://".$clusterIP.":9440/".$API_CALL);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

$result = curl_exec($curl);
print(curl_error($curl)."\n");

curl_close($curl);
var_dump(json_decode($result));

?>

Quick and dirty, and it just works ! Now, sky is the limit, go and create API call for anything you want. You can even re-create Prism Element from scratch - if you want ;)

I really hope this is helping other, I struggled to have the curl authentication working.

Comments

What's hot ?

ShredOS : HDD degaussing with style

Mac OS X : Display images in-line with terminal