End-to-end Data API Examples

Retrieving packet data from live interface.

SteelScript SDK

For more details please check out the online tutorial.

# Use-case:
#  Get the total bandwidth for last one minute broken down to ten seconds buckets.

import pprint

from steelscript.appresponse.core.appresponse import AppResponse
from steelscript.common import UserAuth
from steelscript.appresponse.core.reports import DataDef, Report
from steelscript.appresponse.core.types import Key, Value, TrafficFilter
from steelscript.appresponse.core.reports import SourceProxy

# Open a connection to the appliance and authenticate
ar = AppResponse('host', auth=UserAuth('username', 'password'))

packets_source = ar.get_capture_job_by_name('default_job')
source = SourceProxy(packets_source)

columns = [Key('start_time'), Value('sum_tcp.total_bytes'), Value('avg_frame.total_bytes')]

granularity = '10'
time_range = 'last 1 minute'

data_def = DataDef(source=source, columns=columns, granularity='10', time_range=time_range)
data_def.add_filter(TrafficFilter('tcp.port==80'))

report = Report(ar)
report.add(data_def)
report.run()
pprint.pprint(report.get_data())

PHP

<?php

// Tested on PHP version: 5.3.29

// Use-case:
//  Get the total bandwidth for last ten seconds
//  of Virtual Interface group 'Other VIFG' broken down to one second buckets.

define('HOST', 'host.com');
define('USERNAME', 'username');
define('PASSWORD', 'password');

// Lib functions

// HTTP POST
function _do_POST($url, $string, &$info, $req_headers = array()) {
  $req_headers[] = 'Content-Type: application/json';
  $curl = curl_init();
  curl_setopt($curl, CURLOPT_URL, $url);
  curl_setopt($curl, CURLOPT_SSLVERSION, 1);
  curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
  curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
  curl_setopt($curl, CURLOPT_HEADER, true);
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($curl, CURLOPT_HTTPHEADER, $req_headers);
  curl_setopt($curl, CURLOPT_POST, 1);
  curl_setopt($curl, CURLOPT_POSTFIELDS, $string);
  $output = curl_exec($curl);
  $info   = curl_getinfo($curl);
  curl_close($curl);

  $headers = substr($output, 0, $info['header_size']);
  $headers = explode("\n", $headers);
  $info['headers'] = $headers;
  $body = substr($output, $info['header_size']);
  return $body;
}

// HTTP POST, re-authenticates when access token is expired
function do_POST($url, $string, &$info, &$auth) {
  $req_headers = array("Authorization: Bearer " . $auth['access_token']);
  $info = array();
  $response = _do_POST($url, $string, $info, $req_headers);
  if ($info['http_code'] == 401) {
    echo "exprired access token, re-authenticating\n";
    $auth = authenticate();
    $info = array();
    $req_headers = array("Authorization: Bearer " . $auth['access_token']);
    return _do_POST($url, $string, $info, $req_headers);
  }
  return $response;
}

// HTTP GET
function _do_GET($url, &$info, $req_headers = array()) {
  $req_headers[] = 'Content-Type: application/json';

  $curl = curl_init();
  curl_setopt($curl, CURLOPT_URL, $url);
  curl_setopt($curl, CURLOPT_SSLVERSION, 1);
  curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
  curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
  curl_setopt($curl, CURLOPT_HEADER, true);
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($curl, CURLOPT_HTTPHEADER, $req_headers);
  curl_setopt($curl, CURLOPT_HTTPGET, true);
  $output = curl_exec($curl);
  $info   = curl_getinfo($curl);
  curl_close($curl);

  $headers = substr($output, 0, $info['header_size']);
  $headers = explode("\n", $headers);
  $info['headers'] = $headers;
  $body = substr($output, $info['header_size']);
  return $body;
}

