From b0053769413d1cfb92646e7d98d00ac226509210 Mon Sep 17 00:00:00 2001 From: Mark Nellemann Date: Sun, 11 Oct 2020 12:25:55 +0200 Subject: [PATCH] More refactoring work, from Groovy to plain Java. --- README.md | 2 +- build.gradle | 12 +- doc/hmci.groovy.tpl | 39 --- doc/hmci.toml | 31 ++ .../groovy/biz/nellemann/hmci/Insights.groovy | 176 ---------- .../nellemann/hmci/LogicalPartition.groovy | 194 ----------- .../biz/nellemann/hmci/ManagedSystem.groovy | 279 --------------- .../biz/nellemann/hmci/Configuration.java | 2 +- .../biz/nellemann/hmci/HmcClient.java} | 326 ++++++++++-------- .../biz/nellemann/hmci/InfluxClient.java} | 14 +- .../java/biz/nellemann/hmci/Insights.java | 189 ++++++++++ .../biz/nellemann/hmci/LogicalPartition.java | 225 ++++++++++++ .../biz/nellemann/hmci/Main.java} | 15 +- .../biz/nellemann/hmci/ManagedSystem.java | 326 ++++++++++++++++++ .../biz/nellemann/hmci/MetaSystem.java} | 55 +-- .../hmci/pcm/FiberChannelAdapter.java | 34 +- .../nellemann/hmci/pcm/GenericAdapter.java | 18 +- .../hmci/pcm/GenericPhysicalAdapters.java | 28 +- .../hmci/pcm/GenericVirtualAdapter.java | 31 +- .../biz/nellemann/hmci/pcm/LparMemory.java | 9 +- .../biz/nellemann/hmci/pcm/LparProcessor.java | 52 ++- .../java/biz/nellemann/hmci/pcm/LparUtil.java | 22 +- .../java/biz/nellemann/hmci/pcm/Network.java | 7 +- .../hmci/pcm/PhysicalProcessorPool.java | 10 +- .../biz/nellemann/hmci/pcm/SampleInfo.java | 2 +- .../biz/nellemann/hmci/pcm/ServerMemory.java | 18 +- .../nellemann/hmci/pcm/ServerProcessor.java | 17 +- .../biz/nellemann/hmci/pcm/ServerUtil.java | 8 +- .../biz/nellemann/hmci/pcm/SharedAdapter.java | 36 +- .../hmci/pcm/SharedProcessorPool.java | 26 +- .../java/biz/nellemann/hmci/pcm/Storage.java | 12 +- .../biz/nellemann/hmci/pcm/SystemUtil.java | 10 +- .../java/biz/nellemann/hmci/pcm/UtilInfo.java | 18 +- .../biz/nellemann/hmci/pcm/UtilSample.java | 23 +- .../biz/nellemann/hmci/pcm/ViosMemory.java | 9 +- .../java/biz/nellemann/hmci/pcm/ViosUtil.java | 18 +- .../hmci/pcm/VirtualEthernetAdapter.java | 62 +++- .../hmci/pcm/VirtualFiberChannelAdapter.java | 22 +- src/main/resources/logback.xml | 2 +- .../hmci/LogicalPartitionTest.groovy | 6 +- .../nellemann/hmci/ManagedSystemTest.groovy | 12 +- 41 files changed, 1337 insertions(+), 1060 deletions(-) delete mode 100644 doc/hmci.groovy.tpl create mode 100644 doc/hmci.toml delete mode 100644 src/main/groovy/biz/nellemann/hmci/Insights.groovy delete mode 100644 src/main/groovy/biz/nellemann/hmci/LogicalPartition.groovy delete mode 100644 src/main/groovy/biz/nellemann/hmci/ManagedSystem.groovy rename src/main/{groovy/biz/nellemann/hmci/HmcClient.groovy => java/biz/nellemann/hmci/HmcClient.java} (56%) rename src/main/{groovy/biz/nellemann/hmci/InfluxClient.groovy => java/biz/nellemann/hmci/InfluxClient.java} (97%) create mode 100644 src/main/java/biz/nellemann/hmci/Insights.java create mode 100644 src/main/java/biz/nellemann/hmci/LogicalPartition.java rename src/main/{groovy/biz/nellemann/hmci/Main.groovy => java/biz/nellemann/hmci/Main.java} (83%) create mode 100644 src/main/java/biz/nellemann/hmci/ManagedSystem.java rename src/main/{groovy/biz/nellemann/hmci/MetaSystem.groovy => java/biz/nellemann/hmci/MetaSystem.java} (67%) diff --git a/README.md b/README.md index c411467..822a16b 100644 --- a/README.md +++ b/README.md @@ -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! - 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). - Run the *bin/hmci* program in a shell, as a @reboot cron task or setup a proper service :) diff --git a/build.gradle b/build.gradle index 6af8634..cd4aa0a 100644 --- a/build.gradle +++ b/build.gradle @@ -16,20 +16,18 @@ repositories { } dependencies { - implementation 'info.picocli:picocli:4.5.1' annotationProcessor 'info.picocli:picocli-codegen:4.5.1' - // implementation 'com.thoughtworks.xstream:xstream:1.4.13' - // https://mvnrepository.com/artifact/org.jsoup/jsoup + implementation 'info.picocli:picocli:4.5.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.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.slf4j:slf4j-api:1.7.+' 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.slf4j:slf4j-simple:1.7.+") testImplementation('com.squareup.okhttp3:mockwebserver:4.8.0') diff --git a/doc/hmci.groovy.tpl b/doc/hmci.groovy.tpl deleted file mode 100644 index 37bc0eb..0000000 --- a/doc/hmci.groovy.tpl +++ /dev/null @@ -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 - } - */ - -} diff --git a/doc/hmci.toml b/doc/hmci.toml new file mode 100644 index 0000000..da9e502 --- /dev/null +++ b/doc/hmci.toml @@ -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 diff --git a/src/main/groovy/biz/nellemann/hmci/Insights.groovy b/src/main/groovy/biz/nellemann/hmci/Insights.groovy deleted file mode 100644 index 9334bed..0000000 --- a/src/main/groovy/biz/nellemann/hmci/Insights.groovy +++ /dev/null @@ -1,176 +0,0 @@ -/** - * Copyright 2020 Mark Nellemann - * - * 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 hmcClients = new HashMap<>(); - Map systems = new HashMap(); - Map partitions = new HashMap(); - - - 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) - } - - } - -} diff --git a/src/main/groovy/biz/nellemann/hmci/LogicalPartition.groovy b/src/main/groovy/biz/nellemann/hmci/LogicalPartition.groovy deleted file mode 100644 index 8f229a0..0000000 --- a/src/main/groovy/biz/nellemann/hmci/LogicalPartition.groovy +++ /dev/null @@ -1,194 +0,0 @@ -/** - * Copyright 2020 Mark Nellemann - * - * 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 getAffinityScore() { - - List list = new ArrayList<>() - //Map map = new HashMap() - - HashMap tagsMap = [ - system: system.name, - partition: name, - ] - //map.put("tags", tagsMap) - log.debug("getAffinityScore() - tags: " + tagsMap.toString()) - - HashMap fieldsMap = [ - affinityScore: metrics.systemUtil?.utilSamples?.first()?.lparsUtil?.first()?.affinityScore, - ] as HashMap - //map.put("fields", fieldsMap) - log.debug("getAffinityScore() - fields: " + fieldsMap.toString()) - - Measurement measurement = new Measurement(tagsMap, fieldsMap); - list.add(measurement); - return list - } - - - @CompileDynamic - List getMemoryMetrics() { - - List list = new ArrayList<>() - //Map map = new HashMap() - - HashMap tagsMap = [ - system: system.name, - partition: name, - ] - //map.put("tags", tagsMap) - log.debug("getMemoryMetrics() - tags: " + tagsMap.toString()) - - HashMap fieldsMap = [ - logicalMem: metrics.systemUtil?.utilSamples?.first()?.lparsUtil?.first()?.memory?.logicalMem?.first(), - backedPhysicalMem: metrics.systemUtil?.utilSamples?.first()?.lparsUtil?.first()?.memory?.backedPhysicalMem?.first(), - ] as HashMap - //map.put("fields", fieldsMap) - log.debug("getMemoryMetrics() - fields: " + fieldsMap.toString()) - - Measurement measurement = new Measurement(tagsMap, fieldsMap); - list.add(measurement); - - return list - } - - @CompileDynamic - List getProcessorMetrics() { - - List list = new ArrayList<>() - //Map map = new HashMap() - - HashMap tagsMap = [ - system: system.name, - partition: name, - ] - //map.put("tags", tagsMap) - log.debug("getProcessorMetrics() - tags: " + tagsMap.toString()) - - HashMap 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 - //map.put("fields", fieldsMap) - log.debug("getProcessorMetrics() - fields: " + fieldsMap.toString()) - - Measurement measurement = new Measurement(tagsMap, fieldsMap); - list.add(measurement); - - return list - } - - @CompileDynamic - List getVirtualEthernetAdapterMetrics() { - - List list = new ArrayList<>() - metrics.systemUtil?.utilSamples?.first()?.lparsUtil?.first()?.network?.virtualEthernetAdapters?.each { - //Map map = new HashMap() - - HashMap 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 fieldsMap = [ - receivedPhysicalBytes: it.receivedPhysicalBytes.first(), - sentPhysicalBytes: it.sentPhysicalBytes.first(), - receivedBytes: it.receivedBytes.first(), - sentBytes: it.sentBytes.first(), - ] as HashMap - //map.put("fields", fieldsMap) - log.debug("getVirtualEthernetAdapterMetrics() - fields: " + fieldsMap.toString()) - - Measurement measurement = new Measurement(tagsMap, fieldsMap); - list.add(measurement); - } - - return list - } - - - //PartitionVirtualFiberChannelAdapters - @CompileDynamic - List getVirtualFiberChannelAdaptersMetrics() { - - List list = new ArrayList<>() - metrics.systemUtil?.utilSamples?.first()?.lparsUtil?.first()?.storage?.virtualFiberChannelAdapters?.each { - //Map map = new HashMap() - - HashMap 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 fieldsMap = [ - transmittedBytes: it.transmittedBytes.first(), - writeBytes: it.writeBytes.first(), - readBytes: it.readBytes.first(), - ] as HashMap - //map.put("fields", fieldsMap) - log.debug("getVirtualFiberChannelAdaptersMetrics() - fields: " + fieldsMap.toString()) - - Measurement measurement = new Measurement(tagsMap, fieldsMap); - list.add(measurement); - } - - return list - } -} diff --git a/src/main/groovy/biz/nellemann/hmci/ManagedSystem.groovy b/src/main/groovy/biz/nellemann/hmci/ManagedSystem.groovy deleted file mode 100644 index 2238f85..0000000 --- a/src/main/groovy/biz/nellemann/hmci/ManagedSystem.groovy +++ /dev/null @@ -1,279 +0,0 @@ -/** - * Copyright 2020 Mark Nellemann - * - * 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 getMemoryMetrics() { - - List list = new ArrayList<>() - //Map map = new HashMap() - - HashMap tagsMap = [ - system: name, - ] - //map.put("tags", tagsMap) - log.debug("getMemoryMetrics() - tags: " + tagsMap.toString()) - - Map 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 - - //map.put("fields", fieldsMap) - log.debug("getMemoryMetrics() - fields: " + fieldsMap.toString()) - - Measurement measurement = new Measurement(tagsMap, fieldsMap); - list.add(measurement) - - return list - } - - - @CompileDynamic - List getProcessorMetrics() { - - List list = new ArrayList<>() - //Map map = new HashMap<>() - - HashMap tagsMap = [ - system: name, - ] - //map.put("tags", tagsMap) - //measurement.tags = tagsMap; - log.debug("getProcessorMetrics() - tags: " + tagsMap.toString()) - - HashMap 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 - //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 getSharedProcessorPools() { - - List list = new ArrayList<>() - metrics.systemUtil?.utilSamples?.first()?.serverUtil?.sharedProcessorPool?.each { - //Map map = new HashMap() - - HashMap tagsMap = [ - system: name, - pool: it.name, - ] - //map.put("tags", tagsMap) - log.debug("getSharedProcessorPools() - tags: " + tagsMap.toString()) - - HashMap fieldsMap = [ - assignedProcUnits: it.assignedProcUnits.first(), - availableProcUnits: it.availableProcUnits.first(), - ] as HashMap - //map.put("fields", fieldsMap) - log.debug("getSharedProcessorPools() - fields: " + fieldsMap.toString()) - - Measurement measurement = new Measurement(tagsMap, fieldsMap); - list.add(measurement) - } - - return list - } - - - @CompileDynamic - List getSystemSharedAdapters() { - - List list = new ArrayList<>() - metrics.systemUtil?.utilSamples?.first()?.viosUtil?.each {vios -> - vios.network.sharedAdapters.each { - //Map map = new HashMap() - Measurement measurement = new Measurement(); - - HashMap tagsMap = [ - system: name, - type: it.type, - vios: vios.name, - ] - //map.put("tags", tagsMap) - measurement.tags = tagsMap; - log.debug("getSystemSharedAdapters() - tags: " + tagsMap.toString()) - - HashMap fieldsMap = [ - sentBytes: it.sentBytes.first(), - receivedBytes: it.receivedBytes.first(), - transferredBytes: it.transferredBytes.first(), - ] as HashMap - //map.put("fields", fieldsMap) - measurement.fields = fieldsMap; - log.debug("getSystemSharedAdapters() - fields: " + fieldsMap.toString()) - - list.add(measurement) - } - } - - return list - } - - - @CompileDynamic - List getSystemFiberChannelAdapters() { - - List list = new ArrayList<>() - metrics.systemUtil?.utilSamples?.first()?.viosUtil?.each { vios -> - log.debug("getSystemFiberChannelAdapters() - VIOS: " + vios.name) - vios.storage?.fiberChannelAdapters?.each { - //HashMap map = new HashMap<>() - Measurement measurement = new Measurement(); - - HashMap 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 fieldsMap = [ - writeBytes: it.writeBytes.first(), - readBytes: it.readBytes.first(), - transmittedBytes: it.transmittedBytes.first(), - ] as HashMap - //map.put("fields", fieldsMap) - measurement.fields = fieldsMap; - log.debug("getSystemFiberChannelAdapters() - fields: " + fieldsMap.toString()) - - list.add(measurement) - } - } - - return list - } - - - @CompileDynamic - List getSystemGenericPhysicalAdapters() { - List list = new ArrayList<>() - metrics.systemUtil?.utilSamples?.first()?.viosUtil?.each { vios -> - vios.storage?.genericPhysicalAdapters?.each { - //Map map = new HashMap() - Measurement measurement = new Measurement(); - - HashMap 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 fieldsMap = [ - writeBytes: it.writeBytes.first(), - readBytes: it.readBytes.first(), - transmittedBytes: it.transmittedBytes.first(), - ] as HashMap - //map.put("fields", fieldsMap) - measurement.fields = fieldsMap; - log.debug("getSystemGenericPhysicalAdapters() - fields: " + fieldsMap.toString()) - - list.add(measurement) - } - } - - return list - } - - - @CompileDynamic - List getSystemGenericVirtualAdapters() { - List list = new ArrayList<>() - metrics.systemUtil?.utilSamples?.first()?.viosUtil?.each { vios -> - vios.storage?.genericVirtualAdapters?.each { - //Map map = new HashMap() - Measurement measurement = new Measurement(); - - HashMap 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 fieldsMap = [ - writeBytes: it.writeBytes.first(), - readBytes: it.readBytes.first(), - transmittedBytes: it.transmittedBytes.first(), - ] as HashMap - //map.put("fields", fieldsMap) - measurement.fields = fieldsMap; - log.debug("getSystemGenericVirtualAdapters() - fields: " + fieldsMap.toString()) - - list.add(measurement); - } - } - - return list - } - -} diff --git a/src/main/java/biz/nellemann/hmci/Configuration.java b/src/main/java/biz/nellemann/hmci/Configuration.java index 215b93a..f285c3d 100644 --- a/src/main/java/biz/nellemann/hmci/Configuration.java +++ b/src/main/java/biz/nellemann/hmci/Configuration.java @@ -139,7 +139,7 @@ public class Configuration { String url; String username; String password; - Boolean unsafe; + Boolean unsafe = false; private boolean isValid = false; diff --git a/src/main/groovy/biz/nellemann/hmci/HmcClient.groovy b/src/main/java/biz/nellemann/hmci/HmcClient.java similarity index 56% rename from src/main/groovy/biz/nellemann/hmci/HmcClient.groovy rename to src/main/java/biz/nellemann/hmci/HmcClient.java index 3f53f69..34260ad 100644 --- a/src/main/groovy/biz/nellemann/hmci/HmcClient.groovy +++ b/src/main/java/biz/nellemann/hmci/HmcClient.java @@ -13,88 +13,97 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package biz.nellemann.hmci +package biz.nellemann.hmci; -import biz.nellemann.hmci.Configuration.HmcObject -import com.squareup.moshi.Moshi -import groovy.transform.CompileDynamic -import groovy.transform.CompileStatic -import groovy.util.logging.Slf4j -import groovy.xml.XmlSlurper -import okhttp3.* -import org.jsoup.Jsoup -import org.jsoup.nodes.Document -import org.jsoup.nodes.Element -import org.jsoup.select.Elements +import biz.nellemann.hmci.Configuration.HmcObject; +import okhttp3.*; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import javax.net.ssl.* -import java.security.SecureRandom -import java.security.cert.CertificateException -import java.security.cert.X509Certificate +import javax.net.ssl.*; +import java.io.IOException; +import java.net.URL; +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 { + 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 String hmcId - private final String baseUrl - private final String username - private final String password - private final Boolean unsafe + private final String hmcId; + private final String baseUrl; + private final String username; + private final String password; + private final Boolean unsafe; - protected Integer responseErrors = 0 - protected String authToken - private final OkHttpClient client + protected Integer responseErrors = 0; + protected String authToken; + private final OkHttpClient client; HmcClient(HmcObject configHmc) { - this.hmcId = configHmc.name - this.baseUrl = configHmc.url - this.username = configHmc.username - this.password = configHmc.password - this.unsafe = configHmc.unsafe + this.hmcId = configHmc.name; + this.baseUrl = configHmc.url; + this.username = configHmc.username; + this.password = configHmc.password; + this.unsafe = configHmc.unsafe; if(unsafe) { - this.client = getUnsafeOkHttpClient() + this.client = getUnsafeOkHttpClient(); } 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. - * - * @throws IOException + * @param force + * @throws Exception */ - //@CompileDynamic - void login(Boolean force = false) throws IOException { + void login(Boolean force) throws Exception { - if(authToken && !force) { - return + if(authToken != null && !force) { + return; } log.info("Connecting to HMC - " + baseUrl); - String payload = """\ - - - ${username} - ${password} -""" + StringBuilder payload = new StringBuilder(); + payload.append(""); + payload.append(""); + payload.append("").append(username).append(""); + payload.append("").append(password).append(""); + payload.append(""); - 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() .url(url) //.addHeader("Content-Type", "application/vnd.ibm.powervm.web+xml; type=LogonRequest") .addHeader("Accept", "application/vnd.ibm.powervm.web+xml; type=LogonResponse") .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(); try { @@ -103,15 +112,15 @@ class HmcClient { // Get response body and parse String responseBody = response.body().string(); - response.body().close() + response.body().close(); - def xml = new XmlSlurper().parseText(responseBody) - authToken = xml.toString() + Document doc = Jsoup.parse(responseBody); + authToken = doc.select("X-API-Session").text(); - log.debug("login() - Auth Token: " + authToken) + log.debug("login() - Auth Token: " + authToken); } catch(Exception e) { - log.error(e.message) - throw new Exception(e) + log.error(e.getMessage()); + throw new Exception(e); } } @@ -122,13 +131,13 @@ class HmcClient { * Logoff from the HMC and remove any session * */ - void logoff() { + void logoff() throws IOException { - if(!authToken) { - return + if(authToken == null) { + 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() .url(absUrl) .addHeader("Content-Type", "application/vnd.ibm.powervm.web+xml; type=LogonRequest") @@ -139,8 +148,8 @@ class HmcClient { Response response = client.newCall(request).execute(); if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); - authToken = null - log.debug("logoff()") + authToken = null; + log.debug("logoff()"); } @@ -150,143 +159,158 @@ class HmcClient { * * @return */ - //@CompileDynamic - Map getManagedSystems() { - URL url = new URL(String.format("%s/rest/api/uom/ManagedSystem", baseUrl)) - Response response = getResponse(url) - String responseBody = response.body().string() - Map managedSystemsMap = new HashMap() + Map getManagedSystems() throws Exception { + + URL url = new URL(String.format("%s/rest/api/uom/ManagedSystem", baseUrl)); + Response response = getResponse(url); + String responseBody = Objects.requireNonNull(response.body()).string(); + Map managedSystemsMap = new HashMap(); // Do not try to parse empty response - if(responseBody.empty || responseBody.size() < 1) { - responseErrors++ - return managedSystemsMap + if(responseBody.isEmpty() || responseBody.length() <= 1) { + responseErrors++; + return managedSystemsMap; } try { 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) { ManagedSystem system = new ManagedSystem( hmcId, - el.select("Metadata > Atom > AtomID").text() as String, - el.select("SystemName").text() as String, - el.select("MachineTypeModelAndSerialNumber > MachineType").text() as String, - el.select("MachineTypeModelAndSerialNumber > Model").text() as String, - el.select("MachineTypeModelAndSerialNumber > SerialNumber").text() as String, - ) - managedSystemsMap.put(system.id, system) - log.info("getManagedSystems() - Found system: " + system.toString()) + el.select("Metadata > Atom > AtomID").text(), + el.select("SystemName").text(), + el.select("MachineTypeModelAndSerialNumber > MachineType").text(), + el.select("MachineTypeModelAndSerialNumber > Model").text(), + el.select("MachineTypeModelAndSerialNumber > SerialNumber").text() + ); + managedSystemsMap.put(system.id, system); + log.info("getManagedSystems() - Found system: " + system.toString()); } } catch(Exception e) { log.warn("getManagedSystems() - xml parse error", e); } - return managedSystemsMap + return managedSystemsMap; } /** * Return Map of LogicalPartitions seen by a ManagedSystem on this HMC - - * @param UUID of managed system + * @param system * @return */ - //@CompileDynamic - Map getLogicalPartitionsForManagedSystem(ManagedSystem system) { - URL url = new URL(String.format("%s/rest/api/uom/ManagedSystem/%s/LogicalPartition", baseUrl, system.id)) - Response response = getResponse(url) - String responseBody = response.body().string() - Map partitionMap = new HashMap() {} + Map getLogicalPartitionsForManagedSystem(ManagedSystem system) throws Exception { + URL url = new URL(String.format("%s/rest/api/uom/ManagedSystem/%s/LogicalPartition", baseUrl, system.id)); + Response response = getResponse(url); + String responseBody = Objects.requireNonNull(response.body()).string(); + Map partitionMap = new HashMap() {}; // Do not try to parse empty response - if(responseBody.empty || responseBody.size() < 1) { - responseErrors++ - return partitionMap + if(responseBody.isEmpty() || responseBody.length() <= 1) { + responseErrors++; + return partitionMap; } try { 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) { LogicalPartition logicalPartition = new LogicalPartition( - el.select("PartitionUUID").text() as String, - el.select("PartitionName").text() as String, - el.select("PartitionType").text() as String, + el.select("PartitionUUID").text(), + el.select("PartitionName").text(), + el.select("PartitionType").text(), system - ) - partitionMap.put(logicalPartition.id, logicalPartition) - log.info("getLogicalPartitionsForManagedSystem() - Found partition: " + logicalPartition.toString()) + ); + partitionMap.put(logicalPartition.id, logicalPartition); + log.info("getLogicalPartitionsForManagedSystem() - Found partition: " + logicalPartition.toString()); } } catch(Exception e) { log.warn("getLogicalPartitionsForManagedSystem() - xml parse error", e); } - return partitionMap + return partitionMap; } /** * Parse XML feed to get PCM Data in JSON format - * @param systemId + * @param system * @return */ - //@CompileDynamic - String getPcmDataForManagedSystem(ManagedSystem system) { - log.debug("getPcmDataForManagedSystem() - " + system.id) - URL url = new URL(String.format("%s/rest/api/pcm/ManagedSystem/%s/ProcessedMetrics?NoOfSamples=1", baseUrl, system.id)) - Response response = getResponse(url) - String responseBody = response.body().string() - String jsonBody + String getPcmDataForManagedSystem(ManagedSystem system) throws Exception { + + log.debug("getPcmDataForManagedSystem() - " + system.id); + URL url = new URL(String.format("%s/rest/api/pcm/ManagedSystem/%s/ProcessedMetrics?NoOfSamples=1", baseUrl, system.id)); + Response response = getResponse(url); + String responseBody = Objects.requireNonNull(response.body()).string(); + String jsonBody = null; // Do not try to parse empty response - if(responseBody.empty || responseBody.size() < 1) { - responseErrors++ - return jsonBody + if(responseBody.isEmpty() || responseBody.length() <= 1) { + responseErrors++; + log.warn("getPcmDataForManagedSystem() - empty response"); + return jsonBody; } try { 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(); - 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); jsonBody = getResponseBody(new URL(href)); } + } catch(Exception e) { log.warn("getPcmDataForManagedSystem() - xml parse error", e); } - return jsonBody + return jsonBody; } /** * Parse XML feed to get PCM Data in JSON format - * @param systemId - * @param partitionId + * @param partition * @return */ - //@CompileDynamic - String getPcmDataForLogicalPartition(LogicalPartition partition) { + String getPcmDataForLogicalPartition(LogicalPartition partition) throws Exception { - 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)) - Response response = getResponse(url) - String responseBody = response.body().string() - String jsonBody + 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)); + Response response = getResponse(url); + String responseBody = Objects.requireNonNull(response.body()).string(); + String jsonBody = null; // Do not try to parse empty response - if(responseBody.empty || responseBody.size() < 1) { - responseErrors++ - return jsonBody + if(responseBody.isEmpty() || responseBody.length() <= 1) { + responseErrors++; + 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 { Document doc = Jsoup.parse(responseBody); Element entry = doc.select("entry").first(); @@ -298,9 +322,9 @@ class HmcClient { } } catch(Exception e) { log.warn("getPcmDataForLogicalPartition() - xml parse error", e); - } + }*/ - return jsonBody + return jsonBody; } @@ -310,28 +334,38 @@ class HmcClient { * @param url * @return */ - protected String getResponseBody(URL url) { - Response response = getResponse(url) - String body = response.body().string() - response.body().close() - return body + protected String getResponseBody(URL url) throws Exception { + Response response = getResponse(url); + String body = Objects.requireNonNull(response.body()).string(); + Objects.requireNonNull(response.body()).close(); + return body; } - /** * Return a Response from the HMC - * * @param url * @return */ - //@CompileDynamic - private Response getResponse(URL url, Integer retry = 0) { + private Response getResponse(URL url) throws Exception { + 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) { - responseErrors = 0 - login(true) - return getResponse(url, retry++) + responseErrors = 0; + login(true); + return getResponse(url, retry++); } Request request = new Request.Builder() @@ -343,23 +377,23 @@ class HmcClient { Response response = client.newCall(request).execute(); if (!response.isSuccessful()) { - response.body().close() + response.body().close(); if(response.code() == 401) { - login(true) - return getResponse(url, retry++) + login(true); + return getResponse(url, retry++); } if(retry < 2) { - log.warn("getResponse() - Retrying due to unexpected response: " + response.code()) - return getResponse(url, retry++) + log.warn("getResponse() - Retrying due to unexpected response: " + response.code()); + return getResponse(url, retry++); } - log.error("getResponse() - Unexpected response: " + response.code()) - throw new IOException("getResponse() - Unexpected response: " + response.code()) + log.error("getResponse() - Unexpected response: " + response.code()); + throw new IOException("getResponse() - Unexpected response: " + response.code()); }; - return response + return response; } diff --git a/src/main/groovy/biz/nellemann/hmci/InfluxClient.groovy b/src/main/java/biz/nellemann/hmci/InfluxClient.java similarity index 97% rename from src/main/groovy/biz/nellemann/hmci/InfluxClient.groovy rename to src/main/java/biz/nellemann/hmci/InfluxClient.java index 04a21d2..8d26f9d 100644 --- a/src/main/groovy/biz/nellemann/hmci/InfluxClient.groovy +++ b/src/main/java/biz/nellemann/hmci/InfluxClient.java @@ -15,8 +15,7 @@ */ package biz.nellemann.hmci; -import biz.nellemann.hmci.Configuration.InfluxObject -import groovy.transform.CompileStatic; +import biz.nellemann.hmci.Configuration.InfluxObject; import org.influxdb.BatchOptions; import org.influxdb.InfluxDB; import org.influxdb.InfluxDBFactory; @@ -26,10 +25,11 @@ import org.influxdb.dto.Query; import org.slf4j.Logger; 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; -@CompileStatic class InfluxClient { private final static Logger log = LoggerFactory.getLogger(InfluxClient.class); @@ -54,7 +54,7 @@ class InfluxClient { void login() throws Exception { if(influxDB != null) { - return + return; } try { @@ -91,7 +91,7 @@ class InfluxClient { } - void writeBatchPoints() { + void writeBatchPoints() throws Exception { log.debug("writeBatchPoints()"); try { influxDB.write(batchPoints); @@ -271,7 +271,7 @@ class InfluxClient { // Iterate fields //Map fieldsMap = m.get("fields"); 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) .time(timestamp.toEpochMilli(), TimeUnit.MILLISECONDS) diff --git a/src/main/java/biz/nellemann/hmci/Insights.java b/src/main/java/biz/nellemann/hmci/Insights.java new file mode 100644 index 0000000..e1dcc20 --- /dev/null +++ b/src/main/java/biz/nellemann/hmci/Insights.java @@ -0,0 +1,189 @@ +/** + * Copyright 2020 Mark Nellemann + * + * 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 hmcClients = new HashMap<>(); + Map systems = new HashMap(); + Map partitions = new HashMap(); + + + 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); + } + + } + +} diff --git a/src/main/java/biz/nellemann/hmci/LogicalPartition.java b/src/main/java/biz/nellemann/hmci/LogicalPartition.java new file mode 100644 index 0000000..ac3a436 --- /dev/null +++ b/src/main/java/biz/nellemann/hmci/LogicalPartition.java @@ -0,0 +1,225 @@ +/** + * Copyright 2020 Mark Nellemann + * + * 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 getAffinityScore() { + + List list = new ArrayList<>(); + //Map map = new HashMap() + + Map tagsMap = new HashMap() { + { + put("system", system.name); + put("partition", name); + } + }; + + //map.put("tags", tagsMap) + log.debug("getAffinityScore() - tags: " + tagsMap.toString()); + Map fieldsMap = new HashMap() { + { + 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 getMemoryMetrics() { + + List list = new ArrayList<>(); + //Map map = new HashMap() + + Map tagsMap = new HashMap() { + { + put("system", system.name); + put("partition", name); + } + }; + + //map.put("tags", tagsMap) + log.debug("getMemoryMetrics() - tags: " + tagsMap.toString()); + + Map fieldsMap = new HashMap() { + { + 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 getProcessorMetrics() { + + List list = new ArrayList<>(); + //Map map = new HashMap() + + HashMap tagsMap = new HashMap() { + { + put("system", system.name); + put("partition", name); + } + }; + + //map.put("tags", tagsMap) + log.debug("getProcessorMetrics() - tags: " + tagsMap.toString()); + + HashMap fieldsMap = new HashMap() { + { + 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 getVirtualEthernetAdapterMetrics() { + + List list = new ArrayList<>(); + metrics.systemUtil.sample.lparsUtil.network.virtualEthernetAdapters.forEach( adapter -> { + + HashMap tagsMap = new HashMap() { + { + 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 fieldsMap = new HashMap() { + { + 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 getVirtualFiberChannelAdaptersMetrics() { + + List list = new ArrayList<>(); + metrics.systemUtil.sample.lparsUtil.storage.virtualFiberChannelAdapters.forEach( adapter -> { + //Map map = new HashMap() + + HashMap tagsMap = new HashMap() { + { + 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 fieldsMap = new HashMap() { + { + 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; + } + +} diff --git a/src/main/groovy/biz/nellemann/hmci/Main.groovy b/src/main/java/biz/nellemann/hmci/Main.java similarity index 83% rename from src/main/groovy/biz/nellemann/hmci/Main.groovy rename to src/main/java/biz/nellemann/hmci/Main.java index 0994d74..82d0487 100644 --- a/src/main/groovy/biz/nellemann/hmci/Main.groovy +++ b/src/main/java/biz/nellemann/hmci/Main.java @@ -13,16 +13,17 @@ See the License for the specific language governing permissions and limitations under the License. */ -package biz.nellemann.hmci +package biz.nellemann.hmci; -import groovy.transform.CompileStatic; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import picocli.CommandLine; import picocli.CommandLine.Command; + +import java.io.File; +import java.io.IOException; import java.util.concurrent.Callable; -@CompileStatic @Command(name = "hmci", mixinStandardHelpOptions = true, description = "HMC Insights.", @@ -31,7 +32,7 @@ public class Main implements Callable { 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"; public static void main(String... args) { @@ -51,7 +52,11 @@ public class Main implements Callable { Configuration configuration = new Configuration(configurationFile); Insights insights = new Insights(configuration); - insights.run(); + try { + insights.run(); + } catch (InterruptedException e) { + log.error(e.getMessage()); + } return 0; } diff --git a/src/main/java/biz/nellemann/hmci/ManagedSystem.java b/src/main/java/biz/nellemann/hmci/ManagedSystem.java new file mode 100644 index 0000000..84c1a3d --- /dev/null +++ b/src/main/java/biz/nellemann/hmci/ManagedSystem.java @@ -0,0 +1,326 @@ +/** + * Copyright 2020 Mark Nellemann + * + * 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 getMemoryMetrics() { + + List list = new ArrayList<>(); + //Map map = new HashMap() + + HashMap tagsMap = new HashMap() { + { + put("system", name); + } + }; + + //map.put("tags", tagsMap) + log.debug("getMemoryMetrics() - tags: " + tagsMap.toString()); + + Map fieldsMap = new HashMap() { + { + 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 getProcessorMetrics() { + + List list = new ArrayList<>(); + //Map map = new HashMap<>() + + HashMap tagsMap = new HashMap() { + { + put("system", name); + } + }; + + //map.put("tags", tagsMap) + //measurement.tags = tagsMap; + log.debug("getProcessorMetrics() - tags: " + tagsMap.toString()); + + HashMap fieldsMap = new HashMap() { + { + 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 getSharedProcessorPools() { + + List list = new ArrayList<>(); + metrics.systemUtil.sample.serverUtil.sharedProcessorPool.forEach(adapter -> { + //Map map = new HashMap() + + HashMap tagsMap = new HashMap() { + { + put("system", name); + put("pool", adapter.name); + } + }; + + //map.put("tags", tagsMap) + log.debug("getSharedProcessorPools() - tags: " + tagsMap.toString()); + + HashMap fieldsMap = new HashMap() { + { + 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 getSystemSharedAdapters() { + + List list = new ArrayList<>(); + metrics.systemUtil.sample.viosUtil.forEach(vios -> { + + vios.network.sharedAdapters.forEach(adapter -> { + //Map map = new HashMap() + Measurement measurement = new Measurement(); + + HashMap tagsMap = new HashMap() { + { + 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 fieldsMap = new HashMap() { + { + 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 getSystemFiberChannelAdapters() { + + List list = new ArrayList<>(); + metrics.systemUtil.sample.viosUtil.forEach( vios -> { + log.debug("getSystemFiberChannelAdapters() - VIOS: " + vios.name); + + vios.storage.fiberChannelAdapters.forEach( adapter -> { + //HashMap map = new HashMap<>() + Measurement measurement = new Measurement(); + + HashMap tagsMap = new HashMap() { + { + 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 fieldsMap = new HashMap() { + { + 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 getSystemGenericPhysicalAdapters() { + + List list = new ArrayList<>(); + + metrics.systemUtil.sample.viosUtil.forEach( vios -> { + + vios.storage.genericPhysicalAdapters.forEach( adapter -> { + //Map map = new HashMap() + Measurement measurement = new Measurement(); + + HashMap tagsMap = new HashMap() { + { + 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 fieldsMap = new HashMap() { + { + 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 getSystemGenericVirtualAdapters() { + + List list = new ArrayList<>(); + + metrics.systemUtil.sample.viosUtil.forEach( vios -> { + + vios.storage.genericVirtualAdapters.forEach( adapter -> { + + //Map map = new HashMap() + Measurement measurement = new Measurement(); + + HashMap tagsMap = new HashMap() { + { + 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 fieldsMap = new HashMap() { + { + 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; + } + +} diff --git a/src/main/groovy/biz/nellemann/hmci/MetaSystem.groovy b/src/main/java/biz/nellemann/hmci/MetaSystem.java similarity index 67% rename from src/main/groovy/biz/nellemann/hmci/MetaSystem.groovy rename to src/main/java/biz/nellemann/hmci/MetaSystem.java index 6f50bb9..4176e09 100644 --- a/src/main/groovy/biz/nellemann/hmci/MetaSystem.groovy +++ b/src/main/java/biz/nellemann/hmci/MetaSystem.java @@ -13,35 +13,36 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package biz.nellemann.hmci +package biz.nellemann.hmci; -import biz.nellemann.hmci.pcm.PcmData -import com.squareup.moshi.FromJson -import com.squareup.moshi.JsonAdapter -import com.squareup.moshi.Moshi -import com.squareup.moshi.ToJson -import groovy.transform.CompileStatic -import groovy.util.logging.Slf4j +import biz.nellemann.hmci.pcm.PcmData; +import com.serjltt.moshi.adapters.FirstElement; +import com.squareup.moshi.FromJson; +import com.squareup.moshi.JsonAdapter; +import com.squareup.moshi.Moshi; +import com.squareup.moshi.ToJson; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import java.time.Instant -import java.time.format.DateTimeFormatter -import java.time.format.DateTimeParseException +import java.math.BigDecimal; +import java.time.Instant; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; -@Slf4j -@CompileStatic abstract class MetaSystem { - private final Moshi moshi; + private final static Logger log = LoggerFactory.getLogger(MetaSystem.class); + private final JsonAdapter jsonAdapter; - protected PcmData metrics + protected PcmData metrics; MetaSystem() { 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); } catch(Exception e) { - log.warn("MetaSystem() error", e) + log.warn("MetaSystem() error", e); throw new ExceptionInInitializerError(e); } } @@ -52,7 +53,7 @@ abstract class MetaSystem { try { metrics = jsonAdapter.fromJson(json); } catch(Exception e) { - log.warn("processMetrics() error", e) + log.warn("processMetrics() error", e); } //Map pcmMap = new JsonSlurper().parseText(json) as Map @@ -62,22 +63,22 @@ abstract class MetaSystem { //@CompileDynamic Instant getTimestamp() { - String timestamp = metrics.systemUtil.utilSamples.first().sampleInfo.timeStamp - Instant instant = null + String timestamp = metrics.systemUtil.sample.sampleInfo.timeStamp; + Instant instant = Instant.now(); 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]"); - instant = Instant.from(dateTimeFormatter.parse(timestamp)) - log.debug("getTimestamp() - Instant: " + instant.toString()) + instant = Instant.from(dateTimeFormatter.parse(timestamp)); + log.debug("getTimestamp() - Instant: " + instant.toString()); } 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 BigDecimal fromJson(String string) { @@ -90,7 +91,7 @@ abstract class MetaSystem { } } - class NumberAdapter { + static class NumberAdapter { @FromJson Number fromJson(String string) { diff --git a/src/main/java/biz/nellemann/hmci/pcm/FiberChannelAdapter.java b/src/main/java/biz/nellemann/hmci/pcm/FiberChannelAdapter.java index d91235c..e705870 100644 --- a/src/main/java/biz/nellemann/hmci/pcm/FiberChannelAdapter.java +++ b/src/main/java/biz/nellemann/hmci/pcm/FiberChannelAdapter.java @@ -1,18 +1,32 @@ package biz.nellemann.hmci.pcm; +import com.serjltt.moshi.adapters.FirstElement; + import java.util.List; public class FiberChannelAdapter { - String id; - String wwpn; - String physicalLocation; - Integer numOfPorts; - List numOfReads; - List numOfWrites; - List readBytes; - List writeBytes; - List runningSpeed; - List transmittedBytes; + public String id; + public String wwpn; + public String physicalLocation; + public Integer numOfPorts; + + @FirstElement + public Number numOfReads; + + @FirstElement + public Number numOfWrites; + + @FirstElement + public Number readBytes; + + @FirstElement + public Number writeBytes; + + @FirstElement + public Number runningSpeed; + + @FirstElement + public Number transmittedBytes; } diff --git a/src/main/java/biz/nellemann/hmci/pcm/GenericAdapter.java b/src/main/java/biz/nellemann/hmci/pcm/GenericAdapter.java index c2dbeea..382512e 100644 --- a/src/main/java/biz/nellemann/hmci/pcm/GenericAdapter.java +++ b/src/main/java/biz/nellemann/hmci/pcm/GenericAdapter.java @@ -4,14 +4,14 @@ import java.util.List; public class GenericAdapter { - String id; - String type; - String physicalLocation; - List receivedPackets; - List sentPackets; - List droppedPackets; - List sentBytes; - List receivedBytes; - List transferredBytes; + public String id; + public String type; + public String physicalLocation; + public List receivedPackets; + public List sentPackets; + public List droppedPackets; + public List sentBytes; + public List receivedBytes; + public List transferredBytes; } diff --git a/src/main/java/biz/nellemann/hmci/pcm/GenericPhysicalAdapters.java b/src/main/java/biz/nellemann/hmci/pcm/GenericPhysicalAdapters.java index 008c716..2ec8a35 100644 --- a/src/main/java/biz/nellemann/hmci/pcm/GenericPhysicalAdapters.java +++ b/src/main/java/biz/nellemann/hmci/pcm/GenericPhysicalAdapters.java @@ -1,16 +1,28 @@ package biz.nellemann.hmci.pcm; +import com.serjltt.moshi.adapters.FirstElement; + import java.util.List; public class GenericPhysicalAdapters { - String id; - String type; - String physicalLocation; - List numOfReads; - List numOfWrites; - List readBytes; - List writeBytes; - List transmittedBytes; + public String id; + public String type; + public String physicalLocation; + + @FirstElement + public Number numOfReads; + + @FirstElement + public Number numOfWrites; + + @FirstElement + public Number readBytes; + + @FirstElement + public Number writeBytes; + + @FirstElement + public Number transmittedBytes; } diff --git a/src/main/java/biz/nellemann/hmci/pcm/GenericVirtualAdapter.java b/src/main/java/biz/nellemann/hmci/pcm/GenericVirtualAdapter.java index cff608a..9fe11d6 100644 --- a/src/main/java/biz/nellemann/hmci/pcm/GenericVirtualAdapter.java +++ b/src/main/java/biz/nellemann/hmci/pcm/GenericVirtualAdapter.java @@ -1,17 +1,28 @@ package biz.nellemann.hmci.pcm; -import java.util.List; +import com.serjltt.moshi.adapters.FirstElement; + public class GenericVirtualAdapter { - String id; - String type; - Integer viosId; - String physicalLocation; - List numOfReads; - List numOfWrites; - List readBytes; - List writeBytes; - List transmittedBytes; + public String id; + public String type; + public Integer viosId; + public String physicalLocation; + + @FirstElement + public Number numOfReads; + + @FirstElement + public Number numOfWrites; + + @FirstElement + public Number readBytes; + + @FirstElement + public Number writeBytes; + + @FirstElement + public Number transmittedBytes; } diff --git a/src/main/java/biz/nellemann/hmci/pcm/LparMemory.java b/src/main/java/biz/nellemann/hmci/pcm/LparMemory.java index 025022f..1ab35f0 100644 --- a/src/main/java/biz/nellemann/hmci/pcm/LparMemory.java +++ b/src/main/java/biz/nellemann/hmci/pcm/LparMemory.java @@ -1,10 +1,13 @@ package biz.nellemann.hmci.pcm; -import java.util.List; +import com.serjltt.moshi.adapters.FirstElement; public class LparMemory { - List logicalMem; - List backedPhysicalMem; + @FirstElement + public Number logicalMem; + + @FirstElement + public Number backedPhysicalMem; } diff --git a/src/main/java/biz/nellemann/hmci/pcm/LparProcessor.java b/src/main/java/biz/nellemann/hmci/pcm/LparProcessor.java index d6e18a3..89fe88f 100644 --- a/src/main/java/biz/nellemann/hmci/pcm/LparProcessor.java +++ b/src/main/java/biz/nellemann/hmci/pcm/LparProcessor.java @@ -1,22 +1,46 @@ package biz.nellemann.hmci.pcm; +import com.serjltt.moshi.adapters.FirstElement; + import java.util.List; public class LparProcessor { - Integer poolId; - Integer weight; - String mode; - List maxVirtualProcessors; - List currentVirtualProcessors; - List maxProcUnits; - List entitledProcUnits; - List utilizedProcUnits; - List utilizedCappedProcUnits; - List utilizedUncappedProcUnits; - List idleProcUnits; - List donatedProcUnits; - List timeSpentWaitingForDispatch; - List timePerInstructionExecution; + public Integer poolId; + public Integer weight; + public String mode; + + @FirstElement + public Number maxVirtualProcessors; + + @FirstElement + public Number currentVirtualProcessors; + + @FirstElement + public Number maxProcUnits; + + @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; } diff --git a/src/main/java/biz/nellemann/hmci/pcm/LparUtil.java b/src/main/java/biz/nellemann/hmci/pcm/LparUtil.java index ffa50af..9e2f918 100644 --- a/src/main/java/biz/nellemann/hmci/pcm/LparUtil.java +++ b/src/main/java/biz/nellemann/hmci/pcm/LparUtil.java @@ -2,17 +2,17 @@ package biz.nellemann.hmci.pcm; public class LparUtil { - Integer id; - String uuid; - String name; - String state; - String type; - String osType; - Integer affinityScore; + public Integer id; + public String uuid; + public String name; + public String state; + public String type; + public String osType; + public Number affinityScore; - LparMemory memory; - LparProcessor processor; - Network network; - Storage storage; + public LparMemory memory; + public LparProcessor processor; + public Network network = new Network(); + public Storage storage = new Storage(); } diff --git a/src/main/java/biz/nellemann/hmci/pcm/Network.java b/src/main/java/biz/nellemann/hmci/pcm/Network.java index 053c148..dd2df78 100644 --- a/src/main/java/biz/nellemann/hmci/pcm/Network.java +++ b/src/main/java/biz/nellemann/hmci/pcm/Network.java @@ -1,11 +1,12 @@ package biz.nellemann.hmci.pcm; +import java.util.ArrayList; import java.util.List; public class Network { - List genericAdapters; - List sharedAdapters; - List virtualEthernetAdapters; + public List genericAdapters = new ArrayList<>(); + public List sharedAdapters = new ArrayList<>(); + public List virtualEthernetAdapters = new ArrayList<>(); } diff --git a/src/main/java/biz/nellemann/hmci/pcm/PhysicalProcessorPool.java b/src/main/java/biz/nellemann/hmci/pcm/PhysicalProcessorPool.java index 443c661..09082cd 100644 --- a/src/main/java/biz/nellemann/hmci/pcm/PhysicalProcessorPool.java +++ b/src/main/java/biz/nellemann/hmci/pcm/PhysicalProcessorPool.java @@ -4,10 +4,10 @@ import java.util.List; public class PhysicalProcessorPool { - List assignedProcUnits; - List utilizedProcUnits; - List availableProcUnits; - List configuredProcUnits; - List borrowedProcUnits; + public List assignedProcUnits; + public List utilizedProcUnits; + public List availableProcUnits; + public List configuredProcUnits; + public List borrowedProcUnits; } diff --git a/src/main/java/biz/nellemann/hmci/pcm/SampleInfo.java b/src/main/java/biz/nellemann/hmci/pcm/SampleInfo.java index d5a2fcc..2665d51 100644 --- a/src/main/java/biz/nellemann/hmci/pcm/SampleInfo.java +++ b/src/main/java/biz/nellemann/hmci/pcm/SampleInfo.java @@ -3,6 +3,6 @@ package biz.nellemann.hmci.pcm; public class SampleInfo { public String timeStamp; - Integer status; + public Integer status; } diff --git a/src/main/java/biz/nellemann/hmci/pcm/ServerMemory.java b/src/main/java/biz/nellemann/hmci/pcm/ServerMemory.java index b835a0d..f8d1f72 100644 --- a/src/main/java/biz/nellemann/hmci/pcm/ServerMemory.java +++ b/src/main/java/biz/nellemann/hmci/pcm/ServerMemory.java @@ -1,12 +1,22 @@ package biz.nellemann.hmci.pcm; +import com.serjltt.moshi.adapters.FirstElement; +import com.squareup.moshi.Json; + import java.util.List; public class ServerMemory { - List totalMem; - List availableMem; - List configurableMem; - List assignedMemToLpars; + @FirstElement + public Number totalMem; + + @FirstElement + public Number availableMem; + + @FirstElement + public Number configurableMem; + + @FirstElement + public Number assignedMemToLpars; } diff --git a/src/main/java/biz/nellemann/hmci/pcm/ServerProcessor.java b/src/main/java/biz/nellemann/hmci/pcm/ServerProcessor.java index 0da20ae..47ffe57 100644 --- a/src/main/java/biz/nellemann/hmci/pcm/ServerProcessor.java +++ b/src/main/java/biz/nellemann/hmci/pcm/ServerProcessor.java @@ -1,12 +1,19 @@ package biz.nellemann.hmci.pcm; -import java.util.List; +import com.serjltt.moshi.adapters.FirstElement; public class ServerProcessor { - List totalProcUnits; - List utilizedProcUnits; - List availableProcUnits; - List configurableProcUnits; + @FirstElement + public Number totalProcUnits; + + @FirstElement + public Number utilizedProcUnits; + + @FirstElement + public Number availableProcUnits; + + @FirstElement + public Number configurableProcUnits; } diff --git a/src/main/java/biz/nellemann/hmci/pcm/ServerUtil.java b/src/main/java/biz/nellemann/hmci/pcm/ServerUtil.java index 2b027b6..ea6778f 100644 --- a/src/main/java/biz/nellemann/hmci/pcm/ServerUtil.java +++ b/src/main/java/biz/nellemann/hmci/pcm/ServerUtil.java @@ -4,9 +4,9 @@ import java.util.List; public class ServerUtil { - ServerProcessor processor; - ServerMemory memory; - PhysicalProcessorPool physicalProcessorPool; - List sharedProcessorPool; + public ServerProcessor processor; + public ServerMemory memory; + public PhysicalProcessorPool physicalProcessorPool; + public List sharedProcessorPool; } diff --git a/src/main/java/biz/nellemann/hmci/pcm/SharedAdapter.java b/src/main/java/biz/nellemann/hmci/pcm/SharedAdapter.java index 5ba0e07..5a481e9 100644 --- a/src/main/java/biz/nellemann/hmci/pcm/SharedAdapter.java +++ b/src/main/java/biz/nellemann/hmci/pcm/SharedAdapter.java @@ -1,18 +1,32 @@ package biz.nellemann.hmci.pcm; -import java.util.List; +import com.serjltt.moshi.adapters.FirstElement; public class SharedAdapter { - String id; - String type; - String physicalLocation; - List receivedPackets; - List sentPackets; - List droppedPackets; - List sentBytes; - List receivedBytes; - List transferredBytes; - List bridgedAdapters; + public String id; + public String type; + public String physicalLocation; + + @FirstElement + public Number receivedPackets; + + @FirstElement + public Number sentPackets; + + @FirstElement + public Number droppedPackets; + + @FirstElement + public Number sentBytes; + + @FirstElement + public Number receivedBytes; + + @FirstElement + public Number transferredBytes; + + @FirstElement + public String bridgedAdapters; } diff --git a/src/main/java/biz/nellemann/hmci/pcm/SharedProcessorPool.java b/src/main/java/biz/nellemann/hmci/pcm/SharedProcessorPool.java index 5d86d38..6947081 100644 --- a/src/main/java/biz/nellemann/hmci/pcm/SharedProcessorPool.java +++ b/src/main/java/biz/nellemann/hmci/pcm/SharedProcessorPool.java @@ -1,15 +1,25 @@ package biz.nellemann.hmci.pcm; -import java.util.List; +import com.serjltt.moshi.adapters.FirstElement; public class SharedProcessorPool { - String id; - String name; - List assignedProcUnits; - List utilizedProcUnits; - List availableProcUnits; - List configuredProcUnits; - List borrowedProcUnits; + public String id; + public String name; + + @FirstElement + public Number assignedProcUnits; + + @FirstElement + public Number utilizedProcUnits; + + @FirstElement + public Number availableProcUnits; + + @FirstElement + public Number configuredProcUnits; + + @FirstElement + public Number borrowedProcUnits; } diff --git a/src/main/java/biz/nellemann/hmci/pcm/Storage.java b/src/main/java/biz/nellemann/hmci/pcm/Storage.java index 8c854ac..66c6c85 100644 --- a/src/main/java/biz/nellemann/hmci/pcm/Storage.java +++ b/src/main/java/biz/nellemann/hmci/pcm/Storage.java @@ -1,13 +1,15 @@ package biz.nellemann.hmci.pcm; +import java.util.ArrayList; import java.util.List; +import java.util.Optional; public class Storage { - List clientLpars; - List genericPhysicalAdapters; - List genericVirtualAdapters; - List fiberChannelAdapters; - List virtualFiberChannelAdapters; + public List clientLpars = new ArrayList<>(); + public List genericPhysicalAdapters = new ArrayList<>(); + public List genericVirtualAdapters = new ArrayList<>(); + public List fiberChannelAdapters = new ArrayList<>(); + public List virtualFiberChannelAdapters = new ArrayList<>(); } diff --git a/src/main/java/biz/nellemann/hmci/pcm/SystemUtil.java b/src/main/java/biz/nellemann/hmci/pcm/SystemUtil.java index f2eedb6..783cb93 100644 --- a/src/main/java/biz/nellemann/hmci/pcm/SystemUtil.java +++ b/src/main/java/biz/nellemann/hmci/pcm/SystemUtil.java @@ -1,10 +1,14 @@ package biz.nellemann.hmci.pcm; -import java.util.List; +import com.serjltt.moshi.adapters.FirstElement; +import com.squareup.moshi.Json; public class SystemUtil { - UtilInfo utilInfo; - public List utilSamples; + public UtilInfo utilInfo; + + @FirstElement + @Json(name = "utilSamples") + public UtilSample sample; } diff --git a/src/main/java/biz/nellemann/hmci/pcm/UtilInfo.java b/src/main/java/biz/nellemann/hmci/pcm/UtilInfo.java index b8ceaa2..8a3271a 100644 --- a/src/main/java/biz/nellemann/hmci/pcm/UtilInfo.java +++ b/src/main/java/biz/nellemann/hmci/pcm/UtilInfo.java @@ -4,14 +4,14 @@ import java.util.List; public class UtilInfo { - String version; - String metricType; - Integer frequency; - String startTimeStamp; - String endTimeStamp; - String mtms; - String name; - String uuid; - List metricArrayOrder; + public String version; + public String metricType; + public Integer frequency; + public String startTimeStamp; + public String endTimeStamp; + public String mtms; + public String name; + public String uuid; + public List metricArrayOrder; } diff --git a/src/main/java/biz/nellemann/hmci/pcm/UtilSample.java b/src/main/java/biz/nellemann/hmci/pcm/UtilSample.java index 6298c6c..5652644 100644 --- a/src/main/java/biz/nellemann/hmci/pcm/UtilSample.java +++ b/src/main/java/biz/nellemann/hmci/pcm/UtilSample.java @@ -1,13 +1,28 @@ package biz.nellemann.hmci.pcm; +import com.serjltt.moshi.adapters.FirstElement; + +import java.util.ArrayList; import java.util.List; public class UtilSample { - String sampleType; + public String sampleType; public SampleInfo sampleInfo; - ServerUtil serverUtil; - List viosUtil; - List lparsUtil; + public ServerUtil serverUtil; + public List viosUtil = new ArrayList<>(); + + @FirstElement + public LparUtil lparsUtil; + + /* + public LparUtil getLparsUtil() { + if(lparsUtil == null || lparsUtil.isEmpty()) { + return new LparUtil(); + } else { + return lparsUtil.get(0); + } + }*/ + } diff --git a/src/main/java/biz/nellemann/hmci/pcm/ViosMemory.java b/src/main/java/biz/nellemann/hmci/pcm/ViosMemory.java index 449299d..8643321 100644 --- a/src/main/java/biz/nellemann/hmci/pcm/ViosMemory.java +++ b/src/main/java/biz/nellemann/hmci/pcm/ViosMemory.java @@ -1,10 +1,13 @@ package biz.nellemann.hmci.pcm; -import java.util.List; +import com.serjltt.moshi.adapters.FirstElement; public class ViosMemory { - List assignedMem; - List utilizedMem; + @FirstElement + public Number assignedMem; + + @FirstElement + public Number utilizedMem; } diff --git a/src/main/java/biz/nellemann/hmci/pcm/ViosUtil.java b/src/main/java/biz/nellemann/hmci/pcm/ViosUtil.java index ff5fce3..178b39e 100644 --- a/src/main/java/biz/nellemann/hmci/pcm/ViosUtil.java +++ b/src/main/java/biz/nellemann/hmci/pcm/ViosUtil.java @@ -2,15 +2,15 @@ package biz.nellemann.hmci.pcm; public class ViosUtil { - String id; - String uuid; - String name; - String state; - Integer affinityScore; + public String id; + public String uuid; + public String name; + public String state; + public Integer affinityScore; - ViosMemory memory; - LparProcessor processor; - Network network; - Storage storage; + public ViosMemory memory; + public LparProcessor processor; + public Network network; + public Storage storage; } diff --git a/src/main/java/biz/nellemann/hmci/pcm/VirtualEthernetAdapter.java b/src/main/java/biz/nellemann/hmci/pcm/VirtualEthernetAdapter.java index f1498a4..910e39b 100644 --- a/src/main/java/biz/nellemann/hmci/pcm/VirtualEthernetAdapter.java +++ b/src/main/java/biz/nellemann/hmci/pcm/VirtualEthernetAdapter.java @@ -1,26 +1,52 @@ package biz.nellemann.hmci.pcm; +import com.serjltt.moshi.adapters.FirstElement; + import java.util.List; public class VirtualEthernetAdapter { - String physicalLocation; - Integer vlanId; - Integer vswitchId; - Boolean isPortVlanId; - Integer viosId; - String sharedEthernetAdapterId; - List receivedPackets; - List sentPackets; - List droppedPackets; - List sentBytes; - List receivedBytes; - List receivedPhysicalPackets; - List sentPhysicalPackets; - List droppedPhysicalPackets; - List sentPhysicalBytes; - List receivedPhysicalBytes; - List transferredBytes; - List transferredPhysicalBytes; + public String physicalLocation; + public Integer vlanId; + public Integer vswitchId; + public Boolean isPortVlanId; + public Integer viosId; + public String sharedEthernetAdapterId; + + @FirstElement + public Number receivedPackets; + + @FirstElement + public Number sentPackets; + + @FirstElement + public Number droppedPackets; + + @FirstElement + 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; } diff --git a/src/main/java/biz/nellemann/hmci/pcm/VirtualFiberChannelAdapter.java b/src/main/java/biz/nellemann/hmci/pcm/VirtualFiberChannelAdapter.java index df3192a..3a3066c 100644 --- a/src/main/java/biz/nellemann/hmci/pcm/VirtualFiberChannelAdapter.java +++ b/src/main/java/biz/nellemann/hmci/pcm/VirtualFiberChannelAdapter.java @@ -4,16 +4,16 @@ import java.util.List; public class VirtualFiberChannelAdapter { - String wwpn; - String wwpn2; - String physicalLocation; - String physicalPortWWPN; - Integer viosId; - List numOfReads; - List numOfWrites; - List readBytes; - List writeBytes; - List runningSpeed; - List transmittedBytes; + public String wwpn; + public String wwpn2; + public String physicalLocation; + public String physicalPortWWPN; + public Integer viosId; + public List numOfReads; + public List numOfWrites; + public List readBytes; + public List writeBytes; + public List runningSpeed; + public List transmittedBytes; } diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index c394543..cee78fd 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -3,7 +3,7 @@ - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{12} - %msg%n + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{16} - %msg%n diff --git a/src/test/groovy/biz/nellemann/hmci/LogicalPartitionTest.groovy b/src/test/groovy/biz/nellemann/hmci/LogicalPartitionTest.groovy index 3445c82..9089ee7 100644 --- a/src/test/groovy/biz/nellemann/hmci/LogicalPartitionTest.groovy +++ b/src/test/groovy/biz/nellemann/hmci/LogicalPartitionTest.groovy @@ -17,9 +17,9 @@ class LogicalPartitionTest extends Specification { lpar.processMetrics(testJson) then: - lpar.metrics.systemUtil.utilSamples.first().lparsUtil.first().memory.logicalMem.first() == 8192.000 - lpar.metrics.systemUtil.utilSamples.first().lparsUtil.first().processor.utilizedProcUnits.first() == 0.001 - lpar.metrics.systemUtil.utilSamples.first().lparsUtil.first().network.virtualEthernetAdapters.first().receivedBytes.first() == 276.467 + lpar.metrics.systemUtil.sample.lparsUtil.memory.logicalMem == 8192.000 + lpar.metrics.systemUtil.sample.lparsUtil.processor.utilizedProcUnits == 0.001 + lpar.metrics.systemUtil.sample.lparsUtil.network.virtualEthernetAdapters.first().receivedBytes == 276.467 } diff --git a/src/test/groovy/biz/nellemann/hmci/ManagedSystemTest.groovy b/src/test/groovy/biz/nellemann/hmci/ManagedSystemTest.groovy index 9f58ffc..6643322 100644 --- a/src/test/groovy/biz/nellemann/hmci/ManagedSystemTest.groovy +++ b/src/test/groovy/biz/nellemann/hmci/ManagedSystemTest.groovy @@ -15,12 +15,12 @@ class ManagedSystemTest extends Specification { system.processMetrics(testJson) then: - system.metrics.systemUtil.utilSamples.first().serverUtil.memory.assignedMemToLpars.first() == 40960.000 - system.metrics.systemUtil.utilSamples.first().serverUtil.processor.totalProcUnits.first() == 24.000 - system.metrics.systemUtil.utilSamples.first().viosUtil.first().name == "VIOS1" - system.metrics.systemUtil.utilSamples.first().viosUtil.first().memory.assignedMem.first() == 8192.000 - system.metrics.systemUtil.utilSamples.first().viosUtil.first().storage.genericPhysicalAdapters.first().transmittedBytes.first() == 9966.933 - system.metrics.systemUtil.utilSamples.first().viosUtil.first().storage.fiberChannelAdapters.first().numOfPorts == 3 + system.metrics.systemUtil.sample.serverUtil.memory.assignedMemToLpars == 40960.000 + system.metrics.systemUtil.sample.serverUtil.processor.totalProcUnits == 24.000 + system.metrics.systemUtil.sample.viosUtil.first().name == "VIOS1" + system.metrics.systemUtil.sample.viosUtil.first().memory.assignedMem == 8192.0 + system.metrics.systemUtil.sample.viosUtil.first().storage.genericPhysicalAdapters.first().transmittedBytes == 9966.933 + system.metrics.systemUtil.sample.viosUtil.first().storage.fiberChannelAdapters.first().numOfPorts == 3 }