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.

Virtualization

banshee/virtualization-collection/virtualization/vsphere/https/vcenter-7.0u2/

datastores

Whether each datastore of a VMware vCenter is accessible, and its space, by the vCenter REST API.

  • virtualization
  • vmware
  • vsphere
  • vcenter
  • datastore
  • https
  • api

by banshee1 installation2 versions

v2Latest

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

Keen 1.0.0 · 90 lines
// The datastores of a VMware vCenter, by its REST API (GET /api/vcenter/datastore, then GET
// /api/vcenter/datastore/<id> for each), which vCenter serves under /api from vSphere 7.0 U2: whether each is
// accessible, and its space.
// The address of the API is the vCenter's, 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('datastore', 'Datastores');
output('state', 'text', array('label' => 'State', 'per' => 'datastore'));
output('used-percent', 'number', array('label' => 'Used space', 'unit' => '%', 'per' => 'datastore'));
output('free', 'number', array('label' => 'Free space', 'unit' => 'GiB', 'per' => 'datastore'));
output('size', 'number', array('label' => 'Size', 'unit' => 'GiB', 'per' => 'datastore'));

watch.state('inaccessible', 'Datastore inaccessible', 'state', array('critical' => array('inaccessible')));
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', 'Datastore missing', 'state', array('enabled' => false));

// Log in: POST /api/session, the account in Basic, answers 201 and the id of the session as a JSON text. The
// answer is not secret by itself, the password having gone in Basic, but the id is: secret.mark keeps it out
// of every value and message, and the cache keeps it encrypted on the poller, 50 minutes at most.
function login($address, $user, $password) {
    $answer = http.post('https://' . $address . '/api/session', '', user=$user, password=$password);
    if ($answer['status'] == 401 || $answer['status'] == 403) {
        fail('misconfigured', 'vCenter refuses the account, code ' . $answer['status']);
    }
    if ($answer['status'] != 201) {
        fail('unreachable', 'vCenter answers the login with code ' . $answer['status'],
            'vCenter serves its REST API under /api from vSphere 7.0 U2.');
    }
    $session = secret.mark(json.read($answer['body']));
    cache.set('session', $session, 3000);
    return $session;
}

// One GET with the session kept in the cache; a session vCenter no longer knows (expired, vCenter restarted)
// answers 401, and the collector logs in again, once.
function api_get($address, $path, $user, $password) {
    if (cache.has('session')) {
        $session = cache.get('session');
    } else {
        $session = login($address, $user, $password);
    }
    $answer = http.get('https://' . $address . $path, headers=array('vmware-api-session-id' => $session));
    if ($answer['status'] == 401) {
        $session = login($address, $user, $password);
        $answer = http.get('https://' . $address . $path, headers=array('vmware-api-session-id' => $session));
    }
    if ($answer['status'] == 403) {
        fail('misconfigured', 'The account may not read ' . $path . ', code 403');
    }
    if ($answer['status'] != 200) {
        fail('unreachable', 'vCenter answers ' . $path . ' with code ' . $answer['status']);
    }
    return json.read($answer['body']);
}

// The list: [{"datastore": "datastore-12", "name": "ds-ssd-01", "type": "VMFS", "free_space": 536870912000,
// "capacity": 1099511627776}], in bytes. Each datastore then: {"name": ..., "accessible": true, "free_space":
// ...}, the only place the API says whether it is accessible. Two datastores of one name in two
// datacenters each keep their own, the second carrying its id.
$datastores = api_get($address, '/api/vcenter/datastore', $user, $password);
if (list.count($datastores) == 0) {
    fail('misconfigured', 'vCenter lists no datastore', 'The account sees only the datastores its role is set on.');
}
$seen = array();
foreach ($datastores as $datastore) {
    $name = $datastore['name'];
    if (list.has($seen, $name)) {
        $name = $name . ' #' . $datastore['datastore'];
    }
    $seen[$name] = true;
    $info = api_get($address, '/api/vcenter/datastore/' . url.encode($datastore['datastore']), $user, $password);
    $state = 'inaccessible';
    if (list.get($info, 'accessible', false)) {
        $state = 'accessible';
    }
    value('state', $state, $name);
    // vCenter leaves the space out while it does not know it, an inaccessible datastore among them.
    if (!list.has($datastore, 'capacity') || !list.has($datastore, 'free_space') || $datastore['capacity'] <= 0) {
        continue;
    }
    $size = $datastore['capacity'];
    $free = $datastore['free_space'];
    value('used-percent', number.round(100 * ($size - $free) / $size, 1), $name);
    value('free', number.round($free / 1073741824, 1), $name);
    value('size', number.round($size / 1073741824, 1), $name);
}