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
// 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' => 'MB', '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 MB: 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);
}