diff --git a/CHANGELOG.md b/CHANGELOG.md index 9aada4ab95379..204b30483f313 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -96,6 +96,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Support to clear filecache using clear indices cache API ([#7498](https://github.com/opensearch-project/OpenSearch/pull/7498)) - Create NamedRoute to map extension routes to a shortened name ([#6870](https://github.com/opensearch-project/OpenSearch/pull/6870)) - Added @dbwiddis as on OpenSearch maintainer ([#7665](https://github.com/opensearch-project/OpenSearch/pull/7665)) +- [Extensions] Add ExtensionAwarePlugin extension point to add custom settings for extensions ([#7526](https://github.com/opensearch-project/OpenSearch/pull/7526)) ### Dependencies - Bump `com.netflix.nebula:gradle-info-plugin` from 12.0.0 to 12.1.3 (#7564) diff --git a/server/src/main/java/org/opensearch/common/settings/Setting.java b/server/src/main/java/org/opensearch/common/settings/Setting.java index a0cdf35ee0ad2..32a6686398a2a 100644 --- a/server/src/main/java/org/opensearch/common/settings/Setting.java +++ b/server/src/main/java/org/opensearch/common/settings/Setting.java @@ -132,6 +132,11 @@ public enum Property { */ Deprecated, + /** + * Extension scope + */ + ExtensionScope, + /** * Node scope */ diff --git a/server/src/main/java/org/opensearch/extensions/ExtensionScopedSettings.java b/server/src/main/java/org/opensearch/extensions/ExtensionScopedSettings.java new file mode 100644 index 0000000000000..0c87ce31df737 --- /dev/null +++ b/server/src/main/java/org/opensearch/extensions/ExtensionScopedSettings.java @@ -0,0 +1,34 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.extensions; + +import org.opensearch.common.settings.AbstractScopedSettings; +import org.opensearch.common.settings.Setting; +import org.opensearch.common.settings.Setting.Property; +import org.opensearch.common.settings.SettingUpgrader; +import org.opensearch.common.settings.Settings; + +import java.util.Collections; +import java.util.Set; + +/** + * Encapsulates all valid extension level settings. + * + * @opensearch.internal + */ +public final class ExtensionScopedSettings extends AbstractScopedSettings { + + public ExtensionScopedSettings(final Set> settingsSet) { + this(settingsSet, Collections.emptySet()); + } + + public ExtensionScopedSettings(final Set> settingsSet, final Set> settingUpgraders) { + super(Settings.EMPTY, settingsSet, settingUpgraders, Property.ExtensionScope); + } +} diff --git a/server/src/main/java/org/opensearch/extensions/ExtensionsManager.java b/server/src/main/java/org/opensearch/extensions/ExtensionsManager.java index 2878aa047c667..9d74e8f22d2b1 100644 --- a/server/src/main/java/org/opensearch/extensions/ExtensionsManager.java +++ b/server/src/main/java/org/opensearch/extensions/ExtensionsManager.java @@ -16,9 +16,11 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import java.util.concurrent.TimeUnit; @@ -37,6 +39,7 @@ import org.opensearch.client.node.NodeClient; import org.opensearch.cluster.ClusterSettingsResponse; import org.opensearch.cluster.service.ClusterService; +import org.opensearch.common.settings.Setting; import org.opensearch.core.util.FileSystemUtils; import org.opensearch.common.io.stream.StreamInput; import org.opensearch.common.settings.Settings; @@ -106,6 +109,7 @@ public static enum OpenSearchRequestType { private CustomSettingsRequestHandler customSettingsRequestHandler; private TransportService transportService; private ClusterService clusterService; + private final Set> additionalSettings; private Settings environmentSettings; private AddSettingsUpdateConsumerRequestHandler addSettingsUpdateConsumerRequestHandler; private NodeClient client; @@ -114,9 +118,10 @@ public static enum OpenSearchRequestType { * Instantiate a new ExtensionsManager object to handle requests and responses from extensions. This is called during Node bootstrap. * * @param extensionsPath Path to a directory containing extensions. + * @param additionalSettings Additional settings to read in from extensions.yml * @throws IOException If the extensions discovery file is not properly retrieved. */ - public ExtensionsManager(Path extensionsPath) throws IOException { + public ExtensionsManager(Path extensionsPath, Set> additionalSettings) throws IOException { logger.info("ExtensionsManager initialized"); this.extensionsPath = extensionsPath; this.initializedExtensions = new HashMap(); @@ -125,6 +130,11 @@ public ExtensionsManager(Path extensionsPath) throws IOException { // will be initialized in initializeServicesAndRestHandler which is called after the Node is initialized this.transportService = null; this.clusterService = null; + // Settings added to extensions.yml by ExtensionAwarePlugins, such as security settings + this.additionalSettings = new HashSet<>(); + if (additionalSettings != null) { + this.additionalSettings.addAll(additionalSettings); + } this.client = null; this.extensionTransportActionsHandler = null; @@ -466,6 +476,7 @@ private ExtensionsSettings readFromExtensionsYml(Path filePath) throws IOExcepti } List> unreadExtensions = new ArrayList<>((Collection>) obj.get("extensions")); List readExtensions = new ArrayList(); + Set additionalSettingsKeys = additionalSettings.stream().map(s -> s.getKey()).collect(Collectors.toSet()); for (HashMap extensionMap : unreadExtensions) { try { // checking to see whether any required fields are missing from extension.yml file or not @@ -500,6 +511,16 @@ private ExtensionsSettings readFromExtensionsYml(Path filePath) throws IOExcepti } } + ExtensionScopedSettings extAdditionalSettings = new ExtensionScopedSettings(additionalSettings); + Map additionalSettingsMap = extensionMap.entrySet() + .stream() + .filter(kv -> additionalSettingsKeys.contains(kv.getKey())) + .collect(Collectors.toMap(map -> map.getKey(), map -> map.getValue())); + + Settings.Builder output = Settings.builder(); + output.loadFromMap(additionalSettingsMap); + extAdditionalSettings.applySettings(output.build()); + // Create extension read from yml config readExtensions.add( new Extension( @@ -510,7 +531,8 @@ private ExtensionsSettings readFromExtensionsYml(Path filePath) throws IOExcepti extensionMap.get("version").toString(), extensionMap.get("opensearchVersion").toString(), extensionMap.get("minimumCompatibleVersion").toString(), - extensionDependencyList + extensionDependencyList, + extAdditionalSettings ) ); } catch (IOException e) { diff --git a/server/src/main/java/org/opensearch/extensions/ExtensionsSettings.java b/server/src/main/java/org/opensearch/extensions/ExtensionsSettings.java index fd11aec973d42..9d21469c8fa28 100644 --- a/server/src/main/java/org/opensearch/extensions/ExtensionsSettings.java +++ b/server/src/main/java/org/opensearch/extensions/ExtensionsSettings.java @@ -44,6 +44,7 @@ public static class Extension { private String opensearchVersion; private String minimumCompatibleVersion; private List dependencies = Collections.emptyList(); + private ExtensionScopedSettings additionalSettings; public Extension( String name, @@ -53,7 +54,8 @@ public Extension( String version, String opensearchVersion, String minimumCompatibleVersion, - List dependencies + List dependencies, + ExtensionScopedSettings additionalSettings ) { this.name = name; this.uniqueId = uniqueId; @@ -63,6 +65,7 @@ public Extension( this.opensearchVersion = opensearchVersion; this.minimumCompatibleVersion = minimumCompatibleVersion; this.dependencies = dependencies; + this.additionalSettings = additionalSettings; } public Extension() { @@ -127,6 +130,10 @@ public List getDependencies() { return dependencies; } + public ExtensionScopedSettings getAdditionalSettings() { + return additionalSettings; + } + public String getMinimumCompatibleVersion() { return minimumCompatibleVersion; } diff --git a/server/src/main/java/org/opensearch/extensions/NoopExtensionsManager.java b/server/src/main/java/org/opensearch/extensions/NoopExtensionsManager.java index eb9b389b7a4b1..fb7160bc1bc67 100644 --- a/server/src/main/java/org/opensearch/extensions/NoopExtensionsManager.java +++ b/server/src/main/java/org/opensearch/extensions/NoopExtensionsManager.java @@ -11,6 +11,7 @@ import java.io.IOException; import java.nio.file.Path; import java.util.Optional; +import java.util.Set; import org.opensearch.action.ActionModule; import org.opensearch.client.node.NodeClient; @@ -31,7 +32,7 @@ public class NoopExtensionsManager extends ExtensionsManager { public NoopExtensionsManager() throws IOException { - super(Path.of("")); + super(Path.of(""), Set.of()); } @Override diff --git a/server/src/main/java/org/opensearch/node/Node.java b/server/src/main/java/org/opensearch/node/Node.java index 316622717c9f9..a25bac60f49b6 100644 --- a/server/src/main/java/org/opensearch/node/Node.java +++ b/server/src/main/java/org/opensearch/node/Node.java @@ -54,6 +54,7 @@ import org.opensearch.extensions.NoopExtensionsManager; import org.opensearch.monitor.fs.FsInfo; import org.opensearch.monitor.fs.FsProbe; +import org.opensearch.plugins.ExtensionAwarePlugin; import org.opensearch.plugins.SearchPipelinePlugin; import org.opensearch.search.backpressure.SearchBackpressureService; import org.opensearch.search.backpressure.settings.SearchBackpressureSettings; @@ -234,6 +235,7 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; @@ -466,7 +468,12 @@ protected Node( final IdentityService identityService = new IdentityService(settings, identityPlugins); if (FeatureFlags.isEnabled(FeatureFlags.EXTENSIONS)) { - this.extensionsManager = new ExtensionsManager(initialEnvironment.extensionDir()); + final List extensionAwarePlugins = pluginsService.filterPlugins(ExtensionAwarePlugin.class); + Set> additionalSettings = new HashSet<>(); + for (ExtensionAwarePlugin extAwarePlugin : extensionAwarePlugins) { + additionalSettings.addAll(extAwarePlugin.getExtensionSettings()); + } + this.extensionsManager = new ExtensionsManager(initialEnvironment.extensionDir(), additionalSettings); } else { this.extensionsManager = new NoopExtensionsManager(); } diff --git a/server/src/main/java/org/opensearch/plugins/ExtensionAwarePlugin.java b/server/src/main/java/org/opensearch/plugins/ExtensionAwarePlugin.java new file mode 100644 index 0000000000000..c8426bc964287 --- /dev/null +++ b/server/src/main/java/org/opensearch/plugins/ExtensionAwarePlugin.java @@ -0,0 +1,29 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugins; + +import org.opensearch.common.settings.Setting; + +import java.util.Collections; +import java.util.List; + +/** + * Plugin that provides extra settings for extensions + * + * @opensearch.experimental + */ +public interface ExtensionAwarePlugin { + + /** + * Returns a list of additional {@link Setting} definitions that this plugin adds for extensions + */ + default List> getExtensionSettings() { + return Collections.emptyList(); + } +} diff --git a/server/src/main/java/org/opensearch/plugins/IdentityPlugin.java b/server/src/main/java/org/opensearch/plugins/IdentityPlugin.java index 4cb15f4ab3cbe..511b5595c5328 100644 --- a/server/src/main/java/org/opensearch/plugins/IdentityPlugin.java +++ b/server/src/main/java/org/opensearch/plugins/IdentityPlugin.java @@ -22,5 +22,5 @@ public interface IdentityPlugin { * * Should never return null * */ - public Subject getSubject(); + Subject getSubject(); } diff --git a/server/src/test/java/org/opensearch/extensions/ExtensionsManagerTests.java b/server/src/test/java/org/opensearch/extensions/ExtensionsManagerTests.java index 42a050270466d..75a1d9ec62c82 100644 --- a/server/src/test/java/org/opensearch/extensions/ExtensionsManagerTests.java +++ b/server/src/test/java/org/opensearch/extensions/ExtensionsManagerTests.java @@ -32,6 +32,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -70,6 +71,7 @@ import org.opensearch.extensions.settings.RegisterCustomSettingsRequest; import org.opensearch.identity.IdentityService; import org.opensearch.indices.breaker.NoneCircuitBreakerService; +import org.opensearch.plugins.ExtensionAwarePlugin; import org.opensearch.rest.RestController; import org.opensearch.test.FeatureFlagSetter; import org.opensearch.test.MockLogAppender; @@ -91,6 +93,8 @@ public class ExtensionsManagerTests extends OpenSearchTestCase { private RestController restController; private SettingsModule settingsModule; private ClusterService clusterService; + private ExtensionAwarePlugin extAwarePlugin; + private Setting customSetting = Setting.simpleString("custom_extension_setting", "none", Property.ExtensionScope); private NodeClient client; private MockNioTransport transport; private Path extensionDir; @@ -108,6 +112,7 @@ public class ExtensionsManagerTests extends OpenSearchTestCase { " version: '0.0.7'", " opensearchVersion: '3.0.0'", " minimumCompatibleVersion: '3.0.0'", + " custom_extension_setting: 'custom_setting'", " - name: secondExtension", " uniqueId: 'uniqueid2'", " hostAddress: '127.0.0.1'", @@ -152,6 +157,15 @@ public void setup() throws Exception { Collections.emptySet() ); actionModule = mock(ActionModule.class); + extAwarePlugin = new ExtensionAwarePlugin() { + + @Override + public List> getExtensionSettings() { + List> settings = new ArrayList>(); + settings.add(customSetting); + return settings; + } + }; dynamicActionRegistry = mock(DynamicActionRegistry.class); restController = new RestController( emptySet(), @@ -192,7 +206,7 @@ public void tearDown() throws Exception { public void testDiscover() throws Exception { Files.write(extensionDir.resolve("extensions.yml"), extensionsYmlLines, StandardCharsets.UTF_8); - ExtensionsManager extensionsManager = new ExtensionsManager(extensionDir); + ExtensionsManager extensionsManager = new ExtensionsManager(extensionDir, Set.of()); List expectedExtensions = new ArrayList(); @@ -245,7 +259,7 @@ public void testNonUniqueExtensionsDiscovery() throws Exception { .collect(Collectors.toList()); Files.write(emptyExtensionDir.resolve("extensions.yml"), nonUniqueYmlLines, StandardCharsets.UTF_8); - ExtensionsManager extensionsManager = new ExtensionsManager(emptyExtensionDir); + ExtensionsManager extensionsManager = new ExtensionsManager(emptyExtensionDir, Set.of()); List expectedExtensions = new ArrayList(); @@ -294,7 +308,7 @@ public void testMissingRequiredFieldsInExtensionDiscovery() throws Exception { ) ); - extensionsManager = new ExtensionsManager(emptyExtensionDir); + extensionsManager = new ExtensionsManager(emptyExtensionDir, Set.of()); mockLogAppender.assertAllExpectationsMatched(); } @@ -379,7 +393,7 @@ public void testNonAccessibleDirectory() throws Exception { AccessControlException e = expectThrows( AccessControlException.class, - () -> new ExtensionsManager(PathUtils.get("")) + () -> new ExtensionsManager(PathUtils.get(""), Set.of()) ); assertEquals("access denied (\"java.io.FilePermission\" \"\" \"read\")", e.getMessage()); } @@ -398,7 +412,7 @@ public void testNoExtensionsFile() throws Exception { ) ); - new ExtensionsManager(extensionDir); + new ExtensionsManager(extensionDir, Set.of()); mockLogAppender.assertAllExpectationsMatched(); } @@ -412,12 +426,12 @@ public void testEmptyExtensionsFile() throws Exception { Settings settings = Settings.builder().build(); - expectThrows(IOException.class, () -> new ExtensionsManager(emptyExtensionDir)); + expectThrows(IOException.class, () -> new ExtensionsManager(emptyExtensionDir, Set.of())); } public void testInitialize() throws Exception { Files.write(extensionDir.resolve("extensions.yml"), extensionsYmlLines, StandardCharsets.UTF_8); - ExtensionsManager extensionsManager = new ExtensionsManager(extensionDir); + ExtensionsManager extensionsManager = new ExtensionsManager(extensionDir, Set.of()); initialize(extensionsManager); @@ -460,7 +474,7 @@ public void testInitialize() throws Exception { public void testHandleRegisterRestActionsRequest() throws Exception { Files.write(extensionDir.resolve("extensions.yml"), extensionsYmlLines, StandardCharsets.UTF_8); - ExtensionsManager extensionsManager = new ExtensionsManager(extensionDir); + ExtensionsManager extensionsManager = new ExtensionsManager(extensionDir, Set.of()); initialize(extensionsManager); String uniqueIdStr = "uniqueid1"; @@ -475,7 +489,7 @@ public void testHandleRegisterRestActionsRequest() throws Exception { public void testHandleRegisterSettingsRequest() throws Exception { Files.write(extensionDir.resolve("extensions.yml"), extensionsYmlLines, StandardCharsets.UTF_8); - ExtensionsManager extensionsManager = new ExtensionsManager(extensionDir); + ExtensionsManager extensionsManager = new ExtensionsManager(extensionDir, Set.of()); initialize(extensionsManager); String uniqueIdStr = "uniqueid1"; @@ -491,7 +505,7 @@ public void testHandleRegisterSettingsRequest() throws Exception { } public void testHandleRegisterRestActionsRequestWithInvalidMethod() throws Exception { - ExtensionsManager extensionsManager = new ExtensionsManager(extensionDir); + ExtensionsManager extensionsManager = new ExtensionsManager(extensionDir, Set.of()); initialize(extensionsManager); String uniqueIdStr = "uniqueid1"; @@ -506,7 +520,7 @@ public void testHandleRegisterRestActionsRequestWithInvalidMethod() throws Excep } public void testHandleRegisterRestActionsRequestWithInvalidDeprecatedMethod() throws Exception { - ExtensionsManager extensionsManager = new ExtensionsManager(extensionDir); + ExtensionsManager extensionsManager = new ExtensionsManager(extensionDir, Set.of()); initialize(extensionsManager); String uniqueIdStr = "uniqueid1"; @@ -521,7 +535,7 @@ public void testHandleRegisterRestActionsRequestWithInvalidDeprecatedMethod() th } public void testHandleRegisterRestActionsRequestWithInvalidUri() throws Exception { - ExtensionsManager extensionsManager = new ExtensionsManager(extensionDir); + ExtensionsManager extensionsManager = new ExtensionsManager(extensionDir, Set.of()); initialize(extensionsManager); String uniqueIdStr = "uniqueid1"; List actionsList = List.of("GET", "PUT /bar", "POST /baz"); @@ -535,7 +549,7 @@ public void testHandleRegisterRestActionsRequestWithInvalidUri() throws Exceptio } public void testHandleRegisterRestActionsRequestWithInvalidDeprecatedUri() throws Exception { - ExtensionsManager extensionsManager = new ExtensionsManager(extensionDir); + ExtensionsManager extensionsManager = new ExtensionsManager(extensionDir, Set.of()); initialize(extensionsManager); String uniqueIdStr = "uniqueid1"; List actionsList = List.of("GET /foo", "PUT /bar", "POST /baz"); @@ -549,7 +563,7 @@ public void testHandleRegisterRestActionsRequestWithInvalidDeprecatedUri() throw } public void testHandleExtensionRequest() throws Exception { - ExtensionsManager extensionsManager = new ExtensionsManager(extensionDir); + ExtensionsManager extensionsManager = new ExtensionsManager(extensionDir, Set.of()); initialize(extensionsManager); ExtensionRequest clusterStateRequest = new ExtensionRequest(ExtensionRequestProto.RequestType.REQUEST_EXTENSION_CLUSTER_STATE); @@ -705,7 +719,7 @@ public void testEnvironmentSettingsDefaultValue() throws Exception { public void testAddSettingsUpdateConsumerRequest() throws Exception { Path extensionDir = createTempDir(); Files.write(extensionDir.resolve("extensions.yml"), extensionsYmlLines, StandardCharsets.UTF_8); - ExtensionsManager extensionsManager = new ExtensionsManager(extensionDir); + ExtensionsManager extensionsManager = new ExtensionsManager(extensionDir, Set.of()); initialize(extensionsManager); List> componentSettings = List.of( @@ -752,7 +766,7 @@ public void testHandleAddSettingsUpdateConsumerRequest() throws Exception { Path extensionDir = createTempDir(); Files.write(extensionDir.resolve("extensions.yml"), extensionsYmlLines, StandardCharsets.UTF_8); - ExtensionsManager extensionsManager = new ExtensionsManager(extensionDir); + ExtensionsManager extensionsManager = new ExtensionsManager(extensionDir, Set.of()); initialize(extensionsManager); List> componentSettings = List.of( @@ -774,7 +788,7 @@ public void testHandleAddSettingsUpdateConsumerRequest() throws Exception { public void testUpdateSettingsRequest() throws Exception { Path extensionDir = createTempDir(); Files.write(extensionDir.resolve("extensions.yml"), extensionsYmlLines, StandardCharsets.UTF_8); - ExtensionsManager extensionsManager = new ExtensionsManager(extensionDir); + ExtensionsManager extensionsManager = new ExtensionsManager(extensionDir, Set.of()); initialize(extensionsManager); Setting componentSetting = Setting.boolSetting("falseSetting", false, Property.Dynamic); @@ -803,7 +817,7 @@ public void testUpdateSettingsRequest() throws Exception { public void testRegisterHandler() throws Exception { - ExtensionsManager extensionsManager = new ExtensionsManager(extensionDir); + ExtensionsManager extensionsManager = new ExtensionsManager(extensionDir, Set.of()); TransportService mockTransportService = spy( new TransportService( @@ -853,12 +867,64 @@ public void testIncompatibleExtensionRegistration() throws IOException, IllegalA ); Files.write(extensionDir.resolve("extensions.yml"), incompatibleExtension, StandardCharsets.UTF_8); - ExtensionsManager extensionsManager = new ExtensionsManager(extensionDir); + ExtensionsManager extensionsManager = new ExtensionsManager(extensionDir, Set.of()); assertEquals(0, extensionsManager.getExtensionIdMap().values().size()); mockLogAppender.assertAllExpectationsMatched(); } } + public void testAdditionalExtensionSettingsForExtensionWithCustomSettingSet() throws Exception { + Files.write(extensionDir.resolve("extensions.yml"), extensionsYmlLines, StandardCharsets.UTF_8); + + Set> additionalSettings = extAwarePlugin.getExtensionSettings().stream().collect(Collectors.toSet()); + + ExtensionsManager extensionsManager = new ExtensionsManager(extensionDir, additionalSettings); + + DiscoveryExtensionNode extension = new DiscoveryExtensionNode( + "firstExtension", + "uniqueid1", + new TransportAddress(InetAddress.getByName("127.0.0.1"), 9300), + new HashMap(), + Version.fromString("3.0.0"), + Version.fromString("3.0.0"), + List.of() + ); + DiscoveryExtensionNode initializedExtension = extensionsManager.getExtensionIdMap().get(extension.getId()); + assertEquals(extension.getName(), initializedExtension.getName()); + assertEquals(extension.getId(), initializedExtension.getId()); + assertTrue(extensionsManager.lookupExtensionSettingsById(extension.getId()).isPresent()); + assertEquals( + "custom_setting", + extensionsManager.lookupExtensionSettingsById(extension.getId()).get().getAdditionalSettings().get(customSetting) + ); + } + + public void testAdditionalExtensionSettingsForExtensionWithoutCustomSettingSet() throws Exception { + Files.write(extensionDir.resolve("extensions.yml"), extensionsYmlLines, StandardCharsets.UTF_8); + + Set> additionalSettings = extAwarePlugin.getExtensionSettings().stream().collect(Collectors.toSet()); + + ExtensionsManager extensionsManager = new ExtensionsManager(extensionDir, additionalSettings); + + DiscoveryExtensionNode extension = new DiscoveryExtensionNode( + "secondExtension", + "uniqueid2", + new TransportAddress(InetAddress.getByName("127.0.0.1"), 9301), + new HashMap(), + Version.fromString("2.0.0"), + Version.fromString("2.0.0"), + List.of() + ); + DiscoveryExtensionNode initializedExtension = extensionsManager.getExtensionIdMap().get(extension.getId()); + assertEquals(extension.getName(), initializedExtension.getName()); + assertEquals(extension.getId(), initializedExtension.getId()); + assertTrue(extensionsManager.lookupExtensionSettingsById(extension.getId()).isPresent()); + assertEquals( + "none", + extensionsManager.lookupExtensionSettingsById(extension.getId()).get().getAdditionalSettings().get(customSetting) + ); + } + private void initialize(ExtensionsManager extensionsManager) { transportService.start(); transportService.acceptIncomingRequests();