From 19e54d662488a183c1388e66cfe7463a24c6aa7c Mon Sep 17 00:00:00 2001 From: Vacha Date: Wed, 21 Jul 2021 15:58:49 -0700 Subject: [PATCH] Allowing custom folder name for plugin installation (#848) Signed-off-by: Vacha Shah --- .../gradle/plugin/PluginBuildPlugin.groovy | 1 + .../plugin/PluginPropertiesExtension.java | 10 ++++ .../resources/plugin-descriptor.properties | 3 + .../plugins/InstallPluginCommand.java | 13 +++-- .../plugins/ListPluginsCommand.java | 2 +- .../org/opensearch/plugins/PluginHelper.java | 43 ++++++++++++++ .../plugins/RemovePluginCommand.java | 17 +++++- .../plugins/InstallPluginCommandTests.java | 19 ++++++ .../plugins/ListPluginsCommandTests.java | 12 +++- .../plugins/RemovePluginCommandTests.java | 58 ++++++++++++------- .../org/opensearch/plugins/PluginInfo.java | 49 +++++++++++++++- .../opensearch/plugins/PluginsService.java | 2 +- .../nodesinfo/NodeInfoStreamingTests.java | 10 ++-- .../opensearch/plugins/PluginInfoTests.java | 50 ++++++++++++++-- .../plugins/PluginsServiceTests.java | 55 +++++++++--------- 15 files changed, 269 insertions(+), 75 deletions(-) create mode 100644 distribution/tools/plugin-cli/src/main/java/org/opensearch/plugins/PluginHelper.java diff --git a/buildSrc/src/main/groovy/org/opensearch/gradle/plugin/PluginBuildPlugin.groovy b/buildSrc/src/main/groovy/org/opensearch/gradle/plugin/PluginBuildPlugin.groovy index e07d4800ad7..d69972a25b2 100644 --- a/buildSrc/src/main/groovy/org/opensearch/gradle/plugin/PluginBuildPlugin.groovy +++ b/buildSrc/src/main/groovy/org/opensearch/gradle/plugin/PluginBuildPlugin.groovy @@ -105,6 +105,7 @@ class PluginBuildPlugin implements Plugin { 'opensearchVersion' : Version.fromString(VersionProperties.getOpenSearch()).toString(), 'javaVersion' : project.targetCompatibility as String, 'classname' : extension1.classname, + 'customFolderName' : extension1.customFolderName, 'extendedPlugins' : extension1.extendedPlugins.join(','), 'hasNativeController' : extension1.hasNativeController, 'requiresKeystore' : extension1.requiresKeystore diff --git a/buildSrc/src/main/java/org/opensearch/gradle/plugin/PluginPropertiesExtension.java b/buildSrc/src/main/java/org/opensearch/gradle/plugin/PluginPropertiesExtension.java index a9227813a08..d6117923973 100644 --- a/buildSrc/src/main/java/org/opensearch/gradle/plugin/PluginPropertiesExtension.java +++ b/buildSrc/src/main/java/org/opensearch/gradle/plugin/PluginPropertiesExtension.java @@ -51,6 +51,8 @@ public class PluginPropertiesExtension { private String classname; + private String customFolderName = ""; + /** Other plugins this plugin extends through SPI */ private List extendedPlugins = new ArrayList<>(); @@ -76,6 +78,14 @@ public class PluginPropertiesExtension { this.project = project; } + public String getCustomFolderName() { + return customFolderName; + } + + public void setCustomFolderName(String customFolderName) { + this.customFolderName = customFolderName; + } + public String getName() { return name == null ? project.getName() : name; } diff --git a/buildSrc/src/main/resources/plugin-descriptor.properties b/buildSrc/src/main/resources/plugin-descriptor.properties index 110b5228526..ce1803bdb67 100644 --- a/buildSrc/src/main/resources/plugin-descriptor.properties +++ b/buildSrc/src/main/resources/plugin-descriptor.properties @@ -49,6 +49,9 @@ java.version=${javaVersion} opensearch.version=${opensearchVersion} ### optional elements for plugins: # +# 'custom.foldername': the custom name of the folder in which the plugin is installed. +custom.foldername=${customFolderName} +# # 'extended.plugins': other plugins this plugin extends through SPI extended.plugins=${extendedPlugins} # diff --git a/distribution/tools/plugin-cli/src/main/java/org/opensearch/plugins/InstallPluginCommand.java b/distribution/tools/plugin-cli/src/main/java/org/opensearch/plugins/InstallPluginCommand.java index 3fb11680200..0f9ff212609 100644 --- a/distribution/tools/plugin-cli/src/main/java/org/opensearch/plugins/InstallPluginCommand.java +++ b/distribution/tools/plugin-cli/src/main/java/org/opensearch/plugins/InstallPluginCommand.java @@ -261,7 +261,7 @@ class InstallPluginCommand extends EnvironmentAwareCommand { final Path extractedZip = unzip(pluginZip, env.pluginsFile()); deleteOnFailure.add(extractedZip); final PluginInfo pluginInfo = installPlugin(terminal, isBatch, extractedZip, env, deleteOnFailure); - terminal.println("-> Installed " + pluginInfo.getName()); + terminal.println("-> Installed " + pluginInfo.getName() + " with folder name " + pluginInfo.getTargetFolderName()); // swap the entry by plugin id for one with the installed plugin name, it gives a cleaner error message for URL installs deleteOnFailures.remove(pluginId); deleteOnFailures.put(pluginInfo.getName(), deleteOnFailure); @@ -780,7 +780,9 @@ class InstallPluginCommand extends EnvironmentAwareCommand { throw new UserException(ExitCodes.USAGE, "plugin '" + pluginName + "' cannot be installed as a plugin, it is a system module"); } - final Path destination = pluginPath.resolve(pluginName); + // scan all the installed plugins to see if the plugin being installed already exists + // either with the plugin name or a custom folder name + Path destination = PluginHelper.verifyIfPluginExists(pluginPath, pluginName); if (Files.exists(destination)) { final String message = String.format( Locale.ROOT, @@ -864,14 +866,15 @@ class InstallPluginCommand extends EnvironmentAwareCommand { } PluginSecurity.confirmPolicyExceptions(terminal, permissions, isBatch); - final Path destination = env.pluginsFile().resolve(info.getName()); + String targetFolderName = info.getTargetFolderName(); + final Path destination = env.pluginsFile().resolve(targetFolderName); deleteOnFailure.add(destination); installPluginSupportFiles( info, tmpRoot, - env.binFile().resolve(info.getName()), - env.configFile().resolve(info.getName()), + env.binFile().resolve(targetFolderName), + env.configFile().resolve(targetFolderName), deleteOnFailure ); movePlugin(tmpRoot, destination); diff --git a/distribution/tools/plugin-cli/src/main/java/org/opensearch/plugins/ListPluginsCommand.java b/distribution/tools/plugin-cli/src/main/java/org/opensearch/plugins/ListPluginsCommand.java index 172388c1409..ecf702c4675 100644 --- a/distribution/tools/plugin-cli/src/main/java/org/opensearch/plugins/ListPluginsCommand.java +++ b/distribution/tools/plugin-cli/src/main/java/org/opensearch/plugins/ListPluginsCommand.java @@ -75,8 +75,8 @@ class ListPluginsCommand extends EnvironmentAwareCommand { } private void printPlugin(Environment env, Terminal terminal, Path plugin, String prefix) throws IOException { - terminal.println(Terminal.Verbosity.SILENT, prefix + plugin.getFileName().toString()); PluginInfo info = PluginInfo.readFromProperties(env.pluginsFile().resolve(plugin)); + terminal.println(Terminal.Verbosity.SILENT, prefix + info.getName()); terminal.println(Terminal.Verbosity.VERBOSE, info.toString(prefix)); if (info.getOpenSearchVersion().equals(Version.CURRENT) == false) { terminal.errorPrintln( diff --git a/distribution/tools/plugin-cli/src/main/java/org/opensearch/plugins/PluginHelper.java b/distribution/tools/plugin-cli/src/main/java/org/opensearch/plugins/PluginHelper.java new file mode 100644 index 00000000000..1ef4dd9a36d --- /dev/null +++ b/distribution/tools/plugin-cli/src/main/java/org/opensearch/plugins/PluginHelper.java @@ -0,0 +1,43 @@ +/* + * 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 java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.stream.Collectors; + +/** + * A helper class for the plugin-cli tasks. + */ +public class PluginHelper { + + /** + * Verify if a plugin exists with any folder name. + * @param pluginPath the path for the plugins directory. + * @param pluginName the name of the concerned plugin. + * @return the path of the folder if the plugin exists. + * @throws IOException if any I/O exception occurs while performing a file operation + */ + public static Path verifyIfPluginExists(Path pluginPath, String pluginName) throws IOException { + List pluginSubFolders = Files.walk(pluginPath, 1).filter(Files::isDirectory).collect(Collectors.toList()); + for (Path customPluginFolderPath : pluginSubFolders) { + if (customPluginFolderPath != pluginPath + && !((customPluginFolderPath.getFileName().toString()).contains(".installing")) + && !((customPluginFolderPath.getFileName().toString()).contains(".removing"))) { + final PluginInfo info = PluginInfo.readFromProperties(customPluginFolderPath); + if (info.getName().equals(pluginName)) { + return customPluginFolderPath; + } + } + } + return pluginPath.resolve(pluginName); + } +} diff --git a/distribution/tools/plugin-cli/src/main/java/org/opensearch/plugins/RemovePluginCommand.java b/distribution/tools/plugin-cli/src/main/java/org/opensearch/plugins/RemovePluginCommand.java index c993257baea..fb567e6609b 100644 --- a/distribution/tools/plugin-cli/src/main/java/org/opensearch/plugins/RemovePluginCommand.java +++ b/distribution/tools/plugin-cli/src/main/java/org/opensearch/plugins/RemovePluginCommand.java @@ -114,9 +114,20 @@ class RemovePluginCommand extends EnvironmentAwareCommand { ); } - final Path pluginDir = env.pluginsFile().resolve(pluginName); - final Path pluginConfigDir = env.configFile().resolve(pluginName); - final Path removing = env.pluginsFile().resolve(".removing-" + pluginName); + Path pluginDir = env.pluginsFile().resolve(pluginName); + Path pluginConfigDir = env.configFile().resolve(pluginName); + Path removing = env.pluginsFile().resolve(".removing-" + pluginName); + + /* + * If the plugin directory is not found with the plugin name, scan the list of all installed plugins + * to find if the concerned plugin is installed with a custom folder name. + */ + if (!Files.exists(pluginDir)) { + terminal.println("searching in other folders to find if plugin exists with custom folder name"); + pluginDir = PluginHelper.verifyIfPluginExists(env.pluginsFile(), pluginName); + pluginConfigDir = env.configFile().resolve(pluginDir.getFileName()); + removing = env.pluginsFile().resolve(".removing-" + pluginDir.getFileName()); + } terminal.println("-> removing [" + pluginName + "]..."); /* diff --git a/distribution/tools/plugin-cli/src/test/java/org/opensearch/plugins/InstallPluginCommandTests.java b/distribution/tools/plugin-cli/src/test/java/org/opensearch/plugins/InstallPluginCommandTests.java index 4147fbe9626..7c462481292 100644 --- a/distribution/tools/plugin-cli/src/test/java/org/opensearch/plugins/InstallPluginCommandTests.java +++ b/distribution/tools/plugin-cli/src/test/java/org/opensearch/plugins/InstallPluginCommandTests.java @@ -576,6 +576,17 @@ public class InstallPluginCommandTests extends OpenSearchTestCase { assertInstallCleaned(env.v2()); } + public void testExistingPluginWithCustomFolderName() throws Exception { + Tuple env = createEnv(fs, temp); + Path pluginDir = createPluginDir(temp); + String pluginZip = createPluginUrl("fake", pluginDir, "custom.foldername", "fake-folder"); + installPlugin(pluginZip, env.v1()); + assertPlugin("fake-folder", pluginDir, env.v2()); + UserException e = expectThrows(UserException.class, () -> installPlugin(pluginZip, env.v1())); + assertTrue(e.getMessage(), e.getMessage().contains("already exists")); + assertInstallCleaned(env.v2()); + } + public void testBin() throws Exception { Tuple env = createEnv(fs, temp); Path pluginDir = createPluginDir(temp); @@ -873,6 +884,14 @@ public class InstallPluginCommandTests extends OpenSearchTestCase { ); } + public void testPluginInstallationWithCustomFolderName() throws Exception { + Tuple env = createEnv(fs, temp); + Path pluginDir = createPluginDir(temp); + String pluginZip = createPluginUrl("fake", pluginDir, "custom.foldername", "fake-folder"); + installPlugin(pluginZip, env.v1()); + assertPlugin("fake-folder", pluginDir, env.v2()); + } + private void installPlugin(MockTerminal terminal, boolean isBatch) throws Exception { Tuple env = createEnv(fs, temp); Path pluginDir = createPluginDir(temp); diff --git a/distribution/tools/plugin-cli/src/test/java/org/opensearch/plugins/ListPluginsCommandTests.java b/distribution/tools/plugin-cli/src/test/java/org/opensearch/plugins/ListPluginsCommandTests.java index b5a0349ced2..46a439fcbc8 100644 --- a/distribution/tools/plugin-cli/src/test/java/org/opensearch/plugins/ListPluginsCommandTests.java +++ b/distribution/tools/plugin-cli/src/test/java/org/opensearch/plugins/ListPluginsCommandTests.java @@ -124,6 +124,8 @@ public class ListPluginsCommandTests extends OpenSearchTestCase { "1.8", "classname", classname, + "custom.foldername", + "custom-folder", "has.native.controller", Boolean.toString(hasNativeController) ); @@ -169,7 +171,8 @@ public class ListPluginsCommandTests extends OpenSearchTestCase { "Java Version: 1.8", "Native Controller: false", "Extended Plugins: []", - " * Classname: org.fake" + " * Classname: org.fake", + "Folder name: custom-folder" ), terminal.getOutput() ); @@ -191,7 +194,8 @@ public class ListPluginsCommandTests extends OpenSearchTestCase { "Java Version: 1.8", "Native Controller: true", "Extended Plugins: []", - " * Classname: org.fake" + " * Classname: org.fake", + "Folder name: custom-folder" ), terminal.getOutput() ); @@ -215,6 +219,7 @@ public class ListPluginsCommandTests extends OpenSearchTestCase { "Native Controller: false", "Extended Plugins: []", " * Classname: org.fake", + "Folder name: custom-folder", "fake_plugin2", "- Plugin information:", "Name: fake_plugin2", @@ -224,7 +229,8 @@ public class ListPluginsCommandTests extends OpenSearchTestCase { "Java Version: 1.8", "Native Controller: false", "Extended Plugins: []", - " * Classname: org.fake2" + " * Classname: org.fake2", + "Folder name: custom-folder" ), terminal.getOutput() ); diff --git a/distribution/tools/plugin-cli/src/test/java/org/opensearch/plugins/RemovePluginCommandTests.java b/distribution/tools/plugin-cli/src/test/java/org/opensearch/plugins/RemovePluginCommandTests.java index 4edf41f135e..bae64dfcfc4 100644 --- a/distribution/tools/plugin-cli/src/test/java/org/opensearch/plugins/RemovePluginCommandTests.java +++ b/distribution/tools/plugin-cli/src/test/java/org/opensearch/plugins/RemovePluginCommandTests.java @@ -50,7 +50,9 @@ import java.io.StringReader; import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Arrays; import java.util.Map; +import java.util.stream.Stream; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.not; @@ -90,34 +92,34 @@ public class RemovePluginCommandTests extends OpenSearchTestCase { env = TestEnvironment.newEnvironment(settings); } - void createPlugin(String name) throws IOException { - createPlugin(env.pluginsFile(), name); + void createPlugin(String name, String... additionalProps) throws IOException { + createPlugin(env.pluginsFile(), name, Version.CURRENT, additionalProps); } void createPlugin(String name, Version version) throws IOException { createPlugin(env.pluginsFile(), name, version); } - void createPlugin(Path path, String name) throws IOException { - createPlugin(path, name, Version.CURRENT); - } - - void createPlugin(Path path, String name, Version version) throws IOException { - PluginTestUtil.writePluginProperties( - path.resolve(name), - "description", - "dummy", - "name", - name, - "version", - "1.0", - "opensearch.version", - version.toString(), - "java.version", - System.getProperty("java.specification.version"), - "classname", - "SomeClass" - ); + void createPlugin(Path path, String name, Version version, String... additionalProps) throws IOException { + String[] properties = Stream.concat( + Stream.of( + "description", + "dummy", + "name", + name, + "version", + "1.0", + "opensearch.version", + version.toString(), + "java.version", + System.getProperty("java.specification.version"), + "classname", + "SomeClass" + ), + Arrays.stream(additionalProps) + ).toArray(String[]::new); + String pluginFolderName = additionalProps.length == 0 ? name : additionalProps[1]; + PluginTestUtil.writePluginProperties(path.resolve(pluginFolderName), properties); } static MockTerminal removePlugin(String name, Path home, boolean purge) throws Exception { @@ -154,6 +156,17 @@ public class RemovePluginCommandTests extends OpenSearchTestCase { assertRemoveCleaned(env); } + public void testRemovePluginWithCustomFolderName() throws Exception { + createPlugin("fake", "custom.foldername", "custom-folder"); + Files.createFile(env.pluginsFile().resolve("custom-folder").resolve("plugin.jar")); + Files.createDirectory(env.pluginsFile().resolve("custom-folder").resolve("subdir")); + createPlugin("other"); + removePlugin("fake", home, randomBoolean()); + assertFalse(Files.exists(env.pluginsFile().resolve("custom-folder"))); + assertTrue(Files.exists(env.pluginsFile().resolve("other"))); + assertRemoveCleaned(env); + } + public void testRemoveOldVersion() throws Exception { createPlugin( "fake", @@ -261,6 +274,7 @@ public class RemovePluginCommandTests extends OpenSearchTestCase { BufferedReader reader = new BufferedReader(new StringReader(terminal.getOutput())); BufferedReader errorReader = new BufferedReader(new StringReader(terminal.getErrorOutput())) ) { + assertEquals("searching in other folders to find if plugin exists with custom folder name", reader.readLine()); assertEquals("-> removing [fake]...", reader.readLine()); assertEquals( "ERROR: plugin [fake] not found; run 'opensearch-plugin list' to get list of installed plugins", diff --git a/server/src/main/java/org/opensearch/plugins/PluginInfo.java b/server/src/main/java/org/opensearch/plugins/PluginInfo.java index 81e300941f0..6382a5f9f21 100644 --- a/server/src/main/java/org/opensearch/plugins/PluginInfo.java +++ b/server/src/main/java/org/opensearch/plugins/PluginInfo.java @@ -69,6 +69,7 @@ public class PluginInfo implements Writeable, ToXContentObject { private final Version opensearchVersion; private final String javaVersion; private final String classname; + private final String customFolderName; private final List extendedPlugins; private final boolean hasNativeController; @@ -81,17 +82,19 @@ public class PluginInfo implements Writeable, ToXContentObject { * @param opensearchVersion the version of OpenSearch the plugin was built for * @param javaVersion the version of Java the plugin was built with * @param classname the entry point to the plugin + * @param customFolderName the custom folder name for the plugin * @param extendedPlugins other plugins this plugin extends through SPI * @param hasNativeController whether or not the plugin has a native controller */ public PluginInfo(String name, String description, String version, Version opensearchVersion, String javaVersion, - String classname, List extendedPlugins, boolean hasNativeController) { + String classname, String customFolderName, List extendedPlugins, boolean hasNativeController) { this.name = name; this.description = description; this.version = version; this.opensearchVersion = opensearchVersion; this.javaVersion = javaVersion; this.classname = classname; + this.customFolderName = customFolderName; this.extendedPlugins = Collections.unmodifiableList(extendedPlugins); this.hasNativeController = hasNativeController; } @@ -116,6 +119,11 @@ public class PluginInfo implements Writeable, ToXContentObject { javaVersion = "1.8"; } this.classname = in.readString(); + if (in.getVersion().after(Version.V_1_0_0)) { + customFolderName = in.readString(); + } else { + customFolderName = this.name; + } if (in.getVersion().onOrAfter(LegacyESVersion.V_6_2_0)) { extendedPlugins = in.readStringList(); } else { @@ -141,6 +149,13 @@ public class PluginInfo implements Writeable, ToXContentObject { out.writeString(javaVersion); } out.writeString(classname); + if (out.getVersion().after(Version.V_1_0_0)) { + if (customFolderName != null) { + out.writeString(customFolderName); + } else { + out.writeString(name); + } + } if (out.getVersion().onOrAfter(LegacyESVersion.V_6_2_0)) { out.writeStringCollection(extendedPlugins); } @@ -207,6 +222,14 @@ public class PluginInfo implements Writeable, ToXContentObject { "property [classname] is missing for plugin [" + name + "]"); } + final String customFolderNameValue = propsMap.remove("custom.foldername"); + final String customFolderName; + if (esVersion.after(Version.V_1_0_0)) { + customFolderName = customFolderNameValue; + } else { + customFolderName = name; + } + final String extendedString = propsMap.remove("extended.plugins"); final List extendedPlugins; if (extendedString == null) { @@ -248,7 +271,7 @@ public class PluginInfo implements Writeable, ToXContentObject { } return new PluginInfo(name, description, version, esVersion, javaVersionString, - classname, extendedPlugins, hasNativeController); + classname, customFolderName, extendedPlugins, hasNativeController); } /** @@ -278,6 +301,15 @@ public class PluginInfo implements Writeable, ToXContentObject { return classname; } + /** + * The custom folder name for the plugin. + * + * @return the custom folder name for the plugin + */ + public String getFolderName() { + return customFolderName; + } + /** * Other plugins this plugin extends through SPI. * @@ -323,6 +355,15 @@ public class PluginInfo implements Writeable, ToXContentObject { return hasNativeController; } + /** + * The target folder name for the plugin. + * + * @return the custom folder name for the plugin if the folder name is specified, else return the id with kebab-case. + */ + public String getTargetFolderName() { + return (this.customFolderName == null || this.customFolderName.isEmpty()) ? this.name : this.customFolderName; + } + @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(); @@ -333,6 +374,7 @@ public class PluginInfo implements Writeable, ToXContentObject { builder.field("java_version", javaVersion); builder.field("description", description); builder.field("classname", classname); + builder.field("custom_foldername", customFolderName); builder.field("extended_plugins", extendedPlugins); builder.field("has_native_controller", hasNativeController); } @@ -375,7 +417,8 @@ public class PluginInfo implements Writeable, ToXContentObject { .append(prefix).append("Java Version: ").append(javaVersion).append("\n") .append(prefix).append("Native Controller: ").append(hasNativeController).append("\n") .append(prefix).append("Extended Plugins: ").append(extendedPlugins).append("\n") - .append(prefix).append(" * Classname: ").append(classname); + .append(prefix).append(" * Classname: ").append(classname).append("\n") + .append(prefix).append("Folder name: ").append(customFolderName); return information.toString(); } } diff --git a/server/src/main/java/org/opensearch/plugins/PluginsService.java b/server/src/main/java/org/opensearch/plugins/PluginsService.java index d0aa6ab735c..962d2ecbc9d 100644 --- a/server/src/main/java/org/opensearch/plugins/PluginsService.java +++ b/server/src/main/java/org/opensearch/plugins/PluginsService.java @@ -136,7 +136,7 @@ public class PluginsService implements ReportingService { for (Class pluginClass : classpathPlugins) { Plugin plugin = loadPlugin(pluginClass, settings, configPath); PluginInfo pluginInfo = new PluginInfo(pluginClass.getName(), "classpath plugin", "NA", Version.CURRENT, "1.8", - pluginClass.getName(), Collections.emptyList(), false); + pluginClass.getName(), null, Collections.emptyList(), false); if (logger.isTraceEnabled()) { logger.trace("plugin loaded from classpath [{}]", pluginInfo); } diff --git a/server/src/test/java/org/opensearch/nodesinfo/NodeInfoStreamingTests.java b/server/src/test/java/org/opensearch/nodesinfo/NodeInfoStreamingTests.java index 89bf29e0308..21dcbce24e7 100644 --- a/server/src/test/java/org/opensearch/nodesinfo/NodeInfoStreamingTests.java +++ b/server/src/test/java/org/opensearch/nodesinfo/NodeInfoStreamingTests.java @@ -159,16 +159,18 @@ public class NodeInfoStreamingTests extends OpenSearchTestCase { int numPlugins = randomIntBetween(0, 5); List plugins = new ArrayList<>(); for (int i = 0; i < numPlugins; i++) { - plugins.add(new PluginInfo(randomAlphaOfLengthBetween(3, 10), randomAlphaOfLengthBetween(3, 10), + String name = randomAlphaOfLengthBetween(3, 10); + plugins.add(new PluginInfo(name, randomAlphaOfLengthBetween(3, 10), randomAlphaOfLengthBetween(3, 10), VersionUtils.randomVersion(random()), "1.8", - randomAlphaOfLengthBetween(3, 10), Collections.emptyList(), randomBoolean())); + randomAlphaOfLengthBetween(3, 10), name, Collections.emptyList(), randomBoolean())); } int numModules = randomIntBetween(0, 5); List modules = new ArrayList<>(); for (int i = 0; i < numModules; i++) { - modules.add(new PluginInfo(randomAlphaOfLengthBetween(3, 10), randomAlphaOfLengthBetween(3, 10), + String name = randomAlphaOfLengthBetween(3, 10); + modules.add(new PluginInfo(name, randomAlphaOfLengthBetween(3, 10), randomAlphaOfLengthBetween(3, 10), VersionUtils.randomVersion(random()), "1.8", - randomAlphaOfLengthBetween(3, 10), Collections.emptyList(), randomBoolean())); + randomAlphaOfLengthBetween(3, 10), name, Collections.emptyList(), randomBoolean())); } pluginsAndModules = new PluginsAndModules(plugins, modules); } diff --git a/server/src/test/java/org/opensearch/plugins/PluginInfoTests.java b/server/src/test/java/org/opensearch/plugins/PluginInfoTests.java index f911cb547a4..3dda3dad3a8 100644 --- a/server/src/test/java/org/opensearch/plugins/PluginInfoTests.java +++ b/server/src/test/java/org/opensearch/plugins/PluginInfoTests.java @@ -70,6 +70,44 @@ public class PluginInfoTests extends OpenSearchTestCase { assertThat(info.getExtendedPlugins(), empty()); } + public void testReadFromPropertiesWithFolderNameAndVersionBefore() throws Exception { + Path pluginDir = createTempDir().resolve("fake-plugin"); + PluginTestUtil.writePluginProperties(pluginDir, + "description", "fake desc", + "name", "my_plugin", + "version", "1.0", + "opensearch.version", Version.V_1_0_0.toString(), + "java.version", System.getProperty("java.specification.version"), + "classname", "FakePlugin", + "custom.foldername", "custom-folder"); + PluginInfo info = PluginInfo.readFromProperties(pluginDir); + assertEquals("my_plugin", info.getName()); + assertEquals("fake desc", info.getDescription()); + assertEquals("1.0", info.getVersion()); + assertEquals("FakePlugin", info.getClassname()); + assertEquals("my_plugin", info.getTargetFolderName()); + assertThat(info.getExtendedPlugins(), empty()); + } + + public void testReadFromPropertiesWithFolderNameAndVersionAfter() throws Exception { + Path pluginDir = createTempDir().resolve("fake-plugin"); + PluginTestUtil.writePluginProperties(pluginDir, + "description", "fake desc", + "name", "my_plugin", + "version", "1.0", + "opensearch.version", Version.CURRENT.toString(), + "java.version", System.getProperty("java.specification.version"), + "classname", "FakePlugin", + "custom.foldername", "custom-folder"); + PluginInfo info = PluginInfo.readFromProperties(pluginDir); + assertEquals("my_plugin", info.getName()); + assertEquals("fake desc", info.getDescription()); + assertEquals("1.0", info.getVersion()); + assertEquals("FakePlugin", info.getClassname()); + assertEquals("custom-folder", info.getTargetFolderName()); + assertThat(info.getExtendedPlugins(), empty()); + } + public void testReadFromPropertiesNameMissing() throws Exception { Path pluginDir = createTempDir().resolve("fake-plugin"); PluginTestUtil.writePluginProperties(pluginDir); @@ -199,7 +237,7 @@ public class PluginInfoTests extends OpenSearchTestCase { public void testSerialize() throws Exception { PluginInfo info = new PluginInfo("c", "foo", "dummy", Version.CURRENT, "1.8", "dummyclass", - Collections.singletonList("foo"), randomBoolean()); + "c", Collections.singletonList("foo"), randomBoolean()); BytesStreamOutput output = new BytesStreamOutput(); info.writeTo(output); ByteBuffer buffer = ByteBuffer.wrap(output.bytes().toBytesRef().bytes); @@ -212,15 +250,15 @@ public class PluginInfoTests extends OpenSearchTestCase { public void testPluginListSorted() { List plugins = new ArrayList<>(); plugins.add(new PluginInfo("c", "foo", "dummy", Version.CURRENT, "1.8", "dummyclass", - Collections.emptyList(), randomBoolean())); + null, Collections.emptyList(), randomBoolean())); plugins.add(new PluginInfo("b", "foo", "dummy", Version.CURRENT, "1.8", "dummyclass", - Collections.emptyList(), randomBoolean())); + null, Collections.emptyList(), randomBoolean())); plugins.add(new PluginInfo( "e", "foo", "dummy", Version.CURRENT, "1.8", "dummyclass", - Collections.emptyList(), randomBoolean())); + null, Collections.emptyList(), randomBoolean())); plugins.add(new PluginInfo("a", "foo", "dummy", Version.CURRENT, "1.8", "dummyclass", - Collections.emptyList(), randomBoolean())); + null, Collections.emptyList(), randomBoolean())); plugins.add(new PluginInfo("d", "foo", "dummy", Version.CURRENT, "1.8", "dummyclass", - Collections.emptyList(), randomBoolean())); + null, Collections.emptyList(), randomBoolean())); PluginsAndModules pluginsInfo = new PluginsAndModules(plugins, Collections.emptyList()); final List infos = pluginsInfo.getPluginInfos(); diff --git a/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java b/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java index 9f4473fa07b..8c983b22a17 100644 --- a/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java +++ b/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java @@ -323,7 +323,7 @@ public class PluginsServiceTests extends OpenSearchTestCase { public void testSortBundlesCycleSelfReference() throws Exception { Path pluginDir = createTempDir(); PluginInfo info = new PluginInfo("foo", "desc", "1.0", Version.CURRENT, "1.8", - "MyPlugin", Collections.singletonList("foo"), false); + "MyPlugin", null, Collections.singletonList("foo"), false); PluginsService.Bundle bundle = new PluginsService.Bundle(info, pluginDir); IllegalStateException e = expectThrows(IllegalStateException.class, () -> PluginsService.sortBundles(Collections.singleton(bundle)) @@ -335,16 +335,16 @@ public class PluginsServiceTests extends OpenSearchTestCase { Path pluginDir = createTempDir(); Set bundles = new LinkedHashSet<>(); // control iteration order, so we get know the beginning of the cycle PluginInfo info = new PluginInfo("foo", "desc", "1.0", Version.CURRENT, "1.8", - "MyPlugin", Arrays.asList("bar", "other"), false); + "MyPlugin", null, Arrays.asList("bar", "other"), false); bundles.add(new PluginsService.Bundle(info, pluginDir)); PluginInfo info2 = new PluginInfo("bar", "desc", "1.0", Version.CURRENT, "1.8", - "MyPlugin", Collections.singletonList("baz"), false); + "MyPlugin", null, Collections.singletonList("baz"), false); bundles.add(new PluginsService.Bundle(info2, pluginDir)); PluginInfo info3 = new PluginInfo("baz", "desc", "1.0", Version.CURRENT, "1.8", - "MyPlugin", Collections.singletonList("foo"), false); + "MyPlugin", null, Collections.singletonList("foo"), false); bundles.add(new PluginsService.Bundle(info3, pluginDir)); PluginInfo info4 = new PluginInfo("other", "desc", "1.0", Version.CURRENT, "1.8", - "MyPlugin", Collections.emptyList(), false); + "MyPlugin", null, Collections.emptyList(), false); bundles.add(new PluginsService.Bundle(info4, pluginDir)); IllegalStateException e = expectThrows(IllegalStateException.class, () -> PluginsService.sortBundles(bundles)); @@ -354,7 +354,7 @@ public class PluginsServiceTests extends OpenSearchTestCase { public void testSortBundlesSingle() throws Exception { Path pluginDir = createTempDir(); PluginInfo info = new PluginInfo("foo", "desc", "1.0", Version.CURRENT, "1.8", - "MyPlugin", Collections.emptyList(), false); + "MyPlugin", null, Collections.emptyList(), false); PluginsService.Bundle bundle = new PluginsService.Bundle(info, pluginDir); List sortedBundles = PluginsService.sortBundles(Collections.singleton(bundle)); assertThat(sortedBundles, Matchers.contains(bundle)); @@ -364,15 +364,15 @@ public class PluginsServiceTests extends OpenSearchTestCase { Path pluginDir = createTempDir(); Set bundles = new LinkedHashSet<>(); // control iteration order PluginInfo info1 = new PluginInfo("foo", "desc", "1.0", Version.CURRENT, "1.8", - "MyPlugin", Collections.emptyList(), false); + "MyPlugin", null, Collections.emptyList(), false); PluginsService.Bundle bundle1 = new PluginsService.Bundle(info1, pluginDir); bundles.add(bundle1); PluginInfo info2 = new PluginInfo("bar", "desc", "1.0", Version.CURRENT, "1.8", - "MyPlugin", Collections.emptyList(), false); + "MyPlugin", null, Collections.emptyList(), false); PluginsService.Bundle bundle2 = new PluginsService.Bundle(info2, pluginDir); bundles.add(bundle2); PluginInfo info3 = new PluginInfo("baz", "desc", "1.0", Version.CURRENT, "1.8", - "MyPlugin", Collections.emptyList(), false); + "MyPlugin", null, Collections.emptyList(), false); PluginsService.Bundle bundle3 = new PluginsService.Bundle(info3, pluginDir); bundles.add(bundle3); List sortedBundles = PluginsService.sortBundles(bundles); @@ -382,7 +382,7 @@ public class PluginsServiceTests extends OpenSearchTestCase { public void testSortBundlesMissingDep() throws Exception { Path pluginDir = createTempDir(); PluginInfo info = new PluginInfo("foo", "desc", "1.0", Version.CURRENT, "1.8", - "MyPlugin", Collections.singletonList("dne"), false); + "MyPlugin", "", Collections.singletonList("dne"), false); PluginsService.Bundle bundle = new PluginsService.Bundle(info, pluginDir); IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> PluginsService.sortBundles(Collections.singleton(bundle)) @@ -394,19 +394,19 @@ public class PluginsServiceTests extends OpenSearchTestCase { Path pluginDir = createTempDir(); Set bundles = new LinkedHashSet<>(); // control iteration order PluginInfo info1 = new PluginInfo("grandparent", "desc", "1.0",Version.CURRENT, "1.8", - "MyPlugin", Collections.emptyList(), false); + "MyPlugin", null, Collections.emptyList(), false); PluginsService.Bundle bundle1 = new PluginsService.Bundle(info1, pluginDir); bundles.add(bundle1); PluginInfo info2 = new PluginInfo("foo", "desc", "1.0", Version.CURRENT, "1.8", - "MyPlugin", Collections.singletonList("common"), false); + "MyPlugin", null, Collections.singletonList("common"), false); PluginsService.Bundle bundle2 = new PluginsService.Bundle(info2, pluginDir); bundles.add(bundle2); PluginInfo info3 = new PluginInfo("bar", "desc", "1.0", Version.CURRENT, "1.8", - "MyPlugin", Collections.singletonList("common"), false); + "MyPlugin", null, Collections.singletonList("common"), false); PluginsService.Bundle bundle3 = new PluginsService.Bundle(info3, pluginDir); bundles.add(bundle3); PluginInfo info4 = new PluginInfo("common", "desc", "1.0", Version.CURRENT, "1.8", - "MyPlugin", Collections.singletonList("grandparent"), false); + "MyPlugin", null, Collections.singletonList("grandparent"), false); PluginsService.Bundle bundle4 = new PluginsService.Bundle(info4, pluginDir); bundles.add(bundle4); List sortedBundles = PluginsService.sortBundles(bundles); @@ -417,11 +417,11 @@ public class PluginsServiceTests extends OpenSearchTestCase { Path pluginDir = createTempDir(); Set bundles = new LinkedHashSet<>(); // control iteration order PluginInfo info1 = new PluginInfo("dep", "desc", "1.0", Version.CURRENT, "1.8", - "MyPlugin", Collections.emptyList(), false); + "MyPlugin", null, Collections.emptyList(), false); PluginsService.Bundle bundle1 = new PluginsService.Bundle(info1, pluginDir); bundles.add(bundle1); PluginInfo info2 = new PluginInfo("myplugin", "desc", "1.0", Version.CURRENT, "1.8", - "MyPlugin", Collections.singletonList("dep"), false); + "MyPlugin", null, Collections.singletonList("dep"), false); PluginsService.Bundle bundle2 = new PluginsService.Bundle(info2, pluginDir); bundles.add(bundle2); List sortedBundles = PluginsService.sortBundles(bundles); @@ -480,7 +480,7 @@ public class PluginsServiceTests extends OpenSearchTestCase { Map> transitiveDeps = new HashMap<>(); transitiveDeps.put("dep", Collections.singleton(dupJar.toUri().toURL())); PluginInfo info1 = new PluginInfo("myplugin", "desc", "1.0", Version.CURRENT, "1.8", - "MyPlugin", Collections.singletonList("dep"), false); + "MyPlugin", null, Collections.singletonList("dep"), false); PluginsService.Bundle bundle = new PluginsService.Bundle(info1, pluginDir); IllegalStateException e = expectThrows(IllegalStateException.class, () -> PluginsService.checkBundleJarHell(JarHell.parseClassPath(), bundle, transitiveDeps)); @@ -499,7 +499,7 @@ public class PluginsServiceTests extends OpenSearchTestCase { transitiveDeps.put("dep1", Collections.singleton(dupJar.toUri().toURL())); transitiveDeps.put("dep2", Collections.singleton(dupJar.toUri().toURL())); PluginInfo info1 = new PluginInfo("myplugin", "desc", "1.0", Version.CURRENT, "1.8", - "MyPlugin", Arrays.asList("dep1", "dep2"), false); + "MyPlugin", null, Arrays.asList("dep1", "dep2"), false); PluginsService.Bundle bundle = new PluginsService.Bundle(info1, pluginDir); IllegalStateException e = expectThrows(IllegalStateException.class, () -> PluginsService.checkBundleJarHell(JarHell.parseClassPath(), bundle, transitiveDeps)); @@ -516,7 +516,7 @@ public class PluginsServiceTests extends OpenSearchTestCase { Path pluginJar = pluginDir.resolve("plugin.jar"); makeJar(pluginJar, Level.class); PluginInfo info1 = new PluginInfo("myplugin", "desc", "1.0", Version.CURRENT, "1.8", - "MyPlugin", Collections.emptyList(), false); + "MyPlugin", null, Collections.emptyList(), false); PluginsService.Bundle bundle = new PluginsService.Bundle(info1, pluginDir); IllegalStateException e = expectThrows(IllegalStateException.class, () -> PluginsService.checkBundleJarHell(JarHell.parseClassPath(), bundle, new HashMap<>())); @@ -535,7 +535,7 @@ public class PluginsServiceTests extends OpenSearchTestCase { Map> transitiveDeps = new HashMap<>(); transitiveDeps.put("dep", Collections.singleton(depJar.toUri().toURL())); PluginInfo info1 = new PluginInfo("myplugin", "desc", "1.0", Version.CURRENT, "1.8", - "MyPlugin", Collections.singletonList("dep"), false); + "MyPlugin", null, Collections.singletonList("dep"), false); PluginsService.Bundle bundle = new PluginsService.Bundle(info1, pluginDir); IllegalStateException e = expectThrows(IllegalStateException.class, () -> PluginsService.checkBundleJarHell(JarHell.parseClassPath(), bundle, transitiveDeps)); @@ -558,7 +558,7 @@ public class PluginsServiceTests extends OpenSearchTestCase { transitiveDeps.put("dep1", Collections.singleton(dep1Jar.toUri().toURL())); transitiveDeps.put("dep2", Collections.singleton(dep2Jar.toUri().toURL())); PluginInfo info1 = new PluginInfo("myplugin", "desc", "1.0", Version.CURRENT, "1.8", - "MyPlugin", Arrays.asList("dep1", "dep2"), false); + "MyPlugin", null, Arrays.asList("dep1", "dep2"), false); PluginsService.Bundle bundle = new PluginsService.Bundle(info1, pluginDir); IllegalStateException e = expectThrows(IllegalStateException.class, () -> PluginsService.checkBundleJarHell(JarHell.parseClassPath(), bundle, transitiveDeps)); @@ -581,7 +581,7 @@ public class PluginsServiceTests extends OpenSearchTestCase { transitiveDeps.put("dep1", Collections.singleton(dep1Jar.toUri().toURL())); transitiveDeps.put("dep2", Collections.singleton(dep2Jar.toUri().toURL())); PluginInfo info1 = new PluginInfo("myplugin", "desc", "1.0", Version.CURRENT, "1.8", - "MyPlugin", Arrays.asList("dep1", "dep2"), false); + "MyPlugin", null, Arrays.asList("dep1", "dep2"), false); PluginsService.Bundle bundle = new PluginsService.Bundle(info1, pluginDir); PluginsService.checkBundleJarHell(JarHell.parseClassPath(), bundle, transitiveDeps); Set deps = transitiveDeps.get("myplugin"); @@ -630,14 +630,14 @@ public class PluginsServiceTests extends OpenSearchTestCase { public void testIncompatibleOpenSearchVersion() throws Exception { PluginInfo info = new PluginInfo("my_plugin", "desc", "1.0", LegacyESVersion.V_6_0_0, - "1.8", "FakePlugin", Collections.emptyList(), false); + "1.8", "FakePlugin", null, Collections.emptyList(), false); IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> PluginsService.verifyCompatibility(info)); assertThat(e.getMessage(), containsString("was built for OpenSearch version 6.0.0")); } public void testIncompatibleJavaVersion() throws Exception { PluginInfo info = new PluginInfo("my_plugin", "desc", "1.0", Version.CURRENT, - "1000000.0", "FakePlugin", Collections.emptyList(), false); + "1000000.0", "FakePlugin", null, Collections.emptyList(), false); IllegalStateException e = expectThrows(IllegalStateException.class, () -> PluginsService.verifyCompatibility(info)); assertThat(e.getMessage(), containsString("my_plugin requires Java")); } @@ -761,7 +761,7 @@ public class PluginsServiceTests extends OpenSearchTestCase { public void testExtensiblePlugin() { TestExtensiblePlugin extensiblePlugin = new TestExtensiblePlugin(); PluginsService.loadExtensions(Collections.singletonList( - Tuple.tuple(new PluginInfo("extensible", null, null, null, null, null, Collections.emptyList(), false), extensiblePlugin) + Tuple.tuple(new PluginInfo("extensible", null, null, null, null, null, null, Collections.emptyList(), false), extensiblePlugin) )); assertThat(extensiblePlugin.extensions, notNullValue()); @@ -770,8 +770,9 @@ public class PluginsServiceTests extends OpenSearchTestCase { extensiblePlugin = new TestExtensiblePlugin(); TestPlugin testPlugin = new TestPlugin(); PluginsService.loadExtensions(Arrays.asList( - Tuple.tuple(new PluginInfo("extensible", null, null, null, null, null, Collections.emptyList(), false), extensiblePlugin), - Tuple.tuple(new PluginInfo("test", null, null, null, null, null, Collections.singletonList("extensible"), false), testPlugin) + Tuple.tuple(new PluginInfo("extensible", null, null, null, null, null, null, Collections.emptyList(), false), extensiblePlugin), + Tuple.tuple(new PluginInfo("test", null, null, null, null, null, null, Collections.singletonList("extensible"), false), + testPlugin) )); assertThat(extensiblePlugin.extensions, notNullValue());