Hardware
banshee/hardware-collection/hardware/ibm/https/hmc/
processor-allocation
The share of the processor units assigned, and the units free, of each IBM Power server an HMC manages, by the HMC REST API.
by banshee0 installations1 version
Published on October 27, 2026. First version.
// The processor capacity of the IBM Power servers a Hardware Management Console (HMC) manages, by its REST
// API: for each managed system, the share of its configurable processor units already assigned to its
// partitions, and the units still free. It is an allocation, not a load: the use of the processors is not
// read. The address is the HMC's, the host's: https://<host:address>/rest/api/.
need('protocol:http');
$address = need('host:address');
$user = need('protocol:http:user');
$password = need('protocol:http:password');
per('system', 'Managed systems');
output('assigned', 'number', array('label' => 'Processor units assigned', 'unit' => '%', 'per' => 'system'));
output('available', 'number', array('label' => 'Processor units free', 'per' => 'system'));
watch.above('assigned-high', 'Processor units nearly all assigned', 'assigned', array(
'help' => 'Raises when little processor capacity is left to start or grow a partition.',
'warning' => 90,
'enabled' => false,
));
watch.missing('missing', 'System missing', 'assigned', array('enabled' => false));
// Opens a session: PUT /rest/api/web/Logon, the account in the XML body IBM documents, each value passed by
// xml.escape. The HMC answers a LogonResponse whose X-API-Session is the session; the answer is secret, its
// body having carried the password. The session is kept in the cache, encrypted on the poller, so that one
// session serves every run: IBM warns that sessions opened and never closed wear the HMC's memory.
function logon($address, $user, $password) {
$body = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
. '<LogonRequest xmlns="http://www.ibm.com/xmlns/systems/power/firmware/web/mc/2012_10/" schemaVersion="V1_1_0">'
. '<Metadata><Atom/></Metadata>'
. '<UserID kb="CUR" kxe="false">' . xml.escape($user) . '</UserID>'
. '<Password kb="CUR" kxe="false">' . xml.escape($password) . '</Password>'
. '</LogonRequest>';
$answer = http.put('https://' . $address . '/rest/api/web/Logon', $body,
headers=array('Content-Type' => 'application/vnd.ibm.powervm.web+xml; type=LogonRequest'));
if ($answer['status'] == 401 || $answer['status'] == 403) {
fail('misconfigured', 'The HMC refuses the account, code ' . $answer['status']);
}
if ($answer['status'] != 200) {
fail('unreachable', 'The HMC answers the logon with code ' . $answer['status']);
}
$logon = xml.read($answer['body']);
$session = $logon['LogonResponse'][0]['X-API-Session'][0]['#text'];
cache.set('session', $session, 604800);
return $session;
}
// Returns the entries of an Atom feed of the HMC, read by its path (/rest/api/uom/...), with the session kept
// in the cache. A session the HMC no longer knows (expired, HMC restarted) is refused, 401 or 403: it is
// closed by DELETE /rest/api/web/Logon, whatever its answer, and replaced by a new one, once. The HMC answers
// 204, without a body, for a feed with no entry. Each success keeps the session in the cache seven more days.
function hmc_entries($address, $path, $user, $password) {
if (cache.has('session')) {
$session = cache.get('session');
} else {
$session = logon($address, $user, $password);
}
$answer = http.get('https://' . $address . $path, headers=array('X-API-Session' => $session));
if ($answer['status'] == 401 || $answer['status'] == 403) {
http.delete('https://' . $address . '/rest/api/web/Logon', headers=array('X-API-Session' => $session), errors=$err);
$session = logon($address, $user, $password);
$answer = http.get('https://' . $address . $path, headers=array('X-API-Session' => $session));
}
if ($answer['status'] == 401 || $answer['status'] == 403) {
fail('misconfigured', 'The account may not read ' . $path . ', code ' . $answer['status']);
}
if ($answer['status'] == 204) {
cache.set('session', $session, 604800);
return array();
}
if ($answer['status'] != 200) {
fail('unreachable', 'The HMC answers ' . $path . ' with code ' . $answer['status']);
}
cache.set('session', $session, 604800);
$feed = xml.read($answer['body']);
return list.get($feed['feed'][0], 'entry', array());
}
// Returns the first child of that name, an empty array when the HMC does not give it.
function child($element, $name) {
$children = list.get($element, $name, array());
if (list.count($children) == 0) {
return array();
}
return $children[0];
}
// Returns the text of the first child of that name, '' when the HMC does not give it. The HMC writes each
// value with its attributes: <InstalledSystemProcessorUnits kxe="false" kb="ROR">8</...>.
function child_text($element, $name) {
return list.get(child($element, $name), '#text', '');
}
// <ManagedSystem:ManagedSystem ...> <SystemName>p10-a</SystemName> <AssociatedSystemProcessorConfiguration>
// <ConfigurableSystemProcessorUnits>8</...> <CurrentAvailableSystemProcessorUnits>7.6</...>: processor units,
// a processor core being 1. A system that gives no configurable unit (powered off) returns nothing.
// Two systems of one name each keep their own, the second carrying its UUID.
$systems = hmc_entries($address, '/rest/api/uom/ManagedSystem', $user, $password);
if (list.count($systems) == 0) {
fail('misconfigured', 'The HMC lists no managed system', 'The account sees only the systems its resource role is set on.');
}
$seen = array();
foreach ($systems as $entry) {
$system = $entry['content'][0]['ManagedSystem:ManagedSystem'][0];
$name = child_text($system, 'SystemName');
if ($name == '' || list.has($seen, $name)) {
$name = $name . ' #' . $entry['id'][0];
}
$seen[$name] = true;
$processors = child($system, 'AssociatedSystemProcessorConfiguration');
$configurable = child_text($processors, 'ConfigurableSystemProcessorUnits');
$available = child_text($processors, 'CurrentAvailableSystemProcessorUnits');
if ($configurable == '' || $available == '') {
continue;
}
if ($configurable + 0 == 0) {
continue;
}
value('assigned', number.round(($configurable - $available) * 100 / $configurable, 1), $name);
value('available', $available, $name);
}