
org.sentrysoftware.metricshub.extension.wmi.WmiExtension Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of metricshub-wmi-extension Show documentation
Show all versions of metricshub-wmi-extension Show documentation
MetricsHub WMI Extension implementation providing a set of functionalities used to process WMI criteria and sources.
package org.sentrysoftware.metricshub.extension.wmi;
/*-
* ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
* MetricsHub WMI 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.Set;
import java.util.function.Function;
import java.util.function.UnaryOperator;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.sentrysoftware.metricshub.engine.common.exception.InvalidConfigurationException;
import org.sentrysoftware.metricshub.engine.configuration.IConfiguration;
import org.sentrysoftware.metricshub.engine.connector.model.identity.criterion.CommandLineCriterion;
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.identity.criterion.ProcessCriterion;
import org.sentrysoftware.metricshub.engine.connector.model.identity.criterion.ServiceCriterion;
import org.sentrysoftware.metricshub.engine.connector.model.identity.criterion.WmiCriterion;
import org.sentrysoftware.metricshub.engine.connector.model.monitor.task.source.CommandLineSource;
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.connector.model.monitor.task.source.WmiSource;
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.MetricFactory;
import org.sentrysoftware.metricshub.engine.telemetry.Monitor;
import org.sentrysoftware.metricshub.engine.telemetry.TelemetryManager;
import org.sentrysoftware.metricshub.extension.win.IWinConfiguration;
import org.sentrysoftware.metricshub.extension.win.WinCommandService;
import org.sentrysoftware.metricshub.extension.win.detection.WinCommandLineCriterionProcessor;
import org.sentrysoftware.metricshub.extension.win.detection.WinIpmiCriterionProcessor;
import org.sentrysoftware.metricshub.extension.win.detection.WinProcessCriterionProcessor;
import org.sentrysoftware.metricshub.extension.win.detection.WinServiceCriterionProcessor;
import org.sentrysoftware.metricshub.extension.win.detection.WmiCriterionProcessor;
import org.sentrysoftware.metricshub.extension.win.detection.WmiDetectionService;
import org.sentrysoftware.metricshub.extension.win.source.WinCommandLineSourceProcessor;
import org.sentrysoftware.metricshub.extension.win.source.WinIpmiSourceProcessor;
import org.sentrysoftware.metricshub.extension.win.source.WmiSourceProcessor;
/**
* This class implements the {@link IProtocolExtension} contract, reports the supported features,
* processes WMI sources and criteria.
*/
@Slf4j
public class WmiExtension implements IProtocolExtension {
/**
* Protocol up status value '1.0'
*/
public static final Double UP = 1.0;
/**
* Protocol down status value '0.0'
*/
public static final Double DOWN = 0.0;
/**
* Up metric name format that will be saved by the metric factory
*/
public static final String WMI_UP_METRIC = "metricshub.host.up{protocol=\"wmi\"}";
/**
* WMI namespace
*/
public static final String WMI_TEST_NAMESPACE = "root\\cimv2";
/**
* WMI Query used by the protocol health check
*/
public static final String WMI_TEST_QUERY = "SELECT Name FROM Win32_ComputerSystem";
private WmiRequestExecutor wmiRequestExecutor;
private WmiDetectionService wmiDetectionService;
private WinCommandService winCommandService;
/**
* Creates a new instance of the {@link WmiExtension} implementation.
*/
public WmiExtension() {
wmiRequestExecutor = new WmiRequestExecutor();
wmiDetectionService = new WmiDetectionService(wmiRequestExecutor);
winCommandService = new WinCommandService(wmiRequestExecutor);
}
@Override
public boolean isValidConfiguration(IConfiguration configuration) {
return configuration instanceof WmiConfiguration;
}
@Override
public Set> getSupportedSources() {
return Set.of(WmiSource.class, CommandLineSource.class, IpmiSource.class);
}
@Override
public Map, Set>> getConfigurationToSourceMapping() {
return Map.of(WmiConfiguration.class, Set.of(WmiSource.class));
}
@Override
public Set> getSupportedCriteria() {
return Set.of(WmiCriterion.class, ServiceCriterion.class, CommandLineCriterion.class, IpmiCriterion.class);
}
@Override
public void checkProtocol(TelemetryManager telemetryManager) {
// Create and set the WMI result to null
List> wmiResult = null;
// Retrieve the hostname
final String hostname = telemetryManager.getHostname();
// Retrieve WMI Configuration from the telemetry manager host configuration
final WmiConfiguration wmiConfiguration = (WmiConfiguration) telemetryManager
.getHostConfiguration()
.getConfigurations()
.get(WmiConfiguration.class);
// Retrieve the host endpoint monitor
final Monitor hostMonitor = telemetryManager.getEndpointHostMonitor();
// Stop the health check if there is not an WMI configuration
if (wmiConfiguration == null) {
return;
}
log.info(
"Hostname {} - Checking WMI protocol status. Sending a WQL SELECT request on {} namespace.",
hostname,
WMI_TEST_NAMESPACE
);
// Create the MetricFactory in order to collect the up metric
final MetricFactory metricFactory = new MetricFactory();
// Get the strategy time which represents the collect time of the up metric
final Long strategyTime = telemetryManager.getStrategyTime();
try {
wmiResult = wmiRequestExecutor.executeWmi(hostname, wmiConfiguration, WMI_TEST_QUERY, WMI_TEST_NAMESPACE);
} catch (Exception e) {
if (wmiRequestExecutor.isAcceptableException(e)) {
// Generate a metric from the WMI result
metricFactory.collectNumberMetric(hostMonitor, WMI_UP_METRIC, UP, strategyTime);
return;
}
log.debug(
"Hostname {} - Checking WMI protocol status. WMI exception when performing a WQL SELECT request on {} namespace: ",
hostname,
WMI_TEST_NAMESPACE,
e
);
}
// Generate a metric from the WMI result
metricFactory.collectNumberMetric(hostMonitor, WMI_UP_METRIC, wmiResult != null ? UP : DOWN, strategyTime);
}
@Override
public CriterionTestResult processCriterion(
Criterion criterion,
String connectorId,
TelemetryManager telemetryManager
) {
final Function configurationRetriever = manager ->
(IWinConfiguration) manager.getHostConfiguration().getConfigurations().get(WmiConfiguration.class);
if (criterion instanceof WmiCriterion wmiCriterion) {
return new WmiCriterionProcessor(wmiDetectionService, configurationRetriever, connectorId)
.process(wmiCriterion, telemetryManager);
} else if (criterion instanceof ServiceCriterion serviceCriterion) {
return new WinServiceCriterionProcessor(wmiDetectionService, configurationRetriever)
.process(serviceCriterion, telemetryManager);
} else if (criterion instanceof CommandLineCriterion commandLineCriterion) {
return new WinCommandLineCriterionProcessor(winCommandService, configurationRetriever, connectorId)
.process(commandLineCriterion, telemetryManager);
} else if (criterion instanceof IpmiCriterion ipmiCriterion) {
return new WinIpmiCriterionProcessor(wmiDetectionService, configurationRetriever)
.process(ipmiCriterion, telemetryManager);
} else if (criterion instanceof ProcessCriterion processCriterion) {
return new WinProcessCriterionProcessor(wmiDetectionService)
.process(processCriterion, WmiConfiguration.builder().username(null).password(null).timeout(30L).build());
}
throw new IllegalArgumentException(
String.format(
"Hostname %s - Cannot process criterion %s.",
telemetryManager.getHostname(),
criterion != null ? criterion.getClass().getSimpleName() : ""
)
);
}
@Override
public SourceTable processSource(Source source, String connectorId, TelemetryManager telemetryManager) {
final Function configurationRetriever = manager ->
(IWinConfiguration) manager.getHostConfiguration().getConfigurations().get(WmiConfiguration.class);
if (source instanceof WmiSource wmiSource) {
return new WmiSourceProcessor(wmiRequestExecutor, configurationRetriever, connectorId)
.process(wmiSource, telemetryManager);
} else if (source instanceof IpmiSource ipmiSource) {
return new WinIpmiSourceProcessor(wmiRequestExecutor, configurationRetriever, connectorId)
.process(ipmiSource, telemetryManager);
} else if (source instanceof CommandLineSource commandLineSource) {
return new WinCommandLineSourceProcessor(winCommandService, configurationRetriever, connectorId)
.process(commandLineSource, telemetryManager);
}
throw new IllegalArgumentException(
String.format(
"Hostname %s - Cannot process source %s.",
telemetryManager.getHostname(),
source != null ? source.getClass().getSimpleName() : ""
)
);
}
@Override
public boolean isSupportedConfigurationType(String configurationType) {
return "wmi".equalsIgnoreCase(configurationType);
}
@Override
public IConfiguration buildConfiguration(
@NonNull String configurationType,
@NonNull JsonNode jsonNode,
UnaryOperator decrypt
) throws InvalidConfigurationException {
try {
final WmiConfiguration wmiConfiguration = newObjectMapper().treeToValue(jsonNode, WmiConfiguration.class);
if (decrypt != null) {
final char[] password = wmiConfiguration.getPassword();
if (password != null) {
// Decrypt the password
wmiConfiguration.setPassword(decrypt.apply(password));
}
}
return wmiConfiguration;
} catch (Exception e) {
final String errorMessage = String.format(
"Error while reading WMI Configuration: %s. Error: %s",
jsonNode,
e.getMessage()
);
log.error(errorMessage);
log.debug("Error while reading WMI Configuration: {}. Stack trace:", jsonNode, 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();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy