More refactoring work, from Groovy to plain Java.

This commit is contained in:
Mark Nellemann 2020-10-11 12:25:55 +02:00
parent 3f71aabd4e
commit b005376941
41 changed files with 1337 additions and 1060 deletions

View file

@ -10,7 +10,7 @@ HMCi is a small utility to fetch metrics from one or more HMC's and push those t
- Ensure you have correct date/time and use a NTP service to keep it accurate! - Ensure you have correct date/time and use a NTP service to keep it accurate!
- Install the HMCi package (*.deb* or *.rpm*) from [downloads](https://bitbucket.org/mnellemann/hmci/downloads/) or compile from source. - Install the HMCi package (*.deb* or *.rpm*) from [downloads](https://bitbucket.org/mnellemann/hmci/downloads/) or compile from source.
- Copy the *doc/hmci.groovy.tpl* configuration template into */etc/hmci.groovy* and edit the configuration to suit your environment. You can use the *-c [conf-file]* switch if you place this file elsewhere. - Copy the *doc/hmci.tpml* configuration template into */etc/hmci.toml* and edit the configuration to suit your environment. You can use the *-c* option if you place this file elsewhere.
- Configure Grafana to communicate with your InfluxDB and import dashboards from *doc/* into Grafana (The dashboards are slightly modified versions of the dashboard provided by the nmon2influxdb tool). - Configure Grafana to communicate with your InfluxDB and import dashboards from *doc/* into Grafana (The dashboards are slightly modified versions of the dashboard provided by the nmon2influxdb tool).
- Run the *bin/hmci* program in a shell, as a @reboot cron task or setup a proper service :) - Run the *bin/hmci* program in a shell, as a @reboot cron task or setup a proper service :)

View file

@ -16,20 +16,18 @@ repositories {
} }
dependencies { dependencies {
implementation 'info.picocli:picocli:4.5.1'
annotationProcessor 'info.picocli:picocli-codegen:4.5.1' annotationProcessor 'info.picocli:picocli-codegen:4.5.1'
// implementation 'com.thoughtworks.xstream:xstream:1.4.13' implementation 'info.picocli:picocli:4.5.1'
// https://mvnrepository.com/artifact/org.jsoup/jsoup
implementation 'org.jsoup:jsoup:1.13.1' implementation 'org.jsoup:jsoup:1.13.1'
implementation 'com.squareup.moshi:moshi:1.11.0'
implementation 'org.tomlj:tomlj:1.0.0'
implementation 'org.codehaus.groovy:groovy-all:3.0.5'
implementation 'com.squareup.okhttp3:okhttp:4.8.0' implementation 'com.squareup.okhttp3:okhttp:4.8.0'
implementation 'com.squareup.moshi:moshi:1.11.0'
implementation 'com.serjltt.moshi:moshi-lazy-adapters:2.2'
implementation 'org.tomlj:tomlj:1.0.0'
implementation 'org.influxdb:influxdb-java:2.19' implementation 'org.influxdb:influxdb-java:2.19'
implementation 'org.slf4j:slf4j-api:1.7.+' implementation 'org.slf4j:slf4j-api:1.7.+'
runtimeOnly 'ch.qos.logback:logback-classic:1.+' runtimeOnly 'ch.qos.logback:logback-classic:1.+'
testImplementation 'org.codehaus.groovy:groovy-all:3.0.5'
testImplementation('org.spockframework:spock-core:2.0-M3-groovy-3.0') testImplementation('org.spockframework:spock-core:2.0-M3-groovy-3.0')
testImplementation("org.slf4j:slf4j-simple:1.7.+") testImplementation("org.slf4j:slf4j-simple:1.7.+")
testImplementation('com.squareup.okhttp3:mockwebserver:4.8.0') testImplementation('com.squareup.okhttp3:mockwebserver:4.8.0')

View file

@ -1,39 +0,0 @@
/*
Copy this file to /etc/hmci.groovy and change it to suit your environment.
*/
// How often to query HMC's for data - in seconds
hmci.refresh = 30
// Rescan HMC's for new systems and partitions - every x refresh
hmci.rescan = 60
// InfluxDB to save metrics
influx {
url = "http://localhost:8086"
username = "root"
password = ""
database = "hmci"
}
// One or more HMC's to query for data and metrics
hmc {
// HMC on our primary site
site1 {
url = "https://10.10.10.10:12443"
username = "hmci"
password = "hmcihmci"
unsafe = true // Ignore SSL cert. errors
}
/*
site2 {
url = "https://10.10.20.20:12443"
username = "viewer"
password = "someSecret"
unsafe = false
}
*/
}

31
doc/hmci.toml Normal file
View file

@ -0,0 +1,31 @@
# HMCi Configuration
# How often to query HMC's for data - in seconds
hmci.refresh = 30
# Rescan HMC's for new systems and partitions - every x refresh
hmci.rescan = 60
# InfluxDB to save metrics
[influx]
url = "http://localhost:8086"
username = "root"
password = ""
database = "hmci"
# One or more HMC's to query for data and metrics
[hmc]
# HMC on our primary site
[hmc.site1]
url = "https://10.10.10.10:12443"
username = "hmci"
password = "hmcihmci"
unsafe = true # Ignore SSL cert. errors
# Example
#[hmc.site2]
#url = "https://10.10.20.20:12443"
#username = "viewer"
#password = "someSecret"
#unsafe = false

View file

@ -1,176 +0,0 @@
/**
* Copyright 2020 Mark Nellemann <mark.nellemann@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package biz.nellemann.hmci
import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j;
@Slf4j
@CompileStatic
class Insights {
final Configuration configuration;
InfluxClient influxClient;
Map<String, HmcClient> hmcClients = new HashMap<>();
Map<String,ManagedSystem> systems = new HashMap<String, ManagedSystem>();
Map<String, LogicalPartition> partitions = new HashMap<String, LogicalPartition>();
Insights(Configuration configuration) {
this.configuration = configuration;
try {
influxClient = new InfluxClient(configuration.influx);
influxClient.login();
} catch(Exception e) {
System.exit(1);
}
// Initial scan
discover();
}
void discover() {
configuration.hmc.forEach( configHmc -> {
if(!hmcClients?.containsKey(configHmc.name)) {
log.debug("Adding HMC: " + configHmc.toString())
HmcClient hmcClient = new HmcClient(configHmc)
hmcClients.put(configHmc.name, hmcClient)
}
});
hmcClients.forEach(( hmcId, hmcClient) -> {
try {
hmcClient.login()
hmcClient.getManagedSystems().each { systemId, system ->
// Add to list of known systems
systems.putIfAbsent(systemId, system)
// Get LPAR's for this system
hmcClient.getLogicalPartitionsForManagedSystem(system).forEach((partitionId, partition) -> {
// Add to list of known partitions
partitions.putIfAbsent(partitionId, partition)
});
}
} catch(Exception e) {
log.error("discover() - " + hmcId + " error: " + e.message)
//hmcClients.remove(hmcId)
}
});
}
void getMetricsForSystems() {
try {
systems.forEach((systemId, system) -> {
HmcClient hmcClient = hmcClients.get(system.hmcId)
// Get and process metrics for this system
String tmpJsonString = hmcClient.getPcmDataForManagedSystem(system)
if(tmpJsonString && !tmpJsonString.empty) {
system.processMetrics(tmpJsonString)
}
});
} catch(Exception e) {
log.error(e.message)
}
}
void getMetricsForPartitions() {
try {
// Get LPAR's for this system
partitions.forEach((partitionId, partition) -> {
HmcClient hmcClient = hmcClients.get(partition.system.hmcId)
// Get and process metrics for this partition
String tmpJsonString2 = hmcClient.getPcmDataForLogicalPartition(partition)
if(tmpJsonString2 && !tmpJsonString2.empty) {
partition.processMetrics(tmpJsonString2)
}
});
} catch(Exception e) {
log.error(e.message)
}
}
void writeMetricsForManagedSystems() {
systems.forEach((systemId, system) -> {
influxClient.writeManagedSystem(system)
});
}
void writeMetricsForLogicalPartitions() {
partitions.each {partitionId, partition ->
influxClient.writeLogicalPartition(partition)
}
}
void run() {
log.debug("run()")
boolean keepRunning = true
int executions = 0
while(keepRunning) {
try {
getMetricsForSystems()
getMetricsForPartitions()
writeMetricsForManagedSystems()
writeMetricsForLogicalPartitions()
influxClient.writeBatchPoints()
// Refresh HMC's
if(executions > configuration.rescan) {
executions = 0
discover()
}
} catch(Exception e) {
log.error(e.message, e)
}
executions++
Thread.sleep(configuration.refresh * 1000)
}
}
}

View file

@ -1,194 +0,0 @@
/**
* Copyright 2020 Mark Nellemann <mark.nellemann@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package biz.nellemann.hmci
import groovy.transform.CompileDynamic
import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
@Slf4j
@CompileStatic
class LogicalPartition extends MetaSystem {
public String id
public String name
public String type
ManagedSystem system
LogicalPartition(String id, String name, String type, ManagedSystem system) {
this.id = id
this.name = name
this.type = type
this.system = system
}
String toString() {
return "[${id}] ${name} (${type})"
}
@CompileDynamic
List<Measurement> getAffinityScore() {
List<Measurement> list = new ArrayList<>()
//Map<String, Map> map = new HashMap<String, Map>()
HashMap<String, String> tagsMap = [
system: system.name,
partition: name,
]
//map.put("tags", tagsMap)
log.debug("getAffinityScore() - tags: " + tagsMap.toString())
HashMap<String, Number> fieldsMap = [
affinityScore: metrics.systemUtil?.utilSamples?.first()?.lparsUtil?.first()?.affinityScore,
] as HashMap<String, Number>
//map.put("fields", fieldsMap)
log.debug("getAffinityScore() - fields: " + fieldsMap.toString())
Measurement measurement = new Measurement(tagsMap, fieldsMap);
list.add(measurement);
return list
}
@CompileDynamic
List<Measurement> getMemoryMetrics() {
List<Measurement> list = new ArrayList<>()
//Map<String, Map> map = new HashMap<String, Map>()
HashMap<String, String> tagsMap = [
system: system.name,
partition: name,
]
//map.put("tags", tagsMap)
log.debug("getMemoryMetrics() - tags: " + tagsMap.toString())
HashMap<String, Number> fieldsMap = [
logicalMem: metrics.systemUtil?.utilSamples?.first()?.lparsUtil?.first()?.memory?.logicalMem?.first(),
backedPhysicalMem: metrics.systemUtil?.utilSamples?.first()?.lparsUtil?.first()?.memory?.backedPhysicalMem?.first(),
] as HashMap<String, Number>
//map.put("fields", fieldsMap)
log.debug("getMemoryMetrics() - fields: " + fieldsMap.toString())
Measurement measurement = new Measurement(tagsMap, fieldsMap);
list.add(measurement);
return list
}
@CompileDynamic
List<Measurement> getProcessorMetrics() {
List<Measurement> list = new ArrayList<>()
//Map<String, Map> map = new HashMap<String, Map>()
HashMap<String, String> tagsMap = [
system: system.name,
partition: name,
]
//map.put("tags", tagsMap)
log.debug("getProcessorMetrics() - tags: " + tagsMap.toString())
HashMap<String, Number> fieldsMap = [
utilizedProcUnits: metrics.systemUtil?.utilSamples?.first()?.lparsUtil?.first()?.processor?.utilizedProcUnits?.first(),
maxVirtualProcessors: metrics.systemUtil.utilSamples.first().lparsUtil.first().processor.maxVirtualProcessors.first(),
currentVirtualProcessors: metrics.systemUtil.utilSamples.first().lparsUtil.first().processor.currentVirtualProcessors.first(),
//donatedProcUnits: metrics.systemUtil.utilSamples.first().lparsUtil.first().processor.donatedProcUnits.first(),
entitledProcUnits: metrics.systemUtil.utilSamples.first().lparsUtil.first().processor.entitledProcUnits.first(),
//idleProcUnits: metrics.systemUtil.utilSamples.first().lparsUtil.first().processor.idleProcUnits.first(),
//maxProcUnits: metrics.systemUtil.utilSamples.first().lparsUtil.first().processor.maxProcUnits.first(),
utilizedCappedProcUnits: metrics.systemUtil?.utilSamples?.first()?.lparsUtil?.first()?.processor?.utilizedCappedProcUnits?.first(),
utilizedUncappedProcUnits: metrics.systemUtil?.utilSamples?.first()?.lparsUtil?.first()?.processor?.utilizedUncappedProcUnits?.first(),
timePerInstructionExecution: metrics.systemUtil?.utilSamples?.first()?.lparsUtil?.first()?.processor?.timeSpentWaitingForDispatch?.first(),
timeSpentWaitingForDispatch: metrics.systemUtil?.utilSamples?.first()?.lparsUtil?.first()?.processor?.timePerInstructionExecution?.first(),
] as HashMap<String, Number>
//map.put("fields", fieldsMap)
log.debug("getProcessorMetrics() - fields: " + fieldsMap.toString())
Measurement measurement = new Measurement(tagsMap, fieldsMap);
list.add(measurement);
return list
}
@CompileDynamic
List<Measurement> getVirtualEthernetAdapterMetrics() {
List<Measurement> list = new ArrayList<>()
metrics.systemUtil?.utilSamples?.first()?.lparsUtil?.first()?.network?.virtualEthernetAdapters?.each {
//Map<String, Map> map = new HashMap<String, Map>()
HashMap<String, String> tagsMap = [
system: system.name,
partition: name,
sea: it.sharedEthernetAdapterId as String,
viosId: it.viosId as String,
vlanId: it.vlanId as String,
vswitchId: it.vswitchId as String,
]
//map.put("tags", tagsMap)
log.debug("getVirtualEthernetAdapterMetrics() - tags: " + tagsMap.toString())
HashMap<String, Number> fieldsMap = [
receivedPhysicalBytes: it.receivedPhysicalBytes.first(),
sentPhysicalBytes: it.sentPhysicalBytes.first(),
receivedBytes: it.receivedBytes.first(),
sentBytes: it.sentBytes.first(),
] as HashMap<String, Number>
//map.put("fields", fieldsMap)
log.debug("getVirtualEthernetAdapterMetrics() - fields: " + fieldsMap.toString())
Measurement measurement = new Measurement(tagsMap, fieldsMap);
list.add(measurement);
}
return list
}
//PartitionVirtualFiberChannelAdapters
@CompileDynamic
List<Measurement> getVirtualFiberChannelAdaptersMetrics() {
List<Measurement> list = new ArrayList<>()
metrics.systemUtil?.utilSamples?.first()?.lparsUtil?.first()?.storage?.virtualFiberChannelAdapters?.each {
//Map<String, Map> map = new HashMap<String, Map>()
HashMap<String, String> tagsMap = [
system: system.name,
partition: name,
viosId: it.viosId as String,
wwpn: it.wwpn,
]
//map.put("tags", tagsMap)
log.debug("getVirtualFiberChannelAdaptersMetrics() - tags: " + tagsMap.toString())
HashMap<String, Number> fieldsMap = [
transmittedBytes: it.transmittedBytes.first(),
writeBytes: it.writeBytes.first(),
readBytes: it.readBytes.first(),
] as HashMap<String, Number>
//map.put("fields", fieldsMap)
log.debug("getVirtualFiberChannelAdaptersMetrics() - fields: " + fieldsMap.toString())
Measurement measurement = new Measurement(tagsMap, fieldsMap);
list.add(measurement);
}
return list
}
}

View file

@ -1,279 +0,0 @@
/**
* Copyright 2020 Mark Nellemann <mark.nellemann@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package biz.nellemann.hmci
import groovy.transform.CompileDynamic
import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
@Slf4j
@CompileStatic
class ManagedSystem extends MetaSystem {
public final String hmcId
public final String id
public final String name
public final String type
public final String model
public final String serialNumber
ManagedSystem(String hmcId, String id, String name, String type, String model, String serialNumber) {
this.hmcId = hmcId
this.id = id
this.name = name
this.type = type
this.model = model
this.serialNumber = serialNumber
}
String toString() {
return "[${id}] ${name} (${type}-${model} ${serialNumber})"
}
@CompileDynamic
List<Measurement> getMemoryMetrics() {
List<Measurement> list = new ArrayList<>()
//Map<String, Map> map = new HashMap<String, Map>()
HashMap<String, String> tagsMap = [
system: name,
]
//map.put("tags", tagsMap)
log.debug("getMemoryMetrics() - tags: " + tagsMap.toString())
Map<String, Number> fieldsMap = [
"totalMem": metrics.systemUtil?.utilSamples?.first()?.serverUtil?.memory?.totalMem?.first(),
"availableMem": metrics.systemUtil?.utilSamples?.first()?.serverUtil?.memory?.availableMem?.first(),
"configurableMem": metrics.systemUtil?.utilSamples?.first()?.serverUtil?.memory?.configurableMem?.first(),
"assignedMemToLpars": metrics.systemUtil?.utilSamples?.first()?.serverUtil?.memory?.assignedMemToLpars?.first(),
] as HashMap<String, Number>
//map.put("fields", fieldsMap)
log.debug("getMemoryMetrics() - fields: " + fieldsMap.toString())
Measurement measurement = new Measurement(tagsMap, fieldsMap);
list.add(measurement)
return list
}
@CompileDynamic
List<Measurement> getProcessorMetrics() {
List<Measurement> list = new ArrayList<>()
//Map<String, Map> map = new HashMap<>()
HashMap<String, String> tagsMap = [
system: name,
]
//map.put("tags", tagsMap)
//measurement.tags = tagsMap;
log.debug("getProcessorMetrics() - tags: " + tagsMap.toString())
HashMap<String, Number> fieldsMap = [
availableProcUnits: metrics.systemUtil?.utilSamples?.first()?.serverUtil?.processor?.totalProcUnits?.first(),
utilizedProcUnits: metrics.systemUtil?.utilSamples?.first()?.serverUtil?.processor?.utilizedProcUnits?.first(),
availableProcUnits: metrics.systemUtil?.utilSamples?.first()?.serverUtil?.processor?.availableProcUnits?.first(),
configurableProcUnits: metrics.systemUtil?.utilSamples?.first()?.serverUtil?.processor?.configurableProcUnits?.first(),
] as HashMap<String, Number>
//map.put("fields", fieldsMap)
//measurement.fields = fieldsMap;
log.debug("getProcessorMetrics() - fields: " + fieldsMap.toString())
Measurement measurement = new Measurement(tagsMap, fieldsMap);
list.add(measurement)
return list
}
@CompileDynamic
List<Measurement> getSharedProcessorPools() {
List<Measurement> list = new ArrayList<>()
metrics.systemUtil?.utilSamples?.first()?.serverUtil?.sharedProcessorPool?.each {
//Map<String, Map> map = new HashMap<String, Map>()
HashMap<String, String> tagsMap = [
system: name,
pool: it.name,
]
//map.put("tags", tagsMap)
log.debug("getSharedProcessorPools() - tags: " + tagsMap.toString())
HashMap<String, Number> fieldsMap = [
assignedProcUnits: it.assignedProcUnits.first(),
availableProcUnits: it.availableProcUnits.first(),
] as HashMap<String, Number>
//map.put("fields", fieldsMap)
log.debug("getSharedProcessorPools() - fields: " + fieldsMap.toString())
Measurement measurement = new Measurement(tagsMap, fieldsMap);
list.add(measurement)
}
return list
}
@CompileDynamic
List<Measurement> getSystemSharedAdapters() {
List<Measurement> list = new ArrayList<>()
metrics.systemUtil?.utilSamples?.first()?.viosUtil?.each {vios ->
vios.network.sharedAdapters.each {
//Map<String, Map> map = new HashMap<String, Map>()
Measurement measurement = new Measurement();
HashMap<String, String> tagsMap = [
system: name,
type: it.type,
vios: vios.name,
]
//map.put("tags", tagsMap)
measurement.tags = tagsMap;
log.debug("getSystemSharedAdapters() - tags: " + tagsMap.toString())
HashMap<String, Number> fieldsMap = [
sentBytes: it.sentBytes.first(),
receivedBytes: it.receivedBytes.first(),
transferredBytes: it.transferredBytes.first(),
] as HashMap<String, Number>
//map.put("fields", fieldsMap)
measurement.fields = fieldsMap;
log.debug("getSystemSharedAdapters() - fields: " + fieldsMap.toString())
list.add(measurement)
}
}
return list
}
@CompileDynamic
List<Measurement> getSystemFiberChannelAdapters() {
List<Measurement> list = new ArrayList<>()
metrics.systemUtil?.utilSamples?.first()?.viosUtil?.each { vios ->
log.debug("getSystemFiberChannelAdapters() - VIOS: " + vios.name)
vios.storage?.fiberChannelAdapters?.each {
//HashMap<String, Map> map = new HashMap<>()
Measurement measurement = new Measurement();
HashMap<String, String> tagsMap = [
id: it.id,
system: name,
wwpn: it.wwpn,
vios: vios.name,
device: it.physicalLocation,
]
//map.put("tags", tagsMap)
measurement.tags = tagsMap;
log.debug("getSystemFiberChannelAdapters() - tags: " + tagsMap.toString())
HashMap<String, Number> fieldsMap = [
writeBytes: it.writeBytes.first(),
readBytes: it.readBytes.first(),
transmittedBytes: it.transmittedBytes.first(),
] as HashMap<String, Number>
//map.put("fields", fieldsMap)
measurement.fields = fieldsMap;
log.debug("getSystemFiberChannelAdapters() - fields: " + fieldsMap.toString())
list.add(measurement)
}
}
return list
}
@CompileDynamic
List<Measurement> getSystemGenericPhysicalAdapters() {
List<Measurement> list = new ArrayList<>()
metrics.systemUtil?.utilSamples?.first()?.viosUtil?.each { vios ->
vios.storage?.genericPhysicalAdapters?.each {
//Map<String, Map> map = new HashMap<String, Map>()
Measurement measurement = new Measurement();
HashMap<String, String> tagsMap = [
id: it.id,
system: name,
vios: vios.name,
device: it.physicalLocation,
]
//map.put("tags", tagsMap)
measurement.tags = tagsMap;
log.debug("getSystemGenericPhysicalAdapters() - tags: " + tagsMap.toString())
HashMap<String, Number> fieldsMap = [
writeBytes: it.writeBytes.first(),
readBytes: it.readBytes.first(),
transmittedBytes: it.transmittedBytes.first(),
] as HashMap<String, Number>
//map.put("fields", fieldsMap)
measurement.fields = fieldsMap;
log.debug("getSystemGenericPhysicalAdapters() - fields: " + fieldsMap.toString())
list.add(measurement)
}
}
return list
}
@CompileDynamic
List<Measurement> getSystemGenericVirtualAdapters() {
List<Measurement> list = new ArrayList<>()
metrics.systemUtil?.utilSamples?.first()?.viosUtil?.each { vios ->
vios.storage?.genericVirtualAdapters?.each {
//Map<String, Map> map = new HashMap<String, Map>()
Measurement measurement = new Measurement();
HashMap<String, String> tagsMap = [
id: it.id,
system: name,
vios: vios.name,
device: it.physicalLocation,
]
//map.put("tags", tagsMap)
measurement.tags = tagsMap;
log.debug("getSystemGenericVirtualAdapters() - tags: " + tagsMap.toString())
HashMap<String, Number> fieldsMap = [
writeBytes: it.writeBytes.first(),
readBytes: it.readBytes.first(),
transmittedBytes: it.transmittedBytes.first(),
] as HashMap<String, Number>
//map.put("fields", fieldsMap)
measurement.fields = fieldsMap;
log.debug("getSystemGenericVirtualAdapters() - fields: " + fieldsMap.toString())
list.add(measurement);
}
}
return list
}
}

View file

@ -139,7 +139,7 @@ public class Configuration {
String url; String url;
String username; String username;
String password; String password;
Boolean unsafe; Boolean unsafe = false;
private boolean isValid = false; private boolean isValid = false;

View file

@ -13,88 +13,97 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package biz.nellemann.hmci package biz.nellemann.hmci;
import biz.nellemann.hmci.Configuration.HmcObject import biz.nellemann.hmci.Configuration.HmcObject;
import com.squareup.moshi.Moshi import okhttp3.*;
import groovy.transform.CompileDynamic import org.jsoup.Jsoup;
import groovy.transform.CompileStatic import org.jsoup.nodes.Document;
import groovy.util.logging.Slf4j import org.jsoup.nodes.Element;
import groovy.xml.XmlSlurper import org.jsoup.select.Elements;
import okhttp3.* import org.slf4j.Logger;
import org.jsoup.Jsoup import org.slf4j.LoggerFactory;
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import org.jsoup.select.Elements
import javax.net.ssl.* import javax.net.ssl.*;
import java.security.SecureRandom import java.io.IOException;
import java.security.cert.CertificateException import java.net.URL;
import java.security.cert.X509Certificate import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@Slf4j
@CompileStatic
class HmcClient { class HmcClient {
private final static Logger log = LoggerFactory.getLogger(HmcClient.class);
private final MediaType MEDIA_TYPE_IBM_XML_LOGIN = MediaType.parse("application/vnd.ibm.powervm.web+xml; type=LogonRequest"); private final MediaType MEDIA_TYPE_IBM_XML_LOGIN = MediaType.parse("application/vnd.ibm.powervm.web+xml; type=LogonRequest");
private final String hmcId private final String hmcId;
private final String baseUrl private final String baseUrl;
private final String username private final String username;
private final String password private final String password;
private final Boolean unsafe private final Boolean unsafe;
protected Integer responseErrors = 0 protected Integer responseErrors = 0;
protected String authToken protected String authToken;
private final OkHttpClient client private final OkHttpClient client;
HmcClient(HmcObject configHmc) { HmcClient(HmcObject configHmc) {
this.hmcId = configHmc.name this.hmcId = configHmc.name;
this.baseUrl = configHmc.url this.baseUrl = configHmc.url;
this.username = configHmc.username this.username = configHmc.username;
this.password = configHmc.password this.password = configHmc.password;
this.unsafe = configHmc.unsafe this.unsafe = configHmc.unsafe;
if(unsafe) { if(unsafe) {
this.client = getUnsafeOkHttpClient() this.client = getUnsafeOkHttpClient();
} else { } else {
this.client = new OkHttpClient() this.client = new OkHttpClient();
} }
} }
/**
* Logon to the HMC and get an authentication token for further requests.
* @throws Exception
*/
void login() throws Exception {
this.login(false);
}
/** /**
* Logon to the HMC and get an authentication token for further requests. * Logon to the HMC and get an authentication token for further requests.
* * @param force
* @throws IOException * @throws Exception
*/ */
//@CompileDynamic void login(Boolean force) throws Exception {
void login(Boolean force = false) throws IOException {
if(authToken && !force) { if(authToken != null && !force) {
return return;
} }
log.info("Connecting to HMC - " + baseUrl); log.info("Connecting to HMC - " + baseUrl);
String payload = """\ StringBuilder payload = new StringBuilder();
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> payload.append("<?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_0"> payload.append("<LogonRequest xmlns='http://www.ibm.com/xmlns/systems/power/firmware/web/mc/2012_10/' schemaVersion='V1_0'>");
<UserID>${username}</UserID> payload.append("<UserID>").append(username).append("</UserID>");
<Password>${password}</Password> payload.append("<Password>").append(password).append("</Password>");
</LogonRequest>""" payload.append("</LogonRequest>");
URL url = new URL(String.format("%s/rest/api/web/Logon", baseUrl)) URL url = new URL(String.format("%s/rest/api/web/Logon", baseUrl));
Request request = new Request.Builder() Request request = new Request.Builder()
.url(url) .url(url)
//.addHeader("Content-Type", "application/vnd.ibm.powervm.web+xml; type=LogonRequest") //.addHeader("Content-Type", "application/vnd.ibm.powervm.web+xml; type=LogonRequest")
.addHeader("Accept", "application/vnd.ibm.powervm.web+xml; type=LogonResponse") .addHeader("Accept", "application/vnd.ibm.powervm.web+xml; type=LogonResponse")
.addHeader("X-Audit-Memento", "hmci") .addHeader("X-Audit-Memento", "hmci")
.put(RequestBody.create(payload, MEDIA_TYPE_IBM_XML_LOGIN)) .put(RequestBody.create(payload.toString(), MEDIA_TYPE_IBM_XML_LOGIN))
.build(); .build();
try { try {
@ -103,15 +112,15 @@ class HmcClient {
// Get response body and parse // Get response body and parse
String responseBody = response.body().string(); String responseBody = response.body().string();
response.body().close() response.body().close();
def xml = new XmlSlurper().parseText(responseBody) Document doc = Jsoup.parse(responseBody);
authToken = xml.toString() authToken = doc.select("X-API-Session").text();
log.debug("login() - Auth Token: " + authToken) log.debug("login() - Auth Token: " + authToken);
} catch(Exception e) { } catch(Exception e) {
log.error(e.message) log.error(e.getMessage());
throw new Exception(e) throw new Exception(e);
} }
} }
@ -122,13 +131,13 @@ class HmcClient {
* Logoff from the HMC and remove any session * Logoff from the HMC and remove any session
* *
*/ */
void logoff() { void logoff() throws IOException {
if(!authToken) { if(authToken == null) {
return return;
} }
URL absUrl = new URL(String.format("%s/rest/api/web/Logon", baseUrl)) URL absUrl = new URL(String.format("%s/rest/api/web/Logon", baseUrl));
Request request = new Request.Builder() Request request = new Request.Builder()
.url(absUrl) .url(absUrl)
.addHeader("Content-Type", "application/vnd.ibm.powervm.web+xml; type=LogonRequest") .addHeader("Content-Type", "application/vnd.ibm.powervm.web+xml; type=LogonRequest")
@ -139,8 +148,8 @@ class HmcClient {
Response response = client.newCall(request).execute(); Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
authToken = null authToken = null;
log.debug("logoff()") log.debug("logoff()");
} }
@ -150,143 +159,158 @@ class HmcClient {
* *
* @return * @return
*/ */
//@CompileDynamic Map<String, ManagedSystem> getManagedSystems() throws Exception {
Map<String, ManagedSystem> getManagedSystems() {
URL url = new URL(String.format("%s/rest/api/uom/ManagedSystem", baseUrl)) URL url = new URL(String.format("%s/rest/api/uom/ManagedSystem", baseUrl));
Response response = getResponse(url) Response response = getResponse(url);
String responseBody = response.body().string() String responseBody = Objects.requireNonNull(response.body()).string();
Map<String,ManagedSystem> managedSystemsMap = new HashMap<String, ManagedSystem>() Map<String,ManagedSystem> managedSystemsMap = new HashMap<String, ManagedSystem>();
// Do not try to parse empty response // Do not try to parse empty response
if(responseBody.empty || responseBody.size() < 1) { if(responseBody.isEmpty() || responseBody.length() <= 1) {
responseErrors++ responseErrors++;
return managedSystemsMap return managedSystemsMap;
} }
try { try {
Document doc = Jsoup.parse(responseBody); Document doc = Jsoup.parse(responseBody);
Elements managedSystems = doc.select("ManagedSystem|ManagedSystem") // doc.select("img[src$=.png]"); Elements managedSystems = doc.select("ManagedSystem|ManagedSystem"); // doc.select("img[src$=.png]");
for(Element el : managedSystems) { for(Element el : managedSystems) {
ManagedSystem system = new ManagedSystem( ManagedSystem system = new ManagedSystem(
hmcId, hmcId,
el.select("Metadata > Atom > AtomID").text() as String, el.select("Metadata > Atom > AtomID").text(),
el.select("SystemName").text() as String, el.select("SystemName").text(),
el.select("MachineTypeModelAndSerialNumber > MachineType").text() as String, el.select("MachineTypeModelAndSerialNumber > MachineType").text(),
el.select("MachineTypeModelAndSerialNumber > Model").text() as String, el.select("MachineTypeModelAndSerialNumber > Model").text(),
el.select("MachineTypeModelAndSerialNumber > SerialNumber").text() as String, el.select("MachineTypeModelAndSerialNumber > SerialNumber").text()
) );
managedSystemsMap.put(system.id, system) managedSystemsMap.put(system.id, system);
log.info("getManagedSystems() - Found system: " + system.toString()) log.info("getManagedSystems() - Found system: " + system.toString());
} }
} catch(Exception e) { } catch(Exception e) {
log.warn("getManagedSystems() - xml parse error", e); log.warn("getManagedSystems() - xml parse error", e);
} }
return managedSystemsMap return managedSystemsMap;
} }
/** /**
* Return Map of LogicalPartitions seen by a ManagedSystem on this HMC * Return Map of LogicalPartitions seen by a ManagedSystem on this HMC
* @param system
* @param UUID of managed system
* @return * @return
*/ */
//@CompileDynamic Map<String, LogicalPartition> getLogicalPartitionsForManagedSystem(ManagedSystem system) throws Exception {
Map<String, LogicalPartition> getLogicalPartitionsForManagedSystem(ManagedSystem system) { 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)) Response response = getResponse(url);
Response response = getResponse(url) String responseBody = Objects.requireNonNull(response.body()).string();
String responseBody = response.body().string() Map<String, LogicalPartition> partitionMap = new HashMap<String, LogicalPartition>() {};
Map<String, LogicalPartition> partitionMap = new HashMap<String, LogicalPartition>() {}
// Do not try to parse empty response // Do not try to parse empty response
if(responseBody.empty || responseBody.size() < 1) { if(responseBody.isEmpty() || responseBody.length() <= 1) {
responseErrors++ responseErrors++;
return partitionMap return partitionMap;
} }
try { try {
Document doc = Jsoup.parse(responseBody); Document doc = Jsoup.parse(responseBody);
Elements logicalPartitions = doc.select("LogicalPartition|LogicalPartition") // doc.select("img[src$=.png]"); Elements logicalPartitions = doc.select("LogicalPartition|LogicalPartition"); // doc.select("img[src$=.png]");
for(Element el : logicalPartitions) { for(Element el : logicalPartitions) {
LogicalPartition logicalPartition = new LogicalPartition( LogicalPartition logicalPartition = new LogicalPartition(
el.select("PartitionUUID").text() as String, el.select("PartitionUUID").text(),
el.select("PartitionName").text() as String, el.select("PartitionName").text(),
el.select("PartitionType").text() as String, el.select("PartitionType").text(),
system system
) );
partitionMap.put(logicalPartition.id, logicalPartition) partitionMap.put(logicalPartition.id, logicalPartition);
log.info("getLogicalPartitionsForManagedSystem() - Found partition: " + logicalPartition.toString()) log.info("getLogicalPartitionsForManagedSystem() - Found partition: " + logicalPartition.toString());
} }
} catch(Exception e) { } catch(Exception e) {
log.warn("getLogicalPartitionsForManagedSystem() - xml parse error", e); log.warn("getLogicalPartitionsForManagedSystem() - xml parse error", e);
} }
return partitionMap return partitionMap;
} }
/** /**
* Parse XML feed to get PCM Data in JSON format * Parse XML feed to get PCM Data in JSON format
* @param systemId * @param system
* @return * @return
*/ */
//@CompileDynamic String getPcmDataForManagedSystem(ManagedSystem system) throws Exception {
String getPcmDataForManagedSystem(ManagedSystem system) {
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));
Response response = getResponse(url) Response response = getResponse(url);
String responseBody = response.body().string() String responseBody = Objects.requireNonNull(response.body()).string();
String jsonBody String jsonBody = null;
// Do not try to parse empty response // Do not try to parse empty response
if(responseBody.empty || responseBody.size() < 1) { if(responseBody.isEmpty() || responseBody.length() <= 1) {
responseErrors++ responseErrors++;
return jsonBody log.warn("getPcmDataForManagedSystem() - empty response");
return jsonBody;
} }
try { try {
Document doc = Jsoup.parse(responseBody); Document doc = Jsoup.parse(responseBody);
Element entry = doc.select("entry").first(); Element entry = doc.select("feed > entry").first();
Element link = entry.select("link[href]").first(); Element link = entry.select("link[href]").first();
if(link.attr("type") == "application/json") {
String href = (String) link.attr("href"); if(link.attr("type").equals("application/json")) {
String href = link.attr("href");
log.debug("getPcmDataForManagedSystem() - json url: " + href); log.debug("getPcmDataForManagedSystem() - json url: " + href);
jsonBody = getResponseBody(new URL(href)); jsonBody = getResponseBody(new URL(href));
} }
} catch(Exception e) { } catch(Exception e) {
log.warn("getPcmDataForManagedSystem() - xml parse error", e); log.warn("getPcmDataForManagedSystem() - xml parse error", e);
} }
return jsonBody return jsonBody;
} }
/** /**
* Parse XML feed to get PCM Data in JSON format * Parse XML feed to get PCM Data in JSON format
* @param systemId * @param partition
* @param partitionId
* @return * @return
*/ */
//@CompileDynamic String getPcmDataForLogicalPartition(LogicalPartition partition) throws Exception {
String getPcmDataForLogicalPartition(LogicalPartition partition) {
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));
Response response = getResponse(url) Response response = getResponse(url);
String responseBody = response.body().string() String responseBody = Objects.requireNonNull(response.body()).string();
String jsonBody String jsonBody = null;
// Do not try to parse empty response // Do not try to parse empty response
if(responseBody.empty || responseBody.size() < 1) { if(responseBody.isEmpty() || responseBody.length() <= 1) {
responseErrors++ responseErrors++;
return jsonBody log.warn("getPcmDataForLogicalPartition() - empty response");
return jsonBody;
} }
try {
Document doc = Jsoup.parse(responseBody);
Element entry = doc.select("feed > entry").first();
Element link = entry.select("link[href]").first();
if(link.attr("type").equals("application/json")) {
String href = link.attr("href");
log.debug("getPcmDataForLogicalPartition() - json url: " + href);
jsonBody = getResponseBody(new URL(href));
}
} catch(Exception e) {
log.warn("getPcmDataForLogicalPartition() - xml parse error", e);
}
/*
try { try {
Document doc = Jsoup.parse(responseBody); Document doc = Jsoup.parse(responseBody);
Element entry = doc.select("entry").first(); Element entry = doc.select("entry").first();
@ -298,9 +322,9 @@ class HmcClient {
} }
} catch(Exception e) { } catch(Exception e) {
log.warn("getPcmDataForLogicalPartition() - xml parse error", e); log.warn("getPcmDataForLogicalPartition() - xml parse error", e);
} }*/
return jsonBody return jsonBody;
} }
@ -310,28 +334,38 @@ class HmcClient {
* @param url * @param url
* @return * @return
*/ */
protected String getResponseBody(URL url) { protected String getResponseBody(URL url) throws Exception {
Response response = getResponse(url) Response response = getResponse(url);
String body = response.body().string() String body = Objects.requireNonNull(response.body()).string();
response.body().close() Objects.requireNonNull(response.body()).close();
return body return body;
} }
/** /**
* Return a Response from the HMC * Return a Response from the HMC
*
* @param url * @param url
* @return * @return
*/ */
//@CompileDynamic private Response getResponse(URL url) throws Exception {
private Response getResponse(URL url, Integer retry = 0) { return getResponse(url, 0);
}
/**
* Return a Response from the HMC
* @param url
* @param retry
* @return
*/
private Response getResponse(URL url, Integer retry) throws Exception {
log.debug("getResponse() - " + url.toString());
if(responseErrors > 2) { if(responseErrors > 2) {
responseErrors = 0 responseErrors = 0;
login(true) login(true);
return getResponse(url, retry++) return getResponse(url, retry++);
} }
Request request = new Request.Builder() Request request = new Request.Builder()
@ -343,23 +377,23 @@ class HmcClient {
Response response = client.newCall(request).execute(); Response response = client.newCall(request).execute();
if (!response.isSuccessful()) { if (!response.isSuccessful()) {
response.body().close() response.body().close();
if(response.code() == 401) { if(response.code() == 401) {
login(true) login(true);
return getResponse(url, retry++) return getResponse(url, retry++);
} }
if(retry < 2) { if(retry < 2) {
log.warn("getResponse() - Retrying due to unexpected response: " + response.code()) log.warn("getResponse() - Retrying due to unexpected response: " + response.code());
return getResponse(url, retry++) return getResponse(url, retry++);
} }
log.error("getResponse() - Unexpected response: " + response.code()) log.error("getResponse() - Unexpected response: " + response.code());
throw new IOException("getResponse() - Unexpected response: " + response.code()) throw new IOException("getResponse() - Unexpected response: " + response.code());
}; };
return response return response;
} }

View file

@ -15,8 +15,7 @@
*/ */
package biz.nellemann.hmci; package biz.nellemann.hmci;
import biz.nellemann.hmci.Configuration.InfluxObject import biz.nellemann.hmci.Configuration.InfluxObject;
import groovy.transform.CompileStatic;
import org.influxdb.BatchOptions; import org.influxdb.BatchOptions;
import org.influxdb.InfluxDB; import org.influxdb.InfluxDB;
import org.influxdb.InfluxDBFactory; import org.influxdb.InfluxDBFactory;
@ -26,10 +25,11 @@ import org.influxdb.dto.Query;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.time.Instant import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@CompileStatic
class InfluxClient { class InfluxClient {
private final static Logger log = LoggerFactory.getLogger(InfluxClient.class); private final static Logger log = LoggerFactory.getLogger(InfluxClient.class);
@ -54,7 +54,7 @@ class InfluxClient {
void login() throws Exception { void login() throws Exception {
if(influxDB != null) { if(influxDB != null) {
return return;
} }
try { try {
@ -91,7 +91,7 @@ class InfluxClient {
} }
void writeBatchPoints() { void writeBatchPoints() throws Exception {
log.debug("writeBatchPoints()"); log.debug("writeBatchPoints()");
try { try {
influxDB.write(batchPoints); influxDB.write(batchPoints);
@ -271,7 +271,7 @@ class InfluxClient {
// Iterate fields // Iterate fields
//Map<String, BigDecimal> fieldsMap = m.get("fields"); //Map<String, BigDecimal> fieldsMap = m.get("fields");
m.fields.forEach((fieldName, fieldValue) -> { m.fields.forEach((fieldName, fieldValue) -> {
log.debug("processMeasurementMap() " + measurement + " - fieldName: " + fieldName + ", fieldValue: " + fieldValue) log.debug("processMeasurementMap() " + measurement + " - fieldName: " + fieldName + ", fieldValue: " + fieldValue);
Point.Builder builder = Point.measurement(measurement) Point.Builder builder = Point.measurement(measurement)
.time(timestamp.toEpochMilli(), TimeUnit.MILLISECONDS) .time(timestamp.toEpochMilli(), TimeUnit.MILLISECONDS)

View file

@ -0,0 +1,189 @@
/**
* Copyright 2020 Mark Nellemann <mark.nellemann@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package biz.nellemann.hmci;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
class Insights {
private final static Logger log = LoggerFactory.getLogger(Insights.class);
final Configuration configuration;
InfluxClient influxClient;
Map<String, HmcClient> hmcClients = new HashMap<>();
Map<String,ManagedSystem> systems = new HashMap<String, ManagedSystem>();
Map<String, LogicalPartition> partitions = new HashMap<String, LogicalPartition>();
Insights(Configuration configuration) {
this.configuration = configuration;
try {
influxClient = new InfluxClient(configuration.influx);
influxClient.login();
} catch(Exception e) {
System.exit(1);
}
// Initial scan
discover();
}
void discover() {
configuration.hmc.forEach( configHmc -> {
if(hmcClients != null && !hmcClients.containsKey(configHmc.name)) {
log.debug("Adding HMC: " + configHmc.toString());
HmcClient hmcClient = new HmcClient(configHmc);
hmcClients.put(configHmc.name, hmcClient);
}
});
hmcClients.forEach(( hmcId, hmcClient) -> {
try {
hmcClient.login();
hmcClient.getManagedSystems().forEach((systemId, system) -> {
// Add to list of known systems
systems.putIfAbsent(systemId, system);
// Get LPAR's for this system
try {
hmcClient.getLogicalPartitionsForManagedSystem(system).forEach((partitionId, partition) -> {
// Add to list of known partitions
partitions.putIfAbsent(partitionId, partition);
});
} catch (Exception e) {
log.error("discover()", e);
}
});
} catch(Exception e) {
log.error("discover() - " + hmcId + " error: " + e.getMessage());
//hmcClients.remove(hmcId);
}
});
}
void getMetricsForSystems() {
systems.forEach((systemId, system) -> {
HmcClient hmcClient = hmcClients.get(system.hmcId);
// Get and process metrics for this system
String tmpJsonString = null;
try {
tmpJsonString = hmcClient.getPcmDataForManagedSystem(system);
} catch (Exception e) {
log.error("getMetricsForSystems()", e);
//e.printStackTrace();
}
if(tmpJsonString != null && !tmpJsonString.isEmpty()) {
system.processMetrics(tmpJsonString);
}
});
}
void getMetricsForPartitions() {
try {
// Get LPAR's for this system
partitions.forEach((partitionId, partition) -> {
HmcClient hmcClient = hmcClients.get(partition.system.hmcId);
// Get and process metrics for this partition
String tmpJsonString2 = null;
try {
tmpJsonString2 = hmcClient.getPcmDataForLogicalPartition(partition);
} catch (Exception e) {
log.error("getMetricsForPartitions()", e);
}
if(tmpJsonString2 != null && !tmpJsonString2.isEmpty()) {
partition.processMetrics(tmpJsonString2);
}
});
} catch(Exception e) {
log.error("getMetricsForPartitions()", e);
}
}
void writeMetricsForManagedSystems() {
systems.forEach((systemId, system) -> {
influxClient.writeManagedSystem(system);
});
}
void writeMetricsForLogicalPartitions() {
partitions.forEach((partitionId, partition) -> {
influxClient.writeLogicalPartition(partition);
});
}
void run() throws InterruptedException {
log.debug("run()");
int executions = 0;
while(true) {
try {
getMetricsForSystems();
getMetricsForPartitions();
writeMetricsForManagedSystems();
writeMetricsForLogicalPartitions();
influxClient.writeBatchPoints();
// Refresh HMC's
if(executions > configuration.rescan) {
executions = 0;
discover();
}
} catch(Exception e) {
log.error("run()", e.getMessage());
}
executions++;
Thread.sleep(configuration.refresh * 1000);
}
}
}

View file

@ -0,0 +1,225 @@
/**
* Copyright 2020 Mark Nellemann <mark.nellemann@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package biz.nellemann.hmci;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
class LogicalPartition extends MetaSystem {
private final static Logger log = LoggerFactory.getLogger(LogicalPartition.class);
public String id;
public String name;
public String type;
public ManagedSystem system;
LogicalPartition(String id, String name, String type, ManagedSystem system) {
this.id = id;
this.name = name;
this.type = type;
this.system = system;
}
public String toString() {
return String.format("[%s] %s (%s)", id, name, type);
}
List<Measurement> getAffinityScore() {
List<Measurement> list = new ArrayList<>();
//Map<String, Map> map = new HashMap<String, Map>()
Map<String, String> tagsMap = new HashMap<String, String>() {
{
put("system", system.name);
put("partition", name);
}
};
//map.put("tags", tagsMap)
log.debug("getAffinityScore() - tags: " + tagsMap.toString());
Map<String, Number> fieldsMap = new HashMap<String, Number>() {
{
put("affinityScore", metrics.systemUtil.sample.lparsUtil.affinityScore);
}
};
//map.put("fields", fieldsMap)
log.debug("getAffinityScore() - fields: " + fieldsMap.toString());
Measurement measurement = new Measurement(tagsMap, fieldsMap);
list.add(measurement);
return list;
}
List<Measurement> getMemoryMetrics() {
List<Measurement> list = new ArrayList<>();
//Map<String, Map> map = new HashMap<String, Map>()
Map<String, String> tagsMap = new HashMap<String, String>() {
{
put("system", system.name);
put("partition", name);
}
};
//map.put("tags", tagsMap)
log.debug("getMemoryMetrics() - tags: " + tagsMap.toString());
Map<String, Number> fieldsMap = new HashMap<String, Number>() {
{
put("logicalMem", metrics.systemUtil.sample.lparsUtil.memory.logicalMem);
put("backedPhysicalMem", metrics.systemUtil.sample.lparsUtil.memory.backedPhysicalMem);
}
};
//map.put("fields", fieldsMap)
log.debug("getMemoryMetrics() - fields: " + fieldsMap.toString());
Measurement measurement = new Measurement(tagsMap, fieldsMap);
list.add(measurement);
return list;
}
//@CompileDynamic
List<Measurement> getProcessorMetrics() {
List<Measurement> list = new ArrayList<>();
//Map<String, Map> map = new HashMap<String, Map>()
HashMap<String, String> tagsMap = new HashMap<String, String>() {
{
put("system", system.name);
put("partition", name);
}
};
//map.put("tags", tagsMap)
log.debug("getProcessorMetrics() - tags: " + tagsMap.toString());
HashMap<String, Number> fieldsMap = new HashMap<String, Number>() {
{
put("utilizedProcUnits", metrics.systemUtil.sample.lparsUtil.processor.utilizedProcUnits);
put("maxVirtualProcessors", metrics.systemUtil.sample.lparsUtil.processor.maxVirtualProcessors);
put("currentVirtualProcessors", metrics.systemUtil.sample.lparsUtil.processor.currentVirtualProcessors);
//donatedProcUnits: metrics.systemUtil.utilSamples.first().lparsUtil.first().processor.donatedProcUnits.first(),
put("entitledProcUnits", metrics.systemUtil.sample.lparsUtil.processor.entitledProcUnits);
//idleProcUnits: metrics.systemUtil.utilSamples.first().lparsUtil.first().processor.idleProcUnits.first(),
//maxProcUnits: metrics.systemUtil.utilSamples.first().lparsUtil.first().processor.maxProcUnits.first(),
put("utilizedCappedProcUnits", metrics.systemUtil.sample.lparsUtil.processor.utilizedCappedProcUnits);
put("utilizedUncappedProcUnits", metrics.systemUtil.sample.lparsUtil.processor.utilizedUncappedProcUnits);
put("timePerInstructionExecution", metrics.systemUtil.sample.lparsUtil.processor.timeSpentWaitingForDispatch);
put("timeSpentWaitingForDispatch", metrics.systemUtil.sample.lparsUtil.processor.timePerInstructionExecution);
}
};
//map.put("fields", fieldsMap)
log.debug("getProcessorMetrics() - fields: " + fieldsMap.toString());
Measurement measurement = new Measurement(tagsMap, fieldsMap);
list.add(measurement);
return list;
}
//@CompileDynamic
List<Measurement> getVirtualEthernetAdapterMetrics() {
List<Measurement> list = new ArrayList<>();
metrics.systemUtil.sample.lparsUtil.network.virtualEthernetAdapters.forEach( adapter -> {
HashMap<String, String> tagsMap = new HashMap<String, String>() {
{
put("system", system.name);
put("partition", name);
put("sea", adapter.sharedEthernetAdapterId);
put("viosId", adapter.viosId.toString());
put("vlanId", adapter.vlanId.toString());
put("vswitchId", adapter.vswitchId.toString());
}
};
log.debug("getVirtualEthernetAdapterMetrics() - tags: " + tagsMap.toString());
HashMap<String, Number> fieldsMap = new HashMap<String, Number>() {
{
put("receivedPhysicalBytes", adapter.receivedPhysicalBytes);
put("sentPhysicalBytes", adapter.sentPhysicalBytes);
put("receivedBytes", adapter.receivedBytes);
put("sentBytes", adapter.sentBytes);
}
};
log.debug("getVirtualEthernetAdapterMetrics() - fields: " + fieldsMap.toString());
Measurement measurement = new Measurement(tagsMap, fieldsMap);
list.add(measurement);
});
return list;
}
//PartitionVirtualFiberChannelAdapters
//@CompileDynamic
List<Measurement> getVirtualFiberChannelAdaptersMetrics() {
List<Measurement> list = new ArrayList<>();
metrics.systemUtil.sample.lparsUtil.storage.virtualFiberChannelAdapters.forEach( adapter -> {
//Map<String, Map> map = new HashMap<String, Map>()
HashMap<String, String> tagsMap = new HashMap<String, String>() {
{
put("system", system.name);
put("partition", name);
put("viosId", adapter.viosId.toString());
put("wwpn", adapter.wwpn);
}
};
//map.put("tags", tagsMap)
log.debug("getVirtualFiberChannelAdaptersMetrics() - tags: " + tagsMap.toString());
HashMap<String, Number> fieldsMap = new HashMap<String, Number>() {
{
put("transmittedBytes", adapter.transmittedBytes.get(0));
put("writeBytes", adapter.writeBytes.get(0));
put("readBytes", adapter.readBytes.get(0));
}
};
//map.put("fields", fieldsMap)
log.debug("getVirtualFiberChannelAdaptersMetrics() - fields: " + fieldsMap.toString());
Measurement measurement = new Measurement(tagsMap, fieldsMap);
list.add(measurement);
});
return list;
}
}

View file

@ -13,16 +13,17 @@
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package biz.nellemann.hmci package biz.nellemann.hmci;
import groovy.transform.CompileStatic;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import picocli.CommandLine; import picocli.CommandLine;
import picocli.CommandLine.Command; import picocli.CommandLine.Command;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
@CompileStatic
@Command(name = "hmci", @Command(name = "hmci",
mixinStandardHelpOptions = true, mixinStandardHelpOptions = true,
description = "HMC Insights.", description = "HMC Insights.",
@ -31,7 +32,7 @@ public class Main implements Callable<Integer> {
private final static Logger log = LoggerFactory.getLogger(Main.class); private final static Logger log = LoggerFactory.getLogger(Main.class);
@CommandLine.Option(names = ["-c", "--conf"], description = "Configuration file [default: '/etc/hmci.toml'].") @CommandLine.Option(names = { "-c", "--conf" }, description = "Configuration file [default: '/etc/hmci.toml'].")
private String configurationFile = "/etc/hmci.toml"; private String configurationFile = "/etc/hmci.toml";
public static void main(String... args) { public static void main(String... args) {
@ -51,7 +52,11 @@ public class Main implements Callable<Integer> {
Configuration configuration = new Configuration(configurationFile); Configuration configuration = new Configuration(configurationFile);
Insights insights = new Insights(configuration); Insights insights = new Insights(configuration);
insights.run(); try {
insights.run();
} catch (InterruptedException e) {
log.error(e.getMessage());
}
return 0; return 0;
} }

View file

@ -0,0 +1,326 @@
/**
* Copyright 2020 Mark Nellemann <mark.nellemann@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package biz.nellemann.hmci;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
class ManagedSystem extends MetaSystem {
private final static Logger log = LoggerFactory.getLogger(ManagedSystem.class);
public final String hmcId;
public final String id;
public final String name;
public final String type;
public final String model;
public final String serialNumber;
ManagedSystem(String hmcId, String id, String name, String type, String model, String serialNumber) {
this.hmcId = hmcId;
this.id = id;
this.name = name;
this.type = type;
this.model = model;
this.serialNumber = serialNumber;
}
public String toString() {
return String.format("[%s] %s (%s-%s %s)", id, name, type, model, serialNumber);
}
List<Measurement> getMemoryMetrics() {
List<Measurement> list = new ArrayList<>();
//Map<String, Map> map = new HashMap<String, Map>()
HashMap<String, String> tagsMap = new HashMap<String, String>() {
{
put("system", name);
}
};
//map.put("tags", tagsMap)
log.debug("getMemoryMetrics() - tags: " + tagsMap.toString());
Map<String, Number> fieldsMap = new HashMap<String, Number>() {
{
put("totalMem", metrics.systemUtil.sample.serverUtil.memory.totalMem);
put("availableMem", metrics.systemUtil.sample.serverUtil.memory.availableMem);
put("configurableMem", metrics.systemUtil.sample.serverUtil.memory.configurableMem);
put("assignedMemToLpars", metrics.systemUtil.sample.serverUtil.memory.assignedMemToLpars);
}
};
//map.put("fields", fieldsMap)
log.debug("getMemoryMetrics() - fields: " + fieldsMap.toString());
Measurement measurement = new Measurement(tagsMap, fieldsMap);
list.add(measurement);
return list;
}
List<Measurement> getProcessorMetrics() {
List<Measurement> list = new ArrayList<>();
//Map<String, Map> map = new HashMap<>()
HashMap<String, String> tagsMap = new HashMap<String, String>() {
{
put("system", name);
}
};
//map.put("tags", tagsMap)
//measurement.tags = tagsMap;
log.debug("getProcessorMetrics() - tags: " + tagsMap.toString());
HashMap<String, Number> fieldsMap = new HashMap<String, Number>() {
{
put("availableProcUnits", metrics.systemUtil.sample.serverUtil.processor.totalProcUnits);
put("utilizedProcUnits", metrics.systemUtil.sample.serverUtil.processor.utilizedProcUnits);
put("availableProcUnits", metrics.systemUtil.sample.serverUtil.processor.availableProcUnits);
put("configurableProcUnits", metrics.systemUtil.sample.serverUtil.processor.configurableProcUnits);
}
};
//map.put("fields", fieldsMap)
//measurement.fields = fieldsMap;
log.debug("getProcessorMetrics() - fields: " + fieldsMap.toString());
Measurement measurement = new Measurement(tagsMap, fieldsMap);
list.add(measurement);
return list;
}
List<Measurement> getSharedProcessorPools() {
List<Measurement> list = new ArrayList<>();
metrics.systemUtil.sample.serverUtil.sharedProcessorPool.forEach(adapter -> {
//Map<String, Map> map = new HashMap<String, Map>()
HashMap<String, String> tagsMap = new HashMap<String, String>() {
{
put("system", name);
put("pool", adapter.name);
}
};
//map.put("tags", tagsMap)
log.debug("getSharedProcessorPools() - tags: " + tagsMap.toString());
HashMap<String, Number> fieldsMap = new HashMap<String, Number>() {
{
put("assignedProcUnits", adapter.assignedProcUnits);
put("availableProcUnits", adapter.availableProcUnits);
}
};
//map.put("fields", fieldsMap)
log.debug("getSharedProcessorPools() - fields: " + fieldsMap.toString());
Measurement measurement = new Measurement(tagsMap, fieldsMap);
list.add(measurement);
});
return list;
}
List<Measurement> getSystemSharedAdapters() {
List<Measurement> list = new ArrayList<>();
metrics.systemUtil.sample.viosUtil.forEach(vios -> {
vios.network.sharedAdapters.forEach(adapter -> {
//Map<String, Map> map = new HashMap<String, Map>()
Measurement measurement = new Measurement();
HashMap<String, String> tagsMap = new HashMap<String, String>() {
{
put("system", name);
put("type", adapter.type);
put("vios", vios.name);
}
};
//map.put("tags", tagsMap)
measurement.tags = tagsMap;
log.debug("getSystemSharedAdapters() - tags: " + tagsMap.toString());
HashMap<String, Number> fieldsMap = new HashMap<String, Number>() {
{
put("sentBytes", adapter.sentBytes);
put("receivedBytes", adapter.receivedBytes);
put("transferredBytes", adapter.transferredBytes);
}
};
//map.put("fields", fieldsMap)
measurement.fields = fieldsMap;
log.debug("getSystemSharedAdapters() - fields: " + fieldsMap.toString());
list.add(measurement);
});
});
return list;
}
List<Measurement> getSystemFiberChannelAdapters() {
List<Measurement> list = new ArrayList<>();
metrics.systemUtil.sample.viosUtil.forEach( vios -> {
log.debug("getSystemFiberChannelAdapters() - VIOS: " + vios.name);
vios.storage.fiberChannelAdapters.forEach( adapter -> {
//HashMap<String, Map> map = new HashMap<>()
Measurement measurement = new Measurement();
HashMap<String, String> tagsMap = new HashMap<String, String>() {
{
put("id", adapter.id);
put("system", name);
put("wwpn", adapter.wwpn);
put("vios", vios.name);
put("device", adapter.physicalLocation);
}
};
//map.put("tags", tagsMap)
measurement.tags = tagsMap;
log.debug("getSystemFiberChannelAdapters() - tags: " + tagsMap.toString());
HashMap<String, Number> fieldsMap = new HashMap<String, Number>() {
{
put("writeBytes", adapter.writeBytes);
put("readBytes", adapter.readBytes);
put("transmittedBytes", adapter.transmittedBytes);
}
};
//map.put("fields", fieldsMap)
measurement.fields = fieldsMap;
log.debug("getSystemFiberChannelAdapters() - fields: " + fieldsMap.toString());
list.add(measurement);
});
});
return list;
}
List<Measurement> getSystemGenericPhysicalAdapters() {
List<Measurement> list = new ArrayList<>();
metrics.systemUtil.sample.viosUtil.forEach( vios -> {
vios.storage.genericPhysicalAdapters.forEach( adapter -> {
//Map<String, Map> map = new HashMap<String, Map>()
Measurement measurement = new Measurement();
HashMap<String, String> tagsMap = new HashMap<String, String>() {
{
put("id", adapter.id);
put("system", name);
put("vios", vios.name);
put("device", adapter.physicalLocation);
}
};
//map.put("tags", tagsMap)
measurement.tags = tagsMap;
log.debug("getSystemGenericPhysicalAdapters() - tags: " + tagsMap.toString());
HashMap<String, Number> fieldsMap = new HashMap<String, Number>() {
{
put("writeBytes", adapter.writeBytes);
put("readBytes", adapter.readBytes);
put("transmittedBytes", adapter.transmittedBytes);
}
};
//map.put("fields", fieldsMap)
measurement.fields = fieldsMap;
log.debug("getSystemGenericPhysicalAdapters() - fields: " + fieldsMap.toString());
list.add(measurement);
});
});
return list;
}
List<Measurement> getSystemGenericVirtualAdapters() {
List<Measurement> list = new ArrayList<>();
metrics.systemUtil.sample.viosUtil.forEach( vios -> {
vios.storage.genericVirtualAdapters.forEach( adapter -> {
//Map<String, Map> map = new HashMap<String, Map>()
Measurement measurement = new Measurement();
HashMap<String, String> tagsMap = new HashMap<String, String>() {
{
put("id", adapter.id);
put("system", name);
put("vios", vios.name);
put("device", adapter.physicalLocation);
}
};
//map.put("tags", tagsMap)
measurement.tags = tagsMap;
log.debug("getSystemGenericVirtualAdapters() - tags: " + tagsMap.toString());
HashMap<String, Number> fieldsMap = new HashMap<String, Number>() {
{
put("writeBytes", adapter.writeBytes);
put("readBytes", adapter.readBytes);
put("transmittedBytes", adapter.transmittedBytes);
}
};
//map.put("fields", fieldsMap)
measurement.fields = fieldsMap;
log.debug("getSystemGenericVirtualAdapters() - fields: " + fieldsMap.toString());
list.add(measurement);
});
});
return list;
}
}

View file

@ -13,35 +13,36 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package biz.nellemann.hmci package biz.nellemann.hmci;
import biz.nellemann.hmci.pcm.PcmData import biz.nellemann.hmci.pcm.PcmData;
import com.squareup.moshi.FromJson import com.serjltt.moshi.adapters.FirstElement;
import com.squareup.moshi.JsonAdapter import com.squareup.moshi.FromJson;
import com.squareup.moshi.Moshi import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.ToJson import com.squareup.moshi.Moshi;
import groovy.transform.CompileStatic import com.squareup.moshi.ToJson;
import groovy.util.logging.Slf4j import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.time.Instant import java.math.BigDecimal;
import java.time.format.DateTimeFormatter import java.time.Instant;
import java.time.format.DateTimeParseException import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
@Slf4j
@CompileStatic
abstract class MetaSystem { abstract class MetaSystem {
private final Moshi moshi; private final static Logger log = LoggerFactory.getLogger(MetaSystem.class);
private final JsonAdapter<PcmData> jsonAdapter; private final JsonAdapter<PcmData> jsonAdapter;
protected PcmData metrics protected PcmData metrics;
MetaSystem() { MetaSystem() {
try { try {
moshi = new Moshi.Builder().add(new NumberAdapter()).add(new BigDecimalAdapter())build(); Moshi moshi = new Moshi.Builder().add(new NumberAdapter()).add(new BigDecimalAdapter()).add(FirstElement.ADAPTER_FACTORY).build();
jsonAdapter = moshi.adapter(PcmData.class); jsonAdapter = moshi.adapter(PcmData.class);
} catch(Exception e) { } catch(Exception e) {
log.warn("MetaSystem() error", e) log.warn("MetaSystem() error", e);
throw new ExceptionInInitializerError(e); throw new ExceptionInInitializerError(e);
} }
} }
@ -52,7 +53,7 @@ abstract class MetaSystem {
try { try {
metrics = jsonAdapter.fromJson(json); metrics = jsonAdapter.fromJson(json);
} catch(Exception e) { } catch(Exception e) {
log.warn("processMetrics() error", e) log.warn("processMetrics() error", e);
} }
//Map pcmMap = new JsonSlurper().parseText(json) as Map //Map pcmMap = new JsonSlurper().parseText(json) as Map
@ -62,22 +63,22 @@ abstract class MetaSystem {
//@CompileDynamic //@CompileDynamic
Instant getTimestamp() { Instant getTimestamp() {
String timestamp = metrics.systemUtil.utilSamples.first().sampleInfo.timeStamp String timestamp = metrics.systemUtil.sample.sampleInfo.timeStamp;
Instant instant = null Instant instant = Instant.now();
try { try {
log.debug("getTimeStamp() - PMC Timestamp: " + timestamp) log.debug("getTimeStamp() - PMC Timestamp: " + timestamp);
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[XXX][X]"); DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[XXX][X]");
instant = Instant.from(dateTimeFormatter.parse(timestamp)) instant = Instant.from(dateTimeFormatter.parse(timestamp));
log.debug("getTimestamp() - Instant: " + instant.toString()) log.debug("getTimestamp() - Instant: " + instant.toString());
} catch(DateTimeParseException e) { } catch(DateTimeParseException e) {
log.warn("getTimestamp() - parse error: " + timestamp) log.warn("getTimestamp() - parse error: " + timestamp);
} }
return instant ?: Instant.now() return instant;
} }
class BigDecimalAdapter { static class BigDecimalAdapter {
@FromJson @FromJson
BigDecimal fromJson(String string) { BigDecimal fromJson(String string) {
@ -90,7 +91,7 @@ abstract class MetaSystem {
} }
} }
class NumberAdapter { static class NumberAdapter {
@FromJson @FromJson
Number fromJson(String string) { Number fromJson(String string) {

View file

@ -1,18 +1,32 @@
package biz.nellemann.hmci.pcm; package biz.nellemann.hmci.pcm;
import com.serjltt.moshi.adapters.FirstElement;
import java.util.List; import java.util.List;
public class FiberChannelAdapter { public class FiberChannelAdapter {
String id; public String id;
String wwpn; public String wwpn;
String physicalLocation; public String physicalLocation;
Integer numOfPorts; public Integer numOfPorts;
List<Number> numOfReads;
List<Number> numOfWrites; @FirstElement
List<Number> readBytes; public Number numOfReads;
List<Number> writeBytes;
List<Number> runningSpeed; @FirstElement
List<Number> transmittedBytes; public Number numOfWrites;
@FirstElement
public Number readBytes;
@FirstElement
public Number writeBytes;
@FirstElement
public Number runningSpeed;
@FirstElement
public Number transmittedBytes;
} }

View file

@ -4,14 +4,14 @@ import java.util.List;
public class GenericAdapter { public class GenericAdapter {
String id; public String id;
String type; public String type;
String physicalLocation; public String physicalLocation;
List<Number> receivedPackets; public List<Number> receivedPackets;
List<Number> sentPackets; public List<Number> sentPackets;
List<Number> droppedPackets; public List<Number> droppedPackets;
List<Number> sentBytes; public List<Number> sentBytes;
List<Number> receivedBytes; public List<Number> receivedBytes;
List<Number> transferredBytes; public List<Number> transferredBytes;
} }

View file

@ -1,16 +1,28 @@
package biz.nellemann.hmci.pcm; package biz.nellemann.hmci.pcm;
import com.serjltt.moshi.adapters.FirstElement;
import java.util.List; import java.util.List;
public class GenericPhysicalAdapters { public class GenericPhysicalAdapters {
String id; public String id;
String type; public String type;
String physicalLocation; public String physicalLocation;
List<Number> numOfReads;
List<Number> numOfWrites; @FirstElement
List<Number> readBytes; public Number numOfReads;
List<Number> writeBytes;
List<Number> transmittedBytes; @FirstElement
public Number numOfWrites;
@FirstElement
public Number readBytes;
@FirstElement
public Number writeBytes;
@FirstElement
public Number transmittedBytes;
} }

View file

@ -1,17 +1,28 @@
package biz.nellemann.hmci.pcm; package biz.nellemann.hmci.pcm;
import java.util.List; import com.serjltt.moshi.adapters.FirstElement;
public class GenericVirtualAdapter { public class GenericVirtualAdapter {
String id; public String id;
String type; public String type;
Integer viosId; public Integer viosId;
String physicalLocation; public String physicalLocation;
List<Number> numOfReads;
List<Number> numOfWrites; @FirstElement
List<Number> readBytes; public Number numOfReads;
List<Number> writeBytes;
List<Number> transmittedBytes; @FirstElement
public Number numOfWrites;
@FirstElement
public Number readBytes;
@FirstElement
public Number writeBytes;
@FirstElement
public Number transmittedBytes;
} }

View file

@ -1,10 +1,13 @@
package biz.nellemann.hmci.pcm; package biz.nellemann.hmci.pcm;
import java.util.List; import com.serjltt.moshi.adapters.FirstElement;
public class LparMemory { public class LparMemory {
List<Number> logicalMem; @FirstElement
List<Number> backedPhysicalMem; public Number logicalMem;
@FirstElement
public Number backedPhysicalMem;
} }

View file

@ -1,22 +1,46 @@
package biz.nellemann.hmci.pcm; package biz.nellemann.hmci.pcm;
import com.serjltt.moshi.adapters.FirstElement;
import java.util.List; import java.util.List;
public class LparProcessor { public class LparProcessor {
Integer poolId; public Integer poolId;
Integer weight; public Integer weight;
String mode; public String mode;
List<Number> maxVirtualProcessors;
List<Number> currentVirtualProcessors; @FirstElement
List<Number> maxProcUnits; public Number maxVirtualProcessors;
List<Number> entitledProcUnits;
List<Number> utilizedProcUnits; @FirstElement
List<Number> utilizedCappedProcUnits; public Number currentVirtualProcessors;
List<Number> utilizedUncappedProcUnits;
List<Number> idleProcUnits; @FirstElement
List<Number> donatedProcUnits; public Number maxProcUnits;
List<Number> timeSpentWaitingForDispatch;
List<Number> timePerInstructionExecution; @FirstElement
public Number entitledProcUnits;
@FirstElement
public Number utilizedProcUnits;
@FirstElement
public Number utilizedCappedProcUnits;
@FirstElement
public Number utilizedUncappedProcUnits;
@FirstElement
public Number idleProcUnits;
@FirstElement
public Number donatedProcUnits;
@FirstElement
public Number timeSpentWaitingForDispatch;
@FirstElement
public Number timePerInstructionExecution;
} }

View file

@ -2,17 +2,17 @@ package biz.nellemann.hmci.pcm;
public class LparUtil { public class LparUtil {
Integer id; public Integer id;
String uuid; public String uuid;
String name; public String name;
String state; public String state;
String type; public String type;
String osType; public String osType;
Integer affinityScore; public Number affinityScore;
LparMemory memory; public LparMemory memory;
LparProcessor processor; public LparProcessor processor;
Network network; public Network network = new Network();
Storage storage; public Storage storage = new Storage();
} }

View file

@ -1,11 +1,12 @@
package biz.nellemann.hmci.pcm; package biz.nellemann.hmci.pcm;
import java.util.ArrayList;
import java.util.List; import java.util.List;
public class Network { public class Network {
List<GenericAdapter> genericAdapters; public List<GenericAdapter> genericAdapters = new ArrayList<>();
List<SharedAdapter> sharedAdapters; public List<SharedAdapter> sharedAdapters = new ArrayList<>();
List<VirtualEthernetAdapter> virtualEthernetAdapters; public List<VirtualEthernetAdapter> virtualEthernetAdapters = new ArrayList<>();
} }

View file

@ -4,10 +4,10 @@ import java.util.List;
public class PhysicalProcessorPool { public class PhysicalProcessorPool {
List<Number> assignedProcUnits; public List<Number> assignedProcUnits;
List<Number> utilizedProcUnits; public List<Number> utilizedProcUnits;
List<Number> availableProcUnits; public List<Number> availableProcUnits;
List<Number> configuredProcUnits; public List<Number> configuredProcUnits;
List<Number> borrowedProcUnits; public List<Number> borrowedProcUnits;
} }

View file

@ -3,6 +3,6 @@ package biz.nellemann.hmci.pcm;
public class SampleInfo { public class SampleInfo {
public String timeStamp; public String timeStamp;
Integer status; public Integer status;
} }

View file

@ -1,12 +1,22 @@
package biz.nellemann.hmci.pcm; package biz.nellemann.hmci.pcm;
import com.serjltt.moshi.adapters.FirstElement;
import com.squareup.moshi.Json;
import java.util.List; import java.util.List;
public class ServerMemory { public class ServerMemory {
List<Number> totalMem; @FirstElement
List<Number> availableMem; public Number totalMem;
List<Number> configurableMem;
List<Number> assignedMemToLpars; @FirstElement
public Number availableMem;
@FirstElement
public Number configurableMem;
@FirstElement
public Number assignedMemToLpars;
} }

View file

@ -1,12 +1,19 @@
package biz.nellemann.hmci.pcm; package biz.nellemann.hmci.pcm;
import java.util.List; import com.serjltt.moshi.adapters.FirstElement;
public class ServerProcessor { public class ServerProcessor {
List<Number> totalProcUnits; @FirstElement
List<Number> utilizedProcUnits; public Number totalProcUnits;
List<Number> availableProcUnits;
List<Number> configurableProcUnits; @FirstElement
public Number utilizedProcUnits;
@FirstElement
public Number availableProcUnits;
@FirstElement
public Number configurableProcUnits;
} }

View file

@ -4,9 +4,9 @@ import java.util.List;
public class ServerUtil { public class ServerUtil {
ServerProcessor processor; public ServerProcessor processor;
ServerMemory memory; public ServerMemory memory;
PhysicalProcessorPool physicalProcessorPool; public PhysicalProcessorPool physicalProcessorPool;
List<SharedProcessorPool> sharedProcessorPool; public List<SharedProcessorPool> sharedProcessorPool;
} }

View file

@ -1,18 +1,32 @@
package biz.nellemann.hmci.pcm; package biz.nellemann.hmci.pcm;
import java.util.List; import com.serjltt.moshi.adapters.FirstElement;
public class SharedAdapter { public class SharedAdapter {
String id; public String id;
String type; public String type;
String physicalLocation; public String physicalLocation;
List<Number> receivedPackets;
List<Number> sentPackets; @FirstElement
List<Number> droppedPackets; public Number receivedPackets;
List<Number> sentBytes;
List<Number> receivedBytes; @FirstElement
List<Number> transferredBytes; public Number sentPackets;
List<String> bridgedAdapters;
@FirstElement
public Number droppedPackets;
@FirstElement
public Number sentBytes;
@FirstElement
public Number receivedBytes;
@FirstElement
public Number transferredBytes;
@FirstElement
public String bridgedAdapters;
} }

View file

@ -1,15 +1,25 @@
package biz.nellemann.hmci.pcm; package biz.nellemann.hmci.pcm;
import java.util.List; import com.serjltt.moshi.adapters.FirstElement;
public class SharedProcessorPool { public class SharedProcessorPool {
String id; public String id;
String name; public String name;
List<Number> assignedProcUnits;
List<Number> utilizedProcUnits; @FirstElement
List<Number> availableProcUnits; public Number assignedProcUnits;
List<Number> configuredProcUnits;
List<Number> borrowedProcUnits; @FirstElement
public Number utilizedProcUnits;
@FirstElement
public Number availableProcUnits;
@FirstElement
public Number configuredProcUnits;
@FirstElement
public Number borrowedProcUnits;
} }

View file

@ -1,13 +1,15 @@
package biz.nellemann.hmci.pcm; package biz.nellemann.hmci.pcm;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional;
public class Storage { public class Storage {
List<String> clientLpars; public List<String> clientLpars = new ArrayList<>();
List<GenericPhysicalAdapters> genericPhysicalAdapters; public List<GenericPhysicalAdapters> genericPhysicalAdapters = new ArrayList<>();
List<GenericVirtualAdapter> genericVirtualAdapters; public List<GenericVirtualAdapter> genericVirtualAdapters = new ArrayList<>();
List<FiberChannelAdapter> fiberChannelAdapters; public List<FiberChannelAdapter> fiberChannelAdapters = new ArrayList<>();
List<VirtualFiberChannelAdapter> virtualFiberChannelAdapters; public List<VirtualFiberChannelAdapter> virtualFiberChannelAdapters = new ArrayList<>();
} }

View file

@ -1,10 +1,14 @@
package biz.nellemann.hmci.pcm; package biz.nellemann.hmci.pcm;
import java.util.List; import com.serjltt.moshi.adapters.FirstElement;
import com.squareup.moshi.Json;
public class SystemUtil { public class SystemUtil {
UtilInfo utilInfo; public UtilInfo utilInfo;
public List<UtilSample> utilSamples;
@FirstElement
@Json(name = "utilSamples")
public UtilSample sample;
} }

View file

@ -4,14 +4,14 @@ import java.util.List;
public class UtilInfo { public class UtilInfo {
String version; public String version;
String metricType; public String metricType;
Integer frequency; public Integer frequency;
String startTimeStamp; public String startTimeStamp;
String endTimeStamp; public String endTimeStamp;
String mtms; public String mtms;
String name; public String name;
String uuid; public String uuid;
List<String> metricArrayOrder; public List<String> metricArrayOrder;
} }

View file

@ -1,13 +1,28 @@
package biz.nellemann.hmci.pcm; package biz.nellemann.hmci.pcm;
import com.serjltt.moshi.adapters.FirstElement;
import java.util.ArrayList;
import java.util.List; import java.util.List;
public class UtilSample { public class UtilSample {
String sampleType; public String sampleType;
public SampleInfo sampleInfo; public SampleInfo sampleInfo;
ServerUtil serverUtil; public ServerUtil serverUtil;
List<ViosUtil> viosUtil; public List<ViosUtil> viosUtil = new ArrayList<>();
List<LparUtil> lparsUtil;
@FirstElement
public LparUtil lparsUtil;
/*
public LparUtil getLparsUtil() {
if(lparsUtil == null || lparsUtil.isEmpty()) {
return new LparUtil();
} else {
return lparsUtil.get(0);
}
}*/
} }

View file

@ -1,10 +1,13 @@
package biz.nellemann.hmci.pcm; package biz.nellemann.hmci.pcm;
import java.util.List; import com.serjltt.moshi.adapters.FirstElement;
public class ViosMemory { public class ViosMemory {
List<Number> assignedMem; @FirstElement
List<Number> utilizedMem; public Number assignedMem;
@FirstElement
public Number utilizedMem;
} }

View file

@ -2,15 +2,15 @@ package biz.nellemann.hmci.pcm;
public class ViosUtil { public class ViosUtil {
String id; public String id;
String uuid; public String uuid;
String name; public String name;
String state; public String state;
Integer affinityScore; public Integer affinityScore;
ViosMemory memory; public ViosMemory memory;
LparProcessor processor; public LparProcessor processor;
Network network; public Network network;
Storage storage; public Storage storage;
} }

View file

@ -1,26 +1,52 @@
package biz.nellemann.hmci.pcm; package biz.nellemann.hmci.pcm;
import com.serjltt.moshi.adapters.FirstElement;
import java.util.List; import java.util.List;
public class VirtualEthernetAdapter { public class VirtualEthernetAdapter {
String physicalLocation; public String physicalLocation;
Integer vlanId; public Integer vlanId;
Integer vswitchId; public Integer vswitchId;
Boolean isPortVlanId; public Boolean isPortVlanId;
Integer viosId; public Integer viosId;
String sharedEthernetAdapterId; public String sharedEthernetAdapterId;
List<Number> receivedPackets;
List<Number> sentPackets; @FirstElement
List<Number> droppedPackets; public Number receivedPackets;
List<Number> sentBytes;
List<Number> receivedBytes; @FirstElement
List<Number> receivedPhysicalPackets; public Number sentPackets;
List<Number> sentPhysicalPackets;
List<Number> droppedPhysicalPackets; @FirstElement
List<Number> sentPhysicalBytes; public Number droppedPackets;
List<Number> receivedPhysicalBytes;
List<Number> transferredBytes; @FirstElement
List<Number> transferredPhysicalBytes; public Number sentBytes;
@FirstElement
public Number receivedBytes;
@FirstElement
public Number receivedPhysicalPackets;
@FirstElement
public Number sentPhysicalPackets;
@FirstElement
public Number droppedPhysicalPackets;
@FirstElement
public Number sentPhysicalBytes;
@FirstElement
public Number receivedPhysicalBytes;
@FirstElement
public Number transferredBytes;
@FirstElement
public Number transferredPhysicalBytes;
} }

View file

@ -4,16 +4,16 @@ import java.util.List;
public class VirtualFiberChannelAdapter { public class VirtualFiberChannelAdapter {
String wwpn; public String wwpn;
String wwpn2; public String wwpn2;
String physicalLocation; public String physicalLocation;
String physicalPortWWPN; public String physicalPortWWPN;
Integer viosId; public Integer viosId;
List<Number> numOfReads; public List<Number> numOfReads;
List<Number> numOfWrites; public List<Number> numOfWrites;
List<Number> readBytes; public List<Number> readBytes;
List<Number> writeBytes; public List<Number> writeBytes;
List<Number> runningSpeed; public List<Number> runningSpeed;
List<Number> transmittedBytes; public List<Number> transmittedBytes;
} }

View file

@ -3,7 +3,7 @@
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{12} - %msg%n</pattern> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{16} - %msg%n</pattern>
</encoder> </encoder>
</appender> </appender>

View file

@ -17,9 +17,9 @@ class LogicalPartitionTest extends Specification {
lpar.processMetrics(testJson) lpar.processMetrics(testJson)
then: then:
lpar.metrics.systemUtil.utilSamples.first().lparsUtil.first().memory.logicalMem.first() == 8192.000 lpar.metrics.systemUtil.sample.lparsUtil.memory.logicalMem == 8192.000
lpar.metrics.systemUtil.utilSamples.first().lparsUtil.first().processor.utilizedProcUnits.first() == 0.001 lpar.metrics.systemUtil.sample.lparsUtil.processor.utilizedProcUnits == 0.001
lpar.metrics.systemUtil.utilSamples.first().lparsUtil.first().network.virtualEthernetAdapters.first().receivedBytes.first() == 276.467 lpar.metrics.systemUtil.sample.lparsUtil.network.virtualEthernetAdapters.first().receivedBytes == 276.467
} }

View file

@ -15,12 +15,12 @@ class ManagedSystemTest extends Specification {
system.processMetrics(testJson) system.processMetrics(testJson)
then: then:
system.metrics.systemUtil.utilSamples.first().serverUtil.memory.assignedMemToLpars.first() == 40960.000 system.metrics.systemUtil.sample.serverUtil.memory.assignedMemToLpars == 40960.000
system.metrics.systemUtil.utilSamples.first().serverUtil.processor.totalProcUnits.first() == 24.000 system.metrics.systemUtil.sample.serverUtil.processor.totalProcUnits == 24.000
system.metrics.systemUtil.utilSamples.first().viosUtil.first().name == "VIOS1" system.metrics.systemUtil.sample.viosUtil.first().name == "VIOS1"
system.metrics.systemUtil.utilSamples.first().viosUtil.first().memory.assignedMem.first() == 8192.000 system.metrics.systemUtil.sample.viosUtil.first().memory.assignedMem == 8192.0
system.metrics.systemUtil.utilSamples.first().viosUtil.first().storage.genericPhysicalAdapters.first().transmittedBytes.first() == 9966.933 system.metrics.systemUtil.sample.viosUtil.first().storage.genericPhysicalAdapters.first().transmittedBytes == 9966.933
system.metrics.systemUtil.utilSamples.first().viosUtil.first().storage.fiberChannelAdapters.first().numOfPorts == 3 system.metrics.systemUtil.sample.viosUtil.first().storage.fiberChannelAdapters.first().numOfPorts == 3
} }