// HTTP GET, re-authenticates when acess token is expired
function do_GET($url, &$info, &$auth) {
  $req_headers = array("Authorization: Bearer " . $auth['access_token']);
  $info = array();
  $response = _do_GET($url, $info, $req_headers);
  if ($info['http_code'] == 401) {
    echo "exprired access token, re-authenticating\n";
    $auth = authenticate();
    $info = array();
    $req_headers = array("Authorization: Bearer " . $auth['access_token']);
    return _do_GET($url, $info, $req_headers);
  }
  return $response;
}

// HTTP DELETE
function _do_DELETE($url, &$info, $req_headers = array()) {
  $req_headers[] = 'Content-Type: application/json';
  $curl = curl_init();
  curl_setopt($curl, CURLOPT_URL, $url);
  curl_setopt($curl, CURLOPT_SSLVERSION, 1);
  curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
  curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
  curl_setopt($curl, CURLOPT_HEADER, true);
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($curl, CURLOPT_HTTPHEADER, $req_headers);
  curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
  $output = curl_exec($curl);
  $info   = curl_getinfo($curl);
  curl_close($curl);

  $headers = substr($output, 0, $info['header_size']);
  $headers = explode("\n", $headers);
  $info['headers'] = $headers;
  $body = substr($output, $info['header_size']);
  return $body;
}

// HTTP DELETE, re-authenticates when acess token is expired
function do_DELETE($url, &$info, &$auth) {
  $req_headers = array("Authorization: Bearer " . $auth['access_token']);
  $info = array();
  $response = _do_DELETE($url, $info, $req_headers);
  if ($info['http_code'] == 401) {
    echo "exprired access token, re-authenticating\n";
    $auth = authenticate();
    $info = array();
    $req_headers = array("Authorization: Bearer " . $auth['access_token']);
    return _do_DELETE($url, $info, $req_headers);
  }
  return $response;
}

// Using a username and password, get an access token
// The function is not using refresh tokens, if you are building
// long lasting application, please consider using generate_refresh_token: true
// and use the refresh token to re-authenticate. For more information please
// refer to the Authentication overview document.
function authenticate() {
  $request = array("user_credentials" =>
                   array("username" => USERNAME,
                         "password" => PASSWORD),
                   "generate_refresh_token" => false);
  $url = 'https://' . HOST . '/api/mgmt.aaa/1.0/token';
  echo "Authenticating... ";
  $info = array();
  $json = json_encode($request);
  $response = _do_POST($url, $json, $info);
  if ($info['http_code'] != 201) {
    echo "Unable to authenticate!\n";
    echo $response . "\n";
    exit(1);
  }
  echo "successful.\n";
  return json_decode($response, true);
}

// Finds and returns a HTTP header
function get_header($headers, $header) {
  foreach($headers as $h) {
    if (strpos($h, $header . ':') !== false)
      return trim(substr($h, 10));
  }
  echo "Unable to find {$header} header!\n";
  exit;
}

// CSV helper
function echo_csv($rows) {
  foreach ($rows as $row)
    echo implode(',', $row) . "\n";
}

// Prints the error message, deletes the live instance data object
// and exists with error.
function exit_with_error_and_cleanup($instance_url, $errmsg) {
  global $auth;

  echo $errmsg . "\n";
  echo "DELETE {$instance_url} \n";

  $info = array();
  do_DELETE($instance_url, $info, $auth);

  exit(1);
}

//
// End lib functions
//


//
// Authenticate
//
$auth = authenticate();


$url = 'https://' . HOST . '/api/npm.packet_capture/2.0/vifgs';
echo "Sending VIFGs request... ";
$info = array();
$response = do_GET($url, $info, $auth);
if ($info['http_code'] != 200) {
  echo "failed.\n";
  echo $response . "\n";
  exit(1);
} else {
  echo "successful.\n";
}

$vifgs = json_decode($response, 1);
$vifg_id = null;
foreach ($vifgs['items'] as $vifg) {
  if ($vifg['config']['is_other_vifg']) {
    $vifg_id = $vifg['id'];
  }
}
if (is_null($vifg_id)) {
  echo "Undable to find Other vifg, full response:\n " . $response;
  exit(1);
}

