Skip to content

Commit

Permalink
Merge branch 'feature/issue-424-add-cli-options-for-specific-query-ex…
Browse files Browse the repository at this point in the history
…ecution-eg-snmp-dump' into feature/issue-424-add-cli-options-for-specific-query-execution-http
  • Loading branch information
CherfaElyes committed Dec 6, 2024
2 parents 872653a + f9117e9 commit 36c965c
Show file tree
Hide file tree
Showing 90 changed files with 4,288 additions and 1,105 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,14 @@ This is a multi-module project:
* **metricshub-snmp-extension-common**: Contains common functionalities and utilities used by SNMP-based extensions.
* **metricshub-snmp-extension**: Enables Simple Network Management Protocol (SNMP) for monitoring and managing network devices.
* **metricshub-snmpv3-extension**: Adds support for SNMPv3, which includes enhanced security features like authentication and encryption.
* **metricshub-localsql-source-extension**: Allows execution of SQL queries on already existing sources.
* **metricshub-internaldb-extension**: Executes internal database queries using MetricsHub's internal database engine.
* **metricshub-win-extension-common**: Contains common functionalities and utilities used by Windows-specific extensions.
* **metricshub-wmi-extension**: Provides support for Windows Management Instrumentation (WMI) to gather detailed information about Windows systems.
* **metricshub-winrm-extension**: Enables the use of Windows Remote Management (WinRM) for remote management and monitoring of Windows-based systems.
* **metricshub-wbem-extension**: Supports the Web-Based Enterprise Management (WBEM) standard for accessing management information.
* **metricshub-ping-extension**: Enables testing the reachability of hosts using ICMP-based ping commands.
* **metricshub-jawk-extension**: Allows execution of Jawk scripts.
* **metricshub-jdbc-extension**: Provides support for monitoring SQL databases.
* **metricshub-hardware**: Hardware Energy and Sustainability module, dedicated to managing and monitoring hardware-related metrics, focusing on energy consumption and sustainability aspects.
* **metricshub-it-common**: Contains common code and utilities used by integration tests across various modules.
* **metricshub-windows**: Builds the `.zip` package for MetricsHub on Windows platforms.
Expand Down
6 changes: 6 additions & 0 deletions metricshub-agent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,12 @@
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>metricshub-jdbc-extension</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>

