Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

The REST API allows users to query the iQSonar results directly using the web client protocol. The results are returned in JSON format.

This worked example uses Python to produce a list of hosts (devices) which have enterprise database applications. If the device has a database, we print off the 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 Python to produce a list of hosts (devices) which have enterprise database applications. If the device has a database, we print off the host name, the total installed RAM and the CPU type; we then list the number and edition of the databases. The device name will be taken from the "device" results. For the CPU Type and the installed RAM we need to then go to the details page for the device; For the database details we then go into the applications page. Thus for each device we find, we make at least two and sometimes three REST API calls.

...

  • NOTE: both Python 2 and Python 3 are actively used in different environments. This example uses Python 3 syntax.
  • You need to know the URL for you iQSonar install - in this example our host is iqsonar-host
  • You need credentials for the iQSonar install - in this example we use the default login admin / password
  • You need the  "requests" module for Python which handles web requests very nicely. If this is not installed on your system you can install it as follows:

On Linux or macOS:

...

pip install -U pip requests 

On Windows:

python -m pip install -U pip requests 

Step One – Connect to the iQSonar Host

To access the REST-API we use HTTP with basic authentication. in Python we do this using the "requests" library. You must update this URL to reflect your host, and update the username and password to reflect the credentials for your instance of iQSonar. The "X-fetch-count" variable in the header tells us the total number of devices which have been scanned. In this example we will stop after the first 200 if the Scan Engine has scanned that many. You can look at some of the other worked examples in PowerShell for examples showing paging through the results.

The line "data = r.json()" takes the JSON results and parses it into a Python array variable.

Code Block
languagepy
titleConnect to the remote host
#!/usr/bin/python3
import requests
# Set this to your own host name/login/password)
r = requests.get('http://vm-mike-er3/api/v1/devices',auth=('admin','password'))

max = r.headers['X-fetch-count']
data = r.json()

The line "#!/usr/bin/python3" lets Python know that this is a Python 3 script.

Step Two – Iterate over the array of devices

At this point in the script, we have a variable data which contains the JSON output from the Rest API. 

The data structure is a JSON array of objects, each object contains an array of device attributes:

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

...

  • If this is not installed on your system you can install it as follows:

On Linux or macOS:


pip install -U pip requests 


On Windows:


python -m pip install -U pip requests 

Step One – Connect to the iQSonar Host

To access the REST-API we use HTTP with basic authentication. in Python we do this using the "requests" library. You must update this URL to reflect your host, and update the username and password to reflect the credentials for your instance of iQSonar. The "X-fetch-count" variable in the header tells us the total number of devices which have been scanned. In this example we will stop after the first 200 if the Scan Engine has scanned that many. You can look at some of the other worked examples in PowerShell for examples showing paging through the results.

The line "data = r.json()" takes the JSON results and parses it into a Python array variable.

Code Block
languagepy
titleConnect to the remote host
#!/usr/bin/python3
import requests
# Set this to your own host name/login/password)
r = requests.get('http://iqsonar-host/api/v1/devices',auth=('admin','password'))

max = r.headers['X-fetch-count']
data = r.json()

The line "#!/usr/bin/python3" lets Python know that this is a Python 3 script.

Note that if you have a problem with the credentials, Python will throw an exception when you attempt to access r.headers[]
See step three for an example of exception handling code.

Step Two – Iterate over the array of devices

At this point in the script, we have a variable data which contains the JSON output from the Rest API. 

The data structure is a JSON array of objects, each object contains an array of device attributes:

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

The "self" item is a link to the full details on the device.

Code Block
languagepy
titleIterate over devices
# set some counters
noapps=0
nodb = 0
gotone=0

count = len(data)
i = 0
while (i < count):
    row = data[i]
    gotone=0
        
    if ( 'host_name' in row ):
        hostname = row['host_name']
    else:
        hostname = '(no hostname)'
        
    url2 = row['self']
    r2 = requests.get(url2,auth=('admin','password'))
    device = r2.json()
    if ('total_memory_mb' in device):
        ram = device['total_memory_mb']
    else:
        ram = '(unknown ram)'
    if ('cpu' in device):   
        cpu = device['cpu'][0]['cpu_model']
        # remove commas from the cpu string so as to keep the CSV output valid
        cpu = cpu.replace(',','')
    else:
        cpu = '(unknown cpu)' 
    status = hostname + ': ' + str(ram) + 'MB RAM, ' + str(cpu)

Step Three – Process the Applications link

One caveat - as of Elcano R2, the applications link exists even when the device does not have any scanned applications. Following the link in these cases results in an exception - so we use a TRY/CATCH block to work around this. While this was corrected in Fu R1 and subsequent releases, the exception handling method shown here is still a useful example of handling exceptions.

Code Block
languagepy
titleIterate over devicesGet application details
    # setHaving somegot counters
noapps=0
nodb = 0
gotone=0

count = len(data)
i = 0
while (i < count):Hostname, Ram and CPU, lets look for databases?
    if ('applications' in device):      row  =
data[i]     gotone=0   url3 = device['applications']
        if ( 'host_name' in row ):r3 = requests.get(url3,auth=('admin','password'))
        # the URL hostnamemight = row['host_name']
    else:
    not be valid. If no applications, server will return a 500 error
   hostname  = '(no hostname)' try:
            url2apps = row['self'] r3.json()        r2 = requests.get(url2,auth=('admin','password'))  
  device = r2.json()    except:
if ('total_memory_mb' in device):         ramnoapps += device['total_memory_mb'] 1
        else:
            ramnumapps = 'len(unknown ramapps)'
    if ('cpu' in device):     j=0
      cpu = device['cpu'][0]['cpu_model']    while (j < numapps):
 # remove commas from the cpu string so as to keep the CSV output valid # Deal with the application entries
  cpu = cpu.replace(',','')     else:       j+=1  cpu = '(unknown cpu)' 
    status = hostname + ': ' + str(ram) + 'MB RAM, ' + str(cpu)

Step Three – Process the Applications link

One caveat - as of Elcano R2, the applications link exists even when the device does not have any scanned applications. Following the link in these cases results in an exception - so we use a TRY/CATCH block to work around this.

With each application, we're only interested if it is a database application... for any other application type we're going to ignore it.

The database name is stored in apps[j]['product']['name'], but not all applications have product names... hence the nested IF blocks to test if the variable is defined.

If the application name contains "SQL" (Microsoft SQL Server), "Oracle Database" or "Informix" then we want to list the application along with the edition. If the Application Description contains "DB2 Database" we know it is a DB2 database. We cannot search for DB2 on its own in the Product Name or else we find DB2 Connect as well, and DB2 databases are listed as DB2. 

Code Block
languagepy
titleGet Deal with each application details
    # Having got
Hostname, Ram and CPU, lets look for databases?     ifwhile ('applications'j in< devicenumapps):
                url3 = device['applications']
 if ('product' in apps[j]):
      r3 = requests.get(url3,auth=('admin','password'))         # the URL might not be valid. If no applications, server will return a 500 errorif ('name' in apps[j]['product']):
                 try:       if (('SQL' in apps[j]['product']['name']) or
 apps = r3.json()                     except:    ('Oracle Database' in apps[j]['product']['name']) or
    noapps += 1         else:             numapps = len(apps)
('Informix' in apps[j]['product']['name']) ):
           j=0             while (j < numapps): status = status      + '\n  ' + str(apps[j]['product']['name']) 
  # Deal with the application entries                 j+=1    

With each application, we're only interested if it is a database application... for any other application type we're going to ignore it.

The database name is stored in apps[j]['product']['name'], but not all applications have product names... hence the nested IF blocks to test if the variable is defined.

