readConnectorsWithConfigurationVariablesSa
resourceKey,
e.getMessage()
);
- return new HashMap<>();
+ return new AdditionalConnectorsParsingResult();
}
}
@@ -1046,7 +1043,7 @@ static HostConfiguration buildHostConfiguration(
.hostType(hostType)
.sequential(Boolean.TRUE.equals(resourceConfig.getSequential()))
.configuredConnectorId(configuredConnectorId)
- .connectorVariables(resourceConfig.getVariables())
+ .connectorVariables(resourceConfig.getConnectorVariables())
.resolveHostnameToFqdn(resourceConfig.getResolveHostnameToFqdn())
.build();
}
diff --git a/metricshub-agent/src/main/java/org/sentrysoftware/metricshub/agent/helper/ConnectorTemplateLibraryParser.java b/metricshub-agent/src/main/java/org/sentrysoftware/metricshub/agent/helper/ConnectorTemplateLibraryParser.java
deleted file mode 100644
index 231b4b837..000000000
--- a/metricshub-agent/src/main/java/org/sentrysoftware/metricshub/agent/helper/ConnectorTemplateLibraryParser.java
+++ /dev/null
@@ -1,216 +0,0 @@
-package org.sentrysoftware.metricshub.agent.helper;
-
-/*-
- * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
- * 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 .
- * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
- */
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
-import java.io.IOException;
-import java.nio.file.FileVisitResult;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.SimpleFileVisitor;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.TreeMap;
-import lombok.NonNull;
-import lombok.extern.slf4j.Slf4j;
-import org.sentrysoftware.metricshub.engine.configuration.ConnectorVariables;
-import org.sentrysoftware.metricshub.engine.connector.model.Connector;
-import org.sentrysoftware.metricshub.engine.connector.model.identity.ConnectorDefaultVariable;
-import org.sentrysoftware.metricshub.engine.connector.parser.ConnectorParser;
-
-/**
- * Utility class for parsing connector template YAML files and creating a map of custom connectors.
- * This class provides functionality to visit YAML files in a specified directory, read connector data,
- * and create Connector objects based on the parsed data. The resulting connectors are stored in a map
- * with the connector ID as the key and the corresponding Connector object as the value.
- *
- * The parsing process involves checking for YAML files, validating whether the YAML structure defines a
- * final Connector (with a displayName section), and using ConnectorParser to parse the YAML file and create
- * Connector objects.
- *
- */
-@Slf4j
-public class ConnectorTemplateLibraryParser {
-
- /**
- * This inner class allows to visit the files contained within the Yaml directory
- */
- private static class ConnectorFileVisitor extends SimpleFileVisitor {
-
- private final Map connectorVariablesMap;
- private final Map customConnectorsMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
-
- public Map getCustomConnectorsMap() {
- return customConnectorsMap;
- }
-
- ConnectorFileVisitor(final Map connectorVariablesMap) {
- this.connectorVariablesMap = connectorVariablesMap;
- }
-
- @Override
- public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException {
- // Skip this path if it is a directory or not a YAML file
- if (Files.isDirectory(path) || !isYamlFile(path.toFile().getName())) {
- return FileVisitResult.CONTINUE;
- }
- final ObjectMapper yamlMapper = new YAMLMapper();
- final JsonNode connectorNode = yamlMapper.readTree(path.toFile());
- if (!isConnector(connectorNode)) {
- return FileVisitResult.CONTINUE;
- }
-
- // Get the connector's file name
- final String filename = path.getFileName().toString();
- final String connectorId = filename.substring(0, filename.lastIndexOf('.'));
-
- if (!connectorNode.toString().contains("${var::")) {
- return FileVisitResult.CONTINUE;
- }
-
- // User connector variables
- final ConnectorVariables connectorUserVariables = connectorVariablesMap.computeIfAbsent(
- connectorId,
- id -> new ConnectorVariables()
- );
-
- // Retrieve the default connector variables that have been specified in this connector.
- final Map connectorDefaultVariables = getConnectorVariables(connectorNode);
-
- // User didn't configure variables for this connector, and no connector default variables are configured
- if (connectorUserVariables.getVariableValues().isEmpty() && connectorDefaultVariables.isEmpty()) {
- return FileVisitResult.CONTINUE;
- }
-
- // For each configured default connector variable, if the user didn't specify a value to that variable, user default value.
- for (final Entry entry : connectorDefaultVariables.entrySet()) {
- connectorUserVariables.getVariableValues().putIfAbsent(entry.getKey(), entry.getValue().getDefaultValue());
- }
-
- final ConnectorParser connectorParser = ConnectorParser.withNodeProcessorAndUpdateChain(
- path.getParent(),
- connectorVariablesMap.get(connectorId).getVariableValues()
- );
-
- // Put in the custom connectorsMap
- try {
- customConnectorsMap.put(connectorId, connectorParser.parse(path.toFile()));
- } catch (Exception e) {
- log.error("Error while parsing connector with template variables {}: {}", filename, e.getMessage());
- log.debug("Exception: ", e);
- }
-
- return FileVisitResult.CONTINUE;
- }
-
- /**
- * Whether the JsonNode is a final Connector. It means that this JsonNode defines the displayName section.
- *
- * @param connector JsonNode that contains connector's data
- * @return true
if the {@link JsonNode} is a final connector, otherwise false.
- */
- private boolean isConnector(final JsonNode connector) {
- final JsonNode connectorNode = connector.get("connector");
- if (connectorNode != null && !connectorNode.isNull()) {
- final JsonNode displayName = connectorNode.get("displayName");
- return displayName != null && !displayName.isNull();
- }
-
- return false;
- }
-
- /**
- * Whether the connector is a YAML file or not
- *
- * @param name given fileName
- * @return boolean value
- */
- private boolean isYamlFile(final String name) {
- return name.toLowerCase().endsWith(".yaml");
- }
-
- /**
- * Converts the "variables" section of a {@link JsonNode} into a {@link Map} where each entry consists of
- * a variable name as the key and a {@link ConnectorDefaultVariable} as the value.
- * Each {@link ConnectorDefaultVariable} contains a description and a default value extracted from the JSON node.
- *
- * @param connectorNode the {@link JsonNode} representing the connector, which includes a "variables" section.
- * @return a map where the key is the variable name, and the value is a {@link ConnectorDefaultVariable} object
- * containing the description and defaultValue for that variable. If the "variables" section is not present,
- * an empty map is returned.
- */
- private static Map getConnectorVariables(final JsonNode connectorNode) {
- final JsonNode variablesNode = connectorNode.get("connector").get("variables");
- if (variablesNode == null) {
- return new HashMap<>();
- }
-
- final Map connectorVariablesMap = new HashMap<>();
-
- // Iterate over the variables and extract description and defaultValue
- variablesNode
- .fields()
- .forEachRemaining(entry -> {
- final String variableName = entry.getKey();
- final JsonNode variableValue = entry.getValue();
-
- final String description = variableValue.get("description").asText();
- final String defaultValue = variableValue.get("defaultValue").asText();
-
- // Create a ConnectorDefaultVariable object and put it into the map
- final ConnectorDefaultVariable connectorDefaultVariable = new ConnectorDefaultVariable(
- description,
- defaultValue
- );
- connectorVariablesMap.put(variableName, connectorDefaultVariable);
- });
-
- return connectorVariablesMap;
- }
- }
-
- /**
- * Parses connector template YAML files in the specified directory and creates a map of custom connectors.
- *
- * @param yamlParentDirectory The directory containing connector YAML files
- * @param connectorVariablesMap A map of ConnectorVariables for variable substitution
- * @return Map<String, Connector> (connectors map: key=yamlFileName, value=Connector)
- * @throws IOException if the file does not exist or an I/O error occurs during processing
- */
- public Map parse(
- @NonNull final Path yamlParentDirectory,
- @NonNull final Map connectorVariablesMap
- ) throws IOException {
- final long startTime = System.currentTimeMillis();
- final ConnectorFileVisitor connectorFileVisitor = new ConnectorFileVisitor(connectorVariablesMap);
- Files.walkFileTree(yamlParentDirectory, connectorFileVisitor);
- log.info(
- "Connectors with template variables parsing duration: {} seconds",
- (System.currentTimeMillis() - startTime) / 1000
- );
- return connectorFileVisitor.getCustomConnectorsMap();
- }
-}
diff --git a/metricshub-agent/src/main/java/org/sentrysoftware/metricshub/agent/helper/ConnectorVariablesLibraryParser.java b/metricshub-agent/src/main/java/org/sentrysoftware/metricshub/agent/helper/ConnectorVariablesLibraryParser.java
new file mode 100644
index 000000000..953f3a23c
--- /dev/null
+++ b/metricshub-agent/src/main/java/org/sentrysoftware/metricshub/agent/helper/ConnectorVariablesLibraryParser.java
@@ -0,0 +1,288 @@
+package org.sentrysoftware.metricshub.agent.helper;
+
+/*-
+ * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
+ * 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 .
+ * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
+ */
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+import lombok.NonNull;
+import lombok.extern.slf4j.Slf4j;
+import org.sentrysoftware.metricshub.agent.config.AdditionalConnector;
+import org.sentrysoftware.metricshub.agent.deserialization.AdditionalConnectorsParsingResult;
+import org.sentrysoftware.metricshub.engine.connector.model.Connector;
+import org.sentrysoftware.metricshub.engine.connector.model.identity.ConnectorDefaultVariable;
+import org.sentrysoftware.metricshub.engine.connector.parser.ConnectorParser;
+
+/**
+ * Utility class for parsing connectors with variables and creating a map of custom connectors.
+ * This class provides functionality to visit YAML files in a specified directory, read connector data,
+ * and create Connector objects based on the parsed data. The resulting connectors are stored in a map
+ * with the connector ID as the key and the corresponding Connector object as the value.
+ *
+ * The parsing process involves checking for YAML files, validating whether the YAML structure defines a
+ * final Connector (with a displayName section), and using ConnectorParser to parse the YAML file and create
+ * Connector objects.
+ *
+ */
+@Slf4j
+public class ConnectorVariablesLibraryParser {
+
+ /**
+ * This inner class allows to visit the files contained within the Yaml directory
+ */
+ private static class ConnectorFileVisitor extends SimpleFileVisitor {
+
+ private final Map additionalConnectorConfig;
+ private final AdditionalConnectorsParsingResult connectorsParsingResult = new AdditionalConnectorsParsingResult();
+
+ public AdditionalConnectorsParsingResult getConnectorsParsingResult() {
+ return connectorsParsingResult;
+ }
+
+ ConnectorFileVisitor(final Map additionalConnectorConfig) {
+ this.additionalConnectorConfig = additionalConnectorConfig;
+ }
+
+ @Override
+ public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException {
+ // Skip this path if it is a directory or not a YAML file
+ if (Files.isDirectory(path) || !isYamlFile(path.toFile().getName())) {
+ return FileVisitResult.CONTINUE;
+ }
+ final ObjectMapper yamlMapper = new YAMLMapper();
+ final JsonNode connectorNode = yamlMapper.readTree(path.toFile());
+ if (!isConnector(connectorNode)) {
+ return FileVisitResult.CONTINUE;
+ }
+
+ // Get the connector's file name
+ final String filename = path.getFileName().toString();
+ final String connectorId = filename.substring(0, filename.lastIndexOf('.'));
+
+ if (!connectorNode.toString().contains("${var::")) {
+ return FileVisitResult.CONTINUE;
+ }
+
+ // Normalize additionalConnectors
+ normalizeAdditionalConnectors();
+
+ // Removing all the configurations that are not using this connector.
+ final Map filteredConnectors = additionalConnectorConfig
+ .entrySet()
+ .stream()
+ .filter(entry -> connectorId.equalsIgnoreCase(entry.getValue().getUses()))
+ .collect(
+ Collectors.toMap(
+ Map.Entry::getKey, // Keep the original key
+ Map.Entry::getValue // Keep the original AdditionalConnectorConfig as the value
+ )
+ );
+
+ // Construct a variables map from the default connector variables.
+ final Map defaultVariables = new HashMap<>(getDefaultConnectorVariables(connectorNode));
+
+ // Parse the connector even if it is not configured as an additional connector.
+ // This ensures that the connector will function with the default variables if the user forces it.
+ if (filteredConnectors.isEmpty()) {
+ parseConnectorWithModifier(path, defaultVariables, connectorId, filename, connector -> {});
+ }
+
+ // For each configuration, we create a new custom connector and a new variables map to be used in the connector update.
+ for (final Entry connectorConfigurationEntry : filteredConnectors.entrySet()) {
+ final String additionalConnectorId = connectorConfigurationEntry.getKey();
+ final AdditionalConnector additionalConnectorValue = connectorConfigurationEntry.getValue();
+
+ // Add the connector to the host connectors set.
+ connectorsParsingResult
+ .getHostConnectors()
+ .add(additionalConnectorValue.isForce() ? "+" + additionalConnectorId : additionalConnectorId);
+
+ // Retrieve and use default connector variables on this connector for this configuration.
+ final Map connectorVariables = new HashMap<>(defaultVariables);
+
+ // Override the default connector variables by the connector variables that the user configured.
+ final Map configuredVariables = additionalConnectorValue.getVariables();
+ if (configuredVariables != null) {
+ connectorVariables.putAll(configuredVariables);
+ }
+ // There are at least two additional connectors that use the current connector.
+ // This means that the compiled filename of these connectors needs to be modified.
+ if (filteredConnectors.size() > 1) {
+ parseConnectorWithModifier(
+ path,
+ connectorVariables,
+ additionalConnectorId,
+ filename,
+ connector -> connector.getConnectorIdentity().setCompiledFilename(additionalConnectorId)
+ );
+ continue;
+ }
+ parseConnectorWithModifier(path, connectorVariables, connectorId, filename, connector -> {});
+ }
+ return FileVisitResult.CONTINUE;
+ }
+
+ /**
+ * Whether the JsonNode is a final Connector. It means that this JsonNode defines the displayName section.
+ *
+ * @param connector JsonNode that contains connector's data
+ * @return true
if the {@link JsonNode} is a final connector, otherwise false.
+ */
+ private boolean isConnector(final JsonNode connector) {
+ final JsonNode connectorNode = connector.get("connector");
+ if (connectorNode != null && !connectorNode.isNull()) {
+ final JsonNode displayName = connectorNode.get("displayName");
+ return displayName != null && !displayName.isNull();
+ }
+
+ return false;
+ }
+
+ /**
+ * Whether the connector is a YAML file or not
+ *
+ * @param name given fileName
+ * @return boolean value
+ */
+ private boolean isYamlFile(final String name) {
+ return name.toLowerCase().endsWith(".yaml");
+ }
+
+ /**
+ * Converts the "variables" section of a {@link JsonNode} into a {@link Map} where each entry consists of
+ * a variable name as the key and a {@link ConnectorDefaultVariable} as the value.
+ * Each {@link ConnectorDefaultVariable} contains a description and a default value extracted from the JSON node.
+ *
+ * @param connectorNode the {@link JsonNode} representing the connector, which includes a "variables" section.
+ * @return a map where the key is the variable name, and the value is a {@link ConnectorDefaultVariable} object
+ * containing the description and defaultValue for that variable. If the "variables" section is not present,
+ * an empty map is returned.
+ */
+ private static Map getDefaultConnectorVariables(final JsonNode connectorNode) {
+ final JsonNode variablesNode = connectorNode.get("connector").get("variables");
+ if (variablesNode == null) {
+ return new HashMap<>();
+ }
+
+ final Map connectorVariablesMap = new HashMap<>();
+
+ // Iterate over the variables and extract description and defaultValue
+ variablesNode
+ .fields()
+ .forEachRemaining(entry -> {
+ final String variableName = entry.getKey();
+ final JsonNode variableValue = entry.getValue();
+
+ connectorVariablesMap.put(variableName, variableValue.get("defaultValue").asText());
+ });
+
+ return connectorVariablesMap;
+ }
+
+ /**
+ * Parses a connector file located at the specified path, using the provided variables and connector Id.
+ * The parsed connector is then added to the custom connectors map, with the option to perform additional
+ * operations on the connector before adding it to the map.
+ *
+ * @param path The path to the connector file that needs to be parsed.
+ * @param variables A map of variables to be used for processing the connector, where the keys are variable names and the values are the corresponding values.
+ * @param connectorId The unique identifier for the connector being parsed, used as the key in the custom connectors map.
+ * @param filename The name of the connector file, used for logging in case of an error.
+ * @param connectorModifier A function to apply additional changes to the parsed connector before adding it to the map.
+ */
+ private void parseConnectorWithModifier(
+ final Path path,
+ final Map variables,
+ final String connectorId,
+ final String filename,
+ final Consumer connectorModifier
+ ) {
+ final ConnectorParser connectorParser = ConnectorParser.withNodeProcessorAndUpdateChain(
+ path.getParent(),
+ variables
+ );
+ try {
+ final Connector connector = connectorParser.parse(path.toFile());
+ connectorModifier.accept(connector);
+ connectorsParsingResult.getCustomConnectorsMap().put(connectorId, connector);
+ } catch (Exception e) {
+ log.error("Error while parsing connector with variables {}: {}", filename, e.getMessage());
+ log.debug("Exception: ", e);
+ }
+ }
+
+ /**
+ * Updates the additional connectors configuration by ensuring that each entry has a valid
+ * {@code AdditionalConnector} object. If the connector or its {@code uses} field is null, it is set
+ * to the connector Id.
+ */
+ private void normalizeAdditionalConnectors() {
+ additionalConnectorConfig
+ .entrySet()
+ .forEach(entry -> {
+ final String connectorId = entry.getKey();
+ final AdditionalConnector additionalConnector = entry.getValue();
+
+ // If additionalConnector is null, create a new object and update the entry
+ if (additionalConnector == null) {
+ entry.setValue(AdditionalConnector.builder().force(true).uses(connectorId).variables(null).build());
+ return;
+ }
+
+ // If uses() is null, set it to the connectorId
+ if (additionalConnector.getUses() == null) {
+ additionalConnector.setUses(connectorId);
+ }
+ });
+ }
+ }
+
+ /**
+ * Parses connectors with variables YAML files in the specified directory and creates a map of custom connectors.
+ *
+ * @param yamlParentDirectory The directory containing connector YAML files
+ * @param additionalConnectorConfig A map of additional connector configurations
+ * @return {@link AdditionalConnectorsParsingResult} containing parsed connectors and any forced connectors
+ * @throws IOException if the file does not exist or an I/O error occurs during processing
+ */
+ public AdditionalConnectorsParsingResult parse(
+ @NonNull final Path yamlParentDirectory,
+ @NonNull final Map additionalConnectorConfig
+ ) throws IOException {
+ final long startTime = System.currentTimeMillis();
+ final ConnectorFileVisitor connectorFileVisitor = new ConnectorFileVisitor(additionalConnectorConfig);
+ Files.walkFileTree(yamlParentDirectory, connectorFileVisitor);
+ log.info("Connectors with variables parsing duration: {} seconds", (System.currentTimeMillis() - startTime) / 1000);
+ return connectorFileVisitor.getConnectorsParsingResult();
+ }
+}
diff --git a/metricshub-agent/src/test/java/org/sentrysoftware/metricshub/agent/context/AgentContextTest.java b/metricshub-agent/src/test/java/org/sentrysoftware/metricshub/agent/context/AgentContextTest.java
index 8c1edb446..4a4fdbebc 100644
--- a/metricshub-agent/src/test/java/org/sentrysoftware/metricshub/agent/context/AgentContextTest.java
+++ b/metricshub-agent/src/test/java/org/sentrysoftware/metricshub/agent/context/AgentContextTest.java
@@ -30,6 +30,7 @@
import java.util.Map;
import java.util.Set;
import org.junit.jupiter.api.Test;
+import org.sentrysoftware.metricshub.agent.config.AdditionalConnector;
import org.sentrysoftware.metricshub.agent.config.AgentConfig;
import org.sentrysoftware.metricshub.agent.config.ResourceConfig;
import org.sentrysoftware.metricshub.agent.config.ResourceGroupConfig;
@@ -205,14 +206,43 @@ void testInitializeWithConnectorVariables() throws IOException {
.get(SENTRY_PARIS_RESOURCE_GROUP_KEY)
.getResources()
.get(SERVER_1_RESOURCE_GROUP_KEY);
- final Map variables = resourceConfig.getVariables();
- final ConnectorVariables expectedConnectorVariables = ConnectorVariables
+
+ final Map additionalConnectors = resourceConfig.getAdditionalConnectors();
+ // Check the number of additional connectors
+ assertEquals(5, additionalConnectors.size());
+
+ final Map variables = resourceConfig.getConnectorVariables();
+ // Check the number of configured ConnectorVariables
+ assertEquals(3, variables.size());
+
+ AdditionalConnector pureStorageREST = AdditionalConnector
+ .builder()
+ .uses("PureStorageREST")
+ .variables(Map.of("restQueryPath", "/pure/api/v2"))
+ .force(false)
+ .build();
+ assertEquals(pureStorageREST, additionalConnectors.get("PureStorageREST"));
+ AdditionalConnector windows = AdditionalConnector
.builder()
- .variableValues(Map.of("restQueryPath", "/pure/api/v2"))
+ .variables(Map.of("osType", "windows"))
+ .force(true)
.build();
- assertEquals(Map.of("PureStorageREST", expectedConnectorVariables), variables);
- // Case insensitive check
- assertEquals(expectedConnectorVariables, variables.get("purestoragerest"));
+ AdditionalConnector linux = AdditionalConnector.builder().uses("Linux").variables(null).force(true).build();
+ AdditionalConnector ipmiTool = AdditionalConnector
+ .builder()
+ .uses("IpmiTool")
+ .variables(Map.of())
+ .force(true)
+ .build();
+
+ final Map expectedAdditionalConnectors = new LinkedHashMap<>();
+
+ expectedAdditionalConnectors.put("PureStorageREST", pureStorageREST);
+ expectedAdditionalConnectors.put("Windows", windows);
+ expectedAdditionalConnectors.put("Linux", linux);
+ expectedAdditionalConnectors.put("IpmiTool", ipmiTool);
+ expectedAdditionalConnectors.put("LinuxProcess", null);
+ assertEquals(expectedAdditionalConnectors, additionalConnectors);
}
@Test
diff --git a/metricshub-agent/src/test/java/org/sentrysoftware/metricshub/agent/helper/ConnectorTemplateLibraryParserTest.java b/metricshub-agent/src/test/java/org/sentrysoftware/metricshub/agent/helper/ConnectorVariablesLibraryParserTest.java
similarity index 60%
rename from metricshub-agent/src/test/java/org/sentrysoftware/metricshub/agent/helper/ConnectorTemplateLibraryParserTest.java
rename to metricshub-agent/src/test/java/org/sentrysoftware/metricshub/agent/helper/ConnectorVariablesLibraryParserTest.java
index 78edde3e1..51895ca98 100644
--- a/metricshub-agent/src/test/java/org/sentrysoftware/metricshub/agent/helper/ConnectorTemplateLibraryParserTest.java
+++ b/metricshub-agent/src/test/java/org/sentrysoftware/metricshub/agent/helper/ConnectorVariablesLibraryParserTest.java
@@ -11,33 +11,42 @@
import java.util.Map;
import java.util.Set;
import org.junit.jupiter.api.Test;
-import org.sentrysoftware.metricshub.engine.configuration.ConnectorVariables;
+import org.sentrysoftware.metricshub.agent.config.AdditionalConnector;
+import org.sentrysoftware.metricshub.agent.deserialization.AdditionalConnectorsParsingResult;
import org.sentrysoftware.metricshub.engine.connector.model.Connector;
import org.sentrysoftware.metricshub.engine.connector.model.identity.Detection;
import org.sentrysoftware.metricshub.engine.connector.model.identity.criterion.SnmpGetNextCriterion;
-class ConnectorTemplateLibraryParserTest {
+class ConnectorVariablesLibraryParserTest {
- private static final String CONNECTOR_ID = "templateVariable";
+ private static final String CONNECTOR_ID = "connectorVariable";
@Test
void testParse() throws IOException {
// Define the yaml test files path
- final Path yamlTestPath = Paths.get("src", "test", "resources", "connectorTemplateLibraryParser");
+ final Path yamlTestPath = Paths.get("src", "test", "resources", "connectorVariablesLibraryParser");
- // Call ConnectorTemplateLibraryParser to parse the custom connectors files using the connectorVariables map and the connector id
- final ConnectorTemplateLibraryParser connectorTemplateLibraryParser = new ConnectorTemplateLibraryParser();
+ // Call ConnectorVariablesLibraryParser to parse the custom connectors files using the connectorVariables map and the connector id
+ final ConnectorVariablesLibraryParser connectorVariablesLibraryParser = new ConnectorVariablesLibraryParser();
- final ConnectorVariables connectorVariables = new ConnectorVariables(new HashMap<>());
- connectorVariables.addVariableValue("snmp-get-next", "snmpGetNext");
- connectorVariables.addVariableValue("local-variable", "local");
- final Map connectorVariablesMap = new HashMap<>();
- connectorVariablesMap.put(CONNECTOR_ID, connectorVariables);
- final Map customConnectorsMap = connectorTemplateLibraryParser.parse(
+ final Map connectorVariables = new HashMap<>();
+ connectorVariables.put("snmp-get-next", "snmpGetNext");
+ connectorVariables.put("local-variable", "local");
+ final Map additionalConnectorConfigMap = new HashMap<>();
+ final AdditionalConnector additionalConnectorConfig = AdditionalConnector
+ .builder()
+ .force(true)
+ .uses(CONNECTOR_ID)
+ .variables(connectorVariables)
+ .build();
+ additionalConnectorConfigMap.put(CONNECTOR_ID, additionalConnectorConfig);
+ final AdditionalConnectorsParsingResult parsingResult = connectorVariablesLibraryParser.parse(
yamlTestPath,
- connectorVariablesMap
+ additionalConnectorConfigMap
);
+ final Map customConnectorsMap = parsingResult.getCustomConnectorsMap();
+
// Check that only the connector containing variables is returned in the map
assertEquals(1, customConnectorsMap.size());
diff --git a/metricshub-agent/src/test/resources/config/metricshub-connectorVariables.yaml b/metricshub-agent/src/test/resources/config/metricshub-connectorVariables.yaml
index 60c0098a0..119c26fac 100644
--- a/metricshub-agent/src/test/resources/config/metricshub-connectorVariables.yaml
+++ b/metricshub-agent/src/test/resources/config/metricshub-connectorVariables.yaml
@@ -56,10 +56,28 @@ resourceGroups:
port: 443
username: username
password: password
- variables:
- PureStorageREST:
- restQueryPath: /pure/api/v2
- nullValue:
- OtherNull:
connectors:
- - +PureStorageREST
\ No newline at end of file
+ - +PureStorageREST
+ additionalConnectors:
+ # With an empty variable value and false force
+ PureStorageREST:
+ uses: PureStorageREST
+ force: false
+ variables:
+ restQueryPath: /pure/api/v2
+ nullValue:
+ # Without uses and force
+ Windows:
+ variables:
+ osType: windows
+ # With an empty variables map
+ Linux:
+ uses: Linux
+ force: true
+ variables:
+ # Without variables
+ IpmiTool:
+ uses: IpmiTool
+ force: true
+ # Without uses, force, & variables
+ LinuxProcess:
\ No newline at end of file
diff --git a/metricshub-agent/src/test/resources/connectorTemplateLibraryParser/templateVariable.yaml b/metricshub-agent/src/test/resources/connectorVariablesLibraryParser/connectorVariable.yaml
similarity index 100%
rename from metricshub-agent/src/test/resources/connectorTemplateLibraryParser/templateVariable.yaml
rename to metricshub-agent/src/test/resources/connectorVariablesLibraryParser/connectorVariable.yaml
diff --git a/metricshub-agent/src/test/resources/connectorTemplateLibraryParser/noTemplateVariable.yaml b/metricshub-agent/src/test/resources/connectorVariablesLibraryParser/noConnectorVariable.yaml
similarity index 100%
rename from metricshub-agent/src/test/resources/connectorTemplateLibraryParser/noTemplateVariable.yaml
rename to metricshub-agent/src/test/resources/connectorVariablesLibraryParser/noConnectorVariable.yaml
diff --git a/metricshub-doc/src/site/markdown/configuration/configure-monitoring.md b/metricshub-doc/src/site/markdown/configuration/configure-monitoring.md
index f4e7080bc..99ce61713 100644
--- a/metricshub-doc/src/site/markdown/configuration/configure-monitoring.md
+++ b/metricshub-doc/src/site/markdown/configuration/configure-monitoring.md
@@ -828,7 +828,9 @@ loggerLevel: ...
#### Configure Connector Variables
-In **MetricsHub**, connector variables are essential for customizing the behavior of data collection. The connector variables are configured in the `metricshub.yaml` file under the `variables` section of your configured resource. These variables are specified under the name of the connector to which they belong and contain key-value pairs. The key of each variable corresponds to a variable already configured in the connector.
+In **MetricsHub**, connector variables are essential for customizing the behavior of data collection. These variables are configured in the `additionalConnectors` section of your `metricshub.yaml` file. When configuring variables for connectors with variables, the connector becomes an additional connector, which is forced by default and will use the variables configured by the user.
+
+Each additional connector is identified by its ID, and the variables are specified under this ID in the additionalConnectors section. The variables consist of key-value pairs, where the key corresponds to a variable already defined in the connector.
* Example :
@@ -843,11 +845,19 @@ resources:
protocols:
wmi:
timeout: 120
- variables:
- windowsProcess: # Connector ID
- processName: "('msedge.exe', 'metricshub.exe')"
+ additionalConnectors:
+ metricshubWindowsProcess: # Additional Connector ID
+ uses: WindowsProcess # ID of the connector to customize.
+ force: true # true by default
+ variables:
+ processName: 'metricshub.exe'
+
```
+If a connector with variables is forced or configured under `additionalConnectors` section but without variables, this latter will still be used with default connector variables that are defined in the connector under `defaultVariables` section.
+
+If `uses` is not specified, MetricsHub will deduce that the additional connectorId is the connectorId.
+
#### Discovery cycle
**MetricsHub** periodically performs discoveries to detect new components in your monitored environment. By default, **MetricsHub** runs a discovery after 30 collects. To change this default discovery cycle:
diff --git a/metricshub-linux/src/main/resources/jpackage/metricshub/config/metricshub-example.yaml b/metricshub-linux/src/main/resources/jpackage/metricshub/config/metricshub-example.yaml
index 4ff3ba3da..e24c506bd 100644
--- a/metricshub-linux/src/main/resources/jpackage/metricshub/config/metricshub-example.yaml
+++ b/metricshub-linux/src/main/resources/jpackage/metricshub/config/metricshub-example.yaml
@@ -199,6 +199,13 @@ resourceGroups:
# username: myusername
# password: mypwd
# privateKey: /tmp/ssh-key.txt
+ # additionalConnectors:
+ # ConnectorId:
+ # uses: LinuxProcess
+ # force: true
+ # variables:
+ # var1: value1
+ # var2: value2
#═══════════════════════════════════════════════════
# OSCommand configuration
diff --git a/metricshub-windows/src/main/resources/jpackage/MetricsHub/config/metricshub-example.yaml b/metricshub-windows/src/main/resources/jpackage/MetricsHub/config/metricshub-example.yaml
index 65a39fb9e..e81086467 100644
--- a/metricshub-windows/src/main/resources/jpackage/MetricsHub/config/metricshub-example.yaml
+++ b/metricshub-windows/src/main/resources/jpackage/MetricsHub/config/metricshub-example.yaml
@@ -116,6 +116,13 @@ resourceGroups:
# username: server-3\username
# password: password
# timeout: 120
+ # additionalConnectors:
+ # ConnectorId:
+ # uses: WindowsService
+ # force: true
+ # variables:
+ # var1: value1
+ # var2: value2
#═══════════════════════════════════════════════════
# SNMP v1 protocol configuration