mirror of
https://github.com/elastic/elasticsearch.git
synced 2025-04-25 07:37:19 -04:00
Plugins: Remove site plugins
Site plugins used to be used for things like kibana and marvel, but there is no longer a need since kibana (and marvel as a kibana plugin) uses node.js. This change removes site plugins, as well as the flag for jvm plugins. Now all plugins are jvm plugins.
This commit is contained in:
parent
b4538a5676
commit
3b78267c71
42 changed files with 79 additions and 1033 deletions
|
@ -112,9 +112,6 @@ public class PluginBuildPlugin extends BuildPlugin {
|
||||||
include 'config/**'
|
include 'config/**'
|
||||||
include 'bin/**'
|
include 'bin/**'
|
||||||
}
|
}
|
||||||
from('src/site') {
|
|
||||||
include '_site/**'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
project.assemble.dependsOn(bundle)
|
project.assemble.dependsOn(bundle)
|
||||||
|
|
||||||
|
|
|
@ -36,15 +36,9 @@ class PluginPropertiesExtension {
|
||||||
@Input
|
@Input
|
||||||
String description
|
String description
|
||||||
|
|
||||||
@Input
|
|
||||||
boolean jvm = true
|
|
||||||
|
|
||||||
@Input
|
@Input
|
||||||
String classname
|
String classname
|
||||||
|
|
||||||
@Input
|
|
||||||
boolean site = false
|
|
||||||
|
|
||||||
@Input
|
@Input
|
||||||
boolean isolated = true
|
boolean isolated = true
|
||||||
|
|
||||||
|
|
|
@ -51,11 +51,11 @@ class PluginPropertiesTask extends Copy {
|
||||||
if (extension.description == null) {
|
if (extension.description == null) {
|
||||||
throw new InvalidUserDataException('description is a required setting for esplugin')
|
throw new InvalidUserDataException('description is a required setting for esplugin')
|
||||||
}
|
}
|
||||||
if (extension.jvm && extension.classname == null) {
|
if (extension.classname == null) {
|
||||||
throw new InvalidUserDataException('classname is a required setting for esplugin with jvm=true')
|
throw new InvalidUserDataException('classname is a required setting for esplugin')
|
||||||
}
|
}
|
||||||
doFirst {
|
doFirst {
|
||||||
if (extension.jvm && extension.isolated == false) {
|
if (extension.isolated == false) {
|
||||||
String warning = "WARNING: Disabling plugin isolation in ${project.path} is deprecated and will be removed in the future"
|
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()}")
|
logger.warn("${'=' * warning.length()}\n${warning}\n${'=' * warning.length()}")
|
||||||
}
|
}
|
||||||
|
@ -74,10 +74,8 @@ class PluginPropertiesTask extends Copy {
|
||||||
'version': extension.version,
|
'version': extension.version,
|
||||||
'elasticsearchVersion': VersionProperties.elasticsearch,
|
'elasticsearchVersion': VersionProperties.elasticsearch,
|
||||||
'javaVersion': project.targetCompatibility as String,
|
'javaVersion': project.targetCompatibility as String,
|
||||||
'jvm': extension.jvm as String,
|
|
||||||
'site': extension.site as String,
|
|
||||||
'isolated': extension.isolated as String,
|
'isolated': extension.isolated as String,
|
||||||
'classname': extension.jvm ? extension.classname : 'NA'
|
'classname': extension.classname
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,26 +2,13 @@
|
||||||
# This file must exist as 'plugin-descriptor.properties' at
|
# This file must exist as 'plugin-descriptor.properties' at
|
||||||
# the root directory of all plugins.
|
# the root directory of all plugins.
|
||||||
#
|
#
|
||||||
# A plugin can be 'site', 'jvm', or both.
|
### example plugin for "foo"
|
||||||
#
|
|
||||||
### example site plugin for "foo":
|
|
||||||
#
|
|
||||||
# foo.zip <-- zip file for the plugin, with this structure:
|
|
||||||
# _site/ <-- the contents that will be served
|
|
||||||
# plugin-descriptor.properties <-- example contents below:
|
|
||||||
#
|
|
||||||
# site=true
|
|
||||||
# description=My cool plugin
|
|
||||||
# version=1.0
|
|
||||||
#
|
|
||||||
### example jvm plugin for "foo"
|
|
||||||
#
|
#
|
||||||
# foo.zip <-- zip file for the plugin, with this structure:
|
# foo.zip <-- zip file for the plugin, with this structure:
|
||||||
# <arbitrary name1>.jar <-- classes, resources, dependencies
|
# <arbitrary name1>.jar <-- classes, resources, dependencies
|
||||||
# <arbitrary nameN>.jar <-- any number of jars
|
# <arbitrary nameN>.jar <-- any number of jars
|
||||||
# plugin-descriptor.properties <-- example contents below:
|
# plugin-descriptor.properties <-- example contents below:
|
||||||
#
|
#
|
||||||
# jvm=true
|
|
||||||
# classname=foo.bar.BazPlugin
|
# classname=foo.bar.BazPlugin
|
||||||
# description=My cool plugin
|
# description=My cool plugin
|
||||||
# version=2.0
|
# version=2.0
|
||||||
|
@ -38,21 +25,6 @@ version=${version}
|
||||||
#
|
#
|
||||||
# 'name': the plugin name
|
# 'name': the plugin name
|
||||||
name=${name}
|
name=${name}
|
||||||
|
|
||||||
### mandatory elements for site plugins:
|
|
||||||
#
|
|
||||||
# 'site': set to true to indicate contents of the _site/
|
|
||||||
# directory in the root of the plugin should be served.
|
|
||||||
site=${site}
|
|
||||||
#
|
|
||||||
### mandatory elements for jvm plugins :
|
|
||||||
#
|
|
||||||
# 'jvm': true if the 'classname' class should be loaded
|
|
||||||
# from jar files in the root directory of the plugin.
|
|
||||||
# Note that only jar files in the root directory are
|
|
||||||
# added to the classpath for the plugin! If you need
|
|
||||||
# other resources, package them into a resources jar.
|
|
||||||
jvm=${jvm}
|
|
||||||
#
|
#
|
||||||
# 'classname': the name of the class to load, fully-qualified.
|
# 'classname': the name of the class to load, fully-qualified.
|
||||||
classname=${classname}
|
classname=${classname}
|
||||||
|
|
|
@ -51,7 +51,7 @@ import static org.elasticsearch.rest.RestStatus.NOT_FOUND;
|
||||||
import static org.elasticsearch.rest.RestStatus.OK;
|
import static org.elasticsearch.rest.RestStatus.OK;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* A component to serve http requests, backed by rest handlers.
|
||||||
*/
|
*/
|
||||||
public class HttpServer extends AbstractLifecycleComponent<HttpServer> {
|
public class HttpServer extends AbstractLifecycleComponent<HttpServer> {
|
||||||
|
|
||||||
|
@ -63,10 +63,6 @@ public class HttpServer extends AbstractLifecycleComponent<HttpServer> {
|
||||||
|
|
||||||
private final NodeService nodeService;
|
private final NodeService nodeService;
|
||||||
|
|
||||||
private final boolean disableSites;
|
|
||||||
|
|
||||||
private final PluginSiteFilter pluginSiteFilter = new PluginSiteFilter();
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public HttpServer(Settings settings, Environment environment, HttpServerTransport transport,
|
public HttpServer(Settings settings, Environment environment, HttpServerTransport transport,
|
||||||
RestController restController,
|
RestController restController,
|
||||||
|
@ -77,9 +73,6 @@ public class HttpServer extends AbstractLifecycleComponent<HttpServer> {
|
||||||
this.restController = restController;
|
this.restController = restController;
|
||||||
this.nodeService = nodeService;
|
this.nodeService = nodeService;
|
||||||
nodeService.setHttpServer(this);
|
nodeService.setHttpServer(this);
|
||||||
|
|
||||||
this.disableSites = this.settings.getAsBoolean("http.disable_sites", false);
|
|
||||||
|
|
||||||
transport.httpServerAdapter(new Dispatcher(this));
|
transport.httpServerAdapter(new Dispatcher(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,27 +119,13 @@ public class HttpServer extends AbstractLifecycleComponent<HttpServer> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void internalDispatchRequest(final HttpRequest request, final HttpChannel channel) {
|
public void internalDispatchRequest(final HttpRequest request, final HttpChannel channel) {
|
||||||
String rawPath = request.rawPath();
|
if (request.rawPath().equals("/favicon.ico")) {
|
||||||
if (rawPath.startsWith("/_plugin/")) {
|
|
||||||
RestFilterChain filterChain = restController.filterChain(pluginSiteFilter);
|
|
||||||
filterChain.continueProcessing(request, channel);
|
|
||||||
return;
|
|
||||||
} else if (rawPath.equals("/favicon.ico")) {
|
|
||||||
handleFavicon(request, channel);
|
handleFavicon(request, channel);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
restController.dispatchRequest(request, channel);
|
restController.dispatchRequest(request, channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class PluginSiteFilter extends RestFilter {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void process(RestRequest request, RestChannel channel, RestFilterChain filterChain) throws IOException {
|
|
||||||
handlePluginSite((HttpRequest) request, (HttpChannel) channel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void handleFavicon(HttpRequest request, HttpChannel channel) {
|
void handleFavicon(HttpRequest request, HttpChannel channel) {
|
||||||
if (request.method() == RestRequest.Method.GET) {
|
if (request.method() == RestRequest.Method.GET) {
|
||||||
try {
|
try {
|
||||||
|
@ -163,129 +142,4 @@ public class HttpServer extends AbstractLifecycleComponent<HttpServer> {
|
||||||
channel.sendResponse(new BytesRestResponse(FORBIDDEN));
|
channel.sendResponse(new BytesRestResponse(FORBIDDEN));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void handlePluginSite(HttpRequest request, HttpChannel channel) throws IOException {
|
|
||||||
if (disableSites) {
|
|
||||||
channel.sendResponse(new BytesRestResponse(FORBIDDEN));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (request.method() == RestRequest.Method.OPTIONS) {
|
|
||||||
// when we have OPTIONS request, simply send OK by default (with the Access Control Origin header which gets automatically added)
|
|
||||||
channel.sendResponse(new BytesRestResponse(OK));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (request.method() != RestRequest.Method.GET) {
|
|
||||||
channel.sendResponse(new BytesRestResponse(FORBIDDEN));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// TODO for a "/_plugin" endpoint, we should have a page that lists all the plugins?
|
|
||||||
|
|
||||||
String path = request.rawPath().substring("/_plugin/".length());
|
|
||||||
int i1 = path.indexOf('/');
|
|
||||||
String pluginName;
|
|
||||||
String sitePath;
|
|
||||||
if (i1 == -1) {
|
|
||||||
pluginName = path;
|
|
||||||
sitePath = null;
|
|
||||||
// If a trailing / is missing, we redirect to the right page #2654
|
|
||||||
String redirectUrl = request.rawPath() + "/";
|
|
||||||
BytesRestResponse restResponse = new BytesRestResponse(RestStatus.MOVED_PERMANENTLY, "text/html", "<head><meta http-equiv=\"refresh\" content=\"0; URL=" + redirectUrl + "\"></head>");
|
|
||||||
restResponse.addHeader("Location", redirectUrl);
|
|
||||||
channel.sendResponse(restResponse);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
pluginName = path.substring(0, i1);
|
|
||||||
sitePath = path.substring(i1 + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// we default to index.html, or what the plugin provides (as a unix-style path)
|
|
||||||
// this is a relative path under _site configured by the plugin.
|
|
||||||
if (sitePath.length() == 0) {
|
|
||||||
sitePath = "index.html";
|
|
||||||
} else {
|
|
||||||
// remove extraneous leading slashes, its not an absolute path.
|
|
||||||
while (sitePath.length() > 0 && sitePath.charAt(0) == '/') {
|
|
||||||
sitePath = sitePath.substring(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final Path siteFile = environment.pluginsFile().resolve(pluginName).resolve("_site");
|
|
||||||
|
|
||||||
final String separator = siteFile.getFileSystem().getSeparator();
|
|
||||||
// Convert file separators.
|
|
||||||
sitePath = sitePath.replace("/", separator);
|
|
||||||
|
|
||||||
Path file = siteFile.resolve(sitePath);
|
|
||||||
|
|
||||||
// return not found instead of forbidden to prevent malicious requests to find out if files exist or dont exist
|
|
||||||
if (!Files.exists(file) || FileSystemUtils.isHidden(file) || !file.toAbsolutePath().normalize().startsWith(siteFile.toAbsolutePath().normalize())) {
|
|
||||||
channel.sendResponse(new BytesRestResponse(NOT_FOUND));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicFileAttributes attributes = Files.readAttributes(file, BasicFileAttributes.class);
|
|
||||||
if (!attributes.isRegularFile()) {
|
|
||||||
// If it's not a dir, we send a 403
|
|
||||||
if (!attributes.isDirectory()) {
|
|
||||||
channel.sendResponse(new BytesRestResponse(FORBIDDEN));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// We don't serve dir but if index.html exists in dir we should serve it
|
|
||||||
file = file.resolve("index.html");
|
|
||||||
if (!Files.exists(file) || FileSystemUtils.isHidden(file) || !Files.isRegularFile(file)) {
|
|
||||||
channel.sendResponse(new BytesRestResponse(FORBIDDEN));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
byte[] data = Files.readAllBytes(file);
|
|
||||||
channel.sendResponse(new BytesRestResponse(OK, guessMimeType(sitePath), data));
|
|
||||||
} catch (IOException e) {
|
|
||||||
channel.sendResponse(new BytesRestResponse(INTERNAL_SERVER_ERROR));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: Don't respond with a mime type that violates the request's Accept header
|
|
||||||
private String guessMimeType(String path) {
|
|
||||||
int lastDot = path.lastIndexOf('.');
|
|
||||||
if (lastDot == -1) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
String extension = path.substring(lastDot + 1).toLowerCase(Locale.ROOT);
|
|
||||||
String mimeType = DEFAULT_MIME_TYPES.get(extension);
|
|
||||||
if (mimeType == null) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return mimeType;
|
|
||||||
}
|
|
||||||
|
|
||||||
static {
|
|
||||||
// This is not an exhaustive list, just the most common types. Call registerMimeType() to add more.
|
|
||||||
Map<String, String> mimeTypes = new HashMap<>();
|
|
||||||
mimeTypes.put("txt", "text/plain");
|
|
||||||
mimeTypes.put("css", "text/css");
|
|
||||||
mimeTypes.put("csv", "text/csv");
|
|
||||||
mimeTypes.put("htm", "text/html");
|
|
||||||
mimeTypes.put("html", "text/html");
|
|
||||||
mimeTypes.put("xml", "text/xml");
|
|
||||||
mimeTypes.put("js", "text/javascript"); // Technically it should be application/javascript (RFC 4329), but IE8 struggles with that
|
|
||||||
mimeTypes.put("xhtml", "application/xhtml+xml");
|
|
||||||
mimeTypes.put("json", "application/json");
|
|
||||||
mimeTypes.put("pdf", "application/pdf");
|
|
||||||
mimeTypes.put("zip", "application/zip");
|
|
||||||
mimeTypes.put("tar", "application/x-tar");
|
|
||||||
mimeTypes.put("gif", "image/gif");
|
|
||||||
mimeTypes.put("jpeg", "image/jpeg");
|
|
||||||
mimeTypes.put("jpg", "image/jpeg");
|
|
||||||
mimeTypes.put("tiff", "image/tiff");
|
|
||||||
mimeTypes.put("tif", "image/tiff");
|
|
||||||
mimeTypes.put("png", "image/png");
|
|
||||||
mimeTypes.put("svg", "image/svg+xml");
|
|
||||||
mimeTypes.put("ico", "image/vnd.microsoft.icon");
|
|
||||||
mimeTypes.put("mp3", "audio/mpeg");
|
|
||||||
DEFAULT_MIME_TYPES = unmodifiableMap(mimeTypes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final Map<String, String> DEFAULT_MIME_TYPES;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,9 @@ package org.elasticsearch.plugins;
|
||||||
|
|
||||||
public class DummyPluginInfo extends PluginInfo {
|
public class DummyPluginInfo extends PluginInfo {
|
||||||
|
|
||||||
private DummyPluginInfo(String name, String description, boolean site, String version, boolean jvm, String classname, boolean isolated) {
|
private DummyPluginInfo(String name, String description, String version, String classname, boolean isolated) {
|
||||||
super(name, description, site, version, jvm, classname, isolated);
|
super(name, description, version, classname, isolated);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final DummyPluginInfo INSTANCE = new DummyPluginInfo("dummy_plugin_name", "dummy plugin description", true, "dummy_plugin_version", true, "DummyPluginName", true);
|
public static final DummyPluginInfo INSTANCE = new DummyPluginInfo("dummy_plugin_name", "dummy plugin description", "dummy_plugin_version", "DummyPluginName", true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,19 +42,14 @@ public class PluginInfo implements Streamable, ToXContent {
|
||||||
static final XContentBuilderString NAME = new XContentBuilderString("name");
|
static final XContentBuilderString NAME = new XContentBuilderString("name");
|
||||||
static final XContentBuilderString DESCRIPTION = new XContentBuilderString("description");
|
static final XContentBuilderString DESCRIPTION = new XContentBuilderString("description");
|
||||||
static final XContentBuilderString URL = new XContentBuilderString("url");
|
static final XContentBuilderString URL = new XContentBuilderString("url");
|
||||||
static final XContentBuilderString SITE = new XContentBuilderString("site");
|
|
||||||
static final XContentBuilderString VERSION = new XContentBuilderString("version");
|
static final XContentBuilderString VERSION = new XContentBuilderString("version");
|
||||||
static final XContentBuilderString JVM = new XContentBuilderString("jvm");
|
|
||||||
static final XContentBuilderString CLASSNAME = new XContentBuilderString("classname");
|
static final XContentBuilderString CLASSNAME = new XContentBuilderString("classname");
|
||||||
static final XContentBuilderString ISOLATED = new XContentBuilderString("isolated");
|
static final XContentBuilderString ISOLATED = new XContentBuilderString("isolated");
|
||||||
}
|
}
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
private String description;
|
private String description;
|
||||||
private boolean site;
|
|
||||||
private String version;
|
private String version;
|
||||||
|
|
||||||
private boolean jvm;
|
|
||||||
private String classname;
|
private String classname;
|
||||||
private boolean isolated;
|
private boolean isolated;
|
||||||
|
|
||||||
|
@ -66,15 +61,11 @@ public class PluginInfo implements Streamable, ToXContent {
|
||||||
*
|
*
|
||||||
* @param name Its name
|
* @param name Its name
|
||||||
* @param description Its description
|
* @param description Its description
|
||||||
* @param site true if it's a site plugin
|
|
||||||
* @param jvm true if it's a jvm plugin
|
|
||||||
* @param version Version number
|
* @param version Version number
|
||||||
*/
|
*/
|
||||||
PluginInfo(String name, String description, boolean site, String version, boolean jvm, String classname, boolean isolated) {
|
PluginInfo(String name, String description, String version, String classname, boolean isolated) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
this.site = site;
|
|
||||||
this.jvm = jvm;
|
|
||||||
this.version = version;
|
this.version = version;
|
||||||
this.classname = classname;
|
this.classname = classname;
|
||||||
this.isolated = isolated;
|
this.isolated = isolated;
|
||||||
|
@ -101,43 +92,28 @@ public class PluginInfo implements Streamable, ToXContent {
|
||||||
throw new IllegalArgumentException("Property [version] is missing for plugin [" + name + "]");
|
throw new IllegalArgumentException("Property [version] is missing for plugin [" + name + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean jvm = Boolean.parseBoolean(props.getProperty("jvm"));
|
String esVersionString = props.getProperty("elasticsearch.version");
|
||||||
boolean site = Boolean.parseBoolean(props.getProperty("site"));
|
if (esVersionString == null) {
|
||||||
if (jvm == false && site == false) {
|
throw new IllegalArgumentException("Property [elasticsearch.version] is missing for plugin [" + name + "]");
|
||||||
throw new IllegalArgumentException("Plugin [" + name + "] must be at least a jvm or site plugin");
|
|
||||||
}
|
}
|
||||||
boolean isolated = true;
|
Version esVersion = Version.fromString(esVersionString);
|
||||||
String classname = "NA";
|
if (esVersion.equals(Version.CURRENT) == false) {
|
||||||
if (jvm) {
|
throw new IllegalArgumentException("Plugin [" + name + "] is incompatible with Elasticsearch [" + Version.CURRENT.toString() +
|
||||||
String esVersionString = props.getProperty("elasticsearch.version");
|
"]. Was designed for version [" + esVersionString + "]");
|
||||||
if (esVersionString == null) {
|
}
|
||||||
throw new IllegalArgumentException("Property [elasticsearch.version] is missing for jvm plugin [" + name + "]");
|
String javaVersionString = props.getProperty("java.version");
|
||||||
}
|
if (javaVersionString == null) {
|
||||||
Version esVersion = Version.fromString(esVersionString);
|
throw new IllegalArgumentException("Property [java.version] is missing for plugin [" + name + "]");
|
||||||
if (esVersion.equals(Version.CURRENT) == false) {
|
}
|
||||||
throw new IllegalArgumentException("Plugin [" + name + "] is incompatible with Elasticsearch [" + Version.CURRENT.toString() +
|
JarHell.checkVersionFormat(javaVersionString);
|
||||||
"]. Was designed for version [" + esVersionString + "]");
|
JarHell.checkJavaVersion(name, javaVersionString);
|
||||||
}
|
boolean isolated = Boolean.parseBoolean(props.getProperty("isolated", "true"));
|
||||||
String javaVersionString = props.getProperty("java.version");
|
String classname = props.getProperty("classname");
|
||||||
if (javaVersionString == null) {
|
if (classname == null) {
|
||||||
throw new IllegalArgumentException("Property [java.version] is missing for jvm plugin [" + name + "]");
|
throw new IllegalArgumentException("Property [classname] is missing for plugin [" + name + "]");
|
||||||
}
|
|
||||||
JarHell.checkVersionFormat(javaVersionString);
|
|
||||||
JarHell.checkJavaVersion(name, javaVersionString);
|
|
||||||
isolated = Boolean.parseBoolean(props.getProperty("isolated", "true"));
|
|
||||||
classname = props.getProperty("classname");
|
|
||||||
if (classname == null) {
|
|
||||||
throw new IllegalArgumentException("Property [classname] is missing for jvm plugin [" + name + "]");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (site) {
|
return new PluginInfo(name, description, version, classname, isolated);
|
||||||
if (!Files.exists(dir.resolve("_site"))) {
|
|
||||||
throw new IllegalArgumentException("Plugin [" + name + "] is a site plugin but has no '_site/' directory");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new PluginInfo(name, description, site, version, jvm, classname, isolated);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -155,46 +131,19 @@ public class PluginInfo implements Streamable, ToXContent {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if it's a site plugin
|
* @return true if plugin has isolated classloader
|
||||||
*/
|
|
||||||
public boolean isSite() {
|
|
||||||
return site;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if it's a plugin running in the jvm
|
|
||||||
*/
|
|
||||||
public boolean isJvm() {
|
|
||||||
return jvm;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if jvm plugin has isolated classloader
|
|
||||||
*/
|
*/
|
||||||
public boolean isIsolated() {
|
public boolean isIsolated() {
|
||||||
return isolated;
|
return isolated;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return jvm plugin's classname
|
* @return plugin's classname
|
||||||
*/
|
*/
|
||||||
public String getClassname() {
|
public String getClassname() {
|
||||||
return classname;
|
return classname;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* We compute the URL for sites: "/_plugin/" + name + "/"
|
|
||||||
*
|
|
||||||
* @return relative URL for site plugin
|
|
||||||
*/
|
|
||||||
public String getUrl() {
|
|
||||||
if (site) {
|
|
||||||
return ("/_plugin/" + name + "/");
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Version number for the plugin
|
* @return Version number for the plugin
|
||||||
*/
|
*/
|
||||||
|
@ -212,8 +161,6 @@ public class PluginInfo implements Streamable, ToXContent {
|
||||||
public void readFrom(StreamInput in) throws IOException {
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
this.name = in.readString();
|
this.name = in.readString();
|
||||||
this.description = in.readString();
|
this.description = in.readString();
|
||||||
this.site = in.readBoolean();
|
|
||||||
this.jvm = in.readBoolean();
|
|
||||||
this.version = in.readString();
|
this.version = in.readString();
|
||||||
this.classname = in.readString();
|
this.classname = in.readString();
|
||||||
this.isolated = in.readBoolean();
|
this.isolated = in.readBoolean();
|
||||||
|
@ -223,8 +170,6 @@ public class PluginInfo implements Streamable, ToXContent {
|
||||||
public void writeTo(StreamOutput out) throws IOException {
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
out.writeString(name);
|
out.writeString(name);
|
||||||
out.writeString(description);
|
out.writeString(description);
|
||||||
out.writeBoolean(site);
|
|
||||||
out.writeBoolean(jvm);
|
|
||||||
out.writeString(version);
|
out.writeString(version);
|
||||||
out.writeString(classname);
|
out.writeString(classname);
|
||||||
out.writeBoolean(isolated);
|
out.writeBoolean(isolated);
|
||||||
|
@ -236,15 +181,8 @@ public class PluginInfo implements Streamable, ToXContent {
|
||||||
builder.field(Fields.NAME, name);
|
builder.field(Fields.NAME, name);
|
||||||
builder.field(Fields.VERSION, version);
|
builder.field(Fields.VERSION, version);
|
||||||
builder.field(Fields.DESCRIPTION, description);
|
builder.field(Fields.DESCRIPTION, description);
|
||||||
if (site) {
|
builder.field(Fields.CLASSNAME, classname);
|
||||||
builder.field(Fields.URL, getUrl());
|
builder.field(Fields.ISOLATED, isolated);
|
||||||
}
|
|
||||||
builder.field(Fields.JVM, jvm);
|
|
||||||
if (jvm) {
|
|
||||||
builder.field(Fields.CLASSNAME, classname);
|
|
||||||
builder.field(Fields.ISOLATED, isolated);
|
|
||||||
}
|
|
||||||
builder.field(Fields.SITE, site);
|
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
|
|
||||||
return builder;
|
return builder;
|
||||||
|
@ -274,14 +212,9 @@ public class PluginInfo implements Streamable, ToXContent {
|
||||||
.append("- Plugin information:\n")
|
.append("- Plugin information:\n")
|
||||||
.append("Name: ").append(name).append("\n")
|
.append("Name: ").append(name).append("\n")
|
||||||
.append("Description: ").append(description).append("\n")
|
.append("Description: ").append(description).append("\n")
|
||||||
.append("Site: ").append(site).append("\n")
|
|
||||||
.append("Version: ").append(version).append("\n")
|
.append("Version: ").append(version).append("\n")
|
||||||
.append("JVM: ").append(jvm).append("\n");
|
.append(" * Classname: ").append(classname).append("\n")
|
||||||
|
.append(" * Isolated: ").append(isolated);
|
||||||
if (jvm) {
|
|
||||||
information.append(" * Classname: ").append(classname).append("\n");
|
|
||||||
information.append(" * Isolated: ").append(isolated);
|
|
||||||
}
|
|
||||||
|
|
||||||
return information.toString();
|
return information.toString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -258,9 +258,7 @@ public class PluginManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for jar hell before any copying
|
// check for jar hell before any copying
|
||||||
if (info.isJvm()) {
|
jarHellCheck(root, info.isIsolated());
|
||||||
jarHellCheck(root, info.isIsolated());
|
|
||||||
}
|
|
||||||
|
|
||||||
// read optional security policy (extra permissions)
|
// read optional security policy (extra permissions)
|
||||||
// if it exists, confirm or warn the user
|
// if it exists, confirm or warn the user
|
||||||
|
|
|
@ -98,7 +98,7 @@ public class PluginsService extends AbstractComponent {
|
||||||
// first we load plugins that are on the classpath. this is for tests and transport clients
|
// first we load plugins that are on the classpath. this is for tests and transport clients
|
||||||
for (Class<? extends Plugin> pluginClass : classpathPlugins) {
|
for (Class<? extends Plugin> pluginClass : classpathPlugins) {
|
||||||
Plugin plugin = loadPlugin(pluginClass, settings);
|
Plugin plugin = loadPlugin(pluginClass, settings);
|
||||||
PluginInfo pluginInfo = new PluginInfo(plugin.name(), plugin.description(), false, "NA", true, pluginClass.getName(), false);
|
PluginInfo pluginInfo = new PluginInfo(plugin.name(), plugin.description(), "NA", pluginClass.getName(), false);
|
||||||
if (logger.isTraceEnabled()) {
|
if (logger.isTraceEnabled()) {
|
||||||
logger.trace("plugin loaded from classpath [{}]", pluginInfo);
|
logger.trace("plugin loaded from classpath [{}]", pluginInfo);
|
||||||
}
|
}
|
||||||
|
@ -136,18 +136,10 @@ public class PluginsService extends AbstractComponent {
|
||||||
|
|
||||||
plugins = Collections.unmodifiableList(pluginsLoaded);
|
plugins = Collections.unmodifiableList(pluginsLoaded);
|
||||||
|
|
||||||
// We need to build a List of jvm and site plugins for checking mandatory plugins
|
// We need to build a List of plugins for checking mandatory plugins
|
||||||
Map<String, Plugin> jvmPlugins = new HashMap<>();
|
Set<String> pluginsNames = new HashSet<>();
|
||||||
List<String> sitePlugins = new ArrayList<>();
|
|
||||||
|
|
||||||
for (Tuple<PluginInfo, Plugin> tuple : plugins) {
|
for (Tuple<PluginInfo, Plugin> tuple : plugins) {
|
||||||
PluginInfo info = tuple.v1();
|
pluginsNames.add(tuple.v1().getName());
|
||||||
if (info.isJvm()) {
|
|
||||||
jvmPlugins.put(info.getName(), tuple.v2());
|
|
||||||
}
|
|
||||||
if (info.isSite()) {
|
|
||||||
sitePlugins.add(info.getName());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checking expected plugins
|
// Checking expected plugins
|
||||||
|
@ -155,7 +147,7 @@ public class PluginsService extends AbstractComponent {
|
||||||
if (mandatoryPlugins != null) {
|
if (mandatoryPlugins != null) {
|
||||||
Set<String> missingPlugins = new HashSet<>();
|
Set<String> missingPlugins = new HashSet<>();
|
||||||
for (String mandatoryPlugin : mandatoryPlugins) {
|
for (String mandatoryPlugin : mandatoryPlugins) {
|
||||||
if (!jvmPlugins.containsKey(mandatoryPlugin) && !sitePlugins.contains(mandatoryPlugin) && !missingPlugins.contains(mandatoryPlugin)) {
|
if (!pluginsNames.contains(mandatoryPlugin) && !missingPlugins.contains(mandatoryPlugin)) {
|
||||||
missingPlugins.add(mandatoryPlugin);
|
missingPlugins.add(mandatoryPlugin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,10 +167,11 @@ public class PluginsService extends AbstractComponent {
|
||||||
jvmPluginNames.add(pluginInfo.getName());
|
jvmPluginNames.add(pluginInfo.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info("modules {}, plugins {}, sites {}", moduleNames, jvmPluginNames, sitePlugins);
|
logger.info("modules {}, plugins {}", moduleNames, jvmPluginNames);
|
||||||
|
|
||||||
Map<Plugin, List<OnModuleReference>> onModuleReferences = new HashMap<>();
|
Map<Plugin, List<OnModuleReference>> onModuleReferences = new HashMap<>();
|
||||||
for (Plugin plugin : jvmPlugins.values()) {
|
for (Tuple<PluginInfo, Plugin> pluginEntry : plugins) {
|
||||||
|
Plugin plugin = pluginEntry.v2();
|
||||||
List<OnModuleReference> list = new ArrayList<>();
|
List<OnModuleReference> list = new ArrayList<>();
|
||||||
for (Method method : plugin.getClass().getMethods()) {
|
for (Method method : plugin.getClass().getMethods()) {
|
||||||
if (!method.getName().equals("onModule")) {
|
if (!method.getName().equals("onModule")) {
|
||||||
|
@ -304,9 +297,6 @@ public class PluginsService extends AbstractComponent {
|
||||||
continue; // skip over .DS_Store etc
|
continue; // skip over .DS_Store etc
|
||||||
}
|
}
|
||||||
PluginInfo info = PluginInfo.readFromProperties(module);
|
PluginInfo info = PluginInfo.readFromProperties(module);
|
||||||
if (!info.isJvm()) {
|
|
||||||
throw new IllegalStateException("modules must be jvm plugins: " + info);
|
|
||||||
}
|
|
||||||
if (!info.isIsolated()) {
|
if (!info.isIsolated()) {
|
||||||
throw new IllegalStateException("modules must be isolated: " + info);
|
throw new IllegalStateException("modules must be isolated: " + info);
|
||||||
}
|
}
|
||||||
|
@ -353,17 +343,14 @@ public class PluginsService extends AbstractComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
List<URL> urls = new ArrayList<>();
|
List<URL> urls = new ArrayList<>();
|
||||||
if (info.isJvm()) {
|
try (DirectoryStream<Path> jarStream = Files.newDirectoryStream(plugin, "*.jar")) {
|
||||||
// a jvm plugin: gather urls for jar files
|
for (Path jar : jarStream) {
|
||||||
try (DirectoryStream<Path> jarStream = Files.newDirectoryStream(plugin, "*.jar")) {
|
// normalize with toRealPath to get symlinks out of our hair
|
||||||
for (Path jar : jarStream) {
|
urls.add(jar.toRealPath().toUri().toURL());
|
||||||
// normalize with toRealPath to get symlinks out of our hair
|
|
||||||
urls.add(jar.toRealPath().toUri().toURL());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final Bundle bundle;
|
final Bundle bundle;
|
||||||
if (info.isJvm() && info.isIsolated() == false) {
|
if (info.isIsolated() == false) {
|
||||||
bundle = bundles.get(0); // purgatory
|
bundle = bundles.get(0); // purgatory
|
||||||
} else {
|
} else {
|
||||||
bundle = new Bundle();
|
bundle = new Bundle();
|
||||||
|
@ -395,15 +382,10 @@ public class PluginsService extends AbstractComponent {
|
||||||
// create a child to load the plugins in this bundle
|
// create a child to load the plugins in this bundle
|
||||||
ClassLoader loader = URLClassLoader.newInstance(bundle.urls.toArray(new URL[0]), getClass().getClassLoader());
|
ClassLoader loader = URLClassLoader.newInstance(bundle.urls.toArray(new URL[0]), getClass().getClassLoader());
|
||||||
for (PluginInfo pluginInfo : bundle.plugins) {
|
for (PluginInfo pluginInfo : bundle.plugins) {
|
||||||
final Plugin plugin;
|
// reload lucene SPI with any new services from the plugin
|
||||||
if (pluginInfo.isJvm()) {
|
reloadLuceneSPI(loader);
|
||||||
// reload lucene SPI with any new services from the plugin
|
final Class<? extends Plugin> pluginClass = loadPluginClass(pluginInfo.getClassname(), loader);
|
||||||
reloadLuceneSPI(loader);
|
final Plugin plugin = loadPlugin(pluginClass, settings);
|
||||||
Class<? extends Plugin> pluginClass = loadPluginClass(pluginInfo.getClassname(), loader);
|
|
||||||
plugin = loadPlugin(pluginClass, settings);
|
|
||||||
} else {
|
|
||||||
plugin = new SitePlugin(pluginInfo.getName(), pluginInfo.getDescription());
|
|
||||||
}
|
|
||||||
plugins.add(new Tuple<>(pluginInfo, plugin));
|
plugins.add(new Tuple<>(pluginInfo, plugin));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
/*
|
|
||||||
* Licensed to Elasticsearch under one or more contributor
|
|
||||||
* license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright
|
|
||||||
* ownership. Elasticsearch licenses this file to you under
|
|
||||||
* the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
* not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.elasticsearch.plugins;
|
|
||||||
|
|
||||||
/** A site-only plugin, just serves resources */
|
|
||||||
final class SitePlugin extends Plugin {
|
|
||||||
final String name;
|
|
||||||
final String description;
|
|
||||||
|
|
||||||
SitePlugin(String name, String description) {
|
|
||||||
this.name = name;
|
|
||||||
this.description = description;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String name() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String description() {
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -84,8 +84,6 @@ public class RestPluginsAction extends AbstractCatAction {
|
||||||
table.addCell("name", "alias:n;desc:node name");
|
table.addCell("name", "alias:n;desc:node name");
|
||||||
table.addCell("component", "alias:c;desc:component");
|
table.addCell("component", "alias:c;desc:component");
|
||||||
table.addCell("version", "alias:v;desc:component version");
|
table.addCell("version", "alias:v;desc:component version");
|
||||||
table.addCell("type", "alias:t;desc:type (j for JVM, s for Site)");
|
|
||||||
table.addCell("url", "alias:u;desc:url for site plugins");
|
|
||||||
table.addCell("description", "alias:d;default:false;desc:plugin details");
|
table.addCell("description", "alias:d;default:false;desc:plugin details");
|
||||||
table.endHeaders();
|
table.endHeaders();
|
||||||
return table;
|
return table;
|
||||||
|
@ -104,22 +102,6 @@ public class RestPluginsAction extends AbstractCatAction {
|
||||||
table.addCell(node.name());
|
table.addCell(node.name());
|
||||||
table.addCell(pluginInfo.getName());
|
table.addCell(pluginInfo.getName());
|
||||||
table.addCell(pluginInfo.getVersion());
|
table.addCell(pluginInfo.getVersion());
|
||||||
String type;
|
|
||||||
if (pluginInfo.isSite()) {
|
|
||||||
if (pluginInfo.isJvm()) {
|
|
||||||
type = "j/s";
|
|
||||||
} else {
|
|
||||||
type = "s";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (pluginInfo.isJvm()) {
|
|
||||||
type = "j";
|
|
||||||
} else {
|
|
||||||
type = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
table.addCell(type);
|
|
||||||
table.addCell(pluginInfo.getUrl());
|
|
||||||
table.addCell(pluginInfo.getDescription());
|
table.addCell(pluginInfo.getDescription());
|
||||||
table.endRow();
|
table.endRow();
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,17 +40,13 @@ public class PluginInfoTests extends ESTestCase {
|
||||||
"version", "1.0",
|
"version", "1.0",
|
||||||
"elasticsearch.version", Version.CURRENT.toString(),
|
"elasticsearch.version", Version.CURRENT.toString(),
|
||||||
"java.version", System.getProperty("java.specification.version"),
|
"java.version", System.getProperty("java.specification.version"),
|
||||||
"jvm", "true",
|
|
||||||
"classname", "FakePlugin");
|
"classname", "FakePlugin");
|
||||||
PluginInfo info = PluginInfo.readFromProperties(pluginDir);
|
PluginInfo info = PluginInfo.readFromProperties(pluginDir);
|
||||||
assertEquals("my_plugin", info.getName());
|
assertEquals("my_plugin", info.getName());
|
||||||
assertEquals("fake desc", info.getDescription());
|
assertEquals("fake desc", info.getDescription());
|
||||||
assertEquals("1.0", info.getVersion());
|
assertEquals("1.0", info.getVersion());
|
||||||
assertEquals("FakePlugin", info.getClassname());
|
assertEquals("FakePlugin", info.getClassname());
|
||||||
assertTrue(info.isJvm());
|
|
||||||
assertTrue(info.isIsolated());
|
assertTrue(info.isIsolated());
|
||||||
assertFalse(info.isSite());
|
|
||||||
assertNull(info.getUrl());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testReadFromPropertiesNameMissing() throws Exception {
|
public void testReadFromPropertiesNameMissing() throws Exception {
|
||||||
|
@ -94,27 +90,12 @@ public class PluginInfoTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testReadFromPropertiesJvmAndSiteMissing() throws Exception {
|
|
||||||
Path pluginDir = createTempDir().resolve("fake-plugin");
|
|
||||||
PluginTestUtil.writeProperties(pluginDir,
|
|
||||||
"description", "fake desc",
|
|
||||||
"version", "1.0",
|
|
||||||
"name", "my_plugin");
|
|
||||||
try {
|
|
||||||
PluginInfo.readFromProperties(pluginDir);
|
|
||||||
fail("expected jvm or site exception");
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
assertTrue(e.getMessage().contains("must be at least a jvm or site plugin"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testReadFromPropertiesElasticsearchVersionMissing() throws Exception {
|
public void testReadFromPropertiesElasticsearchVersionMissing() throws Exception {
|
||||||
Path pluginDir = createTempDir().resolve("fake-plugin");
|
Path pluginDir = createTempDir().resolve("fake-plugin");
|
||||||
PluginTestUtil.writeProperties(pluginDir,
|
PluginTestUtil.writeProperties(pluginDir,
|
||||||
"description", "fake desc",
|
"description", "fake desc",
|
||||||
"name", "my_plugin",
|
"name", "my_plugin",
|
||||||
"version", "1.0",
|
"version", "1.0");
|
||||||
"jvm", "true");
|
|
||||||
try {
|
try {
|
||||||
PluginInfo.readFromProperties(pluginDir);
|
PluginInfo.readFromProperties(pluginDir);
|
||||||
fail("expected missing elasticsearch version exception");
|
fail("expected missing elasticsearch version exception");
|
||||||
|
@ -129,8 +110,7 @@ public class PluginInfoTests extends ESTestCase {
|
||||||
"description", "fake desc",
|
"description", "fake desc",
|
||||||
"name", "my_plugin",
|
"name", "my_plugin",
|
||||||
"elasticsearch.version", Version.CURRENT.toString(),
|
"elasticsearch.version", Version.CURRENT.toString(),
|
||||||
"version", "1.0",
|
"version", "1.0");
|
||||||
"jvm", "true");
|
|
||||||
try {
|
try {
|
||||||
PluginInfo.readFromProperties(pluginDir);
|
PluginInfo.readFromProperties(pluginDir);
|
||||||
fail("expected missing java version exception");
|
fail("expected missing java version exception");
|
||||||
|
@ -148,8 +128,7 @@ public class PluginInfoTests extends ESTestCase {
|
||||||
"elasticsearch.version", Version.CURRENT.toString(),
|
"elasticsearch.version", Version.CURRENT.toString(),
|
||||||
"java.version", "1000000.0",
|
"java.version", "1000000.0",
|
||||||
"classname", "FakePlugin",
|
"classname", "FakePlugin",
|
||||||
"version", "1.0",
|
"version", "1.0");
|
||||||
"jvm", "true");
|
|
||||||
try {
|
try {
|
||||||
PluginInfo.readFromProperties(pluginDir);
|
PluginInfo.readFromProperties(pluginDir);
|
||||||
fail("expected incompatible java version exception");
|
fail("expected incompatible java version exception");
|
||||||
|
@ -167,8 +146,7 @@ public class PluginInfoTests extends ESTestCase {
|
||||||
"elasticsearch.version", Version.CURRENT.toString(),
|
"elasticsearch.version", Version.CURRENT.toString(),
|
||||||
"java.version", "1.7.0_80",
|
"java.version", "1.7.0_80",
|
||||||
"classname", "FakePlugin",
|
"classname", "FakePlugin",
|
||||||
"version", "1.0",
|
"version", "1.0");
|
||||||
"jvm", "true");
|
|
||||||
try {
|
try {
|
||||||
PluginInfo.readFromProperties(pluginDir);
|
PluginInfo.readFromProperties(pluginDir);
|
||||||
fail("expected bad java version format exception");
|
fail("expected bad java version format exception");
|
||||||
|
@ -182,7 +160,6 @@ public class PluginInfoTests extends ESTestCase {
|
||||||
PluginTestUtil.writeProperties(pluginDir,
|
PluginTestUtil.writeProperties(pluginDir,
|
||||||
"description", "fake desc",
|
"description", "fake desc",
|
||||||
"version", "1.0",
|
"version", "1.0",
|
||||||
"jvm", "true",
|
|
||||||
"name", "my_plugin",
|
"name", "my_plugin",
|
||||||
"elasticsearch.version", "bogus");
|
"elasticsearch.version", "bogus");
|
||||||
try {
|
try {
|
||||||
|
@ -199,7 +176,6 @@ public class PluginInfoTests extends ESTestCase {
|
||||||
"description", "fake desc",
|
"description", "fake desc",
|
||||||
"name", "my_plugin",
|
"name", "my_plugin",
|
||||||
"version", "1.0",
|
"version", "1.0",
|
||||||
"jvm", "true",
|
|
||||||
"elasticsearch.version", Version.V_1_7_0.toString());
|
"elasticsearch.version", Version.V_1_7_0.toString());
|
||||||
try {
|
try {
|
||||||
PluginInfo.readFromProperties(pluginDir);
|
PluginInfo.readFromProperties(pluginDir);
|
||||||
|
@ -216,8 +192,7 @@ public class PluginInfoTests extends ESTestCase {
|
||||||
"name", "my_plugin",
|
"name", "my_plugin",
|
||||||
"version", "1.0",
|
"version", "1.0",
|
||||||
"elasticsearch.version", Version.CURRENT.toString(),
|
"elasticsearch.version", Version.CURRENT.toString(),
|
||||||
"java.version", System.getProperty("java.specification.version"),
|
"java.version", System.getProperty("java.specification.version"));
|
||||||
"jvm", "true");
|
|
||||||
try {
|
try {
|
||||||
PluginInfo.readFromProperties(pluginDir);
|
PluginInfo.readFromProperties(pluginDir);
|
||||||
fail("expected old elasticsearch version exception");
|
fail("expected old elasticsearch version exception");
|
||||||
|
@ -226,42 +201,13 @@ public class PluginInfoTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testReadFromPropertiesSitePlugin() throws Exception {
|
|
||||||
Path pluginDir = createTempDir().resolve("fake-plugin");
|
|
||||||
Files.createDirectories(pluginDir.resolve("_site"));
|
|
||||||
PluginTestUtil.writeProperties(pluginDir,
|
|
||||||
"description", "fake desc",
|
|
||||||
"name", "my_plugin",
|
|
||||||
"version", "1.0",
|
|
||||||
"site", "true");
|
|
||||||
PluginInfo info = PluginInfo.readFromProperties(pluginDir);
|
|
||||||
assertTrue(info.isSite());
|
|
||||||
assertFalse(info.isJvm());
|
|
||||||
assertEquals("NA", info.getClassname());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testReadFromPropertiesSitePluginWithoutSite() throws Exception {
|
|
||||||
Path pluginDir = createTempDir().resolve("fake-plugin");
|
|
||||||
PluginTestUtil.writeProperties(pluginDir,
|
|
||||||
"description", "fake desc",
|
|
||||||
"name", "my_plugin",
|
|
||||||
"version", "1.0",
|
|
||||||
"site", "true");
|
|
||||||
try {
|
|
||||||
PluginInfo.readFromProperties(pluginDir);
|
|
||||||
fail("didn't get expected exception");
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
assertTrue(e.getMessage().contains("site plugin but has no '_site"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testPluginListSorted() {
|
public void testPluginListSorted() {
|
||||||
PluginsAndModules pluginsInfo = new PluginsAndModules();
|
PluginsAndModules pluginsInfo = new PluginsAndModules();
|
||||||
pluginsInfo.addPlugin(new PluginInfo("c", "foo", true, "dummy", true, "dummyclass", true));
|
pluginsInfo.addPlugin(new PluginInfo("c", "foo", "dummy", "dummyclass", true));
|
||||||
pluginsInfo.addPlugin(new PluginInfo("b", "foo", true, "dummy", true, "dummyclass", true));
|
pluginsInfo.addPlugin(new PluginInfo("b", "foo", "dummy", "dummyclass", true));
|
||||||
pluginsInfo.addPlugin(new PluginInfo("e", "foo", true, "dummy", true, "dummyclass", true));
|
pluginsInfo.addPlugin(new PluginInfo("e", "foo", "dummy", "dummyclass", true));
|
||||||
pluginsInfo.addPlugin(new PluginInfo("a", "foo", true, "dummy", true, "dummyclass", true));
|
pluginsInfo.addPlugin(new PluginInfo("a", "foo", "dummy", "dummyclass", true));
|
||||||
pluginsInfo.addPlugin(new PluginInfo("d", "foo", true, "dummy", true, "dummyclass", true));
|
pluginsInfo.addPlugin(new PluginInfo("d", "foo", "dummy", "dummyclass", true));
|
||||||
|
|
||||||
final List<PluginInfo> infos = pluginsInfo.getPluginInfos();
|
final List<PluginInfo> infos = pluginsInfo.getPluginInfos();
|
||||||
List<String> names = infos.stream().map((input) -> input.getName()).collect(Collectors.toList());
|
List<String> names = infos.stream().map((input) -> input.getName()).collect(Collectors.toList());
|
||||||
|
|
|
@ -1,131 +0,0 @@
|
||||||
/*
|
|
||||||
* Licensed to Elasticsearch under one or more contributor
|
|
||||||
* license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright
|
|
||||||
* ownership. Elasticsearch licenses this file to you under
|
|
||||||
* the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
* not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
package org.elasticsearch.plugins;
|
|
||||||
|
|
||||||
import org.apache.http.client.config.RequestConfig;
|
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
|
||||||
import org.apache.http.impl.client.HttpClients;
|
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.http.HttpServerTransport;
|
|
||||||
import org.elasticsearch.test.ESIntegTestCase;
|
|
||||||
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
|
|
||||||
import org.elasticsearch.test.ESIntegTestCase.Scope;
|
|
||||||
import org.elasticsearch.test.rest.client.http.HttpRequestBuilder;
|
|
||||||
import org.elasticsearch.test.rest.client.http.HttpResponse;
|
|
||||||
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import static org.elasticsearch.common.settings.Settings.settingsBuilder;
|
|
||||||
import static org.elasticsearch.rest.RestStatus.FORBIDDEN;
|
|
||||||
import static org.elasticsearch.rest.RestStatus.MOVED_PERMANENTLY;
|
|
||||||
import static org.elasticsearch.rest.RestStatus.NOT_FOUND;
|
|
||||||
import static org.elasticsearch.rest.RestStatus.OK;
|
|
||||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.hasStatus;
|
|
||||||
import static org.hamcrest.Matchers.containsString;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* We want to test site plugins
|
|
||||||
*/
|
|
||||||
@ClusterScope(scope = Scope.SUITE, numDataNodes = 1)
|
|
||||||
public class SitePluginIT extends ESIntegTestCase {
|
|
||||||
@Override
|
|
||||||
protected Settings nodeSettings(int nodeOrdinal) {
|
|
||||||
Path pluginDir = getDataPath("/org/elasticsearch/test_plugins");
|
|
||||||
return settingsBuilder()
|
|
||||||
.put(super.nodeSettings(nodeOrdinal))
|
|
||||||
.put("path.plugins", pluginDir.toAbsolutePath())
|
|
||||||
.put("force.http.enabled", true)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HttpRequestBuilder httpClient() {
|
|
||||||
RequestConfig.Builder builder = RequestConfig.custom().setRedirectsEnabled(false);
|
|
||||||
CloseableHttpClient httpClient = HttpClients.custom().setDefaultRequestConfig(builder.build()).build();
|
|
||||||
return new HttpRequestBuilder(httpClient).httpTransport(internalCluster().getDataNodeInstance(HttpServerTransport.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testRedirectSitePlugin() throws Exception {
|
|
||||||
// We use an HTTP Client to test redirection
|
|
||||||
HttpResponse response = httpClient().method("GET").path("/_plugin/dummy").execute();
|
|
||||||
assertThat(response, hasStatus(MOVED_PERMANENTLY));
|
|
||||||
assertThat(response.getBody(), containsString("/_plugin/dummy/"));
|
|
||||||
|
|
||||||
// We test the real URL
|
|
||||||
response = httpClient().method("GET").path("/_plugin/dummy/").execute();
|
|
||||||
assertThat(response, hasStatus(OK));
|
|
||||||
assertThat(response.getBody(), containsString("<title>Dummy Site Plugin</title>"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test direct access to an existing file (index.html)
|
|
||||||
*/
|
|
||||||
public void testAnyPage() throws Exception {
|
|
||||||
HttpResponse response = httpClient().path("/_plugin/dummy/index.html").execute();
|
|
||||||
assertThat(response, hasStatus(OK));
|
|
||||||
assertThat(response.getBody(), containsString("<title>Dummy Site Plugin</title>"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test normalizing of path
|
|
||||||
*/
|
|
||||||
public void testThatPathsAreNormalized() throws Exception {
|
|
||||||
// more info: https://www.owasp.org/index.php/Path_Traversal
|
|
||||||
List<String> notFoundUris = new ArrayList<>();
|
|
||||||
notFoundUris.add("/_plugin/dummy/../../../../../log4j.properties");
|
|
||||||
notFoundUris.add("/_plugin/dummy/../../../../../%00log4j.properties");
|
|
||||||
notFoundUris.add("/_plugin/dummy/..%c0%af..%c0%af..%c0%af..%c0%af..%c0%aflog4j.properties");
|
|
||||||
notFoundUris.add("/_plugin/dummy/%2E%2E/%2E%2E/%2E%2E/%2E%2E/index.html");
|
|
||||||
notFoundUris.add("/_plugin/dummy/%2e%2e/%2e%2e/%2e%2e/%2e%2e/index.html");
|
|
||||||
notFoundUris.add("/_plugin/dummy/%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2findex.html");
|
|
||||||
notFoundUris.add("/_plugin/dummy/%2E%2E/%2E%2E/%2E%2E/%2E%2E/index.html");
|
|
||||||
notFoundUris.add("/_plugin/dummy/..%5C..%5C..%5C..%5C..%5Clog4j.properties");
|
|
||||||
|
|
||||||
for (String uri : notFoundUris) {
|
|
||||||
HttpResponse response = httpClient().path(uri).execute();
|
|
||||||
String message = String.format(Locale.ROOT, "URI [%s] expected to be not found", uri);
|
|
||||||
assertThat(message, response, hasStatus(NOT_FOUND));
|
|
||||||
}
|
|
||||||
|
|
||||||
// using relative path inside of the plugin should work
|
|
||||||
HttpResponse response = httpClient().path("/_plugin/dummy/dir1/../dir1/../index.html").execute();
|
|
||||||
assertThat(response, hasStatus(OK));
|
|
||||||
assertThat(response.getBody(), containsString("<title>Dummy Site Plugin</title>"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test case for #4845: https://github.com/elasticsearch/elasticsearch/issues/4845
|
|
||||||
* Serving _site plugins do not pick up on index.html for sub directories
|
|
||||||
*/
|
|
||||||
public void testWelcomePageInSubDirs() throws Exception {
|
|
||||||
HttpResponse response = httpClient().path("/_plugin/subdir/dir/").execute();
|
|
||||||
assertThat(response, hasStatus(OK));
|
|
||||||
assertThat(response.getBody(), containsString("<title>Dummy Site Plugin (subdir)</title>"));
|
|
||||||
|
|
||||||
response = httpClient().path("/_plugin/subdir/dir_without_index/").execute();
|
|
||||||
assertThat(response, hasStatus(FORBIDDEN));
|
|
||||||
|
|
||||||
response = httpClient().path("/_plugin/subdir/dir_without_index/page.html").execute();
|
|
||||||
assertThat(response, hasStatus(OK));
|
|
||||||
assertThat(response.getBody(), containsString("<title>Dummy Site Plugin (page)</title>"));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,88 +0,0 @@
|
||||||
/*
|
|
||||||
* Licensed to Elasticsearch under one or more contributor
|
|
||||||
* license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright
|
|
||||||
* ownership. Elasticsearch licenses this file to you under
|
|
||||||
* the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
* not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
package org.elasticsearch.plugins;
|
|
||||||
|
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
|
||||||
import org.apache.http.impl.client.HttpClients;
|
|
||||||
import org.elasticsearch.common.io.PathUtils;
|
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.http.HttpServerTransport;
|
|
||||||
import org.elasticsearch.test.ESIntegTestCase;
|
|
||||||
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
|
|
||||||
import org.elasticsearch.test.rest.client.http.HttpRequestBuilder;
|
|
||||||
import org.elasticsearch.test.rest.client.http.HttpResponse;
|
|
||||||
|
|
||||||
import java.nio.file.Path;
|
|
||||||
|
|
||||||
import static org.apache.lucene.util.Constants.WINDOWS;
|
|
||||||
import static org.elasticsearch.common.settings.Settings.settingsBuilder;
|
|
||||||
import static org.elasticsearch.rest.RestStatus.OK;
|
|
||||||
import static org.elasticsearch.test.ESIntegTestCase.Scope.SUITE;
|
|
||||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.hasStatus;
|
|
||||||
|
|
||||||
@ClusterScope(scope = SUITE, numDataNodes = 1)
|
|
||||||
public class SitePluginRelativePathConfigIT extends ESIntegTestCase {
|
|
||||||
private final Path root = PathUtils.get(".").toAbsolutePath().getRoot();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Settings nodeSettings(int nodeOrdinal) {
|
|
||||||
String cwdToRoot = getRelativePath(PathUtils.get(".").toAbsolutePath());
|
|
||||||
Path pluginDir = PathUtils.get(cwdToRoot, relativizeToRootIfNecessary(getDataPath("/org/elasticsearch/test_plugins")).toString());
|
|
||||||
|
|
||||||
Path tempDir = createTempDir();
|
|
||||||
boolean useRelativeInMiddleOfPath = randomBoolean();
|
|
||||||
if (useRelativeInMiddleOfPath) {
|
|
||||||
pluginDir = PathUtils.get(tempDir.toString(), getRelativePath(tempDir), pluginDir.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
return settingsBuilder()
|
|
||||||
.put(super.nodeSettings(nodeOrdinal))
|
|
||||||
.put("path.plugins", pluginDir)
|
|
||||||
.put("force.http.enabled", true)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testThatRelativePathsDontAffectPlugins() throws Exception {
|
|
||||||
HttpResponse response = httpClient().method("GET").path("/_plugin/dummy/").execute();
|
|
||||||
assertThat(response, hasStatus(OK));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Path relativizeToRootIfNecessary(Path path) {
|
|
||||||
if (WINDOWS) {
|
|
||||||
return root.relativize(path);
|
|
||||||
}
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getRelativePath(Path path) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
for (int i = 0; i < path.getNameCount(); i++) {
|
|
||||||
sb.append("..");
|
|
||||||
sb.append(path.getFileSystem().getSeparator());
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HttpRequestBuilder httpClient() {
|
|
||||||
CloseableHttpClient httpClient = HttpClients.createDefault();
|
|
||||||
return new HttpRequestBuilder(httpClient).httpTransport(internalCluster().getDataNodeInstance(HttpServerTransport.class));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,8 +3,6 @@
|
||||||
|
|
||||||
The Elasticsearch repository contains examples of:
|
The Elasticsearch repository contains examples of:
|
||||||
|
|
||||||
* a https://github.com/elastic/elasticsearch/tree/master/plugins/site-example[site plugin]
|
|
||||||
for serving static HTML, JavaScript, and CSS.
|
|
||||||
* a https://github.com/elastic/elasticsearch/tree/master/plugins/jvm-example[Java plugin]
|
* a https://github.com/elastic/elasticsearch/tree/master/plugins/jvm-example[Java plugin]
|
||||||
which contains Java code.
|
which contains Java code.
|
||||||
|
|
||||||
|
@ -12,20 +10,6 @@ These examples provide the bare bones needed to get started. For more
|
||||||
information about how to write a plugin, we recommend looking at the plugins
|
information about how to write a plugin, we recommend looking at the plugins
|
||||||
listed in this documentation for inspiration.
|
listed in this documentation for inspiration.
|
||||||
|
|
||||||
[NOTE]
|
|
||||||
.Site plugins
|
|
||||||
====================================
|
|
||||||
|
|
||||||
The example site plugin mentioned above contains all of the scaffolding needed
|
|
||||||
for integrating with Gradle builds. If you don't plan on using Gradle, then all
|
|
||||||
you really need in your plugin is:
|
|
||||||
|
|
||||||
* The `plugin-descriptor.properties` file
|
|
||||||
* The `_site/` directory
|
|
||||||
* The `_site/index.html` file
|
|
||||||
|
|
||||||
====================================
|
|
||||||
|
|
||||||
[float]
|
[float]
|
||||||
=== Plugin descriptor file
|
=== Plugin descriptor file
|
||||||
|
|
||||||
|
@ -43,7 +27,7 @@ instance, see
|
||||||
https://github.com/elastic/elasticsearch/blob/master/plugins/site-example/build.gradle[`/plugins/site-example/build.gradle`].
|
https://github.com/elastic/elasticsearch/blob/master/plugins/site-example/build.gradle[`/plugins/site-example/build.gradle`].
|
||||||
|
|
||||||
[float]
|
[float]
|
||||||
==== Mandatory elements for all plugins
|
==== Mandatory elements for plugins
|
||||||
|
|
||||||
|
|
||||||
[cols="<,<,<",options="header",]
|
[cols="<,<,<",options="header",]
|
||||||
|
@ -56,23 +40,6 @@ https://github.com/elastic/elasticsearch/blob/master/plugins/site-example/build.
|
||||||
|
|
||||||
|`name` |String | the plugin name
|
|`name` |String | the plugin name
|
||||||
|
|
||||||
|=======================================================================
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[float]
|
|
||||||
==== Mandatory elements for Java plugins
|
|
||||||
|
|
||||||
|
|
||||||
[cols="<,<,<",options="header",]
|
|
||||||
|=======================================================================
|
|
||||||
|Element | Type | Description
|
|
||||||
|
|
||||||
|`jvm` |Boolean | true if the `classname` class should be loaded
|
|
||||||
from jar files in the root directory of the plugin.
|
|
||||||
Note that only jar files in the root directory are added to the classpath for the plugin!
|
|
||||||
If you need other resources, package them into a resources jar.
|
|
||||||
|
|
||||||
|`classname` |String | the name of the class to load, fully-qualified.
|
|`classname` |String | the name of the class to load, fully-qualified.
|
||||||
|
|
||||||
|`java.version` |String | version of java the code is built against.
|
|`java.version` |String | version of java the code is built against.
|
||||||
|
@ -83,6 +50,9 @@ of nonnegative decimal integers separated by "."'s and may have leading zeros.
|
||||||
|
|
||||||
|=======================================================================
|
|=======================================================================
|
||||||
|
|
||||||
|
Note that only jar files in the root directory are added to the classpath for the plugin!
|
||||||
|
If you need other resources, package them into a resources jar.
|
||||||
|
|
||||||
[IMPORTANT]
|
[IMPORTANT]
|
||||||
.Plugin release lifecycle
|
.Plugin release lifecycle
|
||||||
==============================================
|
==============================================
|
||||||
|
@ -94,20 +64,6 @@ in the presence of plugins with the incorrect `elasticsearch.version`.
|
||||||
==============================================
|
==============================================
|
||||||
|
|
||||||
|
|
||||||
[float]
|
|
||||||
==== Mandatory elements for Site plugins
|
|
||||||
|
|
||||||
|
|
||||||
[cols="<,<,<",options="header",]
|
|
||||||
|=======================================================================
|
|
||||||
|Element | Type | Description
|
|
||||||
|
|
||||||
|`site` |Boolean | true to indicate contents of the `_site/`
|
|
||||||
directory in the root of the plugin should be served.
|
|
||||||
|
|
||||||
|=======================================================================
|
|
||||||
|
|
||||||
|
|
||||||
[float]
|
[float]
|
||||||
=== Testing your plugin
|
=== Testing your plugin
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ consult this table:
|
||||||
|2.x |3.x |<<restart-upgrade,Full cluster restart>>
|
|2.x |3.x |<<restart-upgrade,Full cluster restart>>
|
||||||
|=======================================================================
|
|=======================================================================
|
||||||
|
|
||||||
TIP: Take plugins into consideration as well when upgrading. Most plugins will have to be upgraded alongside Elasticsearch, although some plugins accessed primarily through the browser (`_site` plugins) may continue to work given that API changes are compatible.
|
TIP: Take plugins into consideration as well when upgrading. Plugins must be upgraded alongside Elasticsearch.
|
||||||
|
|
||||||
include::backup.asciidoc[]
|
include::backup.asciidoc[]
|
||||||
|
|
||||||
|
|
|
@ -39,8 +39,5 @@ subprojects {
|
||||||
if (esplugin.isolated == false) {
|
if (esplugin.isolated == false) {
|
||||||
throw new InvalidModelException("Modules cannot disable isolation")
|
throw new InvalidModelException("Modules cannot disable isolation")
|
||||||
}
|
}
|
||||||
if (esplugin.jvm == false) {
|
|
||||||
throw new InvalidModelException("Modules must be jvm plugins")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,4 +11,3 @@
|
||||||
nodes.info: {}
|
nodes.info: {}
|
||||||
|
|
||||||
- match: { nodes.$master.modules.0.name: lang-expression }
|
- match: { nodes.$master.modules.0.name: lang-expression }
|
||||||
- match: { nodes.$master.modules.0.jvm: true }
|
|
||||||
|
|
|
@ -11,4 +11,3 @@
|
||||||
nodes.info: {}
|
nodes.info: {}
|
||||||
|
|
||||||
- match: { nodes.$master.modules.0.name: lang-groovy }
|
- match: { nodes.$master.modules.0.name: lang-groovy }
|
||||||
- match: { nodes.$master.modules.0.jvm: true }
|
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
nodes.info: {}
|
nodes.info: {}
|
||||||
|
|
||||||
- match: { nodes.$master.modules.0.name: lang-mustache }
|
- match: { nodes.$master.modules.0.name: lang-mustache }
|
||||||
- match: { nodes.$master.modules.0.jvm: true }
|
|
||||||
|
|
||||||
---
|
---
|
||||||
"Indexed template":
|
"Indexed template":
|
||||||
|
|
|
@ -11,4 +11,3 @@
|
||||||
nodes.info: {}
|
nodes.info: {}
|
||||||
|
|
||||||
- match: { nodes.$master.plugins.0.name: discovery-azure }
|
- match: { nodes.$master.plugins.0.name: discovery-azure }
|
||||||
- match: { nodes.$master.plugins.0.jvm: true }
|
|
||||||
|
|
|
@ -11,4 +11,3 @@
|
||||||
nodes.info: {}
|
nodes.info: {}
|
||||||
|
|
||||||
- match: { nodes.$master.plugins.0.name: discovery-ec2 }
|
- match: { nodes.$master.plugins.0.name: discovery-ec2 }
|
||||||
- match: { nodes.$master.plugins.0.jvm: true }
|
|
||||||
|
|
|
@ -11,4 +11,3 @@
|
||||||
nodes.info: {}
|
nodes.info: {}
|
||||||
|
|
||||||
- match: { nodes.$master.plugins.0.name: discovery-gce }
|
- match: { nodes.$master.plugins.0.name: discovery-gce }
|
||||||
- match: { nodes.$master.plugins.0.jvm: true }
|
|
||||||
|
|
|
@ -11,4 +11,3 @@
|
||||||
nodes.info: {}
|
nodes.info: {}
|
||||||
|
|
||||||
- match: { nodes.$master.plugins.0.name: discovery-multicast }
|
- match: { nodes.$master.plugins.0.name: discovery-multicast }
|
||||||
- match: { nodes.$master.plugins.0.jvm: true }
|
|
||||||
|
|
|
@ -11,4 +11,3 @@
|
||||||
nodes.info: {}
|
nodes.info: {}
|
||||||
|
|
||||||
- match: { nodes.$master.plugins.0.name: jvm-example }
|
- match: { nodes.$master.plugins.0.name: jvm-example }
|
||||||
- match: { nodes.$master.plugins.0.jvm: true }
|
|
||||||
|
|
|
@ -11,4 +11,3 @@
|
||||||
nodes.info: {}
|
nodes.info: {}
|
||||||
|
|
||||||
- match: { nodes.$master.plugins.0.name: lang-plan-a }
|
- match: { nodes.$master.plugins.0.name: lang-plan-a }
|
||||||
- match: { nodes.$master.plugins.0.jvm: true }
|
|
||||||
|
|
|
@ -11,4 +11,3 @@
|
||||||
nodes.info: {}
|
nodes.info: {}
|
||||||
|
|
||||||
- match: { nodes.$master.plugins.0.name: mapper-attachments }
|
- match: { nodes.$master.plugins.0.name: mapper-attachments }
|
||||||
- match: { nodes.$master.plugins.0.jvm: true }
|
|
||||||
|
|
|
@ -11,4 +11,3 @@
|
||||||
nodes.info: {}
|
nodes.info: {}
|
||||||
|
|
||||||
- match: { nodes.$master.plugins.0.name: repository-azure }
|
- match: { nodes.$master.plugins.0.name: repository-azure }
|
||||||
- match: { nodes.$master.plugins.0.jvm: true }
|
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
nodes.info: {}
|
nodes.info: {}
|
||||||
|
|
||||||
- match: { nodes.$master.plugins.0.name: repository-hdfs }
|
- match: { nodes.$master.plugins.0.name: repository-hdfs }
|
||||||
- match: { nodes.$master.plugins.0.jvm: true }
|
|
||||||
---
|
---
|
||||||
#
|
#
|
||||||
# Check that we can't use file:// repositories or anything like that
|
# Check that we can't use file:// repositories or anything like that
|
||||||
|
|
|
@ -11,4 +11,3 @@
|
||||||
nodes.info: {}
|
nodes.info: {}
|
||||||
|
|
||||||
- match: { nodes.$master.plugins.0.name: repository-s3 }
|
- match: { nodes.$master.plugins.0.name: repository-s3 }
|
||||||
- match: { nodes.$master.plugins.0.jvm: true }
|
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
/*
|
|
||||||
* Licensed to Elasticsearch under one or more contributor
|
|
||||||
* license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright
|
|
||||||
* ownership. Elasticsearch licenses this file to you under
|
|
||||||
* the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
* not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
esplugin {
|
|
||||||
description 'Demonstrates how to serve resources via elasticsearch.'
|
|
||||||
jvm false
|
|
||||||
site true
|
|
||||||
}
|
|
||||||
|
|
||||||
// no unit tests
|
|
||||||
test.enabled = false
|
|
|
@ -1,6 +0,0 @@
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Page title</title>
|
|
||||||
</head>
|
|
||||||
<body>Page body</body>
|
|
||||||
</html>
|
|
|
@ -1,59 +0,0 @@
|
||||||
/*
|
|
||||||
* Licensed to Elasticsearch under one or more contributor
|
|
||||||
* license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright
|
|
||||||
* ownership. Elasticsearch licenses this file to you under
|
|
||||||
* the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
* not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.elasticsearch.example;
|
|
||||||
|
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
|
||||||
import org.apache.http.impl.client.HttpClients;
|
|
||||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
|
||||||
import org.elasticsearch.common.network.NetworkAddress;
|
|
||||||
import org.elasticsearch.test.ESIntegTestCase;
|
|
||||||
import org.elasticsearch.test.ExternalTestCluster;
|
|
||||||
import org.elasticsearch.test.TestCluster;
|
|
||||||
import org.elasticsearch.test.rest.client.RestResponse;
|
|
||||||
import org.elasticsearch.test.rest.client.http.HttpRequestBuilder;
|
|
||||||
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* verifies content is actually served for the site plugin
|
|
||||||
*/
|
|
||||||
public class SiteContentsIT extends ESIntegTestCase {
|
|
||||||
|
|
||||||
// TODO: probably a better way to test, but we don't want to really
|
|
||||||
// define a fake rest spec or anything?
|
|
||||||
public void test() throws Exception {
|
|
||||||
TestCluster cluster = cluster();
|
|
||||||
assumeTrue("this test will not work from an IDE unless you pass tests.cluster pointing to a running instance", cluster instanceof ExternalTestCluster);
|
|
||||||
ExternalTestCluster externalCluster = (ExternalTestCluster) cluster;
|
|
||||||
try (CloseableHttpClient httpClient = HttpClients.createMinimal(new PoolingHttpClientConnectionManager(15, TimeUnit.SECONDS))) {
|
|
||||||
for (InetSocketAddress address : externalCluster.httpAddresses()) {
|
|
||||||
RestResponse restResponse = new RestResponse(
|
|
||||||
new HttpRequestBuilder(httpClient)
|
|
||||||
.host(NetworkAddress.formatAddress(address.getAddress())).port(address.getPort())
|
|
||||||
.path("/_plugin/site-example/")
|
|
||||||
.method("GET").execute());
|
|
||||||
assertEquals(200, restResponse.getStatusCode());
|
|
||||||
String body = restResponse.getBodyAsString();
|
|
||||||
assertTrue("unexpected body contents: " + body, body.contains("<body>Page body</body>"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
/*
|
|
||||||
* Licensed to Elasticsearch under one or more contributor
|
|
||||||
* license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright
|
|
||||||
* ownership. Elasticsearch licenses this file to you under
|
|
||||||
* the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
* not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.elasticsearch.example;
|
|
||||||
|
|
||||||
import com.carrotsearch.randomizedtesting.annotations.Name;
|
|
||||||
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
|
|
||||||
import org.elasticsearch.test.rest.ESRestTestCase;
|
|
||||||
import org.elasticsearch.test.rest.RestTestCandidate;
|
|
||||||
import org.elasticsearch.test.rest.parser.RestTestParseException;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class SiteRestIT extends ESRestTestCase {
|
|
||||||
|
|
||||||
public SiteRestIT(@Name("yaml") RestTestCandidate testCandidate) {
|
|
||||||
super(testCandidate);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ParametersFactory
|
|
||||||
public static Iterable<Object[]> parameters() throws IOException, RestTestParseException {
|
|
||||||
return ESRestTestCase.createParameters(0, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
# Integration tests for Example site plugin
|
|
||||||
#
|
|
||||||
"Example site loaded":
|
|
||||||
- do:
|
|
||||||
cluster.state: {}
|
|
||||||
|
|
||||||
# Get master node id
|
|
||||||
- set: { master_node: master }
|
|
||||||
|
|
||||||
- do:
|
|
||||||
nodes.info: {}
|
|
||||||
|
|
||||||
- match: { nodes.$master.plugins.0.name: site-example }
|
|
||||||
- match: { nodes.$master.plugins.0.jvm: false }
|
|
||||||
- match: { nodes.$master.plugins.0.site: true }
|
|
|
@ -11,4 +11,3 @@
|
||||||
nodes.info: {}
|
nodes.info: {}
|
||||||
|
|
||||||
- match: { nodes.$master.plugins.0.name: store-smb }
|
- match: { nodes.$master.plugins.0.name: store-smb }
|
||||||
- match: { nodes.$master.plugins.0.jvm: true }
|
|
||||||
|
|
|
@ -196,7 +196,6 @@ public class PluginManagerTests extends ESIntegTestCase {
|
||||||
"version", "1.0",
|
"version", "1.0",
|
||||||
"elasticsearch.version", Version.CURRENT.toString(),
|
"elasticsearch.version", Version.CURRENT.toString(),
|
||||||
"java.version", System.getProperty("java.specification.version"),
|
"java.version", System.getProperty("java.specification.version"),
|
||||||
"jvm", "true",
|
|
||||||
"classname", "FakePlugin");
|
"classname", "FakePlugin");
|
||||||
assertStatus("install", USAGE);
|
assertStatus("install", USAGE);
|
||||||
}
|
}
|
||||||
|
@ -216,7 +215,6 @@ public class PluginManagerTests extends ESIntegTestCase {
|
||||||
"version", "1.0",
|
"version", "1.0",
|
||||||
"elasticsearch.version", Version.CURRENT.toString(),
|
"elasticsearch.version", Version.CURRENT.toString(),
|
||||||
"java.version", System.getProperty("java.specification.version"),
|
"java.version", System.getProperty("java.specification.version"),
|
||||||
"jvm", "true",
|
|
||||||
"classname", "FakePlugin");
|
"classname", "FakePlugin");
|
||||||
|
|
||||||
Path binDir = environment.binFile();
|
Path binDir = environment.binFile();
|
||||||
|
@ -260,7 +258,6 @@ public class PluginManagerTests extends ESIntegTestCase {
|
||||||
"version", "1.0",
|
"version", "1.0",
|
||||||
"elasticsearch.version", Version.CURRENT.toString(),
|
"elasticsearch.version", Version.CURRENT.toString(),
|
||||||
"java.version", System.getProperty("java.specification.version"),
|
"java.version", System.getProperty("java.specification.version"),
|
||||||
"jvm", "true",
|
|
||||||
"classname", "FakePlugin");
|
"classname", "FakePlugin");
|
||||||
|
|
||||||
Path pluginConfigDir = environment.configFile().resolve(pluginName);
|
Path pluginConfigDir = environment.configFile().resolve(pluginName);
|
||||||
|
@ -296,7 +293,6 @@ public class PluginManagerTests extends ESIntegTestCase {
|
||||||
"version", "2.0",
|
"version", "2.0",
|
||||||
"elasticsearch.version", Version.CURRENT.toString(),
|
"elasticsearch.version", Version.CURRENT.toString(),
|
||||||
"java.version", System.getProperty("java.specification.version"),
|
"java.version", System.getProperty("java.specification.version"),
|
||||||
"jvm", "true",
|
|
||||||
"classname", "FakePlugin");
|
"classname", "FakePlugin");
|
||||||
|
|
||||||
assertStatusOk(String.format(Locale.ROOT, "install %s --verbose", pluginUrl));
|
assertStatusOk(String.format(Locale.ROOT, "install %s --verbose", pluginUrl));
|
||||||
|
@ -361,7 +357,6 @@ public class PluginManagerTests extends ESIntegTestCase {
|
||||||
"version", "1.0",
|
"version", "1.0",
|
||||||
"elasticsearch.version", Version.CURRENT.toString(),
|
"elasticsearch.version", Version.CURRENT.toString(),
|
||||||
"java.version", System.getProperty("java.specification.version"),
|
"java.version", System.getProperty("java.specification.version"),
|
||||||
"jvm", "true",
|
|
||||||
"classname", "FakePlugin");
|
"classname", "FakePlugin");
|
||||||
|
|
||||||
Path binDir = environment.binFile();
|
Path binDir = environment.binFile();
|
||||||
|
@ -392,16 +387,13 @@ public class PluginManagerTests extends ESIntegTestCase {
|
||||||
"version", "1.0",
|
"version", "1.0",
|
||||||
"elasticsearch.version", Version.CURRENT.toString(),
|
"elasticsearch.version", Version.CURRENT.toString(),
|
||||||
"java.version", System.getProperty("java.specification.version"),
|
"java.version", System.getProperty("java.specification.version"),
|
||||||
"jvm", "true",
|
|
||||||
"classname", "FakePlugin");
|
"classname", "FakePlugin");
|
||||||
System.err.println("install " + pluginUrl + " --verbose");
|
System.err.println("install " + pluginUrl + " --verbose");
|
||||||
ExitStatus status = new PluginManagerCliParser(terminal).execute(args("install " + pluginUrl + " --verbose"));
|
ExitStatus status = new PluginManagerCliParser(terminal).execute(args("install " + pluginUrl + " --verbose"));
|
||||||
assertThat("Terminal output was: " + terminal.getTerminalOutput(), status, is(ExitStatus.OK));
|
assertThat("Terminal output was: " + terminal.getTerminalOutput(), status, is(ExitStatus.OK));
|
||||||
assertThat(terminal.getTerminalOutput(), hasItem(containsString("Name: fake-plugin")));
|
assertThat(terminal.getTerminalOutput(), hasItem(containsString("Name: fake-plugin")));
|
||||||
assertThat(terminal.getTerminalOutput(), hasItem(containsString("Description: fake desc")));
|
assertThat(terminal.getTerminalOutput(), hasItem(containsString("Description: fake desc")));
|
||||||
assertThat(terminal.getTerminalOutput(), hasItem(containsString("Site: false")));
|
|
||||||
assertThat(terminal.getTerminalOutput(), hasItem(containsString("Version: 1.0")));
|
assertThat(terminal.getTerminalOutput(), hasItem(containsString("Version: 1.0")));
|
||||||
assertThat(terminal.getTerminalOutput(), hasItem(containsString("JVM: true")));
|
|
||||||
assertThatPluginIsListed(pluginName);
|
assertThatPluginIsListed(pluginName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -414,7 +406,6 @@ public class PluginManagerTests extends ESIntegTestCase {
|
||||||
"version", "1.0",
|
"version", "1.0",
|
||||||
"elasticsearch.version", Version.CURRENT.toString(),
|
"elasticsearch.version", Version.CURRENT.toString(),
|
||||||
"java.version", System.getProperty("java.specification.version"),
|
"java.version", System.getProperty("java.specification.version"),
|
||||||
"jvm", "true",
|
|
||||||
"classname", "FakePlugin");
|
"classname", "FakePlugin");
|
||||||
ExitStatus status = new PluginManagerCliParser(terminal).execute(args("install " + pluginUrl));
|
ExitStatus status = new PluginManagerCliParser(terminal).execute(args("install " + pluginUrl));
|
||||||
assertThat("Terminal output was: " + terminal.getTerminalOutput(), status, is(ExitStatus.OK));
|
assertThat("Terminal output was: " + terminal.getTerminalOutput(), status, is(ExitStatus.OK));
|
||||||
|
@ -447,7 +438,6 @@ public class PluginManagerTests extends ESIntegTestCase {
|
||||||
"elasticsearch.version", Version.CURRENT.toString(),
|
"elasticsearch.version", Version.CURRENT.toString(),
|
||||||
"java.version", System.getProperty("java.specification.version"),
|
"java.version", System.getProperty("java.specification.version"),
|
||||||
"isolated", "false",
|
"isolated", "false",
|
||||||
"jvm", "true",
|
|
||||||
"classname", "FakePlugin");
|
"classname", "FakePlugin");
|
||||||
|
|
||||||
// install
|
// install
|
||||||
|
@ -465,63 +455,20 @@ public class PluginManagerTests extends ESIntegTestCase {
|
||||||
assertTrue(foundExpectedMessage);
|
assertTrue(foundExpectedMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testInstallSitePluginVerbose() throws IOException {
|
|
||||||
String pluginName = "fake-plugin";
|
|
||||||
Path pluginDir = createTempDir().resolve(pluginName);
|
|
||||||
Files.createDirectories(pluginDir.resolve("_site"));
|
|
||||||
Files.createFile(pluginDir.resolve("_site").resolve("somefile"));
|
|
||||||
String pluginUrl = createPlugin(pluginDir,
|
|
||||||
"description", "fake desc",
|
|
||||||
"name", pluginName,
|
|
||||||
"version", "1.0",
|
|
||||||
"site", "true");
|
|
||||||
ExitStatus status = new PluginManagerCliParser(terminal).execute(args("install " + pluginUrl + " --verbose"));
|
|
||||||
assertThat("Terminal output was: " + terminal.getTerminalOutput(), status, is(ExitStatus.OK));
|
|
||||||
assertThat(terminal.getTerminalOutput(), hasItem(containsString("Name: fake-plugin")));
|
|
||||||
assertThat(terminal.getTerminalOutput(), hasItem(containsString("Description: fake desc")));
|
|
||||||
assertThat(terminal.getTerminalOutput(), hasItem(containsString("Site: true")));
|
|
||||||
assertThat(terminal.getTerminalOutput(), hasItem(containsString("Version: 1.0")));
|
|
||||||
assertThat(terminal.getTerminalOutput(), hasItem(containsString("JVM: false")));
|
|
||||||
assertThatPluginIsListed(pluginName);
|
|
||||||
// We want to check that Plugin Manager moves content to _site
|
|
||||||
assertFileExists(environment.pluginsFile().resolve(pluginName).resolve("_site"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testInstallSitePlugin() throws IOException {
|
|
||||||
String pluginName = "fake-plugin";
|
|
||||||
Path pluginDir = createTempDir().resolve(pluginName);
|
|
||||||
Files.createDirectories(pluginDir.resolve("_site"));
|
|
||||||
Files.createFile(pluginDir.resolve("_site").resolve("somefile"));
|
|
||||||
String pluginUrl = createPlugin(pluginDir,
|
|
||||||
"description", "fake desc",
|
|
||||||
"name", pluginName,
|
|
||||||
"version", "1.0",
|
|
||||||
"site", "true");
|
|
||||||
ExitStatus status = new PluginManagerCliParser(terminal).execute(args("install " + pluginUrl));
|
|
||||||
assertThat("Terminal output was: " + terminal.getTerminalOutput(), status, is(ExitStatus.OK));
|
|
||||||
assertThat(terminal.getTerminalOutput(), not(hasItem(containsString("Name: fake-plugin"))));
|
|
||||||
assertThat(terminal.getTerminalOutput(), not(hasItem(containsString("Description:"))));
|
|
||||||
assertThat(terminal.getTerminalOutput(), not(hasItem(containsString("Site:"))));
|
|
||||||
assertThat(terminal.getTerminalOutput(), not(hasItem(containsString("Version:"))));
|
|
||||||
assertThat(terminal.getTerminalOutput(), not(hasItem(containsString("JVM:"))));
|
|
||||||
assertThatPluginIsListed(pluginName);
|
|
||||||
// We want to check that Plugin Manager moves content to _site
|
|
||||||
assertFileExists(environment.pluginsFile().resolve(pluginName).resolve("_site"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testInstallPluginWithBadChecksum() throws IOException {
|
public void testInstallPluginWithBadChecksum() throws IOException {
|
||||||
String pluginName = "fake-plugin";
|
String pluginName = "fake-plugin";
|
||||||
Path pluginDir = createTempDir().resolve(pluginName);
|
Path pluginDir = createTempDir().resolve(pluginName);
|
||||||
Files.createDirectories(pluginDir.resolve("_site"));
|
|
||||||
Files.createFile(pluginDir.resolve("_site").resolve("somefile"));
|
|
||||||
String pluginUrl = createPluginWithBadChecksum(pluginDir,
|
String pluginUrl = createPluginWithBadChecksum(pluginDir,
|
||||||
"description", "fake desc",
|
"description", "fake desc",
|
||||||
"version", "1.0",
|
"name", pluginName,
|
||||||
"site", "true");
|
"version", "1.0",
|
||||||
|
"elasticsearch.version", Version.CURRENT.toString(),
|
||||||
|
"java.version", System.getProperty("java.specification.version"),
|
||||||
|
"classname", "FakePlugin");
|
||||||
assertStatus(String.format(Locale.ROOT, "install %s --verbose", pluginUrl),
|
assertStatus(String.format(Locale.ROOT, "install %s --verbose", pluginUrl),
|
||||||
ExitStatus.IO_ERROR);
|
ExitStatus.IO_ERROR);
|
||||||
assertThatPluginIsNotListed(pluginName);
|
assertThatPluginIsNotListed(pluginName);
|
||||||
assertFileNotExists(environment.pluginsFile().resolve(pluginName).resolve("_site"));
|
assertFileNotExists(environment.pluginsFile().resolve(pluginName));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void singlePluginInstallAndRemove(String pluginDescriptor, String pluginName, String pluginCoordinates) throws IOException {
|
private void singlePluginInstallAndRemove(String pluginDescriptor, String pluginName, String pluginCoordinates) throws IOException {
|
||||||
|
@ -606,7 +553,6 @@ public class PluginManagerTests extends ESIntegTestCase {
|
||||||
"version", "1.0.0",
|
"version", "1.0.0",
|
||||||
"elasticsearch.version", Version.CURRENT.toString(),
|
"elasticsearch.version", Version.CURRENT.toString(),
|
||||||
"java.version", System.getProperty("java.specification.version"),
|
"java.version", System.getProperty("java.specification.version"),
|
||||||
"jvm", "true",
|
|
||||||
"classname", "FakePlugin");
|
"classname", "FakePlugin");
|
||||||
|
|
||||||
// We want to remove plugin with plugin short name
|
// We want to remove plugin with plugin short name
|
||||||
|
|
|
@ -263,12 +263,6 @@ fi
|
||||||
install_and_check_plugin repository s3 aws-java-sdk-core-*.jar
|
install_and_check_plugin repository s3 aws-java-sdk-core-*.jar
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "[$GROUP] install site example" {
|
|
||||||
# Doesn't use install_and_check_plugin because this is a site plugin
|
|
||||||
install_plugin site-example $(readlink -m site-example-*.zip)
|
|
||||||
assert_file_exist "$ESHOME/plugins/site-example/_site/index.html"
|
|
||||||
}
|
|
||||||
|
|
||||||
@test "[$GROUP] install store-smb plugin" {
|
@test "[$GROUP] install store-smb plugin" {
|
||||||
install_and_check_plugin store smb
|
install_and_check_plugin store smb
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,5 @@
|
||||||
name .+ \n
|
name .+ \n
|
||||||
component .+ \n
|
component .+ \n
|
||||||
version .+ \n
|
version .+ \n
|
||||||
type .+ \n
|
|
||||||
url .+ \n
|
|
||||||
description .+ \n
|
description .+ \n
|
||||||
$/
|
$/
|
||||||
|
|
|
@ -34,7 +34,6 @@ List projects = [
|
||||||
'plugins:repository-hdfs',
|
'plugins:repository-hdfs',
|
||||||
'plugins:repository-s3',
|
'plugins:repository-s3',
|
||||||
'plugins:jvm-example',
|
'plugins:jvm-example',
|
||||||
'plugins:site-example',
|
|
||||||
'plugins:store-smb',
|
'plugins:store-smb',
|
||||||
'qa:evil-tests',
|
'qa:evil-tests',
|
||||||
'qa:smoke-test-client',
|
'qa:smoke-test-client',
|
||||||
|
|
|
@ -154,11 +154,9 @@ public class BootstrapForTesting {
|
||||||
try (InputStream stream = url.openStream()) {
|
try (InputStream stream = url.openStream()) {
|
||||||
properties.load(stream);
|
properties.load(stream);
|
||||||
}
|
}
|
||||||
if (Boolean.parseBoolean(properties.getProperty("jvm"))) {
|
String clazz = properties.getProperty("classname");
|
||||||
String clazz = properties.getProperty("classname");
|
if (clazz != null) {
|
||||||
if (clazz != null) {
|
Class.forName(clazz);
|
||||||
Class.forName(clazz);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|
|
@ -731,82 +731,6 @@ public class ElasticsearchAssertions {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void assertNodeContainsPlugins(NodesInfoResponse response, String nodeId,
|
|
||||||
List<String> expectedJvmPluginNames,
|
|
||||||
List<String> expectedJvmPluginDescriptions,
|
|
||||||
List<String> expectedJvmVersions,
|
|
||||||
List<String> expectedSitePluginNames,
|
|
||||||
List<String> expectedSitePluginDescriptions,
|
|
||||||
List<String> expectedSiteVersions) {
|
|
||||||
|
|
||||||
Assert.assertThat(response.getNodesMap().get(nodeId), notNullValue());
|
|
||||||
|
|
||||||
PluginsAndModules plugins = response.getNodesMap().get(nodeId).getPlugins();
|
|
||||||
Assert.assertThat(plugins, notNullValue());
|
|
||||||
|
|
||||||
List<String> pluginNames = filterAndMap(plugins, jvmPluginPredicate, nameFunction);
|
|
||||||
for (String expectedJvmPluginName : expectedJvmPluginNames) {
|
|
||||||
Assert.assertThat(pluginNames, hasItem(expectedJvmPluginName));
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> pluginDescriptions = filterAndMap(plugins, jvmPluginPredicate, descriptionFunction);
|
|
||||||
for (String expectedJvmPluginDescription : expectedJvmPluginDescriptions) {
|
|
||||||
Assert.assertThat(pluginDescriptions, hasItem(expectedJvmPluginDescription));
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> jvmPluginVersions = filterAndMap(plugins, jvmPluginPredicate, versionFunction);
|
|
||||||
for (String pluginVersion : expectedJvmVersions) {
|
|
||||||
Assert.assertThat(jvmPluginVersions, hasItem(pluginVersion));
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean anyHaveUrls =
|
|
||||||
plugins
|
|
||||||
.getPluginInfos()
|
|
||||||
.stream()
|
|
||||||
.filter(jvmPluginPredicate.and(sitePluginPredicate.negate()))
|
|
||||||
.map(urlFunction)
|
|
||||||
.anyMatch(p -> p != null);
|
|
||||||
assertFalse(anyHaveUrls);
|
|
||||||
|
|
||||||
List<String> sitePluginNames = filterAndMap(plugins, sitePluginPredicate, nameFunction);
|
|
||||||
|
|
||||||
Assert.assertThat(sitePluginNames.isEmpty(), is(expectedSitePluginNames.isEmpty()));
|
|
||||||
for (String expectedSitePluginName : expectedSitePluginNames) {
|
|
||||||
Assert.assertThat(sitePluginNames, hasItem(expectedSitePluginName));
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> sitePluginDescriptions = filterAndMap(plugins, sitePluginPredicate, descriptionFunction);
|
|
||||||
Assert.assertThat(sitePluginDescriptions.isEmpty(), is(expectedSitePluginDescriptions.isEmpty()));
|
|
||||||
for (String sitePluginDescription : expectedSitePluginDescriptions) {
|
|
||||||
Assert.assertThat(sitePluginDescriptions, hasItem(sitePluginDescription));
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> sitePluginUrls = filterAndMap(plugins, sitePluginPredicate, urlFunction);
|
|
||||||
Assert.assertThat(sitePluginUrls, not(contains(nullValue())));
|
|
||||||
|
|
||||||
List<String> sitePluginVersions = filterAndMap(plugins, sitePluginPredicate, versionFunction);
|
|
||||||
Assert.assertThat(sitePluginVersions.isEmpty(), is(expectedSiteVersions.isEmpty()));
|
|
||||||
for (String pluginVersion : expectedSiteVersions) {
|
|
||||||
Assert.assertThat(sitePluginVersions, hasItem(pluginVersion));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<String> filterAndMap(PluginsAndModules pluginsInfo, Predicate<PluginInfo> predicate, Function<PluginInfo, String> function) {
|
|
||||||
return pluginsInfo.getPluginInfos().stream().filter(predicate).map(function).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Predicate<PluginInfo> jvmPluginPredicate = p -> p.isJvm();
|
|
||||||
|
|
||||||
private static Predicate<PluginInfo> sitePluginPredicate = p -> p.isSite();
|
|
||||||
|
|
||||||
private static Function<PluginInfo, String> nameFunction = p -> p.getName();
|
|
||||||
|
|
||||||
private static Function<PluginInfo, String> descriptionFunction = p -> p.getDescription();
|
|
||||||
|
|
||||||
private static Function<PluginInfo, String> urlFunction = p -> p.getUrl();
|
|
||||||
|
|
||||||
private static Function<PluginInfo, String> versionFunction = p -> p.getVersion();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a file exists
|
* Check if a file exists
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue