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:
Ryan Ernst 2016-01-16 21:54:05 -08:00
parent b4538a5676
commit 3b78267c71
42 changed files with 79 additions and 1033 deletions

View File

@ -112,9 +112,6 @@ public class PluginBuildPlugin extends BuildPlugin {
include 'config/**'
include 'bin/**'
}
from('src/site') {
include '_site/**'
}
}
project.assemble.dependsOn(bundle)

View File

@ -36,15 +36,9 @@ class PluginPropertiesExtension {
@Input
String description
@Input
boolean jvm = true
@Input
String classname
@Input
boolean site = false
@Input
boolean isolated = true

View File

@ -51,11 +51,11 @@ class PluginPropertiesTask extends Copy {
if (extension.description == null) {
throw new InvalidUserDataException('description is a required setting for esplugin')
}
if (extension.jvm && extension.classname == null) {
throw new InvalidUserDataException('classname is a required setting for esplugin with jvm=true')
if (extension.classname == null) {
throw new InvalidUserDataException('classname is a required setting for esplugin')
}
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"
logger.warn("${'=' * warning.length()}\n${warning}\n${'=' * warning.length()}")
}
@ -74,10 +74,8 @@ class PluginPropertiesTask extends Copy {
'version': extension.version,
'elasticsearchVersion': VersionProperties.elasticsearch,
'javaVersion': project.targetCompatibility as String,
'jvm': extension.jvm as String,
'site': extension.site as String,
'isolated': extension.isolated as String,
'classname': extension.jvm ? extension.classname : 'NA'
'classname': extension.classname
]
}
}

View File

@ -2,26 +2,13 @@
# This file must exist as 'plugin-descriptor.properties' at
# the root directory of all plugins.
#
# A plugin can be 'site', 'jvm', or both.
#
### 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"
### example plugin for "foo"
#
# foo.zip <-- zip file for the plugin, with this structure:
# <arbitrary name1>.jar <-- classes, resources, dependencies
# <arbitrary nameN>.jar <-- any number of jars
# plugin-descriptor.properties <-- example contents below:
#
# jvm=true
# classname=foo.bar.BazPlugin
# description=My cool plugin
# version=2.0
@ -38,21 +25,6 @@ version=${version}
#
# 'name': the plugin 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=${classname}

View File

