Replace jvm-example by two plugin examples (#28339)

This pull request replaces the jvm-example plugin (from the jvm/site plugins era) by two new plugins: a custom-settings that shows how to register and use custom settings (including secured settings) in a plugin, and rest-handler plugin that shows how to register a rest handler.

The two plugins now reside in the plugins/examples project. They can serve as sample plugins for users, a special attention has been put on documentation. The packaging tests have been adapted to use the custom-settings plugin.
This commit is contained in:
Tanguy Leroux 2018-01-26 17:34:24 +01:00 committed by GitHub
parent 9d06cc09ae
commit be74f11517
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 572 additions and 202 deletions

View File

@ -5,8 +5,10 @@
The Elasticsearch repository contains examples of:
* a https://github.com/elastic/elasticsearch/tree/master/plugins/jvm-example[Java plugin]
which contains Java code.
* a https://github.com/elastic/elasticsearch/tree/master/plugins/custom-settings[Java plugin]
which contains a plugin with custom settings.
* a https://github.com/elastic/elasticsearch/tree/master/plugins/rest-handler[Java plugin]
which contains a plugin that registers a Rest handler.
* a https://github.com/elastic/elasticsearch/tree/master/plugins/examples/rescore[Java plugin]
which contains a rescore plugin.
* a https://github.com/elastic/elasticsearch/tree/master/plugins/examples/script-expert-scoring[Java plugin]

View File

@ -27,10 +27,10 @@ U7321H6 discovery-gce {version} The Google Compute Engine (GCE) Discov
U7321H6 ingest-attachment {version} Ingest processor that uses Apache Tika to extract contents
U7321H6 ingest-geoip {version} Ingest processor that uses looksup geo data based on ip adresses using the Maxmind geo database
U7321H6 ingest-user-agent {version} Ingest processor that extracts information from a user agent
U7321H6 jvm-example {version} Demonstrates all the pluggable Java entry points in Elasticsearch
U7321H6 mapper-murmur3 {version} The Mapper Murmur3 plugin allows to compute hashes of a field's values at index-time and to store them in the index.
U7321H6 mapper-size {version} The Mapper Size plugin allows document to record their uncompressed size at index time.
U7321H6 store-smb {version} The Store SMB plugin adds support for SMB stores.
U7321H6 transport-nio {version} The nio transport.
------------------------------------------------------------------------------
// TESTRESPONSE[s/([.()])/\\$1/ s/U7321H6/.+/ _cat]

View File

@ -0,0 +1,31 @@
/*
* 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.
*/
apply plugin: 'elasticsearch.esplugin'
esplugin {
name 'custom-settings'
description 'An example plugin showing how to register custom settings'
classname 'org.elasticsearch.example.customsettings.ExampleCustomSettingsPlugin'
}
integTestCluster {
// Adds a setting in the Elasticsearch keystore before running the integration tests
keystoreSetting 'custom.secured', 'password'
}

View File

@ -0,0 +1,6 @@
#!/bin/bash
# Plugin can contain executable files that are copied by the plugin manager
# to a <plugin-name>/bin folder.
echo test

View File

@ -0,0 +1,4 @@
REM Plugin can contain executable files that are copied by the plugin manager
REM to a <plugin-name>/bin folder.
echo test

View File

@ -0,0 +1,5 @@
# Custom configuration file for the custom-settings plugin
custom:
simple: foo
list: [0, 1, 1, 2, 3, 5, 8, 13, 21]
filtered: secret

View File

@ -0,0 +1,128 @@
/*
* 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.customsettings;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.settings.SecureSetting;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
/**
* {@link ExampleCustomSettingsConfig} contains the custom settings values and their static declarations.
*/
public class ExampleCustomSettingsConfig {
/**
* A simple string setting
*/
static final Setting<String> SIMPLE_SETTING = Setting.simpleString("custom.simple", Property.NodeScope);
/**
* A simple boolean setting that can be dynamically updated using the Cluster Settings API and that is {@code "false"} by default
*/
static final Setting<Boolean> BOOLEAN_SETTING = Setting.boolSetting("custom.bool", false, Property.NodeScope, Property.Dynamic);
/**
* A string setting that can be dynamically updated and that is validated by some logic
*/
static final Setting<String> VALIDATED_SETTING = Setting.simpleString("custom.validated", (value, settings) -> {
if (value != null && value.contains("forbidden")) {
throw new IllegalArgumentException("Setting must not contain [forbidden]");
}
}, Property.NodeScope, Property.Dynamic);
/**
* A setting that is filtered out when listing all the cluster's settings
*/
static final Setting<String> FILTERED_SETTING = Setting.simpleString("custom.filtered", Property.NodeScope, Property.Filtered);
/**
* A setting which contains a sensitive string. This may be any sensitive string, e.g. a username, a password, an auth token, etc.
*/
static final Setting<SecureString> SECURED_SETTING = SecureSetting.secureString("custom.secured", null);
/**
* A setting that consists of a list of integers
*/
static final Setting<List<Integer>> LIST_SETTING =
Setting.listSetting("custom.list", Collections.emptyList(), Integer::valueOf, Property.NodeScope);
private final String simple;
private final String validated;
private final Boolean bool;
private final List<Integer> list;
private final String filtered;
public ExampleCustomSettingsConfig(final Environment environment) {
// Elasticsearch config directory
final Path configDir = environment.configFile();
// Resolve the plugin's custom settings file
final Path customSettingsYamlFile = configDir.resolve("custom-settings/custom.yml");
// Load the settings from the plugin's custom settings file
final Settings customSettings;
try {
customSettings = Settings.builder().loadFromPath(customSettingsYamlFile).build();
assert customSettings != null;
} catch (IOException e) {
throw new ElasticsearchException("Failed to load settings", e);
}
this.simple = SIMPLE_SETTING.get(customSettings);
this.bool = BOOLEAN_SETTING.get(customSettings);
this.validated = VALIDATED_SETTING.get(customSettings);
this.filtered = FILTERED_SETTING.get(customSettings);
this.list = LIST_SETTING.get(customSettings);
// Loads the secured setting from the keystore
final SecureString secured = SECURED_SETTING.get(environment.settings());
assert secured != null;
}
public String getSimple() {
return simple;
}
public Boolean getBool() {
return bool;
}
public String getValidated() {
return validated;
}
public String getFiltered() {
return filtered;
}
public List<Integer> getList() {
return list;
}
}

View File

@ -0,0 +1,68 @@
/*
* 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.customsettings;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.plugins.Plugin;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import static java.util.stream.Collectors.toList;
public class ExampleCustomSettingsPlugin extends Plugin {
private final ExampleCustomSettingsConfig config;
public ExampleCustomSettingsPlugin(final Settings settings, final Path configPath) {
this.config = new ExampleCustomSettingsConfig(new Environment(settings, configPath));
// asserts that the setting has been correctly loaded from the custom setting file
assert "secret".equals(config.getFiltered());
}
/**
* @return the plugin's custom settings
*/
@Override
public List<Setting<?>> getSettings() {
return Arrays.asList(ExampleCustomSettingsConfig.SIMPLE_SETTING,
ExampleCustomSettingsConfig.BOOLEAN_SETTING,
ExampleCustomSettingsConfig.VALIDATED_SETTING,
ExampleCustomSettingsConfig.FILTERED_SETTING,
ExampleCustomSettingsConfig.SECURED_SETTING,
ExampleCustomSettingsConfig.LIST_SETTING);
}
@Override
public Settings additionalSettings() {
final Settings.Builder builder = Settings.builder();
// Exposes SIMPLE_SETTING and LIST_SETTING as a node settings
builder.put(ExampleCustomSettingsConfig.SIMPLE_SETTING.getKey(), config.getSimple());
final List<String> values = config.getList().stream().map(integer -> Integer.toString(integer)).collect(toList());
builder.putList(ExampleCustomSettingsConfig.LIST_SETTING.getKey(), values);
return builder.build();
}
}