//
// Create live request object
//
$data_defs =
  array('live' => true,
        'data_defs' =>
        array(array('source' => array('name' => 'packets',
                                      'path' => 'vifgs/' . $vifg_id),
                    'time' => array('retention_time' => '1 hour',
                                    'granularity' => '1'),
                    'columns' => array('start_time',
                                       'sum_tcp.total_bytes',
                                       'avg_frame.total_bytes'),
                    'group_by' => array('start_time')
                    )
              )
        );
$json = json_encode($data_defs);
$url = 'https://' . HOST . '/api/npm.probe.reports/1.0/instances';
echo "Creating live request... ";
$info = array();
$response = do_POST($url, $json, $info, $auth);
if ($info['http_code'] != 201) {
  echo "failed.\n";
  echo $response . "\n";
  exit(1);
}

$location = get_header($info['headers'], 'Location');
echo "successful, instance URI: {$location}\n";

$instance_url = 'https://' . HOST . '' . $location;

//
// Wait for the data request to get into collecting state
//
$status_url = $instance_url . '/status';
echo "Waiting to get into collecting state\n";
while (true) {
  $info = array();
  $response = do_GET($status_url, $info, $auth);
  if ($info['http_code'] != 200) {
    echo "Get status failed.\n";
    exit_with_error_and_cleanup($instance_url,
                                "Get status failed.\n" . $response);
  }

  $data_defs = json_decode($response, 1);
  $done = true;
  foreach ($data_defs as $d) {
    if ($d['state'] == 'error') {
      exit_with_error_and_cleanup($instance_url,
                                  "Data object in error state.\n" . $response);
    }
    echo " data object ID: {$d['id']} state: {$d['state']}\n";
    if ($d['state'] != 'collecting') {
      $done = false;
    }
  }

  if ($done) {
    break;
  }

  usleep (100);
}

//
// Print live data
//
echo "Getting data\n";

$last_end_time = 0;

$counter = 0;

while (true) {
  // Get info
  $response = do_GET($instance_url . '/data_defs/items/1', $info, $auth);
  if ($info['http_code'] != 200) {
    exit_with_error_and_cleanup($instance_url,
                                "Get info failed.\n" . $response);
  }

  $d = json_decode($response, 1);
  if ($d['status']['state'] != 'collecting') {
    exit_with_error_and_cleanup($instance_url,
                                "Data object no longer in collecting state.\n"
                                . $response);
  }

  if (!isset($d['actual_time']['time_ranges'][0]['end'])) {
    // Can happen initially, keep waiting
    sleep(1);
    continue;
  }

  $end_time = $d['actual_time']['time_ranges'][0]['end'];
  if ($end_time > $last_end_time) {

    if ($last_end_time == 0) {
      // print the data headers only the first time
      echo implode(',', $d['columns']) . "\n";
    }

    // New end time is availabe, get it
    $url = $instance_url . '/data_defs/items/1/data?granularity=1';
    $url .= '&start_time=' . $last_end_time;
    $url .= '&end_time=' . $end_time;

    $response = do_GET($url, $info, $auth);
    if ($info['http_code'] != 200) {
      exit_with_error_and_cleanup($instance_url,
                                  "Get data failed.\n"
                                  . $response);
    }

    $data_resp = json_decode($response, 1);
    $data = array();
    if (isset($data_resp['data'])) {
      // echo "Data for time range {$last_end_time} - {$end_time} \n";
      echo_csv($data_resp['data']);
    } else {
      echo "No data for time range {$last_end_time} - {$end_time} \n";
    }

    // set the last time to the new end time
    $last_end_time = $end_time;
    $counter++;
    sleep(1);
  }

  if ($counter > 10) {
    // That's enough, exiting
    // echo "DELETE {$instance_url}\n";
    do_DELETE($instance_url, $info, $auth);
    exit(0);
  }
}