@ -51,7 +51,7 @@ import static org.elasticsearch.rest.RestStatus.NOT_FOUND;
import static org.elasticsearch.rest.RestStatus.OK;
/**
*
* A component to serve http requests, backed by rest handlers.
*/
public class HttpServer extends AbstractLifecycleComponent<HttpServer> {
@ -63,10 +63,6 @@ public class HttpServer extends AbstractLifecycleComponent<HttpServer> {
private final NodeService nodeService;
private final boolean disableSites;
private final PluginSiteFilter pluginSiteFilter = new PluginSiteFilter();
@Inject
public HttpServer(Settings settings, Environment environment, HttpServerTransport transport,
RestController restController,
@ -77,9 +73,6 @@ public class HttpServer extends AbstractLifecycleComponent<HttpServer> {
this.restController = restController;
this.nodeService = nodeService;
nodeService.setHttpServer(this);
this.disableSites = this.settings.getAsBoolean("http.disable_sites", false);
transport.httpServerAdapter(new Dispatcher(this));
}
@ -126,27 +119,13 @@ public class HttpServer extends AbstractLifecycleComponent<HttpServer> {
}
public void internalDispatchRequest(final HttpRequest request, final HttpChannel channel) {
String rawPath = request.rawPath();
if (rawPath.startsWith("/_plugin/")) {
RestFilterChain filterChain = restController.filterChain(pluginSiteFilter);
filterChain.continueProcessing(request, channel);
return;
} else if (rawPath.equals("/favicon.ico")) {
if (request.rawPath().equals("/favicon.ico")) {
handleFavicon(request, channel);
return;
}
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) {
if (request.method() == RestRequest.Method.GET) {
try {
@ -163,129 +142,4 @@ public class HttpServer extends AbstractLifecycleComponent<HttpServer> {
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;
}

View File

@ -20,9 +20,9 @@ package org.elasticsearch.plugins;
public class DummyPluginInfo extends PluginInfo {
private DummyPluginInfo(String name, String description, boolean site, String version, boolean jvm, String classname, boolean isolated) {
super(name, description, site, version, jvm, classname, isolated);
private DummyPluginInfo(String name, String description, String version, String classname, boolean 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);
}

View File

@ -42,19 +42,14 @@ public class PluginInfo implements Streamable, ToXContent {
static final XContentBuilderString NAME = new XContentBuilderString("name");
static final XContentBuilderString DESCRIPTION = new XContentBuilderString("description");
static final XContentBuilderString URL = new XContentBuilderString("url");
static final XContentBuilderString SITE = new XContentBuilderString("site");
static final XContentBuilderString VERSION = new XContentBuilderString("version");
static final XContentBuilderString JVM = new XContentBuilderString("jvm");
static final XContentBuilderString CLASSNAME = new XContentBuilderString("classname");
static final XContentBuilderString ISOLATED = new XContentBuilderString("isolated");
}
private String name;
private String description;
private boolean site;
private String version;
private boolean jvm;
private String classname;
private boolean isolated;
@ -66,15 +61,11 @@ public class PluginInfo implements Streamable, ToXContent {
*
* @param name Its name
* @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
*/
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.description = description;
this.site = site;
this.jvm = jvm;
this.version = version;
this.classname = classname;
this.isolated = isolated;
@ -101,43 +92,28 @@ public class PluginInfo implements Streamable, ToXContent {
throw new IllegalArgumentException("Property [version] is missing for plugin [" + name + "]");
}
boolean jvm = Boolean.parseBoolean(props.getProperty("jvm"));
boolean site = Boolean.parseBoolean(props.getProperty("site"));
if (jvm == false && site == false) {
throw new IllegalArgumentException("Plugin [" + name + "] must be at least a jvm or site plugin");
String esVersionString = props.getProperty("elasticsearch.version");
if (esVersionString == null) {
throw new IllegalArgumentException("Property [elasticsearch.version] is missing for plugin [" + name + "]");
}
boolean isolated = true;
String classname = "NA";
if (jvm) {
String esVersionString = props.getProperty("elasticsearch.version");
if (esVersionString == null) {
throw new IllegalArgumentException("Property [elasticsearch.version] is missing for jvm plugin [" + name + "]");
}
Version esVersion = Version.fromString(esVersionString);
if (esVersion.equals(Version.CURRENT) == false) {
throw new IllegalArgumentException("Plugin [" + name + "] is incompatible with Elasticsearch [" + Version.CURRENT.toString() +
"]. Was designed for version [" + esVersionString + "]");
}
String javaVersionString = props.getProperty("java.version");
if (javaVersionString == null) {
throw new IllegalArgumentException("Property [java.version] is missing for jvm 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 + "]");
}
Version esVersion = Version.fromString(esVersionString);
if (esVersion.equals(Version.CURRENT) == false) {
throw new IllegalArgumentException("Plugin [" + name + "] is incompatible with Elasticsearch [" + Version.CURRENT.toString() +
"]. Was designed for version [" + esVersionString + "]");
}
String javaVersionString = props.getProperty("java.version");
if (javaVersionString == null) {
throw new IllegalArgumentException("Property [java.version] is missing for plugin [" + name + "]");
}
JarHell.checkVersionFormat(javaVersionString);
JarHell.checkJavaVersion(name, javaVersionString);
boolean isolated = Boolean.parseBoolean(props.getProperty("isolated", "true"));
String classname = props.getProperty("classname");
if (classname == null) {
throw new IllegalArgumentException("Property [classname] is missing for plugin [" + name + "]");
}
if (site) {
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);
return new PluginInfo(name, description, version, classname, isolated);
}
/**
@ -155,46 +131,19 @@ public class PluginInfo implements Streamable, ToXContent {
}
/**
* @return true if it's a site plugin
*/
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
* @return true if plugin has isolated classloader
*/
public boolean isIsolated() {
return isolated;
}
/**
* @return jvm plugin's classname
* @return plugin's classname
*/
public String getClassname() {
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
*/
@ -212,8 +161,6 @@ public class PluginInfo implements Streamable, ToXContent {
public void readFrom(StreamInput in) throws IOException {
this.name = in.readString();
this.description = in.readString();
this.site = in.readBoolean();
this.jvm = in.readBoolean();
this.version = in.readString();
this.classname = in.readString();
this.isolated = in.readBoolean();
@ -223,8 +170,6 @@ public class PluginInfo implements Streamable, ToXContent {
public void writeTo(StreamOutput out) throws IOException {
out.writeString(name);
out.writeString(description);
out.writeBoolean(site);
out.writeBoolean(jvm);
out.writeString(version);
out.writeString(classname);
out.writeBoolean(isolated);
@ -236,15 +181,8 @@ public class PluginInfo implements Streamable, ToXContent {
builder.field(Fields.NAME, name);
builder.field(Fields.VERSION, version);
builder.field(Fields.DESCRIPTION, description);
if (site) {
builder.field(Fields.URL, getUrl());
}
builder.field(Fields.JVM, jvm);
if (jvm) {
builder.field(Fields.CLASSNAME, classname);
builder.field(Fields.ISOLATED, isolated);
}
builder.field(Fields.SITE, site);
builder.field(Fields.CLASSNAME, classname);
builder.field(Fields.ISOLATED, isolated);
builder.endObject();
return builder;
@ -274,14 +212,9 @@ public class PluginInfo implements Streamable, ToXContent {
.append("- Plugin information:\n")
.append("Name: ").append(name).append("\n")
.append("Description: ").append(description).append("\n")
.append("Site: ").append(site).append("\n")
.append("Version: ").append(version).append("\n")
.append("JVM: ").append(jvm).append("\n");
if (jvm) {
information.append(" * Classname: ").append(classname).append("\n");
information.append(" * Isolated: ").append(isolated);
}
.append(" * Classname: ").append(classname).append("\n")
.append(" * Isolated: ").append(isolated);
return information.toString();
}

View File

@ -258,9 +258,7 @@ public class PluginManager {
}
// check for jar hell before any copying
if (info.isJvm()) {
jarHellCheck(root, info.isIsolated());
}
jarHellCheck(root, info.isIsolated());
// read optional security policy (extra permissions)
// if it exists, confirm or warn the user

View File

@ -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
for (Class<? extends Plugin> pluginClass : classpathPlugins) {
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()) {
logger.trace("plugin loaded from classpath [{}]", pluginInfo);
}
@ -136,18 +136,10 @@ public class PluginsService extends AbstractComponent {
plugins = Collections.unmodifiableList(pluginsLoaded);
// We need to build a List of jvm and site plugins for checking mandatory plugins
Map<String, Plugin> jvmPlugins = new HashMap<>();
List<String> sitePlugins = new ArrayList<>();
// We need to build a List of plugins for checking mandatory plugins
Set<String> pluginsNames = new HashSet<>();
for (Tuple<PluginInfo, Plugin> tuple : plugins) {
PluginInfo info = tuple.v1();
if (info.isJvm()) {
jvmPlugins.put(info.getName(), tuple.v2());
}
if (info.isSite()) {
sitePlugins.add(info.getName());
}
pluginsNames.add(tuple.v1().getName());
}
// Checking expected plugins
@ -155,7 +147,7 @@ public class PluginsService extends AbstractComponent {
if (mandatoryPlugins != null) {
Set<String> missingPlugins = new HashSet<>();
for (String mandatoryPlugin : mandatoryPlugins) {
if (!jvmPlugins.containsKey(mandatoryPlugin) && !sitePlugins.contains(mandatoryPlugin) && !missingPlugins.contains(mandatoryPlugin)) {
if (!pluginsNames.contains(mandatoryPlugin) && !missingPlugins.contains(mandatoryPlugin)) {
missingPlugins.add(mandatoryPlugin);
}
}
@ -175,10 +167,11 @@ public class PluginsService extends AbstractComponent {
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<>();
for (Plugin plugin : jvmPlugins.values()) {
for (Tuple<PluginInfo, Plugin> pluginEntry : plugins) {
Plugin plugin = pluginEntry.v2();
List<OnModuleReference> list = new ArrayList<>();
for (Method method : plugin.getClass().getMethods()) {
if (!method.getName().equals("onModule")) {
@ -304,9 +297,6 @@ public class PluginsService extends AbstractComponent {
continue; // skip over .DS_Store etc
}
PluginInfo info = PluginInfo.readFromProperties(module);
if (!info.isJvm()) {
throw new IllegalStateException("modules must be jvm plugins: " + info);
}
if (!info.isIsolated()) {
throw new IllegalStateException("modules must be isolated: " + info);
}
@ -353,17 +343,14 @@ public class PluginsService extends AbstractComponent {
}
List<URL> urls = new ArrayList<>();
if (info.isJvm()) {
// a jvm plugin: gather urls for jar files
try (DirectoryStream<Path> jarStream = Files.newDirectoryStream(plugin, "*.jar")) {
for (Path jar : jarStream) {
// normalize with toRealPath to get symlinks out of our hair
urls.add(jar.toRealPath().toUri().toURL());
}
try (DirectoryStream<Path> jarStream = Files.newDirectoryStream(plugin, "*.jar")) {
for (Path jar : jarStream) {
// normalize with toRealPath to get symlinks out of our hair
urls.add(jar.toRealPath().toUri().toURL());
}
}
final Bundle bundle;
if (info.isJvm() && info.isIsolated() == false) {
if (info.isIsolated() == false) {
bundle = bundles.get(0); // purgatory
} else {
bundle = new Bundle();
@ -395,15 +382,10 @@ public class PluginsService extends AbstractComponent {
// create a child to load the plugins in this bundle
ClassLoader loader = URLClassLoader.newInstance(bundle.urls.toArray(new URL[0]), getClass().getClassLoader());
for (PluginInfo pluginInfo : bundle.plugins) {
final Plugin plugin;
if (pluginInfo.isJvm()) {
// reload lucene SPI with any new services from the plugin
reloadLuceneSPI(loader);
Class<? extends Plugin> pluginClass = loadPluginClass(pluginInfo.getClassname(), loader);
plugin = loadPlugin(pluginClass, settings);
} else {
plugin = new SitePlugin(pluginInfo.getName(), pluginInfo.getDescription());
}
// reload lucene SPI with any new services from the plugin
reloadLuceneSPI(loader);
final Class<? extends Plugin> pluginClass = loadPluginClass(pluginInfo.getClassname(), loader);
final Plugin plugin = loadPlugin(pluginClass, settings);
plugins.add(new Tuple<>(pluginInfo, plugin));
}
}

View File

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

View File

@ -84,8 +84,6 @@ public class RestPluginsAction extends AbstractCatAction {
table.addCell("name", "alias:n;desc:node name");
table.addCell("component", "alias:c;desc:component");
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.endHeaders();
return table;
@ -104,22 +102,6 @@ public class RestPluginsAction extends AbstractCatAction {
table.addCell(node.name());
table.addCell(pluginInfo.getName());
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.endRow();
}

View File

@ -40,17 +40,13 @@ public class PluginInfoTests extends ESTestCase {
"version", "1.0",
"elasticsearch.version", Version.CURRENT.toString(),
"java.version", System.getProperty("java.specification.version"),
"jvm", "true",
"classname", "FakePlugin");
PluginInfo info = PluginInfo.readFromProperties(pluginDir);
assertEquals("my_plugin", info.getName());
assertEquals("fake desc", info.getDescription());
assertEquals("1.0", info.getVersion());
assertEquals("FakePlugin", info.getClassname());
assertTrue(info.isJvm());
assertTrue(info.isIsolated());
assertFalse(info.isSite());
assertNull(info.getUrl());
}
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 {
Path pluginDir = createTempDir().resolve("fake-plugin");
PluginTestUtil.writeProperties(pluginDir,
"description", "fake desc",
"name", "my_plugin",
"version", "1.0",
"jvm", "true");
"version", "1.0");
try {
PluginInfo.readFromProperties(pluginDir);
fail("expected missing elasticsearch version exception");
@ -129,8 +110,7 @@ public class PluginInfoTests extends ESTestCase {
"description", "fake desc",
"name", "my_plugin",
"elasticsearch.version", Version.CURRENT.toString(),
"version", "1.0",
"jvm", "true");
"version", "1.0");
try {
PluginInfo.readFromProperties(pluginDir);
fail("expected missing java version exception");
@ -148,8 +128,7 @@ public class PluginInfoTests extends ESTestCase {
"elasticsearch.version", Version.CURRENT.toString(),
"java.version", "1000000.0",
"classname", "FakePlugin",
"version", "1.0",
"jvm", "true");
"version", "1.0");
try {
PluginInfo.readFromProperties(pluginDir);
fail("expected incompatible java version exception");
@ -167,8 +146,7 @@ public class PluginInfoTests extends ESTestCase {
"elasticsearch.version", Version.CURRENT.toString(),
"java.version", "1.7.0_80",
"classname", "FakePlugin",
"version", "1.0",
"jvm", "true");
"version", "1.0");
try {
PluginInfo.readFromProperties(pluginDir);
fail("expected bad java version format exception");
@ -182,7 +160,6 @@ public class PluginInfoTests extends ESTestCase {
PluginTestUtil.writeProperties(pluginDir,
"description", "fake desc",
"version", "1.0",
"jvm", "true",
"name", "my_plugin",
"elasticsearch.version", "bogus");
try {
@ -199,7 +176,6 @@ public class PluginInfoTests extends ESTestCase {
"description", "fake desc",
"name", "my_plugin",
"version", "1.0",
"jvm", "true",
"elasticsearch.version", Version.V_1_7_0.toString());
try {
PluginInfo.readFromProperties(pluginDir);
@ -216,8 +192,7 @@ public class PluginInfoTests extends ESTestCase {
"name", "my_plugin",
"version", "1.0",
"elasticsearch.version", Version.CURRENT.toString(),
"java.version", System.getProperty("java.specification.version"),
"jvm", "true");
"java.version", System.getProperty("java.specification.version"));
try {
PluginInfo.readFromProperties(pluginDir);
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() {
PluginsAndModules pluginsInfo = new PluginsAndModules();
pluginsInfo.addPlugin(new PluginInfo("c", "foo", true, "dummy", true, "dummyclass", true));
pluginsInfo.addPlugin(new PluginInfo("b", "foo", true, "dummy", true, "dummyclass", true));
pluginsInfo.addPlugin(new PluginInfo("e", "foo", true, "dummy", true, "dummyclass", true));
pluginsInfo.addPlugin(new PluginInfo("a", "foo", true, "dummy", true, "dummyclass", true));
pluginsInfo.addPlugin(new PluginInfo("d", "foo", true, "dummy", true, "dummyclass", true));
pluginsInfo.addPlugin(new PluginInfo("c", "foo", "dummy", "dummyclass", true));
pluginsInfo.addPlugin(new PluginInfo("b", "foo", "dummy", "dummyclass", true));
pluginsInfo.addPlugin(new PluginInfo("e", "foo", "dummy", "dummyclass", true));
pluginsInfo.addPlugin(new PluginInfo("a", "foo", "dummy", "dummyclass", true));
pluginsInfo.addPlugin(new PluginInfo("d", "foo", "dummy", "dummyclass", true));
final List<PluginInfo> infos = pluginsInfo.getPluginInfos();
List<String> names = infos.stream().map((input) -> input.getName()).collect(Collectors.toList());

View File

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

View File

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

View File

@ -3,8 +3,6 @@
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]
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
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]
=== 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`].
[float]
==== Mandatory elements for all plugins
==== Mandatory elements for plugins
[cols="<,<,<",options="header",]
@ -56,23 +40,6 @@ https://github.com/elastic/elasticsearch/blob/master/plugins/site-example/build.
|`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.
|`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]
.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]
=== Testing your plugin

View File

@ -27,7 +27,7 @@ consult this table:
|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[]

View File

@ -39,8 +39,5 @@ subprojects {
if (esplugin.isolated == false) {
throw new InvalidModelException("Modules cannot disable isolation")
}
if (esplugin.jvm == false) {
throw new InvalidModelException("Modules must be jvm plugins")
}
}
}

View File

@ -11,4 +11,3 @@
nodes.info: {}
- match: { nodes.$master.modules.0.name: lang-expression }
- match: { nodes.$master.modules.0.jvm: true }

View File

@ -11,4 +11,3 @@
nodes.info: {}
- match: { nodes.$master.modules.0.name: lang-groovy }
- match: { nodes.$master.modules.0.jvm: true }

View File

@ -11,7 +11,6 @@
nodes.info: {}
- match: { nodes.$master.modules.0.name: lang-mustache }
- match: { nodes.$master.modules.0.jvm: true }
---
"Indexed template":

View File

@ -11,4 +11,3 @@
nodes.info: {}
- match: { nodes.$master.plugins.0.name: discovery-azure }
- match: { nodes.$master.plugins.0.jvm: true }

View File

@ -11,4 +11,3 @@
nodes.info: {}
- match: { nodes.$master.plugins.0.name: discovery-ec2 }
- match: { nodes.$master.plugins.0.jvm: true }

View File

@ -11,4 +11,3 @@
nodes.info: {}
- match: { nodes.$master.plugins.0.name: discovery-gce }
- match: { nodes.$master.plugins.0.jvm: true }

View File

@ -11,4 +11,3 @@
nodes.info: {}
- match: { nodes.$master.plugins.0.name: discovery-multicast }
- match: { nodes.$master.plugins.0.jvm: true }

View File

@ -11,4 +11,3 @@
nodes.info: {}
- match: { nodes.$master.plugins.0.name: jvm-example }
- match: { nodes.$master.plugins.0.jvm: true }

View File

@ -11,4 +11,3 @@
nodes.info: {}
- match: { nodes.$master.plugins.0.name: lang-plan-a }
- match: { nodes.$master.plugins.0.jvm: true }

View File

@ -11,4 +11,3 @@
nodes.info: {}
- match: { nodes.$master.plugins.0.name: mapper-attachments }
- match: { nodes.$master.plugins.0.jvm: true }

View File

@ -11,4 +11,3 @@
nodes.info: {}
- match: { nodes.$master.plugins.0.name: repository-azure }
- match: { nodes.$master.plugins.0.jvm: true }

View File

@ -13,7 +13,6 @@
nodes.info: {}
- 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

View File

@ -11,4 +11,3 @@
nodes.info: {}
- match: { nodes.$master.plugins.0.name: repository-s3 }
- match: { nodes.$master.plugins.0.jvm: true }

View File

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

View File

@ -1,6 +0,0 @@
<html>
<head>
<title>Page title</title>
</head>
<body>Page body</body>
</html>

View File

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

View File

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

View File

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

View File

@ -11,4 +11,3 @@
nodes.info: {}
- match: { nodes.$master.plugins.0.name: store-smb }
- match: { nodes.$master.plugins.0.jvm: true }

View File

@ -196,7 +196,6 @@ public class PluginManagerTests extends ESIntegTestCase {
"version", "1.0",
"elasticsearch.version", Version.CURRENT.toString(),
"java.version", System.getProperty("java.specification.version"),
"jvm", "true",
"classname", "FakePlugin");
assertStatus("install", USAGE);
}
@ -216,7 +215,6 @@ public class PluginManagerTests extends ESIntegTestCase {
"version", "1.0",
"elasticsearch.version", Version.CURRENT.toString(),
"java.version", System.getProperty("java.specification.version"),
"jvm", "true",
"classname", "FakePlugin");
Path binDir = environment.binFile();
@ -260,7 +258,6 @@ public class PluginManagerTests extends ESIntegTestCase {
"version", "1.0",
"elasticsearch.version", Version.CURRENT.toString(),
"java.version", System.getProperty("java.specification.version"),
"jvm", "true",
"classname", "FakePlugin");
Path pluginConfigDir = environment.configFile().resolve(pluginName);
@ -296,7 +293,6 @@ public class PluginManagerTests extends ESIntegTestCase {
"version", "2.0",
"elasticsearch.version", Version.CURRENT.toString(),
"java.version", System.getProperty("java.specification.version"),
"jvm", "true",
"classname", "FakePlugin");
assertStatusOk(String.format(Locale.ROOT, "install %s --verbose", pluginUrl));
@ -361,7 +357,6 @@ public class PluginManagerTests extends ESIntegTestCase {
"version", "1.0",
"elasticsearch.version", Version.CURRENT.toString(),
"java.version", System.getProperty("java.specification.version"),
"jvm", "true",
"classname", "FakePlugin");
Path binDir = environment.binFile();
@ -392,16 +387,13 @@ public class PluginManagerTests extends ESIntegTestCase {
"version", "1.0",
"elasticsearch.version", Version.CURRENT.toString(),
"java.version", System.getProperty("java.specification.version"),
"jvm", "true",
"classname", "FakePlugin");
System.err.println("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.getTerminalOutput(), hasItem(containsString("Name: fake-plugin")));
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("JVM: true")));
assertThatPluginIsListed(pluginName);
}
@ -414,7 +406,6 @@ public class PluginManagerTests extends ESIntegTestCase {
"version", "1.0",
"elasticsearch.version", Version.CURRENT.toString(),
"java.version", System.getProperty("java.specification.version"),
"jvm", "true",
"classname", "FakePlugin");
ExitStatus status = new PluginManagerCliParser(terminal).execute(args("install " + pluginUrl));
assertThat("Terminal output was: " + terminal.getTerminalOutput(), status, is(ExitStatus.OK));
@ -447,7 +438,6 @@ public class PluginManagerTests extends ESIntegTestCase {
"elasticsearch.version", Version.CURRENT.toString(),
"java.version", System.getProperty("java.specification.version"),
"isolated", "false",
"jvm", "true",
"classname", "FakePlugin");
// install
@ -465,63 +455,20 @@ public class PluginManagerTests extends ESIntegTestCase {
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 {
String pluginName = "fake-plugin";
Path pluginDir = createTempDir().resolve(pluginName);
Files.createDirectories(pluginDir.resolve("_site"));
Files.createFile(pluginDir.resolve("_site").resolve("somefile"));
String pluginUrl = createPluginWithBadChecksum(pluginDir,
"description", "fake desc",
"version", "1.0",
"site", "true");
"description", "fake desc",
"name", pluginName,
"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),
ExitStatus.IO_ERROR);
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 {
@ -606,7 +553,6 @@ public class PluginManagerTests extends ESIntegTestCase {
"version", "1.0.0",
"elasticsearch.version", Version.CURRENT.toString(),
"java.version", System.getProperty("java.specification.version"),
"jvm", "true",
"classname", "FakePlugin");
// We want to remove plugin with plugin short name

View File

@ -263,12 +263,6 @@ fi
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" {
install_and_check_plugin store smb
}

View File

@ -10,7 +10,5 @@
name .+ \n
component .+ \n
version .+ \n
type .+ \n
url .+ \n
description .+ \n
$/

View File

@ -34,7 +34,6 @@ List projects = [
'plugins:repository-hdfs',
'plugins:repository-s3',
'plugins:jvm-example',
'plugins:site-example',
'plugins:store-smb',
'qa:evil-tests',
'qa:smoke-test-client',

View File

@ -154,11 +154,9 @@ public class BootstrapForTesting {
try (InputStream stream = url.openStream()) {
properties.load(stream);
}
if (Boolean.parseBoolean(properties.getProperty("jvm"))) {
String clazz = properties.getProperty("classname");
if (clazz != null) {
Class.forName(clazz);
}
String clazz = properties.getProperty("classname");
if (clazz != null) {
Class.forName(clazz);
}
}
} catch (Exception e) {

View File

@ -731,82 +731,6 @@ public class ElasticsearchAssertions {
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
*/