View File

@ -0,0 +1,51 @@
/*
* 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.customsettings;
import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
/**
* {@link ExampleCustomSettingsClientYamlTestSuiteIT} executes the plugin's REST API integration tests.
* <p>
* The tests can be executed using the command: ./gradlew :example-plugins:custom-settings:check
* <p>
* This class extends {@link ESClientYamlSuiteTestCase}, which takes care of parsing the YAML files
* located in the src/test/resources/rest-api-spec/test/ directory and validates them against the
* custom REST API definition files located in src/test/resources/rest-api-spec/api/.
* <p>
* Once validated, {@link ESClientYamlSuiteTestCase} executes the REST tests against a single node
* integration cluster which has the plugin already installed by the Gradle build script.
* </p>
*/
public class ExampleCustomSettingsClientYamlTestSuiteIT extends ESClientYamlSuiteTestCase {
public ExampleCustomSettingsClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate);
}
@ParametersFactory
public static Iterable<Object[]> parameters() throws Exception {
// The test executes all the test candidates by default
// see ESClientYamlSuiteTestCase.REST_TESTS_SUITE
return ESClientYamlSuiteTestCase.createParameters();
}
}

View File

@ -0,0 +1,44 @@
/*
* 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.customsettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.test.ESTestCase;
import static org.elasticsearch.example.customsettings.ExampleCustomSettingsConfig.VALIDATED_SETTING;
/**
* {@link ExampleCustomSettingsConfigTests} is a unit test class for {@link ExampleCustomSettingsConfig}.
* <p>
* It's a JUnit test class that extends {@link ESTestCase} which provides useful methods for testing.
* <p>
* The tests can be executed in the IDE or using the command: ./gradlew :example-plugins:custom-settings:test
*/
public class ExampleCustomSettingsConfigTests extends ESTestCase {
public void testValidatedSetting() {
final String expected = randomAlphaOfLengthBetween(1, 5);
final String actual = VALIDATED_SETTING.get(Settings.builder().put(VALIDATED_SETTING.getKey(), expected).build());
assertEquals(expected, actual);
final IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, () ->
VALIDATED_SETTING.get(Settings.builder().put("custom.validated", "it's forbidden").build()));
assertEquals("Setting must not contain [forbidden]", exception.getMessage());
}
}

