Enforce isolated mode for all plugins
This commit removes the isolated option, each plugin have its own classloader.
This commit is contained in:
parent
69b71e66f3
commit
da42f199bd
|
@ -39,9 +39,6 @@ class PluginPropertiesExtension {
|
|||
@Input
|
||||
String classname
|
||||
|
||||
@Input
|
||||
boolean isolated = true
|
||||
|
||||
PluginPropertiesExtension(Project project) {
|
||||
name = project.name
|
||||
version = project.version
|
||||
|
|
|
@ -54,12 +54,6 @@ class PluginPropertiesTask extends Copy {
|
|||
if (extension.classname == null) {
|
||||
throw new InvalidUserDataException('classname is a required setting for esplugin')
|
||||
}
|
||||
doFirst {
|
||||
if (extension.isolated == false) {
|
||||
String warning = "WARNING: Disabling plugin isolation in ${project.path} is deprecated and will be removed in the future"
|
||||
logger.warn("${'=' * warning.length()}\n${warning}\n${'=' * warning.length()}")
|
||||
}
|
||||
}
|
||||
// configure property substitution
|
||||
from(templateFile)
|
||||
into(generatedResourcesDir)
|
||||
|
@ -80,7 +74,6 @@ class PluginPropertiesTask extends Copy {
|
|||
'version': stringSnap(extension.version),
|
||||
'elasticsearchVersion': stringSnap(VersionProperties.elasticsearch),
|
||||
'javaVersion': project.targetCompatibility as String,
|
||||
'isolated': extension.isolated as String,
|
||||
'classname': extension.classname
|
||||
]
|
||||
}
|
||||
|
|
|
@ -38,12 +38,3 @@ java.version=${javaVersion}
|
|||
#
|
||||
# 'elasticsearch.version' version of elasticsearch compiled against
|
||||
elasticsearch.version=${elasticsearchVersion}
|
||||
#
|
||||
### deprecated elements for jvm plugins :
|
||||
#
|
||||
# 'isolated': true if the plugin should have its own classloader.
|
||||
# passing false is deprecated, and only intended to support plugins
|
||||
# that have hard dependencies against each other. If this is
|
||||
# not specified, then the plugin is isolated by default.
|
||||
isolated=${isolated}
|
||||
#
|
|
@ -20,9 +20,9 @@ package org.elasticsearch.plugins;
|
|||
|
||||
public class DummyPluginInfo extends PluginInfo {
|
||||
|
||||
private DummyPluginInfo(String name, String description, String version, String classname, boolean isolated) {
|
||||
super(name, description, version, classname, isolated);
|
||||
private DummyPluginInfo(String name, String description, String version, String classname) {
|
||||
super(name, description, version, classname);
|
||||
}
|
||||
|
||||
public static final DummyPluginInfo INSTANCE = new DummyPluginInfo("dummy_plugin_name", "dummy plugin description", "dummy_plugin_version", "DummyPluginName", true);
|
||||
public static final DummyPluginInfo INSTANCE = new DummyPluginInfo("dummy_plugin_name", "dummy plugin description", "dummy_plugin_version", "DummyPluginName");
|
||||
}
|
||||
|
|
|
@ -342,7 +342,7 @@ class InstallPluginCommand extends Command {
|
|||
}
|
||||
|
||||
// check for jar hell before any copying
|
||||
jarHellCheck(pluginRoot, env.pluginsFile(), info.isIsolated());
|
||||
jarHellCheck(pluginRoot, env.pluginsFile());
|
||||
|
||||
// read optional security policy (extra permissions)
|
||||
// if it exists, confirm or warn the user
|
||||
|
@ -355,19 +355,13 @@ class InstallPluginCommand extends Command {
|
|||
}
|
||||
|
||||
/** check a candidate plugin for jar hell before installing it */
|
||||
void jarHellCheck(Path candidate, Path pluginsDir, boolean isolated) throws Exception {
|
||||
void jarHellCheck(Path candidate, Path pluginsDir) throws Exception {
|
||||
// create list of current jars in classpath
|
||||
final List<URL> jars = new ArrayList<>();
|
||||
jars.addAll(Arrays.asList(JarHell.parseClassPath()));
|
||||
|
||||
// read existing bundles. this does some checks on the installation too.
|
||||
List<PluginsService.Bundle> bundles = PluginsService.getPluginBundles(pluginsDir);
|
||||
|
||||
// if we aren't isolated, we need to jarhellcheck against any other non-isolated plugins
|
||||
// that's always the first bundle
|
||||
if (isolated == false) {
|
||||
jars.addAll(bundles.get(0).urls);
|
||||
}
|
||||
PluginsService.getPluginBundles(pluginsDir);
|
||||
|
||||
// add plugin jars to the list
|
||||
Path pluginJars[] = FileSystemUtils.files(candidate, "*.jar");
|
||||
|
|
|
@ -44,14 +44,12 @@ public class PluginInfo implements Streamable, ToXContent {
|
|||
static final XContentBuilderString URL = new XContentBuilderString("url");
|
||||
static final XContentBuilderString VERSION = new XContentBuilderString("version");
|
||||
static final XContentBuilderString CLASSNAME = new XContentBuilderString("classname");
|
||||
static final XContentBuilderString ISOLATED = new XContentBuilderString("isolated");
|
||||
}
|
||||
|
||||
private String name;
|
||||
private String description;
|
||||
private String version;
|
||||
private String classname;
|
||||
private boolean isolated;
|
||||
|
||||
public PluginInfo() {
|
||||
}
|
||||
|
@ -63,12 +61,11 @@ public class PluginInfo implements Streamable, ToXContent {
|
|||
* @param description Its description
|
||||
* @param version Version number
|
||||
*/
|
||||
PluginInfo(String name, String description, String version, String classname, boolean isolated) {
|
||||
PluginInfo(String name, String description, String version, String classname) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.version = version;
|
||||
this.classname = classname;
|
||||
this.isolated = isolated;
|
||||
}
|
||||
|
||||
/** reads (and validates) plugin metadata descriptor file */
|
||||
|
@ -106,13 +103,12 @@ public class PluginInfo implements Streamable, ToXContent {
|
|||
}
|
||||
JarHell.checkVersionFormat(javaVersionString);
|
||||
JarHell.checkJavaVersion(name, javaVersionString);
|
||||
boolean isolated = Boolean.parseBoolean(props.getProperty("isolated", "true"));
|
||||
String classname = props.getProperty("classname");
|
||||
if (classname == null) {
|
||||
throw new IllegalArgumentException("Property [classname] is missing for plugin [" + name + "]");
|
||||
}
|
||||
|
||||
return new PluginInfo(name, description, version, classname, isolated);
|
||||
return new PluginInfo(name, description, version, classname);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -129,13 +125,6 @@ public class PluginInfo implements Streamable, ToXContent {
|
|||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if plugin has isolated classloader
|
||||
*/
|
||||
public boolean isIsolated() {
|
||||
return isolated;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return plugin's classname
|
||||
*/
|
||||
|
@ -162,7 +151,6 @@ public class PluginInfo implements Streamable, ToXContent {
|
|||
this.description = in.readString();
|
||||
this.version = in.readString();
|
||||
this.classname = in.readString();
|
||||
this.isolated = in.readBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -171,7 +159,6 @@ public class PluginInfo implements Streamable, ToXContent {
|
|||
out.writeString(description);
|
||||
out.writeString(version);
|
||||
out.writeString(classname);
|
||||
out.writeBoolean(isolated);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -181,7 +168,6 @@ public class PluginInfo implements Streamable, ToXContent {
|
|||
builder.field(Fields.VERSION, version);
|
||||
builder.field(Fields.DESCRIPTION, description);
|
||||
builder.field(Fields.CLASSNAME, classname);
|
||||
builder.field(Fields.ISOLATED, isolated);
|
||||
builder.endObject();
|
||||
|
||||
return builder;
|
||||
|
@ -212,8 +198,7 @@ public class PluginInfo implements Streamable, ToXContent {
|
|||
.append("Name: ").append(name).append("\n")
|
||||
.append("Description: ").append(description).append("\n")
|
||||
.append("Version: ").append(version).append("\n")
|
||||
.append(" * Classname: ").append(classname).append("\n")
|
||||
.append(" * Isolated: ").append(isolated);
|
||||
.append(" * Classname: ").append(classname);
|
||||
|
||||
return information.toString();
|
||||
}
|
||||
|
|
|
@ -103,7 +103,7 @@ public class PluginsService extends AbstractComponent {
|
|||
// first we load plugins that are on the classpath. this is for tests and transport clients
|
||||
for (Class<? extends Plugin> pluginClass : classpathPlugins) {
|
||||
Plugin plugin = loadPlugin(pluginClass, settings);
|
||||
PluginInfo pluginInfo = new PluginInfo(plugin.name(), plugin.description(), "NA", pluginClass.getName(), false);
|
||||
PluginInfo pluginInfo = new PluginInfo(plugin.name(), plugin.description(), "NA", pluginClass.getName());
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("plugin loaded from classpath [{}]", pluginInfo);
|
||||
}
|
||||
|
@ -302,9 +302,6 @@ public class PluginsService extends AbstractComponent {
|
|||
continue; // skip over .DS_Store etc
|
||||
}
|
||||
PluginInfo info = PluginInfo.readFromProperties(module);
|
||||
if (!info.isIsolated()) {
|
||||
throw new IllegalStateException("modules must be isolated: " + info);
|
||||
}
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.plugins.add(info);
|
||||
// gather urls for jar files
|
||||
|
@ -329,8 +326,6 @@ public class PluginsService extends AbstractComponent {
|
|||
}
|
||||
|
||||
List<Bundle> bundles = new ArrayList<>();
|
||||
// a special purgatory for plugins that directly depend on each other
|
||||
bundles.add(new Bundle());
|
||||
|
||||
try (DirectoryStream<Path> stream = Files.newDirectoryStream(pluginsDirectory)) {
|
||||
for (Path plugin : stream) {
|
||||
|
@ -354,13 +349,8 @@ public class PluginsService extends AbstractComponent {
|
|||
urls.add(jar.toRealPath().toUri().toURL());
|
||||
}
|
||||
}
|
||||
final Bundle bundle;
|
||||
if (info.isIsolated() == false) {
|
||||
bundle = bundles.get(0); // purgatory
|
||||
} else {
|
||||
bundle = new Bundle();
|
||||
bundles.add(bundle);
|
||||
}
|
||||
final Bundle bundle = new Bundle();
|
||||
bundles.add(bundle);
|
||||
bundle.plugins.add(info);
|
||||
bundle.urls.addAll(urls);
|
||||
}
|
||||
|
|
|
@ -46,7 +46,6 @@ public class PluginInfoTests extends ESTestCase {
|
|||
assertEquals("fake desc", info.getDescription());
|
||||
assertEquals("1.0", info.getVersion());
|
||||
assertEquals("FakePlugin", info.getClassname());
|
||||
assertTrue(info.isIsolated());
|
||||
}
|
||||
|
||||
public void testReadFromPropertiesNameMissing() throws Exception {
|
||||
|
@ -203,11 +202,11 @@ public class PluginInfoTests extends ESTestCase {
|
|||
|
||||
public void testPluginListSorted() {
|
||||
PluginsAndModules pluginsInfo = new PluginsAndModules();
|
||||
pluginsInfo.addPlugin(new PluginInfo("c", "foo", "dummy", "dummyclass", true));
|
||||
pluginsInfo.addPlugin(new PluginInfo("b", "foo", "dummy", "dummyclass", true));
|
||||
pluginsInfo.addPlugin(new PluginInfo("e", "foo", "dummy", "dummyclass", true));
|
||||
pluginsInfo.addPlugin(new PluginInfo("a", "foo", "dummy", "dummyclass", true));
|
||||
pluginsInfo.addPlugin(new PluginInfo("d", "foo", "dummy", "dummyclass", true));
|
||||
pluginsInfo.addPlugin(new PluginInfo("c", "foo", "dummy", "dummyclass"));
|
||||
pluginsInfo.addPlugin(new PluginInfo("b", "foo", "dummy", "dummyclass"));
|
||||
pluginsInfo.addPlugin(new PluginInfo("e", "foo", "dummy", "dummyclass"));
|
||||
pluginsInfo.addPlugin(new PluginInfo("a", "foo", "dummy", "dummyclass"));
|
||||
pluginsInfo.addPlugin(new PluginInfo("d", "foo", "dummy", "dummyclass"));
|
||||
|
||||
final List<PluginInfo> infos = pluginsInfo.getPluginInfos();
|
||||
List<String> names = infos.stream().map((input) -> input.getName()).collect(Collectors.toList());
|
||||
|
|
|
@ -6,6 +6,10 @@ structure of the plugin ZIP archive has changed. All the plugin files must be
|
|||
contained in a top-level directory called `elasticsearch`. If you use the
|
||||
gradle build, this structure is automatically generated.
|
||||
|
||||
==== Plugins isolation
|
||||
|
||||
`isolated` option has been removed. Each plugin will have its own classloader.
|
||||
|
||||
==== Site plugins removed
|
||||
|
||||
Site plugins have been removed. Site plugins should be reimplemented as Kibana
|
||||
|
|
|
@ -35,12 +35,6 @@ subprojects {
|
|||
throw new InvalidModelException("Modules cannot contain config files")
|
||||
}
|
||||
|
||||
project.afterEvaluate {
|
||||
if (esplugin.isolated == false) {
|
||||
throw new InvalidModelException("Modules cannot disable isolation")
|
||||
}
|
||||
}
|
||||
|
||||
// these are implementation details of our build, no need to publish them!
|
||||
install.enabled = false
|
||||
uploadArchives.enabled = false
|
||||
|
|
|
@ -193,9 +193,9 @@ public class InstallPluginCommandTests extends ESTestCase {
|
|||
MockTerminal terminal = new MockTerminal();
|
||||
new InstallPluginCommand(env) {
|
||||
@Override
|
||||
void jarHellCheck(Path candidate, Path pluginsDir, boolean isolated) throws Exception {
|
||||
void jarHellCheck(Path candidate, Path pluginsDir) throws Exception {
|
||||
if (jarHellCheck) {
|
||||
super.jarHellCheck(candidate, pluginsDir, isolated);
|
||||
super.jarHellCheck(candidate, pluginsDir);
|
||||
}
|
||||
}
|
||||
}.execute(terminal, pluginUrl, true);
|
||||
|
@ -369,40 +369,6 @@ public class InstallPluginCommandTests extends ESTestCase {
|
|||
assertPlugin("fake2", pluginDir2, env);
|
||||
}
|
||||
|
||||
public void testPurgatoryJarHell() throws Exception {
|
||||
assumeTrue("real filesystem", isReal);
|
||||
Environment environment = createEnv(fs, temp);
|
||||
Path pluginDir1 = createPluginDir(temp);
|
||||
PluginTestUtil.writeProperties(pluginDir1,
|
||||
"description", "fake desc",
|
||||
"name", "fake1",
|
||||
"version", "1.0",
|
||||
"elasticsearch.version", Version.CURRENT.toString(),
|
||||
"java.version", System.getProperty("java.specification.version"),
|
||||
"classname", "FakePlugin",
|
||||
"isolated", "false");
|
||||
writeJar(pluginDir1.resolve("plugin.jar"), "FakePlugin");
|
||||
String pluginZip1 = writeZip(pluginDir1, "elasticsearch");
|
||||
installPlugin(pluginZip1, environment);
|
||||
|
||||
Path pluginDir2 = createPluginDir(temp);
|
||||
PluginTestUtil.writeProperties(pluginDir2,
|
||||
"description", "fake desc",
|
||||
"name", "fake2",
|
||||
"version", "1.0",
|
||||
"elasticsearch.version", Version.CURRENT.toString(),
|
||||
"java.version", System.getProperty("java.specification.version"),
|
||||
"classname", "FakePlugin",
|
||||
"isolated", "false");
|
||||
writeJar(pluginDir2.resolve("plugin.jar"), "FakePlugin");
|
||||
String pluginZip2 = writeZip(pluginDir2, "elasticsearch");
|
||||
IllegalStateException e = expectThrows(IllegalStateException.class, () -> {
|
||||
installPlugin(pluginZip2, environment, true);
|
||||
});
|
||||
assertTrue(e.getMessage(), e.getMessage().contains("jar hell"));
|
||||
assertInstallCleaned(environment);
|
||||
}
|
||||
|
||||
public void testExistingPlugin() throws Exception {
|
||||
Environment env = createEnv(fs, temp);
|
||||
Path pluginDir = createPluginDir(temp);
|
||||
|
|
Loading…
Reference in New Issue