Hardware
banshee/hardware-collection/hardware/ibm/https/hmc/
memory-allocation
The share of the memory taken, and the memory free, of each IBM Power server an HMC manages, by the HMC REST API.
by banshee0 installations2 versions
v2Latest
Published on October 28, 2026. One naming convention across collections; documentation completed.
// The memory of the IBM Power servers a Hardware Management Console (HMC) manages, by its REST API: for each
// managed system, the share of its configurable memory already taken, and the memory still free to assign
// to a partition. It is an allocation, not a load: the use of the memory inside the
// partitions 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' => 'Memory assigned', 'unit' => '%', 'per' => 'system'));
output('available', 'number', array('label' => 'Memory free', 'unit' => 'MiB', 'per' => 'system'));
watch.above('assigned-high', 'Memory nearly all assigned', 'assigned', array(
'help' => 'Raises when little memory 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: <InstalledSystemMemory kb="ROR" kxe="false">98304</InstalledSystemMemory>.
function child_text($element, $name) {
return list.get(child($element, $name), '#text', '');
}
// <ManagedSystem:ManagedSystem ...> <SystemName>p10-a</SystemName> <AssociatedSystemMemoryConfiguration>
// <ConfigurableSystemMemory>98304</...> <CurrentAvailableSystemMemory>88832</...>, in the HMC's MB, whole
// numbers of memory regions of 256, powers of two: returned as MiB, the binary unit they point to. The
// configurable memory that is not available is taken. A system that gives no configurable memory (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;
$memory = child($system, 'AssociatedSystemMemoryConfiguration');
$configurable = child_text($memory, 'ConfigurableSystemMemory');
$available = child_text($memory, 'CurrentAvailableSystemMemory');
if ($configurable == '' || $available == '') {
continue;
}
if ($configurable + 0 == 0) {
continue;
}
value('assigned', number.round(($configurable - $available) * 100 / $configurable, 1), $name);
value('available', $available, $name);
}