From bdfa535b75c1b49370891d82c348899afecf08ef Mon Sep 17 00:00:00 2001 From: Mark Nellemann Date: Thu, 10 Aug 2023 11:02:53 +0200 Subject: [PATCH 1/3] Work on avoiding lingering sessions on the HMC. --- build.gradle | 14 ++++++------- doc/readme-hmc.md | 4 ++-- gradle.properties | 2 +- .../java/biz/nellemann/hmci/InfluxClient.java | 4 ++-- .../java/biz/nellemann/hmci/RestClient.java | 20 +++++++++++++++++++ .../nellemann/hmci/dto/json/PowerUtil.java | 2 +- .../hmci/LogicalPartitionTest.groovy | 1 + .../nellemann/hmci/ManagedSystemTest.groovy | 1 + 8 files changed, 35 insertions(+), 13 deletions(-) diff --git a/build.gradle b/build.gradle index 57476aa..af8e1d2 100644 --- a/build.gradle +++ b/build.gradle @@ -17,15 +17,15 @@ group = projectGroup version = projectVersion dependencies { - annotationProcessor 'info.picocli:picocli-codegen:4.7.3' - implementation 'info.picocli:picocli:4.7.3' + annotationProcessor 'info.picocli:picocli-codegen:4.7.4' + implementation 'info.picocli:picocli:4.7.4' implementation 'org.slf4j:slf4j-api:2.0.7' implementation 'org.slf4j:slf4j-simple:2.0.7' - implementation 'com.squareup.okhttp3:okhttp:4.10.0' // Also used by InfluxDB Client - implementation 'com.influxdb:influxdb-client-java:6.8.0' - implementation 'com.fasterxml.jackson.core:jackson-databind:2.14.3' - implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.14.3' - implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-toml:2.14.3' + implementation 'com.squareup.okhttp3:okhttp:4.11.0' // Also used by InfluxDB Client + implementation 'com.influxdb:influxdb-client-java:6.10.0' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.2' + implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.15.2' + implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-toml:2.15.2' testImplementation 'junit:junit:4.13.2' testImplementation 'org.spockframework:spock-core:2.3-groovy-4.0' diff --git a/doc/readme-hmc.md b/doc/readme-hmc.md index 610c6be..6b889fe 100644 --- a/doc/readme-hmc.md +++ b/doc/readme-hmc.md @@ -11,9 +11,9 @@ Ensure you have **correct date/time** and NTPd running to keep it accurate! - 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*: - - Set *Session timeout minutes* to **60** + - Set *Session timeout minutes* to **120** (or at least 61 minutes) - Set *Verify timeout minutes* to **15** - - Set *Idle timeout minutes* to **90** + - Set *Idle timeout minutes* to **15** - Set *Minimum time in days between password changes* to **0** - **Enable** *Allow remote access via the web* - Navigate to *HMC Management* and *Console Settings* diff --git a/gradle.properties b/gradle.properties index 91253d0..842f543 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ projectId = hmci projectGroup = biz.nellemann.hmci -projectVersion = 1.4.4 +projectVersion = 1.4.5 diff --git a/src/main/java/biz/nellemann/hmci/InfluxClient.java b/src/main/java/biz/nellemann/hmci/InfluxClient.java index 90803b7..f1972f5 100644 --- a/src/main/java/biz/nellemann/hmci/InfluxClient.java +++ b/src/main/java/biz/nellemann/hmci/InfluxClient.java @@ -83,10 +83,10 @@ public final class InfluxClient { Runtime.getRuntime().addShutdownHook(new Thread(influxDBClient::close)); // Todo: Handle events - https://github.com/influxdata/influxdb-client-java/tree/master/client#handle-the-events - //writeApi = influxDBClient.makeWriteApi(); writeApi = influxDBClient.makeWriteApi( WriteOptions.builder() - .bufferLimit(20_000) + .batchSize(15_000) + .bufferLimit(500_000) .flushInterval(5_000) .build()); diff --git a/src/main/java/biz/nellemann/hmci/RestClient.java b/src/main/java/biz/nellemann/hmci/RestClient.java index 3a3567b..0848a97 100644 --- a/src/main/java/biz/nellemann/hmci/RestClient.java +++ b/src/main/java/biz/nellemann/hmci/RestClient.java @@ -16,6 +16,8 @@ import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.cert.X509Certificate; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.Objects; import java.util.concurrent.TimeUnit; @@ -38,6 +40,9 @@ public class RestClient { protected final String username; protected final String password; + private final static int MAX_MINUTES_BETWEEN_AUTHENTICATION = 60; // TODO: Make configurable and match HMC timeout settings + private Instant lastAuthenticationTimestamp; + public RestClient(String baseUrl, String username, String password, Boolean trustAll) { this.baseUrl = baseUrl; @@ -63,6 +68,8 @@ public class RestClient { log.error("ManagementConsole() - trace error: " + e.getMessage()); } }*/ + Thread shutdownHook = new Thread(this::logoff); + Runtime.getRuntime().addShutdownHook(shutdownHook); } @@ -70,6 +77,9 @@ public class RestClient { * Logon to the HMC and get an authentication token for further requests. */ public synchronized void login() { + if(authToken != null) { + logoff(); + } log.info("Connecting to HMC - {} @ {}", username, baseUrl); StringBuilder payload = new StringBuilder(); @@ -102,10 +112,12 @@ public class RestClient { LogonResponse logonResponse = xmlMapper.readValue(responseBody, LogonResponse.class); authToken = logonResponse.getToken(); + lastAuthenticationTimestamp = Instant.now(); log.debug("logon() - auth token: {}", authToken); } catch (Exception e) { log.warn("logon() - error: {}", e.getMessage()); + lastAuthenticationTimestamp = null; } } @@ -136,6 +148,7 @@ public class RestClient { log.warn("logoff() error: {}", e.getMessage()); } finally { authToken = null; + lastAuthenticationTimestamp = null; } } catch (MalformedURLException e) { @@ -164,6 +177,9 @@ public class RestClient { public synchronized String getRequest(URL url) throws IOException { log.debug("getRequest() - URL: {}", url.toString()); + if (lastAuthenticationTimestamp == null || lastAuthenticationTimestamp.plus(MAX_MINUTES_BETWEEN_AUTHENTICATION, ChronoUnit.MINUTES).isBefore(Instant.now())) { + login(); + } Request request = new Request.Builder() .url(url) @@ -222,6 +238,10 @@ public class RestClient { public synchronized String postRequest(URL url, String payload) throws IOException { log.debug("sendPostRequest() - URL: {}", url.toString()); + if (lastAuthenticationTimestamp == null || lastAuthenticationTimestamp.plus(MAX_MINUTES_BETWEEN_AUTHENTICATION, ChronoUnit.MINUTES).isBefore(Instant.now())) { + login(); + } + RequestBody requestBody; if(payload != null) { requestBody = RequestBody.create(payload, MEDIA_TYPE_IBM_XML_POST); diff --git a/src/main/java/biz/nellemann/hmci/dto/json/PowerUtil.java b/src/main/java/biz/nellemann/hmci/dto/json/PowerUtil.java index ab028eb..f77f9aa 100644 --- a/src/main/java/biz/nellemann/hmci/dto/json/PowerUtil.java +++ b/src/main/java/biz/nellemann/hmci/dto/json/PowerUtil.java @@ -5,6 +5,6 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @JsonIgnoreProperties(ignoreUnknown = true) public final class PowerUtil { - public Number powerReading = 0.0; + public float powerReading = 0.0F; } diff --git a/src/test/groovy/biz/nellemann/hmci/LogicalPartitionTest.groovy b/src/test/groovy/biz/nellemann/hmci/LogicalPartitionTest.groovy index 6367cfc..92c4866 100644 --- a/src/test/groovy/biz/nellemann/hmci/LogicalPartitionTest.groovy +++ b/src/test/groovy/biz/nellemann/hmci/LogicalPartitionTest.groovy @@ -52,6 +52,7 @@ class LogicalPartitionTest extends Specification { } def cleanupSpec() { + serviceClient.logoff() mockServer.stop() } diff --git a/src/test/groovy/biz/nellemann/hmci/ManagedSystemTest.groovy b/src/test/groovy/biz/nellemann/hmci/ManagedSystemTest.groovy index 88f1cdc..3cf0ca6 100644 --- a/src/test/groovy/biz/nellemann/hmci/ManagedSystemTest.groovy +++ b/src/test/groovy/biz/nellemann/hmci/ManagedSystemTest.groovy @@ -42,6 +42,7 @@ class ManagedSystemTest extends Specification { } def cleanupSpec() { + serviceClient.logoff() mockServer.stop() } -- 2.43.4 From d59079e6dac49a2d2f25646074149d8dc5d408e4 Mon Sep 17 00:00:00 2001 From: Mark Nellemann Date: Thu, 10 Aug 2023 18:31:04 +0200 Subject: [PATCH 2/3] Update gradle plugin ospackage plugin. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index af8e1d2..25d8eb9 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ plugins { id 'groovy' id 'application' id "net.nemerosa.versioning" version "2.15.1" - id "com.netflix.nebula.ospackage" version "11.2.0" + id "com.netflix.nebula.ospackage" version "11.4.0" id "com.github.johnrengelman.shadow" version "7.1.2" } -- 2.43.4 From a24b03f4adc8d3d8033a6807338e2e0b6e8933b9 Mon Sep 17 00:00:00 2001 From: Mark Nellemann Date: Mon, 13 Nov 2023 14:14:27 +0100 Subject: [PATCH 3/3] Update 3rd party dependencies. --- CHANGELOG.md | 4 ++ build.gradle | 10 ++--- .../java/biz/nellemann/hmci/Application.java | 16 ++++---- .../java/biz/nellemann/hmci/InfluxClient.java | 17 +++++---- .../biz/nellemann/hmci/ManagementConsole.java | 28 ++++++++------ .../java/biz/nellemann/hmci/RestClient.java | 37 +++++++++++++------ .../java/biz/nellemann/hmci/SystemEnergy.java | 20 ++++++---- .../biz/nellemann/hmci/VersionProvider.java | 4 +- .../biz/nellemann/hmci/VirtualIOServer.java | 15 +++++--- 9 files changed, 92 insertions(+), 59 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53849ca..fbcc81d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to this project will be documented in this file. +## 1.4.5 - 2023-11-13 +- Adjust timeout to not have lingering sessions on HMC +- Update 3rd party dependencies + ## 1.4.4 - 2023-05-20 - Support for InfluxDB v2, now requires InfluxDB 1.8 or later - Increase influx writer buffer limit diff --git a/build.gradle b/build.gradle index 25d8eb9..486c2e8 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ plugins { id 'groovy' id 'application' id "net.nemerosa.versioning" version "2.15.1" - id "com.netflix.nebula.ospackage" version "11.4.0" + id "com.netflix.nebula.ospackage" version "11.5.0" id "com.github.johnrengelman.shadow" version "7.1.2" } @@ -17,10 +17,10 @@ group = projectGroup version = projectVersion dependencies { - annotationProcessor 'info.picocli:picocli-codegen:4.7.4' - implementation 'info.picocli:picocli:4.7.4' - implementation 'org.slf4j:slf4j-api:2.0.7' - implementation 'org.slf4j:slf4j-simple:2.0.7' + annotationProcessor 'info.picocli:picocli-codegen:4.7.5' + implementation 'info.picocli:picocli:4.7.5' + implementation 'org.slf4j:slf4j-api:2.0.9' + implementation 'org.slf4j:slf4j-simple:2.0.9' implementation 'com.squareup.okhttp3:okhttp:4.11.0' // Also used by InfluxDB Client implementation 'com.influxdb:influxdb-client-java:6.10.0' implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.2' diff --git a/src/main/java/biz/nellemann/hmci/Application.java b/src/main/java/biz/nellemann/hmci/Application.java index 9b6abb4..135ce28 100644 --- a/src/main/java/biz/nellemann/hmci/Application.java +++ b/src/main/java/biz/nellemann/hmci/Application.java @@ -15,17 +15,19 @@ */ 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; +import com.fasterxml.jackson.dataformat.toml.TomlMapper; + +import biz.nellemann.hmci.dto.toml.Configuration; +import picocli.CommandLine; +import picocli.CommandLine.Command; +import picocli.CommandLine.Option; + @Command(name = "hmci", mixinStandardHelpOptions = true, versionProvider = biz.nellemann.hmci.VersionProvider.class, @@ -90,7 +92,7 @@ public class Application implements Callable { } influxClient.logoff(); - } catch (Exception e) { + } catch (IOException | InterruptedException e) { System.err.println(e.getMessage()); return 1; } diff --git a/src/main/java/biz/nellemann/hmci/InfluxClient.java b/src/main/java/biz/nellemann/hmci/InfluxClient.java index f1972f5..ae63e80 100644 --- a/src/main/java/biz/nellemann/hmci/InfluxClient.java +++ b/src/main/java/biz/nellemann/hmci/InfluxClient.java @@ -15,20 +15,21 @@ */ package biz.nellemann.hmci; -import biz.nellemann.hmci.dto.toml.InfluxConfiguration; +import static java.lang.Thread.sleep; +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.influxdb.client.InfluxDBClient; import com.influxdb.client.InfluxDBClientFactory; import com.influxdb.client.WriteApi; import com.influxdb.client.WriteOptions; -import com.influxdb.client.write.Point; import com.influxdb.client.domain.WritePrecision; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.influxdb.client.write.Point; -import java.util.ArrayList; -import java.util.List; - -import static java.lang.Thread.sleep; +import biz.nellemann.hmci.dto.toml.InfluxConfiguration; public final class InfluxClient { diff --git a/src/main/java/biz/nellemann/hmci/ManagementConsole.java b/src/main/java/biz/nellemann/hmci/ManagementConsole.java index c0fe494..c2fc0fe 100644 --- a/src/main/java/biz/nellemann/hmci/ManagementConsole.java +++ b/src/main/java/biz/nellemann/hmci/ManagementConsole.java @@ -15,21 +15,25 @@ */ package biz.nellemann.hmci; +import java.io.IOException; +import static java.lang.Thread.sleep; +import java.time.Duration; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.dataformat.xml.XmlMapper; + 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.time.Duration; -import java.time.Instant; -import java.time.temporal.ChronoUnit; -import java.util.*; -import java.util.concurrent.atomic.AtomicBoolean; - -import static java.lang.Thread.sleep; class ManagementConsole implements Runnable { @@ -170,7 +174,7 @@ class ManagementConsole implements Runnable { } } - } catch (Exception e) { + } catch (IOException e) { log.warn("discover() - error: {}", e.getMessage()); } diff --git a/src/main/java/biz/nellemann/hmci/RestClient.java b/src/main/java/biz/nellemann/hmci/RestClient.java index 0848a97..cc4ff85 100644 --- a/src/main/java/biz/nellemann/hmci/RestClient.java +++ b/src/main/java/biz/nellemann/hmci/RestClient.java @@ -1,17 +1,8 @@ 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.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; @@ -21,6 +12,23 @@ import java.time.temporal.ChronoUnit; import java.util.Objects; import java.util.concurrent.TimeUnit; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.dataformat.xml.XmlMapper; + +import biz.nellemann.hmci.dto.xml.LogonResponse; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; + public class RestClient { private final static Logger log = LoggerFactory.getLogger(RestClient.class); @@ -173,6 +181,7 @@ public class RestClient { * Return a Response from the HMC * @param url to get Response from * @return Response body string + * @throws IOException */ public synchronized String getRequest(URL url) throws IOException { @@ -234,6 +243,10 @@ public class RestClient { /** * Send a POST request with a payload (can be null) to the HMC + * @param url + * @param payload + * @return Response body string + * @throws IOException */ public synchronized String postRequest(URL url, String payload) throws IOException { diff --git a/src/main/java/biz/nellemann/hmci/SystemEnergy.java b/src/main/java/biz/nellemann/hmci/SystemEnergy.java index f97f26a..fb28eeb 100644 --- a/src/main/java/biz/nellemann/hmci/SystemEnergy.java +++ b/src/main/java/biz/nellemann/hmci/SystemEnergy.java @@ -1,14 +1,20 @@ package biz.nellemann.hmci; -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.io.IOException; import java.net.URI; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.dataformat.xml.XmlMapper; + +import biz.nellemann.hmci.dto.xml.Link; +import biz.nellemann.hmci.dto.xml.XmlFeed; class SystemEnergy extends Resource { diff --git a/src/main/java/biz/nellemann/hmci/VersionProvider.java b/src/main/java/biz/nellemann/hmci/VersionProvider.java index 0651de2..ec3a974 100644 --- a/src/main/java/biz/nellemann/hmci/VersionProvider.java +++ b/src/main/java/biz/nellemann/hmci/VersionProvider.java @@ -15,12 +15,12 @@ */ package biz.nellemann.hmci; -import picocli.CommandLine; - import java.io.IOException; import java.util.jar.Attributes; import java.util.jar.Manifest; +import picocli.CommandLine; + class VersionProvider implements CommandLine.IVersionProvider { @Override diff --git a/src/main/java/biz/nellemann/hmci/VirtualIOServer.java b/src/main/java/biz/nellemann/hmci/VirtualIOServer.java index 62a94ee..f7d0e86 100644 --- a/src/main/java/biz/nellemann/hmci/VirtualIOServer.java +++ b/src/main/java/biz/nellemann/hmci/VirtualIOServer.java @@ -1,13 +1,16 @@ 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 java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.net.URI; -import java.net.URISyntaxException; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; + +import biz.nellemann.hmci.dto.xml.VirtualIOServerEntry; +import biz.nellemann.hmci.dto.xml.XmlEntry; public class VirtualIOServer { private final static Logger log = LoggerFactory.getLogger(VirtualIOServer.class); @@ -58,7 +61,7 @@ public class VirtualIOServer { throw new UnsupportedOperationException("Failed to deserialize VirtualIOServer"); } - } catch (Exception e) { + } catch (IOException e) { log.error("discover() - error: {}", e.getMessage()); } } -- 2.43.4