Check that a plugin is Lucene compatible with the current running node using `lucene` property in `es-plugin.properties` file.

* If plugin does not provide `lucene` property, we consider that the plugin is compatible.
* If plugin provides `lucene` property, we try to load related Enum org.apache.lucene.util.Version. If this fails, it means that the node is too "old" comparing to the Lucene version the plugin was built for.
* We compare then two first digits of current node lucene version against two first digits of plugin Lucene version. If not equal, it means that the plugin is too "old" for the current node.

Plugin developers who wants to launch plugin check only have to add a `lucene` property in `es-plugin.properties` file. If you are using maven to build your plugin, you can do it like this:

In `pom.xml`:

```xml
    <properties>
        <lucene.version>4.6.0</lucene.version>
    </properties>

    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>
```

In `es-plugin.properties`, add:

```properties
lucene=${lucene.version}
```

BTW, if you don't already have it, you can add the plugin version as well:

```properties
version=${project.version}
```

You can disable that check using `plugins.check_lucene: false`.
This commit is contained in:
David Pilato 2014-02-01 22:12:00 +01:00
parent 094908ac7f
commit bd871f96c2
13 changed files with 487 additions and 118 deletions

View File

@ -142,6 +142,19 @@ bin/plugin --install mobz/elasticsearch-head --timeout 1m
bin/plugin --install mobz/elasticsearch-head --timeout 0
-----------------------------------
[float]
==== Lucene version dependent plugins
coming[1.2.0]
For some plugins, such as analysis plugins, a specific major Lucene version is
required to run. In that case, the plugin provides in its `es-plugin.properties`
file the Lucene version for which the plugin was built for.
If present at startup the node will check the Lucene version before loading the plugin.
You can disable that check using `plugins.check_lucene: false`.
[float]
[[known-plugins]]
=== Known Plugins

View File

@ -335,7 +335,9 @@
<include>**/*.json</include>
<include>**/*.yml</include>
<include>**/*.txt</include>
<include>**/*.properties</include>
</includes>
<filtering>true</filtering>
</testResource>
<testResource>
<directory>${basedir}/src/test/resources</directory>

View File