If the application name contains "SQL" (Microsoft SQL Server), "Oracle" or "Informix" then we want to list the application along with the edition.

Code Block
languagepy
titleDeal with each application
if ('edition' in apps[j]): status = status + ' '+ str(apps[j]['edition'])
                            else: status = status + while' (jno <edition numapps):info)'
                            gotone+=1
if ('product' in apps[j]):                     if ('nameDB2 Database' in apps[j]['product']['description']):
                            status = status + '\n if ('SQL' in+ str(apps[j]['product']['name']): 
                           status = status + '\n  ' + str(if ('edition' in apps[j]['product']['name']) ): status = status + ' '+ str(apps[j]['edition'])
                            else: status gotone+=1= status + ' (no edition info)'
                         if ('Oracle' in apps[j]['product']['name']):
                  gotone+=1

Outside the loop, we want to only print results if the database has been discovered. If there was no database gotone will be 0, so we only print the status line where gotone is greater than zero.

The final test is to see whether we've got more results. Code to actually process more than one batch of devices is left as an exercise for the reader.

Code Block
languagepy
titleDisplay results
#
    if (gotone > 0):
  status = status + '\n  ' +print str(apps[j]['product']['name'](status)
+ ' '+ str(apps[j]['edition'])
     i+=1
if (max > count):
    print(   "There is another page of results in the REST-API if you want to get it"  gotone+=1)
else:
    print("That's all folks")


Final completed application

Code Block
languagepy
titleCompleted Script
#!/usr/bin/python3
# RestAPI example in Python
#
import requests
# Set this to your own host name/login/password)
r 

...

= requests.get('

...

http://iqsonar-host/api/v1/devices',auth=('admin','password'))

# set some counters
noapps=0
nodb = 0
gotone=0

max = r.headers['X-fetch-count']
data = r.json()


count = len(data)
i = 0
while (i < count):
    row = data[i]
    gotone=0
        
    if ( 

...

Outside the loop, we want to only print results if the database has been discovered. If there was no database gotone will be 0, so we only print the status line where gotone is greater than zero.

The final test is to see whether we've got more results. Code to actually process more than one batch of devices is left as an exercise for the reader.

...

languagepy
titleDisplay results

...

'host_name' in row ):
        hostname = row['host_name']
    else:
        hostname = '(no hostname)'
        
    url2 = row['self']
    r2 = requests.get(url2,auth=('admin','password'))
    

...

device =

...

 

...

r2.json()
    if 

...

Final completed application

info
Code Block
languagepy
titleCompleted Script
collapsetrue
#!/usr/bin/python3
# RestAPI example in Python
#
import requests
# Set this to your own host name/login/password)
r = requests.get('http://vm-mike-er3/api/v1/devices',auth=('admin','password'))

# set some counters
noapps=0
nodb = 0
gotone=0

max = r.headers['X-fetch-count']
data = r.json()


count = len(data)
i = 0
while (i < count):
    row = data[i]
    gotone=0('total_memory_mb' in device):
        ram = device['total_memory_mb']
    else:
        ram = '(unknown ram)'
    if ('cpu' in device):   
        cpu = device['cpu'][0]['cpu_model']
        # remove commas from the cpu string so as to keep the CSV output valid
        cpu = cpu.replace(',','')
    else:
        cpu = '(unknown cpu)' 
        
    status = ifhostname (+ 'host_name: ' in row ):
     + str(ram) + 'MB RAM, ' + str(cpu)
  hostname = row['host_name']
    else:
     # Having got Hostname, Ram and CPU, lets look for databases?
   hostname =if '(no hostname)'('applications' in device):        
        url2url3 = rowdevice['selfapplications']
      r2  r3 = requests.get(url2url3,auth=('admin','password'))))
        # the URL might not be valid. If no applications, server will return a 500 error
        try:
    device = r2.json()     if ('total_memory_mb' in device): apps = r3.json()         ram = device['total_memory_mb'] 
   else:     except:
   ram = '(unknown ram)'     if ('cpu' in device):noapps += 1
        else:
  cpu = device['cpu'][0]['cpu_model']        numapps # remove commas from the cpu string so as to keep the CSV output valid= len(apps)
            j=0
        cpu = cpu.replace(',','')  while (j < elsenumapps):

       cpu = '(unknown cpu)'      if ('product' in apps[j]):
     status = hostname + ': ' + str(ram) + 'MB RAM, ' + str(cpu)     # Having got Hostname, Ram and CPU, lets look for databases?if (('SQL' in apps[j]['product']['name']) or
         if ('applications' in device):                ('Oracle url3Database' = devicein apps[j]['product']['applicationsname']) or
       r3  = requests.get(url3,auth=('admin','password'))         # the URL might not be valid. If no applications, server will return a 500 error ('Informix' in apps[j]['product']['name']) ):
           try:             apps = r3.json()  status = status + '\n  ' + str(apps[j]['product']['name']) 
         except:             noapps += 1    if ('edition'    elsein apps[j]): status = status + '        numapps = len(apps'+ str(apps[j]['edition'])
            j=0             while (j < numapps)else:                 if ('product' in apps[j]):status = status + ' (no edition info)'
                         if ('name' in apps[j]['product']): gotone+=1
                        if ('SQLDB2 Database' in apps[j]['product']['namedescription']):
                            status = status + '\n  ' + str(apps[j]['product']['name']) + ' '+ str(apps[j]['edition']) 
                           gotone+=1 if ('edition' in apps[j]): status = status + ' '+ str(apps[j]['edition'])
             if ('Oracle' in apps[j]['product']['name']):            else: status = status    + ' (no edition info)'
     status = status + '\n  ' + str(apps[j]['product']['name']) + ' '+ str(apps[j]['edition'])           gotone+=1

                gotonej+=1        
    if (gotone       > 0):
   if ('Informix' in apps[j]['product']['name']):  print (status)
    i+=1
