Merged in enableThermal (pull request #14)

EnableThermal
This commit is contained in:
Mark Nellemann 2021-01-29 10:22:11 +00:00
commit 30f1f71a95
7 changed files with 162 additions and 23 deletions

View file

@ -6,7 +6,7 @@ Metrics includes:
- *Managed Systems* - the physical Power servers - *Managed Systems* - the physical Power servers
- *Logical Partitions* - the virtualized servers running AIX, Linux and IBM-i (AS/400) - *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 - *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) ![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 ### 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). written to InfluxDB (which uses the name as key).
### Renaming partitions ### Renaming partitions

View file

@ -2,6 +2,8 @@
Description=HMC Insights Service Description=HMC Insights Service
[Service] [Service]
#User=nobody
#Group=nogroup
TimeoutStartSec=0 TimeoutStartSec=0
Restart=always Restart=always
ExecStart=/opt/hmci/bin/hmci ExecStart=/opt/hmci/bin/hmci

View file

@ -1,3 +1,3 @@
id = hmci id = hmci
group = biz.nellemann.hmci group = biz.nellemann.hmci
version = 1.1.2 version = 1.1.3

View file

@ -110,6 +110,8 @@ class HmcInstance implements Runnable {
log.debug("discover() - " + hmcId); log.debug("discover() - " + hmcId);
Map<String, LogicalPartition> tmpPartitions = new HashMap<>();
try { try {
hmcRestClient.logoff(); hmcRestClient.logoff();
hmcRestClient.login(); hmcRestClient.login();
@ -119,19 +121,16 @@ class HmcInstance implements Runnable {
if(!systems.containsKey(systemId)) { if(!systems.containsKey(systemId)) {
systems.put(systemId, system); systems.put(systemId, system);
log.info("discover() - Found ManagedSystem: " + system + " @" + hmcId); log.info("discover() - Found ManagedSystem: " + system + " @" + hmcId);
hmcRestClient.enableEnergyMonitoring(system);
} }
// Get LPAR's for this system // Get LPAR's for this system
try { try {
hmcRestClient.getLogicalPartitionsForManagedSystem(system).forEach((partitionId, partition) -> { hmcRestClient.getLogicalPartitionsForManagedSystem(system).forEach(tmpPartitions::put);
if(!tmpPartitions.isEmpty()) {
// Add to list of known partitions partitions.clear();
if(!partitions.containsKey(partitionId)) { tmpPartitions.forEach(partitions::put);
partitions.put(partitionId, partition);
log.info("discover() - Found LogicalPartition: " + partition + " @" + hmcId);
} }
});
} catch (Exception e) { } catch (Exception e) {
log.warn("discover() - getLogicalPartitions", e); log.warn("discover() - getLogicalPartitions", e);
} }
@ -142,6 +141,7 @@ class HmcInstance implements Runnable {
log.warn("discover() - getManagedSystems: " + e.getMessage()); log.warn("discover() - getManagedSystems: " + e.getMessage());
} }
} }

View file

@ -19,6 +19,8 @@ import okhttp3.*;
import org.jsoup.Jsoup; import org.jsoup.Jsoup;
import org.jsoup.nodes.Document; import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element; import org.jsoup.nodes.Element;
import org.jsoup.nodes.Entities;
import org.jsoup.parser.Parser;
import org.jsoup.select.Elements; import org.jsoup.select.Elements;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -160,7 +162,7 @@ public class HmcRestClient {
Map<String, ManagedSystem> getManagedSystems() throws Exception { Map<String, ManagedSystem> getManagedSystems() throws Exception {
URL url = new URL(String.format("%s/rest/api/uom/ManagedSystem", baseUrl)); URL url = new URL(String.format("%s/rest/api/uom/ManagedSystem", baseUrl));
String responseBody = getResponse(url); String responseBody = sendGetRequest(url);
Map<String,ManagedSystem> managedSystemsMap = new HashMap<>(); Map<String,ManagedSystem> managedSystemsMap = new HashMap<>();
// Do not try to parse empty response // Do not try to parse empty response
@ -200,7 +202,7 @@ public class HmcRestClient {
*/ */
Map<String, LogicalPartition> getLogicalPartitionsForManagedSystem(ManagedSystem system) throws Exception { Map<String, LogicalPartition> getLogicalPartitionsForManagedSystem(ManagedSystem system) throws Exception {
URL url = new URL(String.format("%s/rest/api/uom/ManagedSystem/%s/LogicalPartition", baseUrl, system.id)); URL url = new URL(String.format("%s/rest/api/uom/ManagedSystem/%s/LogicalPartition", baseUrl, system.id));
String responseBody = getResponse(url); String responseBody = sendGetRequest(url);
Map<String, LogicalPartition> partitionMap = new HashMap<>(); Map<String, LogicalPartition> partitionMap = new HashMap<>();
// Do not try to parse empty response // Do not try to parse empty response
@ -240,7 +242,7 @@ public class HmcRestClient {
log.debug("getPcmDataForManagedSystem() - " + system.id); log.debug("getPcmDataForManagedSystem() - " + system.id);
URL url = new URL(String.format("%s/rest/api/pcm/ManagedSystem/%s/ProcessedMetrics?NoOfSamples=1", baseUrl, system.id)); URL url = new URL(String.format("%s/rest/api/pcm/ManagedSystem/%s/ProcessedMetrics?NoOfSamples=1", baseUrl, system.id));
String responseBody = getResponse(url); String responseBody = sendGetRequest(url);
String jsonBody = null; String jsonBody = null;
// Do not try to parse empty response // Do not try to parse empty response
@ -258,7 +260,7 @@ public class HmcRestClient {
if(link.attr("type").equals("application/json")) { if(link.attr("type").equals("application/json")) {
String href = link.attr("href"); String href = link.attr("href");
log.debug("getPcmDataForManagedSystem() - json url: " + href); log.debug("getPcmDataForManagedSystem() - json url: " + href);
jsonBody = getResponse(new URL(href)); jsonBody = sendGetRequest(new URL(href));
} }
} catch(Exception e) { } catch(Exception e) {
@ -278,7 +280,7 @@ public class HmcRestClient {
log.debug(String.format("getPcmDataForLogicalPartition() - %s @ %s", partition.id, partition.system.id)); log.debug(String.format("getPcmDataForLogicalPartition() - %s @ %s", partition.id, partition.system.id));
URL url = new URL(String.format("%s/rest/api/pcm/ManagedSystem/%s/LogicalPartition/%s/ProcessedMetrics?NoOfSamples=1", baseUrl, partition.system.id, partition.id)); URL url = new URL(String.format("%s/rest/api/pcm/ManagedSystem/%s/LogicalPartition/%s/ProcessedMetrics?NoOfSamples=1", baseUrl, partition.system.id, partition.id));
String responseBody = getResponse(url); String responseBody = sendGetRequest(url);
String jsonBody = null; String jsonBody = null;
// Do not try to parse empty response // Do not try to parse empty response
@ -296,7 +298,7 @@ public class HmcRestClient {
if(link.attr("type").equals("application/json")) { if(link.attr("type").equals("application/json")) {
String href = link.attr("href"); String href = link.attr("href");
log.debug("getPcmDataForLogicalPartition() - json url: " + href); log.debug("getPcmDataForLogicalPartition() - json url: " + href);
jsonBody = getResponse(new URL(href)); jsonBody = sendGetRequest(new URL(href));
} }
} catch(Exception e) { } catch(Exception e) {
@ -317,7 +319,7 @@ public class HmcRestClient {
log.debug("getPcmDataForEnergy() - " + systemEnergy.system.id); log.debug("getPcmDataForEnergy() - " + systemEnergy.system.id);
URL url = new URL(String.format("%s/rest/api/pcm/ManagedSystem/%s/ProcessedMetrics?Type=Energy&NoOfSamples=1", baseUrl, systemEnergy.system.id)); URL url = new URL(String.format("%s/rest/api/pcm/ManagedSystem/%s/ProcessedMetrics?Type=Energy&NoOfSamples=1", baseUrl, systemEnergy.system.id));
String responseBody = getResponse(url); String responseBody = sendGetRequest(url);
String jsonBody = null; String jsonBody = null;
//log.info(responseBody); //log.info(responseBody);
@ -336,7 +338,7 @@ public class HmcRestClient {
if(link.attr("type").equals("application/json")) { if(link.attr("type").equals("application/json")) {
String href = link.attr("href"); String href = link.attr("href");
log.debug("getPcmDataForEnergy() - json url: " + href); log.debug("getPcmDataForEnergy() - json url: " + href);
jsonBody = getResponse(new URL(href)); jsonBody = sendGetRequest(new URL(href));
} }
} catch(Exception e) { } catch(Exception e) {
@ -347,12 +349,64 @@ public class HmcRestClient {
} }
/**
* Set EnergyMonitorEnabled preference to true, if possible.
* @param system
*/
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 = sendGetRequest(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 * Return a Response from the HMC
* @param url to get Response from * @param url to get Response from
* @return Response body string * @return Response body string
*/ */
private String getResponse(URL url) throws Exception { private String sendGetRequest(URL url) throws Exception {
log.debug("getResponse() - " + url.toString()); log.debug("getResponse() - " + url.toString());
@ -384,6 +438,47 @@ public class HmcRestClient {
} }
/**
* Send a POST request with a payload (can be null) to the HMC
* @param url
* @param payload
* @return
* @throws Exception
*/
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 * Provide an unsafe (ignoring SSL problems) OkHttpClient

View file

@ -73,7 +73,7 @@ class HmcRestClientTest extends Specification {
mockServer.enqueue(new MockResponse().setBody(testJson)) mockServer.enqueue(new MockResponse().setBody(testJson))
when: when:
String jsonString = hmc.getResponse(new URL(mockServer.url("/rest/api/pcm/ProcessedMetrics/ManagedSystem_e09834d1-c930-3883-bdad-405d8e26e166_20200807T122600+0200_20200807T122600+0200_30.json") as String)) String jsonString = hmc.sendGetRequest(new URL(mockServer.url("/rest/api/pcm/ProcessedMetrics/ManagedSystem_e09834d1-c930-3883-bdad-405d8e26e166_20200807T122600+0200_20200807T122600+0200_30.json") as String))
then: then:
jsonString.contains('"uuid": "e09834d1-c930-3883-bdad-405d8e26e166"') jsonString.contains('"uuid": "e09834d1-c930-3883-bdad-405d8e26e166"')
@ -87,7 +87,7 @@ class HmcRestClientTest extends Specification {
mockServer.enqueue(new MockResponse().setBody(testJson)) mockServer.enqueue(new MockResponse().setBody(testJson))
when: when:
String jsonString = hmc.getResponse(new URL(mockServer.url("/rest/api/pcm/ProcessedMetrics/LogicalPartition_2DE05DB6-8AD5-448F-8327-0F488D287E82_20200807T123730+0200_20200807T123730+0200_30.json") as String)) String jsonString = hmc.sendGetRequest(new URL(mockServer.url("/rest/api/pcm/ProcessedMetrics/LogicalPartition_2DE05DB6-8AD5-448F-8327-0F488D287E82_20200807T123730+0200_20200807T123730+0200_30.json") as String))
then: then:
jsonString.contains('"uuid": "b597e4da-2aab-3f52-8616-341d62153559"') jsonString.contains('"uuid": "b597e4da-2aab-3f52-8616-341d62153559"')

View file

@ -0,0 +1,42 @@
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:ns2="http://a9.com/-/spec/opensearch/1.1/" xmlns:ns3="http://www.w3.org/1999/xhtml">
<id>d93d97ab-757a-38ed-afe7-013c51cf60c9</id>
<title type="text">Performance and Capacity Monitoring Preferences</title>
<subtitle type="text"/>
<link rel="self" href="https://10.32.64.40:12443/rest/api/pcm/ManagedSystem/d93d97ab-757a-38ed-afe7-013c51cf60c9/preferences"/>
<generator uri="IBM Power Systems Management Console" version="1"/>
<entry>
<id>e40c41c0-4aff-472d-85f2-715e11ed1a74</id>
<updated>2021-01-28T13:13:23.636+01:00</updated>
<title type="text">Performance and Capacity Monitoring Preferences</title>
<published>2021-01-28T13:13:23.636+01:00</published>
<author>
<name>IBM Power Systems Management Console</name>
</author>
<content type="application/xml">
<ManagedSystemPcmPreference:ManagedSystemPcmPreference xmlns:ManagedSystemPcmPreference="http://www.ibm.com/xmlns/systems/power/firmware/pcm/mc/2012_10/" xmlns="http://www.ibm.com/xmlns/systems/power/firmware/pcm/mc/2012_10/" xmlns:ns2="http://www.w3.org/XML/1998/namespace/k2" schemaVersion="V1_5_3">
<Metadata>
<Atom>
<AtomID>d93d97ab-757a-38ed-afe7-013c51cf60c9</AtomID>
<AtomCreated>1611836003635</AtomCreated>
</Atom>
</Metadata>
<SystemName kxe="false" kb="ROR">P750-8408-E8D-SN211D04V</SystemName>
<MachineTypeModelSerialNumber kb="ROR" kxe="false" schemaVersion="V1_5_3">
<Metadata>
<Atom/>
</Metadata>
<MachineType kb="ROR" kxe="false">8408</MachineType>
<Model kxe="false" kb="ROR">E8D</Model>
<SerialNumber kxe="false" kb="ROR">211D04V</SerialNumber>
</MachineTypeModelSerialNumber>
<EnergyMonitoringCapable kxe="false" kb="ROO">false</EnergyMonitoringCapable>
<LongTermMonitorEnabled kb="UOD" kxe="false">true</LongTermMonitorEnabled>
<AggregationEnabled kxe="false" kb="UOD">true</AggregationEnabled>
<ShortTermMonitorEnabled kb="UOD" kxe="false">false</ShortTermMonitorEnabled>
<ComputeLTMEnabled ksv="V1_1_0" kxe="false" kb="UOD">true</ComputeLTMEnabled>
<EnergyMonitorEnabled kb="UOD" kxe="false">false</EnergyMonitorEnabled>
<AssociatedManagedSystem kxe="false" kb="ROO" href="https://127.0.0.1:13443/rest/api/uom/ManagedSystem/d93d97ab-757a-38ed-afe7-013c51cf60c9" rel="related"/>
</ManagedSystemPcmPreference:ManagedSystemPcmPreference>
</content>
</entry>
</feed>