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/

hosts

The connection state and the power state of each ESXi host of a VMware vCenter by its REST API.

  • virtualization
  • vmware
  • vsphere
  • vcenter
  • esxi
  • host
  • https
  • api

by banshee1 installation1 version

v1Latest

Published on October 27, 2026. First version.

Keen 1.0.0 · 75 lines
// The ESXi hosts of a VMware vCenter, by its REST API (GET /api/vcenter/host), which vCenter serves under /api
// from vSphere 7.0 U2: the connection state and the power state of each host it manages.
// 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('host', 'Hosts');
output('connection', 'text', array('label' => 'Connection', 'per' => 'host'));
output('power', 'text', array('label' => 'Power', 'per' => 'host'));

watch.state('not-responding', 'Host not responding', 'connection', array('critical' => array('not-responding')));
watch.state('disconnected', 'Host disconnected', 'connection', array('warning' => array('disconnected')));
watch.state('powered-off', 'Host powered off or in standby', 'power', array('warning' => array('standby'), 'critical' => array('powered-off')));
watch.missing('missing', 'Host missing', 'connection', 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']);
}

// [{"host": "host-10", "name": "esx01.example", "connection_state": "CONNECTED", "power_state": "POWERED_ON"}].
// power_state is only given for a connected host. Both are returned in lower case, "_" written "-".
// Two hosts of one name in two datacenters each keep their own, the second carrying its id.
$hosts = api_get($address, '/api/vcenter/host', $user, $password);
if (list.count($hosts) == 0) {
    fail('misconfigured', 'vCenter lists no host', 'The account sees only the hosts its role is set on.');
}
$seen = array();
foreach ($hosts as $host) {
    $name = $host['name'];
    if (list.has($seen, $name)) {
        $name = $name . ' #' . $host['host'];
    }
    $seen[$name] = true;
    value('connection', text.join(text.split(text.lower($host['connection_state']), '_'), '-'), $name);
    if (list.has($host, 'power_state')) {
        value('power', text.join(text.split(text.lower($host['power_state']), '_'), '-'), $name);
    }
}