Output:

Authenticating... successful.
Sending VIFGs request... successful.
Creating live request... successful, instance URI: /api/npm.probe.reports/1.0/instances/items/45
Waiting to get into collecting state
 data object ID: 1 state: collecting
Getting data
start_time,sum_tcp.total_bytes,avg_frame.total_bytes
1523025579,325243,267.025
1523025580,367649,208.427
1523025581,399139,177.478
1523025582,374621,205.57
1523025583,431028,196.044
1523025584,414299,193.134
1523025585,363306,209.815
1523025586,453000,261.833
1523025587,471342,224.392
1523025588,355008,185.305

Retrieving historical/performance data.

SteelScript SDK

# Use-case: Get top host groups for the last 10 minutes by total bytes.

import pprint
from steelscript.appresponse.core.appresponse import AppResponse
from steelscript.common import UserAuth
from steelscript.appresponse.core.reports import DataDef, Report
from steelscript.appresponse.core.types import Key, Value, TrafficFilter
from steelscript.appresponse.core.reports import SourceProxy

# Open a connection to the appliance and authenticate
ar = AppResponse('host.com', auth=UserAuth('username', 'password'))

source = SourceProxy(name='aggregates')
columns = [Key('host_group.id'), Value('host_group.name'), Value('sum_traffic.total_bytes')]
data_def = DataDef(source=source,
                   columns=columns,
                   time_range='last 10 minutes')

report = Report(ar)
report.add(data_def)

report.run()

pprint.pprint(report.get_data())

Curl (shell script)

Use-case: Get top host groups for the last 10 minutes by total bytes.

To prepare, please create these two files. The auth_request.json is used to obtain an access_token. The data_request.json is used to send a data request. For this example we are using the convenient ‘sync’ end-point, please refer to the Overview document for more details.

Create the request json files:

% cat <<EOF > auth_request.json
{
  "user_credentials": {
      "username": "username",
      "password": "password"
  },
  "generate_refresh_token": false
}
EOF

% cat <<EOF > data_request.json
{
  "data_defs" : [
    {
      "source" : {
        "name" : "aggregates"
      },
      "group_by" : [ "host_group.id" ],
      "time" : {
        "duration" : "last 10 minutes"
      },
      "top_by": [
        {"id": "sum_traffic.total_bytes", "direction": "desc"}
      ],
      "columns" : [
        "host_group.id",
        "host_group.name",
        "sum_traffic.total_bytes"
      ]
    }
  ]
}
EOF

Authenticate:

% curl -H "Content-Type: application/json" \
-k -d@auth_request.json https://<host>/api/mgmt.aaa/1.0/token

The response will be JSON object with access token:

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ ... 4rU",
  "token_type": "bearer",
  "expires_at": 1523894563
}

Take the access token and make a data request (replace with the actual token in the Authorization request header):

% curl -d@data_request.json \
-k \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access_token>" \
https://<host>/api/npm.reports/1.0/instances/sync

The response is JSON object that includes the data:

...
 "data":[
   ["1","Default-10.x.x.x","430723319"],
   ["2","Default-Internet","325627617"],
   ["4","Default-192.168.x.x","283020518"],
   ["0","Other Group","177495063"],
   ["3","Default-172.x.x.x","12752"]
 ],
...

PHP

<?php

// Tested on PHP version: 5.3.29

// Use-case: Get top host groups for the last 10 minutes by total bytes.

define('HOST', 'host.com');
define('USERNAME', 'username');
define('PASSWORD', 'password');