if (int(max) > count):
    print( "There is another page of results in the REST-API if you statuswant =to statusget + '\n  ' + str(apps[j]['product']['name']) + ' '+ str(apps[j]['edition'])
                            gotone+=1

                j+=1        
    if (gotone > 0):
        print (status)
    i+=1
if (max > count):
    print( "There is another page of results in the REST-API if you want to get it" )
else:
    print("That's all folks")
it" )
else:
    print("That's all folks")

Sample Output

Below is a small excerpt of the output of this script from our test environment, showing four different hosts; two hosting SQL server instances, one hosting an Informix database and one hosting an Oracle database:

Code Block
languagebash
titleSample Output
mike@ubuntu:~/python$ python3 v1.python
VM-SQL16-2K12: 2047MB RAM, Intel(R) Xeon(R) CPU E5-2667 v3 @ 3.20GHz
  SQL Server Express Edition (64-bit)
  SQL Server Enterprise Edition (64-bit)
vm-pegasus-f10: 2048MB RAM, Intel(R) Xeon(R) CPU E5-2667 v3 @ 3.20GHz
  Informix Developer Edition
ORA-DB-WL-2K3: 766MB RAM, Intel(R) Pentium(R) 4 CPU 2.80GHz
  Oracle Database Server Standard
VM-SQL2K-2K: 1023MB RAM, Intel(R) Xeon(R) CPU E5-2667 v3 @ 3.20GHz
  SQL Server Enterprise Edition
  SQL Server Standard Edition
  SQL Server Standard Edition



Filter by label (Content by label)
showLabelsfalse
max5
spacescom.atlassian.confluence.content.render.xhtml.model.resource.identifiers.SpaceResourceIdentifier@226f31
showSpacefalse
sortmodified
reversetrue
typepage
cqllabel in ("python","restapi") and type = "page" and space = "ISDK"
labelsRestAPI python

...