Work on reading and updating PCM preferences to enable energymonitoring.

This commit is contained in:
Mark Nellemann 2022-11-26 10:47:10 +01:00
parent 930a1b982d
commit bcd2b84e9f
11 changed files with 206 additions and 92 deletions

View File

@ -2,11 +2,9 @@
All notable changes to this project will be documented in this file.
## [1.3.5] - 2022-11-08
## [1.3.4] - 2022-10-24
### Changed
- Updated 3rd party dependencies
## [1.4.0] - 2011-12-xx
- Major rewrite of toml+xml+json de-serialization
- Changes to configuration file format - please look at [doc/hmci.toml](doc/hmci.toml) as example.
## [1.3.3] - 2022-09-20
### Added
@ -29,8 +27,7 @@ All notable changes to this project will be documented in this file.
### Added
- Options to include/exclude Managed Systems and/or Logical Partitions.
[1.3.5]: https://bitbucket.org/mnellemann/hmci/branches/compare/v1.3.5%0Dv1.3.4
[1.3.4]: https://bitbucket.org/mnellemann/hmci/branches/compare/v1.3.4%0Dv1.3.3
[1.4.0]: https://bitbucket.org/mnellemann/hmci/branches/compare/v1.4.0%0Dv1.3.3
[1.3.3]: https://bitbucket.org/mnellemann/hmci/branches/compare/v1.3.3%0Dv1.3.0
[1.3.0]: https://bitbucket.org/mnellemann/hmci/branches/compare/v1.3.0%0Dv1.2.8
[1.2.8]: https://bitbucket.org/mnellemann/hmci/branches/compare/v1.2.8%0Dv1.2.7

View File

@ -13,6 +13,7 @@ password = ""
database = "hmci"
###
### Define one or more HMC's to query for metrics
### Each entry must be named [hmc.<something-unique>]
@ -21,7 +22,7 @@ database = "hmci"
# HMC to query for data and metrics
[hmc.site1]
url = "https://10.10.10.10:12443"
url = "https://10.10.10.5:12443"
username = "hmci"
password = "hmcihmci"
refresh = 30 # How often to query HMC for data - in seconds
@ -32,10 +33,10 @@ energy = true # Collect energy metrics on supported systems
# Another HMC example
#[hmc.site2]
#url = "https://10.10.10.30:12443"
#url = "https://10.10.20.5:12443"
#username = "user"
#password = "password"
#trace = "/tmp/hmci-trace" # When present, store JSON metrics files from HMC into this folder
#trace = "/tmp/hmci-trace" # When present, store JSON metrics files from HMC into this folder
#excludeSystems = [ 'notThisSystem' ] # Collect metrics from all systems except those listed here
#includeSystems = [ 'onlyThisSystems' ] # Collcet metrics from no systems but those listed here
#excludePartitions = [ 'skipThisPartition' ] # Collect metrics from all partitions except those listed here

View File

@ -32,7 +32,7 @@ import java.util.concurrent.Callable;
defaultValueProvider = biz.nellemann.hmci.DefaultProvider.class)
public class Application implements Callable<Integer> {
@Option(names = { "-c", "--conf" }, description = "Configuration file [default: ${DEFAULT-VALUE}].", paramLabel = "<file>")
@Option(names = { "-c", "--conf" }, description = "Configuration file [default: ${DEFAULT-VALUE}].", paramLabel = "<file>", defaultValue = "/etc/hmci.toml")
private File configurationFile;
@Option(names = { "-d", "--debug" }, description = "Enable debugging [default: false].")
@ -85,14 +85,6 @@ public class Application implements Callable<Integer> {
}
});
/*
for(Configuration.HmcConfiguration configHmc : configuration.getHmc()) {
Thread t = new Thread(new ManagementConsole(configHmc, influxClient));
t.setName(configHmc.name);
t.start();
threadList.add(t);
}*/
for (Thread thread : threadList) {
thread.join();
}

View File