//
// Lib functions
//
// HTTP POST
function _do_POST($url, $string, &$info, $req_headers = array()) {
  $req_headers[] = 'Content-Type: application/json';
  $curl = curl_init();
  curl_setopt($curl, CURLOPT_URL, $url);
  curl_setopt($curl, CURLOPT_SSLVERSION, 1);
  curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
  curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
  curl_setopt($curl, CURLOPT_HEADER, true);
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($curl, CURLOPT_HTTPHEADER, $req_headers);
  curl_setopt($curl, CURLOPT_POST, 1);
  curl_setopt($curl, CURLOPT_POSTFIELDS, $string);
  $output = curl_exec($curl);
  $info   = curl_getinfo($curl);
  curl_close($curl);

  $headers = substr($output, 0, $info['header_size']);
  $headers = explode("\n", $headers);
  $info['headers'] = $headers;
  $body = substr($output, $info['header_size']);
  return $body;
}

// HTTP POST, re-authenticates when access token is expired
function do_POST($url, $string, &$info, &$auth) {
  $req_headers = array("Authorization: Bearer " . $auth['access_token']);
  $info = array();
  $response = _do_POST($url, $string, $info, $req_headers);
  if ($info['http_code'] == 401) {
    echo "exprired access token, re-authenticating\n";
    $auth = authenticate();
    $info = array();
    $req_headers = array("Authorization: Bearer " . $auth['access_token']);
    return _do_POST($url, $string, $info, $req_headers);
  }
  return $response;
}

// HTTP GET
function _do_GET($url, &$info, $req_headers = array()) {
  $req_headers[] = 'Content-Type: application/json';

  $curl = curl_init();
  curl_setopt($curl, CURLOPT_URL, $url);
  curl_setopt($curl, CURLOPT_SSLVERSION, 1);
  curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
  curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
  curl_setopt($curl, CURLOPT_HEADER, true);
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($curl, CURLOPT_HTTPHEADER, $req_headers);
  curl_setopt($curl, CURLOPT_HTTPGET, true);
  $output = curl_exec($curl);
  $info   = curl_getinfo($curl);
  curl_close($curl);

  $headers = substr($output, 0, $info['header_size']);
  $headers = explode("\n", $headers);
  $info['headers'] = $headers;
  $body = substr($output, $info['header_size']);
  return $body;
}

// HTTP GET, re-authenticates when acess token is expired
function do_GET($url, &$info, &$auth) {
  $req_headers = array("Authorization: Bearer " . $auth['access_token']);
  $info = array();
  $response = _do_GET($url, $info, $req_headers);
  if ($info['http_code'] == 401) {
    echo "exprired access token, re-authenticating\n";
    $auth = authenticate();
    $info = array();
    $req_headers = array("Authorization: Bearer " . $auth['access_token']);
    return _do_GET($url, $info, $req_headers);
  }
  return $response;
}

// Using a username and password, get an access token
// The function is not using refresh tokens, if you are building
// long lasting application, please consider using generate_refresh_token: true
// and use the refresh token to re-authenticate. For more information please
// refer to the Authentication overview document.
function authenticate() {
  $request = array("user_credentials" =>
                   array("username" => USERNAME,
                         "password" => PASSWORD),
                   "generate_refresh_token" => false);
  $url = 'https://' . HOST . '/api/mgmt.aaa/1.0/token';
  echo "Authenticating... ";
  $info = array();
  $json = json_encode($request);
  $response = _do_POST($url, $json, $info);
  if ($info['http_code'] != 201) {
    echo "Unable to authenticate!\n";
    echo $response . "\n";
    exit(1);
  }
  echo "successful.\n";
  return json_decode($response, true);
}

// Finds and returns a HTTP header
function get_header($headers, $header) {
  foreach($headers as $h) {
    if (strpos($h, $header . ':') !== false)
      return trim(substr($h, 10));
  }
  echo "Unable to find {$header} header!\n";
  exit;
}

// CSV helper
function echo_csv($headers, $rows) {
  echo implode(',', $headers) . "\n";
  foreach ($rows as $row)
    echo implode(',', $row) . "\n";
}

//
// End lib functions
//


//
// Authenticate
//
$auth = authenticate();

//
// Send data request
//
$data_defs =
  array('data_defs' =>
        array(array('source'  => array('name' => 'aggregates'),
                    'time'    => array('duration' => 'last 10 minutes'),
                    'columns' => array('host_group.id',
                                       'host_group.name',
                                       'sum_traffic.total_bytes'),
                    'group_by' => array('host_group.id')
                    )
              )
        );
$json = json_encode($data_defs);
$url = 'https://' . HOST . '/api/npm.reports/1.0/instances';
echo "Sending data request... ";
$info = array();
$response = do_POST($url, $json, $info, $auth);
if ($info['http_code'] != 201) {
  echo "failed.\n";
  echo $response . "\n";
  exit(1);
}

$location = get_header($info['headers'], 'Location');
echo "successful, instance URI: {$location}\n";

//
// Wait for the data request to complete
//
$status_url = 'https://' . HOST . '' . $location . '/status';
echo "Waiting to complete\n";
while (true) {
  $info = array();
  $response = do_GET($status_url, $info, $auth);
  if ($info['http_code'] != 200) {
    echo "Get status failed.\n";
    echo $response . "\n";
    exit(1);
  }

  $data_defs = json_decode($response, 1);
  $done = true;
  foreach ($data_defs as $d) {
    if ($d['state'] == 'error') {
      echo "Error: \n";
      echo $d['messages'];
      exit(1);
    }
    echo " data object ID: {$d['id']} state: {$d['state']}\n";
    if ($d['state'] != 'completed') {
      $done = false;
    }
  }

  if ($done) {
    break;
  }

  usleep (100);
}

//
// Get and print the data
//
echo "Getting data...";
$data_url = 'https://' . HOST . '' . $location . '/data';
$output = do_GET($data_url, $info, $auth);

$data = json_decode($output, 1);
if ($info['http_code'] != 200) {
  echo "failed.\n";
  echo $output . "\n";
  exit(1);
} else {
  echo "successful.\n";
}

// Print the data
foreach ($data['data_defs'] as $d) {
  echo "Data object ID: " . $d['id'] . "\n";
  $data = array();
  if (isset($d['data'])) {
    $data = $d['data'];
  }
  echo_csv($d['columns'], $data);
}

?>

Output:

Authenticating... successful.
Sending data request... successful, instance URI: /api/npm.reports/1.0/instances/items/334
Waiting to complete
 data object ID: 1 state: executing
 data object ID: 1 state: executing
 data object ID: 1 state: completed
Getting data...successful.
Data object ID: 1
host_group.id,host_group.name,sum_traffic.total_bytes
0,Other Group,16174105659
1,Default-10.x.x.x,31395223107
2,Default-Internet,21423988720
3,Default-172.x.x.x,1049557
4,Default-192.168.x.x,25632954659

Perl

#!/usr/bin/perl

# Tested on Perl version: 5.10.1

# Use-case: Get top host groups for the last 10 minutes by total bytes.

use strict;
use warnings;

use LWP::UserAgent;
use HTTP::Request;
use List::MoreUtils qw(firstidx);
use JSON qw( encode_json decode_json );

use constant HOST     => 'host.com';
use constant USERNAME => 'username';
use constant PASSWORD => 'password';

#
# Lib functions
#

our $ua = LWP::UserAgent->new;
$ua->agent("ExampleScript");

our $API_BASE = "https://" . HOST;

sub _request($)
{
    my $req = shift;

    $req->header('Accept' => 'application/json');

    my $res = $ua->request($req);

    return {
        code    => $res->code,
        status  => $res->status_line,
        headers => $res->headers(),
        data    => decode_json($res->content)
    };
}

# HTTP GET, re-authenticates when acess token is expired
sub GET($$)
{
    my $req = HTTP::Request->new(GET => $API_BASE . shift);
    my $auth = shift;
    $req->authorization('Bearer ' . $auth->{access_token});
    my $response = _request($req);
    if ($response->{code} == 401) {
    $auth = authenticate();
    $req->authorization('Bearer ' . $auth->{access_token});
    return _request($req);
    }
    return $response;
}

# HTTP POST, re-authenticates when acess token is expired
sub POST($$$)
{
    my $req = HTTP::Request->new(POST => $API_BASE . shift);
    my $auth = shift;
    $req->authorization('Bearer ' . $auth->{access_token});
    $req->content_type('application/json');
    $req->content(encode_json(shift));
    my $response = _request($req);
    if ($response->{code} == 401) {
    $auth = authenticate();
    $req->authorization('Bearer ' . $auth->{access_token});
    return _request($req);
    }
    return $response;
}

# Using a username and password, get an access token
# The function is not using refresh tokens, if you are building
# long lasting application, please consider using generate_refresh_token: true
# and use the refresh token to re-authenticate. For more information please
# refer to the Authentication overview document.
sub authenticate()
{
    print "Authenticating... ";

    my $struct = {
        user_credentials => {
            username => USERNAME,
            password => PASSWORD
        },
        generate_refresh_token => JSON::false
    };

    my $req = HTTP::Request->new(POST => $API_BASE . '/api/mgmt.aaa/1.0/token');
    $req->content_type('application/json');
    $req->content(encode_json($struct));

    my $response = _request($req);
    if ($response->{code} != 201)
    {
    print "Unable to authenticate!\n";
        print encode_json($response->{data});
        exit();
    }
    print "successful.\n";
    return $response->{data}
}

#
# Authenticate
#

my $auth = authenticate();

#
# Send data request
#
my $data_defs = {
  data_defs => [
    {source  => {name => 'aggregates'},
     time    => {duration => 'last 10 minutes'},
     columns => ['host_group.id',
                 'host_group.name',
                 'sum_traffic.total_bytes'],
     group_by => ['host_group.id']
    }
  ]
};

my $url = '/api/npm.reports/1.0/instances';
print "Sending data request... ";
my $response = POST($url, $auth, $data_defs);
if ($response->{code} != 201) {
    print "failed.\n";
    print encode_json($response->{data}) . "\n";
    exit(1);
}

my $location = $response->{headers}->header('Location');
print "successful, instance URI: $location\n";

#
# Wait for the data request to complete
#
my $status_url = $location . '/status';
print "Waiting to complete\n";
while (1) {
    my $response = GET($status_url, $auth);
    if ($response->{code} != 200) {
        print "Get status failed.\n";
        print encode_json($response->{data}) . "\n";
        exit(1);
    }

    my $done = 1;
    foreach my $d (@{$response->{data}}) {
        if ($d->{state} eq 'error') {
            print "Error: \n";
            print encode_json($d->{messages});
            exit(1);
        }
        print " data object ID: $d->{id} state: $d->{state}\n";
        if ($d->{state} ne 'completed') {
            $done = 0;
        }
    }
    last if  $done eq 1;
    sleep(1);
}

#
# Get and print the data
#
print "Getting data...";
my $data_url = $location . '/data';
$response = GET($data_url, $auth);

if ($response->{code} != 200) {
    print "failed.\n";
    print encode_json($response->{data}) . "\n";
    exit(1);
} else {
    print "successful.\n";
}

# Print the data
foreach my $d (@{$response->{data}->{data_defs}}) {
    print "Data object ID: " . $d->{id} . "\n";

    my @columns = @{$d->{columns}};

    print join ",", @columns;
    print "\n";

    foreach my $row (@{$d->{data}}) {
        print join ",", @$row;
        print "\n";
    }
}

Output:

Authenticating... successful.
Sending data request... successful, instance URI: /api/npm.reports/1.0/instances/items/702
Waiting to complete
 data object ID: 1 state: completed
Getting data...successful.
Data object ID: 1
host_group.id,host_group.name,sum_traffic.total_bytes
0,Other Group,139925908
1,Default-10.x.x.x,483894223
2,Default-Internet,406507955
3,Default-172.x.x.x,12456
4,Default-192.168.x.x,210087340