352 lines
12 KiB
Groovy
352 lines
12 KiB
Groovy
/**
|
|
* Copyright 2020 Mark Nellemann <mark.nellemann@gmail.com>
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
package biz.nellemann.hmci
|
|
|
|
import groovy.util.logging.Slf4j
|
|
import groovy.xml.XmlSlurper
|
|
import okhttp3.MediaType
|
|
import okhttp3.OkHttpClient
|
|
import okhttp3.Request
|
|
import okhttp3.RequestBody
|
|
import okhttp3.Response
|
|
|
|
import javax.net.ssl.HostnameVerifier
|
|
import javax.net.ssl.SSLContext
|
|
import javax.net.ssl.SSLSession
|
|
import javax.net.ssl.SSLSocketFactory
|
|
import javax.net.ssl.TrustManager
|
|
import javax.net.ssl.X509TrustManager
|
|
import java.security.SecureRandom
|
|
import java.security.cert.CertificateException
|
|
import java.security.cert.X509Certificate;
|
|
|
|
@Slf4j
|
|
class HmcClient {
|
|
|
|
private final MediaType MEDIA_TYPE_IBM_XML_LOGIN = MediaType.parse("application/vnd.ibm.powervm.web+xml; type=LogonRequest");
|
|
|
|
private final String hmcId
|
|
private final String baseUrl
|
|
private final String username
|
|
private final String password
|
|
private final Boolean unsafe
|
|
|
|
protected String authToken
|
|
private final OkHttpClient client
|
|
|
|
HmcClient(String hmcId, String baseUrl, String username, String password, Boolean unsafe = false) {
|
|
this.hmcId = hmcId
|
|
this.baseUrl = baseUrl
|
|
this.username = username
|
|
this.password = password
|
|
this.unsafe = unsafe
|
|
|
|
if(unsafe) {
|
|
this.client = getUnsafeOkHttpClient()
|
|
} else {
|
|
this.client = new OkHttpClient()
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Logon to the HMC and get an authentication token for further requests.
|
|
*
|
|
* @throws IOException
|
|
*/
|
|
void login() throws IOException {
|
|
|
|
String payload = """\
|
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
<LogonRequest xmlns="http://www.ibm.com/xmlns/systems/power/firmware/web/mc/2012_10/" schemaVersion="V1_0">
|
|
<UserID>${username}</UserID>
|
|
<Password>${password}</Password>
|
|
</LogonRequest>"""
|
|
|
|
URL url = new URL(String.format("%s/rest/api/web/Logon", baseUrl))
|
|
Request request = new Request.Builder()
|
|
.url(url)
|
|
//.addHeader("Content-Type", "application/vnd.ibm.powervm.web+xml; type=LogonRequest")
|
|
.addHeader("Accept", "application/vnd.ibm.powervm.web+xml; type=LogonResponse")
|
|
.addHeader("X-Audit-Memento", "hmci")
|
|
.put(RequestBody.create(payload, MEDIA_TYPE_IBM_XML_LOGIN))
|
|
.build();
|
|
|
|
try {
|
|
Response response = client.newCall(request).execute();
|
|
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
|
|
|
|
// Get response body and parse
|
|
String responseBody = response.body.string()
|
|
|
|
def xml = new XmlSlurper().parseText(responseBody)
|
|
authToken = xml.toString()
|
|
|
|
log.debug("login() - Auth Token: " + authToken)
|
|
} catch(Exception e) {
|
|
log.error(e.message)
|
|
throw new Exception(e)
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Logoff from the HMC and remove any session
|
|
*
|
|
*/
|
|
void logoff() {
|
|
|
|
if(!authToken) {
|
|
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();
|
|
|
|
Response response = client.newCall(request).execute();
|
|
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
|
|
|
|
authToken = null
|
|
log.debug("logoff()")
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Return Map of ManagedSystems seen by this HMC
|
|
*
|
|
* @return
|
|
*/
|
|
Map<String, ManagedSystem> getManagedSystems() {
|
|
URL url = new URL(String.format("%s/rest/api/uom/ManagedSystem", baseUrl))
|
|
Response response = getResponse(url)
|
|
String responseBody = response.body.string()
|
|
Map<String,ManagedSystem> managedSystemsMap = new HashMap<String, ManagedSystem>()
|
|
|
|
def feed = new XmlSlurper().parseText(responseBody)
|
|
feed?.entry?.each { entry ->
|
|
entry.content.each { content ->
|
|
content.ManagedSystem.each { system ->
|
|
ManagedSystem managedSystem = new ManagedSystem(
|
|
hmcId,
|
|
entry.id as String,
|
|
system.SystemName as String,
|
|
system.MachineTypeModelAndSerialNumber?.MachineType as String,
|
|
system.MachineTypeModelAndSerialNumber?.Model as String,
|
|
system.MachineTypeModelAndSerialNumber?.SerialNumber as String
|
|
)
|
|
managedSystemsMap.put(managedSystem.id, managedSystem)
|
|
log.debug("getManagedSystems() - Found system: " + managedSystem.toString())
|
|
}
|
|
}
|
|
}
|
|
|
|
return managedSystemsMap
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Return Map of LogicalPartitions seen by a ManagedSystem on this HMC
|
|
|
|
* @param UUID of managed system
|
|
* @return
|
|
*/
|
|
Map<String, LogicalPartition> getLogicalPartitionsForManagedSystem(ManagedSystem system) {
|
|
URL url = new URL(String.format("%s/rest/api/uom/ManagedSystem/%s/LogicalPartition", baseUrl, system.id))
|
|
Response response = getResponse(url)
|
|
String responseBody = response.body.string()
|
|
|
|
Map<String, LogicalPartition> partitionMap = new HashMap<String, LogicalPartition>() {}
|
|
def feed = new XmlSlurper().parseText(responseBody)
|
|
feed?.entry?.each { entry ->
|
|
//log.debug("Entry")
|
|
entry.content.each { content ->
|
|
//log.debug("Content")
|
|
content.LogicalPartition.each { partition ->
|
|
LogicalPartition logicalPartition = new LogicalPartition(
|
|
partition.PartitionUUID as String,
|
|
partition.PartitionName as String,
|
|
partition.PartitionType as String,
|
|
system
|
|
)
|
|
partitionMap.put(logicalPartition.id, logicalPartition)
|
|
log.debug("getLogicalPartitionsForManagedSystem() - Found partition: " + logicalPartition.toString())
|
|
}
|
|
}
|
|
}
|
|
|
|
return partitionMap
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Parse XML feed to get PCM Data in JSON format
|
|
* @param systemId
|
|
* @return
|
|
*/
|
|
String getPcmDataForManagedSystem(ManagedSystem system) {
|
|
log.debug("getPcmDataForManagedSystem() - " + system.id)
|
|
URL url = new URL(String.format("%s/rest/api/pcm/ManagedSystem/%s/ProcessedMetrics?NoOfSamples=1", baseUrl, system.id))
|
|
Response response = getResponse(url)
|
|
String responseBody = response.body.string()
|
|
|
|
String jsonBody
|
|
|
|
// Parse XML and fetch JSON link
|
|
def feed = new XmlSlurper().parseText(responseBody)
|
|
feed?.entry?.each { entry ->
|
|
String link = entry.link["@href"]
|
|
if(entry.category["@term"] == "ManagedSystem") {
|
|
jsonBody = getReponseBody(new URL(link))
|
|
}
|
|
}
|
|
|
|
return jsonBody
|
|
}
|
|
|
|
|
|
/**
|
|
* Parse XML feed to get PCM Data in JSON format
|
|
* @param systemId
|
|
* @param partitionId
|
|
* @return
|
|
*/
|
|
String getPcmDataForLogicalPartition(LogicalPartition partition) {
|
|
|
|
log.debug(String.format("getPcmDataForLogicalPartition() - %s @ %s", partition.id, partition.system.id))
|
|
URL url = new URL(String.format("%s/rest/api/pcm/ManagedSystem/%s/LogicalPartition/%s/ProcessedMetrics?NoOfSamples=1", baseUrl, partition.system.id, partition.id))
|
|
Response response = getResponse(url)
|
|
String responseBody = response.body.string()
|
|
|
|
//log.debug(responseBody)
|
|
String jsonBody
|
|
|
|
// Parse XML and fetch JSON link
|
|
def feed = new XmlSlurper().parseText(responseBody)
|
|
feed?.entry?.each { entry ->
|
|
String link = entry.link["@href"]
|
|
if(entry.category["@term"] == "LogicalPartition") {
|
|
jsonBody = getReponseBody(new URL(link))
|
|
}
|
|
}
|
|
|
|
return jsonBody
|
|
}
|
|
|
|
|
|
/**
|
|
* Return body text from a HTTP response from the HMC
|
|
*
|
|
* @param url
|
|
* @return
|
|
*/
|
|
protected String getReponseBody(URL url) {
|
|
//log.debug("getBody() - " + url.toString())
|
|
Response response = getResponse(url)
|
|
return response.body.string()
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Return a Response from the HMC
|
|
*
|
|
* @param url
|
|
* @return
|
|
*/
|
|
private Response getResponse(URL url) {
|
|
|
|
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();
|
|
if (!response.isSuccessful()) {
|
|
if(response.code == 401) {
|
|
login()
|
|
} else {
|
|
throw new IOException("Unexpected code " + response)
|
|
}
|
|
};
|
|
|
|
return response
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Provide an unsafe (ignoring SSL problems) OkHttpClient
|
|
*
|
|
* @return
|
|
*/
|
|
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) throws CertificateException {
|
|
}
|
|
|
|
@Override
|
|
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
|
|
}
|
|
|
|
@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 an 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(new HostnameVerifier() {
|
|
@Override
|
|
public boolean verify(String hostname, SSLSession session) {
|
|
return true;
|
|
}
|
|
});
|
|
|
|
OkHttpClient okHttpClient = builder.build();
|
|
return okHttpClient;
|
|
} catch (Exception e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
|
|
}
|