Major refactoring of xml+json deserialization.

Initial work for optionally moving hmc specific code into it's own library.
This commit is contained in:
Mark Nellemann 2022-11-24 12:35:49 +01:00
parent 4f341e0909
commit 930a1b982d
117 changed files with 16476 additions and 3290 deletions

View File

@ -2,11 +2,12 @@
All notable changes to this project will be documented in this file.
## [1.3.5] - 2022-11-08
## [1.3.4] - 2022-10-24
### Changed
- Updated 3rd party dependencies
## [1.3.3] - 2022-09-20
### Added
- Default configuration location on Windows platform.
@ -28,6 +29,7 @@ All notable changes to this project will be documented in this file.
### Added
- Options to include/exclude Managed Systems and/or Logical Partitions.
[1.3.5]: https://bitbucket.org/mnellemann/hmci/branches/compare/v1.3.5%0Dv1.3.4
[1.3.4]: https://bitbucket.org/mnellemann/hmci/branches/compare/v1.3.4%0Dv1.3.3
[1.3.3]: https://bitbucket.org/mnellemann/hmci/branches/compare/v1.3.3%0Dv1.3.0
[1.3.0]: https://bitbucket.org/mnellemann/hmci/branches/compare/v1.3.0%0Dv1.2.8

View File

@ -9,7 +9,7 @@ Metrics includes:
- *Managed Systems* - the physical Power servers
- *Logical Partitions* - the virtualized servers running AIX, Linux or IBM-i (AS/400)
- *Virtual I/O Servers* - the i/o partition(s) virtualizing network and storage
- *Energy* - power consumption and temperatures (needs to be enabled and is not available on P7 and multi-chassis systems)
- *Energy* - watts and temperatures (needs to be enabled and is not available on P7 and multi-chassis systems)
![architecture](doc/HMCi.png)
@ -33,8 +33,11 @@ There are few steps in the installation.
- Navigate to *Users and Security*
- Create a new read-only/viewer **hmci** user, which will be used to connect to the HMC.
- Click *Manage User Profiles and Access*, edit the newly created *hmci* user and click *User Properties*:
- **Enable** *Allow remote access via the web*
- Set *Session timeout minutes* to **60**
- Set *Verify timeout minutes* to **15**
- Set *Idle timeout minutes* to **90**
- Set *Minimum time in days between password changes* to **0**
- **Enable** *Allow remote access via the web*
- Navigate to *HMC Management* and *Console Settings*
- Click *Change Performance Monitoring Settings*:
- Enable *Performance Monitoring Data Collection for Managed Servers*: **All On**
@ -63,17 +66,17 @@ Install *HMCi* on a host, that can connect to your Power HMC (on port 12443), an
- Ensure you have **correct date/time** and NTPd running to keep it accurate!
- The only requirement for **hmci** is the Java runtime, version 8 (or later)
- Install **HMCi** from [downloads](https://bitbucket.org/mnellemann/hmci/downloads/) (rpm, deb or jar) or build from source
- On RPM based systems: **sudo rpm -i hmci-x.y.z-n.noarch.rpm**
- On DEB based systems: **sudo dpkg -i hmci_x.y.z-n_all.deb**
- On RPM based systems: ```sudo rpm -ivh hmci-x.y.z-n.noarch.rpm```
- On DEB based systems: ```sudo dpkg -i hmci_x.y.z-n_all.deb```
- Copy the **/opt/hmci/doc/hmci.toml** configuration example into **/etc/hmci.toml** and edit the configuration to suit your environment. The location of the configuration file can optionally be changed with the *--conf* option.
- Run the **/opt/hmci/bin/hmci** program in a shell, as a @reboot cron task or configure as a proper service - there are instructions in the [doc/readme-service.md](doc/readme-service.md) file.
- When started, *hmci* expects the InfluxDB database to be created by you.
- When started, *hmci* expects the InfluxDB database to exist already.
### 4 - Grafana Configuration
- Configure Grafana to use InfluxDB as a new datasource
- **NOTE:** set *Min time interval* to *30s* or *1m* depending on your HMCi *refresh* setting.
- Import example dashboards from [doc/dashboards/*.json](doc/dashboards/) into Grafana as a starting point and get creative making your own cool dashboards :)
- Import example dashboards from [doc/dashboards/*.json](doc/dashboards/) into Grafana as a starting point and get creative making your own cool dashboards - please share anything useful :)
## Notes
@ -188,30 +191,30 @@ Use the gradle build tool, which will download all required dependencies:
### Local Testing
#### InfluxDB container
#### InfluxDB
Start the InfluxDB container:
```shell
docker run --name=influxdb --rm -d -p 8086:8086 influxdb:1.8-alpine
docker run --name=influxdb --rm -d -p 8086:8086 influxdb:1.8
```
To execute the Influx client from within the container:
Create the *hmci* database:
```shell
docker exec -it influxdb influx
docker exec -i influxdb influx -execute "CREATE DATABASE hmci"
```
#### Grafana container
#### Grafana
Start the Grafana container, linking it to the InfluxDB container:
```shell
docker run --name grafana --link influxdb:influxdb --rm -d -p 3000:3000 grafana/grafana:7.1.3
docker run --name grafana --link influxdb:influxdb --rm -d -p 3000:3000 grafana/grafana
```
Setup Grafana to connect to the InfluxDB container by defining a new datasource on URL *http://influxdb:8086* named *hmci*.
The hmci database must be created beforehand, which can be done by running the hmci tool first.
Grafana dashboards can be imported from the *doc/* folder.

View File

@ -1,4 +1,4 @@
image: openjdk:8
image: eclipse-temurin:8-jdk
pipelines:
branches:

View File

@ -20,25 +20,26 @@ group = projectGroup
version = projectVersion
dependencies {
annotationProcessor 'info.picocli:picocli-codegen:4.6.3'
implementation 'info.picocli:picocli:4.6.3'
implementation 'org.jsoup:jsoup:1.15.3'
implementation 'com.squareup.okhttp3:okhttp:4.10.0'
implementation 'com.squareup.moshi:moshi:1.14.0'
implementation 'com.serjltt.moshi:moshi-lazy-adapters:2.2'
implementation 'org.tomlj:tomlj:1.1.0'
annotationProcessor 'info.picocli:picocli-codegen:4.7.0'
implementation 'info.picocli:picocli:4.7.0'
implementation 'org.influxdb:influxdb-java:2.23'
implementation 'org.slf4j:slf4j-api:2.0.3'
implementation 'org.slf4j:slf4j-simple:2.0.3'
//implementation 'com.influxdb:influxdb-client-java:6.7.0'
implementation 'org.slf4j:slf4j-api:2.0.4'
implementation 'org.slf4j:slf4j-simple:2.0.4'
implementation 'com.squareup.okhttp3:okhttp:4.10.0' // Also used by InfluxDB Client
//implementation "org.eclipse.jetty:jetty-client:9.4.49.v20220914"
implementation 'com.fasterxml.jackson.core:jackson-databind:2.14.1'
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.14.1'
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-toml:2.14.1'
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.spockframework:spock-core:2.3-groovy-3.0'
testImplementation 'com.squareup.okhttp3:mockwebserver:4.10.0'
testImplementation 'org.slf4j:slf4j-simple:2.0.3'
testImplementation "org.mock-server:mockserver-netty-no-dependencies:5.14.0"
}
application {
mainClass.set('biz.nellemann.hmci.Application')
applicationDefaultJvmArgs = [ "-server", "-Xms64m", "-Xmx64m", "-XX:+UseG1GC" ]
applicationDefaultJvmArgs = [ "-server", "-Xms64m", "-Xmx64m", "-XX:+UseG1GC", "-XX:+ExitOnOutOfMemoryError", "-XX:+AlwaysPreTouch" ]
}
java {
@ -50,6 +51,7 @@ test {
useJUnitPlatform()
}
apply plugin: 'nebula.ospackage'
ospackage {
packageName = 'hmci'
@ -104,7 +106,7 @@ jacocoTestCoverageVerification {
violationRules {
rule {
limit {
minimum = 0.5
minimum = 0.4
}
}
}

View File

@ -1,16 +1,6 @@
# HMCi Configuration
# Copy this file into /etc/hmci.toml and customize it to your environment.
###
### General HMCi Settings
###
# How often to query HMC's for data - in seconds
hmci.update = 30
# Rescan HMC's for new systems and partitions - every x update
hmci.rescan = 120
###
### Define one InfluxDB to save metrics into
@ -34,15 +24,17 @@ database = "hmci"
url = "https://10.10.10.10:12443"
username = "hmci"
password = "hmcihmci"
unsafe = true # Ignore SSL cert. errors
refresh = 30 # How often to query HMC for data - in seconds
discover = 120 # Rescan HMC for new systems and partitions - in minutes
trust = true # Ignore SSL cert. errors (due to default self-signed cert. on HMC)
energy = true # Collect energy metrics on supported systems
# Another HMC example
#[hmc.site2]
#url = "https://10.10.10.30:12443"
#username = "user"
#password = "password"
#unsafe = false # When false, validate SSL/TLS cerfificate, default is true
#energy = false # When false, do not collect energy metrics, default is true
#trace = "/tmp/hmci-trace" # When present, store JSON metrics files from HMC into this folder
#excludeSystems = [ 'notThisSystem' ] # Collect metrics from all systems except those listed here
#includeSystems = [ 'onlyThisSystems' ] # Collcet metrics from no systems but those listed here

View File

@ -1,3 +1,3 @@
projectId = hmci
projectGroup = biz.nellemann.hmci
projectVersion = 1.3.4
projectVersion = 1.4.0

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@ -15,12 +15,13 @@
*/
package biz.nellemann.hmci;
import biz.nellemann.hmci.dto.toml.Configuration;
import com.fasterxml.jackson.dataformat.toml.TomlMapper;
import picocli.CommandLine;
import picocli.CommandLine.Option;
import picocli.CommandLine.Command;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
@ -45,9 +46,8 @@ public class Application implements Callable<Integer> {
@Override
public Integer call() throws IOException {
public Integer call() {
Configuration configuration;
InfluxClient influxClient;
List<Thread> threadList = new ArrayList<>();
@ -66,22 +66,39 @@ public class Application implements Callable<Integer> {
}
try {
configuration = new Configuration(configurationFile.toPath());
influxClient = new InfluxClient(configuration.getInflux());
TomlMapper mapper = new TomlMapper();
Configuration configuration = mapper.readerFor(Configuration.class)
.readValue(configurationFile);
influxClient = new InfluxClient(configuration.influx);
influxClient.login();
for(Configuration.HmcObject configHmc : configuration.getHmc()) {
Thread t = new Thread(new HmcInstance(configHmc, influxClient));
configuration.hmc.forEach((key, value) -> {
try {
ManagementConsole managementConsole = new ManagementConsole(value, influxClient);
Thread t = new Thread(managementConsole);
t.setName(key);
t.start();
threadList.add(t);
} catch (Exception e) {
System.err.println(e.getMessage());
}
});
/*
for(Configuration.HmcConfiguration configHmc : configuration.getHmc()) {
Thread t = new Thread(new ManagementConsole(configHmc, influxClient));
t.setName(configHmc.name);
t.start();
threadList.add(t);
}
}*/
for (Thread thread : threadList) {
thread.join();
}
} catch (InterruptedException | RuntimeException e) {
influxClient.logoff();
} catch (Exception e) {
System.err.println(e.getMessage());
return 1;
}

View File

@ -1,268 +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 org.tomlj.Toml;
import org.tomlj.TomlParseResult;
import org.tomlj.TomlTable;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
public final class Configuration {
final private Long update;
final private Long rescan;
final private InfluxObject influx;
final private List<HmcObject> hmcList;
Configuration(Path configurationFile) throws IOException {
TomlParseResult result = Toml.parse(configurationFile);
result.errors().forEach(error -> System.err.println(error.toString()));
if(result.contains("hmci.update")) {
update = result.getLong("hmci.update");
} else {
update = 30L;
}
if(result.contains("hmci.rescan")) {
rescan = result.getLong("hmci.rescan");
} else {
rescan = 60L;
}
hmcList = parseConfigurationForHmc(result);
influx = parseConfigurationForInflux(result);
}
private List<HmcObject> parseConfigurationForHmc(TomlParseResult result) {
ArrayList<HmcObject> list = new ArrayList<>();
if(result.contains("hmc") && result.isTable("hmc")) {
TomlTable hmcTable = result.getTable("hmc");
if(hmcTable == null) {
return list;
}
for(String key : hmcTable.keySet()) {
HmcObject c = new HmcObject();
c.name = key;
c.update = update;
c.rescan = rescan;
if(hmcTable.contains(key+".url")) {
c.url = hmcTable.getString(key+".url");
}
if(hmcTable.contains(key+".username")) {
c.username = hmcTable.getString(key+".username");
}
if(hmcTable.contains(key+".password")) {
c.password = hmcTable.getString(key+".password");
}
if(hmcTable.contains(key+".unsafe")) {
c.unsafe = hmcTable.getBoolean(key+".unsafe");
} else {
c.unsafe = false;
}
if(hmcTable.contains(key+".energy")) {
c.energy = hmcTable.getBoolean(key+".energy");
} else {
c.energy = true;
}
if(hmcTable.contains(key+".trace")) {
c.trace = hmcTable.getString(key+".trace");
} else {
c.trace = null;
}
if(hmcTable.contains(key+".excludeSystems")) {
List<Object> tmpList = hmcTable.getArrayOrEmpty(key+".excludeSystems").toList();
c.excludeSystems = tmpList.stream()
.map(object -> Objects.toString(object, null))
.collect(Collectors.toList());
} else {
c.excludeSystems = new ArrayList<>();
}
if(hmcTable.contains(key+".includeSystems")) {
List<Object> tmpList = hmcTable.getArrayOrEmpty(key+".includeSystems").toList();
c.includeSystems = tmpList.stream()
.map(object -> Objects.toString(object, null))
.collect(Collectors.toList());
} else {
c.includeSystems = new ArrayList<>();
}
if(hmcTable.contains(key+".excludePartitions")) {
List<Object> tmpList = hmcTable.getArrayOrEmpty(key+".excludePartitions").toList();
c.excludePartitions = tmpList.stream()
.map(object -> Objects.toString(object, null))
.collect(Collectors.toList());
} else {
c.excludePartitions = new ArrayList<>();
}
if(hmcTable.contains(key+".includePartitions")) {
List<Object> tmpList = hmcTable.getArrayOrEmpty(key+".includePartitions").toList();
c.includePartitions = tmpList.stream()
.map(object -> Objects.toString(object, null))
.collect(Collectors.toList());
} else {
c.includePartitions = new ArrayList<>();
}
list.add(c);
}
}
return list;
}
private InfluxObject parseConfigurationForInflux(TomlParseResult result) {
InfluxObject c = new InfluxObject();
if(result.contains("influx")) {
TomlTable t = result.getTable("influx");
if(t != null && t.contains("url")) {
c.url = t.getString("url");
}
if(t != null && t.contains("username")) {
c.username = t.getString("username");
}
if(t != null && t.contains("password")) {
c.password = t.getString("password");
}
if(t != null && t.contains("database")) {
c.database = t.getString("database");
}
}
return c;
}
public List<HmcObject> getHmc() {
return hmcList;
}
public InfluxObject getInflux() {
return influx;
}
static class InfluxObject {
String url = "http://localhost:8086";
String username = "root";
String password = "";
String database = "hmci";
private boolean validated = false;
InfluxObject() { }
InfluxObject(String url, String username, String password, String database) {
this.url = url;
this.username = username;
this.password = password;
this.database = database;
}
Boolean isValid() {
return validated;
}
// TODO: Implement validation
void validate() {
validated = true;
}
@Override
public String toString() {
return url;
}
}
static class HmcObject {
String name;
String url;
String username;
String password;
Boolean unsafe = false;
Boolean energy = true;
String trace;
List<String> excludeSystems;
List<String> includeSystems;
List<String> excludePartitions;
List<String> includePartitions;
Long update = 30L;
Long rescan = 60L;
private boolean validated = false;
HmcObject() { }
HmcObject(String name, String url, String username, String password, Boolean unsafe, Long update, Long rescan) {
this.url = url;
this.username = username;
this.password = password;
this.unsafe = unsafe;
this.update = update;
this.rescan = rescan;
}
Boolean isValid() {
return validated;
}
// TODO: Implement validation
void validate() {
validated = true;
}
@Override
public String toString() {
return name;
}
}
}

View File

@ -1,337 +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 biz.nellemann.hmci.Configuration.HmcObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import static java.lang.Thread.sleep;
class HmcInstance implements Runnable {
private final static Logger log = LoggerFactory.getLogger(HmcInstance.class);
private final String hmcId;
private final Long updateValue;
private final Long rescanValue;
private final Map<String,ManagedSystem> systems = new HashMap<>();
private final Map<String, LogicalPartition> partitions = new HashMap<>();
private final HmcRestClient hmcRestClient;
private final InfluxClient influxClient;
private final AtomicBoolean keepRunning = new AtomicBoolean(true);
private File traceDir;
private Boolean doTrace = false;
private Boolean doEnergy = true;
private List<String> excludeSystems;
private List<String> includeSystems;
private List<String> excludePartitions;
private List<String> includePartitions;
HmcInstance(HmcObject configHmc, InfluxClient influxClient) {
this.hmcId = configHmc.name;
this.updateValue = configHmc.update;
this.rescanValue = configHmc.rescan;
this.doEnergy = configHmc.energy;
this.influxClient = influxClient;
hmcRestClient = new HmcRestClient(configHmc.url, configHmc.username, configHmc.password, configHmc.unsafe);
log.debug("HmcInstance() - id: {}, update: {}, refresh {}", hmcId, updateValue, rescanValue);
if(configHmc.trace != null) {
try {
traceDir = new File(configHmc.trace);
traceDir.mkdirs();
if(traceDir.canWrite()) {
doTrace = true;
} else {
log.warn("HmcInstance() - can't write to trace dir: " + traceDir.toString());
}
} catch (Exception e) {
log.error("HmcInstance() - trace error: " + e.getMessage());
}
}
this.excludeSystems = configHmc.excludeSystems;
this.includeSystems = configHmc.includeSystems;
this.excludePartitions = configHmc.excludePartitions;
this.includePartitions = configHmc.includePartitions;
}
@Override
public String toString() {
return hmcId;
}
@Override
public void run() {
log.trace("run() - " + hmcId);
int executions = 0;
discover();
do {
Instant instantStart = Instant.now();
try {
if (doEnergy) {
getMetricsForEnergy();
}
getMetricsForSystems();
getMetricsForPartitions();
writeMetricsForSystemEnergy();
writeMetricsForManagedSystems();
writeMetricsForLogicalPartitions();
//influxClient.writeBatchPoints();
// Refresh
if (++executions > rescanValue) {
executions = 0;
discover();
}
} catch (Exception e) {
log.error("run() - fatal error: {}", e.getMessage());
keepRunning.set(false);
throw new RuntimeException(e);
}
Instant instantEnd = Instant.now();
long timeSpend = Duration.between(instantStart, instantEnd).toMillis();
log.trace("run() - duration millis: " + timeSpend);
if(timeSpend < (updateValue * 1000)) {
try {
long sleepTime = (updateValue * 1000) - timeSpend;
log.trace("run() - sleeping millis: " + sleepTime);
if(sleepTime > 0) {
//noinspection BusyWait
sleep(sleepTime);
}
} catch (InterruptedException e) {
log.error("run() - sleep interrupted", e);
}
} else {
log.warn("run() - possible slow response from this HMC");
}
} while (keepRunning.get());
// Logout of HMC
try {
hmcRestClient.logoff();
} catch (IOException e) {
log.warn("run() - error logging out of HMC: " + e.getMessage());
}
}
void discover() {
log.info("discover() - Querying HMC for Managed Systems and Logical Partitions");
Map<String, LogicalPartition> tmpPartitions = new HashMap<>();
try {
hmcRestClient.login();
hmcRestClient.getManagedSystems().forEach((systemId, system) -> {
// Add to list of known systems
if(!systems.containsKey(systemId)) {
// Check excludeSystems and includeSystems
if(!excludeSystems.contains(system.name) && includeSystems.isEmpty()) {
systems.put(systemId, system);
log.info("discover() - ManagedSystem: {}", system);
if (doEnergy) {
hmcRestClient.enableEnergyMonitoring(system);
}
} else if(!includeSystems.isEmpty() && includeSystems.contains(system.name)) {
systems.put(systemId, system);
log.info("discover() - ManagedSystem (include): {}", system);
if (doEnergy) {
hmcRestClient.enableEnergyMonitoring(system);
}
} else {
log.debug("discover() - Skipping ManagedSystem: {}", system);
}
}
// Get partitions for this system
try {
tmpPartitions.putAll(hmcRestClient.getLogicalPartitionsForManagedSystem(system));
if(!tmpPartitions.isEmpty()) {
partitions.clear();
//partitions.putAll(tmpPartitions);
tmpPartitions.forEach((lparKey, lpar) -> {
if(!excludePartitions.contains(lpar.name) && includePartitions.isEmpty()) {
partitions.put(lparKey, lpar);
log.info("discover() - LogicalPartition: {}", lpar);
} else if(!includePartitions.isEmpty() && includePartitions.contains(lpar.name)) {
partitions.put(lparKey, lpar);
log.info("discover() - LogicalPartition (include): {}", lpar);
} else {
log.debug("discover() - Skipping LogicalPartition: {}", lpar);
}
});
}
} catch (Exception e) {
log.warn("discover() - getLogicalPartitions error: {}", e.getMessage());
}
});
} catch(Exception e) {
log.warn("discover() - getManagedSystems error: {}", e.getMessage());
}
}
void getMetricsForSystems() {
systems.forEach((systemId, system) -> {
// Get and process metrics for this system
String tmpJsonString = null;
try {
tmpJsonString = hmcRestClient.getPcmDataForManagedSystem(system);
} catch (Exception e) {
log.warn("getMetricsForSystems() - error: {}", e.getMessage());
}
if(tmpJsonString != null && !tmpJsonString.isEmpty()) {
system.processMetrics(tmpJsonString);
if(doTrace) {
writeTraceFile(systemId, tmpJsonString);
}
}
});
}
void getMetricsForPartitions() {
try {
// Get partitions for this system
partitions.forEach((partitionId, partition) -> {
// Get and process metrics for this partition
String tmpJsonString2 = null;
try {
tmpJsonString2 = hmcRestClient.getPcmDataForLogicalPartition(partition);
} catch (Exception e) {
log.warn("getMetricsForPartitions() - getPcmDataForLogicalPartition error: {}", e.getMessage());
}
if(tmpJsonString2 != null && !tmpJsonString2.isEmpty()) {
partition.processMetrics(tmpJsonString2);
if(doTrace) {
writeTraceFile(partitionId, tmpJsonString2);
}
}
});
} catch(Exception e) {
log.warn("getMetricsForPartitions() - error: {}", e.getMessage());
}
}
void getMetricsForEnergy() {
systems.forEach((systemId, system) -> {
// Get and process metrics for this system
String tmpJsonString = null;
try {
tmpJsonString = hmcRestClient.getPcmDataForEnergy(system.energy);
} catch (Exception e) {
log.warn("getMetricsForEnergy() - error: {}", e.getMessage());
}
if(tmpJsonString != null && !tmpJsonString.isEmpty()) {
system.energy.processMetrics(tmpJsonString);
}
});
}
void writeMetricsForManagedSystems() {
try {
systems.forEach((systemId, system) -> influxClient.writeManagedSystem(system));
} catch (NullPointerException npe) {
log.warn("writeMetricsForManagedSystems() - NPE: {}", npe.getMessage(), npe);
}
}
void writeMetricsForLogicalPartitions() {
try {
partitions.forEach((partitionId, partition) -> influxClient.writeLogicalPartition(partition));
} catch (NullPointerException npe) {
log.warn("writeMetricsForLogicalPartitions() - NPE: {}", npe.getMessage(), npe);
}
}
void writeMetricsForSystemEnergy() {
try {
systems.forEach((systemId, system) -> influxClient.writeSystemEnergy(system.energy));
} catch (NullPointerException npe) {
log.warn("writeMetricsForSystemEnergy() - NPE: {}", npe.getMessage(), npe);
}
}
private void writeTraceFile(String id, String json) {
String fileName = String.format("%s-%s.json", id, Instant.now().toString());
try {
log.debug("Writing trace file: " + fileName);
File traceFile = new File(traceDir, fileName);
BufferedWriter writer = new BufferedWriter(new FileWriter(traceFile));
writer.write(json);
writer.close();
} catch (IOException e) {
log.warn("writeTraceFile() - " + e.getMessage());
}
}
}

View File

@ -1,545 +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 okhttp3.*;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Entities;
import org.jsoup.parser.Parser;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.*;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
public class HmcRestClient {
private final static Logger log = LoggerFactory.getLogger(HmcRestClient.class);
private final MediaType MEDIA_TYPE_IBM_XML_LOGIN = MediaType.parse("application/vnd.ibm.powervm.web+xml; type=LogonRequest");
protected Integer responseErrors = 0;
protected String authToken;
private final OkHttpClient client;
// OkHttpClient timeouts
private final static int CONNECT_TIMEOUT = 30;
private final static int WRITE_TIMEOUT = 30;
private final static int READ_TIMEOUT = 180;
private final String baseUrl;
private final String username;
private final String password;
HmcRestClient(String url, String username, String password, Boolean unsafe) {
this.baseUrl = url;
this.username = username;
this.password = password;
if(unsafe) {
this.client = getUnsafeOkHttpClient();
} else {
this.client = getSafeOkHttpClient();
}
}
@Override
public String toString() {
return baseUrl;
}
/**
* Logon to the HMC and get an authentication token for further requests.
*/
synchronized void login() throws Exception {
log.debug("Connecting to HMC - " + baseUrl);
logoff();
StringBuilder payload = new StringBuilder();
payload.append("<?xml version='1.0' encoding='UTF-8' standalone='yes'?>");
payload.append("<LogonRequest xmlns='http://www.ibm.com/xmlns/systems/power/firmware/web/mc/2012_10/' schemaVersion='V1_0'>");
payload.append("<UserID>").append(username).append("</UserID>");
payload.append("<Password>").append(password).append("</Password>");
payload.append("</LogonRequest>");
try {
URL url = new URL(String.format("%s/rest/api/web/Logon", baseUrl));
Request request = new Request.Builder()
.url(url)
.addHeader("Accept", "application/vnd.ibm.powervm.web+xml; type=LogonResponse")
.addHeader("X-Audit-Memento", "hmci")
.put(RequestBody.create(payload.toString(), MEDIA_TYPE_IBM_XML_LOGIN))
.build();
Response response = client.newCall(request).execute();
String responseBody = Objects.requireNonNull(response.body()).string();
if (!response.isSuccessful()) {
log.warn("login() - Unexpected response: {}", response.code());
throw new IOException("Unexpected code: " + response);
}
Document doc = Jsoup.parse(responseBody);
authToken = doc.select("X-API-Session").text();
log.debug("login() - Auth Token: " + authToken);
} catch (MalformedURLException e) {
log.error("login() - URL Error: {}", e.getMessage());
throw e;
} catch (Exception e) {
log.error("login() - Error: {}", e.getMessage());
throw e;
}
}
/**
* Logoff from the HMC and remove any session
*
*/
synchronized void logoff() throws IOException {
if(authToken == null) {
return;
}
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")
.addHeader("X-API-Session", authToken)
.delete()
.build();
try {
client.newCall(request).execute();
} catch (IOException e) {
log.warn("logoff() error: {}", e.getMessage());
} finally {
authToken = null;
}
}
/**
* Return Map of ManagedSystems seen by this HMC
*
* @return Map of system-id and ManagedSystem
*/
Map<String, ManagedSystem> getManagedSystems() throws Exception {
URL url = new URL(String.format("%s/rest/api/uom/ManagedSystem", baseUrl));
String responseBody = sendGetRequest(url);
Map<String,ManagedSystem> managedSystemsMap = new HashMap<>();
// Do not try to parse empty response
if(responseBody == null || responseBody.length() <= 1) {
responseErrors++;
return managedSystemsMap;
}
try {
Document doc = Jsoup.parse(responseBody);
Elements managedSystems = doc.select("ManagedSystem|ManagedSystem"); // doc.select("img[src$=.png]");
for(Element el : managedSystems) {
ManagedSystem system = new ManagedSystem(
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.debug("getManagedSystems() - Found system: {}", system);
}
} catch(Exception e) {
log.warn("getManagedSystems() - XML parse error", e);
}
return managedSystemsMap;
}
/**
* Return Map of LogicalPartitions seen by a ManagedSystem on this HMC
* @param system a valid ManagedSystem
* @return Map of partition-id and LogicalPartition
*/
Map<String, LogicalPartition> getLogicalPartitionsForManagedSystem(ManagedSystem system) throws Exception {
URL url = new URL(String.format("%s/rest/api/uom/ManagedSystem/%s/LogicalPartition", baseUrl, system.id));
String responseBody = sendGetRequest(url);
Map<String, LogicalPartition> partitionMap = new HashMap<>();
// Do not try to parse empty response
if(responseBody == null || responseBody.length() <= 1) {
responseErrors++;
return partitionMap;
}
try {
Document doc = Jsoup.parse(responseBody);
Elements logicalPartitions = doc.select("LogicalPartition|LogicalPartition");
for(Element el : logicalPartitions) {
LogicalPartition logicalPartition = new LogicalPartition(
el.select("PartitionUUID").text(),
el.select("PartitionName").text(),
el.select("PartitionType").text(),
system
);
partitionMap.put(logicalPartition.id, logicalPartition);
log.debug("getLogicalPartitionsForManagedSystem() - Found partition: {}", logicalPartition);
}
} catch(Exception e) {
log.warn("getLogicalPartitionsForManagedSystem() - XML parse error: {}", system, e);
}
return partitionMap;
}
/**
* Parse XML feed to get PCM Data in JSON format
* @param system a valid ManagedSystem
* @return JSON string with PCM data for this ManagedSystem
*/
String getPcmDataForManagedSystem(ManagedSystem system) throws Exception {
log.trace("getPcmDataForManagedSystem() - {}", system.id);
URL url = new URL(String.format("%s/rest/api/pcm/ManagedSystem/%s/ProcessedMetrics?NoOfSamples=1", baseUrl, system.id));
String responseBody = sendGetRequest(url);
String jsonBody = null;
// Do not try to parse empty response
if(responseBody == null || responseBody.length() <= 1) {
responseErrors++;
log.warn("getPcmDataForManagedSystem() - empty response, skipping: {}", system.name);
return null;
}
try {
Document doc = Jsoup.parse(responseBody);
Element entry = doc.select("feed > entry").first();
Element link = Objects.requireNonNull(entry).select("link[href]").first();
if(Objects.requireNonNull(link).attr("type").equals("application/json")) {
String href = link.attr("href");
log.trace("getPcmDataForManagedSystem() - URL: {}", href);
jsonBody = sendGetRequest(new URL(href));
}
} catch(Exception e) {
log.warn("getPcmDataForManagedSystem() - XML parse error: {}", system, e);
}
return jsonBody;
}
/**
* Parse XML feed to get PCM Data in JSON format
* @param partition a valid LogicalPartition
* @return JSON string with PCM data for this LogicalPartition
*/
String getPcmDataForLogicalPartition(LogicalPartition partition) throws Exception {
log.trace("getPcmDataForLogicalPartition() - {} @ {}", 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));
String responseBody = sendGetRequest(url);
String jsonBody = null;
// Do not try to parse empty response
if(responseBody == null || responseBody.length() <= 1) {
responseErrors++;
log.warn("getPcmDataForLogicalPartition() - empty response, skipping: {}", partition.name);
return null;
}
try {
Document doc = Jsoup.parse(responseBody);
Element entry = doc.select("feed > entry").first();
Element link = Objects.requireNonNull(entry).select("link[href]").first();
if(Objects.requireNonNull(link).attr("type").equals("application/json")) {
String href = link.attr("href");
log.trace("getPcmDataForLogicalPartition() - URL: {}", href);
jsonBody = sendGetRequest(new URL(href));
}
} catch(Exception e) {
log.warn("getPcmDataForLogicalPartition() - XML parse error: {}", partition.id, e);
}
return jsonBody;
}
/**
* Parse XML feed to get PCM Data in JSON format.
* Does not work for older HMC (pre v9) and older Power server (pre Power 8).
* @param systemEnergy a valid SystemEnergy
* @return JSON string with PCM data for this SystemEnergy
*/
String getPcmDataForEnergy(SystemEnergy systemEnergy) throws Exception {
log.trace("getPcmDataForEnergy() - " + systemEnergy.system.id);
URL url = new URL(String.format("%s/rest/api/pcm/ManagedSystem/%s/ProcessedMetrics?Type=Energy&NoOfSamples=1", baseUrl, systemEnergy.system.id));
String responseBody = sendGetRequest(url);
String jsonBody = null;
//log.info(responseBody);
// Do not try to parse empty response
if(responseBody == null || responseBody.length() <= 1) {
responseErrors++;
log.trace("getPcmDataForEnergy() - empty response, skipping: {}", systemEnergy);
return null;
}
try {
Document doc = Jsoup.parse(responseBody);
Element entry = doc.select("feed > entry").first();
Element link = Objects.requireNonNull(entry).select("link[href]").first();
if(Objects.requireNonNull(link).attr("type").equals("application/json")) {
String href = link.attr("href");
log.trace("getPcmDataForEnergy() - URL: {}", href);
jsonBody = sendGetRequest(new URL(href));
}
} catch(Exception e) {
log.warn("getPcmDataForEnergy() - XML parse error: {}", systemEnergy, e);
}
return jsonBody;
}
/**
* Set EnergyMonitorEnabled preference to true, if possible.
* @param system
*/
void enableEnergyMonitoring(ManagedSystem system) {
log.trace("enableEnergyMonitoring() - {}", system);
try {
URL url = new URL(String.format("%s/rest/api/pcm/ManagedSystem/%s/preferences", baseUrl, system.id));
String responseBody = sendGetRequest(url);
// Do not try to parse empty response
if(responseBody == null || responseBody.length() <= 1) {
responseErrors++;
log.warn("enableEnergyMonitoring() - empty response, skipping: {}", system);
return;
}
Document doc = Jsoup.parse(responseBody, "", Parser.xmlParser());
doc.outputSettings().escapeMode(Entities.EscapeMode.xhtml);
doc.outputSettings().prettyPrint(false);
doc.outputSettings().charset("US-ASCII");
Element entry = doc.select("feed > entry").first();
Element link1 = Objects.requireNonNull(entry).select("EnergyMonitoringCapable").first();
Element link2 = entry.select("EnergyMonitorEnabled").first();
if(Objects.requireNonNull(link1).text().equals("true")) {
log.debug("enableEnergyMonitoring() - EnergyMonitoringCapable == true");
if(Objects.requireNonNull(link2).text().equals("false")) {
//log.warn("enableEnergyMonitoring() - EnergyMonitorEnabled == false");
link2.text("true");
Document content = Jsoup.parse(Objects.requireNonNull(doc.select("Content").first()).html(), "", Parser.xmlParser());
content.outputSettings().escapeMode(Entities.EscapeMode.xhtml);
content.outputSettings().prettyPrint(false);
content.outputSettings().charset("UTF-8");
String updateXml = content.outerHtml();
sendPostRequest(url, updateXml);
}
} else {
log.warn("enableEnergyMonitoring() - EnergyMonitoringCapable == false");
}
} catch (Exception e) {
log.debug("enableEnergyMonitoring() - Error: {}", e.getMessage());
}
}
/**
* Return a Response from the HMC
* @param url to get Response from
* @return Response body string
*/
private String sendGetRequest(URL url) throws Exception {
log.trace("getResponse() - URL: {}", url.toString());
if(authToken == null) {
return null;
}
Request request = new Request.Builder()
.url(url)
.addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8")
.addHeader("X-API-Session", authToken)
.get().build();
Response response = client.newCall(request).execute();
String body = Objects.requireNonNull(response.body()).string();
if (!response.isSuccessful()) {
response.close();
if(response.code() == 401) {
log.warn("getResponse() - 401 - login and retry.");
authToken = null;
login();
return null;
}
log.error("getResponse() - Unexpected response: {}", response.code());
throw new IOException("getResponse() - Unexpected response: " + response.code());
}
return body;
}
/**
* Send a POST request with a payload (can be null) to the HMC
* @param url
* @param payload
* @return
* @throws Exception
*/
public String sendPostRequest(URL url, String payload) throws Exception {
log.trace("sendPostRequest() - URL: {}", url.toString());
if(authToken == null) {
return null;
}
RequestBody requestBody;
if(payload != null) {
//log.debug("sendPostRequest() - payload: " + payload);
requestBody = RequestBody.create(payload, MediaType.get("application/xml"));
} else {
requestBody = RequestBody.create("", null);
}
Request request = new Request.Builder()
.url(url)
//.addHeader("Content-Type", "application/xml")
.addHeader("content-type", "application/xml")
.addHeader("X-API-Session", authToken)
.post(requestBody).build();
Response response = client.newCall(request).execute();
String body = Objects.requireNonNull(response.body()).string();
if (!response.isSuccessful()) {
response.close();
log.warn(body);
log.error("sendPostRequest() - Unexpected response: {}", response.code());
throw new IOException("sendPostRequest() - Unexpected response: " + response.code());
}
return body;
}
/**
* Provide an unsafe (ignoring SSL problems) OkHttpClient
*
* @return OkHttpClient ignoring SSL/TLS errors
*/
private static OkHttpClient getUnsafeOkHttpClient() {
try {
// Create a trust manager that does not validate certificate chains
final TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) { }
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
}
};
// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new SecureRandom());
// Create a ssl socket factory with our all-trusting manager
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.sslSocketFactory(sslSocketFactory, (X509TrustManager)trustAllCerts[0]);
builder.hostnameVerifier((hostname, session) -> true);
builder.connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS);
builder.writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS);
builder.readTimeout(READ_TIMEOUT, TimeUnit.SECONDS);
return builder.build();
} catch (KeyManagementException | NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
/**
* Get OkHttpClient with our preferred timeout values.
* @return OkHttpClient
*/
private static OkHttpClient getSafeOkHttpClient() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS);
builder.writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS);
builder.readTimeout(READ_TIMEOUT, TimeUnit.SECONDS);
return builder.build();
}
}

