Using the XtremIO REST API - Part 5

In Part 1 of Using the XtremIO REST API I covered how to access the API, and how to read data from it. Part 2 covered how to create and modify objects, Part 3 covered Snapshots, Part 4 was some Best Practices. Next up is an example using the API from Perl.

Using the REST API from Perl

My language-of-choice for scripting is Perl, and whilst it's not necessarily the best language for RESP API's, there are a few modules that can make it relatively easy, including REST::Client and JSON.

If you're using Red Hat/CentOS/etc then the majority of the modules you need can be installed using the following :

yum install perl-libwww-perl perl-JSON perl-Crypt-SSLeay

However at least for verison 6, the REST::Client module itself isn't available in the default RHEL/CentOS repositories, but it is available in EPEL. After configuring access to EPEL ("yum install epel-release" on CentOS, a little more difficult on RHEL) you can install it using :

yum install perl-REST-Client

Alternatively you can download the REST::Client module from CPAN and either compile/install it, or simply grab the lib/REST directory and put it somewhere in your Perl library path (eg, the currently directory!)

Next grab this relatively simple example script - show-vols - which will query the API and show basic details of all volumes configured on an array. You'll need to configure the details near the top of the script (username/password/XMS hostname or IP), but otherwise this script shouldn't need any changes.

Firstly we load in the Perl modules we're going to use. REST::Client is obviously used to make the REST requests, whilst JSON is needed to help us parse the results returned from the API, and MIME::Base64 is used to encode the username/password into the request. Data::Dumper isn't technically required, but it can be useful when trying to see the details of what is being returned by the API.

use REST::Client;
use MIME::Base64;
use JSON;
use Data::Dumper;

Next is a fairly simple function called checkerr() that can be used after each REST call to make sure the the call succeeded. In this case all errors will be fatal and the script will immediately print an error and exit, but of course that could be modified to act differently if required.

The XtremIO REST API requires very minimal configuration within the REST::Client module - we simply need to set the Content-Type to be application/json, and configure the standard HTTP Authentication header (note that whilst the password appears to be sent in clear-text, all communication is over HTTPS, so it's actually fully encrypted) :

my $client = REST::Client->new();
my $headers = {Authorization => "Basic ".encode_base64($username.":".$password), "Content-Type" => 'application/json'};

Now we can make our API call. REST::Client has a few ways of doing this, but the easiest is to just use the GET, POST, PUT and DELETE methods. So to issue a GET request to get the list of volumes we simply have :

$client->GET("https://$xms/api/json/v2/types/volumes", $headers);

The output from the above command will be a block of JSON formatted code, like :

{
    "volumes": [
        {
            "href": "https://xtremio4.scxtremiolab.com/api/json/v2/types/volumes/344",
            "name": "MyVol1",
            "sys-name": "mycluster"
        },
        {
            "href": "https://xtremio4.scxtremiolab.com/api/json/v2/types/volumes/345",
            "name": "MyVol2",
            "sys-name": "mycluster"
        },

The Perl JSON module (specifically the from_json() function) can trivially parse this, returning a tree of hashes and arrays depending on the actual data. The easiest way to see how it has actually formatted the resulting data is using the Data::Dumper module. Using print Dumper($resp) gives us :

$VAR1 = {
          'volumes' => [
                         {
                           'href' => 'https://xtremio4.scxtremiolab.com/api/json/v2/types/volumes/344',
                           'name' => 'MyVol1',
                           'sys-name' => 'mycluster'
                         },
                         {
                           'sys-name' => 'mycluster',
                           'name' => 'MyVol2',
                           'href' => 'https://xtremio4.scxtremiolab.com/api/json/v2/types/volumes/345'
                         },
[...]

So we have a hash (with at least one key called "volumes"), containing values that are an array (due to the []'s displayed), with each entry in the array being a hash with at 3 entries for name (the name of the volume), sys-name (the cluster name) and the unique URI for that volume. The URI is what will allow us to get more information for each of those volumes, so we can then walk through the array and grab just the href values for each of the volumes :

foreach my $v (@{$resp->{volumes}}) {
	push @Volumes, $v->{href};
}

Next it's simply a matter of looping through each of the href values , doing a GET for the URI to get the full details for that volume, and then printing the results.

Of course once again we'll get back a JSON string for the results, so again it's best to use Data::Dumper to start with to learn the format of the response :

$VAR1 = {
          'content' => {
                         'creation-time' => '2017-11-06 15:30:23',
                         'acc-size-of-rd' => '0',
                         'small-rd-bw' => '0',
                         'wr-latency' => '0',
[...etc...]
                         'name' => 'MyVol1',
                         'acc-num-of-small-rd' => '0'
                       }
        };

And from there we can find the fields we want and display them :

print << "EOT"
Volume name : $resp->{content}->{name}
Volume size : $resp->{content}->{"vol-size"}

The easier way

The example above gets the list of volumes and then loops through each one to get the full details. There's actually an easier way to do this, which is to append ?full=1 to the URL. eg, instead of requesting

https://xms.example.com/api/json/v2/types/volumes

which returns the name/cluster/href for each volume and requires a subsequent call for each volume to get the actual details, we can request

https://xms.example.com/api/json/v2/types/volumes?full=1

which will return all of the available data for all volumes.

You can even take this a step further and specify exactly which options you want returned, rather than the full list. In the script linked above we are only interetsed in the vol-size, logical-space-in-use and creation-time properties (plus name, which is always included) so we could use the following request :

https://xms.example.com/api/json/v2/types/volumes?full=1&prop=vol-size&prop=logical-space-in-use&prop=creation-time

which will return only those fields (plus a few default ones) :

{
    "volumes": [
        {
            "index": 344,
            "creation-time": "2017-11-06 15:30:23",
            "name": "MyVol1",
            "vol-size": "1048576",
            "guid": "e44cdfc10d914d7cba85de1a90af6d95",
            "logical-space-in-use": "0"
        },

Making changes

You can just as readily use REST::Client to make changes to the array as well, using POST, PUT and DELETE functions. Take a look at the create-vol script for a simple example of using a POST call to create a new volume.