org.sentrysoftware.metricshub.extension.ipmi.IpmiExtension Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of metricshub-ipmi-extension Show documentation
Show all versions of metricshub-ipmi-extension Show documentation
MetricsHub IPMI Extension implementation providing a set of functionalities used to process IPMI-over-lan criterion and source.
The newest version!
package org.sentrysoftware.metricshub.extension.ipmi;
/*-
* ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
* MetricsHub Ipmi Extension
* ჻჻჻჻჻჻
* Copyright 2023 - 2024 Sentry Software
* ჻჻჻჻჻჻
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
* ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
*/
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.UnaryOperator;
import lombok.extern.slf4j.Slf4j;
import org.sentrysoftware.ipmi.client.IpmiClient;
import org.sentrysoftware.ipmi.client.IpmiClientConfiguration;
import org.sentrysoftware.metricshub.engine.common.exception.InvalidConfigurationException;
import org.sentrysoftware.metricshub.engine.common.helpers.ArrayHelper;
import org.sentrysoftware.metricshub.engine.common.helpers.LoggingHelper;
import org.sentrysoftware.metricshub.engine.configuration.IConfiguration;
import org.sentrysoftware.metricshub.engine.connector.model.identity.criterion.Criterion;
import org.sentrysoftware.metricshub.engine.connector.model.identity.criterion.IpmiCriterion;
import org.sentrysoftware.metricshub.engine.connector.model.monitor.task.source.IpmiSource;
import org.sentrysoftware.metricshub.engine.connector.model.monitor.task.source.Source;
import org.sentrysoftware.metricshub.engine.extension.IProtocolExtension;
import org.sentrysoftware.metricshub.engine.strategy.detection.CriterionTestResult;
import org.sentrysoftware.metricshub.engine.strategy.source.SourceTable;
import org.sentrysoftware.metricshub.engine.telemetry.TelemetryManager;
@Slf4j
public class IpmiExtension implements IProtocolExtension {
/**
* The identifier for the Ipmi protocol.
*/
private static final String IDENTIFIER = "ipmi";
private IpmiRequestExecutor ipmiRequestExecutor = new IpmiRequestExecutor();
@Override
public boolean isValidConfiguration(IConfiguration configuration) {
return configuration instanceof IpmiConfiguration;
}
@Override
public Set> getSupportedSources() {
return Set.of(IpmiSource.class);
}
@Override
public Map, Set>> getConfigurationToSourceMapping() {
return Map.of(IpmiConfiguration.class, Set.of(IpmiSource.class));
}
@Override
public Set> getSupportedCriteria() {
return Set.of(IpmiCriterion.class);
}
@Override
public Optional checkProtocol(TelemetryManager telemetryManager) {
// Retrieve the hostname from the IpmiConfiguration, otherwise from the telemetryManager
String hostname = telemetryManager.getHostname(List.of(IpmiConfiguration.class));
// Create and set the IPMI result to null
String ipmiResult = null;
// Retrieve IPMI Configuration from the telemetry manager host configuration
final IpmiConfiguration ipmiConfiguration = (IpmiConfiguration) telemetryManager
.getHostConfiguration()
.getConfigurations()
.get(IpmiConfiguration.class);
// Stop the IPMI health check if there is not an IPMI configuration
if (ipmiConfiguration == null) {
return Optional.empty();
}
log.info("Hostname {} - Performing {} protocol health check.", hostname, getIdentifier());
log.info(
"Hostname {} - Checking IPMI protocol status. Sending a IPMI 'Get Chassis Status As String Result' request.",
hostname
);
// Execute IPMI test command
try {
ipmiResult =
IpmiClient.getChassisStatusAsStringResult(
new IpmiClientConfiguration(
hostname,
ipmiConfiguration.getUsername(),
ipmiConfiguration.getPassword(),
ArrayHelper.hexToByteArray(ipmiConfiguration.getBmcKey()),
ipmiConfiguration.isSkipAuth(),
ipmiConfiguration.getTimeout()
)
);
} catch (Exception e) {
log.debug(
"Hostname {} - Checking IPMI protocol status. IPMI exception when performing a IPMI 'Get Chassis Status As String Result' query: ",
hostname,
e
);
}
return Optional.of(ipmiResult != null);
}
@Override
public SourceTable processSource(Source source, String connectorId, TelemetryManager telemetryManager) {
final IpmiConfiguration ipmiConfiguration = (IpmiConfiguration) telemetryManager
.getHostConfiguration()
.getConfigurations()
.get(IpmiConfiguration.class);
if (ipmiConfiguration == null) {
log.warn(
"Hostname {} - The IPMI credentials are not configured. Cannot process IPMI-over-LAN source.",
telemetryManager.getHostname()
);
return SourceTable.empty();
}
// Retrieve the hostname from the IpmiConfiguration, otherwise from the telemetryManager
final String hostname = telemetryManager.getHostname(List.of(IpmiConfiguration.class));
try {
final String result = ipmiRequestExecutor.executeIpmiGetSensors(hostname, ipmiConfiguration);
if (result != null) {
return SourceTable.builder().rawData(result).build();
} else {
log.error("Hostname {} - IPMI-over-LAN request returned result. Returning an empty table.", hostname);
}
} catch (Exception e) {
LoggingHelper.logSourceError(connectorId, source.getKey(), "IPMI-over-LAN", hostname, e);
}
return SourceTable.empty();
}
@Override
public CriterionTestResult processCriterion(
Criterion criterion,
String connectorId,
TelemetryManager telemetryManager
) {
final IpmiConfiguration configuration = (IpmiConfiguration) telemetryManager
.getHostConfiguration()
.getConfigurations()
.get(IpmiConfiguration.class);
if (configuration == null) {
log.debug(
"Hostname {} - The IPMI credentials are not configured for this host. Cannot process IPMI-over-LAN detection.",
telemetryManager.getHostname()
);
return CriterionTestResult.empty();
}
// Retrieve the hostname from the IpmiConfiguration, otherwise from the telemetryManager
final String hostname = telemetryManager.getHostname(List.of(IpmiConfiguration.class));
try {
final String result = ipmiRequestExecutor.executeIpmiDetection(hostname, configuration);
if (result == null) {
return CriterionTestResult
.builder()
.message("Received result after connecting to the IPMI BMC chip with the IPMI-over-LAN interface.")
.build();
}
return CriterionTestResult
.builder()
.result(result)
.message("Successfully connected to the IPMI BMC chip with the IPMI-over-LAN interface.")
.success(true)
.build();
} catch (final Exception e) { // NOSONAR on interruption
final String message = String.format(
"Hostname %s - Cannot execute IPMI-over-LAN command to get the chassis status. Exception: %s",
hostname,
e.getMessage()
);
log.debug(message, e);
return CriterionTestResult.builder().message(message).build();
}
}
@Override
public boolean isSupportedConfigurationType(String configurationType) {
return IDENTIFIER.equalsIgnoreCase(configurationType);
}
@Override
public IConfiguration buildConfiguration(String configurationType, JsonNode jsonNode, UnaryOperator decrypt)
throws InvalidConfigurationException {
try {
final IpmiConfiguration ipmiConfiguration = newObjectMapper().treeToValue(jsonNode, IpmiConfiguration.class);
if (decrypt != null) {
final char[] password = ipmiConfiguration.getPassword();
if (password != null) {
// Decrypt the password
ipmiConfiguration.setPassword(decrypt.apply(password));
}
}
return ipmiConfiguration;
} catch (Exception e) {
final String errorMessage = String.format("Error while reading IPMI Configuration. Error: %s", e.getMessage());
log.error(errorMessage);
log.debug("Error while reading IPMI Configuration. Stack trace:", e);
throw new InvalidConfigurationException(errorMessage, e);
}
}
/**
* Creates and configures a new instance of the Jackson ObjectMapper for handling YAML data.
*
* @return A configured ObjectMapper instance.
*/
public static JsonMapper newObjectMapper() {
return JsonMapper
.builder(new YAMLFactory())
.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS)
.enable(SerializationFeature.INDENT_OUTPUT)
.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false)
.build();
}
@Override
public String getIdentifier() {
return IDENTIFIER;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy