Allowing custom folder name for plugin installation (#848)

Signed-off-by: Vacha Shah <vachshah@amazon.com>
This commit is contained in:
Vacha 2021-07-21 15:58:49 -07:00 committed by GitHub
parent 6bc4ce017a
commit 19e54d6624
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 269 additions and 75 deletions

View File

@ -105,6 +105,7 @@ class PluginBuildPlugin implements Plugin<Project> {
'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

View File

@ -51,6 +51,8 @@ public class PluginPropertiesExtension {
private String classname;
private String customFolderName = "";
/** Other plugins this plugin extends through SPI */
private List<String> 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;
}

View File

@ -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}
#

View File

@ -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);

View File

@ -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(

View File

@ -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<Path> 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);
}
}

View File

@ -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 + "]...");
/*

View File

@ -576,6 +576,17 @@ public class InstallPluginCommandTests extends OpenSearchTestCase {
assertInstallCleaned(env.v2());
}
public void testExistingPluginWithCustomFolderName() throws Exception {
Tuple<Path, Environment> 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<Path, Environment> env = createEnv(fs, temp);
Path pluginDir = createPluginDir(temp);
@ -873,6 +884,14 @@ public class InstallPluginCommandTests extends OpenSearchTestCase {
);
}
public void testPluginInstallationWithCustomFolderName() throws Exception {
Tuple<Path, Environment> 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<Path, Environment> env = createEnv(fs, temp);
Path pluginDir = createPluginDir(temp);

View File

@ -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()
);

View File

@ -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",

View File

@ -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<String> 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<String> extendedPlugins, boolean hasNativeController) {
String classname, String customFolderName, List<String> 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<String> 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();
}
}

View File

@ -136,7 +136,7 @@ public class PluginsService implements ReportingService<PluginsAndModules> {
for (Class<? extends Plugin> 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);
}

View File

@ -159,16 +159,18 @@ public class NodeInfoStreamingTests extends OpenSearchTestCase {
int numPlugins = randomIntBetween(0, 5);
List<PluginInfo> 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<PluginInfo> 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);
}

View File

@ -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<PluginInfo> 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<PluginInfo> infos = pluginsInfo.getPluginInfos();

View File

@ -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<PluginsService.Bundle> 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<PluginsService.Bundle> sortedBundles = PluginsService.sortBundles(Collections.singleton(bundle));
assertThat(sortedBundles, Matchers.contains(bundle));
@ -364,15 +364,15 @@ public class PluginsServiceTests extends OpenSearchTestCase {
Path pluginDir = createTempDir();
Set<PluginsService.Bundle> 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<PluginsService.Bundle> 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<PluginsService.Bundle> 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<PluginsService.Bundle> sortedBundles = PluginsService.sortBundles(bundles);
@ -417,11 +417,11 @@ public class PluginsServiceTests extends OpenSearchTestCase {
Path pluginDir = createTempDir();
Set<PluginsService.Bundle> 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<PluginsService.Bundle> sortedBundles = PluginsService.sortBundles(bundles);
@ -480,7 +480,7 @@ public class PluginsServiceTests extends OpenSearchTestCase {
Map<String, Set<URL>> 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<String, Set<URL>> 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<URL> 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());