View File

@ -15,7 +15,7 @@
*/
package biz.nellemann.hmci;
import biz.nellemann.hmci.Configuration.InfluxObject;
import biz.nellemann.hmci.dto.toml.InfluxConfiguration;
import org.influxdb.BatchOptions;
import org.influxdb.InfluxDB;
import org.influxdb.InfluxDBFactory;
@ -26,8 +26,6 @@ import org.slf4j.LoggerFactory;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;
import static java.lang.Thread.sleep;
@ -43,8 +41,7 @@ public final class InfluxClient {
private InfluxDB influxDB;
InfluxClient(InfluxObject config) {
InfluxClient(InfluxConfiguration config) {
this.url = config.url;
this.username = config.username;
this.password = config.password;
@ -74,8 +71,7 @@ public final class InfluxClient {
thread.setDaemon(true);
return thread;
})
); // (4)
);
Runtime.getRuntime().addShutdownHook(new Thread(influxDB::close));
connected = true;
@ -100,314 +96,27 @@ public final class InfluxClient {
influxDB = null;
}
/*
synchronized void writeBatchPoints() throws Exception {
log.trace("writeBatchPoints()");
try {
influxDB.write(batchPoints);
batchPoints = BatchPoints.database(database).precision(TimeUnit.SECONDS).build();
errorCounter = 0;
} catch (InfluxDBException.DatabaseNotFoundException e) {
log.error("writeBatchPoints() - database \"{}\" not found/created: can't write data", database);
if (++errorCounter > 3) {
throw new RuntimeException(e);
}
} catch (org.influxdb.InfluxDBIOException e) {
log.warn("writeBatchPoints() - io exception: {}", e.getMessage());
if(++errorCounter < 3) {
log.warn("writeBatchPoints() - reconnecting to InfluxDB due to io exception.");
logoff();
login();
writeBatchPoints();
} else {
throw new RuntimeException(e);
}
} catch(Exception e) {
log.warn("writeBatchPoints() - general exception: {}", e.getMessage());
if(++errorCounter < 3) {
log.warn("writeBatchPoints() - reconnecting to InfluxDB due to general exception.");
logoff();
login();
writeBatchPoints();
} else {
throw new RuntimeException(e);
}
}
}
*/
/*
Managed System
*/
void writeManagedSystem(ManagedSystem system) {
if(system.metrics == null) {
log.trace("writeManagedSystem() - null metrics, skipping: {}", system.name);
return;
}
Instant timestamp = system.getTimestamp();
if(timestamp == null) {
log.warn("writeManagedSystem() - no timestamp, skipping: {}", system.name);
return;
}
//getSystemDetails(system, timestamp).forEach( it -> batchPoints.point(it) );
getSystemDetails(system, timestamp).forEach( it -> influxDB.write(it));
//getSystemProcessor(system, timestamp).forEach( it -> batchPoints.point(it) );
getSystemProcessor(system, timestamp).forEach( it -> influxDB.write(it) );
//getSystemPhysicalProcessorPool(system, timestamp).forEach( it -> batchPoints.point(it) );
getSystemPhysicalProcessorPool(system, timestamp).forEach( it -> influxDB.write(it) );
//getSystemSharedProcessorPools(system, timestamp).forEach( it -> batchPoints.point(it) );
getSystemSharedProcessorPools(system, timestamp).forEach( it -> influxDB.write(it) );
//getSystemMemory(system, timestamp).forEach( it -> batchPoints.point(it) );
getSystemMemory(system, timestamp).forEach( it -> influxDB.write(it) );
//getSystemViosDetails(system, timestamp).forEach(it -> batchPoints.point(it) );
getSystemViosDetails(system, timestamp).forEach(it -> influxDB.write(it) );
//getSystemViosProcessor(system, timestamp).forEach( it -> batchPoints.point(it) );
getSystemViosProcessor(system, timestamp).forEach( it -> influxDB.write(it) );
//getSystemViosMemory(system, timestamp).forEach( it -> batchPoints.point(it) );
getSystemViosMemory(system, timestamp).forEach( it -> influxDB.write(it) );
//getSystemViosNetworkLpars(system, timestamp).forEach(it -> batchPoints.point(it) );
getSystemViosNetworkLpars(system, timestamp).forEach(it -> influxDB.write(it) );
//getSystemViosNetworkGenericAdapters(system, timestamp).forEach(it -> batchPoints.point(it) );
getSystemViosNetworkGenericAdapters(system, timestamp).forEach(it -> influxDB.write(it) );
//getSystemViosNetworkSharedAdapters(system, timestamp).forEach(it -> batchPoints.point(it) );
getSystemViosNetworkSharedAdapters(system, timestamp).forEach(it -> influxDB.write(it) );
//getSystemViosNetworkVirtualAdapters(system, timestamp).forEach(it -> batchPoints.point(it) );
getSystemViosNetworkVirtualAdapters(system, timestamp).forEach(it -> influxDB.write(it) );
//getSystemViosStorageLpars(system, timestamp).forEach(it -> batchPoints.point(it) );
getSystemViosStorageLpars(system, timestamp).forEach(it -> influxDB.write(it) );
//getSystemViosFiberChannelAdapters(system, timestamp).forEach(it -> batchPoints.point(it) );
getSystemViosFiberChannelAdapters(system, timestamp).forEach(it -> influxDB.write(it) );
//getSystemViosStoragePhysicalAdapters(system, timestamp).forEach(it -> batchPoints.point(it) );
getSystemViosStoragePhysicalAdapters(system, timestamp).forEach(it -> influxDB.write(it) );
//getSystemViosStorageVirtualAdapters(system, timestamp).forEach(it -> batchPoints.point(it) );
getSystemViosStorageVirtualAdapters(system, timestamp).forEach(it -> influxDB.write(it) );
public void write(List<Measurement> measurements, Instant timestamp, String measurement) {
log.debug("write() - measurement: {} {}", measurement, measurements.size());
processMeasurementMap(measurements, timestamp, measurement).forEach( (point) -> { influxDB.write(point); });
}
// TODO: server_details
private static List<Point> getSystemDetails(ManagedSystem system, Instant timestamp) {
List<Measurement> metrics = system.getDetails();
return processMeasurementMap(metrics, timestamp, "server_details");
}
private static List<Point> getSystemProcessor(ManagedSystem system, Instant timestamp) {
List<Measurement> metrics = system.getProcessorMetrics();
return processMeasurementMap(metrics, timestamp, "server_processor");
}
private static List<Point> getSystemPhysicalProcessorPool (ManagedSystem system, Instant timestamp) {
List<Measurement> metrics = system.getPhysicalProcessorPool();
return processMeasurementMap(metrics, timestamp, "server_physicalProcessorPool");
}
private static List<Point> getSystemSharedProcessorPools(ManagedSystem system, Instant timestamp) {
List<Measurement> metrics = system.getSharedProcessorPools();
return processMeasurementMap(metrics, timestamp, "server_sharedProcessorPool");
}
private static List<Point> getSystemMemory(ManagedSystem system, Instant timestamp) {
List<Measurement> metrics = system.getMemoryMetrics();
return processMeasurementMap(metrics, timestamp, "server_memory");
}
private static List<Point> getSystemViosDetails(ManagedSystem system, Instant timestamp) {
List<Measurement> metrics = system.getViosDetails();
return processMeasurementMap(metrics, timestamp, "vios_details");
}
private static List<Point> getSystemViosProcessor(ManagedSystem system, Instant timestamp) {
List<Measurement> metrics = system.getViosProcessorMetrics();
return processMeasurementMap(metrics, timestamp, "vios_processor");
}
private static List<Point> getSystemViosMemory(ManagedSystem system, Instant timestamp) {
List<Measurement> metrics = system.getViosMemoryMetrics();
return processMeasurementMap(metrics, timestamp, "vios_memory");
}
private static List<Point> getSystemViosNetworkLpars(ManagedSystem system, Instant timestamp) {
List<Measurement> metrics = system.getViosNetworkLpars();
return processMeasurementMap(metrics, timestamp, "vios_network_lpars");
}
private static List<Point> getSystemViosNetworkVirtualAdapters(ManagedSystem system, Instant timestamp) {
List<Measurement> metrics = system.getViosNetworkVirtualAdapters();
return processMeasurementMap(metrics, timestamp, "vios_network_virtual");
}
private static List<Point> getSystemViosNetworkSharedAdapters(ManagedSystem system, Instant timestamp) {
List<Measurement> metrics = system.getViosNetworkSharedAdapters();
return processMeasurementMap(metrics, timestamp, "vios_network_shared");
}
private static List<Point> getSystemViosNetworkGenericAdapters(ManagedSystem system, Instant timestamp) {
List<Measurement> metrics = system.getViosNetworkGenericAdapters();
return processMeasurementMap(metrics, timestamp, "vios_network_generic");
}
private static List<Point> getSystemViosStorageLpars(ManagedSystem system, Instant timestamp) {
List<Measurement> metrics = system.getViosStorageLpars();
return processMeasurementMap(metrics, timestamp, "vios_storage_lpars");
}
private static List<Point> getSystemViosFiberChannelAdapters(ManagedSystem system, Instant timestamp) {
List<Measurement> metrics = system.getViosStorageFiberChannelAdapters();
return processMeasurementMap(metrics, timestamp, "vios_storage_FC");
}
private static List<Point> getSystemViosSharedStoragePools(ManagedSystem system, Instant timestamp) {
List<Measurement> metrics = system.getViosStorageSharedStoragePools();
return processMeasurementMap(metrics, timestamp, "vios_storage_SSP");
}
private static List<Point> getSystemViosStoragePhysicalAdapters(ManagedSystem system, Instant timestamp) {
List<Measurement> metrics = system.getViosStoragePhysicalAdapters();
return processMeasurementMap(metrics, timestamp, "vios_storage_physical");
}
private static List<Point> getSystemViosStorageVirtualAdapters(ManagedSystem system, Instant timestamp) {
List<Measurement> metrics = system.getViosStorageVirtualAdapters();
return processMeasurementMap(metrics, timestamp, "vios_storage_vFC");
}
/*
Logical Partitions
*/
void writeLogicalPartition(LogicalPartition partition) {
if(partition.metrics == null) {
log.warn("writeLogicalPartition() - null metrics, skipping: {}", partition.name);
return;
}
Instant timestamp = partition.getTimestamp();
if(timestamp == null) {
log.warn("writeLogicalPartition() - no timestamp, skipping: {}", partition.name);
return;
}
//getPartitionDetails(partition, timestamp).forEach( it -> batchPoints.point(it));
getPartitionDetails(partition, timestamp).forEach( it -> influxDB.write(it));
//getPartitionMemory(partition, timestamp).forEach( it -> batchPoints.point(it));
getPartitionMemory(partition, timestamp).forEach( it -> influxDB.write(it));
//getPartitionProcessor(partition, timestamp).forEach( it -> batchPoints.point(it));
getPartitionProcessor(partition, timestamp).forEach( it -> influxDB.write(it));
//getPartitionNetworkVirtual(partition, timestamp).forEach(it -> batchPoints.point(it));
getPartitionNetworkVirtual(partition, timestamp).forEach(it -> influxDB.write(it));
getPartitionSriovLogicalPorts(partition, timestamp).forEach(it -> influxDB.write(it));
//getPartitionStorageVirtualGeneric(partition, timestamp).forEach(it -> batchPoints.point(it));
getPartitionStorageVirtualGeneric(partition, timestamp).forEach(it -> influxDB.write(it));
//getPartitionStorageVirtualFibreChannel(partition, timestamp).forEach(it -> batchPoints.point(it));
getPartitionStorageVirtualFibreChannel(partition, timestamp).forEach(it -> influxDB.write(it));
}
private static List<Point> getPartitionDetails(LogicalPartition partition, Instant timestamp) {
List<Measurement> metrics = partition.getDetails();
return processMeasurementMap(metrics, timestamp, "lpar_details");
}
private static List<Point> getPartitionProcessor(LogicalPartition partition, Instant timestamp) {
List<Measurement> metrics = partition.getProcessorMetrics();
return processMeasurementMap(metrics, timestamp, "lpar_processor");
}
private static List<Point> getPartitionMemory(LogicalPartition partition, Instant timestamp) {
List<Measurement> metrics = partition.getMemoryMetrics();
return processMeasurementMap(metrics, timestamp, "lpar_memory");
}
private static List<Point> getPartitionNetworkVirtual(LogicalPartition partition, Instant timestamp) {
List<Measurement> metrics = partition.getVirtualEthernetAdapterMetrics();
return processMeasurementMap(metrics, timestamp, "lpar_net_virtual"); // Not 'network'
}
private static List<Point> getPartitionSriovLogicalPorts(LogicalPartition partition, Instant timestamp) {
List<Measurement> metrics = partition.getSriovLogicalPorts();
return processMeasurementMap(metrics, timestamp, "lpar_net_sriov"); // Not 'network'
}
// TODO: lpar_net_sriov
private static List<Point> getPartitionStorageVirtualGeneric(LogicalPartition partition, Instant timestamp) {
List<Measurement> metrics = partition.getVirtualGenericAdapterMetrics();
return processMeasurementMap(metrics, timestamp, "lpar_storage_virtual");
}
private static List<Point> getPartitionStorageVirtualFibreChannel(LogicalPartition partition, Instant timestamp) {
List<Measurement> metrics = partition.getVirtualFibreChannelAdapterMetrics();
return processMeasurementMap(metrics, timestamp, "lpar_storage_vFC");
}
/*
System Energy
Not supported on older HMC (pre v8) or older Power server (pre Power 8)
*/
void writeSystemEnergy(SystemEnergy systemEnergy) {
if(systemEnergy.metrics == null) {
log.trace("writeSystemEnergy() - null metrics, skipping: {}", systemEnergy.system.name);
return;
}
Instant timestamp = systemEnergy.getTimestamp();
if(timestamp == null) {
log.warn("writeSystemEnergy() - no timestamp, skipping: {}", systemEnergy.system.name);
return;
}
//getSystemEnergyPower(systemEnergy, timestamp).forEach(it -> batchPoints.point(it) );
getSystemEnergyPower(systemEnergy, timestamp).forEach(it -> influxDB.write(it) );
//getSystemEnergyTemperature(systemEnergy, timestamp).forEach(it -> batchPoints.point(it) );
getSystemEnergyTemperature(systemEnergy, timestamp).forEach(it -> influxDB.write(it) );
}
private static List<Point> getSystemEnergyPower(SystemEnergy system, Instant timestamp) {
List<Measurement> metrics = system.getPowerMetrics();
return processMeasurementMap(metrics, timestamp, "server_energy_power");
}
private static List<Point> getSystemEnergyTemperature(SystemEnergy system, Instant timestamp) {
List<Measurement> metrics = system.getThermalMetrics();
return processMeasurementMap(metrics, timestamp, "server_energy_thermal");
}
/*
Shared
*/
private static List<Point> processMeasurementMap(List<Measurement> measurements, Instant timestamp, String measurement) {
private List<Point> processMeasurementMap(List<Measurement> measurements, Instant timestamp, String measurement) {
List<Point> listOfPoints = new ArrayList<>();
measurements.forEach( m -> {
measurements.forEach( (m) -> {
Point.Builder builder = Point.measurement(measurement)
.time(timestamp.getEpochSecond(), TimeUnit.SECONDS);
.time(timestamp.toEpochMilli(), TimeUnit.MILLISECONDS)
.tag(m.tags)
.fields(m.fields);
/*
// Iterate fields
m.fields.forEach((fieldName, fieldValue) -> {
log.trace("processMeasurementMap() {} - fieldName: {}, fieldValue: {}", measurement, fieldName, fieldValue);
log.info("processMeasurementMap() {} - fieldName: {}, fieldValue: {}", measurement, fieldName, fieldValue);
if(fieldValue instanceof Number) {
Number num = (Number) fieldValue;
builder.addField(fieldName, num);
@ -421,14 +130,18 @@ public final class InfluxClient {
});
// Iterate sorted tags
Map<String, String> sortedTags = new TreeMap<String, String>(m.tags);
Map<String, String> sortedTags = new TreeMap<>(m.tags);
sortedTags.forEach((tagName, tagValue) -> {
log.trace("processMeasurementMap() {} - tagName: {}, tagValue: {}", measurement, tagName, tagValue);
log.info("processMeasurementMap() {} - tagName: {}, tagValue: {}", measurement, tagName, tagValue);
builder.tag(tagName, tagValue);
});
*/
/*
if(m.fields.size() > 0 && m.tags.size() > 0) {
listOfPoints.add(builderbuilder.build());
}*/
listOfPoints.add(builder.build());
});
return listOfPoints;

View File

@ -15,57 +15,151 @@
*/
package biz.nellemann.hmci;
import biz.nellemann.hmci.dto.xml.Link;
import biz.nellemann.hmci.dto.xml.LogicalPartitionEntry;
import biz.nellemann.hmci.dto.xml.XmlEntry;
import biz.nellemann.hmci.dto.xml.XmlFeed;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
class LogicalPartition extends MetaSystem {
class LogicalPartition extends Resource {
private final static Logger log = LoggerFactory.getLogger(LogicalPartition.class);
public final String id;
public final String name;
public final String type;
public final ManagedSystem system;
private final RestClient restClient;
private final ManagedSystem managedSystem;
protected String id;
protected String name;
protected LogicalPartitionEntry entry;
private String uriPath;
LogicalPartition(String id, String name, String type, ManagedSystem system) {
this.id = id;
this.name = name;
this.type = type;
this.system = system;
public LogicalPartition(RestClient restClient, String href, ManagedSystem managedSystem) throws URISyntaxException {
log.debug("LogicalPartition() - {}", href);
this.restClient = restClient;
this.managedSystem = managedSystem;
try {
URI uri = new URI(href);
uriPath = uri.getPath();
} catch (URISyntaxException e) {
log.error("LogicalPartition() - {}", e.getMessage());
}
}
@Override
public String toString() {
return String.format("[%s] %s (%s)", id, name, type);
return entry.getName();
}
public void discover() {
try {
String xml = restClient.getRequest(uriPath);
// Do not try to parse empty response
if(xml == null || xml.length() <= 1) {
log.warn("discover() - no data.");
return;
}
XmlMapper xmlMapper = new XmlMapper();
XmlEntry xmlEntry = xmlMapper.readValue(xml, XmlEntry.class);
if(xmlEntry.getContent() == null){
log.warn("discover() - no content.");
return;
}
this.id = xmlEntry.id;
if(xmlEntry.getContent().isLogicalPartition()) {
entry = xmlEntry.getContent().getLogicalPartitionEntry();
this.name = entry.getName();
log.info("discover() - {}", entry.getName());
} else {
throw new UnsupportedOperationException("Failed to deserialize LogicalPartition");
}
} catch (Exception e) {
log.error("discover() - error: {}", e.getMessage());
}
}
public void refresh() {
log.debug("refresh()");
try {
String xml = restClient.getRequest(String.format("/rest/api/pcm/ManagedSystem/%s/LogicalPartition/%s/ProcessedMetrics?NoOfSamples=1", managedSystem.id, id));
// Do not try to parse empty response
if(xml == null || xml.length() <= 1) {
log.warn("refresh() - no data.");
return;
}
XmlMapper xmlMapper = new XmlMapper();
XmlFeed xmlFeed = xmlMapper.readValue(xml, XmlFeed.class);
xmlFeed.entries.forEach((entry) -> {
if(entry.category.term.equals("LogicalPartition")) {
Link link = entry.link;
if (link.getType() != null && Objects.equals(link.getType(), "application/json")) {
try {
URI jsonUri = URI.create(link.getHref());
String json = restClient.getRequest(jsonUri.getPath());
deserialize(json);
} catch (IOException e) {
log.error("refresh() - error 1: {}", e.getMessage());
}
}
}
});
} catch (IOException e) {
log.error("refresh() - error 2: {}", e.getMessage());
}
}
// LPAR Details
List<Measurement> getDetails() {
List<Measurement> list = new ArrayList<>();
Map<String, String> tagsMap = new HashMap<>();
tagsMap.put("servername", system.name);
tagsMap.put("lparname", name);
log.trace("getDetails() - tags: {}", tagsMap);
try {
Map<String, String> tagsMap = new HashMap<>();
TreeMap<String, Object> fieldsMap = new TreeMap<>();
Map<String, Object> fieldsMap = new HashMap<>();
fieldsMap.put("id", metrics.systemUtil.sample.lparsUtil.id);
fieldsMap.put("type", metrics.systemUtil.sample.lparsUtil.type);
fieldsMap.put("state", metrics.systemUtil.sample.lparsUtil.state);
fieldsMap.put("osType", metrics.systemUtil.sample.lparsUtil.osType);
fieldsMap.put("affinityScore", metrics.systemUtil.sample.lparsUtil.affinityScore);
log.trace("getDetails() - fields: {}", fieldsMap);
tagsMap.put("servername", managedSystem.entry.getName());
tagsMap.put("lparname", entry.getName());
log.trace("getDetails() - tags: " + tagsMap);
fieldsMap.put("id", metric.getSample().lparsUtil.id);
fieldsMap.put("type", metric.getSample().lparsUtil.type);
fieldsMap.put("state", metric.getSample().lparsUtil.state);
fieldsMap.put("osType", metric.getSample().lparsUtil.osType);
fieldsMap.put("affinityScore", metric.getSample().lparsUtil.affinityScore);
log.trace("getDetails() - fields: " + fieldsMap);
list.add(new Measurement(tagsMap, fieldsMap));
} catch (Exception e) {
log.warn("getDetails() - error: {}", e.getMessage());
}
list.add(new Measurement(tagsMap, fieldsMap));
return list;
}
@ -75,17 +169,22 @@ class LogicalPartition extends MetaSystem {
List<Measurement> list = new ArrayList<>();
Map<String, String> tagsMap = new HashMap<>();
tagsMap.put("servername", system.name);
tagsMap.put("lparname", name);
log.trace("getMemoryMetrics() - tags: {}", tagsMap);
try {
Map<String, String> tagsMap = new HashMap<>();
TreeMap<String, Object> fieldsMap = new TreeMap<>();
Map<String, Object> fieldsMap = new HashMap<>();
fieldsMap.put("logicalMem", metrics.systemUtil.sample.lparsUtil.memory.logicalMem);
fieldsMap.put("backedPhysicalMem", metrics.systemUtil.sample.lparsUtil.memory.backedPhysicalMem);
log.trace("getMemoryMetrics() - fields: {}", fieldsMap);
tagsMap.put("servername", managedSystem.entry.getName());
tagsMap.put("lparname", entry.getName());
log.trace("getMemoryMetrics() - tags: " + tagsMap);
list.add(new Measurement(tagsMap, fieldsMap));
fieldsMap.put("logicalMem", metric.getSample().lparsUtil.memory.logicalMem);
fieldsMap.put("backedPhysicalMem", metric.getSample().lparsUtil.memory.backedPhysicalMem);
log.trace("getMemoryMetrics() - fields: " + fieldsMap);
list.add(new Measurement(tagsMap, fieldsMap));
} catch (Exception e) {
log.warn("getMemoryMetrics() - error: {}", e.getMessage());
}
return list;
}
@ -95,29 +194,35 @@ class LogicalPartition extends MetaSystem {
List<Measurement> list = new ArrayList<>();
HashMap<String, String> tagsMap = new HashMap<>();
tagsMap.put("servername", system.name);
tagsMap.put("lparname", name);
log.trace("getProcessorMetrics() - tags: {}", tagsMap);
try {
HashMap<String, String> tagsMap = new HashMap<>();
HashMap<String, Object> fieldsMap = new HashMap<>();
HashMap<String, Object> fieldsMap = new HashMap<>();
fieldsMap.put("utilizedProcUnits", metrics.systemUtil.sample.lparsUtil.processor.utilizedProcUnits);
fieldsMap.put("entitledProcUnits", metrics.systemUtil.sample.lparsUtil.processor.entitledProcUnits);
fieldsMap.put("donatedProcUnits", metrics.systemUtil.sample.lparsUtil.processor.donatedProcUnits);
fieldsMap.put("idleProcUnits", metrics.systemUtil.sample.lparsUtil.processor.idleProcUnits);
fieldsMap.put("maxProcUnits", metrics.systemUtil.sample.lparsUtil.processor.maxProcUnits);
fieldsMap.put("maxVirtualProcessors", metrics.systemUtil.sample.lparsUtil.processor.maxVirtualProcessors);
fieldsMap.put("currentVirtualProcessors", metrics.systemUtil.sample.lparsUtil.processor.currentVirtualProcessors);
fieldsMap.put("utilizedCappedProcUnits", metrics.systemUtil.sample.lparsUtil.processor.utilizedCappedProcUnits);
fieldsMap.put("utilizedUncappedProcUnits", metrics.systemUtil.sample.lparsUtil.processor.utilizedUncappedProcUnits);
fieldsMap.put("timePerInstructionExecution", metrics.systemUtil.sample.lparsUtil.processor.timeSpentWaitingForDispatch);
fieldsMap.put("timeSpentWaitingForDispatch", metrics.systemUtil.sample.lparsUtil.processor.timePerInstructionExecution);
fieldsMap.put("mode", metrics.systemUtil.sample.lparsUtil.processor.mode);
fieldsMap.put("weight", metrics.systemUtil.sample.lparsUtil.processor.weight);
fieldsMap.put("poolId", metrics.systemUtil.sample.lparsUtil.processor.poolId);
log.trace("getProcessorMetrics() - fields: {}", fieldsMap);
tagsMap.put("servername", managedSystem.entry.getName());
tagsMap.put("lparname", entry.getName());
log.trace("getProcessorMetrics() - tags: " + tagsMap);
fieldsMap.put("utilizedProcUnits", metric.getSample().lparsUtil.processor.utilizedProcUnits);
fieldsMap.put("entitledProcUnits", metric.getSample().lparsUtil.processor.entitledProcUnits);
fieldsMap.put("donatedProcUnits", metric.getSample().lparsUtil.processor.donatedProcUnits);
fieldsMap.put("idleProcUnits", metric.getSample().lparsUtil.processor.idleProcUnits);
fieldsMap.put("maxProcUnits", metric.getSample().lparsUtil.processor.maxProcUnits);
fieldsMap.put("maxVirtualProcessors", metric.getSample().lparsUtil.processor.maxVirtualProcessors);
fieldsMap.put("currentVirtualProcessors", metric.getSample().lparsUtil.processor.currentVirtualProcessors);
fieldsMap.put("utilizedCappedProcUnits", metric.getSample().lparsUtil.processor.utilizedCappedProcUnits);
fieldsMap.put("utilizedUncappedProcUnits", metric.getSample().lparsUtil.processor.utilizedUncappedProcUnits);
fieldsMap.put("timePerInstructionExecution", metric.getSample().lparsUtil.processor.timeSpentWaitingForDispatch);
fieldsMap.put("timeSpentWaitingForDispatch", metric.getSample().lparsUtil.processor.timePerInstructionExecution);
fieldsMap.put("mode", metric.getSample().lparsUtil.processor.mode);
fieldsMap.put("weight", metric.getSample().lparsUtil.processor.weight);
fieldsMap.put("poolId", metric.getSample().lparsUtil.processor.poolId);
log.trace("getProcessorMetrics() - fields: " + fieldsMap);
list.add(new Measurement(tagsMap, fieldsMap));
} catch (Exception e) {
log.warn("getProcessorMetrics() - error: {}", e.getMessage());
}
list.add(new Measurement(tagsMap, fieldsMap));
return list;
}
@ -127,72 +232,41 @@ class LogicalPartition extends MetaSystem {
List<Measurement> list = new ArrayList<>();
metrics.systemUtil.sample.lparsUtil.network.virtualEthernetAdapters.forEach( adapter -> {
try {
metric.getSample().lparsUtil.network.virtualEthernetAdapters.forEach(adapter -> {
HashMap<String, String> tagsMap = new HashMap<>();
tagsMap.put("servername", system.name);
tagsMap.put("lparname", name);
tagsMap.put("location", adapter.physicalLocation);
tagsMap.put("viosId", adapter.viosId.toString());
tagsMap.put("vlanId", adapter.vlanId.toString());
tagsMap.put("vswitchId", adapter.vswitchId.toString());
log.trace("getVirtualEthernetAdapterMetrics() - tags: {}", tagsMap);
HashMap<String, String> tagsMap = new HashMap<>();
HashMap<String, Object> fieldsMap = new HashMap<>();
HashMap<String, Object> fieldsMap = new HashMap<>();
fieldsMap.put("droppedPackets", adapter.droppedPackets);
fieldsMap.put("droppedPhysicalPackets", adapter.droppedPhysicalPackets);
fieldsMap.put("isPortVlanId", adapter.isPortVlanId);
fieldsMap.put("receivedPhysicalBytes", adapter.receivedPhysicalBytes);
fieldsMap.put("receivedPhysicalPackets", adapter.receivedPhysicalPackets);
fieldsMap.put("sentPhysicalBytes", adapter.sentPhysicalBytes);
fieldsMap.put("sentPhysicalPackets", adapter.sentPhysicalPackets);
fieldsMap.put("receivedBytes", adapter.receivedBytes);
fieldsMap.put("receivedPackets", adapter.receivedPackets);
fieldsMap.put("sentBytes", adapter.sentBytes);
fieldsMap.put("sentPackets", adapter.sentPackets);
fieldsMap.put("transferredBytes", adapter.transferredBytes);
fieldsMap.put("transferredPhysicalBytes", adapter.transferredPhysicalBytes);
fieldsMap.put("sharedEthernetAdapterId", adapter.sharedEthernetAdapterId);
log.trace("getVirtualEthernetAdapterMetrics() - fields: {}", fieldsMap);
tagsMap.put("servername", managedSystem.entry.getName());
tagsMap.put("lparname", entry.getName());
tagsMap.put("location", adapter.physicalLocation);
tagsMap.put("viosId", adapter.viosId.toString());
tagsMap.put("vlanId", adapter.vlanId.toString());
tagsMap.put("vswitchId", adapter.vswitchId.toString());
log.trace("getVirtualEthernetAdapterMetrics() - tags: " + tagsMap);
list.add(new Measurement(tagsMap, fieldsMap));
});
fieldsMap.put("droppedPackets", adapter.droppedPackets);
fieldsMap.put("droppedPhysicalPackets", adapter.droppedPhysicalPackets);
fieldsMap.put("isPortVlanId", adapter.isPortVlanId);
fieldsMap.put("receivedPhysicalBytes", adapter.receivedPhysicalBytes);
fieldsMap.put("receivedPhysicalPackets", adapter.receivedPhysicalPackets);
fieldsMap.put("sentPhysicalBytes", adapter.sentPhysicalBytes);
fieldsMap.put("sentPhysicalPackets", adapter.sentPhysicalPackets);
fieldsMap.put("receivedBytes", adapter.receivedBytes);
fieldsMap.put("receivedPackets", adapter.receivedPackets);
fieldsMap.put("sentBytes", adapter.sentBytes);
fieldsMap.put("sentPackets", adapter.sentPackets);
fieldsMap.put("transferredBytes", adapter.transferredBytes);
fieldsMap.put("transferredPhysicalBytes", adapter.transferredPhysicalBytes);
fieldsMap.put("sharedEthernetAdapterId", adapter.sharedEthernetAdapterId);
log.trace("getVirtualEthernetAdapterMetrics() - fields: " + fieldsMap);
return list;
}
// LPAR Network - SR-IOV
List<Measurement> getSriovLogicalPorts() {
List<Measurement> list = new ArrayList<>();
metrics.systemUtil.sample.lparsUtil.network.sriovLogicalPorts.forEach( port -> {
HashMap<String, String> tagsMap = new HashMap<>();
tagsMap.put("servername", system.name);
tagsMap.put("lparname", name);
tagsMap.put("location", port.physicalLocation);
tagsMap.put("vnicDeviceMode", port.vnicDeviceMode);
tagsMap.put("configurationType", port.configurationType);
log.trace("getSriovLogicalPorts() - tags: {}", tagsMap);
HashMap<String, Object> fieldsMap = new HashMap<>();
fieldsMap.put("drcIndex", port.drcIndex);
fieldsMap.put("physicalPortId", port.physicalPortId);
fieldsMap.put("physicalDrcIndex", port.physicalDrcIndex);
fieldsMap.put("droppedPackets", port.droppedPackets);
fieldsMap.put("receivedBytes", port.receivedBytes);
fieldsMap.put("receivedPackets", port.receivedPackets);
fieldsMap.put("sentBytes", port.sentBytes);
fieldsMap.put("sentPackets", port.sentPackets);
fieldsMap.put("errorIn", port.errorIn);
fieldsMap.put("errorOut", port.errorOut);
fieldsMap.put("transferredBytes", port.transferredBytes);
log.trace("getSriovLogicalPorts() - fields: {}", fieldsMap);
list.add(new Measurement(tagsMap, fieldsMap));
});
list.add(new Measurement(tagsMap, fieldsMap));
});
} catch (Exception e) {
log.warn("getVirtualEthernetAdapterMetrics() - error: {}", e.getMessage());
}
return list;
}
@ -202,26 +276,33 @@ class LogicalPartition extends MetaSystem {
List<Measurement> getVirtualGenericAdapterMetrics() {
List<Measurement> list = new ArrayList<>();
metrics.systemUtil.sample.lparsUtil.storage.genericVirtualAdapters.forEach( adapter -> {
HashMap<String, String> tagsMap = new HashMap<>();
tagsMap.put("servername", system.name);
tagsMap.put("lparname", name);
tagsMap.put("viosId", adapter.viosId.toString());
tagsMap.put("location", adapter.physicalLocation);
tagsMap.put("id", adapter.id);
log.trace("getVirtualGenericAdapterMetrics() - tags: {}", tagsMap);
try {
metric.getSample().lparsUtil.storage.genericVirtualAdapters.forEach(adapter -> {
HashMap<String, Object> fieldsMap = new HashMap<>();
fieldsMap.put("numOfReads", adapter.numOfReads);
fieldsMap.put("numOfWrites", adapter.numOfWrites);
fieldsMap.put("writeBytes", adapter.writeBytes);
fieldsMap.put("readBytes", adapter.readBytes);
fieldsMap.put("type", adapter.type);
log.trace("getVirtualGenericAdapterMetrics() - fields: {}", fieldsMap);
HashMap<String, String> tagsMap = new HashMap<>();
HashMap<String, Object> fieldsMap = new HashMap<>();
tagsMap.put("servername", managedSystem.entry.getName());
tagsMap.put("lparname", entry.getName());
tagsMap.put("viosId", adapter.viosId.toString());
tagsMap.put("location", adapter.physicalLocation);
tagsMap.put("id", adapter.id);
log.trace("getVirtualGenericAdapterMetrics() - tags: " + tagsMap);
fieldsMap.put("numOfReads", adapter.numOfReads);
fieldsMap.put("numOfWrites", adapter.numOfWrites);
fieldsMap.put("writeBytes", adapter.writeBytes);
fieldsMap.put("readBytes", adapter.readBytes);
fieldsMap.put("type", adapter.type);
log.trace("getVirtualGenericAdapterMetrics() - fields: " + fieldsMap);
list.add(new Measurement(tagsMap, fieldsMap));
});
} catch (Exception e) {
log.warn("getVirtualGenericAdapterMetrics() - error: {}", e.getMessage());
}
list.add(new Measurement(tagsMap, fieldsMap));
});
return list;
}
@ -230,32 +311,71 @@ class LogicalPartition extends MetaSystem {
List<Measurement> getVirtualFibreChannelAdapterMetrics() {
List<Measurement> list = new ArrayList<>();
metrics.systemUtil.sample.lparsUtil.storage.virtualFiberChannelAdapters.forEach( adapter -> {
HashMap<String, String> tagsMap = new HashMap<>();
tagsMap.put("servername", system.name);
tagsMap.put("lparname", name);
tagsMap.put("viosId", adapter.viosId.toString());
tagsMap.put("location", adapter.physicalLocation);
log.trace("getVirtualFibreChannelAdapterMetrics() - tags: {}", tagsMap);
try {
metric.getSample().lparsUtil.storage.virtualFiberChannelAdapters.forEach(adapter -> {
HashMap<String, Object> fieldsMap = new HashMap<>();
fieldsMap.put("numOfReads", adapter.numOfReads);
fieldsMap.put("numOfWrites", adapter.numOfWrites);
fieldsMap.put("writeBytes", adapter.writeBytes);
fieldsMap.put("readBytes", adapter.readBytes);
fieldsMap.put("runningSpeed", adapter.runningSpeed);
fieldsMap.put("transmittedBytes", adapter.transmittedBytes);
fieldsMap.put("transferredByte", adapter.transmittedBytes); // TODO: Must be error in dashboard, remove when checked.
//fieldsMap.put("wwpn", adapter.wwpn);
//fieldsMap.put("wwpn2", adapter.wwpn2);
log.trace("getVirtualFibreChannelAdapterMetrics() - fields: {}", fieldsMap);
HashMap<String, String> tagsMap = new HashMap<>();
HashMap<String, Object> fieldsMap = new HashMap<>();
list.add(new Measurement(tagsMap, fieldsMap));
});
tagsMap.put("servername", managedSystem.entry.getName());
tagsMap.put("lparname", entry.getName());
tagsMap.put("viosId", adapter.viosId.toString());
tagsMap.put("location", adapter.physicalLocation);
log.trace("getVirtualFibreChannelAdapterMetrics() - tags: " + tagsMap);
fieldsMap.put("numOfReads", adapter.numOfReads);
fieldsMap.put("numOfWrites", adapter.numOfWrites);
fieldsMap.put("writeBytes", adapter.writeBytes);
fieldsMap.put("readBytes", adapter.readBytes);
fieldsMap.put("runningSpeed", adapter.runningSpeed);
fieldsMap.put("transmittedBytes", adapter.transmittedBytes);
fieldsMap.put("transferredByte", adapter.transmittedBytes); // TODO: Must be error in dashboard, remove when checked.
log.trace("getVirtualFibreChannelAdapterMetrics() - fields: " + fieldsMap);
list.add(new Measurement(tagsMap, fieldsMap));
});
} catch (Exception e) {
log.warn("getVirtualFibreChannelAdapterMetrics() - error: {}", e.getMessage());
}
return list;
}
// LPAR Network - SR-IOV Logical Ports
List<Measurement> getSriovLogicalPorts() {
List<Measurement> list = new ArrayList<>();
try {
metric.getSample().lparsUtil.network.sriovLogicalPorts.forEach(port -> {
HashMap<String, String> tagsMap = new HashMap<>();
HashMap<String, Object> fieldsMap = new HashMap<>();
tagsMap.put("servername", managedSystem.entry.getName());
tagsMap.put("lparname", entry.getName());
tagsMap.put("location", port.physicalLocation);
tagsMap.put("type", port.configurationType);
log.trace("getSriovLogicalPorts() - tags: " + tagsMap);
fieldsMap.put("sentBytes", port.sentBytes);
fieldsMap.put("receivedBytes", port.receivedBytes);
fieldsMap.put("transferredBytes", port.transferredBytes);
fieldsMap.put("sentPackets", port.sentPackets);
fieldsMap.put("receivedPackets", port.receivedPackets);
fieldsMap.put("droppedPackets", port.droppedPackets);
fieldsMap.put("errorIn", port.errorIn);
fieldsMap.put("errorOut", port.errorOut);
log.trace("getSriovLogicalPorts() - fields: " + fieldsMap);
list.add(new Measurement(tagsMap, fieldsMap));
});
} catch (Exception e) {
log.warn("getSriovLogicalPorts() - error: {}", e.getMessage());
}
return list;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,261 @@
/*
* 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 biz.nellemann.hmci.dto.toml.HmcConfiguration;
import biz.nellemann.hmci.dto.xml.Link;
import biz.nellemann.hmci.dto.xml.ManagementConsoleEntry;
import biz.nellemann.hmci.dto.xml.XmlFeed;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.time.Duration;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import static java.lang.Thread.sleep;
class ManagementConsole implements Runnable {
private final static Logger log = LoggerFactory.getLogger(ManagementConsole.class);
private final Integer refreshValue;
private final Integer discoverValue;
private final List<ManagedSystem> managedSystems = new ArrayList<>();
private final RestClient restClient;
private final InfluxClient influxClient;
private final AtomicBoolean keepRunning = new AtomicBoolean(true);
protected Integer responseErrors = 0;
private Boolean doEnergy = true;
private final List<String> excludeSystems;
private final List<String> includeSystems;
private final List<String> excludePartitions;
private final List<String> includePartitions;
ManagementConsole(HmcConfiguration configuration, InfluxClient influxClient) {
this.refreshValue = configuration.refresh;
this.discoverValue = configuration.discover;
this.doEnergy = configuration.energy;
this.influxClient = influxClient;
restClient = new RestClient(configuration.url, configuration.username, configuration.password, configuration.trust);
if(configuration.trace != null) {
try {
File traceDir = new File(configuration.trace);
traceDir.mkdirs();
if(traceDir.canWrite()) {
Boolean doTrace = true;
} else {
log.warn("HmcInstance() - can't write to trace dir: " + traceDir.toString());
}
} catch (Exception e) {
log.error("HmcInstance() - trace error: " + e.getMessage());
}
}
this.excludeSystems = configuration.excludeSystems;
this.includeSystems = configuration.includeSystems;
this.excludePartitions = configuration.excludePartitions;
this.includePartitions = configuration.includePartitions;
}
@Override
public void run() {
log.trace("run()");
int executions = 0;
restClient.login();
discover();
do {
Instant instantStart = Instant.now();
try {
refresh();
if (++executions > discoverValue) { // FIXME: Change to time based logic
executions = 0;
discover();
}
} catch (Exception e) {
log.error("run() - fatal error: {}", e.getMessage());
keepRunning.set(false);
throw new RuntimeException(e);
}
Instant instantEnd = Instant.now();
long timeSpend = Duration.between(instantStart, instantEnd).toMillis();
log.trace("run() - duration millis: " + timeSpend);
if(timeSpend < (refreshValue * 1000)) {
try {
long sleepTime = (refreshValue * 1000) - timeSpend;
log.trace("run() - sleeping millis: " + sleepTime);
if(sleepTime > 0) {
//noinspection BusyWait
sleep(sleepTime);
}
} catch (InterruptedException e) {
log.error("run() - sleep interrupted", e);
}
} else {
log.warn("run() - possible slow response from this HMC");
}
} while (keepRunning.get());
// Logout of HMC
restClient.logoff();
}
public void discover() {
try {
String xml = restClient.getRequest("/rest/api/uom/ManagementConsole");
// Do not try to parse empty response
if(xml == null || xml.length() <= 1) {
responseErrors++;
log.warn("discover() - no data.");
return;
}
XmlMapper xmlMapper = new XmlMapper();
XmlFeed xmlFeed = xmlMapper.readValue(xml, XmlFeed.class);
ManagementConsoleEntry entry;
if(xmlFeed.getEntry() == null){
log.warn("discover() - xmlFeed.entry == null");
return;
}
if(xmlFeed.getEntry().getContent().isManagementConsole()) {
entry = xmlFeed.getEntry().getContent().getManagementConsole();
log.info("discover() - {}", entry.getName());
} else {
throw new UnsupportedOperationException("Failed to deserialize ManagementConsole");
}
managedSystems.clear();
for (Link link : entry.getAssociatedManagedSystems()) {
ManagedSystem managedSystem = new ManagedSystem(restClient, link.getHref());
managedSystem.setExcludePartitions(excludePartitions);
managedSystem.setIncludePartitions(includePartitions);
managedSystem.setDoEnergy(doEnergy);
managedSystem.discover();
// Only continue for powered-on operating systems
if(managedSystem.entry != null && Objects.equals(managedSystem.entry.state, "operating")) {
// Check exclude / include
if (!excludeSystems.contains(managedSystem.name) && includeSystems.isEmpty()) {
managedSystems.add(managedSystem);
//log.info("discover() - adding !excluded system: {}", managedSystem.name);
} else if (!includeSystems.isEmpty() && includeSystems.contains(managedSystem.name)) {
managedSystems.add(managedSystem);
//log.info("discover() - adding included system: {}", managedSystem.name);
}
}
}
} catch (Exception e) {
log.warn("discover() - error: {}", e.getMessage());
}
}
void refresh() {
log.debug("refresh()");
managedSystems.forEach( (system) -> {
if(system.entry == null){
log.warn("refresh() - system.entry == null");
return;
}
system.refresh();
influxClient.write(system.getDetails(), system.getTimestamp(),"server_details");
influxClient.write(system.getMemoryMetrics(), system.getTimestamp(),"server_memory");
influxClient.write(system.getProcessorMetrics(), system.getTimestamp(),"server_processor");
influxClient.write(system.getPhysicalProcessorPool(), system.getTimestamp(),"server_physicalProcessorPool");
influxClient.write(system.getSharedProcessorPools(), system.getTimestamp(),"server_sharedProcessorPool");
if(doEnergy) {
system.systemEnergy.refresh();
if(system.systemEnergy.metric != null) {
influxClient.write(system.systemEnergy.getPowerMetrics(), system.getTimestamp(), "server_energy_power");
influxClient.write(system.systemEnergy.getThermalMetrics(), system.getTimestamp(), "server_energy_thermal");
}
}
influxClient.write(system.getVioDetails(), system.getTimestamp(),"vios_details");
influxClient.write(system.getVioProcessorMetrics(), system.getTimestamp(),"vios_processor");
influxClient.write(system.getVioMemoryMetrics(), system.getTimestamp(),"vios_memory");
influxClient.write(system.getVioNetworkLpars(), system.getTimestamp(),"vios_network_lpars");
influxClient.write(system.getVioNetworkVirtualAdapters(), system.getTimestamp(),"vios_network_virtual");
influxClient.write(system.getVioNetworkSharedAdapters(), system.getTimestamp(),"vios_network_shared");
influxClient.write(system.getVioNetworkGenericAdapters(), system.getTimestamp(),"vios_network_generic");
influxClient.write(system.getVioStorageLpars(), system.getTimestamp(),"vios_storage_lpars");
influxClient.write(system.getVioStorageFiberChannelAdapters(), system.getTimestamp(),"vios_storage_FC");
influxClient.write(system.getVioStorageVirtualAdapters(), system.getTimestamp(),"vios_storage_vFC");
influxClient.write(system.getVioStoragePhysicalAdapters(), system.getTimestamp(),"vios_storage_physical");
// Missing: vios_storage_SSP
system.logicalPartitions.forEach( (partition) -> {
partition.refresh();
influxClient.write(partition.getDetails(), partition.getTimestamp(),"lpar_details");
influxClient.write(partition.getMemoryMetrics(), partition.getTimestamp(),"lpar_memory");
influxClient.write(partition.getProcessorMetrics(), partition.getTimestamp(),"lpar_processor");
influxClient.write(partition.getSriovLogicalPorts(), partition.getTimestamp(),"lpar_net_sriov");
influxClient.write(partition.getVirtualEthernetAdapterMetrics(), partition.getTimestamp(),"lpar_net_virtual");
influxClient.write(partition.getVirtualGenericAdapterMetrics(), partition.getTimestamp(),"lpar_storage_virtual");
influxClient.write(partition.getVirtualFibreChannelAdapterMetrics(), partition.getTimestamp(),"lpar_storage_vFC");
});
});
}
/*
private void writeTraceFile(String id, String json) {
String fileName = String.format("%s-%s.json", id, Instant.now().toString());
try {
log.debug("Writing trace file: " + fileName);
File traceFile = new File(traceDir, fileName);
BufferedWriter writer = new BufferedWriter(new FileWriter(traceFile));
writer.write(json);
writer.close();
} catch (IOException e) {
log.warn("writeTraceFile() - " + e.getMessage());
}
}
*/
}

View File

@ -1,133 +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 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 java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
abstract class MetaSystem {
private final static Logger log = LoggerFactory.getLogger(MetaSystem.class);
private final JsonAdapter<PcmData> jsonAdapter;
protected PcmData metrics;
MetaSystem() {
try {
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);
throw new ExceptionInInitializerError(e);
}
}
void processMetrics(String json) {
try {
metrics = jsonAdapter.nullSafe().fromJson(json);
} catch(IOException e) {
log.warn("processMetrics() error", e);
}
//System.out.println(jsonAdapter.toJson(metrics));
}
Instant getTimestamp() {
String timestamp = getStringMetricObject(metrics.systemUtil.sample.sampleInfo.timeStamp);
Instant instant = Instant.now();
try {
log.trace("getTimeStamp() - PMC Timestamp: {}", timestamp);
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[XXX][X]");
instant = Instant.from(dateTimeFormatter.parse(timestamp));
log.trace("getTimestamp() - Instant: {}", instant.toString());
} catch(DateTimeParseException e) {
log.warn("getTimestamp() - parse error: {}", timestamp);
}
return instant;
}
String getStringMetricObject(Object obj) {
String metric = null;
try {
metric = (String) obj;
} catch (NullPointerException npe) {
log.warn("getStringMetricObject()", npe);
}
return metric;
}
Number getNumberMetricObject(Object obj) {
Number metric = null;
try {
metric = (Number) obj;
} catch (NullPointerException npe) {
log.warn("getNumberMetricObject()", npe);
}
return metric;
}
static class BigDecimalAdapter {
@FromJson
BigDecimal fromJson(String string) {
return new BigDecimal(string);
}
@ToJson
String toJson(BigDecimal value) {
return value.toString();
}
}
static class NumberAdapter {
@FromJson
Number fromJson(String string) {
return Double.parseDouble(string);
}
@ToJson
String toJson(Number value) {
return value.toString();
}
}
}

View File

@ -0,0 +1,64 @@
package biz.nellemann.hmci;
import biz.nellemann.hmci.dto.json.ProcessedMetrics;
import biz.nellemann.hmci.dto.json.SystemUtil;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
public class Resource {
private final static Logger log = LoggerFactory.getLogger(Resource.class);
private final ObjectMapper objectMapper = new ObjectMapper();
protected SystemUtil metric;
Resource() {
objectMapper.enable(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS);
objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
objectMapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
}
void deserialize(String json) {
if(json == null || json.length() < 1) {
return;
}
try {
ProcessedMetrics processedMetrics = objectMapper.readValue(json, ProcessedMetrics.class);
metric = processedMetrics.systemUtil;
} catch (Exception e) {
log.error("deserialize() - error: {}", e.getMessage());
}
}
Instant getTimestamp() {
Instant instant = Instant.now();
if (metric == null) {
return instant;
}
String timestamp = metric.getSample().sampleInfo.timestamp;
try {
log.trace("getTimeStamp() - PMC Timestamp: {}", timestamp);
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[XXX][X]");
instant = Instant.from(dateTimeFormatter.parse(timestamp));
log.trace("getTimestamp() - Instant: {}", instant.toString());
} catch(DateTimeParseException e) {
log.warn("getTimestamp() - parse error: {}", timestamp);
}
return instant;
}
}

View File

@ -0,0 +1,295 @@
package biz.nellemann.hmci;
import biz.nellemann.hmci.dto.xml.LogonResponse;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.*;
import java.net.*;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
public class RestClient {
private final static Logger log = LoggerFactory.getLogger(RestClient.class);
private final MediaType MEDIA_TYPE_IBM_XML_LOGIN = MediaType.parse("application/vnd.ibm.powervm.web+xml; type=LogonRequest");
protected OkHttpClient httpClient;
// OkHttpClient timeouts
private final static int CONNECT_TIMEOUT = 30;
private final static int WRITE_TIMEOUT = 30;
private final static int READ_TIMEOUT = 180;
//protected final HttpClient httpClient;
protected String authToken;
protected final String baseUrl;
protected final String username;
protected final String password;
public RestClient(String baseUrl, String username, String password, Boolean trustAll) {
this.baseUrl = baseUrl;
this.username = username;
this.password = password;
//this.httpClient = getHttpClient(trustAll);
//httpClient.start();
if (trustAll) {
this.httpClient = getUnsafeOkHttpClient();
} else {
this.httpClient = getSafeOkHttpClient();
}
}
/**
* Logon to the HMC and get an authentication token for further requests.
*/
public synchronized void login() {
log.info("Connecting to HMC - {} @ {}", username, baseUrl);
StringBuilder payload = new StringBuilder();
payload.append("<?xml version='1.0' encoding='UTF-8' standalone='yes'?>");
payload.append("<LogonRequest xmlns='http://www.ibm.com/xmlns/systems/power/firmware/web/mc/2012_10/' schemaVersion='V1_0'>");
payload.append("<UserID>").append(username).append("</UserID>");
payload.append("<Password>").append(password).append("</Password>");
payload.append("</LogonRequest>");
try {
//httpClient.start();
URL url = new URL(String.format("%s/rest/api/web/Logon", baseUrl));
Request request = new Request.Builder()
.url(url)
.addHeader("Accept", "application/vnd.ibm.powervm.web+xml; type=LogonResponse")
.addHeader("X-Audit-Memento", "IBM Power HMC Insights")
.put(RequestBody.create(payload.toString(), MEDIA_TYPE_IBM_XML_LOGIN))
.build();
String responseBody;
try (Response response = httpClient.newCall(request).execute()) {
responseBody = Objects.requireNonNull(response.body()).string();
if (!response.isSuccessful()) {
log.warn("login() - Unexpected response: {}", response.code());
throw new IOException("Unexpected code: " + response);
}
}
XmlMapper xmlMapper = new XmlMapper();
LogonResponse logonResponse = xmlMapper.readValue(responseBody, LogonResponse.class);
authToken = logonResponse.getToken();
log.debug("logon() - auth token: {}", authToken);
} catch (Exception e) {
log.warn("logon() - error: {}", e.getMessage());
}
}
/**
* Logoff from the HMC and remove any session
*
*/
synchronized void logoff() {
if(authToken == null) {
return;
}
try {
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("X-API-Session", authToken)
.delete()
.build();
String responseBody;
try (Response response = httpClient.newCall(request).execute()) {
responseBody = Objects.requireNonNull(response.body()).string();
} catch (IOException e) {
log.warn("logoff() error: {}", e.getMessage());
} finally {
authToken = null;
}
} catch (MalformedURLException e) {
log.warn("logoff() - error: {}", e.getMessage());
}
}
public String getRequest(String urlPath) throws IOException {
URL absUrl = new URL(String.format("%s%s", baseUrl, urlPath));
return getRequest(absUrl);
}
public String postRequest(String urlPath, String payload) throws IOException {
URL absUrl = new URL(String.format("%s%s", baseUrl, urlPath));
return postRequest(absUrl, payload);
}
/**
* Return a Response from the HMC
* @param url to get Response from
* @return Response body string
*/
private String getRequest(URL url) throws IOException {
log.trace("getRequest() - URL: {}", url.toString());
Request request = new Request.Builder()
.url(url)
.addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8")
.addHeader("X-API-Session", (authToken == null ? "" : authToken))
.get().build();
String responseBody;
try (Response response = httpClient.newCall(request).execute()) {
responseBody = Objects.requireNonNull(response.body()).string();;
if (!response.isSuccessful()) {
// Auth. failure
if(response.code() == 401) {
log.warn("getRequest() - 401 - login and retry.");
// Let's login again and retry
authToken = null;
login();
try (Response responseRetry = httpClient.newCall(request).execute()) {
log.debug("getRequest() - in retry: {}", Objects.requireNonNull(responseRetry.body()).string());
if (responseRetry.isSuccessful()) {
return Objects.requireNonNull(responseRetry.body()).string();
}
return null;
}
}
log.error("getRequest() - Unexpected response: {}", response.code());
throw new IOException("getRequest() - Unexpected response: " + response.code());
}
}
return responseBody;
}
/**
* Send a POST request with a payload (can be null) to the HMC
* @param url
* @param payload
* @return
* @throws IOException
*/
public String postRequest(URL url, String payload) throws IOException {
log.trace("sendPostRequest() - URL: {}", url.toString());
RequestBody requestBody;
if(payload != null) {
requestBody = RequestBody.create(payload, MediaType.get("application/xml"));
} else {
requestBody = RequestBody.create("", null);
}
Request request = new Request.Builder()
.url(url)
//.addHeader("Content-Type", "application/xml")
.addHeader("content-type", "application/xml")
.addHeader("X-API-Session", (authToken == null ? "" : authToken) )
.post(requestBody).build();
String responseBody;
try (Response response = httpClient.newCall(request).execute()) {
responseBody = Objects.requireNonNull(response.body()).string();
if (!response.isSuccessful()) {
response.close();
log.warn(responseBody);
log.error("sendPostRequest() - Unexpected response: {}", response.code());
throw new IOException("sendPostRequest() - Unexpected response: " + response.code());
}
}
return responseBody;
}
/**
* Provide an unsafe (ignoring SSL problems) OkHttpClient
*
* @return OkHttpClient ignoring SSL/TLS errors
*/
private static OkHttpClient getUnsafeOkHttpClient() {
try {
// Create a trust manager that does not validate certificate chains
final TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) { }
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
}
};
// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new SecureRandom());
// Create a ssl socket factory with our all-trusting manager
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.sslSocketFactory(sslSocketFactory, (X509TrustManager)trustAllCerts[0]);
builder.hostnameVerifier((hostname, session) -> true);
builder.connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS);
builder.writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS);
builder.readTimeout(READ_TIMEOUT, TimeUnit.SECONDS);
return builder.build();
} catch (KeyManagementException | NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
/**
* Get OkHttpClient with our preferred timeout values.
* @return OkHttpClient
*/
private static OkHttpClient getSafeOkHttpClient() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS);
builder.writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS);
builder.readTimeout(READ_TIMEOUT, TimeUnit.SECONDS);
return builder.build();
}
}

View File

@ -1,60 +1,107 @@
/*
* 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 biz.nellemann.hmci.pcm.Temperature;
import biz.nellemann.hmci.dto.xml.Link;
import biz.nellemann.hmci.dto.xml.XmlFeed;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.io.IOException;
import java.net.URI;
import java.util.*;
class SystemEnergy extends MetaSystem {
class SystemEnergy extends Resource {
private final static Logger log = LoggerFactory.getLogger(SystemEnergy.class);
public final ManagedSystem system;
private final RestClient restClient;
private final ManagedSystem managedSystem;
protected String id;
protected String name;
SystemEnergy(ManagedSystem system) {
this.system = system;
public SystemEnergy(RestClient restClient, ManagedSystem managedSystem) {
log.debug("SystemEnergy()");
this.restClient = restClient;
this.managedSystem = managedSystem;
}
@Override
public String toString() {
return system.name;
public void refresh() {
log.debug("refresh()");
try {
String xml = restClient.getRequest(String.format("/rest/api/pcm/ManagedSystem/%s/ProcessedMetrics?Type=Energy&NoOfSamples=1", managedSystem.id));
// Do not try to parse empty response
if(xml == null || xml.length() <= 1) {
log.warn("refresh() - no data.");
return;
}
XmlMapper xmlMapper = new XmlMapper();
XmlFeed xmlFeed = xmlMapper.readValue(xml, XmlFeed.class);
xmlFeed.entries.forEach((entry) -> {
if (entry.category.term.equals("ManagedSystem")) {
Link link = entry.link;
if (link.getType() != null && Objects.equals(link.getType(), "application/json")) {
try {
URI jsonUri = URI.create(link.getHref());
String json = restClient.getRequest(jsonUri.getPath());
deserialize(json);
} catch (IOException e) {
log.error("refresh() - error 1: {}", e.getMessage());
}
}
}
});
} catch (IOException e) {
log.error("refresh() - error: {} {}", e.getClass(), e.getMessage());
}
/*
try {
Document doc = Jsoup.parse(responseBody);
Element entry = doc.select("feed > entry").first();
Element link = Objects.requireNonNull(entry).select("link[href]").first();
if(Objects.requireNonNull(link).attr("type").equals("application/json")) {
String href = link.attr("href");
log.trace("getPcmDataForEnergy() - URL: {}", href);
jsonBody = sendGetRequest(new URL(href));
}
} catch(Exception e) {
log.warn("getPcmDataForEnergy() - XML parse error: {}", systemEnergy, e);
}
*/
}
List<Measurement> getPowerMetrics() {
List<Measurement> list = new ArrayList<>();
try {
HashMap<String, String> tagsMap = new HashMap<>();
Map<String, Object> fieldsMap = new HashMap<>();
HashMap<String, String> tagsMap = new HashMap<>();
tagsMap.put("servername", system.name);
log.trace("getPowerMetrics() - tags: {}", tagsMap);
tagsMap.put("servername", managedSystem.name);
log.trace("getPowerMetrics() - tags: {}", tagsMap);
Map<String, Object> fieldsMap = new HashMap<>();
fieldsMap.put("powerReading", metrics.systemUtil.sample.energyUtil.powerUtil.powerReading);
log.trace("getPowerMetrics() - fields: {}", fieldsMap);
fieldsMap.put("powerReading", metric.getSample().energyUtil.powerUtil.powerReading);
log.trace("getPowerMetrics() - fields: {}", fieldsMap);
list.add(new Measurement(tagsMap, fieldsMap));
} catch (Exception e) {
log.warn("getPowerMetrics() - error: {}", e.getMessage());
}
list.add(new Measurement(tagsMap, fieldsMap));
return list;
}
@ -62,28 +109,36 @@ class SystemEnergy extends MetaSystem {
List<Measurement> getThermalMetrics() {
List<Measurement> list = new ArrayList<>();
try {
HashMap<String, String> tagsMap = new HashMap<>();
Map<String, Object> fieldsMap = new HashMap<>();
HashMap<String, String> tagsMap = new HashMap<>();
tagsMap.put("servername", system.name);
log.trace("getThermalMetrics() - tags: {}", tagsMap);
tagsMap.put("servername", managedSystem.name);
log.trace("getThermalMetrics() - tags: {}", tagsMap);
Map<String, Object> fieldsMap = new HashMap<>();
metric.getSample().energyUtil.thermalUtil.cpuTemperatures.forEach((t) -> {
fieldsMap.put("cpuTemperature_" + t.entityInstance, t.temperatureReading);
});
for(Temperature t : metrics.systemUtil.sample.energyUtil.thermalUtil.cpuTemperatures) {
fieldsMap.put("cpuTemperature_" + t.entityInstance, t.temperatureReading);
metric.getSample().energyUtil.thermalUtil.inletTemperatures.forEach((t) -> {
fieldsMap.put("inletTemperature_" + t.entityInstance, t.temperatureReading);
});
/* Disabled, not sure if useful
for(Temperature t : metrics.systemUtil.sample.energyUtil.thermalUtil.baseboardTemperatures) {
fieldsMap.put("baseboardTemperature_" + t.entityInstance, t.temperatureReading);
}*/
log.trace("getThermalMetrics() - fields: {}", fieldsMap);
list.add(new Measurement(tagsMap, fieldsMap));
} catch (Exception e) {
log.warn("getThermalMetrics() - error: {}", e.getMessage());
}
for(Temperature t : metrics.systemUtil.sample.energyUtil.thermalUtil.inletTemperatures) {
fieldsMap.put("inletTemperature_" + t.entityInstance, t.temperatureReading);
}
/* Disabled, not sure if useful
for(Temperature t : metrics.systemUtil.sample.energyUtil.thermalUtil.baseboardTemperatures) {
fieldsMap.put("baseboardTemperature_" + t.entityInstance, t.temperatureReading);
}*/
log.trace("getThermalMetrics() - fields: {}", fieldsMap);
list.add(new Measurement(tagsMap, fieldsMap));
return list;
}
}

View File

@ -0,0 +1,66 @@
package biz.nellemann.hmci;
import biz.nellemann.hmci.dto.xml.VirtualIOServerEntry;
import biz.nellemann.hmci.dto.xml.XmlEntry;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URI;
import java.net.URISyntaxException;
public class VirtualIOServer {
private final static Logger log = LoggerFactory.getLogger(VirtualIOServer.class);
private final RestClient restClient;
private final ManagedSystem managedSystem;
protected String id;
private String uriPath;
protected VirtualIOServerEntry entry;
public VirtualIOServer(RestClient restClient, String href, ManagedSystem system) {
log.debug("VirtualIOServer() - {}", href);
this.restClient = restClient;
this.managedSystem = system;
try {
URI uri = new URI(href);
uriPath = uri.getPath();
//refresh();
} catch (URISyntaxException e) {
log.error("VirtualIOServer() - {}", e.getMessage());
}
}
public void discover() {
try {
String xml = restClient.getRequest(uriPath);
// Do not try to parse empty response
if(xml == null || xml.length() <= 1) {
log.warn("discover() - no data.");
return;
}
XmlMapper xmlMapper = new XmlMapper();
XmlEntry xmlEntry = xmlMapper.readValue(xml, XmlEntry.class);
if(xmlEntry.getContent() == null){
log.warn("discover() - no content.");
return;
}
if(xmlEntry.getContent().isVirtualIOServer()) {
entry = xmlEntry.getContent().getVirtualIOServerEntry();
log.debug("discover() - {}", entry.getName());
} else {
throw new UnsupportedOperationException("Failed to deserialize VirtualIOServer");
}
} catch (Exception e) {
log.error("discover() - error: {}", e.getMessage());
}
}
}

View File

@ -0,0 +1,8 @@
package biz.nellemann.hmci.dto.json;
public final class EnergyUtil {
public PowerUtil powerUtil = new PowerUtil();
public ThermalUtil thermalUtil = new ThermalUtil();
}

View File

@ -0,0 +1,22 @@
package biz.nellemann.hmci.dto.json;
/**
* Storage adapter
*/
public final class FiberChannelAdapter {
public String id;
public String wwpn;
public String physicalLocation;
public int numOfPorts;
public double numOfReads;
public double numOfWrites;
public double readBytes;
public double writeBytes;
public double runningSpeed;
public double transmittedBytes;
}

View File

@ -0,0 +1,16 @@
package biz.nellemann.hmci.dto.json;
public final class GenericAdapter {
public String id;
public String type = "";
public String physicalLocation = "";
public double receivedPackets = 0.0;
public double sentPackets = 0.0;
public double droppedPackets = 0.0;
public double sentBytes = 0.0;
public double receivedBytes = 0.0;
public double transferredBytes = 0.0;
}

View File

@ -0,0 +1,15 @@
package biz.nellemann.hmci.dto.json;
public final class GenericPhysicalAdapters {
public String id;
public String type;
public String physicalLocation;
public double numOfReads;
public double numOfWrites;
public double readBytes;
public double writeBytes;
public double transmittedBytes;
}

View File

@ -0,0 +1,22 @@
package biz.nellemann.hmci.dto.json;
import com.fasterxml.jackson.annotation.JsonIgnore;
/**
* Storage adapter
*/
public final class GenericVirtualAdapter {
public String id = "";
public String type = "";
public Integer viosId = 0;
public String physicalLocation = "";
public Double numOfReads = 0.0;
public Double numOfWrites = 0.0;
public Double readBytes = 0.0;
public Double writeBytes = 0.0;
public Double transmittedBytes = 0.0;
}

View File

@ -0,0 +1,12 @@
package biz.nellemann.hmci.dto.json;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true)
public final class LparMemory {
public Double logicalMem;
public Double utilizedMem = 0.0;
public Double backedPhysicalMem = 0.0;
}

View File

@ -0,0 +1,21 @@
package biz.nellemann.hmci.dto.json;
public final class LparProcessor {
public Integer poolId = 0;
public Integer weight = 0;
public String mode = "";
public Double maxVirtualProcessors = 0.0;
public Double currentVirtualProcessors = 0.0;
public Double maxProcUnits = 0.0;
public Double entitledProcUnits = 0.0;
public Double utilizedProcUnits = 0.0;
public Double utilizedCappedProcUnits = 0.0;
public Double utilizedUncappedProcUnits = 0.0;
public Double idleProcUnits = 0.0;
public Double donatedProcUnits = 0.0;
public Double timeSpentWaitingForDispatch = 0.0;
public Double timePerInstructionExecution = 0.0;
}

View File

@ -1,5 +1,8 @@
package biz.nellemann.hmci.pcm;
package biz.nellemann.hmci.dto.json;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true)
public final class LparUtil {
public Integer id = 0;
@ -8,7 +11,7 @@ public final class LparUtil {
public String state = "";
public String type = "";
public String osType = "";
public Number affinityScore = 0.0f;
public Float affinityScore = 0.0f;
public final LparMemory memory = new LparMemory();
public final LparProcessor processor = new LparProcessor();

View File

@ -0,0 +1,16 @@
package biz.nellemann.hmci.dto.json;
import java.util.ArrayList;
import java.util.List;
public final class Network {
public List<String> clientLpars = new ArrayList<>();
public List<GenericAdapter> genericAdapters = new ArrayList<>();
public List<SharedAdapter> sharedAdapters = new ArrayList<>();
public List<VirtualEthernetAdapter> virtualEthernetAdapters = new ArrayList<>();
public List<SRIOVAdapter> sriovAdapters = new ArrayList<>();
public List<SRIOVLogicalPort> sriovLogicalPorts = new ArrayList<>();
}

View File

@ -0,0 +1,12 @@
package biz.nellemann.hmci.dto.json;
public final class PhysicalProcessorPool {
public double assignedProcUnits = 0.0;
public double utilizedProcUnits = 0.0;
public double availableProcUnits = 0.0;
public double configuredProcUnits = 0.0;
public double borrowedProcUnits = 0.0;
}

View File

@ -0,0 +1,7 @@
package biz.nellemann.hmci.dto.json;
public final class PowerUtil {
public Number powerReading = 0.0;
}

View File

@ -0,0 +1,7 @@
package biz.nellemann.hmci.dto.json;
public class ProcessedMetrics {
public SystemUtil systemUtil;
}

View File

@ -0,0 +1,11 @@
package biz.nellemann.hmci.dto.json;
import java.util.List;
public final class SRIOVAdapter {
public String drcIndex = "";
public List<SRIOVPhysicalPort> physicalPorts;
}

View File

@ -0,0 +1,21 @@
package biz.nellemann.hmci.dto.json;
public class SRIOVLogicalPort {
public String drcIndex;
public String physicalLocation;
public String physicalDrcIndex;
public Number physicalPortId;
public String clientPartitionUUID;
public String vnicDeviceMode;
public String configurationType;
public Number receivedPackets;
public Number sentPackets;
public Number droppedPackets;
public Number sentBytes;
public Number receivedBytes;
public Number errorIn;
public Number errorOut;
public Number transferredBytes;
}

View File

@ -1,44 +1,20 @@
package biz.nellemann.hmci.pcm;
package biz.nellemann.hmci.dto.json;
import com.serjltt.moshi.adapters.FirstElement;
public class SriovLogicalPort {
public String drcIndex = "";
public final class SRIOVPhysicalPort {
public String id;
public String physicalLocation = ""; // "U78CA.001.CSS0CXA-P1-C2-C1-T1-S2"
public String physicalDrcIndex = "";
public Number physicalPortId = 0;
public String vnicDeviceMode = ""; // "NonVNIC"
public String configurationType = ""; // "Ethernet"
@FirstElement
public Number receivedPackets = 0.0;
@FirstElement
public Number sentPackets = 0.0;
@FirstElement
public Number droppedPackets = 0.0;
@FirstElement
public Number sentBytes = 0.0;
@FirstElement
public Number receivedBytes = 0.0;
@FirstElement
public Number errorIn = 0.0;
@FirstElement
public Number errorOut = 0.0;
@FirstElement
public Number transferredBytes = 0.0;
}

View File

@ -0,0 +1,29 @@
package biz.nellemann.hmci.dto.json;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
public final class SampleInfo {
@JsonProperty("timeStamp")
public String timestamp ;
public String getTimeStamp() {
return timestamp;
}
public Integer status ;
@JsonProperty("errorInfo")
public List<ErrorInfo> errors;
static class ErrorInfo {
public String errId;
public String errMsg;
public String uuid;
public String reportedBy;
public Integer occurrenceCount;
}
}

View File

@ -0,0 +1,11 @@
package biz.nellemann.hmci.dto.json;
public final class ServerMemory {
public double totalMem = 0.0;
public double availableMem = 0.0;
public double configurableMem = 0.0;
public double assignedMemToLpars = 0.0;
public double virtualPersistentMem = 0.0;
}

View File

@ -0,0 +1,10 @@
package biz.nellemann.hmci.dto.json;
public final class ServerProcessor {
public Double totalProcUnits = 0.0;
public Double utilizedProcUnits = 0.0;
public Double availableProcUnits = 0.0;
public Double configurableProcUnits = 0.0;
}

View File

@ -0,0 +1,15 @@
package biz.nellemann.hmci.dto.json;
import java.util.ArrayList;
import java.util.List;
public final class ServerUtil {
public final ServerProcessor processor = new ServerProcessor();
public final ServerMemory memory = new ServerMemory();
public PhysicalProcessorPool physicalProcessorPool = new PhysicalProcessorPool();
public List<SharedProcessorPool> sharedProcessorPool = new ArrayList<>();
public Network network = new Network();
}

View File

@ -0,0 +1,25 @@
package biz.nellemann.hmci.dto.json;
import java.util.List;
/**
* Network adapter
*/
public final class SharedAdapter {
public String id;
public String type;
public String physicalLocation;
public double receivedPackets;
public double sentPackets;
public double droppedPackets;
public double sentBytes;
public double receivedBytes;
public double transferredBytes;
public List<String> bridgedAdapters;
}

View File

@ -0,0 +1,15 @@
package biz.nellemann.hmci.dto.json;
public final class SharedProcessorPool {
public int id;
public String name;
public double assignedProcUnits = 0.0;
public double utilizedProcUnits = 0.0;
public double availableProcUnits = 0.0;
public double configuredProcUnits = 0.0;
public double borrowedProcUnits = 0.0;
}

View File

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

View File

@ -0,0 +1,14 @@
package biz.nellemann.hmci.dto.json;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
public final class SystemFirmware {
@JsonUnwrapped
public Double utilizedProcUnits;// = 0.0;
public Double assignedMem = 0.0;
}

View File

@ -0,0 +1,24 @@
package biz.nellemann.hmci.dto.json;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
import java.util.List;
public final class SystemUtil {
@JsonProperty("utilInfo")
public UtilInfo utilInfo;
public UtilInfo getUtilInfo() {
return utilInfo;
}
@JsonUnwrapped
@JsonProperty("utilSamples")
public List<UtilSample> samples;
public UtilSample getSample() {
return samples.size() > 0 ? samples.get(0) : new UtilSample();
}
}

View File

@ -1,13 +1,9 @@
package biz.nellemann.hmci.pcm;
import com.serjltt.moshi.adapters.FirstElement;
package biz.nellemann.hmci.dto.json;
public final class Temperature {
public String entityId = "";
public String entityInstance = "";
@FirstElement
public Number temperatureReading = 0.0;
}

View File

@ -0,0 +1,12 @@
package biz.nellemann.hmci.dto.json;
import java.util.ArrayList;
import java.util.List;
public final class ThermalUtil {
public List<Temperature> inletTemperatures = new ArrayList<>();
public List<Temperature> cpuTemperatures = new ArrayList<>();
public List<Temperature> baseboardTemperatures = new ArrayList<>();
}

View File

@ -1,7 +1,8 @@
package biz.nellemann.hmci.pcm;
package biz.nellemann.hmci.dto.json;
import com.serjltt.moshi.adapters.FirstElement;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties({ "metricArrayOrder" })
public final class UtilInfo {
public String version = "";
@ -13,7 +14,4 @@ public final class UtilInfo {
public String name = "";
public String uuid = "";
@FirstElement
public String metricArrayOrder = "";
}

View File

@ -0,0 +1,30 @@
package biz.nellemann.hmci.dto.json;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.ArrayList;
import java.util.List;
public final class UtilSample {
public String sampleType = "";
@JsonProperty("sampleInfo")
public SampleInfo sampleInfo = new SampleInfo();
public SampleInfo getInfo() {
return sampleInfo;
}
@JsonProperty("systemFirmwareUtil")
public SystemFirmware systemFirmwareUtil = new SystemFirmware();
public ServerUtil serverUtil = new ServerUtil();
public EnergyUtil energyUtil = new EnergyUtil();
public List<ViosUtil> viosUtil = new ArrayList<>();
public LparUtil lparsUtil = new LparUtil();
}

View File

@ -0,0 +1,7 @@
package biz.nellemann.hmci.dto.json;
public final class ViosMemory {
public double assignedMem;
public double utilizedMem;
public double virtualPersistentMem;
}

View File

@ -1,9 +1,9 @@
package biz.nellemann.hmci.pcm;
package biz.nellemann.hmci.dto.json;
public final class ViosUtil {
public String id = "";
public String uuid = "";
public int id;
public String uuid;
public String name = "";
public String state = "";
public Integer affinityScore = 0;

View File

@ -0,0 +1,30 @@
package biz.nellemann.hmci.dto.json;
/**
* Network adapter SEA
*/
public final class VirtualEthernetAdapter {
public String physicalLocation = "";
public Integer vlanId = 0;
public Integer vswitchId = 0;
public Boolean isPortVlanId = false;
public Integer viosId = 0;
public String sharedEthernetAdapterId = "";
public Double receivedPackets = 0.0;
public Double sentPackets = 0.0;
public Double droppedPackets = 0.0;
public Double sentBytes = 0.0;
public Double receivedBytes = 0.0;
public Double receivedPhysicalPackets = 0.0;
public Double sentPhysicalPackets = 0.0;
public Double droppedPhysicalPackets = 0.0;
public Double sentPhysicalBytes = 0.0;
public Double receivedPhysicalBytes = 0.0;
public Double transferredBytes = 0.0;
public Double transferredPhysicalBytes = 0.0;
}

View File

@ -0,0 +1,23 @@
package biz.nellemann.hmci.dto.json;
/**
* Storage adapter - NPIV ?
*/
public final class VirtualFiberChannelAdapter {
public String wwpn = "";
public String wwpn2 = "";
public String physicalLocation = "";
public String physicalPortWWPN = "";
public Integer viosId = 0;
public Double numOfReads = 0.0;
public Double numOfWrites = 0.0;
public Double readBytes = 0.0;
public Double writeBytes = 0.0;
public Double runningSpeed = 0.0;
public Double transmittedBytes = 0.0;
}

View File

@ -0,0 +1,12 @@
package biz.nellemann.hmci.dto.toml;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import java.util.Map;
@JsonIgnoreProperties(ignoreUnknown = true)
public class Configuration {
public InfluxConfiguration influx;
public Map<String, HmcConfiguration> hmc;
}

View File

@ -0,0 +1,28 @@
package biz.nellemann.hmci.dto.toml;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import java.util.ArrayList;
import java.util.List;
@JsonIgnoreProperties(ignoreUnknown = true)
public class HmcConfiguration {
public String url;
public String name;
public String username;
public String password;
public Integer refresh = 30;
public Integer discover = 120;
public String trace;
public Boolean energy = true;
public Boolean trust = true;
public List<String> excludeSystems = new ArrayList<>();
public List<String> includeSystems = new ArrayList<>();
public List<String> excludePartitions = new ArrayList<>();
public List<String> includePartitions = new ArrayList<>();
}

View File

@ -0,0 +1,17 @@
package biz.nellemann.hmci.dto.toml;
public class InfluxConfiguration {
public String url;
public String username;
public String password;
public String database;
/*public InfluxConfiguration(String url, String username, String password, String database) {
this.url = url;
this.username = username;
this.password = password;
this.database = database;
}*/
}

View File

@ -0,0 +1,16 @@
package biz.nellemann.hmci.dto.xml;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
@JsonIgnoreProperties({ "Atom", "ksv", "kxe", "kb", "schemaVersion", "" })
public class IFixDetail implements Serializable {
private static final long serialVersionUID = 1L;
@JsonProperty("IFix")
public String iFix;
}

View File

@ -0,0 +1,29 @@
package biz.nellemann.hmci.dto.xml;
import java.io.Serializable;
public class Link implements Serializable {
private static final long serialVersionUID = 1L;
public String rel;
public String getRel() {
return rel;
}
public String type;
public String getType() {
return type;
}
public String href;
public String getHref() {
return href;
}
}

View File

@ -0,0 +1,52 @@
package biz.nellemann.hmci.dto.xml;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
/*
@JsonIgnoreProperties({
"ksv", "kxe", "kb", "schemaVersion", "Metadata", "AllowPerformanceDataCollection",
"AssociatedPartitionProfile", "AvailabilityPriority", "CurrentProcessorCompatibilityMode", "CurrentProfileSync",
"IsBootable", "IsConnectionMonitoringEnabled", "IsOperationInProgress", "IsRedundantErrorPathReportingEnabled",
"IsTimeReferencePartition", "IsVirtualServiceAttentionLEDOn", "IsVirtualTrustedPlatformModuleEnabled",
"KeylockPosition", "LogicalSerialNumber", "OperatingSystemVersion", "PartitionCapabilities", "PartitionID",
"PartitionIOConfiguration", "PartitionMemoryConfiguration", "PartitionProcessorConfiguration", "PartitionProfiles",
"PendingProcessorCompatibilityMode", "ProcessorPool", "ProgressPartitionDataRemaining", "ProgressPartitionDataTotal",
"ProgressState", "ResourceMonitoringControlState", "ResourceMonitoringIPAddress", "AssociatedManagedSystem",
"ClientNetworkAdapters", "HostEthernetAdapterLogicalPorts", "MACAddressPrefix", "IsServicePartition",
"PowerVMManagementCapable", "ReferenceCode", "AssignAllResources", "HardwareAcceleratorQoS", "LastActivatedProfile",
"HasPhysicalIO", "AllowPerformanceDataCollection", "PendingSecureBoot", "CurrentSecureBoot", "BootMode",
"PowerOnWithHypervisor", "Description", "MigrationStorageViosDataStatus", "MigrationStorageViosDataTimestamp",
"RemoteRestartCapable", "SimplifiedRemoteRestartCapable", "HasDedicatedProcessorsForMigration", "SuspendCapable",
"MigrationDisable", "MigrationState", "RemoteRestartState", "VirtualFibreChannelClientAdapters",
"VirtualSCSIClientAdapters", "BootListInformation"
})
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class LogicalPartitionEntry implements Serializable, ResourceEntry {
private static final long serialVersionUID = 1L;
@JsonProperty("PartitionName")
public String partitionName;
@JsonProperty("PartitionState")
public String partitionState;
@JsonProperty("PartitionType")
public String partitionType;
@JsonProperty("PartitionUUID")
public String partitionUUID;
@JsonProperty("OperatingSystemType")
public String operatingSystemType;
@Override
public String getName() {
return partitionName.trim();
}
}

View File

@ -0,0 +1,21 @@
package biz.nellemann.hmci.dto.xml;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
@JsonIgnoreProperties({ "schemaVersion", "Metadata" })
public class LogonResponse implements Serializable {
private static final long serialVersionUID = 1L;
@JsonProperty("X-API-Session")
private String token;
public String getToken() {
return token;
}
}

View File

@ -0,0 +1,34 @@
package biz.nellemann.hmci.dto.xml;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
@JsonIgnoreProperties({ "kb", "kxe", "schemaVersion", "Metadata" })
public class MachineTypeModelAndSerialNumber implements Serializable {
private static final long serialVersionUID = 1L;
@JsonProperty("MachineType")
public String machineType;
public String getMachineType() {
return machineType;
}
@JsonProperty("Model")
public String model;
public String getModel() {
return model;
}
@JsonProperty("SerialNumber")
public String serialNumber;
public String getSerialNumber() {
return serialNumber;
}
}

View File

@ -0,0 +1,94 @@
package biz.nellemann.hmci.dto.xml;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/*
@JsonIgnoreProperties({
"schemaVersion", "Metadata", "AssociatedIPLConfiguration", "AssociatedSystemCapabilities",
"AssociatedSystemIOConfiguration", "AssociatedSystemMemoryConfiguration", "AssociatedSystemProcessorConfiguration",
"AssociatedSystemSecurity", "DetailedState", "ManufacturingDefaultConfigurationEnabled", "MaximumPartitions",
"MaximumPowerControlPartitions", "MaximumRemoteRestartPartitions", "MaximumSharedProcessorCapablePartitionID",
"MaximumSuspendablePartitions", "MaximumBackingDevicesPerVNIC", "PhysicalSystemAttentionLEDState",
"PrimaryIPAddress", "ServiceProcessorFailoverEnabled", "ServiceProcessorFailoverReason", "ServiceProcessorFailoverState",
"ServiceProcessorVersion", "VirtualSystemAttentionLEDState", "SystemMigrationInformation", "ReferenceCode",
"MergedReferenceCode", "EnergyManagementConfiguration", "IsPowerVMManagementMaster", "IsClassicHMCManagement",
"IsPowerVMManagementWithoutMaster", "IsManagementPartitionPowerVMManagementMaster", "IsHMCPowerVMManagementMaster",
"IsNotPowerVMManagementMaster", "IsPowerVMManagementNormalMaster", "IsPowerVMManagementPersistentMaster",
"IsPowerVMManagementTemporaryMaster", "IsPowerVMManagementPartitionEnabled", "SupportedHardwareAcceleratorTypes",
"CurrentStealableProcUnits", "CurrentStealableMemory", "Description", "SystemLocation", "SystemType",
"ProcessorThrottling", "AssociatedPersistentMemoryConfiguration"
})*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class ManagedSystemEntry implements Serializable, ResourceEntry {
private static final long serialVersionUID = 1L;
@JsonProperty("State")
public String state;
@JsonProperty("Hostname")
public String hostname;
//@JsonAlias("ActivatedLevel")
@JsonProperty("ActivatedLevel")
public Integer activatedLevel;
public Integer getActivatedLevel() {
return activatedLevel;
}
@JsonAlias("ActivatedServicePackNameAndLevel")
public String activatedServicePackNameAndLevel;
public String getActivatedServicePackNameAndLevel() {
return activatedServicePackNameAndLevel;
}
@JsonAlias("SystemName")
public String systemName = "";
public String getSystemName() {
return systemName.trim();
}
@Override
public String getName() {
return systemName.trim();
}
@JsonProperty("SystemTime")
public Long systemTime;
@JsonProperty("SystemFirmware")
public String systemFirmware;
@JsonAlias("AssociatedLogicalPartitions")
public List<Link> associatedLogicalPartitions;
public List<Link> getAssociatedLogicalPartitions() {
return associatedLogicalPartitions != null ? associatedLogicalPartitions : new ArrayList<>();
}
@JsonAlias("AssociatedVirtualIOServers")
public List<Link> associatedVirtualIOServers;
public List<Link> getAssociatedVirtualIOServers() {
return associatedVirtualIOServers != null ? associatedVirtualIOServers : new ArrayList<>();
}
@JsonAlias("MachineTypeModelAndSerialNumber")
public MachineTypeModelAndSerialNumber machineTypeModelAndSerialNumber;
public MachineTypeModelAndSerialNumber getMachineTypeModelAndSerialNumber() {
return machineTypeModelAndSerialNumber;
}
}

View File

@ -0,0 +1,99 @@
package biz.nellemann.hmci.dto.xml;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/*
@JsonIgnoreProperties({
"schemaVersion", "Metadata", "NetworkInterfaces", "Driver", "LicenseID", "LicenseFirstYear", "UVMID",
"TemplateObjectModelVersion", "UserObjectModelVersion", "WebObjectModelVersion", "PublicSSHKeyValue",
"MinimumKeyStoreSize", "MinimumKeyStoreSize"
})*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class ManagementConsoleEntry implements Serializable, ResourceEntry {
private static final long serialVersionUID = 1L;
@JsonProperty("MachineTypeModelAndSerialNumber")
private MachineTypeModelAndSerialNumber machineTypeModelAndSerialNumber;
public MachineTypeModelAndSerialNumber getMachineTypeModelAndSerialNumber() {
return machineTypeModelAndSerialNumber;
}
@JsonProperty("ManagedSystems")
protected List<Link> associatedManagedSystems;
public List<Link> getAssociatedManagedSystems() {
// TODO: Security - Return new array, so receiver cannot modify ours.
return new ArrayList<>(associatedManagedSystems);
}
@JsonProperty("ManagementConsoleName")
public String managementConsoleName;
@Override
public String getName() {
return managementConsoleName.replace("\n", "").trim();
}
@JsonProperty("VersionInfo")
public VersionInfo versionInfo;
@JsonProperty("BIOS")
protected String bios;
@JsonProperty("BaseVersion")
protected String baseVersion;
public String getBaseVersion() {
return baseVersion;
}
@JsonProperty("IFixDetails")
public IFixDetails iFixDetails;
@JsonIgnoreProperties({ "ksv", "kxe", "kb", "schemaVersion", "Metadata" })
static class IFixDetails {
@JsonProperty("IFixDetail")
public List<IFixDetail> iFixDetailList;
}
@JsonProperty("ProcConfiguration")
public ProcConfiguration procConfiguration;
@JsonIgnoreProperties({ "ksv", "kxe", "kb", "schemaVersion", "Metadata", "Atom" })
static class ProcConfiguration {
@JsonProperty("NumberOfProcessors")
public Integer numberOfProcessors;
@JsonProperty("ModelName")
public String modelName;
@JsonProperty("Architecture")
public String architecture;
}
@JsonProperty("MemConfiguration")
public MemConfiguration memConfiguration;
@JsonIgnoreProperties({ "ksv", "kxe", "kb", "schemaVersion", "Metadata", "Atom" })
static class MemConfiguration {
@JsonProperty("TotalMemory")
public Integer totalMemory;
@JsonProperty("TotalSwapMemory")
public Integer totalSwapMemory;
}
}

View File

@ -0,0 +1,6 @@
package biz.nellemann.hmci.dto.xml;
public interface ResourceEntry {
String getName();
}

View File

@ -0,0 +1,32 @@
package biz.nellemann.hmci.dto.xml;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
@JsonIgnoreProperties({ "kxe", "kb", "schemaVersion", "Metadata" })
public class VersionInfo implements Serializable {
private static final long serialVersionUID = 1L;
@JsonProperty("BuildLevel")
public String buildLevel;
@JsonProperty("Maintenance")
protected String maintenance;
@JsonProperty("Minor")
protected String minor;
@JsonProperty("Release")
protected String release;
@JsonProperty("ServicePackName")
public String servicePackName;
@JsonProperty("Version")
protected String version;
}

View File

@ -0,0 +1,26 @@
package biz.nellemann.hmci.dto.xml;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
@JsonIgnoreProperties(ignoreUnknown = true)
public class VirtualIOServerEntry implements Serializable, ResourceEntry {
private static final long serialVersionUID = 1L;
@JsonProperty("PartitionName")
private String partitionName;
public String getPartitionName() {
return partitionName;
}
@Override
public String getName() {
return partitionName;
}
}

View File

@ -0,0 +1,97 @@
package biz.nellemann.hmci.dto.xml;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.util.List;
//@JsonIgnoreProperties({ "author", "etag" })
@JsonIgnoreProperties(ignoreUnknown = true)
public class XmlEntry implements Serializable {
private static final long serialVersionUID = 1L;
public String id; // 2c6b6620-e3e3-3294-aaf5-38e546ff672b
public String title; // ManagementConsole
public String published; // 2021-11-09T21:13:40.467+01:00
public Category category;
@JsonIgnoreProperties(ignoreUnknown = true)
public class Category {
public String term;
}
@JsonProperty("link")
public Link link;
//public List<Link> links;
/*public List<Link> getLinks() {
return links;
}
*/
public Content content;
public Content getContent() {
return content;
}
public boolean hasContent() {
return content != null;
}
@JsonIgnoreProperties({ "type" })
public static class Content {
@JsonProperty("ManagementConsole")
private ManagementConsoleEntry managementConsoleEntry;
public ManagementConsoleEntry getManagementConsole() {
return managementConsoleEntry;
}
public boolean isManagementConsole() {
return managementConsoleEntry != null;
}
@JsonProperty("ManagedSystem")
private ManagedSystemEntry managedSystemEntry;
public ManagedSystemEntry getManagedSystemEntry() {
return managedSystemEntry;
}
public boolean isManagedSystem() {
return managedSystemEntry != null;
}
@JsonAlias("VirtualIOServer")
private VirtualIOServerEntry virtualIOServerEntry;
public VirtualIOServerEntry getVirtualIOServerEntry() {
return virtualIOServerEntry;
}
public boolean isVirtualIOServer() {
return virtualIOServerEntry != null;
}
@JsonAlias("LogicalPartition")
private LogicalPartitionEntry logicalPartitionEntry;
public LogicalPartitionEntry getLogicalPartitionEntry() {
return logicalPartitionEntry;
}
public boolean isLogicalPartition() {
return logicalPartitionEntry != null;
}
}
}

View File

@ -0,0 +1,35 @@
package biz.nellemann.hmci.dto.xml;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
//@JsonIgnoreProperties({ "link" })
@JsonIgnoreProperties(ignoreUnknown = true)
public class XmlFeed implements Serializable {
private static final long serialVersionUID = 1L;
public String id; // 347ecfcf-acac-3724-8915-a3d7d7a6f298
public String updated; // 2021-11-09T21:13:39.591+01:00
public String generator; // IBM Power Systems Management Console
@JsonProperty("link")
@JacksonXmlElementWrapper(useWrapping = false)
public List<Link> links; // <link rel="SELF" href="https://10.32.64.39:12443/rest/api/uom/ManagementConsole"/>
@JsonProperty("entry")
@JacksonXmlElementWrapper(useWrapping = false)
public List<XmlEntry> entries;
public XmlEntry getEntry() {
return entries.size() > 0 ? entries.get(0) : null;
}
}

View File

@ -1,6 +0,0 @@
package biz.nellemann.hmci.pcm;
public final class EnergyUtil {
public final PowerUtil powerUtil = new PowerUtil();
public final ThermalUtil thermalUtil = new ThermalUtil();
}

View File

@ -1,30 +0,0 @@
package biz.nellemann.hmci.pcm;
import com.serjltt.moshi.adapters.FirstElement;
public final class FiberChannelAdapter {
public String id = "";
public String wwpn = "";
public String physicalLocation = "";
public Integer numOfPorts = 0;
@FirstElement
public Number numOfReads = 0.0;
@FirstElement
public Number numOfWrites = 0.0;
@FirstElement
public Number readBytes = 0.0;
@FirstElement
public Number writeBytes = 0.0;
@FirstElement
public Number runningSpeed = 0.0;
@FirstElement
public Number transmittedBytes = 0.0;
}

View File

@ -1,29 +0,0 @@
package biz.nellemann.hmci.pcm;
import com.serjltt.moshi.adapters.FirstElement;
public final class GenericAdapter {
public String id = "";
public String type = "";
public String physicalLocation = "";
@FirstElement
public Number receivedPackets = 0.0;
@FirstElement
public Number sentPackets = 0.0;
@FirstElement
public Number droppedPackets = 0.0;
@FirstElement
public Number sentBytes = 0.0;
@FirstElement
public Number receivedBytes = 0.0;
@FirstElement
public Number transferredBytes = 0.0;
}

View File

@ -1,26 +0,0 @@
package biz.nellemann.hmci.pcm;
import com.serjltt.moshi.adapters.FirstElement;
public final class GenericPhysicalAdapters {
public String id = "";
public String type = "";
public String physicalLocation = "";
@FirstElement
public Number numOfReads = 0.0;
@FirstElement
public Number numOfWrites = 0.0;
@FirstElement
public Number readBytes = 0.0;
@FirstElement
public Number writeBytes = 0.0;
@FirstElement
public Number transmittedBytes = 0.0;
}

View File

@ -1,28 +0,0 @@
package biz.nellemann.hmci.pcm;
import com.serjltt.moshi.adapters.FirstElement;
public final class GenericVirtualAdapter {
public String id = "";
public String type = "";
public Integer viosId = 0;
public String physicalLocation = "";
@FirstElement
public Number numOfReads = 0.0;
@FirstElement
public Number numOfWrites = 0.0;
@FirstElement
public Number readBytes = 0.0;
@FirstElement
public Number writeBytes = 0.0;
@FirstElement
public Number transmittedBytes = 0.0;
}

View File

@ -1,16 +0,0 @@
package biz.nellemann.hmci.pcm;
import com.serjltt.moshi.adapters.FirstElement;
public final class LparMemory {
@FirstElement
public Number logicalMem = 0.0;
@FirstElement
public Number utilizedMem = 0.0;
@FirstElement
public Number backedPhysicalMem = 0.0;
}

View File

@ -1,44 +0,0 @@
package biz.nellemann.hmci.pcm;
import com.serjltt.moshi.adapters.FirstElement;
public final class LparProcessor {
public Integer poolId = 0;
public Integer weight = 0;
public String mode = "";
@FirstElement
public Number maxVirtualProcessors = 0.0;
@FirstElement
public Number currentVirtualProcessors = 0.0;
@FirstElement
public Number maxProcUnits = 0.0;
@FirstElement
public Number entitledProcUnits = 0.0;
@FirstElement
public Number utilizedProcUnits = 0.0;
@FirstElement
public Number utilizedCappedProcUnits = 0.0;
@FirstElement
public Number utilizedUncappedProcUnits = 0.0;
@FirstElement
public Number idleProcUnits = 0.0;
@FirstElement
public Number donatedProcUnits = 0.0;
@FirstElement
public Number timeSpentWaitingForDispatch = 0.0;
@FirstElement
public Number timePerInstructionExecution = 0.0;
}

View File

@ -1,15 +0,0 @@
package biz.nellemann.hmci.pcm;
import java.util.ArrayList;
import java.util.List;
public final class Network {
public final List<String> clientLpars = new ArrayList<>();
public final List<GenericAdapter> genericAdapters = new ArrayList<>();
public final List<SharedAdapter> sharedAdapters = new ArrayList<>();
public final List<VirtualEthernetAdapter> virtualEthernetAdapters = new ArrayList<>();
public final List<SriovLogicalPort> sriovLogicalPorts = new ArrayList<>();
}

View File

@ -1,7 +0,0 @@
package biz.nellemann.hmci.pcm;
public final class PcmData {
public final SystemUtil systemUtil = new SystemUtil();
}

View File

@ -1,22 +0,0 @@
package biz.nellemann.hmci.pcm;
import com.serjltt.moshi.adapters.FirstElement;
public final class PhysicalProcessorPool {
@FirstElement
public Number assignedProcUnits = 0.0;
@FirstElement
public Number utilizedProcUnits = 0.0;
@FirstElement
public Number availableProcUnits = 0.0;
@FirstElement
public Number configuredProcUnits = 0.0;
@FirstElement
public Number borrowedProcUnits = 0.0;
}

View File

@ -1,11 +0,0 @@
package biz.nellemann.hmci.pcm;
import com.serjltt.moshi.adapters.FirstElement;
public final class PowerUtil {
@FirstElement
public Number powerReading = 0.0;
}

View File

@ -1,8 +0,0 @@
package biz.nellemann.hmci.pcm;
public final class SampleInfo {
public String timeStamp = "";
public Integer status = 0;
}

View File

@ -1,22 +0,0 @@
package biz.nellemann.hmci.pcm;
import com.serjltt.moshi.adapters.FirstElement;
public final class ServerMemory {
@FirstElement
public Number totalMem = 0.0;
@FirstElement
public Number availableMem = 0.0;
@FirstElement
public Number configurableMem = 0.0;
@FirstElement
public Number assignedMemToLpars = 0.0;
@FirstElement
public Number virtualPersistentMem = 0.0;
}

View File

@ -1,19 +0,0 @@
package biz.nellemann.hmci.pcm;
import com.serjltt.moshi.adapters.FirstElement;
public final class ServerProcessor {
@FirstElement
public Number totalProcUnits = 0.0;
@FirstElement
public Number utilizedProcUnits = 0.0;
@FirstElement
public Number availableProcUnits = 0.0;
@FirstElement
public Number configurableProcUnits = 0.0;
}

View File

@ -1,13 +0,0 @@
package biz.nellemann.hmci.pcm;
import java.util.ArrayList;
import java.util.List;
public final class ServerUtil {
public final ServerProcessor processor = new ServerProcessor();
public final ServerMemory memory = new ServerMemory();
public final PhysicalProcessorPool physicalProcessorPool = new PhysicalProcessorPool();
public final List<SharedProcessorPool> sharedProcessorPool = new ArrayList<>();
}

View File

@ -1,32 +0,0 @@
package biz.nellemann.hmci.pcm;
import com.serjltt.moshi.adapters.FirstElement;
public final class SharedAdapter {
public String id = "";
public String type = "";
public String physicalLocation = "";
@FirstElement
public Number receivedPackets = 0.0;
@FirstElement
public Number sentPackets = 0.0;
@FirstElement
public Number droppedPackets = 0.0;
@FirstElement
public Number sentBytes = 0.0;
@FirstElement
public Number receivedBytes = 0.0;
@FirstElement
public Number transferredBytes = 0.0;
@FirstElement
public String bridgedAdapters = "";
}

View File

@ -1,25 +0,0 @@
package biz.nellemann.hmci.pcm;
import com.serjltt.moshi.adapters.FirstElement;
public final class SharedProcessorPool {
public String id = "";
public String name = "";
@FirstElement
public Number assignedProcUnits = 0.0;
@FirstElement
public Number utilizedProcUnits = 0.0;
@FirstElement
public Number availableProcUnits = 0.0;
@FirstElement
public Number configuredProcUnits = 0.0;
@FirstElement
public Number borrowedProcUnits = 0.0;
}

View File

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

View File

@ -1,13 +0,0 @@
package biz.nellemann.hmci.pcm;
import com.serjltt.moshi.adapters.FirstElement;
public final class SystemFirmware {
@FirstElement
public Number utilizedProcUnits = 0.0;
@FirstElement
public Number assignedMem = 0.0;
}

View File

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

View File

@ -1,12 +0,0 @@
package biz.nellemann.hmci.pcm;
import java.util.ArrayList;
import java.util.List;
public final class ThermalUtil {
public final List<Temperature> inletTemperatures = new ArrayList<>();
public final List<Temperature> cpuTemperatures = new ArrayList<>();
public final List<Temperature> baseboardTemperatures = new ArrayList<>();
}

View File

@ -1,20 +0,0 @@
package biz.nellemann.hmci.pcm;
import com.serjltt.moshi.adapters.FirstElement;
import java.util.ArrayList;
import java.util.List;
public final class UtilSample {
public String sampleType = "";
public final SampleInfo sampleInfo = new SampleInfo();
public final SystemFirmware systemFirmwareUtil = new SystemFirmware();
public final ServerUtil serverUtil = new ServerUtil();
public final EnergyUtil energyUtil = new EnergyUtil();
public final List<ViosUtil> viosUtil = new ArrayList<>();
@FirstElement
public final LparUtil lparsUtil = new LparUtil();
}

View File

@ -1,13 +0,0 @@
package biz.nellemann.hmci.pcm;
import com.serjltt.moshi.adapters.FirstElement;
public final class ViosMemory {
@FirstElement
public Number assignedMem = 0.0;
@FirstElement
public Number utilizedMem = 0.0;
}

View File

@ -1,51 +0,0 @@
package biz.nellemann.hmci.pcm;
import com.serjltt.moshi.adapters.FirstElement;
public final class VirtualEthernetAdapter {
public String physicalLocation = "";
public Integer vlanId = 0;
public Integer vswitchId = 0;
public Boolean isPortVlanId = false;
public Integer viosId = 0;
public String sharedEthernetAdapterId = "";
@FirstElement
public Number receivedPackets = 0.0;
@FirstElement
public Number sentPackets = 0.0;
@FirstElement
public Number droppedPackets = 0.0;
@FirstElement
public Number sentBytes = 0.0;
@FirstElement
public Number receivedBytes = 0.0;
@FirstElement
public Number receivedPhysicalPackets = 0.0;
@FirstElement
public Number sentPhysicalPackets = 0.0;
@FirstElement
public Number droppedPhysicalPackets = 0.0;
@FirstElement
public Number sentPhysicalBytes = 0.0;
@FirstElement
public Number receivedPhysicalBytes = 0.0;
@FirstElement
public Number transferredBytes = 0.0;
@FirstElement
public Number transferredPhysicalBytes = 0.0;
}

View File

@ -1,31 +0,0 @@
package biz.nellemann.hmci.pcm;
import com.serjltt.moshi.adapters.FirstElement;
public final class VirtualFiberChannelAdapter {
public String wwpn = "";
public String wwpn2 = "";
public String physicalLocation = "";
public String physicalPortWWPN = "";
public Integer viosId = 0;
@FirstElement
public Number numOfReads = 0.0;
@FirstElement
public Number numOfWrites = 0.0;
@FirstElement
public Number readBytes = 0.0;
@FirstElement
public Number writeBytes = 0.0;
@FirstElement
public Number runningSpeed = 0.0;
@FirstElement
public Number transmittedBytes = 0.0;
}

View File

@ -1,5 +1,8 @@
package biz.nellemann.hmci
import biz.nellemann.hmci.dto.toml.Configuration
import biz.nellemann.hmci.dto.toml.HmcConfiguration
import com.fasterxml.jackson.dataformat.toml.TomlMapper
import spock.lang.Specification
import java.nio.file.Path
@ -10,36 +13,52 @@ class ConfigurationTest extends Specification {
Path testConfigurationFile = Paths.get(getClass().getResource('/hmci.toml').toURI())
TomlMapper mapper
def setup() {
mapper = new TomlMapper();
}
def cleanup() {
}
void "test parsing of configuration file"() {
when:
Configuration conf = new Configuration(testConfigurationFile)
Configuration conf = mapper.readerFor(Configuration.class).readValue(testConfigurationFile.toFile())
println(conf.hmc.entrySet().forEach((e) -> {
println((String)e.key + " -> " + e);
HmcConfiguration c = e.value;
println(c.url);
}));
then:
conf != null
}
void "test HMC energy flag, default setting"() {
when:
Configuration conf = mapper.readerFor(Configuration.class).readValue(testConfigurationFile.toFile())
then:
!conf.hmc.get("site1").energy
}
void "test energy flag, default setting"() {
void "test HMC exclude and include options"() {
when:
Configuration conf = new Configuration(testConfigurationFile)
Configuration conf = mapper.readerFor(Configuration.class).readValue(testConfigurationFile.toFile())
then:
!conf.getHmc().get(0).energy
}
void "test exclude and include options"() {
when:
Configuration conf = new Configuration(testConfigurationFile)
then:
conf.getHmc().get(0).excludeSystems.contains("notThisSys")
conf.getHmc().get(0).includeSystems.contains("onlyThisSys")
conf.getHmc().get(0).excludePartitions.contains("notThisPartition")
conf.getHmc().get(0).includePartitions.contains("onlyThisPartition")
conf.hmc.get("site1").excludeSystems.contains("notThisSys")
conf.hmc.get("site1").includeSystems.contains("onlyThisSys")
conf.hmc.get("site1").excludePartitions.contains("notThisPartition")
conf.hmc.get("site1").includePartitions.contains("onlyThisPartition")
}

View File

@ -1,102 +0,0 @@
package biz.nellemann.hmci
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import spock.lang.Specification
class HmcRestClientTest extends Specification {
HmcRestClient hmc
MockWebServer mockServer = new MockWebServer()
def setup() {
mockServer.start()
hmc = new HmcRestClient(mockServer.url("/").toString(), "testUser", "testPassword", true)
hmc.authToken = "blaBla"
}
def cleanup() {
mockServer.shutdown()
}
void "test against empty xml"() {
setup:
def testXml = ""
mockServer.enqueue(new MockResponse().setBody(testXml))
when:
Map<String, ManagedSystem> systems = hmc.getManagedSystems()
then:
systems.size() == 0
}
void "test getManagedSystems"() {
setup:
def testFile = new File(getClass().getResource('/managed-systems.xml').toURI())
def testXml = testFile.getText('UTF-8')
mockServer.enqueue(new MockResponse().setBody(testXml))
when:
Map<String, ManagedSystem> systems = hmc.getManagedSystems()
then:
systems.size() == 2
systems.get("e09834d1-c930-3883-bdad-405d8e26e166").name == "S822L-8247-213C1BA"
}
void "test getLogicalPartitionsForManagedSystem"() {
setup:
def testFile = new File(getClass().getResource('/logical-partitions.xml').toURI())
def testXml = testFile.getText('UTF-8')
mockServer.enqueue(new MockResponse().setBody(testXml))
when:
ManagedSystem system = new ManagedSystem("e09834d1-c930-3883-bdad-405d8e26e166", "Test Name","Test Type", "Test Model", "Test S/N")
Map<String, LogicalPartition> partitions = hmc.getLogicalPartitionsForManagedSystem(system)
then:
partitions.size() == 12
partitions.get("3380A831-9D22-4F03-A1DF-18B249F0FF8E").name == "AIX_Test1-e0f725f0-00000005"
partitions.get("3380A831-9D22-4F03-A1DF-18B249F0FF8E").type == "AIX/Linux"
}
void "test getBody with JSON for ManagedSystem"() {
setup:
def testFile = new File(getClass().getResource('/pcm-data-managed-system.json').toURI())
def testJson = testFile.getText('UTF-8')
mockServer.enqueue(new MockResponse().setBody(testJson))
when:
String jsonString = hmc.sendGetRequest(new URL(mockServer.url("/rest/api/pcm/ProcessedMetrics/ManagedSystem_e09834d1-c930-3883-bdad-405d8e26e166_20200807T122600+0200_20200807T122600+0200_30.json") as String))
then:
jsonString.contains('"uuid": "e09834d1-c930-3883-bdad-405d8e26e166"')
}
void "test getBody with JSON for LogicalPartition"() {
setup:
def testFile = new File(getClass().getResource('/pcm-data-logical-partition.json').toURI())
def testJson = testFile.getText('UTF-8')
mockServer.enqueue(new MockResponse().setBody(testJson))
when:
String jsonString = hmc.sendGetRequest(new URL(mockServer.url("/rest/api/pcm/ProcessedMetrics/LogicalPartition_2DE05DB6-8AD5-448F-8327-0F488D287E82_20200807T123730+0200_20200807T123730+0200_30.json") as String))
then:
jsonString.contains('"uuid": "b597e4da-2aab-3f52-8616-341d62153559"')
}
// getPcmDataForManagedSystem
// getPcmDataForLogicalPartition
}

View File

@ -1,5 +1,6 @@
package biz.nellemann.hmci
import biz.nellemann.hmci.dto.toml.InfluxConfiguration
import spock.lang.Ignore
import spock.lang.Specification
@ -9,7 +10,7 @@ class InfluxClientTest extends Specification {
InfluxClient influxClient
def setup() {
influxClient = new InfluxClient(new Configuration.InfluxObject("http://localhost:8086", "root", "", "hmci"))
influxClient = new InfluxClient(new InfluxConfiguration("http://localhost:8086", "root", "", "hmci"))
influxClient.login()
}

View File

@ -1,101 +1,145 @@
package biz.nellemann.hmci
import biz.nellemann.hmci.dto.xml.LogicalPartitionEntry
import org.mockserver.integration.ClientAndServer
import org.mockserver.logging.MockServerLogger
import org.mockserver.socket.PortFactory
import org.mockserver.socket.tls.KeyStoreFactory
import spock.lang.Shared
import spock.lang.Specification
import javax.net.ssl.HttpsURLConnection
class LogicalPartitionTest extends Specification {
@Shared
private static ClientAndServer mockServer;
void "test processPcmJson for LogicalPartition"() {
@Shared
private RestClient serviceClient
setup:
def testFile = new File(getClass().getResource('/pcm-data-logical-partition.json').toURI())
def testJson = testFile.getText('UTF-8')
@Shared
private ManagedSystem managedSystem
when:
ManagedSystem system = new ManagedSystem("e09834d1-c930-3883-bdad-405d8e26e166", "Test Name","Test Type", "Test Model", "Test S/N")
LogicalPartition lpar = new LogicalPartition("2DE05DB6-8AD5-448F-8327-0F488D287E82", "9Flash01", "OS400", system)
lpar.processMetrics(testJson)
@Shared
private LogicalPartition logicalPartition
then:
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
@Shared
private File metricsFile
def setupSpec() {
HttpsURLConnection.setDefaultSSLSocketFactory(new KeyStoreFactory(new MockServerLogger()).sslContext().getSocketFactory());
mockServer = ClientAndServer.startClientAndServer(PortFactory.findFreePort());
serviceClient = new RestClient(String.format("http://localhost:%d", mockServer.getPort()), "user", "password", false)
MockResponses.prepareClientResponseForLogin(mockServer)
MockResponses.prepareClientResponseForManagedSystem(mockServer)
MockResponses.prepareClientResponseForVirtualIOServer(mockServer)
MockResponses.prepareClientResponseForLogicalPartition(mockServer)
serviceClient.login()
managedSystem = new ManagedSystem(serviceClient, String.format("%s/rest/api/uom/ManagementConsole/2c6b6620-e3e3-3294-aaf5-38e546ff672b/ManagedSystem/b597e4da-2aab-3f52-8616-341d62153559", serviceClient.baseUrl));
managedSystem.discover()
logicalPartition = managedSystem.logicalPartitions.first()
logicalPartition.refresh()
metricsFile = new File("src/test/resources/3-logical-partition-perf-data.json")
}
def cleanupSpec() {
mockServer.stop()
}
def setup() {
}
def "check that we found 2 logical partitions"() {
expect:
managedSystem.logicalPartitions.size() == 18
}
def "check name of 1st virtual server"() {
when:
LogicalPartitionEntry entry = logicalPartition.entry
then:
entry.getName() == "rhel8-ocp-helper"
}
void "process metrics data"() {
when:
logicalPartition.deserialize(metricsFile.getText('UTF-8'))
then:
logicalPartition.metric != null
}
void "test basic metrics"() {
when:
logicalPartition.deserialize(metricsFile.getText('UTF-8'))
then:
logicalPartition.metric.getSample().lparsUtil.memory.logicalMem == 8192.000
logicalPartition.metric.getSample().lparsUtil.processor.utilizedProcUnits == 0.001
logicalPartition.metric.getSample().lparsUtil.network.virtualEthernetAdapters.first().receivedBytes == 276.467
}
void "test getDetails"() {
setup:
def testFile = new File(getClass().getResource('/pcm-data-logical-partition.json').toURI())
def testJson = testFile.getText('UTF-8')
ManagedSystem system = new ManagedSystem("e09834d1-c930-3883-bdad-405d8e26e166", "Test Name","Test Type", "Test Model", "Test S/N")
LogicalPartition lpar = new LogicalPartition("2DE05DB6-8AD5-448F-8327-0F488D287E82", "9Flash01", "OS400", system)
when:
lpar.processMetrics(testJson)
List<Measurement> listOfMeasurements = lpar.getDetails()
logicalPartition.deserialize(metricsFile.getText('UTF-8'))
List<Measurement> listOfMeasurements = logicalPartition.getDetails()
then:
listOfMeasurements.size() == 1
listOfMeasurements.first().fields['affinityScore'] == 100.0
listOfMeasurements.first().fields['osType'] == 'Linux'
listOfMeasurements.first().fields['type'] == 'AIX/Linux'
listOfMeasurements.first().tags['lparname'] == '9Flash01'
listOfMeasurements.first().tags['lparname'] == 'rhel8-ocp-helper'
}
void "test getMemoryMetrics"() {
setup:
def testFile = new File(getClass().getResource('/pcm-data-logical-partition.json').toURI())
def testJson = testFile.getText('UTF-8')
ManagedSystem system = new ManagedSystem("e09834d1-c930-3883-bdad-405d8e26e166", "Test Name","Test Type", "Test Model", "Test S/N")
LogicalPartition lpar = new LogicalPartition("2DE05DB6-8AD5-448F-8327-0F488D287E82", "9Flash01", "OS400", system)
when:
lpar.processMetrics(testJson)
List<Measurement> listOfMeasurements = lpar.getMemoryMetrics()
logicalPartition.deserialize(metricsFile.getText('UTF-8'))
List<Measurement> listOfMeasurements = logicalPartition.getMemoryMetrics()
then:
listOfMeasurements.size() == 1
listOfMeasurements.first().fields['logicalMem'] == 8192.000
listOfMeasurements.first().tags['lparname'] == '9Flash01'
listOfMeasurements.first().tags['lparname'] == 'rhel8-ocp-helper'
}
void "test getProcessorMetrics"() {
setup:
def testFile = new File(getClass().getResource('/pcm-data-logical-partition.json').toURI())
def testJson = testFile.getText('UTF-8')
ManagedSystem system = new ManagedSystem("e09834d1-c930-3883-bdad-405d8e26e166", "Test Name","Test Type", "Test Model", "Test S/N")
LogicalPartition lpar = new LogicalPartition("2DE05DB6-8AD5-448F-8327-0F488D287E82", "9Flash01", "OS400", system)
when:
lpar.processMetrics(testJson)
List<Measurement> listOfMeasurements = lpar.getProcessorMetrics()
logicalPartition.deserialize(metricsFile.getText('UTF-8'))
List<Measurement> listOfMeasurements = logicalPartition.getProcessorMetrics()
then:
listOfMeasurements.size() == 1
listOfMeasurements.first().fields['utilizedProcUnits'] == 0.001
listOfMeasurements.first().tags['lparname'] == '9Flash01'
listOfMeasurements.first().tags['lparname'] == 'rhel8-ocp-helper'
}
void "test getVirtualEthernetAdapterMetrics"() {
setup:
def testFile = new File(getClass().getResource('/pcm-data-logical-partition.json').toURI())
def testJson = testFile.getText('UTF-8')
ManagedSystem system = new ManagedSystem("e09834d1-c930-3883-bdad-405d8e26e166", "Test Name","Test Type", "Test Model", "Test S/N")
LogicalPartition lpar = new LogicalPartition("2DE05DB6-8AD5-448F-8327-0F488D287E82", "9Flash01", "OS400", system)
when:
lpar.processMetrics(testJson)
List<Measurement> listOfMeasurements = lpar.getVirtualEthernetAdapterMetrics()
logicalPartition.deserialize(metricsFile.getText('UTF-8'))
List<Measurement> listOfMeasurements = logicalPartition.getVirtualEthernetAdapterMetrics()
then:
listOfMeasurements.size() == 1
@ -103,17 +147,12 @@ class LogicalPartitionTest extends Specification {
listOfMeasurements.first().tags['location'] == 'U9009.42A.21F64EV-V13-C32'
}
void "test getVirtualFiberChannelAdaptersMetrics"() {
setup:
def testFile = new File(getClass().getResource('/pcm-data-logical-partition.json').toURI())
def testJson = testFile.getText('UTF-8')
ManagedSystem system = new ManagedSystem("e09834d1-c930-3883-bdad-405d8e26e166", "Test Name","Test Type", "Test Model", "Test S/N")
LogicalPartition lpar = new LogicalPartition("2DE05DB6-8AD5-448F-8327-0F488D287E82", "9Flash01", "OS400", system)
when:
lpar.processMetrics(testJson)
List<Measurement> listOfMeasurements = lpar.getVirtualFibreChannelAdapterMetrics()
logicalPartition.deserialize(metricsFile.getText('UTF-8'))
List<Measurement> listOfMeasurements = logicalPartition.getVirtualFibreChannelAdapterMetrics()
then:
listOfMeasurements.size() == 4
@ -122,48 +161,16 @@ class LogicalPartitionTest extends Specification {
}
void "test getVirtualGenericAdapterMetrics"() {
setup:
def testFile = new File(getClass().getResource('/pcm-data-logical-partition.json').toURI())
def testJson = testFile.getText('UTF-8')
ManagedSystem system = new ManagedSystem("e09834d1-c930-3883-bdad-405d8e26e166", "Test Name","Test Type", "Test Model", "Test S/N")
LogicalPartition lpar = new LogicalPartition("2DE05DB6-8AD5-448F-8327-0F488D287E82", "9Flash01", "OS400", system)
when:
lpar.processMetrics(testJson)
List<Measurement> listOfMeasurements = lpar.getVirtualGenericAdapterMetrics()
logicalPartition.deserialize(metricsFile.getText('UTF-8'))
List<Measurement> listOfMeasurements = logicalPartition.getVirtualGenericAdapterMetrics()
then:
listOfMeasurements.size() == 1
listOfMeasurements.first().fields['readBytes'] == 0.0
}
void "test getSriovLogicalPortMetrics'"() {
setup:
def testFile = new File(getClass().getResource('/pcm-data-logical-partition-sriov.json').toURI())
def testJson = testFile.getText('UTF-8')
ManagedSystem system = new ManagedSystem("e09834d1-c930-3883-bdad-405d8e26e166", "Test Name","Test Type", "Test Model", "Test S/N")
LogicalPartition lpar = new LogicalPartition("2DE05DB6-8AD5-448F-8327-0F488D287E82", "9Flash01", "OS400", system)
when:
lpar.processMetrics(testJson)
List<Measurement> listOfMeasurements = lpar.getSriovLogicalPorts()
then:
listOfMeasurements.size() == 6
listOfMeasurements.first().tags['location'] == "U78CA.001.CSS0CXA-P1-C2-C1-T1-S2"
listOfMeasurements.first().tags['vnicDeviceMode'] == "NonVNIC"
listOfMeasurements.first().tags['configurationType'] == "Ethernet"
listOfMeasurements.first().fields['drcIndex'] == "654327810"
listOfMeasurements.first().fields['physicalPortId'] == 0
listOfMeasurements.first().fields['physicalDrcIndex'] == "553713681"
listOfMeasurements.first().fields['receivedPackets'] == 16.867
listOfMeasurements.first().fields['sentPackets'] == 0.067
listOfMeasurements.first().fields['sentBytes'] == 8.533
listOfMeasurements.first().fields['receivedBytes'] == 1032.933
listOfMeasurements.first().fields['transferredBytes'] == 1041.466
}
}

View File

@ -0,0 +1,28 @@
package biz.nellemann.hmci
import biz.nellemann.hmci.dto.xml.ManagedSystemEntry
import biz.nellemann.hmci.dto.xml.XmlEntry
import com.fasterxml.jackson.dataformat.xml.XmlMapper
import spock.lang.Specification
class ManagedSystemEntryTest extends Specification {
void "parsing hmc xml managed system"() {
setup:
def testFile = new File(getClass().getResource('/2-managed-system.xml').toURI())
XmlMapper xmlMapper = new XmlMapper();
when:
XmlEntry entry = xmlMapper.readValue(testFile, XmlEntry.class);
ManagedSystemEntry managedSystem = entry.getContent().getManagedSystemEntry()
then:
managedSystem != null
managedSystem.activatedLevel == 145
managedSystem.activatedServicePackNameAndLevel == "FW930.50 (145)"
}
}

View File

@ -1,57 +1,74 @@
package biz.nellemann.hmci
import org.mockserver.integration.ClientAndServer
import org.mockserver.logging.MockServerLogger
import org.mockserver.socket.PortFactory
import org.mockserver.socket.tls.KeyStoreFactory
import spock.lang.Shared
import spock.lang.Specification
import javax.net.ssl.HttpsURLConnection
class ManagedSystemTest extends Specification {
void "test processPcmJson for ManagedSystem"() {
@Shared
private static ClientAndServer mockServer;
setup:
def testFile = new File(getClass().getResource('/pcm-data-managed-system.json').toURI())
def testJson = testFile.getText('UTF-8')
@Shared
private RestClient serviceClient
when:
ManagedSystem system = new ManagedSystem("e09834d1-c930-3883-bdad-405d8e26e166", "Test Name","Test Type", "Test Model", "Test S/N")
system.processMetrics(testJson)
@Shared
private ManagedSystem managedSystem
then:
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
@Shared
private File metricsFile
def setupSpec() {
HttpsURLConnection.setDefaultSSLSocketFactory(new KeyStoreFactory(new MockServerLogger()).sslContext().getSocketFactory());
mockServer = ClientAndServer.startClientAndServer(PortFactory.findFreePort());
serviceClient = new RestClient(String.format("http://localhost:%d", mockServer.getPort()), "user", "password", false)
MockResponses.prepareClientResponseForLogin(mockServer)
MockResponses.prepareClientResponseForManagementConsole(mockServer)
MockResponses.prepareClientResponseForManagedSystem(mockServer)
MockResponses.prepareClientResponseForVirtualIOServer(mockServer)
MockResponses.prepareClientResponseForLogicalPartition(mockServer)
serviceClient.login()
managedSystem = new ManagedSystem(serviceClient, String.format("%s/rest/api/uom/ManagementConsole/2c6b6620-e3e3-3294-aaf5-38e546ff672b/ManagedSystem/b597e4da-2aab-3f52-8616-341d62153559", serviceClient.baseUrl));
managedSystem.discover()
metricsFile = new File(getClass().getResource('/2-managed-system-perf-data2.json').toURI())
}
def cleanupSpec() {
mockServer.stop()
}
def setup() {
}
def "test we got entry"() {
expect:
managedSystem.entry.getName() == "Server-9009-42A-SN21F64EV"
}
void "test getDetails"() {
setup:
def testFile = new File(getClass().getResource('/pcm-data-managed-system.json').toURI())
def testJson = testFile.getText('UTF-8')
ManagedSystem system = new ManagedSystem("e09834d1-c930-3883-bdad-405d8e26e166", "Test Name","Test Type", "Test Model", "Test S/N")
when:
system.processMetrics(testJson)
List<Measurement> listOfMeasurements = system.getDetails()
managedSystem.deserialize(metricsFile.getText('UTF-8'))
List<Measurement> listOfMeasurements = managedSystem.getDetails()
then:
listOfMeasurements.size() == 1
listOfMeasurements.first().tags['servername'] == 'Test Name'
listOfMeasurements.first().fields['utilizedProcUnits'] == 0.0
listOfMeasurements.first().fields['assignedMem'] == 5632.0
listOfMeasurements.first().tags['servername'] == 'Server-9009-42A-SN21F64EV'
listOfMeasurements.first().fields['utilizedProcUnits'] == 0.00458
listOfMeasurements.first().fields['assignedMem'] == 40448.0
}
void "test getMemoryMetrics"() {
setup:
def testFile = new File(getClass().getResource('/pcm-data-managed-system.json').toURI())
def testJson = testFile.getText('UTF-8')
ManagedSystem system = new ManagedSystem("e09834d1-c930-3883-bdad-405d8e26e166", "Test Name","Test Type", "Test Model", "Test S/N")
when:
system.processMetrics(testJson)
List<Measurement> listOfMeasurements = system.getMemoryMetrics()
managedSystem.deserialize(metricsFile.getText('UTF-8'))
List<Measurement> listOfMeasurements = managedSystem.getMemoryMetrics()
then:
listOfMeasurements.size() == 1
@ -60,240 +77,37 @@ class ManagedSystemTest extends Specification {
void "test getProcessorMetrics"() {
setup:
def testFile = new File(getClass().getResource('/pcm-data-managed-system.json').toURI())
def testJson = testFile.getText('UTF-8')
ManagedSystem system = new ManagedSystem("e09834d1-c930-3883-bdad-405d8e26e166", "Test Name","Test Type", "Test Model", "Test S/N")
when:
system.processMetrics(testJson)
List<Measurement> listOfMeasurements = system.getProcessorMetrics()
managedSystem.deserialize(metricsFile.getText('UTF-8'))
List<Measurement> listOfMeasurements = managedSystem.getProcessorMetrics()
then:
listOfMeasurements.size() == 1
listOfMeasurements.first().fields['availableProcUnits'] == 16.000
listOfMeasurements.first().fields['availableProcUnits'] == 4.65
}
void "test getSystemSharedProcessorPools"() {
setup:
def testFile = new File(getClass().getResource('/pcm-data-managed-system.json').toURI())
def testJson = testFile.getText('UTF-8')
ManagedSystem system = new ManagedSystem("e09834d1-c930-3883-bdad-405d8e26e166", "Test Name","Test Type", "Test Model", "Test S/N")
when:
system.processMetrics(testJson)
List<Measurement> listOfMeasurements = system.getSharedProcessorPools()
then:
listOfMeasurements.size() == 1
listOfMeasurements.first().fields['assignedProcUnits'] == 23.767
}
void "test VIOS data"() {
setup:
def testFile = new File(getClass().getResource('/pcm-data-managed-system.json').toURI())
def testJson = testFile.getText('UTF-8')
ManagedSystem system = new ManagedSystem("e09834d1-c930-3883-bdad-405d8e26e166", "Test Name","Test Type", "Test Model", "Test S/N")
when:
system.processMetrics(testJson)
List<Measurement> listOfMeasurements = system.getSharedProcessorPools()
then:
listOfMeasurements.size() == 1
listOfMeasurements.first().fields['assignedProcUnits'] == 23.767
}
void "test getViosMemoryMetrics"() {
setup:
def testFile = new File(getClass().getResource('/pcm-data-managed-system.json').toURI())
def testJson = testFile.getText('UTF-8')
ManagedSystem system = new ManagedSystem("e09834d1-c930-3883-bdad-405d8e26e166", "Test Name","Test Type", "Test Model", "Test S/N")
when:
system.processMetrics(testJson)
List<Measurement> listOfMeasurements = system.getViosMemoryMetrics()
then:
listOfMeasurements.size() == 2
listOfMeasurements.first().fields['assignedMem'] == 8192.000
listOfMeasurements.first().fields['utilizedMem'] == 2093.000
}
void "test getViosProcessorMetrics"() {
setup:
def testFile = new File(getClass().getResource('/pcm-data-managed-system.json').toURI())
def testJson = testFile.getText('UTF-8')
ManagedSystem system = new ManagedSystem("e09834d1-c930-3883-bdad-405d8e26e166", "Test Name","Test Type", "Test Model", "Test S/N")
when:
system.processMetrics(testJson)
List<Measurement> listOfMeasurements = system.getViosProcessorMetrics()
then:
listOfMeasurements.size() == 2
listOfMeasurements.first().fields['mode'] == "share_idle_procs_active"
listOfMeasurements.first().fields['entitledProcUnits'] == 1.0
listOfMeasurements.first().fields['utilizedCappedProcUnits'] == 0.12
}
void "test getViosNetworkLpars"() {
setup:
def testFile = new File(getClass().getResource('/pcm-data-managed-system.json').toURI())
def testJson = testFile.getText('UTF-8')
ManagedSystem system = new ManagedSystem("e09834d1-c930-3883-bdad-405d8e26e166", "Test Name","Test Type", "Test Model", "Test S/N")
when:
system.processMetrics(testJson)
List<Measurement> listOfMeasurements = system.getViosNetworkLpars()
then:
listOfMeasurements.size() == 2
listOfMeasurements.first().tags['viosname'] == "VIOS1"
listOfMeasurements.first().fields['clientlpars'] == 1
}
void "test getViosNetworkSharedAdapters"() {
setup:
def testFile = new File(getClass().getResource('/pcm-data-managed-system.json').toURI())
def testJson = testFile.getText('UTF-8')
ManagedSystem system = new ManagedSystem("e09834d1-c930-3883-bdad-405d8e26e166", "Test Name","Test Type", "Test Model", "Test S/N")
when:
system.processMetrics(testJson)
List<Measurement> listOfMeasurements = system.getViosNetworkSharedAdapters()
then:
listOfMeasurements.size() == 2
listOfMeasurements.first().tags['viosname'] == "VIOS1"
listOfMeasurements.first().tags['location'] == "U8247.22L.213C1BA-V1-C2-T1"
listOfMeasurements.first().fields['type'] == "sea"
listOfMeasurements.first().fields['transferredBytes'] == 14180.2d
}
void "test getViosNetworkVirtualAdapters"() {
setup:
def testFile = new File(getClass().getResource('/pcm-data-managed-system.json').toURI())
def testJson = testFile.getText('UTF-8')
ManagedSystem system = new ManagedSystem("e09834d1-c930-3883-bdad-405d8e26e166", "Test Name","Test Type", "Test Model", "Test S/N")
when:
system.processMetrics(testJson)
List<Measurement> listOfMeasurements = system.getViosNetworkVirtualAdapters()
managedSystem.deserialize(metricsFile.getText('UTF-8'))
List<Measurement> listOfMeasurements = managedSystem.getSharedProcessorPools()
then:
listOfMeasurements.size() == 4
listOfMeasurements.first().tags['viosname'] == "VIOS1"
listOfMeasurements.first().tags['location'] == "U8247.22L.213C1BA-V1-C2"
listOfMeasurements.first().tags['vswitchid'] == "0"
listOfMeasurements.first().fields['transferredBytes'] == 8245.4d
listOfMeasurements.first().fields['assignedProcUnits'] == 22.00013
}
void "test getViosNetworkGenericAdapters"() {
setup:
def testFile = new File(getClass().getResource('/pcm-data-managed-system.json').toURI())
def testJson = testFile.getText('UTF-8')
ManagedSystem system = new ManagedSystem("e09834d1-c930-3883-bdad-405d8e26e166", "Test Name","Test Type", "Test Model", "Test S/N")
void "test getPhysicalProcessorPool"() {
when:
system.processMetrics(testJson)
List<Measurement> listOfMeasurements = system.getViosNetworkGenericAdapters()
managedSystem.deserialize(metricsFile.getText('UTF-8'))
List<Measurement> listOfMeasurements = managedSystem.getPhysicalProcessorPool()
then:
listOfMeasurements.size() == 6
listOfMeasurements.first().tags['viosname'] == "VIOS1"
listOfMeasurements.first().tags['location'] == "U78CB.001.WZS0BYF-P1-C10-T3"
listOfMeasurements.first().fields['receivedBytes'] == 1614.567d
listOfMeasurements.first().fields['sentBytes'] == 3511.833d
listOfMeasurements.size() == 1
listOfMeasurements.first().fields['assignedProcUnits'] == 22.0
}
void "test getViosStorageLpars"() {
setup:
def testFile = new File(getClass().getResource('/pcm-data-managed-system.json').toURI())
def testJson = testFile.getText('UTF-8')
ManagedSystem system = new ManagedSystem("e09834d1-c930-3883-bdad-405d8e26e166", "Test Name","Test Type", "Test Model", "Test S/N")
when:
system.processMetrics(testJson)
List<Measurement> listOfMeasurements = system.getViosStorageLpars()
then:
listOfMeasurements.size() == 2
listOfMeasurements.first().tags['viosname'] == "VIOS1"
listOfMeasurements.first().fields['clientlpars'] == 1
}
void "test getViosStorageFiberChannelAdapters"() {
setup:
def testFile = new File(getClass().getResource('/pcm-data-managed-system.json').toURI())
def testJson = testFile.getText('UTF-8')
ManagedSystem system = new ManagedSystem("e09834d1-c930-3883-bdad-405d8e26e166", "Test Name","Test Type", "Test Model", "Test S/N")
when:
system.processMetrics(testJson)
List<Measurement> listOfMeasurements = system.getViosStorageFiberChannelAdapters()
then:
listOfMeasurements.size() == 4
listOfMeasurements.first().tags['viosname'] == "VIOS1"
listOfMeasurements.first().tags['location'] == "U78CB.001.WZS0BYF-P1-C12-T1"
listOfMeasurements.first().fields['numOfReads'] == 0.0
listOfMeasurements.first().fields['numOfWrites'] == 0.067d
}
void "test getViosStoragePhysicalAdapters"() {
setup:
def testFile = new File(getClass().getResource('/pcm-data-managed-system.json').toURI())
def testJson = testFile.getText('UTF-8')
ManagedSystem system = new ManagedSystem("e09834d1-c930-3883-bdad-405d8e26e166", "Test Name","Test Type", "Test Model", "Test S/N")
when:
system.processMetrics(testJson)
List<Measurement> listOfMeasurements = system.getViosStoragePhysicalAdapters()
then:
listOfMeasurements.size() == 2
listOfMeasurements.first().tags['viosname'] == "VIOS1"
listOfMeasurements.first().tags['location'] == "U78CB.001.WZS0BYF-P1-C14-T1"
listOfMeasurements.first().fields['numOfReads'] == 0.0
listOfMeasurements.first().fields['numOfWrites'] == 19.467d
}
void "test getViosStorageVirtualAdapters"() {
setup:
def testFile = new File(getClass().getResource('/pcm-data-managed-system.json').toURI())
def testJson = testFile.getText('UTF-8')
ManagedSystem system = new ManagedSystem("e09834d1-c930-3883-bdad-405d8e26e166", "Test Name","Test Type", "Test Model", "Test S/N")
when:
system.processMetrics(testJson)
List<Measurement> listOfMeasurements = system.getViosStorageVirtualAdapters()
then:
listOfMeasurements.size() == 3
listOfMeasurements.first().tags['viosname'] == "VIOS1"
listOfMeasurements.first().tags['location'] == "U8247.22L.213C1BA-V1-C6"
listOfMeasurements.first().fields['numOfReads'] == 0.0
listOfMeasurements.first().fields['numOfWrites'] == 0.0
}
}

View File

@ -0,0 +1,60 @@
package biz.nellemann.hmci
import biz.nellemann.hmci.dto.xml.ManagementConsoleEntry
import biz.nellemann.hmci.dto.xml.XmlEntry
import biz.nellemann.hmci.dto.xml.XmlFeed
import com.fasterxml.jackson.dataformat.xml.XmlMapper
import spock.lang.Specification
class ManagementConsoleEntryTest extends Specification {
void "parsing hmc xml feed and entry"() {
setup:
def testFile = new File(getClass().getResource('/1-hmc.xml').toURI())
XmlMapper xmlMapper = new XmlMapper();
when:
XmlFeed feed = xmlMapper.readValue(testFile.getText(), XmlFeed.class);
XmlEntry entry = feed.entry;
then:
feed.id == "347ecfcf-acac-3724-8915-a3d7d7a6f298"
//feed.links.first().rel == "SELF"
//feed.links.first().href == "https://10.32.64.39:12443/rest/api/uom/ManagementConsole"
entry.id == "2c6b6620-e3e3-3294-aaf5-38e546ff672b"
entry.title == "ManagementConsole"
}
void "parsing hmc xml management console"() {
setup:
def testFile = new File(getClass().getResource('/1-hmc.xml').toURI())
XmlMapper xmlMapper = new XmlMapper();
when:
XmlFeed feed = xmlMapper.readValue(testFile.getText(), XmlFeed.class);
ManagementConsoleEntry managementConsole = feed.entry.getContent().getManagementConsole();
then:
managementConsole.getMachineTypeModelAndSerialNumber() != null
managementConsole.getMachineTypeModelAndSerialNumber().getMachineType() == "7042"
managementConsole.getMachineTypeModelAndSerialNumber().getModel() == "CR7"
managementConsole.getMachineTypeModelAndSerialNumber().getSerialNumber() == "21D3CBC"
managementConsole.getAssociatedManagedSystems().size() == 1;
managementConsole.getAssociatedManagedSystems().first().href == "https://10.32.64.39:12443/rest/api/uom/ManagementConsole/2c6b6620-e3e3-3294-aaf5-38e546ff672b/ManagedSystem/b597e4da-2aab-3f52-8616-341d62153559"
managementConsole.managementConsoleName == 'HMC-P9\n '
managementConsole.versionInfo.buildLevel == '2011270432'
managementConsole.versionInfo.servicePackName == '942'
managementConsole.iFixDetails.iFixDetailList.size() == 2
managementConsole.procConfiguration.numberOfProcessors == 6
managementConsole.procConfiguration.modelName == "Intel(R) Xeon(R) CPU E5-2640 0 @ 2.50GHz"
managementConsole.procConfiguration.architecture == "x86_64"
managementConsole.memConfiguration.totalMemory == 7957
managementConsole.memConfiguration.totalSwapMemory == 2046
}
}

View File

@ -1,24 +0,0 @@
package biz.nellemann.hmci
import spock.lang.Specification
import java.time.Instant
class MetaSystemTest extends Specification {
void "test timestamp retrieval from xml"() {
setup:
def testFile = new File(getClass().getResource('/pcm-data-managed-system.json').toURI())
def testJson = testFile.getText('UTF-8')
when:
ManagedSystem system = new ManagedSystem("e09834d1-c930-3883-bdad-405d8e26e166", "Test Name","Test Type", "Test Model", "Test S/N")
system.processMetrics(testJson)
Instant instant = system.getTimestamp()
then:
instant.getEpochSecond() == 1597086630
}
}

Some files were not shown because too many files have changed in this diff Show More