Using REST API with PERL

The REST API allows users to query the iQSonar results directly using the web client protocol. The results are returned in JSON format. This article is part of a series on how to make use of the Rest API.

This worked example uses PERL to produce a CSV file containing details of devices directly from the scan results. We look for the host name, the total installed RAM and the CPU type. The device name will be listed in the "device" results. For the CPU Type and the installed RAM we need to then go to the details page for the device.

Step-by-step guide

Prerequisites:

  • You need to know the URL for you iQSonar install - in this example our host is vm-mike-2k12a
  • You need credentials for the iQSonar install - in this example we use the default login admin / password
  • PERL - this is installed as part of almost all Unix distributions. A free version called Strawberry Perl, and a commercial implementation from Active State called ActivePerl are available for Windows.
  • CPAN Modules used: LWP, JSON::XS


Step One: Connect to the REST API on our iQSonar instance.

In order to connect to the RestAPI we need to know the following:

  • The URL of the iQSonar host (in this example we use a host called vm-mike-2k12a )
  • The “realm” for the security credentials (iQSonar uses iQSonar RestAPI Realm )
  • The username and password (in this example we’re using the installation default credentials username “admin” password “password”; in a real world deployment you should always change your passwords!)

So, the PERL code to connect to the server and get the devices is as follows:


Get the list of devices
#!/bin/perl -w
# Perl script to access JSON data from iQSonar REST API
use LWP;                            # Module to get web page content
use JSON::XS ;                      # Module to parse JSON
my $iQSonar = 'iqsonar-host:80';  # URL of the REST API for the iQSonar instance, for credentials
my $realm = 'iQSonar RestAPI Realm';
my $browser = LWP::UserAgent->new;                    # need to get a web page
$browser -> credentials($iQSonar,$realm,'admin'=>'password');
my $url =  'http://iqsonar-host/api/v1/devices';
my $DeviceList = $browser→get($url);
   die "Error: unable to get REST API results"
   unless $DeviceList->is_success;
# The variable $DeviceList now contains the JSON output list of known devices
my @ParsedDeviceList = @{decode_json( $DeviceList->content ) };
            #  Parse into a PERL Array of objects


At this point in the script, we have a variable $DeviceList which contains the JSON output from the Rest API. We then use a function call “decode_json()” from the “JSON::XS” library to convert this text file into a PERL data structure.

The data structure is a JSON array of objects, each object contains an associative array (in PERL, this is a hash) of device attributes:

  • device_id
  • host_name
  • serial_number
  • manufacturer
  • model
  • last_scan
  • self

The “self” attribute is particularly interesting, as it is a URL that gives the link to more details about the device. Also note that if the device in question does not have a value, the key is omitted.

(Note that by default the REST API returns a list of 200 devices at a time. Use the off_set and fetch_size parameters to page through a longer list of devices.

Step Two - iterate over the list of devices

Now we’re producing a CSV file from the device list… so for each key/value pair we test it is defined, and print out either a result or a placeholder showing there is no result.

Iterate over devices
foreach $device ( @ParsedDeviceList  )
{
    if ( defined $device->{'host_name'} )
    {
           print $device->{'host_name'} ;
    } else { 
            print "(no hostname)";
    }
    print  ",";
    if ( defined $device->{'serial_number'})
    {
        print $device->{'serial_number'};
    } else {
        print "(no s/n)" ;
    }
    … and so on …
}


Step Three: For each device, get the extra information we’re interested in

Let’s say that we want to know the CPU details – CPU Count, CPU Type, and No of Cores. (Useful for licencing queries)

We take the value from the “self” key and look up another result from the server

Get extra details for devices
my $urlSelf = $device->{'self'} ;
    $selfResults = $browser->get($urlSelf) ;
    if ( $selfResults ->is_success )
    {
        my $deviceDetails = decode_json( $selfResults->content ) ;
        if ( defined $deviceDetails -> {'cpu_count'} )
        {
            print $deviceDetails -> {'cpu_count'} , ",";
        } else {
            print "(no cpu count), " ;
        }
        if (defined $deviceDetails->{'cpu'}  )
        {
            # CPU info is an ARRAY - let's just report on the first one
            # Also, CPU model can contain a comma, so enclose in quotes
            print '"';
            print $deviceDetails->{'cpu'}->[0]->{'cpu_model'};
            print '"';
        } else {
            print "(No CPU Model)";
        }
        … and so on …
    }


Source code for the completed script

#!/bin/perl -w
# Perl script to access JSON data from iQSonar REST API
use LWP;					# Module to get web page content
use JSON::XS ;				# Module to parse JSON

my $iQSonar = 'iqsonar-host:80';	# URL of the REST API for the iQSonar instance, for credentials
my $realm = 'iQSonar RestAPI Realm';
my $browser = LWP::UserAgent->new;				# need to get a web page
$browser -> credentials($iQSonar,$realm,'admin'=>'password');

my $url =  'http://iqsonar-host/api/v1/devices';
my $DeviceList = $browser->get($url);
  die "Error: unable to get REST API results"
   unless $DeviceList->is_success;

# The variable $DeviceList now contains the JSON output list of known devices
my @ParsedDeviceList = @{decode_json( $DeviceList->content ) };		#  Parse into a PERL Array of objects

print "HostName,Serial No,Manufacturer,Model,VM,CPU Count,Core Count,Total Ram,CPU Model \n"; 

foreach $device ( @ParsedDeviceList  )
{	
	if ( defined $device->{'host_name'} )
	{ 
		print $device->{'host_name'} ;
	} else { 
		print "(no hostname)"; 
	} print  ",";
	if ( defined $device->{'serial_number'})
	{
		print $device->{'serial_number'};
	} else {
		print "(no s/n)" ;
	}
	print ",";
	if (defined $device->{'manufacturer'})
	{
		# The VMWare manufacturer string contains a comma, so output this in double quotes to keep this as valid CSV
		print '"', $device->{'manufacturer'}, '"';
	} else {
		print "(no mfg)" ;
	}	  print ",";
	if ( defined $device->{'model'} )
	{
		# SUN models can contain a comma
		print '"', $device->{'model'} , '"';
	} else {
		print "(no model)" ;
	} 
	print ",";
	
	my $urlSelf = $device->{'self'} ;
	$selfResults = $browser->get($urlSelf) ;
	if ( $selfResults ->is_success )
	{
		my $deviceDetails = decode_json( $selfResults->content ) ;
		
		if ( $deviceDetails -> {'is_virtual'} )
		{
			print "True,";
		} else {
			print "False,"	;
		}							# VM or physical host?
		
		if ( defined $deviceDetails -> {'cpu_count'} )
		{
			print $deviceDetails -> {'cpu_count'} , ",";
		}
		else {
			print "(no cpu count), " ;
		}
		if ( defined $deviceDetails -> {'core_count'} )
		{
			print $deviceDetails -> {'core_count'} , ",";
		}
		else {
			print "(no core count), " ;
		}
		if (defined $deviceDetails->{'total_memory_mb'})
		{
			print $deviceDetails->{'total_memory_mb'} , ",";
		}
		else {
			print "(No RAM), ";
		}
		if (defined $deviceDetails->{'cpu'}  )
		{
			# CPU info is an ARRAY - but let's just report on the first one
			# Also, CPU model can contain a comma
			
			print  '"', $deviceDetails->{'cpu'}->[0]->{'cpu_model'} , '"';
		} 
		else {
			print "(No CPU Model)";
		}
	}
	else {
		print " ** Unable to query device details ** ";
	}
	print "\n";
}


Related articles