From 98044859aeaaf7cad965ae03c106df8af38ed730 Mon Sep 17 00:00:00 2001 From: Mark Nellemann Date: Thu, 28 Jan 2021 19:53:45 +0100 Subject: [PATCH] Option to enable power and thermal readings through the HCM REST API. --- README.md | 4 +- doc/hmci.service | 2 + .../java/biz/nellemann/hmci/HmcInstance.java | 18 ++-- .../biz/nellemann/hmci/HmcRestClient.java | 85 +++++++++++++++++++ src/test/resources/system-preferences.xml | 42 +++++++++ 5 files changed, 140 insertions(+), 11 deletions(-) create mode 100644 src/test/resources/system-preferences.xml diff --git a/README.md b/README.md index 7f40f03..153964e 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Metrics includes: - *Managed Systems* - the physical Power servers - *Logical Partitions* - the virtualized servers running AIX, Linux and IBM-i (AS/400) - *Virtual I/O Servers* - the i/o partition(s) taking care of network and storage -- *Energy* - power consumption and temperatures +- *Energy* - power consumption and temperatures (needs to be enabled and not available for E880, E980) ![architecture](https://bitbucket.org/mnellemann/hmci/downloads/HMCi.png) @@ -57,7 +57,7 @@ Below are screenshots of the provided Grafana dashboards (found in the **doc/** ### Naming collision -You can't have partitions on different HMC's with the same name, as these cannot be distinguished when metrics are +You can't have partitions (or Virtual I/O Servers) on different Systems with the same name, as these cannot be distinguished when metrics are written to InfluxDB (which uses the name as key). ### Renaming partitions diff --git a/doc/hmci.service b/doc/hmci.service index bf34023..d7b7038 100644 --- a/doc/hmci.service +++ b/doc/hmci.service @@ -2,6 +2,8 @@ Description=HMC Insights Service [Service] +#User=nobody +#Group=nogroup TimeoutStartSec=0 Restart=always ExecStart=/opt/hmci/bin/hmci diff --git a/src/main/java/biz/nellemann/hmci/HmcInstance.java b/src/main/java/biz/nellemann/hmci/HmcInstance.java index 6c1062e..48ac246 100644 --- a/src/main/java/biz/nellemann/hmci/HmcInstance.java +++ b/src/main/java/biz/nellemann/hmci/HmcInstance.java @@ -110,6 +110,8 @@ class HmcInstance implements Runnable { log.debug("discover() - " + hmcId); + Map tmpPartitions = new HashMap<>(); + try { hmcRestClient.logoff(); hmcRestClient.login(); @@ -119,19 +121,16 @@ class HmcInstance implements Runnable { if(!systems.containsKey(systemId)) { systems.put(systemId, system); log.info("discover() - Found ManagedSystem: " + system + " @" + hmcId); + hmcRestClient.enableEnergyMonitoring(system); } // Get LPAR's for this system try { - hmcRestClient.getLogicalPartitionsForManagedSystem(system).forEach((partitionId, partition) -> { - - // Add to list of known partitions - if(!partitions.containsKey(partitionId)) { - partitions.put(partitionId, partition); - log.info("discover() - Found LogicalPartition: " + partition + " @" + hmcId); - } - - }); + hmcRestClient.getLogicalPartitionsForManagedSystem(system).forEach(tmpPartitions::put); + if(!tmpPartitions.isEmpty()) { + partitions.clear(); + tmpPartitions.forEach(partitions::put); + } } catch (Exception e) { log.warn("discover() - getLogicalPartitions", e); } @@ -142,6 +141,7 @@ class HmcInstance implements Runnable { log.warn("discover() - getManagedSystems: " + e.getMessage()); } + } diff --git a/src/main/java/biz/nellemann/hmci/HmcRestClient.java b/src/main/java/biz/nellemann/hmci/HmcRestClient.java index 49f2428..a39e24d 100644 --- a/src/main/java/biz/nellemann/hmci/HmcRestClient.java +++ b/src/main/java/biz/nellemann/hmci/HmcRestClient.java @@ -19,6 +19,8 @@ import okhttp3.*; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; +import org.jsoup.nodes.Entities; +import org.jsoup.parser.Parser; import org.jsoup.select.Elements; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -347,6 +349,54 @@ public class HmcRestClient { } + void enableEnergyMonitoring(ManagedSystem system) { + + log.debug("enableEnergyMonitoring() - " + system.id); + try { + URL url = new URL(String.format("%s/rest/api/pcm/ManagedSystem/%s/preferences", baseUrl, system.id)); + String responseBody = getResponse(url); + String jsonBody = null; + + // Do not try to parse empty response + if(responseBody == null || responseBody.isEmpty() || responseBody.length() <= 1) { + responseErrors++; + log.warn("enableEnergyMonitoring() - empty response"); + return; + } + + Document doc = Jsoup.parse(responseBody, "", Parser.xmlParser()); + doc.outputSettings().escapeMode(Entities.EscapeMode.xhtml); + doc.outputSettings().prettyPrint(false); + doc.outputSettings().charset("US-ASCII"); + Element entry = doc.select("feed > entry").first(); + Element link1 = entry.select("EnergyMonitoringCapable").first(); + Element link2 = entry.select("EnergyMonitorEnabled").first(); + + if(link1.text().equals("true")) { + log.debug("enableEnergyMonitoring() - EnergyMonitoringCapable == true"); + if(link2.text().equals("false")) { + //log.warn("enableEnergyMonitoring() - EnergyMonitorEnabled == false"); + link2.text("true"); + + Document content = Jsoup.parse(doc.select("Content").first().html(), "", Parser.xmlParser()); + content.outputSettings().escapeMode(Entities.EscapeMode.xhtml); + content.outputSettings().prettyPrint(false); + content.outputSettings().charset("UTF-8"); + String updateXml = content.outerHtml(); + + sendPostRequest(url, updateXml); + } + } else { + log.warn("enableEnergyMonitoring() - EnergyMonitoringCapable == false"); + } + + } catch (Exception e) { + log.warn("enableEnergyMonitoring() - Exception: " + e.getMessage()); + } + } + + + /** * Return a Response from the HMC * @param url to get Response from @@ -385,6 +435,41 @@ public class HmcRestClient { + + public String sendPostRequest(URL url, String payload) throws Exception { + + log.debug("sendPostRequest() - " + url.toString()); + + RequestBody requestBody; + if(payload != null) { + //log.debug("sendPostRequest() - payload: " + payload); + requestBody = RequestBody.create(payload, MediaType.get("application/xml")); + } else { + requestBody = RequestBody.create("", null); + } + + + Request request = new Request.Builder() + .url(url) + //.addHeader("Content-Type", "application/xml") + .addHeader("content-type", "application/xml") + .addHeader("X-API-Session", authToken) + .post(requestBody).build(); + + Response response = client.newCall(request).execute(); + String body = Objects.requireNonNull(response.body()).string(); + + if (!response.isSuccessful()) { + response.close(); + log.warn(body); + log.error("sendPostRequest() - Unexpected response: " + response.code()); + throw new IOException("sendPostRequest() - Unexpected response: " + response.code()); + } + + log.debug("sendPostRequest() - response: " + body); + return body; + } + /** * Provide an unsafe (ignoring SSL problems) OkHttpClient * diff --git a/src/test/resources/system-preferences.xml b/src/test/resources/system-preferences.xml new file mode 100644 index 0000000..78712b5 --- /dev/null +++ b/src/test/resources/system-preferences.xml @@ -0,0 +1,42 @@ + + d93d97ab-757a-38ed-afe7-013c51cf60c9 + Performance and Capacity Monitoring Preferences + + + + + e40c41c0-4aff-472d-85f2-715e11ed1a74 + 2021-01-28T13:13:23.636+01:00 + Performance and Capacity Monitoring Preferences + 2021-01-28T13:13:23.636+01:00 + + IBM Power Systems Management Console + + + + + + d93d97ab-757a-38ed-afe7-013c51cf60c9 + 1611836003635 + + + P750-8408-E8D-SN211D04V + + + + + 8408 + E8D + 211D04V + + false + true + true + false + true + false + + + + +