@ -20,8 +20,10 @@
package org.elasticsearch.plugins;
import com.google.common.collect.*;
import org.apache.lucene.util.Constants;
import org.apache.lucene.util.IOUtils;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.Version;
import org.elasticsearch.action.admin.cluster.node.info.PluginInfo;
import org.elasticsearch.action.admin.cluster.node.info.PluginsInfo;
import org.elasticsearch.common.Strings;
@ -30,6 +32,7 @@ import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.component.LifecycleComponent;
import org.elasticsearch.common.inject.Module;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
@ -50,7 +53,7 @@ import static org.elasticsearch.common.io.FileSystemUtils.isAccessibleDirectory;
*
*/
public class PluginsService extends AbstractComponent {
private static final String ES_PLUGIN_PROPERTIES = "es-plugin.properties";
public static final String ES_PLUGIN_PROPERTIES = "es-plugin.properties";
private final Environment environment;
@ -63,6 +66,7 @@ public class PluginsService extends AbstractComponent {
private PluginsInfo cachedPluginsInfo;
private final TimeValue refreshInterval;
private final boolean checkLucene;
private long lastRefresh;
static class OnModuleReference {
@ -83,6 +87,7 @@ public class PluginsService extends AbstractComponent {
public PluginsService(Settings settings, Environment environment) {
super(settings);
this.environment = environment;
this.checkLucene = componentSettings.getAsBoolean("check_lucene", true);
ImmutableList.Builder<Tuple<PluginInfo, Plugin>> tupleBuilder = ImmutableList.builder();
@ -161,7 +166,6 @@ public class PluginsService extends AbstractComponent {
this.onModuleReferences = onModuleReferences.immutableMap();
this.refreshInterval = componentSettings.getAsTime("info_refresh_interval", TimeValue.timeValueSeconds(10));
}
public ImmutableList<Tuple<PluginInfo, Plugin>> plugins() {
@ -494,22 +498,87 @@ public class PluginsService extends AbstractComponent {
try {
Class<? extends Plugin> pluginClass = (Class<? extends Plugin>) settings.getClassLoader().loadClass(className);
Plugin plugin;
try {
plugin = pluginClass.getConstructor(Settings.class).newInstance(settings);
} catch (NoSuchMethodException e) {
if (!checkLucene || checkLuceneCompatibility(pluginClass, settings, logger)) {
try {
plugin = pluginClass.getConstructor().newInstance();
} catch (NoSuchMethodException e1) {
throw new ElasticsearchException("No constructor for [" + pluginClass + "]. A plugin class must " +
"have either an empty default constructor or a single argument constructor accepting a " +
"Settings instance");
plugin = pluginClass.getConstructor(Settings.class).newInstance(settings);
} catch (NoSuchMethodException e) {
try {
plugin = pluginClass.getConstructor().newInstance();
} catch (NoSuchMethodException e1) {
throw new ElasticsearchException("No constructor for [" + pluginClass + "]. A plugin class must " +
"have either an empty default constructor or a single argument constructor accepting a " +
"Settings instance");
}
}
} else {
throw new ElasticsearchException("Plugin is incompatible with the current node");
}
return plugin;
} catch (Throwable e) {
throw new ElasticsearchException("Failed to load plugin class [" + className + "]", e);
}
}
/**
* <p>Check that a plugin is Lucene compatible with the current running node using `lucene` property
* in `es-plugin.properties` file.</p>
* <p>If plugin does not provide `lucene` property, we consider that the plugin is compatible.</p>
* <p>If plugin provides `lucene` property, we try to load related Enum org.apache.lucene.util.Version. If this
* fails, it means that the node is too "old" comparing to the Lucene version the plugin was built for.</p>
* <p>We compare then two first digits of current node lucene version against two first digits of plugin Lucene
* version. If not equal, it means that the plugin is too "old" for the current node.</p>
*
* @param pluginClass Plugin class we are checking
* @return true if the plugin is Lucene compatible
*/
public static boolean checkLuceneCompatibility(Class<? extends Plugin> pluginClass, Settings settings, ESLogger logger) {
String luceneVersion = null;
try {
// We try to read the es-plugin.properties file
// But as we can have several plugins in the same classloader,
// we have to find the right es-plugin.properties file
Enumeration<URL> pluginUrls = settings.getClassLoader().getResources(PluginsService.ES_PLUGIN_PROPERTIES);
while (pluginUrls.hasMoreElements()) {
URL pluginUrl = pluginUrls.nextElement();
try (InputStream is = pluginUrl.openStream()) {
Properties pluginProps = new Properties();
pluginProps.load(is);
String plugin = pluginProps.getProperty("plugin");
// If we don't have the expected plugin, let's continue to the next one
if (pluginClass.getName().equals(plugin)) {
luceneVersion = pluginProps.getProperty("lucene");
break;
}
logger.debug("skipping [{}]", pluginUrl);
}
}
if (luceneVersion != null) {
// We only keep the first two parts
String parts[] = luceneVersion.split("\\.");
// Should fail if the running node is too old!
org.apache.lucene.util.Version luceneExpectedVersion = org.apache.lucene.util.Version.parseLeniently(parts[0]+"."+parts[1]);
if (Version.CURRENT.luceneVersion.equals(luceneExpectedVersion)) {
logger.debug("starting analysis plugin for Lucene [{}].", luceneExpectedVersion);
return true;
}
} else {
logger.debug("lucene property is not set in plugin {} file. Skipping test.", PluginsService.ES_PLUGIN_PROPERTIES);
return true;
}
} catch (Throwable t) {
// We don't have the expected version... Let's fail after.
logger.debug("exception raised while checking plugin Lucene version.", t);
}
logger.error("cannot start plugin due to incorrect Lucene version: plugin [{}], node [{}].",
luceneVersion, Constants.LUCENE_MAIN_VERSION);
return false;
}
}

View File

@ -19,22 +19,18 @@
package org.elasticsearch.nodesinfo;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
import org.elasticsearch.action.admin.cluster.node.info.PluginInfo;
import org.elasticsearch.action.admin.cluster.node.info.PluginsInfo;
import org.elasticsearch.cluster.ClusterService;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.nodesinfo.plugin.dummy1.TestPlugin;
import org.elasticsearch.nodesinfo.plugin.dummy2.TestNoVersionPlugin;
import org.elasticsearch.test.ElasticsearchIntegrationTest;
import org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
import org.elasticsearch.test.hamcrest.ElasticsearchAssertions;
import org.junit.Test;
import java.io.File;
@ -43,8 +39,6 @@ import java.net.URL;
import java.util.Collections;
import java.util.List;
import static com.google.common.base.Predicates.and;
import static com.google.common.base.Predicates.isNull;
import static org.elasticsearch.client.Requests.clusterHealthRequest;
import static org.elasticsearch.client.Requests.nodesInfoRequest;
import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
@ -133,23 +127,23 @@ public class SimpleNodesInfoTests extends ElasticsearchIntegrationTest {
NodesInfoResponse response = client().admin().cluster().prepareNodesInfo().clear().setPlugins(true).execute().actionGet();
logger.info("--> full json answer, status " + response.toString());
assertNodeContainsPlugins(response, server1NodeId,
ElasticsearchAssertions.assertNodeContainsPlugins(response, server1NodeId,
Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST, // No JVM Plugin
Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST);// No Site Plugin
assertNodeContainsPlugins(response, server2NodeId,
ElasticsearchAssertions.assertNodeContainsPlugins(response, server2NodeId,
Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST, // No JVM Plugin
Lists.newArrayList(Fields.SITE_PLUGIN), // Site Plugin
Lists.newArrayList(Fields.SITE_PLUGIN_DESCRIPTION),
Lists.newArrayList(Fields.SITE_PLUGIN_VERSION));
assertNodeContainsPlugins(response, server3NodeId,
ElasticsearchAssertions.assertNodeContainsPlugins(response, server3NodeId,
Lists.newArrayList(TestPlugin.Fields.NAME), // JVM Plugin
Lists.newArrayList(TestPlugin.Fields.DESCRIPTION),
Lists.newArrayList(PluginInfo.VERSION_NOT_AVAILABLE),
Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST);// No site Plugin
assertNodeContainsPlugins(response, server4NodeId,
ElasticsearchAssertions.assertNodeContainsPlugins(response, server4NodeId,
Lists.newArrayList(TestNoVersionPlugin.Fields.NAME), // JVM Plugin
Lists.newArrayList(TestNoVersionPlugin.Fields.DESCRIPTION),
Lists.newArrayList(PluginInfo.VERSION_NOT_AVAILABLE),
@ -158,63 +152,14 @@ public class SimpleNodesInfoTests extends ElasticsearchIntegrationTest {
Lists.newArrayList(PluginInfo.VERSION_NOT_AVAILABLE));
}
private void assertNodeContainsPlugins(NodesInfoResponse response, String nodeId,
List<String> expectedJvmPluginNames,
List<String> expectedJvmPluginDescriptions,
List<String> expectedJvmVersions,
List<String> expectedSitePluginNames,
List<String> expectedSitePluginDescriptions,
List<String> expectedSiteVersions) {
assertThat(response.getNodesMap().get(nodeId), notNullValue());
PluginsInfo plugins = response.getNodesMap().get(nodeId).getPlugins();
assertThat(plugins, notNullValue());
List<String> pluginNames = FluentIterable.from(plugins.getInfos()).filter(jvmPluginPredicate).transform(nameFunction).toList();
for (String expectedJvmPluginName : expectedJvmPluginNames) {
assertThat(pluginNames, hasItem(expectedJvmPluginName));
}
List<String> pluginDescriptions = FluentIterable.from(plugins.getInfos()).filter(jvmPluginPredicate).transform(descriptionFunction).toList();
for (String expectedJvmPluginDescription : expectedJvmPluginDescriptions) {
assertThat(pluginDescriptions, hasItem(expectedJvmPluginDescription));
}
List<String> jvmPluginVersions = FluentIterable.from(plugins.getInfos()).filter(jvmPluginPredicate).transform(versionFunction).toList();
for (String pluginVersion : expectedJvmVersions) {
assertThat(jvmPluginVersions, hasItem(pluginVersion));
}
FluentIterable<String> jvmUrls = FluentIterable.from(plugins.getInfos())
.filter(and(jvmPluginPredicate, Predicates.not(sitePluginPredicate)))
.filter(isNull())
.transform(urlFunction);
assertThat(Iterables.size(jvmUrls), is(0));
List<String> sitePluginNames = FluentIterable.from(plugins.getInfos()).filter(sitePluginPredicate).transform(nameFunction).toList();
for (String expectedSitePluginName : expectedSitePluginNames) {
assertThat(sitePluginNames, hasItem(expectedSitePluginName));
}
List<String> sitePluginDescriptions = FluentIterable.from(plugins.getInfos()).filter(sitePluginPredicate).transform(descriptionFunction).toList();
for (String sitePluginDescription : expectedSitePluginDescriptions) {
assertThat(sitePluginDescriptions, hasItem(sitePluginDescription));
}
List<String> sitePluginUrls = FluentIterable.from(plugins.getInfos()).filter(sitePluginPredicate).transform(urlFunction).toList();
assertThat(sitePluginUrls, not(contains(nullValue())));
List<String> sitePluginVersions = FluentIterable.from(plugins.getInfos()).filter(sitePluginPredicate).transform(versionFunction).toList();
for (String pluginVersion : expectedSiteVersions) {
assertThat(sitePluginVersions, hasItem(pluginVersion));
}
public static String startNodeWithPlugins(int nodeId, String ... pluginClassNames) throws URISyntaxException {
return startNodeWithPlugins(ImmutableSettings.EMPTY, "/org/elasticsearch/nodesinfo/node" + Integer.toString(nodeId) + "/", pluginClassNames);
}
private String startNodeWithPlugins(int nodeId, String ... pluginClassNames) throws URISyntaxException {
URL resource = SimpleNodesInfoTests.class.getResource("/org/elasticsearch/nodesinfo/node" + Integer.toString(nodeId) + "/");
public static String startNodeWithPlugins(Settings nodeSettings, String pluginDir, String ... pluginClassNames) throws URISyntaxException {
URL resource = SimpleNodesInfoTests.class.getResource(pluginDir);
ImmutableSettings.Builder settings = settingsBuilder();
settings.put(nodeSettings);
if (resource != null) {
settings.put("path.plugins", new File(resource.toURI()).getAbsolutePath());
}
@ -228,45 +173,8 @@ public class SimpleNodesInfoTests extends ElasticsearchIntegrationTest {
// We wait for a Green status
client().admin().cluster().health(clusterHealthRequest().waitForGreenStatus()).actionGet();
String serverNodeId = cluster().getInstance(ClusterService.class, nodeName).state().nodes().localNodeId();
logger.debug("--> server {} started" + serverNodeId);
return serverNodeId;
return cluster().getInstance(ClusterService.class, nodeName).state().nodes().localNodeId();
}
private Predicate<PluginInfo> jvmPluginPredicate = new Predicate<PluginInfo>() {
public boolean apply(PluginInfo pluginInfo) {
return pluginInfo.isJvm();
}
};
private Predicate<PluginInfo> sitePluginPredicate = new Predicate<PluginInfo>() {
public boolean apply(PluginInfo pluginInfo) {
return pluginInfo.isSite();
}
};
private Function<PluginInfo, String> nameFunction = new Function<PluginInfo, String>() {
public String apply(PluginInfo pluginInfo) {
return pluginInfo.getName();
}
};
private Function<PluginInfo, String> descriptionFunction = new Function<PluginInfo, String>() {
public String apply(PluginInfo pluginInfo) {
return pluginInfo.getDescription();
}
};
private Function<PluginInfo, String> urlFunction = new Function<PluginInfo, String>() {
public String apply(PluginInfo pluginInfo) {
return pluginInfo.getUrl();
}
};
private Function<PluginInfo, String> versionFunction = new Function<PluginInfo, String>() {
public String apply(PluginInfo pluginInfo) {
return pluginInfo.getVersion();
}
};
}

View File

@ -0,0 +1,82 @@
/*
* 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.plugin;
import com.google.common.collect.Lists;
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
import org.elasticsearch.nodesinfo.SimpleNodesInfoTests;
import org.elasticsearch.test.ElasticsearchIntegrationTest;
import org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
import org.elasticsearch.test.hamcrest.ElasticsearchAssertions;
import org.junit.Test;
import java.net.URISyntaxException;
import java.util.Collections;
import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
/**
*
*/
@ClusterScope(scope= ElasticsearchIntegrationTest.Scope.TEST, numDataNodes=0, transportClientRatio = 0)
public class PluginLuceneCheckerTests extends ElasticsearchIntegrationTest {
/**
* We check that no Lucene version checking is done
* when we set `"plugins.check_lucene":false`
*/
@Test
public void testDisableLuceneVersionCheckingPlugin() throws URISyntaxException {
String serverNodeId = SimpleNodesInfoTests.startNodeWithPlugins(
settingsBuilder().put("plugins.check_lucene", false).build(),
"/org/elasticsearch/plugin/lucene/");
logger.info("--> server {} started" + serverNodeId);
NodesInfoResponse response = client().admin().cluster().prepareNodesInfo().clear().setPlugins(true).execute().actionGet();
logger.info("--> full json answer, status " + response.toString());
ElasticsearchAssertions.assertNodeContainsPlugins(response, serverNodeId,
Lists.newArrayList("old-lucene"), Lists.newArrayList("old"), Lists.newArrayList("1.0.0"), // JVM Plugin
Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST);// No Site Plugin
}
/**
* We check that with an old plugin (built on an old Lucene version)
* plugin is not loaded
* We check that with a recent plugin (built on current Lucene version)
* plugin is loaded
* We check that with a too recent plugin (built on an unknown Lucene version)
* plugin is not loaded
*/
@Test
public void testEnableLuceneVersionCheckingPlugin() throws URISyntaxException {
String serverNodeId = SimpleNodesInfoTests.startNodeWithPlugins(
settingsBuilder().put("plugins.check_lucene", true).build(),
"/org/elasticsearch/plugin/lucene/");
logger.info("--> server {} started" + serverNodeId);
NodesInfoResponse response = client().admin().cluster().prepareNodesInfo().clear().setPlugins(true).execute().actionGet();
logger.info("--> full json answer, status " + response.toString());
ElasticsearchAssertions.assertNodeContainsPlugins(response, serverNodeId,
Lists.newArrayList("current-lucene"), Lists.newArrayList("current"), Lists.newArrayList("2.0.0"), // JVM Plugin
Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST);// No Site Plugin
}
}

View File

@ -22,6 +22,7 @@ import com.google.common.base.Predicate;
import org.elasticsearch.ElasticsearchIllegalArgumentException;
import org.elasticsearch.ElasticsearchTimeoutException;
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
import org.elasticsearch.action.admin.cluster.node.info.PluginInfo;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.io.FileSystemUtils;
import org.elasticsearch.common.settings.ImmutableSettings;
@ -46,8 +47,9 @@ import java.io.IOException;
import java.net.URI;
import java.util.concurrent.TimeUnit;
import static org.elasticsearch.test.ElasticsearchIntegrationTest.*;
import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.notNullValue;
@ -150,9 +152,18 @@ public class PluginManagerTests extends ElasticsearchIntegrationTest {
NodesInfoResponse nodesInfoResponse = client().admin().cluster().prepareNodesInfo().clear().setPlugins(true).get();
assertThat(nodesInfoResponse.getNodes().length, equalTo(1));
assertThat(nodesInfoResponse.getNodes()[0].getPlugins().getInfos(), notNullValue());
assertThat(nodesInfoResponse.getNodes()[0].getPlugins().getInfos().size(), equalTo(1));
assertThat(nodesInfoResponse.getNodes()[0].getPlugins().getInfos().get(0).getName(), equalTo(pluginName));
assertThat(nodesInfoResponse.getNodes()[0].getPlugins().getInfos().get(0).isSite(), equalTo(true));
assertThat(nodesInfoResponse.getNodes()[0].getPlugins().getInfos().size(), not(0));
boolean pluginFound = false;
for (PluginInfo pluginInfo : nodesInfoResponse.getNodes()[0].getPlugins().getInfos()) {
if (pluginInfo.getName().equals(pluginName)) {
pluginFound = true;
break;
}
}
assertThat(pluginFound, is(true));
}
private void assertPluginAvailable(String pluginName) throws InterruptedException {

View File

@ -0,0 +1,40 @@
/*
* 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.plugin.lucene.current;
import org.elasticsearch.plugins.AbstractPlugin;
public class CurrentLucenePlugin extends AbstractPlugin {
/**
* The name of the plugin.
*/
@Override
public String name() {
return "current-lucene";
}
/**
* The description of the plugin.
*/
@Override
public String description() {
return "current";
}
}

View File

@ -0,0 +1,21 @@
################################################################
# 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.
################################################################
plugin=org.elasticsearch.plugin.lucene.current.CurrentLucenePlugin
version=2.0.0
lucene=${lucene.version}

View File

@ -0,0 +1,40 @@
/*
* 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.plugin.lucene.newer;
import org.elasticsearch.plugins.AbstractPlugin;
public class NewerLucenePlugin extends AbstractPlugin {
/**
* The name of the plugin.
*/
@Override
public String name() {
return "newer-lucene";
}
/**
* The description of the plugin.
*/
@Override
public String description() {
return "newer";
}
}

View File

@ -0,0 +1,21 @@
################################################################
# 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.
################################################################
plugin=org.elasticsearch.plugin.lucene.newer.NewerLucenePlugin
version=3.0.0
lucene=99.0.0

View File

@ -0,0 +1,40 @@
/*
* 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.plugin.lucene.old;
import org.elasticsearch.plugins.AbstractPlugin;
public class OldLucenePlugin extends AbstractPlugin {
/**
* The name of the plugin.
*/
@Override
public String name() {
return "old-lucene";
}
/**
* The description of the plugin.
*/
@Override
public String description() {
return "old";
}
}

View File

@ -0,0 +1,21 @@
################################################################
# 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.
################################################################
plugin=org.elasticsearch.plugin.lucene.old.OldLucenePlugin
version=1.0.0
lucene=3.0.0

View File

@ -18,7 +18,11 @@
*/
package org.elasticsearch.test.hamcrest;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.Iterables;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Query;
import org.elasticsearch.ElasticsearchException;
@ -31,6 +35,9 @@ import org.elasticsearch.action.ActionRequestBuilder;
import org.elasticsearch.action.ShardOperationFailedException;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequestBuilder;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
import org.elasticsearch.action.admin.cluster.node.info.PluginInfo;
import org.elasticsearch.action.admin.cluster.node.info.PluginsInfo;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequestBuilder;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse;
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse;
@ -58,6 +65,7 @@ import org.elasticsearch.test.engine.MockInternalEngine;
import org.elasticsearch.test.store.MockDirectoryHelper;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers;
import org.junit.Assert;
import java.io.IOException;
import java.lang.reflect.Constructor;
@ -65,6 +73,7 @@ import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import static com.google.common.base.Predicates.isNull;
import static org.elasticsearch.test.ElasticsearchTestCase.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
@ -575,4 +584,96 @@ public class ElasticsearchAssertions {
}
}
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());
PluginsInfo plugins = response.getNodesMap().get(nodeId).getPlugins();
Assert.assertThat(plugins, notNullValue());
List<String> pluginNames = FluentIterable.from(plugins.getInfos()).filter(jvmPluginPredicate).transform(nameFunction).toList();
for (String expectedJvmPluginName : expectedJvmPluginNames) {
Assert.assertThat(pluginNames, hasItem(expectedJvmPluginName));
}
List<String> pluginDescriptions = FluentIterable.from(plugins.getInfos()).filter(jvmPluginPredicate).transform(descriptionFunction).toList();
for (String expectedJvmPluginDescription : expectedJvmPluginDescriptions) {
Assert.assertThat(pluginDescriptions, hasItem(expectedJvmPluginDescription));
}
List<String> jvmPluginVersions = FluentIterable.from(plugins.getInfos()).filter(jvmPluginPredicate).transform(versionFunction).toList();
for (String pluginVersion : expectedJvmVersions) {
Assert.assertThat(jvmPluginVersions, hasItem(pluginVersion));
}
FluentIterable<String> jvmUrls = FluentIterable.from(plugins.getInfos())
.filter(Predicates.and(jvmPluginPredicate, Predicates.not(sitePluginPredicate)))
.filter(isNull())
.transform(urlFunction);
Assert.assertThat(Iterables.size(jvmUrls), is(0));
List<String> sitePluginNames = FluentIterable.from(plugins.getInfos()).filter(sitePluginPredicate).transform(nameFunction).toList();
Assert.assertThat(sitePluginNames.isEmpty(), is(expectedSitePluginNames.isEmpty()));
for (String expectedSitePluginName : expectedSitePluginNames) {
Assert.assertThat(sitePluginNames, hasItem(expectedSitePluginName));
}
List<String> sitePluginDescriptions = FluentIterable.from(plugins.getInfos()).filter(sitePluginPredicate).transform(descriptionFunction).toList();
Assert.assertThat(sitePluginDescriptions.isEmpty(), is(expectedSitePluginDescriptions.isEmpty()));
for (String sitePluginDescription : expectedSitePluginDescriptions) {
Assert.assertThat(sitePluginDescriptions, hasItem(sitePluginDescription));
}
List<String> sitePluginUrls = FluentIterable.from(plugins.getInfos()).filter(sitePluginPredicate).transform(urlFunction).toList();
Assert.assertThat(sitePluginUrls, not(contains(nullValue())));
List<String> sitePluginVersions = FluentIterable.from(plugins.getInfos()).filter(sitePluginPredicate).transform(versionFunction).toList();
Assert.assertThat(sitePluginVersions.isEmpty(), is(expectedSiteVersions.isEmpty()));
for (String pluginVersion : expectedSiteVersions) {
Assert.assertThat(sitePluginVersions, hasItem(pluginVersion));
}
}
private static Predicate<PluginInfo> jvmPluginPredicate = new Predicate<PluginInfo>() {
public boolean apply(PluginInfo pluginInfo) {
return pluginInfo.isJvm();
}
};
private static Predicate<PluginInfo> sitePluginPredicate = new Predicate<PluginInfo>() {
public boolean apply(PluginInfo pluginInfo) {
return pluginInfo.isSite();
}
};
private static Function<PluginInfo, String> nameFunction = new Function<PluginInfo, String>() {
public String apply(PluginInfo pluginInfo) {
return pluginInfo.getName();
}
};
private static Function<PluginInfo, String> descriptionFunction = new Function<PluginInfo, String>() {
public String apply(PluginInfo pluginInfo) {
return pluginInfo.getDescription();
}
};
private static Function<PluginInfo, String> urlFunction = new Function<PluginInfo, String>() {
public String apply(PluginInfo pluginInfo) {
return pluginInfo.getUrl();
}
};
private static Function<PluginInfo, String> versionFunction = new Function<PluginInfo, String>() {
public String apply(PluginInfo pluginInfo) {
return pluginInfo.getVersion();
}
};
}