Allowing custom folder name for plugin installation (#848) (#1116)

Signed-off-by: Vacha Shah <vachshah@amazon.com>
This commit is contained in:
Vacha 2021-08-23 14:39:27 -07:00 committed by GitHub
parent e153629871
commit f73e66e5e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 270 additions and 76 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,9 +770,10 @@ 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());
assertThat(extensiblePlugin.extensions, hasSize(2));