View File

@ -0,0 +1,10 @@
"Test that the custom-settings plugin is loaded in Elasticsearch":
# Use the Cat Plugins API to retrieve the list of plugins
- do:
cat.plugins:
local: true
h: component
- match:
$body: /^custom-settings\n$/

View File

@ -0,0 +1,54 @@
"Test custom settings":
# Use the Get Cluster Settings API to list the settings including the default ones
- do:
cluster.get_settings:
include_defaults: true
- is_false: defaults.custom.bool
- match: { defaults.custom.list.0: "0" }
- match: { defaults.custom.list.1: "1" }
- match: { defaults.custom.list.2: "1" }
- match: { defaults.custom.list.3: "2" }
- match: { defaults.custom.list.4: "3" }
- match: { defaults.custom.list.5: "5" }
- match: { defaults.custom.list.6: "8" }
- match: { defaults.custom.list.7: "13" }
- match: { defaults.custom.list.8: "21" }
# This setting is filtered: it does not appear in the response
- is_false: defaults.custom.filtered
# Use the Cluster Update Settings API to update some custom settings
- do:
cluster.put_settings:
body:
transient:
custom:
bool: true
validated: "updated"
# Use the Get Cluster Settings API to list the settings again
- do:
cluster.get_settings: {}
- is_true: transient.custom.bool
- match: { transient.custom.validated: "updated" }
# Try to update the "validated" setting with a forbidden value
- do:
catch: bad_request
cluster.put_settings:
body:
transient:
custom:
validated: "forbidden"
# Reset the settings to their default values
- do:
cluster.put_settings:
body:
transient:
custom:
bool: null
validated: null

View File