<!-- Log4j2 -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -988,10 +988,10 @@ private static void validateAndNormalizeProtocols(
for (Map.Entry<String, IConfiguration> entry : protocols.entrySet()) {
IConfiguration protocolConfig = entry.getValue();
if (protocolConfig != null) {
protocolConfig.validateConfiguration(resourceKey);
if (protocolConfig.getHostname() == null) {
protocolConfig.setHostname(hostname);
}
protocolConfig.validateConfiguration(resourceKey);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
import org.sentrysoftware.metricshub.engine.telemetry.metric.NumberMetric;

/**
* AbstractNumberMetricObserver is an extension of AbstractMetricObserver and serves as the base classd
* AbstractNumberMetricObserver is an extension of AbstractMetricObserver and serves as the base class
* for defining generic number metric observers in the MetricsHub agent. It introduces functionality specific
* to observing metrics with numerical values and is further extended by concrete number metric observer classes.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,22 @@ public void run() {
new HardwarePostDiscoveryStrategy(telemetryManager, discoveryTime, clientsExecutor, extensionManager)
);

/*
* Metrics are flushed after each collection and are only refreshed when they are explicitly updated.
* During the collection cycle, the discovery-related metrics may expire due to the "collect time".
* To prevent this expiration, send the metrics at the moment of discovery, ensuring they have the correct "collect time".
* This guarantees that the metrics remain valid and are not prematurely expired.
*/

// Initialize the OpenTelemetry observers and LogEmitter after the discovery
// as at this time we should have what we want to observe
initOtelSdk(telemetryManager, resourceConfig);

// Initialize metric observers
initAllObservers(telemetryManager);

// Call the flush of all the metric readers associated with this meter provider
autoConfiguredOpenTelemetrySdk.getOpenTelemetrySdk().getSdkMeterProvider().forceFlush();
}

log.info("Calling the engine to collect resource: {}.", hostId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import org.sentrysoftware.metricshub.cli.service.converter.DeviceKindConverter;
import org.sentrysoftware.metricshub.cli.service.protocol.HttpConfigCli;
import org.sentrysoftware.metricshub.cli.service.protocol.IpmiConfigCli;
import org.sentrysoftware.metricshub.cli.service.protocol.JdbcConfigCli;
import org.sentrysoftware.metricshub.cli.service.protocol.SnmpConfigCli;
import org.sentrysoftware.metricshub.cli.service.protocol.SnmpV3ConfigCli;
import org.sentrysoftware.metricshub.cli.service.protocol.SshConfigCli;
Expand Down Expand Up @@ -102,7 +103,8 @@
"@|bold ${ROOT-COMMAND-NAME}|@ " +
"@|yellow HOSTNAME|@ " +
"@|yellow -t|@=@|italic TYPE|@ " +
"<@|yellow --http|@|@|yellow --https|@|@|yellow --ipmi|@|@|yellow --snmp|@=@|italic VERSION|@|@|yellow --ssh|@|@|yellow --wbem|@|@|yellow --wmi|@|@|yellow --winrm|@> " +
"<@|yellow --http|@|@|yellow --https|@|@|yellow --ipmi|@|@|yellow --jdbc|@|@|yellow " +
"--snmp|@=@|italic VERSION|@|@|yellow --ssh|@|@|yellow --wbem|@|@|yellow --wmi|@|@|yellow --winrm|@> " +
"[@|yellow -u|@=@|italic USER|@ [@|yellow -p|@=@|italic P4SSW0RD|@]] [OPTIONS]..."
}
)
Expand Down Expand Up @@ -166,6 +168,9 @@ public class MetricsHubCliService implements Callable<Integer> {
@ArgGroup(exclusive = false, heading = "%n@|bold,underline WinRM Options|@:%n")
WinRmConfigCli winRmConfigCli;

@ArgGroup(exclusive = false, heading = "%n@|bold,underline JDBC Options|@:%n")
JdbcConfigCli jdbcConfigCli;

@Option(names = { "-u", "--username" }, order = 2, paramLabel = "USER", description = "Username for authentication")
String username;

Expand Down Expand Up @@ -476,12 +481,15 @@ private Map<Class<? extends IConfiguration>, IConfiguration> buildConfigurations
httpConfigCli,
wmiConfigCli,
winRmConfigCli,
wbemConfigCli
wbemConfigCli,
jdbcConfigCli
)
.filter(Objects::nonNull)
.map(protocolConfig -> {
try {
return protocolConfig.toProtocol(username, password);
final IConfiguration protocol = protocolConfig.toConfiguration(username, password);
protocol.validateConfiguration(hostname);
return protocol;
} catch (InvalidConfigurationException e) {
throw new IllegalStateException("Invalid configuration detected.", e);
}
Expand Down Expand Up @@ -513,14 +521,15 @@ private void validate() {
httpConfigCli,
wmiConfigCli,
winRmConfigCli,
wbemConfigCli
wbemConfigCli,
jdbcConfigCli
)
.allMatch(Objects::isNull);

if (protocolsNotConfigured) {
throw new ParameterException(
spec.commandLine(),
"At least one protocol must be specified: --http[s], --ipmi, --snmp,--snmpv3,--ssh, --wbem, --wmi, --winrm."
"At least one protocol must be specified: --http[s], --ipmi, --jdbc, --snmp, --snmpv3, --ssh, --wbem, --winrm, --wmi."
);
}
}
Expand Down Expand Up @@ -584,6 +593,8 @@ void tryInteractivePasswords(final CliPasswordReader<char[]> passwordReader) {
tryInteractiveWinRmPassword(passwordReader);

tryInteractiveSnmpV3Password(passwordReader);

tryInteractiveJdbcPassword(passwordReader);
}

/**
Expand Down Expand Up @@ -674,6 +685,17 @@ void tryInteractiveSnmpV3Password(final CliPasswordReader<char[]> passwordReader
}
}

/**
* Try to start the interactive mode to request and set JDBC password
*
* @param passwordReader password reader which displays the prompt text and wait for user's input
*/
void tryInteractiveJdbcPassword(final CliPasswordReader<char[]> passwordReader) {
if (jdbcConfigCli != null && jdbcConfigCli.getUsername() != null && jdbcConfigCli.getPassword() == null) {
jdbcConfigCli.setPassword(passwordReader.read("%s password for JDBC connection: ", jdbcConfigCli.getUsername()));
}
}

/**
* Prints the list of connectors embedded in the engine.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,15 @@ public static class HttpOrHttps {
private String timeout;

/**
* This method creates an {@link IConfiguration} for a given username and a given password.
*
* @param defaultUsername Username specified at the top level of the CLI (with the --username option)
* @param defaultPassword Password specified at the top level of the CLI (with the --password option)
* @return an HttpProtocol instance corresponding to the options specified by the user in the CLI
* @throws InvalidConfigurationException
*/
@Override
public IConfiguration toProtocol(String defaultUsername, char[] defaultPassword)
public IConfiguration toConfiguration(String defaultUsername, char[] defaultPassword)
throws InvalidConfigurationException {
final ObjectNode configuration = JsonNodeFactory.instance.objectNode();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,5 @@ public interface IProtocolConfigCli {
* @return Instance of {@link IConfiguration}
* @throws InvalidConfigurationException if the configuration is invalid.
*/
IConfiguration toProtocol(String defaultUsername, char[] defaultPassword) throws InvalidConfigurationException;
IConfiguration toConfiguration(String defaultUsername, char[] defaultPassword) throws InvalidConfigurationException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ public class IpmiConfigCli implements IProtocolConfigCli {
* @return an {@link IConfiguration} instance corresponding to the options specified by the user in the CLI
*/
@Override
public IConfiguration toProtocol(final String defaultUsername, final char[] defaultPassword)
public IConfiguration toConfiguration(final String defaultUsername, final char[] defaultPassword)
throws InvalidConfigurationException {
final ObjectNode configuration = JsonNodeFactory.instance.objectNode();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package org.sentrysoftware.metricshub.cli.service.protocol;

/*-
* ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
* MetricsHub Agent
* ჻჻჻჻჻჻
* 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 <http://www.gnu.org/licenses/>.
* ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
*/

import com.fasterxml.jackson.databind.node.IntNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import lombok.Data;
import org.sentrysoftware.metricshub.cli.service.CliExtensionManager;
import org.sentrysoftware.metricshub.engine.common.exception.InvalidConfigurationException;
import org.sentrysoftware.metricshub.engine.configuration.IConfiguration;
import picocli.CommandLine.Option;

/**
* This class is used by MetricsHubCliService to configure JDBC when using the MetricsHub CLI.
* It creates the engine's {@link IConfiguration} for JDBC object that is used to monitor a specific resource.
*/
@Data
public class JdbcConfigCli implements IProtocolConfigCli {

/**
* Default timeout in seconds for an SQL query
*/
public static final int DEFAULT_TIMEOUT = 30;

@Option(names = "--jdbc", order = 1, description = "Enables JDBC")
private boolean useJdbc;

@Option(names = "--jdbc-url", order = 2, paramLabel = "URL", description = "JDBC URL")
private char[] url;

@Option(
names = "--jdbc-username",
order = 3,
paramLabel = "USERNAME",
description = "Username for JDBC authentication"
)
private String username;

@Option(
names = "--jdbc-password",
order = 4,
paramLabel = "PASSWORD",
description = "Password for JDBC authentication"
)
private char[] password;

@Option(
names = "--jdbc-timeout",
order = 5,
paramLabel = "TIMEOUT",
defaultValue = "" + DEFAULT_TIMEOUT,
description = "Timeout in seconds for SQL queries(default: ${DEFAULT-VALUE} s)"
)
private String timeout;

@Option(names = "--jdbc-port", order = 6, paramLabel = "PORT", description = "Port for JDBC connection")
private int port;

@Option(names = "--jdbc-database", order = 7, paramLabel = "DATABASE", description = "Name of the database")
private String database;

@Option(
names = "--jdbc-type",
order = 8,
paramLabel = "TYPE",
description = "Type of JDBC database (e.g., MySQL, PostgreSQL, SQLServer)"
)
private String type;

/**
* This method creates an {@link IConfiguration} for a given username and a given password..
*
* @param defaultUsername Username specified at the top level of the CLI (with the --username option)
* @param defaultPassword Password specified at the top level of the CLI (with the --password option)
* @return an SQLProtocol instance corresponding to the options specified by the user in the CLI
* @throws InvalidConfigurationException If the SQL extension is unable to parse SQL configuration inputs.
*/
@Override
public IConfiguration toConfiguration(final String defaultUsername, final char[] defaultPassword)
throws InvalidConfigurationException {
final ObjectNode configuration = JsonNodeFactory.instance.objectNode();

final String finalUsername = username == null ? defaultUsername : username;
configuration.set("username", new TextNode(finalUsername));

final char[] finalPassword = username == null ? defaultPassword : password;
if (finalPassword != null) {
configuration.set("password", new TextNode(String.valueOf(finalPassword)));
}

if (url != null && url.length > 0) {
configuration.set("url", new TextNode(String.valueOf(url)));
}
configuration.set("timeout", new TextNode(timeout));
configuration.set("port", new IntNode(port));
configuration.set("database", new TextNode(database));
configuration.set("type", new TextNode(type));

return CliExtensionManager
.getExtensionManagerSingleton()
.buildConfigurationFromJsonNode("jdbc", configuration, value -> value)
.orElseThrow();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public class SnmpConfigCli implements IProtocolConfigCli {

@Option(
names = { "--snmp-retry-intervals", "--retry" },
order = 2,
order = 5,
paramLabel = "RETRYINTERVALS",
description = "Timeout in milliseconds after which the elementary operations will be retried"
)
Expand All @@ -98,7 +98,7 @@ public class SnmpConfigCli implements IProtocolConfigCli {
* @throws InvalidConfigurationException If the given configuration JSON node is invalid.
*/
@Override
public IConfiguration toProtocol(final String defaultUsername, final char[] defaultPassword)
public IConfiguration toConfiguration(final String defaultUsername, final char[] defaultPassword)
throws InvalidConfigurationException {
final ObjectNode configuration = JsonNodeFactory.instance.objectNode();
configuration.set("version", new TextNode(snmpVersion));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ public class SnmpV3ConfigCli implements IProtocolConfigCli {
* parse SNMPV3 configuration inputs.
*/
@Override
public IConfiguration toProtocol(final String defaultUsername, final char[] defaultPassword)
public IConfiguration toConfiguration(final String defaultUsername, final char[] defaultPassword)
throws InvalidConfigurationException {
final ObjectNode configuration = JsonNodeFactory.instance.objectNode();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public class SshConfigCli implements IProtocolConfigCli {
* @throws InvalidConfigurationException
*/
@Override
public IConfiguration toProtocol(final String defaultUsername, final char[] defaultPassword)
public IConfiguration toConfiguration(final String defaultUsername, final char[] defaultPassword)
throws InvalidConfigurationException {
final ObjectNode configuration = JsonNodeFactory.instance.objectNode();
// Create an arrayNode that will contain all the sudo commands that the user introduced
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public class WbemConfigCli extends AbstractTransportProtocolCli {
* @return an {@link IConfiguration} instance corresponding to the options specified by the user in the CLI
*/
@Override
public IConfiguration toProtocol(final String defaultUsername, final char[] defaultPassword)
public IConfiguration toConfiguration(final String defaultUsername, final char[] defaultPassword)
throws InvalidConfigurationException {
final ObjectNode configuration = JsonNodeFactory.instance.objectNode();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ public class WinRmConfigCli extends AbstractTransportProtocolCli {
* @throws InvalidConfigurationException
*/
@Override
public IConfiguration toProtocol(String defaultUsername, char[] defaultPassword)
public IConfiguration toConfiguration(String defaultUsername, char[] defaultPassword)
throws InvalidConfigurationException {
final ObjectNode configuration = JsonNodeFactory.instance.objectNode();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public class WmiConfigCli implements IProtocolConfigCli {
* @throws InvalidConfigurationException If the WMI extension is unable to parse WMI configuration inputs.
*/
@Override
public IConfiguration toProtocol(String defaultUsername, char[] defaultPassword)
public IConfiguration toConfiguration(String defaultUsername, char[] defaultPassword)
throws InvalidConfigurationException {
final ObjectNode configuration = JsonNodeFactory.instance.objectNode();

Expand Down
Loading

0 comments on commit 36c965c

Please sign in to comment.