banshee is under active development: collectors will keep changing, and a version you publish will likely need adjustments. For stable use, wait for version 1.0.0.

Storage

banshee/storage-collection/storage/netapp/https/ontap-9.6/

volumes

The state and the space of each volume of a NetApp ONTAP cluster by its REST API.

  • storage
  • netapp
  • ontap
  • volume
  • svm
  • https
  • api

by banshee1 installation2 versions

v2Latest

Published on October 28, 2026. One naming convention across collections; documentation completed.

Keen 1.0.0 · 60 lines
// The volumes of a NetApp ONTAP cluster, by its REST API (GET /api/storage/volumes), which ONTAP serves from
// 9.6: the state and the space of each, named after its SVM ("svm1/vol_data").
// The address of the API is the cluster's management address, the host's: https://<host:address>/api/.
need('protocol:http');
$address = need('host:address');
$user = need('protocol:http:user');
$password = need('protocol:http:password');

per('volume', 'Volumes');
output('state', 'text', array('label' => 'State', 'per' => 'volume'));
output('used-percent', 'number', array('label' => 'Used space', 'unit' => '%', 'per' => 'volume'));
output('free', 'number', array('label' => 'Free space', 'unit' => 'GiB', 'per' => 'volume'));
output('size', 'number', array('label' => 'Size', 'unit' => 'GiB', 'per' => 'volume'));

watch.state('failed', 'Volume offline or in error', 'state', array('critical' => array('offline', 'error', 'restricted')));
watch.expect('not-online', 'Volume not online', 'state', array('warning' => array('online')));
watch.above('used', 'Used space', 'used-percent', array('warning' => 80, 'critical' => 90));
watch.above('full-soon', 'Full within a week', 'used-percent', array('warning' => 99, 'ahead' => '7 d'));
watch.missing('missing', 'Volume missing', 'state', array('enabled' => false));

// One page of records at a time: ONTAP gives the next page's path under _links.next.href when it cuts the
// list, until the last. The password goes in Basic: the answer is not secret.
$path = '/api/storage/volumes?fields=name,svm.name,state,space.size,space.used,space.available&max_records=1000';
$volumes = array();
while ($path != '') {
    $answer = http.get('https://' . $address . $path, user=$user, password=$password);
    if ($answer['status'] == 401 || $answer['status'] == 403) {
        fail('misconfigured', 'ONTAP refuses the account, code ' . $answer['status']);
    }
    if ($answer['status'] != 200) {
        fail('unreachable', 'The ONTAP API answers code ' . $answer['status'],
            'ONTAP serves its REST API from 9.6.');
    }
    $page = json.read($answer['body']);
    foreach ($page['records'] as $record) {
        $volumes = list.add($volumes, $record);
    }
    $path = '';
    $links = list.get($page, '_links', array());
    if (list.has($links, 'next')) {
        $path = $links['next']['href'];
    }
}

// {"name": "vol_data", "svm": {"name": "svm1"}, "state": "online", "space": {"size": 1099511627776, "used":
// 549755813888, "available": 549755813888}}, in bytes. A volume that is not online may have no space.
foreach ($volumes as $volume) {
    $name = $volume['svm']['name'] . '/' . $volume['name'];
    value('state', $volume['state'], $name);
    $space = list.get($volume, 'space', array());
    if (!list.has($space, 'size') || !list.has($space, 'used') || !list.has($space, 'available')) {
        continue;
    }
    // Used over used plus available, as df shows it: the snapshot reserve is left out of the size.
    if ($space['used'] + $space['available'] > 0) {
        value('used-percent', number.round(100 * $space['used'] / ($space['used'] + $space['available']), 1), $name);
    }
    value('free', number.round($space['available'] / 1073741824, 1), $name);
    value('size', number.round($space['size'] / 1073741824, 1), $name);
}