@ -17,15 +17,15 @@
* under the License.
*/
esplugin {
description 'Demonstrates all the pluggable Java entry points in Elasticsearch'
classname 'org.elasticsearch.plugin.example.JvmExamplePlugin'
}
// Not published so no need to assemble
tasks.remove(assemble)
build.dependsOn.remove('assemble')
apply plugin: 'elasticsearch.esplugin'
// no unit tests
esplugin {
name 'rest-handler'
description 'An example plugin showing how to register a REST handler'
classname 'org.elasticsearch.example.resthandler.ExampleRestHandlerPlugin'
}
// No unit tests in this example
test.enabled = false
configurations {
@ -40,8 +40,8 @@ task exampleFixture(type: org.elasticsearch.gradle.test.AntFixture) {
dependsOn project.configurations.exampleFixture
executable = new File(project.runtimeJavaHome, 'bin/java')
args '-cp', "${ -> project.configurations.exampleFixture.asPath }",
'example.ExampleTestFixture',
baseDir
'example.ExampleTestFixture',
baseDir
}
integTestCluster {

View File

@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.plugin.example;
package org.elasticsearch.example.resthandler;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.Table;
@ -28,29 +28,31 @@ import org.elasticsearch.rest.action.cat.AbstractCatAction;
import org.elasticsearch.rest.action.cat.RestTable;
import static org.elasticsearch.rest.RestRequest.Method.GET;
import static org.elasticsearch.rest.RestRequest.Method.POST;
/**
* Example of adding a cat action with a plugin.
*/
public class ExampleCatAction extends AbstractCatAction {
private final ExamplePluginConfiguration config;
public ExampleCatAction(Settings settings, RestController controller, ExamplePluginConfiguration config) {
ExampleCatAction(final Settings settings, final RestController controller) {
super(settings);
this.config = config;
controller.registerHandler(GET, "/_cat/configured_example", this);
controller.registerHandler(GET, "/_cat/example", this);
controller.registerHandler(POST, "/_cat/example", this);
}
@Override
public String getName() {
return "example_cat_action";
return "rest_handler_cat_example";
}
@Override
protected RestChannelConsumer doCatRequest(final RestRequest request, final NodeClient client) {
final String message = request.param("message", "Hello from Cat Example action");
Table table = getTableWithHeader(request);
table.startRow();
table.addCell(config.getTestConfig());
table.addCell(message);
table.endRow();
return channel -> {
try {
@ -67,7 +69,7 @@ public class ExampleCatAction extends AbstractCatAction {
}
public static String documentation() {
return "/_cat/configured_example\n";
return "/_cat/example\n";
}
@Override

View File

@ -17,7 +17,7 @@
* under the License.
*/
package org.elasticsearch.plugin.example;
package org.elasticsearch.example.resthandler;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.node.DiscoveryNodes;
@ -25,37 +25,27 @@ import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.IndexScopedSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsFilter;
import org.elasticsearch.env.Environment;
import org.elasticsearch.plugins.ActionPlugin;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestHandler;
import java.nio.file.Path;
import java.util.List;
import java.util.function.Supplier;
import static java.util.Collections.singletonList;
/**
* Example of a plugin.
*/
public class JvmExamplePlugin extends Plugin implements ActionPlugin {
private final ExamplePluginConfiguration config;
public JvmExamplePlugin(Settings settings, Path configPath) {
config = new ExamplePluginConfiguration(new Environment(settings, configPath));
}
public class ExampleRestHandlerPlugin extends Plugin implements ActionPlugin {
@Override
public Settings additionalSettings() {
return Settings.EMPTY;
}
public List<RestHandler> getRestHandlers(final Settings settings,
final RestController restController,
final ClusterSettings clusterSettings,
final IndexScopedSettings indexScopedSettings,
final SettingsFilter settingsFilter,
final IndexNameExpressionResolver indexNameExpressionResolver,
final Supplier<DiscoveryNodes> nodesInCluster) {
@Override
public List<RestHandler> getRestHandlers(Settings settings, RestController restController, ClusterSettings clusterSettings,
IndexScopedSettings indexScopedSettings, SettingsFilter settingsFilter, IndexNameExpressionResolver indexNameExpressionResolver,
Supplier<DiscoveryNodes> nodesInCluster) {
return singletonList(new ExampleCatAction(settings, restController, config));
return singletonList(new ExampleCatAction(settings, restController));
}
}

View File

@ -17,7 +17,7 @@
* under the License.
*/
package org.elasticsearch.plugin.example;
package org.elasticsearch.example.resthandler;
import org.elasticsearch.mocksocket.MockSocket;
import org.elasticsearch.test.ESTestCase;
@ -30,14 +30,18 @@ import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
public class ExampleExternalIT extends ESTestCase {
public class ExampleFixtureIT extends ESTestCase {
public void testExample() throws Exception {
String stringAddress = Objects.requireNonNull(System.getProperty("external.address"));
URL url = new URL("http://" + stringAddress);
InetAddress address = InetAddress.getByName(url.getHost());
try (Socket socket = new MockSocket(address, url.getPort());
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8))) {
assertEquals("TEST", reader.readLine());
final String stringAddress = Objects.requireNonNull(System.getProperty("external.address"));
final URL url = new URL("http://" + stringAddress);
final InetAddress address = InetAddress.getByName(url.getHost());
try (
Socket socket = new MockSocket(address, url.getPort());
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8))
) {
assertEquals("TEST", reader.readLine());
}
}
}

View File

@ -16,24 +16,36 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.plugin.example;
package org.elasticsearch.example.resthandler;
import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
public class JvmExampleClientYamlTestSuiteIT extends ESClientYamlSuiteTestCase {
/**
* {@link ExampleRestHandlerClientYamlTestSuiteIT} executes the plugin's REST API integration tests.
* <p>
* The tests can be executed using the command: ./gradlew :example-plugins:rest-handler:check
* <p>
* This class extends {@link ESClientYamlSuiteTestCase}, which takes care of parsing the YAML files
* located in the src/test/resources/rest-api-spec/test/ directory and validates them against the
* custom REST API definition files located in src/test/resources/rest-api-spec/api/.
* <p>
* Once validated, {@link ESClientYamlSuiteTestCase} executes the REST tests against a single node
* integration cluster which has the plugin already installed by the Gradle build script.
* </p>
*/
public class ExampleRestHandlerClientYamlTestSuiteIT extends ESClientYamlSuiteTestCase {
public JvmExampleClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
public ExampleRestHandlerClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate);
}
@ParametersFactory
public static Iterable<Object[]> parameters() throws Exception {
// The test executes all the test candidates by default
// see ESClientYamlSuiteTestCase.REST_TESTS_SUITE
return ESClientYamlSuiteTestCase.createParameters();
}
}

View File

@ -1,10 +1,10 @@
{
"cat.configured_example": {
"cat.example": {
"documentation": "",
"methods": ["GET"],
"url": {
"path": "/_cat/configured_example",
"paths": ["/_cat/configured_example"],
"path": "/_cat/example",
"paths": ["/_cat/example"],
"parts": {},
"params": {
"help": {
@ -16,6 +16,11 @@
"type": "boolean",
"description": "Verbose mode. Display column headers",
"default": true
},
"message": {
"type": "string",
"description": "A simple message that will be printed out in the response",
"default": "Hello from Cat Example action"
}
}
},

View File

@ -0,0 +1,10 @@
"Test that the rest-handler plugin is loaded in Elasticsearch":
# Use the Cat Plugins API to retrieve the list of plugins
- do:
cat.plugins:
local: true
h: component
- match:
$body: /^rest-handler\n$/

View File

@ -0,0 +1,26 @@
---
"Help":
- do:
cat.example:
help: true
- match:
$body: |
/^ test .+ \n
$/
---
"Default message":
- do:
cat.example:
v: false
- match: {$body: "Hello from Cat Example action\n" }
---
"Custom message":
- do:
cat.example:
message: Hello from REST API test
- match: {$body: "Hello from REST API test\n" }

View File

@ -1,3 +0,0 @@
#!/bin/bash
echo test

View File

@ -1 +0,0 @@
echo test

View File

@ -1 +0,0 @@
test: foo

View File

@ -1,56 +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.plugin.example;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import java.io.IOException;
import java.nio.file.Path;
/**
* Example configuration.
*/
public class ExamplePluginConfiguration {
private final Settings customSettings;
public static final Setting<String> TEST_SETTING =
new Setting<String>("test", "default_value",
(value) -> value, Setting.Property.Dynamic);
public ExamplePluginConfiguration(Environment env) {
// The directory part of the location matches the artifactId of this plugin
Path path = env.configFile().resolve("jvm-example/example.yml");
try {
customSettings = Settings.builder().loadFromPath(path).build();
} catch (IOException e) {
throw new RuntimeException("Failed to load settings, giving up", e);
}
// asserts for tests
assert customSettings != null;
assert TEST_SETTING.get(customSettings) != null;
}
public String getTestConfig() {
return TEST_SETTING.get(customSettings);
}
}

View File

@ -1,13 +0,0 @@
# Integration tests for JVM Example Plugin
#
"JVM Example loaded":
- do:
cluster.state: {}
# Get master node id
- set: { master_node: master }
- do:
nodes.info: {}
- match: { nodes.$master.plugins.0.name: jvm-example }

View File

@ -1,22 +0,0 @@
---
"Help":
- do:
cat.configured_example:
help: true
- match:
$body: |
/^ test .+ \n
$/
---
"Data":
- do:
cat.configured_example:
v: false
- match:
$body: |
/^
foo \s+
$/

View File

@ -22,7 +22,7 @@ apply plugin: 'elasticsearch.vagrant'
List<String> plugins = []
for (Project subproj : project.rootProject.subprojects) {
if (subproj.path.startsWith(':plugins:')) {
if (subproj.path.startsWith(':plugins:') || subproj.path.equals(':example-plugins:custom-settings')) {
// add plugin as a dep
dependencies {
bats project(path: "${subproj.path}", configuration: 'zip')

View File

@ -57,7 +57,7 @@ setup() {
# other tests. Commenting out lots of test cases seems like a reasonably
# common workflow.
if [ $BATS_TEST_NUMBER == 1 ] ||
[[ $BATS_TEST_NAME =~ install_jvm.*example ]] ||
[[ $BATS_TEST_NAME =~ install_a_sample_plugin ]] ||
[ ! -d "$ESHOME" ]; then
clean_before_test
install
@ -89,7 +89,7 @@ else
}
fi
@test "[$GROUP] install jvm-example plugin with a symlinked plugins path" {
@test "[$GROUP] install a sample plugin with a symlinked plugins path" {
# Clean up after the last time this test was run
rm -rf /tmp/plugins.*
rm -rf /tmp/old_plugins.*
@ -99,48 +99,63 @@ fi
chown -R elasticsearch:elasticsearch "$es_plugins"
ln -s "$es_plugins" "$ESPLUGINS"
install_jvm_example
install_plugin_example
start_elasticsearch_service
# check that symlinked plugin was actually picked up
curl -s localhost:9200/_cat/configured_example | sed 's/ *$//' > /tmp/installed
echo "foo" > /tmp/expected
curl -XGET -H 'Content-Type: application/json' 'http://localhost:9200/_cat/plugins?h=component' | sed 's/ *$//' > /tmp/installed
echo "custom-settings" > /tmp/expected
diff /tmp/installed /tmp/expected
curl -XGET -H 'Content-Type: application/json' 'http://localhost:9200/_cluster/settings?include_defaults&filter_path=defaults.custom.simple' > /tmp/installed
echo -n '{"defaults":{"custom":{"simple":"foo"}}}' > /tmp/expected
diff /tmp/installed /tmp/expected
stop_elasticsearch_service
remove_jvm_example
remove_plugin_example
unlink "$ESPLUGINS"
}
@test "[$GROUP] install jvm-example plugin with a custom CONFIG_DIR" {
@test "[$GROUP] install a sample plugin with a custom CONFIG_DIR" {
# Clean up after the last time we ran this test
rm -rf /tmp/config.*
move_config
ES_PATH_CONF="$ESCONFIG" install_jvm_example
ES_PATH_CONF="$ESCONFIG" install_plugin_example
ES_PATH_CONF="$ESCONFIG" start_elasticsearch_service
diff <(curl -s localhost:9200/_cat/configured_example | sed 's/ //g') <(echo "foo")
# check that symlinked plugin was actually picked up
curl -XGET -H 'Content-Type: application/json' 'http://localhost:9200/_cat/plugins?h=component' | sed 's/ *$//' > /tmp/installed
echo "custom-settings" > /tmp/expected
diff /tmp/installed /tmp/expected
curl -XGET -H 'Content-Type: application/json' 'http://localhost:9200/_cluster/settings?include_defaults&filter_path=defaults.custom.simple' > /tmp/installed
echo -n '{"defaults":{"custom":{"simple":"foo"}}}' > /tmp/expected
diff /tmp/installed /tmp/expected
stop_elasticsearch_service
ES_PATH_CONF="$ESCONFIG" remove_jvm_example
ES_PATH_CONF="$ESCONFIG" remove_plugin_example
}
@test "[$GROUP] install jvm-example plugin from a directory with a space" {
@test "[$GROUP] install a sample plugin from a directory with a space" {
rm -rf "/tmp/plugins with space"
mkdir -p "/tmp/plugins with space"
local zip=$(ls jvm-example-*.zip)
local zip=$(ls custom-settings-*.zip)
cp $zip "/tmp/plugins with space"
install_jvm_example "/tmp/plugins with space/$zip"
remove_jvm_example
install_plugin_example "/tmp/plugins with space/$zip"
remove_plugin_example
}
@test "[$GROUP] install jvm-example plugin to elasticsearch directory with a space" {
@test "[$GROUP] install a sample plugin to elasticsearch directory with a space" {
[ "$GROUP" == "TAR PLUGINS" ] || skip "Test case only supported by TAR PLUGINS"
move_elasticsearch "/tmp/elastic search"
install_jvm_example
remove_jvm_example
install_plugin_example
remove_plugin_example
}
@test "[$GROUP] fail if java executable is not found" {
@ -161,8 +176,8 @@ fi
# Note that all of the tests from here to the end of the file expect to be run
# in sequence and don't take well to being run one at a time.
@test "[$GROUP] install jvm-example plugin" {
install_jvm_example
@test "[$GROUP] install a sample plugin" {
install_plugin_example
}
@test "[$GROUP] install icu plugin" {
@ -293,8 +308,8 @@ fi
stop_elasticsearch_service
}
@test "[$GROUP] remove jvm-example plugin" {
remove_jvm_example
@test "[$GROUP] remove a sample plugin" {
remove_plugin_example
}
@test "[$GROUP] remove icu plugin" {
@ -399,8 +414,8 @@ fi
stop_elasticsearch_service
}
@test "[$GROUP] install jvm-example with different logging modes and check output" {
local relativePath=${1:-$(readlink -m jvm-example-*.zip)}
@test "[$GROUP] install a sample plugin with different logging modes and check output" {
local relativePath=${1:-$(readlink -m custom-settings-*.zip)}
sudo -E -u $ESPLUGIN_COMMAND_USER "$ESHOME/bin/elasticsearch-plugin" install "file://$relativePath" > /tmp/plugin-cli-output
# exclude progress line
local loglines=$(cat /tmp/plugin-cli-output | grep -v "^[[:cntrl:]]" | wc -l)
@ -409,9 +424,9 @@ fi
cat /tmp/plugin-cli-output
false
}
remove_jvm_example
remove_plugin_example
local relativePath=${1:-$(readlink -m jvm-example-*.zip)}
local relativePath=${1:-$(readlink -m custom-settings-*.zip)}
sudo -E -u $ESPLUGIN_COMMAND_USER ES_JAVA_OPTS="-Des.logger.level=DEBUG" "$ESHOME/bin/elasticsearch-plugin" install "file://$relativePath" > /tmp/plugin-cli-output
local loglines=$(cat /tmp/plugin-cli-output | grep -v "^[[:cntrl:]]" | wc -l)
[ "$loglines" -gt "2" ] || {
@ -419,7 +434,7 @@ fi
cat /tmp/plugin-cli-output
false
}
remove_jvm_example
remove_plugin_example
}
@test "[$GROUP] test java home with space" {
@ -456,7 +471,7 @@ fi
}
@test "[$GROUP] test umask" {
install_jvm_example $(readlink -m jvm-example-*.zip) 0077
install_plugin_example $(readlink -m custom-settings-*.zip) 0077
}
@test "[$GROUP] hostname" {

View File

@ -82,50 +82,49 @@ remove_plugin() {
fi
}
# Install the jvm-example plugin which fully exercises the special case file
# placements for non-site plugins.
install_jvm_example() {
local relativePath=${1:-$(readlink -m jvm-example-*.zip)}
install_plugin jvm-example "$relativePath" $2
# Install a sample plugin which fully exercises the special case file placements.
install_plugin_example() {
local relativePath=${1:-$(readlink -m custom-settings-*.zip)}
install_plugin custom-settings "$relativePath" $2
bin_user=$(find "$ESHOME/bin" -maxdepth 0 -printf "%u")
bin_owner=$(find "$ESHOME/bin" -maxdepth 0 -printf "%g")
assert_file "$ESHOME/plugins/jvm-example" d $bin_user $bin_owner 755
assert_file "$ESHOME/plugins/jvm-example/jvm-example-$(cat version).jar" f $bin_user $bin_owner 644
assert_file "$ESHOME/plugins/custom-settings" d $bin_user $bin_owner 755
assert_file "$ESHOME/plugins/custom-settings/custom-settings-$(cat version).jar" f $bin_user $bin_owner 644
#owner group and permissions vary depending on how es was installed
#just make sure that everything is the same as the parent bin dir, which was properly set up during install
assert_file "$ESHOME/bin/jvm-example" d $bin_user $bin_owner 755
assert_file "$ESHOME/bin/jvm-example/test" f $bin_user $bin_owner 755
assert_file "$ESHOME/bin/custom-settings" d $bin_user $bin_owner 755
assert_file "$ESHOME/bin/custom-settings/test" f $bin_user $bin_owner 755
#owner group and permissions vary depending on how es was installed
#just make sure that everything is the same as $CONFIG_DIR, which was properly set up during install
config_user=$(find "$ESCONFIG" -maxdepth 0 -printf "%u")
config_owner=$(find "$ESCONFIG" -maxdepth 0 -printf "%g")
# directories should user the user file-creation mask
assert_file "$ESCONFIG/jvm-example" d $config_user $config_owner 750
assert_file "$ESCONFIG/jvm-example/example.yml" f $config_user $config_owner 660
assert_file "$ESCONFIG/custom-settings" d $config_user $config_owner 750
assert_file "$ESCONFIG/custom-settings/custom.yml" f $config_user $config_owner 660
run sudo -E -u vagrant LANG="en_US.UTF-8" cat "$ESCONFIG/jvm-example/example.yml"
run sudo -E -u vagrant LANG="en_US.UTF-8" cat "$ESCONFIG/custom-settings/custom.yml"
[ $status = 1 ]
[[ "$output" == *"Permission denied"* ]] || {
echo "Expected permission denied but found $output:"
false
}
echo "Running jvm-example's bin script...."
"$ESHOME/bin/jvm-example/test" | grep test
echo "Running sample plugin bin script...."
"$ESHOME/bin/custom-settings/test" | grep test
}
# Remove the jvm-example plugin which fully exercises the special cases of
# Remove the sample plugin which fully exercises the special cases of
# removing bin and not removing config.
remove_jvm_example() {
remove_plugin jvm-example
remove_plugin_example() {
remove_plugin custom-settings
assert_file_not_exist "$ESHOME/bin/jvm-example"
assert_file_exist "$ESCONFIG/jvm-example"
assert_file_exist "$ESCONFIG/jvm-example/example.yml"
assert_file_not_exist "$ESHOME/bin/custom-settings"
assert_file_exist "$ESCONFIG/custom-settings"
assert_file_exist "$ESCONFIG/custom-settings/custom.yml"
}
# Install a plugin with a special prefix. For the most part prefixes are just