@ -15,10 +15,9 @@
*/
package biz.nellemann.hmci;
import biz.nellemann.hmci.dto.json.SystemUtil;
import biz.nellemann.hmci.dto.json.Temperature;
import biz.nellemann.hmci.dto.xml.*;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -27,8 +26,6 @@ import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
class ManagedSystem extends Resource {
@ -46,6 +43,7 @@ class ManagedSystem extends Resource {
protected ManagedSystemEntry entry;
protected ManagedSystemPcmPreference pcmPreference;
protected SystemEnergy systemEnergy;
private String uriPath;
@ -81,9 +79,20 @@ class ManagedSystem extends Resource {
}
public void setDoEnergy(Boolean doEnergy) {
this.doEnergy = doEnergy;
// TODO: Enable energy command.
systemEnergy = new SystemEnergy(restClient, this);
if(pcmPreference == null) {
return;
}
if(pcmPreference.energyMonitoringCapable && !pcmPreference.energyMonitorEnabled) {
// TODO: Try to enable
}
if(pcmPreference.energyMonitorEnabled) {
this.doEnergy = doEnergy;
systemEnergy = new SystemEnergy(restClient, this);
}
}
public void discover() {
@ -183,54 +192,46 @@ class ManagedSystem extends Resource {
}
public void getPcmPreferences() {
log.info("getPcmPreferences()");
/*
void enableEnergyMonitoring() {
log.trace("enableEnergyMonitoring() - {}", system);
try {
URL url = new URL(String.format("%s/rest/api/pcm/ManagedSystem/%s/preferences", baseUrl, system.id));
String responseBody = sendGetRequest(url);
String urlPath = String.format("/rest/api/pcm/ManagedSystem/%s/preferences", id);
String xml = restClient.getRequest(urlPath);
// Do not try to parse empty response
if(responseBody == null || responseBody.length() <= 1) {
responseErrors++;
log.warn("enableEnergyMonitoring() - empty response, skipping: {}", system);
if(xml == null || xml.length() <= 1) {
log.warn("getPcmPreferences() - no data.");
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 = Objects.requireNonNull(entry).select("EnergyMonitoringCapable").first();
Element link2 = entry.select("EnergyMonitorEnabled").first();
XmlMapper xmlMapper = new XmlMapper();
XmlFeed xmlFeed = xmlMapper.readValue(xml, XmlFeed.class);
if(Objects.requireNonNull(link1).text().equals("true")) {
log.debug("enableEnergyMonitoring() - EnergyMonitoringCapable == true");
if(Objects.requireNonNull(link2).text().equals("false")) {
//log.warn("enableEnergyMonitoring() - EnergyMonitorEnabled == false");
link2.text("true");
if(xmlFeed.getEntry().getContent() == null){
log.warn("getPcmPreferences() - no content.");
log.info(xml);
return;
}
Document content = Jsoup.parse(Objects.requireNonNull(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);
if(xmlFeed.getEntry().getContent().isManagedSystemPcmPreference()) {
pcmPreference = xmlFeed.getEntry().getContent().getManagedSystemPcmPreference();
if(pcmPreference.energyMonitoringCapable && !pcmPreference.energyMonitorEnabled) {
log.warn("getPcmPreferences() - TODO: Enable energyMonitor");
//pcmPreference.energyMonitorEnabled = true;
//xmlMapper.configure(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED,true);
//String updateXml = xmlMapper.writeValueAsString(pcmPreference);
//restClient.postRequest(urlPath, updateXml);
}
} else {
log.warn("enableEnergyMonitoring() - EnergyMonitoringCapable == false");
throw new UnsupportedOperationException("Failed to deserialize ManagedSystemPcmPreference");
}
} catch (Exception e) {
log.debug("enableEnergyMonitoring() - Error: {}", e.getMessage());
log.debug("getPcmPreferences() - Error: {}", e.getMessage());
}
}
*/
// System details

View File

@ -26,6 +26,7 @@ import org.slf4j.LoggerFactory;
import java.io.File;
import java.time.Duration;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
@ -67,10 +68,10 @@ class ManagementConsole implements Runnable {
if(traceDir.canWrite()) {
Boolean doTrace = true;
} else {
log.warn("HmcInstance() - can't write to trace dir: " + traceDir.toString());
log.warn("ManagementConsole() - can't write to trace dir: " + traceDir.toString());
}
} catch (Exception e) {
log.error("HmcInstance() - trace error: " + e.getMessage());
log.error("ManagementConsole() - trace error: " + e.getMessage());
}
}
this.excludeSystems = configuration.excludeSystems;
@ -84,8 +85,8 @@ class ManagementConsole implements Runnable {
public void run() {
log.trace("run()");
int executions = 0;
Instant lastDiscover = Instant.now();
restClient.login();
discover();
@ -93,8 +94,8 @@ class ManagementConsole implements Runnable {
Instant instantStart = Instant.now();
try {
refresh();
if (++executions > discoverValue) { // FIXME: Change to time based logic
executions = 0;
if(instantStart.isAfter(lastDiscover.plus(discoverValue, ChronoUnit.MINUTES))) {
lastDiscover = instantStart;
discover();
}
} catch (Exception e) {
@ -126,7 +127,6 @@ class ManagementConsole implements Runnable {
// Logout of HMC
restClient.logoff();
}
@ -163,12 +163,14 @@ class ManagementConsole implements Runnable {
ManagedSystem managedSystem = new ManagedSystem(restClient, link.getHref());
managedSystem.setExcludePartitions(excludePartitions);
managedSystem.setIncludePartitions(includePartitions);
managedSystem.setDoEnergy(doEnergy);
managedSystem.discover();
// Only continue for powered-on operating systems
if(managedSystem.entry != null && Objects.equals(managedSystem.entry.state, "operating")) {
managedSystem.getPcmPreferences();
managedSystem.setDoEnergy(doEnergy);
// Check exclude / include
if (!excludeSystems.contains(managedSystem.name) && includeSystems.isEmpty()) {
managedSystems.add(managedSystem);
@ -193,19 +195,18 @@ class ManagementConsole implements Runnable {
managedSystems.forEach( (system) -> {
if(system.entry == null){
log.warn("refresh() - system.entry == null");
log.warn("refresh() - no data.");
return;
}
system.refresh();
influxClient.write(system.getDetails(), system.getTimestamp(),"server_details");
influxClient.write(system.getMemoryMetrics(), system.getTimestamp(),"server_memory");
influxClient.write(system.getProcessorMetrics(), system.getTimestamp(),"server_processor");
influxClient.write(system.getPhysicalProcessorPool(), system.getTimestamp(),"server_physicalProcessorPool");
influxClient.write(system.getSharedProcessorPools(), system.getTimestamp(),"server_sharedProcessorPool");
if(doEnergy) {
if(system.systemEnergy != null) {
system.systemEnergy.refresh();
if(system.systemEnergy.metric != null) {
influxClient.write(system.systemEnergy.getPowerMetrics(), system.getTimestamp(), "server_energy_power");

View File

@ -32,9 +32,7 @@ public class RestClient {
private final static int WRITE_TIMEOUT = 30;
private final static int READ_TIMEOUT = 180;
//protected final HttpClient httpClient;
protected String authToken;
protected final String baseUrl;
protected final String username;
protected final String password;
@ -44,8 +42,6 @@ public class RestClient {
this.baseUrl = baseUrl;
this.username = username;
this.password = password;
//this.httpClient = getHttpClient(trustAll);
//httpClient.start();
if (trustAll) {
this.httpClient = getUnsafeOkHttpClient();
} else {
@ -151,7 +147,7 @@ public class RestClient {
* @param url to get Response from
* @return Response body string
*/
private String getRequest(URL url) throws IOException {
public synchronized String getRequest(URL url) throws IOException {
log.trace("getRequest() - URL: {}", url.toString());
@ -172,16 +168,8 @@ public class RestClient {
log.warn("getRequest() - 401 - login and retry.");
// Let's login again and retry
authToken = null;
login();
try (Response responseRetry = httpClient.newCall(request).execute()) {
log.debug("getRequest() - in retry: {}", Objects.requireNonNull(responseRetry.body()).string());
if (responseRetry.isSuccessful()) {
return Objects.requireNonNull(responseRetry.body()).string();
}
return null;
}
return retryGetRequest(url);
}
log.error("getRequest() - Unexpected response: {}", response.code());
@ -194,6 +182,26 @@ public class RestClient {
}
private String retryGetRequest(URL url) throws IOException {
log.debug("retryGetRequest() - URL: {}", url.toString());
Request request = new Request.Builder()
.url(url)
.addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8")
.addHeader("X-API-Session", (authToken == null ? "" : authToken))
.get().build();
String responseBody = null;
try (Response responseRetry = httpClient.newCall(request).execute()) {
if(responseRetry.isSuccessful()) {
responseBody = responseRetry.body().string();
}
}
return responseBody;
}
/**
* Send a POST request with a payload (can be null) to the HMC
* @param url
@ -201,9 +209,9 @@ public class RestClient {
* @return
* @throws IOException
*/
public String postRequest(URL url, String payload) throws IOException {
public synchronized String postRequest(URL url, String payload) throws IOException {
log.trace("sendPostRequest() - URL: {}", url.toString());
log.info("sendPostRequest() - URL: {}", url.toString());
RequestBody requestBody;
if(payload != null) {
requestBody = RequestBody.create(payload, MediaType.get("application/xml"));

View File

@ -0,0 +1,45 @@
package biz.nellemann.hmci.dto.xml;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
@JsonIgnoreProperties(ignoreUnknown = true)
@JacksonXmlRootElement(localName = "ManagedSystemPcmPreference:ManagedSystemPcmPreference")
public class ManagedSystemPcmPreference {
@JacksonXmlProperty(isAttribute = true)
private final String schemaVersion = "V1_0";
@JacksonXmlProperty(isAttribute = true, localName = "xmlns:ManagedSystemPcmPreference")
private final String xmlns = "http://www.ibm.com/xmlns/systems/power/firmware/pcm/mc/2012_10/";
@JsonProperty("Metadata")
public Metadata metadata;
@JsonProperty("SystemName")
public String systemName;
//public MachineTypeModelAndSerialNumber machineTypeModelSerialNumber;
@JsonProperty("EnergyMonitoringCapable")
public Boolean energyMonitoringCapable = false;
@JsonProperty("LongTermMonitorEnabled")
public Boolean longTermMonitorEnabled = false;
@JsonProperty("AggregationEnabled")
public Boolean aggregationEnabled = false;
@JsonProperty("ShortTermMonitorEnabled")
public Boolean shortTermMonitorEnabled;
@JsonProperty("ComputeLTMEnabled")
public Boolean computeLTMEnabled;
@JsonProperty("EnergyMonitorEnabled")
public Boolean energyMonitorEnabled;
}

View File

@ -0,0 +1,21 @@
package biz.nellemann.hmci.dto.xml;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
@JsonIgnoreProperties(ignoreUnknown = true)
public class Metadata {
@JsonProperty("Atom")
public Atom atom;
@JsonIgnoreProperties(ignoreUnknown = true)
public class Atom {
@JsonProperty("AtomID")
public String atomID;
@JsonProperty("AtomCreated")
public String atomCreated;
}
}

View File

@ -57,6 +57,7 @@ public class XmlEntry implements Serializable {
return managementConsoleEntry != null;
}
@JsonProperty("ManagedSystem")
private ManagedSystemEntry managedSystemEntry;
@ -69,6 +70,18 @@ public class XmlEntry implements Serializable {
}
@JsonProperty("ManagedSystemPcmPreference")
private ManagedSystemPcmPreference managedSystemPcmPreference;
public ManagedSystemPcmPreference getManagedSystemPcmPreference() {
return managedSystemPcmPreference;
}
public boolean isManagedSystemPcmPreference() {
return managedSystemPcmPreference != null;
}
@JsonAlias("VirtualIOServer")
private VirtualIOServerEntry virtualIOServerEntry;

View File

@ -0,0 +1,43 @@
<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>b597e4da-2aab-3f52-8616-341d62153559</id>
<title type="text">Performance and Capacity Monitoring Preferences</title>
<subtitle type="text"/>
<link rel="self" href="https://10.32.64.80:12443/rest/api/pcm/ManagedSystem/b597e4da-2aab-3f52-8616-341d62153559/preferences"/>
<generator uri="IBM Power Systems Management Console" version="1"/>
<entry>
<id>103bfcca-ea8f-48bc-b946-e8928343a6f7</id>
<updated>2022-11-26T08:48:26.340+01:00</updated>
<title type="text">Performance and Capacity Monitoring Preferences</title>
<published>2022-11-26T08:48:26.340+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_0">
<Metadata>
<Atom>
<AtomID>b597e4da-2aab-3f52-8616-341d62153559</AtomID>
<AtomCreated>1669448906337</AtomCreated>
</Atom>
</Metadata>
<SystemName kb="ROR" kxe="false">Server-9009-42A-SN21F64EV</SystemName>
<MachineTypeModelSerialNumber kb="ROR" kxe="false" schemaVersion="V1_0">
<Metadata>
<Atom/>
</Metadata>
<MachineType kxe="false" kb="ROR">9009</MachineType>
<Model kxe="false" kb="ROR">42A</Model>
<SerialNumber kb="ROR" kxe="false">21F64EV</SerialNumber>
</MachineTypeModelSerialNumber>
<EnergyMonitoringCapable kb="ROO" kxe="false">true</EnergyMonitoringCapable>
<LongTermMonitorEnabled kb="UOD" kxe="false">true</LongTermMonitorEnabled>
<AggregationEnabled kxe="false" kb="UOD">true</AggregationEnabled>
<ShortTermMonitorEnabled kxe="false" kb="UOD">false</ShortTermMonitorEnabled>
<ComputeLTMEnabled ksv="V1_1_0" kb="UOD" kxe="false">false</ComputeLTMEnabled>
<EnergyMonitorEnabled kb="UOD" kxe="false">true</EnergyMonitorEnabled>
<AssociatedManagedSystem kb="ROO" kxe="false" href="https://10.32.64.80:12443/rest/api/uom/ManagedSystem/b597e4da-2aab-3f52-8616-341d62153559" rel="related"/>
</ManagedSystemPcmPreference:ManagedSystemPcmPreference>
</content>
</entry>
</feed>

View File

@ -21,19 +21,11 @@ includeSystems = [ 'onlyThisSys', 'andOnlyThisSys' ]
excludePartitions = [ 'notThisPartition' ]
includePartitions = [ 'onlyThisPartition' ]
# SVC
[svc]
name = "site2"
url = "https://10.32.64.182:7443"
username = "superuser"
password = "Password"
# Example
[hmc.site2]
url = "https://10.10.20.20:12443"
username = "viewer"
password = "someSecret"
unsafe = false
trust = false
energy = true
trace = "/tmp/pcm-files"