Merge remote-tracking branch 'origin/master' into feature/client_aggs_parsing

This commit is contained in:
Tanguy Leroux 2017-05-18 09:43:57 +02:00
commit eeef2e6c31
130 changed files with 684 additions and 2802 deletions

View File

@ -61,17 +61,42 @@ configure(subprojects.findAll { it.projectDir.toPath().startsWith(rootPath) }) {
}
}
int prevMajor = Integer.parseInt(VersionProperties.elasticsearch.split('\\.')[0]) - 1
String prevSnapshot = VersionProperties.elasticsearch.contains('alpha') ? '-SNAPSHOT' : ''
// introspect all versions of ES that may be tested agains for backwards compatibility
String currentVersion = VersionProperties.elasticsearch.minus('-SNAPSHOT')
int prevMajor = Integer.parseInt(currentVersion.split('\\.')[0]) - 1
File versionFile = file('core/src/main/java/org/elasticsearch/Version.java')
List<String> versionLines = versionFile.readLines('UTF-8')
int prevMinor = 0
List<String> versions = []
// keep track of the previous major version's last minor, so we know where wire compat begins
int prevMinorIndex = -1 // index in the versions list of the last minor from the prev major
int lastPrevMinor = -1 // the minor version number from the prev major we most recently seen
for (String line : versionLines) {
Matcher match = line =~ /\W+public static final Version V_${prevMajor}_(\d+)_.*/
Matcher match = line =~ /\W+public static final Version V_(\d+)_(\d+)_(\d+)(_UNRELEASED)? .*/
if (match.matches()) {
prevMinor = Math.max(Integer.parseInt(match.group(1)), prevMinor)
int major = Integer.parseInt(match.group(1))
int minor = Integer.parseInt(match.group(2))
int bugfix = Integer.parseInt(match.group(3))
String versionStr = "${major}.${minor}.${bugfix}"
if (currentVersion != versionStr) {
versions.add(versionStr)
}
if (major == prevMajor && minor > lastPrevMinor) {
prevMinorIndex = versions.size() - 1
lastPrevMinor = minor
}
}
}
if (versions.toSorted() != versions) {
throw new GradleException('Versions.java contains out of order version constants')
}
if (currentVersion.split('\\.')[2].split('-')[0] == '0') {
// If on a release branch, after the initial release of that branch, the bugfix version will
// be bumped, and will be != 0. On master and N.x branches, we want to test against the
// unreleased version of closest branch. So for those cases, the version includes -SNAPSHOT,
// and the bwc-zip distribution will checkout and build that version. The version parsing
// logic above pulls the bugfix version, and then strips off any prerelease version
versions[-1] += '-SNAPSHOT'
}
// injecting groovy property variables into all projects
allprojects {
@ -80,7 +105,8 @@ allprojects {
isEclipse = System.getProperty("eclipse.launcher") != null || gradle.startParameter.taskNames.contains('eclipse') || gradle.startParameter.taskNames.contains('cleanEclipse')
isIdea = System.getProperty("idea.active") != null || gradle.startParameter.taskNames.contains('idea') || gradle.startParameter.taskNames.contains('cleanIdea')
// for backcompat testing
bwcVersion = "${prevMajor}.${prevMinor}.0${prevSnapshot}"
indexCompatVersions = versions
wireCompatVersions = versions.subList(prevMinorIndex, versions.size())
}
}
@ -128,7 +154,7 @@ subprojects {
"org.elasticsearch.client:transport:${version}": ':client:transport',
"org.elasticsearch.test:framework:${version}": ':test:framework',
"org.elasticsearch.distribution.integ-test-zip:elasticsearch:${version}": ':distribution:integ-test-zip',
"org.elasticsearch.distribution.zip:elasticsearch:${bwcVersion}": ':distribution:bwc-zip',
"org.elasticsearch.distribution.zip:elasticsearch:${wireCompatVersions[-1]}": ':distribution:bwc-zip',
"org.elasticsearch.distribution.zip:elasticsearch:${version}": ':distribution:zip',
"org.elasticsearch.distribution.tar:elasticsearch:${version}": ':distribution:tar',
"org.elasticsearch.distribution.rpm:elasticsearch:${version}": ':distribution:rpm',

View File

@ -180,12 +180,14 @@ public class RestTestsFromSnippetsTask extends SnippetsTask {
}
if (test.setup != null) {
// Insert a setup defined outside of the docs
String setup = setups[test.setup]
if (setup == null) {
throw new InvalidUserDataException("Couldn't find setup "
+ "for $test")
for (String setupName : test.setup.split(',')) {
String setup = setups[setupName]
if (setup == null) {
throw new InvalidUserDataException("Couldn't find setup "
+ "for $test")
}
current.println(setup)
}
current.println(setup)
}
body(test, false)

View File

@ -338,7 +338,7 @@ public class QueryDSLDocumentationTests extends ESTestCase {
Map<String, Object> parameters = new HashMap<>();
parameters.put("param1", 5);
scriptQuery(new Script(
ScriptType.FILE, // <1>
ScriptType.STORED, // <1>
"painless", // <2>
"myscript", // <3>
singletonMap("param1", 5))); // <4>

View File

@ -256,7 +256,6 @@ final class Security {
addPath(policy, Environment.PATH_HOME_SETTING.getKey(), environment.modulesFile(), "read,readlink");
addPath(policy, Environment.PATH_HOME_SETTING.getKey(), environment.pluginsFile(), "read,readlink");
addPath(policy, Environment.PATH_CONF_SETTING.getKey(), environment.configFile(), "read,readlink");
addPath(policy, Environment.PATH_SCRIPTS_SETTING.getKey(), environment.scriptsFile(), "read,readlink");
// read-write dirs
addPath(policy, "java.io.tmpdir", environment.tmpFile(), "read,readlink,write,delete");
addPath(policy, Environment.PATH_LOGS_SETTING.getKey(), environment.logsFile(), "read,readlink,write,delete");

View File

@ -193,7 +193,7 @@ public class RoutingNode implements Iterable<ShardRouting> {
public String prettyPrint() {
StringBuilder sb = new StringBuilder();
sb.append("-----node_id[").append(nodeId).append("][" + (node == null ? "X" : "V") + "]\n");
sb.append("-----node_id[").append(nodeId).append("][").append(node == null ? "X" : "V").append("]\n");
for (ShardRouting entry : shards.values()) {
sb.append("--------").append(entry.shortSummary()).append('\n');
}

View File

@ -121,15 +121,15 @@ public final class IfConfig {
sb.append("inet ");
sb.append(NetworkAddress.format(address));
int netmask = 0xFFFFFFFF << (32 - interfaceAddress.getNetworkPrefixLength());
sb.append(" netmask:" + NetworkAddress.format(InetAddress.getByAddress(new byte[] {
(byte)(netmask >>> 24),
(byte)(netmask >>> 16 & 0xFF),
(byte)(netmask >>> 8 & 0xFF),
(byte)(netmask & 0xFF)
sb.append(" netmask:").append(NetworkAddress.format(InetAddress.getByAddress(new byte[]{
(byte) (netmask >>> 24),
(byte) (netmask >>> 16 & 0xFF),
(byte) (netmask >>> 8 & 0xFF),
(byte) (netmask & 0xFF)
})));
InetAddress broadcast = interfaceAddress.getBroadcast();
if (broadcast != null) {
sb.append(" broadcast:" + NetworkAddress.format(broadcast));
sb.append(" broadcast:").append(NetworkAddress.format(broadcast));
}
}
if (address.isLoopbackAddress()) {
@ -160,8 +160,8 @@ public final class IfConfig {
if (nic.isVirtual()) {
flags.append("VIRTUAL ");
}
flags.append("mtu:" + nic.getMTU());
flags.append(" index:" + nic.getIndex());
flags.append("mtu:").append(nic.getMTU());
flags.append(" index:").append(nic.getIndex());
return flags.toString();
}
}

View File

@ -302,7 +302,6 @@ public final class ClusterSettings extends AbstractScopedSettings {
IndexSettings.QUERY_STRING_ALLOW_LEADING_WILDCARD,
ScriptService.SCRIPT_CACHE_SIZE_SETTING,
ScriptService.SCRIPT_CACHE_EXPIRE_SETTING,
ScriptService.SCRIPT_AUTO_RELOAD_ENABLED_SETTING,
ScriptService.SCRIPT_MAX_SIZE_IN_BYTES,
ScriptService.SCRIPT_MAX_COMPILATIONS_PER_MINUTE,
IndicesService.INDICES_CACHE_CLEAN_INTERVAL_SETTING,
@ -321,7 +320,6 @@ public final class ClusterSettings extends AbstractScopedSettings {
Environment.DEFAULT_PATH_LOGS_SETTING,
Environment.PATH_LOGS_SETTING,
Environment.PATH_REPO_SETTING,
Environment.PATH_SCRIPTS_SETTING,
Environment.PATH_SHARED_DATA_SETTING,
Environment.PIDFILE_SETTING,
NodeEnvironment.NODE_ID_SEED_SETTING,

View File

@ -37,7 +37,7 @@ public abstract class SecureSetting<T> extends Setting<T> {
/** Determines whether legacy settings with sensitive values should be allowed. */
private static final boolean ALLOW_INSECURE_SETTINGS = Booleans.parseBoolean(System.getProperty("es.allow_insecure_settings", "false"));
private static final Set<Property> ALLOWED_PROPERTIES = EnumSet.of(Property.Deprecated, Property.Shared);
private static final Set<Property> ALLOWED_PROPERTIES = EnumSet.of(Property.Deprecated);
private static final Property[] FIXED_PROPERTIES = {
Property.NodeScope

View File

@ -85,11 +85,6 @@ public class Setting<T> extends ToXContentToBytes {
*/
Filtered,
/**
* iff this setting is shared with more than one module ie. can be defined multiple times.
*/
Shared,
/**
* iff this setting can be dynamically updateable
*/
@ -270,13 +265,6 @@ public class Setting<T> extends ToXContentToBytes {
return properties.contains(Property.Deprecated);
}
/**
* Returns <code>true</code> if this setting is shared with more than one other module or plugin, otherwise <code>false</code>
*/
public boolean isShared() {
return properties.contains(Property.Shared);
}
/**
* Returns <code>true</code> iff this setting is a group setting. Group settings represent a set of settings rather than a single value.
* The key, see {@link #getKey()}, in contrast to non-group settings is a prefix like <tt>cluster.store.</tt> that matches all settings

View File

@ -164,14 +164,14 @@ public class SettingsModule implements Module {
if (setting.hasNodeScope() || setting.hasIndexScope()) {
if (setting.hasNodeScope()) {
Setting<?> existingSetting = nodeSettings.get(setting.getKey());
if (existingSetting != null && (setting.isShared() == false || existingSetting.isShared() == false)) {
if (existingSetting != null) {
throw new IllegalArgumentException("Cannot register setting [" + setting.getKey() + "] twice");
}
nodeSettings.put(setting.getKey(), setting);
}
if (setting.hasIndexScope()) {
Setting<?> existingSetting = indexSettings.get(setting.getKey());
if (existingSetting != null && (setting.isShared() == false || existingSetting.isShared() == false)) {
if (existingSetting != null) {
throw new IllegalArgumentException("Cannot register setting [" + setting.getKey() + "] twice");
}
indexSettings.put(setting.getKey(), setting);

View File

@ -55,8 +55,6 @@ public class Environment {
public static final Setting<String> DEFAULT_PATH_CONF_SETTING = Setting.simpleString("default.path.conf", Property.NodeScope);
public static final Setting<String> PATH_CONF_SETTING =
new Setting<>("path.conf", DEFAULT_PATH_CONF_SETTING, Function.identity(), Property.NodeScope);
public static final Setting<String> PATH_SCRIPTS_SETTING =
Setting.simpleString("path.scripts", Property.NodeScope, Property.Deprecated);
public static final Setting<List<String>> DEFAULT_PATH_DATA_SETTING =
Setting.listSetting("default.path.data", Collections.emptyList(), Function.identity(), Property.NodeScope);
public static final Setting<List<String>> PATH_DATA_SETTING =
@ -79,8 +77,6 @@ public class Environment {
private final Path configFile;
private final Path scriptsFile;
private final Path pluginsFile;
private final Path modulesFile;
@ -116,12 +112,6 @@ public class Environment {
configFile = homeFile.resolve("config");
}
if (PATH_SCRIPTS_SETTING.exists(settings)) {
scriptsFile = PathUtils.get(cleanPath(PATH_SCRIPTS_SETTING.get(settings)));
} else {
scriptsFile = configFile.resolve("scripts");
}
pluginsFile = homeFile.resolve("plugins");
List<String> dataPaths = PATH_DATA_SETTING.get(settings);
@ -281,13 +271,6 @@ public class Environment {
return configFile;
}
/**
* Location of on-disk scripts
*/
public Path scriptsFile() {
return scriptsFile;
}
public Path pluginsFile() {
return pluginsFile;
}
@ -332,7 +315,6 @@ public class Environment {
assertEquals(actual.dataWithClusterFiles(), expected.dataWithClusterFiles(), "dataWithClusterFiles");
assertEquals(actual.repoFiles(), expected.repoFiles(), "repoFiles");
assertEquals(actual.configFile(), expected.configFile(), "configFile");
assertEquals(actual.scriptsFile(), expected.scriptsFile(), "scriptsFile");
assertEquals(actual.pluginsFile(), expected.pluginsFile(), "pluginsFile");
assertEquals(actual.binFile(), expected.binFile(), "binFile");
assertEquals(actual.libFile(), expected.libFile(), "libFile");

View File

@ -21,6 +21,7 @@ package org.elasticsearch.index.shard;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.message.ParameterizedMessage;
import org.apache.logging.log4j.util.Supplier;
import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.search.internal.SearchContext;
import java.util.List;
@ -104,6 +105,14 @@ public interface SearchOperationListener {
*/
default void onFreeScrollContext(SearchContext context) {};
/**
* Executed prior to using a {@link SearchContext} that has been retrieved
* from the active contexts. If the context is deemed invalid a runtime
* exception can be thrown, which will prevent the context from being used.
* @param context the context retrieved from the active contexts
*/
default void validateSearchContext(SearchContext context) {}
/**
* A Composite listener that multiplexes calls to each of the listeners methods.
*/
@ -225,5 +234,18 @@ public interface SearchOperationListener {
}
}
}
@Override
public void validateSearchContext(SearchContext context) {
Exception exception = null;
for (SearchOperationListener listener : listeners) {
try {
listener.validateSearchContext(context);
} catch (Exception e) {
exception = ExceptionsHelper.useOrSuppress(exception, e);
}
}
ExceptionsHelper.reThrowIfNotNull(exception);
}
}
}

View File

@ -325,8 +325,7 @@ public class Node implements Closeable {
}
client = new NodeClient(settings, threadPool);
final ResourceWatcherService resourceWatcherService = new ResourceWatcherService(settings, threadPool);
final ScriptModule scriptModule = ScriptModule.create(settings, this.environment, resourceWatcherService,
pluginsService.filterPlugins(ScriptPlugin.class));
final ScriptModule scriptModule = ScriptModule.create(settings, pluginsService.filterPlugins(ScriptPlugin.class));
AnalysisModule analysisModule = new AnalysisModule(this.environment, pluginsService.filterPlugins(AnalysisPlugin.class));
additionalSettings.addAll(scriptModule.getSettings());
// this is as early as we can validate settings at this point. we already pass them to ScriptModule as well as ThreadPool

View File

@ -19,13 +19,9 @@
package org.elasticsearch.plugins;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.script.NativeScriptFactory;
import org.elasticsearch.script.ScriptContext;
import org.elasticsearch.script.ScriptEngine;
import java.util.Collections;
import java.util.List;
/**
* An additional extension point for {@link Plugin}s that extends Elasticsearch's scripting functionality.
*/
@ -38,13 +34,6 @@ public interface ScriptPlugin {
return null;
}
/**
* Returns a list of {@link NativeScriptFactory} instances.
*/
default List<NativeScriptFactory> getNativeScripts() {
return Collections.emptyList();
}
/**
* Returns a {@link ScriptContext.Plugin} instance or <code>null</code> if this plugin doesn't add a new script context plugin
*/

View File

@ -1,40 +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.script;
/**
* A simpler base class instead of {@link AbstractSearchScript} for computations
* that return a double number.
*/
public abstract class AbstractDoubleSearchScript extends AbstractSearchScript {
@Override
public Object run() {
return runAsDouble();
}
@Override
public abstract double runAsDouble();
@Override
public long runAsLong() {
return (long) runAsDouble();
}
}

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.
*/
package org.elasticsearch.script;
public abstract class AbstractExecutableScript implements ExecutableScript {
@Override
public void setNextVar(String name, Object value) {
}
}

View File

@ -1,40 +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.script;
/**
* A simpler base class instead of {@link AbstractSearchScript} for computations
* that return a long number.
*/
public abstract class AbstractLongSearchScript extends AbstractSearchScript {
@Override
public Object run() {
return runAsLong();
}
@Override
public abstract long runAsLong();
@Override
public double runAsDouble() {
return runAsLong();
}
}

View File

@ -1,124 +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.script;
import org.apache.lucene.search.Scorer;
import org.elasticsearch.index.fielddata.ScriptDocValues;
import org.elasticsearch.search.lookup.LeafDocLookup;
import org.elasticsearch.search.lookup.LeafFieldsLookup;
import org.elasticsearch.search.lookup.LeafSearchLookup;
import org.elasticsearch.search.lookup.SourceLookup;
import java.io.IOException;
import java.util.Map;
/**
* A base class for any script type that is used during the search process (custom score, aggs, and so on).
* <p>
* If the script returns a specific numeric type, consider overriding the type specific base classes
* such as {@link AbstractDoubleSearchScript} and {@link AbstractLongSearchScript}
* for better performance.
* <p>
* The use is required to implement the {@link #run()} method.
*/
public abstract class AbstractSearchScript extends AbstractExecutableScript implements LeafSearchScript {
private LeafSearchLookup lookup;
private Scorer scorer;
/**
* Returns the doc lookup allowing to access field data (cached) values as well as the current document score
* (where applicable).
*/
protected final LeafDocLookup doc() {
return lookup.doc();
}
/**
* Returns the current score and only applicable when used as a scoring script in a custom score query!.
*/
protected final float score() throws IOException {
return scorer.score();
}
/**
* Returns field data strings access for the provided field.
*/
protected ScriptDocValues.Strings docFieldStrings(String field) {
return (ScriptDocValues.Strings) doc().get(field);
}
/**
* Returns field data double (floating point) access for the provided field.
*/
protected ScriptDocValues.Doubles docFieldDoubles(String field) {
return (ScriptDocValues.Doubles) doc().get(field);
}
/**
* Returns field data long (integers) access for the provided field.
*/
protected ScriptDocValues.Longs docFieldLongs(String field) {
return (ScriptDocValues.Longs) doc().get(field);
}
/**
* Allows to access the actual source (loaded and parsed).
*/
protected final SourceLookup source() {
return lookup.source();
}
/**
* Allows to access the *stored* fields.
*/
protected final LeafFieldsLookup fields() {
return lookup.fields();
}
void setLookup(LeafSearchLookup lookup) {
this.lookup = lookup;
}
@Override
public void setScorer(Scorer scorer) {
this.scorer = scorer;
}
@Override
public void setDocument(int doc) {
lookup.setDocument(doc);
}
@Override
public void setSource(Map<String, Object> source) {
lookup.source().setSource(source);
}
@Override
public long runAsLong() {
return ((Number) run()).longValue();
}
@Override
public double runAsDouble() {
return ((Number) run()).doubleValue();
}
}

View File

@ -1,105 +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.script;
import org.apache.logging.log4j.Logger;
import org.apache.lucene.index.LeafReaderContext;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.logging.DeprecationLogger;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.search.lookup.SearchLookup;
import java.io.IOException;
import java.util.Map;
import static java.util.Collections.unmodifiableMap;
/**
* A native script engine service.
*/
public class NativeScriptEngine extends AbstractComponent implements ScriptEngine {
public static final String NAME = "native";
private final Map<String, NativeScriptFactory> scripts;
public NativeScriptEngine(Settings settings, Map<String, NativeScriptFactory> scripts) {
super(settings);
if (scripts.isEmpty() == false) {
Logger logger = Loggers.getLogger(ScriptModule.class);
DeprecationLogger deprecationLogger = new DeprecationLogger(logger);
deprecationLogger.deprecated("Native scripts are deprecated. Use a custom ScriptEngine to write scripts in java.");
}
this.scripts = unmodifiableMap(scripts);
}
@Override
public String getType() {
return NAME;
}
@Override
public String getExtension() {
return ""; // Native scripts have no extensions
}
@Override
public Object compile(String scriptName, String scriptSource, Map<String, String> params) {
NativeScriptFactory scriptFactory = scripts.get(scriptSource);
if (scriptFactory != null) {
return scriptFactory;
}
throw new IllegalArgumentException("Native script [" + scriptSource + "] not found");
}
@Override
public ExecutableScript executable(CompiledScript compiledScript, @Nullable Map<String, Object> vars) {
NativeScriptFactory scriptFactory = (NativeScriptFactory) compiledScript.compiled();
return scriptFactory.newScript(vars);
}
@Override
public SearchScript search(CompiledScript compiledScript, final SearchLookup lookup, @Nullable final Map<String, Object> vars) {
final NativeScriptFactory scriptFactory = (NativeScriptFactory) compiledScript.compiled();
final AbstractSearchScript script = (AbstractSearchScript) scriptFactory.newScript(vars);
return new SearchScript() {
@Override
public LeafSearchScript getLeafSearchScript(LeafReaderContext context) throws IOException {
script.setLookup(lookup.getLeafSearchLookup(context));
return script;
}
@Override
public boolean needsScores() {
return scriptFactory.needsScores();
}
};
}
@Override
public void close() {
}
@Override
public boolean isInlineScriptEnabled() {
return true;
}
}

View File

@ -1,57 +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.script;
import org.elasticsearch.common.Nullable;
import java.util.Map;
/**
* A factory to create instances of either {@link ExecutableScript} or {@link SearchScript}. Note,
* if this factory creates {@link SearchScript}, it must extend {@link AbstractSearchScript}.
*
* @see AbstractExecutableScript
* @see AbstractSearchScript
* @see AbstractLongSearchScript
* @see AbstractDoubleSearchScript
* @deprecated Create a {@link ScriptEngine} instead of using native scripts
*/
@Deprecated
public interface NativeScriptFactory {
/**
* Creates a new instance of either a {@link ExecutableScript} or a {@link SearchScript}.
*
* @param params The parameters passed to the script. Can be <tt>null</tt>.
*/
ExecutableScript newScript(@Nullable Map<String, Object> params);
/**
* Indicates if document scores may be needed by the produced scripts.
*
* @return {@code true} if scores are needed.
*/
boolean needsScores();
/**
* Returns the name of the script factory
*/
String getName();
}

View File

@ -74,15 +74,6 @@ import java.util.Objects;
* <li> {@link Script#params} - {@link Map} of user-defined parameters; must not be {@code null},
* use an empty {@link Map} to specify no params
* </ul>
* <li> {@link ScriptType#FILE}
* <ul>
* <li> {@link Script#lang} - specifies the language for look up, defaults to {@link Script#DEFAULT_SCRIPT_LANG}
* <li> {@link Script#idOrCode} - specifies the id of the file script to be looked up, must not be {@code null}
* <li> {@link Script#options} - compiler options will be specified when a file script is loaded,
* so they have no meaning here and must be {@code null}
* <li> {@link Script#params} - {@link Map} of user-defined parameters; must not be {@code null},
* use an empty {@link Map} to specify no params
* </ul>
* </ul>
*/
public final class Script implements ToXContentObject, Writeable {
@ -193,26 +184,13 @@ public final class Script implements ToXContentObject, Writeable {
this.idOrCode = idOrCode;
}
/**
* Set both the id and the type of the file script.
*/
private void setFile(String idOrCode) {
if (type != null) {
throwOnlyOneOfType();
}
type = ScriptType.FILE;
this.idOrCode = idOrCode;
}
/**
* Helper method to throw an exception if more than one type of {@link Script} is specified.
*/
private void throwOnlyOneOfType() {
throw new IllegalArgumentException("must only use one of [" +
ScriptType.INLINE.getParseField().getPreferredName() + " + , " +
ScriptType.STORED.getParseField().getPreferredName() + " + , " +
ScriptType.FILE.getParseField().getPreferredName() + "]" +
ScriptType.INLINE.getParseField().getPreferredName() + ", " +
ScriptType.STORED.getParseField().getPreferredName() + "]" +
" when specifying a script");
}
@ -242,8 +220,7 @@ public final class Script implements ToXContentObject, Writeable {
if (type == null) {
throw new IllegalArgumentException(
"must specify either code for an [" + ScriptType.INLINE.getParseField().getPreferredName() + "] script " +
"or an id for a [" + ScriptType.STORED.getParseField().getPreferredName() + "] script " +
"or [" + ScriptType.FILE.getParseField().getPreferredName() + "] script");
"or an id for a [" + ScriptType.STORED.getParseField().getPreferredName() + "] script");
}
if (type == ScriptType.INLINE) {
@ -283,22 +260,6 @@ public final class Script implements ToXContentObject, Writeable {
throw new IllegalArgumentException("field [" + OPTIONS_PARSE_FIELD.getPreferredName() + "] " +
"cannot be specified using a [" + ScriptType.STORED.getParseField().getPreferredName() + "] script");
}
} else if (type == ScriptType.FILE) {
if (lang == null) {
lang = defaultLang;
}
if (idOrCode == null) {
throw new IllegalArgumentException(
"must specify <code> for an [" + ScriptType.FILE.getParseField().getPreferredName() + "] script");
}
if (options.isEmpty()) {
options = null;
} else {
throw new IllegalArgumentException("field [" + OPTIONS_PARSE_FIELD.getPreferredName() + "] " +
"cannot be specified using a [" + ScriptType.FILE.getParseField().getPreferredName() + "] script");
}
}
return new Script(type, lang, idOrCode, options, params);
@ -311,7 +272,6 @@ public final class Script implements ToXContentObject, Writeable {
// Defines the fields necessary to parse a Script as XContent using an ObjectParser.
PARSER.declareField(Builder::setInline, parser -> parser, ScriptType.INLINE.getParseField(), ValueType.OBJECT_OR_STRING);
PARSER.declareString(Builder::setStored, ScriptType.STORED.getParseField());
PARSER.declareString(Builder::setFile, ScriptType.FILE.getParseField());
PARSER.declareString(Builder::setLang, LANG_PARSE_FIELD);
PARSER.declareField(Builder::setOptions, XContentParser::mapStrings, OPTIONS_PARSE_FIELD, ValueType.OBJECT);
PARSER.declareField(Builder::setParams, XContentParser::map, PARAMS_PARSE_FIELD, ValueType.OBJECT);
@ -425,10 +385,10 @@ public final class Script implements ToXContentObject, Writeable {
/**
* Constructor for a script that does not need to use compiler options.
* @param type The {@link ScriptType}.
* @param lang The language for this {@link Script} if the {@link ScriptType} is {@link ScriptType#INLINE} or
* {@link ScriptType#FILE}. For {@link ScriptType#STORED} scripts this should be null, but can
* @param lang The language for this {@link Script} if the {@link ScriptType} is {@link ScriptType#INLINE}.
* For {@link ScriptType#STORED} scripts this should be null, but can
* be specified to access scripts stored as part of the stored scripts deprecated API.
* @param idOrCode The id for this {@link Script} if the {@link ScriptType} is {@link ScriptType#FILE} or {@link ScriptType#STORED}.
* @param idOrCode The id for this {@link Script} if the {@link ScriptType} is {@link ScriptType#STORED}.
* The code for this {@link Script} if the {@link ScriptType} is {@link ScriptType#INLINE}.
* @param params The user-defined params to be bound for script execution.
*/
@ -439,10 +399,10 @@ public final class Script implements ToXContentObject, Writeable {
/**
* Constructor for a script that requires the use of compiler options.
* @param type The {@link ScriptType}.
* @param lang The language for this {@link Script} if the {@link ScriptType} is {@link ScriptType#INLINE} or
* {@link ScriptType#FILE}. For {@link ScriptType#STORED} scripts this should be null, but can
* @param lang The language for this {@link Script} if the {@link ScriptType} is {@link ScriptType#INLINE}.
* For {@link ScriptType#STORED} scripts this should be null, but can
* be specified to access scripts stored as part of the stored scripts deprecated API.
* @param idOrCode The id for this {@link Script} if the {@link ScriptType} is {@link ScriptType#FILE} or {@link ScriptType#STORED}.
* @param idOrCode The id for this {@link Script} if the {@link ScriptType} is {@link ScriptType#STORED}.
* The code for this {@link Script} if the {@link ScriptType} is {@link ScriptType#INLINE}.
* @param options The map of compiler options for this {@link Script} if the {@link ScriptType}
* is {@link ScriptType#INLINE}, {@code null} otherwise.
@ -464,15 +424,6 @@ public final class Script implements ToXContentObject, Writeable {
"options must be null for [" + ScriptType.STORED.getParseField().getPreferredName() + "] scripts");
}
this.options = null;
} else if (type == ScriptType.FILE) {
this.lang = Objects.requireNonNull(lang);
if (options != null) {
throw new IllegalStateException(
"options must be null for [" + ScriptType.FILE.getParseField().getPreferredName() + "] scripts");
}
this.options = null;
} else {
throw new IllegalStateException("unknown script type [" + type.getName() + "]");
@ -701,8 +652,8 @@ public final class Script implements ToXContentObject, Writeable {
}
/**
* @return The language for this {@link Script} if the {@link ScriptType} is {@link ScriptType#INLINE} or
* {@link ScriptType#FILE}. For {@link ScriptType#STORED} scripts this should be null, but can
* @return The language for this {@link Script} if the {@link ScriptType} is {@link ScriptType#INLINE}.
* For {@link ScriptType#STORED} scripts this should be null, but can
* be specified to access scripts stored as part of the stored scripts deprecated API.
*/
public String getLang() {
@ -710,7 +661,7 @@ public final class Script implements ToXContentObject, Writeable {
}
/**
* @return The id for this {@link Script} if the {@link ScriptType} is {@link ScriptType#FILE} or {@link ScriptType#STORED}.
* @return The id for this {@link Script} if the {@link ScriptType} is {@link ScriptType#STORED}.
* The code for this {@link Script} if the {@link ScriptType} is {@link ScriptType#INLINE}.
*/
public String getIdOrCode() {

View File

@ -35,13 +35,6 @@ public interface ScriptEngine extends Closeable {
*/
String getType();
/**
* The extension for file scripts in this language.
*/
default String getExtension() {
return getType();
}
/**
* Compiles a script.
* @param scriptName name of the script. {@code null} if it is anonymous (inline).

View File

@ -105,11 +105,6 @@ public class ScriptModes {
* @return whether scripts are enabled (true) or disabled (false)
*/
public boolean getScriptEnabled(String lang, ScriptType scriptType, ScriptContext scriptContext) {
//native scripts are always enabled as they are static by definition
if (NativeScriptEngine.NAME.equals(lang)) {
return true;
}
if (typesAllowed != null && typesAllowed.contains(scriptType.getName()) == false) {
throw new IllegalArgumentException("[" + scriptType.getName() + "] scripts cannot be executed");
}

View File

@ -42,33 +42,26 @@ public class ScriptModule {
/**
* Build from {@linkplain ScriptPlugin}s. Convenient for normal use but not great for tests. See
* {@link ScriptModule#ScriptModule(Settings, Environment, ResourceWatcherService, List, List)} for easier use in tests.
* {@link ScriptModule#ScriptModule(Settings, List, List)} for easier use in tests.
*/
public static ScriptModule create(Settings settings, Environment environment,
ResourceWatcherService resourceWatcherService, List<ScriptPlugin> scriptPlugins) {
Map<String, NativeScriptFactory> factoryMap = scriptPlugins.stream().flatMap(x -> x.getNativeScripts().stream())
.collect(Collectors.toMap(NativeScriptFactory::getName, Function.identity()));
NativeScriptEngine nativeScriptEngineService = new NativeScriptEngine(settings, factoryMap);
public static ScriptModule create(Settings settings, List<ScriptPlugin> scriptPlugins) {
List<ScriptEngine> scriptEngines = scriptPlugins.stream().map(x -> x.getScriptEngine(settings))
.filter(Objects::nonNull).collect(Collectors.toList());
scriptEngines.add(nativeScriptEngineService);
List<ScriptContext.Plugin> plugins = scriptPlugins.stream().map(x -> x.getCustomScriptContexts()).filter(Objects::nonNull)
.collect(Collectors.toList());
return new ScriptModule(settings, environment, resourceWatcherService, scriptEngines, plugins);
return new ScriptModule(settings, scriptEngines, plugins);
}
/**
* Build {@linkplain ScriptEngine} and {@linkplain ScriptContext.Plugin}.
*/
public ScriptModule(Settings settings, Environment environment,
ResourceWatcherService resourceWatcherService, List<ScriptEngine> scriptEngines,
public ScriptModule(Settings settings, List<ScriptEngine> scriptEngines,
List<ScriptContext.Plugin> customScriptContexts) {
ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(customScriptContexts);
ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(scriptEngines);
scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
try {
scriptService = new ScriptService(settings, environment, resourceWatcherService, scriptEngineRegistry, scriptContextRegistry,
scriptSettings);
scriptService = new ScriptService(settings, scriptEngineRegistry, scriptContextRegistry, scriptSettings);
} catch (IOException e) {
throw new RuntimeException("Couldn't setup ScriptService", e);
}

View File

@ -19,10 +19,13 @@
package org.elasticsearch.script;
import org.apache.logging.log4j.message.ParameterizedMessage;
import org.apache.logging.log4j.util.Supplier;
import java.io.Closeable;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import org.apache.lucene.util.IOUtils;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.ResourceNotFoundException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.admin.cluster.storedscripts.DeleteStoredScriptRequest;
@ -43,39 +46,14 @@ import org.elasticsearch.common.cache.Cache;
import org.elasticsearch.common.cache.CacheBuilder;
import org.elasticsearch.common.cache.RemovalListener;
import org.elasticsearch.common.cache.RemovalNotification;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.io.Streams;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.concurrent.ConcurrentCollections;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.env.Environment;
import org.elasticsearch.search.lookup.SearchLookup;
import org.elasticsearch.template.CompiledTemplate;
import org.elasticsearch.watcher.FileChangesListener;
import org.elasticsearch.watcher.FileWatcher;
import org.elasticsearch.watcher.ResourceWatcherService;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentMap;
import static java.util.Collections.unmodifiableMap;
public class ScriptService extends AbstractComponent implements Closeable, ClusterStateListener {
@ -85,21 +63,14 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust
Setting.intSetting("script.cache.max_size", 100, 0, Property.NodeScope);
public static final Setting<TimeValue> SCRIPT_CACHE_EXPIRE_SETTING =
Setting.positiveTimeSetting("script.cache.expire", TimeValue.timeValueMillis(0), Property.NodeScope);
public static final Setting<Boolean> SCRIPT_AUTO_RELOAD_ENABLED_SETTING =
Setting.boolSetting("script.auto_reload_enabled", true, Property.NodeScope, Property.Deprecated);
public static final Setting<Integer> SCRIPT_MAX_SIZE_IN_BYTES =
Setting.intSetting("script.max_size_in_bytes", 65535, Property.NodeScope);
public static final Setting<Integer> SCRIPT_MAX_COMPILATIONS_PER_MINUTE =
Setting.intSetting("script.max_compilations_per_minute", 15, 0, Property.Dynamic, Property.NodeScope);
private final Collection<ScriptEngine> scriptEngines;
private final Map<String, ScriptEngine> scriptEnginesByLang;
private final Map<String, ScriptEngine> scriptEnginesByExt;
private final ConcurrentMap<CacheKey, CompiledScript> staticCache = ConcurrentCollections.newConcurrentMap();
private final Map<String, ScriptEngine> engines;
private final Cache<CacheKey, CompiledScript> cache;
private final Path scriptsDirectory;
private final ScriptModes scriptModes;
private final ScriptContextRegistry scriptContextRegistry;
@ -113,8 +84,7 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust
private double scriptsPerMinCounter;
private double compilesAllowedPerNano;
public ScriptService(Settings settings, Environment env,
ResourceWatcherService resourceWatcherService, ScriptEngineRegistry scriptEngineRegistry,
public ScriptService(Settings settings, ScriptEngineRegistry scriptEngineRegistry,
ScriptContextRegistry scriptContextRegistry, ScriptSettings scriptSettings) throws IOException {
super(settings);
Objects.requireNonNull(scriptEngineRegistry);
@ -125,7 +95,6 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust
"Dynamic scripts can be enabled for all languages and all operations by replacing `script.disable_dynamic: false` with `script.inline: true` and `script.stored: true` in elasticsearch.yml");
}
this.scriptEngines = scriptEngineRegistry.getRegisteredLanguages().values();
this.scriptContextRegistry = scriptContextRegistry;
int cacheMaxSize = SCRIPT_CACHE_SIZE_SETTING.get(settings);
@ -141,35 +110,8 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust
logger.debug("using script cache with max_size [{}], expire [{}]", cacheMaxSize, cacheExpire);
this.cache = cacheBuilder.removalListener(new ScriptCacheRemovalListener()).build();
Map<String, ScriptEngine> enginesByLangBuilder = new HashMap<>();
Map<String, ScriptEngine> enginesByExtBuilder = new HashMap<>();
for (ScriptEngine scriptEngine : scriptEngines) {
String language = scriptEngineRegistry.getLanguage(scriptEngine.getClass());
enginesByLangBuilder.put(language, scriptEngine);
enginesByExtBuilder.put(scriptEngine.getExtension(), scriptEngine);
}
this.scriptEnginesByLang = unmodifiableMap(enginesByLangBuilder);
this.scriptEnginesByExt = unmodifiableMap(enginesByExtBuilder);
this.engines = scriptEngineRegistry.getRegisteredLanguages();
this.scriptModes = new ScriptModes(scriptContextRegistry, scriptSettings, settings);
// add file watcher for static scripts
scriptsDirectory = env.scriptsFile();
if (logger.isTraceEnabled()) {
logger.trace("Using scripts directory [{}] ", scriptsDirectory);
}
FileWatcher fileWatcher = new FileWatcher(scriptsDirectory);
fileWatcher.addListener(new ScriptChangesListener());
if (SCRIPT_AUTO_RELOAD_ENABLED_SETTING.get(settings) && resourceWatcherService != null) {
// automatic reload is enabled - register scripts
resourceWatcherService.add(fileWatcher);
} else {
// automatic reload is disable just load scripts once
fileWatcher.init();
}
this.lastInlineCompileTime = System.nanoTime();
this.setMaxCompilationsPerMinute(SCRIPT_MAX_COMPILATIONS_PER_MINUTE.get(settings));
}
@ -180,25 +122,17 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust
@Override
public void close() throws IOException {
IOUtils.close(scriptEngines);
IOUtils.close(engines.values());
}
private ScriptEngine getScriptEngineServiceForLang(String lang) {
ScriptEngine scriptEngine = scriptEnginesByLang.get(lang);
private ScriptEngine getEngine(String lang) {
ScriptEngine scriptEngine = engines.get(lang);
if (scriptEngine == null) {
throw new IllegalArgumentException("script_lang not supported [" + lang + "]");
}
return scriptEngine;
}
private ScriptEngine getScriptEngineServiceForFileExt(String fileExtension) {
ScriptEngine scriptEngine = scriptEnginesByExt.get(fileExtension);
if (scriptEngine == null) {
throw new IllegalArgumentException("script file extension not supported [" + fileExtension + "]");
}
return scriptEngine;
}
void setMaxCompilationsPerMinute(Integer newMaxPerMinute) {
this.totalCompilesPerMinute = newMaxPerMinute;
// Reset the counter to allow new compilations
@ -258,7 +192,7 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust
" operation [" + scriptContext.getKey() + "] and lang [" + lang + "] are not supported");
}
ScriptEngine scriptEngine = getScriptEngineServiceForLang(lang);
ScriptEngine scriptEngine = getEngine(lang);
if (canExecuteScript(lang, type, scriptContext) == false) {
throw new IllegalStateException("scripts of type [" + script.getType() + "]," +
@ -269,17 +203,6 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust
logger.trace("compiling lang: [{}] type: [{}] script: {}", lang, type, idOrCode);
}
if (type == ScriptType.FILE) {
CacheKey cacheKey = new CacheKey(lang, idOrCode, options);
CompiledScript compiledScript = staticCache.get(cacheKey);
if (compiledScript == null) {
throw new IllegalArgumentException("unable to find file script [" + idOrCode + "] using lang [" + lang + "]");
}
return compiledScript;
}
CacheKey cacheKey = new CacheKey(lang, idOrCode, options);
CompiledScript compiledScript = cache.get(cacheKey);
@ -362,8 +285,7 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust
public boolean isLangSupported(String lang) {
Objects.requireNonNull(lang);
return scriptEnginesByLang.containsKey(lang);
return engines.containsKey(lang);
}
StoredScriptSource getScriptFromClusterState(String id, String lang) {
@ -404,7 +326,7 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust
}
try {
ScriptEngine scriptEngine = getScriptEngineServiceForLang(source.getLang());
ScriptEngine scriptEngine = getEngine(source.getLang());
if (isAnyScriptContextEnabled(source.getLang(), ScriptType.STORED)) {
Object compiled = scriptEngine.compile(request.id(), source.getCode(), Collections.emptyMap());
@ -481,7 +403,7 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust
* Executes a previously compiled script provided as an argument
*/
public ExecutableScript executable(CompiledScript compiledScript, Map<String, Object> params) {
return getScriptEngineServiceForLang(compiledScript.lang()).executable(compiledScript, params);
return getEngine(compiledScript.lang()).executable(compiledScript, params);
}
/**
@ -497,7 +419,7 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust
* {@link SearchScript} ready for execution
*/
public SearchScript search(SearchLookup lookup, CompiledScript compiledScript, Map<String, Object> params) {
return getScriptEngineServiceForLang(compiledScript.lang()).search(compiledScript, lookup, params);
return getEngine(compiledScript.lang()).search(compiledScript, lookup, params);
}
private boolean isAnyScriptContextEnabled(String lang, ScriptType scriptType) {
@ -541,108 +463,6 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust
}
}
private class ScriptChangesListener implements FileChangesListener {
private boolean deprecationEmitted = false;
private Tuple<String, String> getScriptNameExt(Path file) {
Path scriptPath = scriptsDirectory.relativize(file);
int extIndex = scriptPath.toString().lastIndexOf('.');
if (extIndex <= 0) {
return null;
}
String ext = scriptPath.toString().substring(extIndex + 1);
if (ext.isEmpty()) {
return null;
}
String scriptName = scriptPath.toString().substring(0, extIndex).replace(scriptPath.getFileSystem().getSeparator(), "_");
return new Tuple<>(scriptName, ext);
}
@Override
public void onFileInit(Path file) {
Tuple<String, String> scriptNameExt = getScriptNameExt(file);
if (scriptNameExt == null) {
logger.debug("Skipped script with invalid extension : [{}]", file);
return;
}
if (logger.isTraceEnabled()) {
logger.trace("Loading script file : [{}]", file);
}
ScriptEngine engineService = getScriptEngineServiceForFileExt(scriptNameExt.v2());
if (engineService == null) {
logger.warn("No script engine found for [{}]", scriptNameExt.v2());
} else {
if (deprecationEmitted == false) {
deprecationLogger.deprecated("File scripts are deprecated. Use stored or inline scripts instead.");
deprecationEmitted = true;
}
try {
//we don't know yet what the script will be used for, but if all of the operations for this lang
// with file scripts are disabled, it makes no sense to even compile it and cache it.
if (isAnyScriptContextEnabled(engineService.getType(), ScriptType.FILE)) {
logger.info("compiling script file [{}]", file.toAbsolutePath());
try (InputStreamReader reader = new InputStreamReader(Files.newInputStream(file), StandardCharsets.UTF_8)) {
String script = Streams.copyToString(reader);
String id = scriptNameExt.v1();
CacheKey cacheKey = new CacheKey(engineService.getType(), id, null);
// pass the actual file name to the compiler (for script engines that care about this)
Object executable = engineService.compile(file.getFileName().toString(), script, Collections.emptyMap());
CompiledScript compiledScript = new CompiledScript(ScriptType.FILE, id, engineService.getType(), executable);
staticCache.put(cacheKey, compiledScript);
scriptMetrics.onCompilation();
}
} else {
logger.warn("skipping compile of script file [{}] as all scripted operations are disabled for file scripts", file.toAbsolutePath());
}
} catch (ScriptException e) {
try (XContentBuilder builder = JsonXContent.contentBuilder()) {
builder.prettyPrint();
builder.startObject();
ElasticsearchException.generateThrowableXContent(builder, ToXContent.EMPTY_PARAMS, e);
builder.endObject();
logger.warn("failed to load/compile script [{}]: {}", scriptNameExt.v1(), builder.string());
} catch (IOException ioe) {
ioe.addSuppressed(e);
logger.warn((Supplier<?>) () -> new ParameterizedMessage(
"failed to log an appropriate warning after failing to load/compile script [{}]", scriptNameExt.v1()), ioe);
}
/* Log at the whole exception at the debug level as well just in case the stack trace is important. That way you can
* turn on the stack trace if you need it. */
logger.debug((Supplier<?>) () -> new ParameterizedMessage("failed to load/compile script [{}]. full exception:",
scriptNameExt.v1()), e);
} catch (Exception e) {
logger.warn((Supplier<?>) () -> new ParameterizedMessage("failed to load/compile script [{}]", scriptNameExt.v1()), e);
}
}
}
@Override
public void onFileCreated(Path file) {
onFileInit(file);
}
@Override
public void onFileDeleted(Path file) {
Tuple<String, String> scriptNameExt = getScriptNameExt(file);
if (scriptNameExt != null) {
ScriptEngine engineService = getScriptEngineServiceForFileExt(scriptNameExt.v2());
assert engineService != null;
logger.info("removing script file [{}]", file.toAbsolutePath());
staticCache.remove(new CacheKey(engineService.getType(), scriptNameExt.v1(), null));
}
}
@Override
public void onFileChanged(Path file) {
onFileInit(file);
}
}
private static final class CacheKey {
final String lang;
final String idOrCode;

View File

@ -74,19 +74,12 @@ public class ScriptSettings {
final List<Setting<Boolean>> scriptModeSettings = new ArrayList<>();
for (final Class<? extends ScriptEngine> scriptEngineService : scriptEngineRegistry.getRegisteredScriptEngineServices()) {
if (scriptEngineService == NativeScriptEngine.class) {
// native scripts are always enabled, and their settings can not be changed
continue;
}
final String language = scriptEngineRegistry.getLanguage(scriptEngineService);
for (final ScriptType scriptType : ScriptType.values()) {
// Top level, like "script.engine.groovy.inline"
final boolean defaultNonFileScriptMode = scriptEngineRegistry.getDefaultInlineScriptEnableds().get(language);
boolean defaultLangAndType = defaultNonFileScriptMode;
// Files are treated differently because they are never default-deny
if (ScriptType.FILE == scriptType) {
defaultLangAndType = ScriptType.FILE.isDefaultEnabled();
}
final boolean defaultIfNothingSet = defaultLangAndType;
Function<Settings, String> defaultLangAndTypeFn = settings -> {

View File

@ -49,14 +49,7 @@ public enum ScriptType implements Writeable {
* (Groovy and others), but can be overridden by the specific {@link ScriptEngine}
* if the language is naturally secure (Painless, Mustache, and Expressions).
*/
STORED ( 1 , new ParseField("stored", "id") , false ),
/**
* FILE scripts are loaded from disk either on start-up or on-the-fly depending on
* user-defined settings. They will be compiled and cached as soon as they are loaded
* from disk. They are turned on by default as they should always be safe to execute.
*/
FILE ( 2 , new ParseField("file") , true );
STORED ( 1 , new ParseField("stored", "id") , false );
/**
* Reads an int from the input stream and converts it to a {@link ScriptType}.
@ -66,15 +59,12 @@ public enum ScriptType implements Writeable {
public static ScriptType readFrom(StreamInput in) throws IOException {
int id = in.readVInt();
if (FILE.id == id) {
return FILE;
} else if (STORED.id == id) {
if (STORED.id == id) {
return STORED;
} else if (INLINE.id == id) {
return INLINE;
} else {
throw new IllegalStateException("Error reading ScriptType id [" + id + "] from stream, expected one of [" +
FILE.id + " [" + FILE.parseField.getPreferredName() + "], " +
STORED.id + " [" + STORED.parseField.getPreferredName() + "], " +
INLINE.id + " [" + INLINE.parseField.getPreferredName() + "]]");
}

View File

@ -437,7 +437,15 @@ public class SearchService extends AbstractLifecycleComponent implements IndexEv
if (context == null) {
throw new SearchContextMissingException(id);
}
return context;
SearchOperationListener operationListener = context.indexShard().getSearchOperationListener();
try {
operationListener.validateSearchContext(context);
return context;
} catch (Exception e) {
processFailure(context, e);
throw e;
}
}
final SearchContext createAndPutContext(ShardSearchRequest request) throws IOException {

View File

@ -253,9 +253,6 @@ public class TribeService extends AbstractLifecycleComponent {
if (Environment.PATH_LOGS_SETTING.exists(globalSettings)) {
sb.put(Environment.PATH_LOGS_SETTING.getKey(), Environment.PATH_LOGS_SETTING.get(globalSettings));
}
if (Environment.PATH_SCRIPTS_SETTING.exists(globalSettings)) {
sb.put(Environment.PATH_SCRIPTS_SETTING.getKey(), Environment.PATH_SCRIPTS_SETTING.get(globalSettings));
}
for (Setting<?> passthrough : PASS_THROUGH_SETTINGS) {
if (passthrough.exists(tribeSettings) == false && passthrough.exists(globalSettings)) {
sb.put(passthrough.getKey(), globalSettings.get(passthrough.getKey()));

View File

@ -888,9 +888,10 @@ public class TransportReplicationActionTests extends ESTestCase {
final TestAction.ReplicaOperationTransportHandler replicaOperationTransportHandler = action.new ReplicaOperationTransportHandler();
final PlainActionFuture<TestResponse> listener = new PlainActionFuture<>();
final Request request = new Request().setShardId(shardId);
final long checkpoint = randomNonNegativeLong();
request.primaryTerm(state.metaData().getIndexSafe(shardId.getIndex()).primaryTerm(shardId.id()));
replicaOperationTransportHandler.messageReceived(
new TransportReplicationAction.ConcreteReplicaRequest<>(request, replica.allocationId().getId(), randomNonNegativeLong()),
new TransportReplicationAction.ConcreteReplicaRequest<>(request, replica.allocationId().getId(), checkpoint),
createTransportChannel(listener), task);
if (listener.isDone()) {
listener.get(); // fail with the exception if there
@ -911,7 +912,9 @@ public class TransportReplicationActionTests extends ESTestCase {
assertThat(capturedRequests.size(), equalTo(1));
final CapturingTransport.CapturedRequest capturedRequest = capturedRequests.get(0);
assertThat(capturedRequest.action, equalTo("testActionWithExceptions[r]"));
assertThat(capturedRequest.request, instanceOf(TransportReplicationAction.ConcreteShardRequest.class));
assertThat(capturedRequest.request, instanceOf(TransportReplicationAction.ConcreteReplicaRequest.class));
assertThat(((TransportReplicationAction.ConcreteReplicaRequest) capturedRequest.request).getGlobalCheckpoint(),
equalTo(checkpoint));
assertConcreteShardRequest(capturedRequest.request, request, replica.allocationId());
}

View File

@ -151,8 +151,6 @@ public class UpdateRequestTests extends ESTestCase {
new ResourceWatcherService(baseSettings, null);
ScriptService scriptService = new ScriptService(
baseSettings,
environment,
watcherService,
scriptEngineRegistry,
scriptContextRegistry,
scriptSettings);

View File

@ -20,7 +20,6 @@
package org.elasticsearch.common.lucene.search.function;
import org.apache.lucene.index.LeafReaderContext;
import org.elasticsearch.script.AbstractDoubleSearchScript;
import org.elasticsearch.script.GeneralScriptException;
import org.elasticsearch.script.LeafSearchScript;
import org.elasticsearch.script.SearchScript;
@ -37,17 +36,7 @@ public class ScriptScoreFunctionTests extends ESTestCase {
ScoreFunction scoreFunction = new ScriptScoreFunction(mockScript("Double.NaN"), new SearchScript() {
@Override
public LeafSearchScript getLeafSearchScript(LeafReaderContext context) throws IOException {
return new AbstractDoubleSearchScript() {
@Override
public double runAsDouble() {
return Double.NaN;
}
@Override
public void setDocument(int doc) {
// do nothing: we are a fake with no lookup
}
};
return () -> Double.NaN;
}
@Override

View File

@ -207,23 +207,4 @@ public class SettingsModuleTests extends ModuleTestCase {
assertEquals("unknown setting [index.query.bool.max_clause_count] did you mean [indices.query.bool.max_clause_count]?",
ex.getMessage());
}
public void testRegisterShared() {
Property scope = randomFrom(Property.NodeScope, Property.IndexScope);
expectThrows(IllegalArgumentException.class, () ->
new SettingsModule(Settings.EMPTY,
Setting.simpleString("index.foo.bar", scope), Setting.simpleString("index.foo.bar", scope))
);
expectThrows(IllegalArgumentException.class, () ->
new SettingsModule(Settings.EMPTY,
Setting.simpleString("index.foo.bar", scope, Property.Shared), Setting.simpleString("index.foo.bar", scope))
);
expectThrows(IllegalArgumentException.class, () ->
new SettingsModule(Settings.EMPTY,
Setting.simpleString("index.foo.bar", scope), Setting.simpleString("index.foo.bar", scope, Property.Shared))
);
new SettingsModule(Settings.EMPTY,
Setting.simpleString("index.foo.bar", scope, Property.Shared),
Setting.simpleString("index.foo.bar", scope, Property.Shared));
}
}

View File

@ -131,8 +131,7 @@ public class IndexModuleTests extends ESTestCase {
ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(emptyList());
ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(Collections.emptyList());
ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
scriptService = new ScriptService(settings, environment, new ResourceWatcherService(settings, threadPool), scriptEngineRegistry,
scriptContextRegistry, scriptSettings);
scriptService = new ScriptService(settings, scriptEngineRegistry, scriptContextRegistry, scriptSettings);
clusterService = ClusterServiceUtils.createClusterService(threadPool);
nodeEnvironment = new NodeEnvironment(settings, environment);
mapperRegistry = new IndicesModule(Collections.emptyList()).getMapperRegistry();

View File

@ -31,10 +31,8 @@ import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.Requests;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.plugins.ScriptPlugin;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.NativeScriptFactory;
import org.elasticsearch.script.MockScriptPlugin;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.test.ESIntegTestCase;
@ -42,9 +40,9 @@ import org.junit.Before;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.function.Function;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singleton;
@ -111,7 +109,8 @@ public class WaitUntilRefreshIT extends ESIntegTestCase {
assertSearchHits(client().prepareSearch("test").setQuery(matchQuery("foo", "cat")).get(), "2");
// Update-becomes-delete with RefreshPolicy.WAIT_UNTIL
update = client().prepareUpdate("test", "test", "2").setScript(new Script(ScriptType.INLINE, "native", "delete_plz", emptyMap()))
update = client().prepareUpdate("test", "test", "2").setScript(
new Script(ScriptType.INLINE, "mockscript", "delete_plz", emptyMap()))
.setRefreshPolicy(RefreshPolicy.WAIT_UNTIL).get();
assertEquals(2, update.getVersion());
assertFalse("request shouldn't have forced a refresh", update.forcedRefresh());
@ -171,43 +170,15 @@ public class WaitUntilRefreshIT extends ESIntegTestCase {
return singleton(DeletePlzPlugin.class);
}
public static class DeletePlzPlugin extends Plugin implements ScriptPlugin {
public static class DeletePlzPlugin extends MockScriptPlugin {
@Override
public List<NativeScriptFactory> getNativeScripts() {
return Collections.singletonList(new DeletePlzFactory());
}
}
public static class DeletePlzFactory implements NativeScriptFactory {
@Override
public ExecutableScript newScript(Map<String, Object> params) {
return new ExecutableScript() {
private Map<String, Object> ctx;
@Override
@SuppressWarnings("unchecked") // Elasicsearch convention
public void setNextVar(String name, Object value) {
if (name.equals("ctx")) {
ctx = (Map<String, Object>) value;
}
}
@Override
public Object run() {
ctx.put("op", "delete");
return null;
}
};
}
@Override
public boolean needsScores() {
return false;
}
@Override
public String getName() {
return "delete_plz";
public Map<String, Function<Map<String, Object>, Object>> pluginScripts() {
return Collections.singletonMap("delete_plz", params -> {
@SuppressWarnings("unchecked")
Map<String, Object> ctx = (Map<String, Object>) params.get("ctx");
ctx.put("op", "delete");
return null;
});
}
}
}

View File

@ -18,9 +18,6 @@
*/
package org.elasticsearch.index.shard;
import org.apache.lucene.index.Term;
import org.elasticsearch.client.Client;
import org.elasticsearch.index.engine.Engine;
import org.elasticsearch.search.internal.SearchContext;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.TestSearchContext;
@ -32,6 +29,9 @@ import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.sameInstance;
public class SearchOperationListenerTests extends ESTestCase {
// this test also tests if calls are correct if one or more listeners throw exceptions
@ -46,6 +46,7 @@ public class SearchOperationListenerTests extends ESTestCase {
AtomicInteger freeContext = new AtomicInteger();
AtomicInteger newScrollContext = new AtomicInteger();
AtomicInteger freeScrollContext = new AtomicInteger();
AtomicInteger validateSearchContext = new AtomicInteger();
AtomicInteger timeInNanos = new AtomicInteger(randomIntBetween(0, 10));
SearchOperationListener listener = new SearchOperationListener() {
@Override
@ -109,17 +110,26 @@ public class SearchOperationListenerTests extends ESTestCase {
assertNotNull(context);
freeScrollContext.incrementAndGet();
}
@Override
public void validateSearchContext(SearchContext context) {
assertNotNull(context);
validateSearchContext.incrementAndGet();
}
};
SearchOperationListener throwingListener = (SearchOperationListener) Proxy.newProxyInstance(
SearchOperationListener.class.getClassLoader(),
new Class[]{SearchOperationListener.class},
(a,b,c) -> { throw new RuntimeException();});
int throwingListeners = 0;
final List<SearchOperationListener> indexingOperationListeners = new ArrayList<>(Arrays.asList(listener, listener));
if (randomBoolean()) {
indexingOperationListeners.add(throwingListener);
throwingListeners++;
if (randomBoolean()) {
indexingOperationListeners.add(throwingListener);
throwingListeners++;
}
}
Collections.shuffle(indexingOperationListeners, random());
@ -137,6 +147,7 @@ public class SearchOperationListenerTests extends ESTestCase {
assertEquals(0, newScrollContext.get());
assertEquals(0, freeContext.get());
assertEquals(0, freeScrollContext.get());
assertEquals(0, validateSearchContext.get());
compositeListener.onFetchPhase(ctx, timeInNanos.get());
assertEquals(0, preFetch.get());
@ -149,6 +160,7 @@ public class SearchOperationListenerTests extends ESTestCase {
assertEquals(0, newScrollContext.get());
assertEquals(0, freeContext.get());
assertEquals(0, freeScrollContext.get());
assertEquals(0, validateSearchContext.get());
compositeListener.onPreQueryPhase(ctx);
assertEquals(0, preFetch.get());
@ -161,6 +173,7 @@ public class SearchOperationListenerTests extends ESTestCase {
assertEquals(0, newScrollContext.get());
assertEquals(0, freeContext.get());
assertEquals(0, freeScrollContext.get());
assertEquals(0, validateSearchContext.get());
compositeListener.onPreFetchPhase(ctx);
assertEquals(2, preFetch.get());
@ -173,6 +186,7 @@ public class SearchOperationListenerTests extends ESTestCase {
assertEquals(0, newScrollContext.get());
assertEquals(0, freeContext.get());
assertEquals(0, freeScrollContext.get());
assertEquals(0, validateSearchContext.get());
compositeListener.onFailedFetchPhase(ctx);
assertEquals(2, preFetch.get());
@ -185,6 +199,7 @@ public class SearchOperationListenerTests extends ESTestCase {
assertEquals(0, newScrollContext.get());
assertEquals(0, freeContext.get());
assertEquals(0, freeScrollContext.get());
assertEquals(0, validateSearchContext.get());
compositeListener.onFailedQueryPhase(ctx);
assertEquals(2, preFetch.get());
@ -197,6 +212,7 @@ public class SearchOperationListenerTests extends ESTestCase {
assertEquals(0, newScrollContext.get());
assertEquals(0, freeContext.get());
assertEquals(0, freeScrollContext.get());
assertEquals(0, validateSearchContext.get());
compositeListener.onNewContext(ctx);
assertEquals(2, preFetch.get());
@ -209,6 +225,7 @@ public class SearchOperationListenerTests extends ESTestCase {
assertEquals(0, newScrollContext.get());
assertEquals(0, freeContext.get());
assertEquals(0, freeScrollContext.get());
assertEquals(0, validateSearchContext.get());
compositeListener.onNewScrollContext(ctx);
assertEquals(2, preFetch.get());
@ -221,6 +238,7 @@ public class SearchOperationListenerTests extends ESTestCase {
assertEquals(2, newScrollContext.get());
assertEquals(0, freeContext.get());
assertEquals(0, freeScrollContext.get());
assertEquals(0, validateSearchContext.get());
compositeListener.onFreeContext(ctx);
assertEquals(2, preFetch.get());
@ -233,6 +251,7 @@ public class SearchOperationListenerTests extends ESTestCase {
assertEquals(2, newScrollContext.get());
assertEquals(2, freeContext.get());
assertEquals(0, freeScrollContext.get());
assertEquals(0, validateSearchContext.get());
compositeListener.onFreeScrollContext(ctx);
assertEquals(2, preFetch.get());
@ -245,5 +264,28 @@ public class SearchOperationListenerTests extends ESTestCase {
assertEquals(2, newScrollContext.get());
assertEquals(2, freeContext.get());
assertEquals(2, freeScrollContext.get());
assertEquals(0, validateSearchContext.get());
if (throwingListeners == 0) {
compositeListener.validateSearchContext(ctx);
} else {
RuntimeException expected = expectThrows(RuntimeException.class, () -> compositeListener.validateSearchContext(ctx));
assertNull(expected.getMessage());
assertEquals(throwingListeners - 1, expected.getSuppressed().length);
if (throwingListeners > 1) {
assertThat(expected.getSuppressed()[0], not(sameInstance(expected)));
}
}
assertEquals(2, preFetch.get());
assertEquals(2, preQuery.get());
assertEquals(2, failedFetch.get());
assertEquals(2, failedQuery.get());
assertEquals(2, onQuery.get());
assertEquals(2, onFetch.get());
assertEquals(2, newContext.get());
assertEquals(2, newScrollContext.get());
assertEquals(2, freeContext.get());
assertEquals(2, freeScrollContext.get());
assertEquals(2, validateSearchContext.get());
}
}

View File

@ -1,96 +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.script;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.script.MockScriptEngine.MockCompiledScript;
import org.elasticsearch.test.ESTestCase;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
// TODO: these really should just be part of ScriptService tests, there is nothing special about them
public class FileScriptTests extends ESTestCase {
private ScriptSettings scriptSettings;
ScriptService makeScriptService(Settings settings) throws Exception {
Path homeDir = createTempDir();
Path scriptsDir = homeDir.resolve("config").resolve("scripts");
Files.createDirectories(scriptsDir);
Path mockscript = scriptsDir.resolve("script1.mockscript");
String scriptSource = "1";
Files.write(mockscript, scriptSource.getBytes("UTF-8"));
settings = Settings.builder()
.put(Environment.PATH_HOME_SETTING.getKey(), homeDir)
// no file watching, so we don't need a ResourceWatcherService
.put(ScriptService.SCRIPT_AUTO_RELOAD_ENABLED_SETTING.getKey(), false)
.put(settings)
.build();
MockScriptEngine scriptEngine = new MockScriptEngine(MockScriptEngine.NAME, Collections.singletonMap(scriptSource, script -> "1"));
ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(Collections.singleton(scriptEngine));
ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(Collections.emptyList());
scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
return new ScriptService(settings, new Environment(settings), null, scriptEngineRegistry, scriptContextRegistry, scriptSettings);
}
public void testFileScriptFound() throws Exception {
Settings settings = Settings.builder()
.put("script.engine." + MockScriptEngine.NAME + ".file.aggs", "false").build();
ScriptService scriptService = makeScriptService(settings);
Script script = new Script(ScriptType.FILE, MockScriptEngine.NAME, "script1", Collections.emptyMap());
CompiledScript compiledScript = scriptService.compile(script, ScriptContext.Standard.SEARCH);
assertNotNull(compiledScript);
MockCompiledScript executable = (MockCompiledScript) compiledScript.compiled();
assertEquals("script1.mockscript", executable.getName());
assertSettingDeprecationsAndWarnings(ScriptSettingsTests.buildDeprecatedSettingsArray(
new Setting[] {ScriptService.SCRIPT_AUTO_RELOAD_ENABLED_SETTING},
scriptSettings, "script.engine." + MockScriptEngine.NAME + ".file.aggs"),
"File scripts are deprecated. Use stored or inline scripts instead.");
}
public void testAllOpsDisabled() throws Exception {
Settings settings = Settings.builder()
.put("script.engine." + MockScriptEngine.NAME + ".file.aggs", "false")
.put("script.engine." + MockScriptEngine.NAME + ".file.search", "false")
.put("script.engine." + MockScriptEngine.NAME + ".file.mapping", "false")
.put("script.engine." + MockScriptEngine.NAME + ".file.update", "false")
.put("script.engine." + MockScriptEngine.NAME + ".file.ingest", "false").build();
ScriptService scriptService = makeScriptService(settings);
Script script = new Script(ScriptType.FILE, MockScriptEngine.NAME, "script1", Collections.emptyMap());
for (ScriptContext context : ScriptContext.Standard.values()) {
try {
scriptService.compile(script, context);
fail(context.getKey() + " script should have been rejected");
} catch(Exception e) {
assertTrue(e.getMessage(), e.getMessage().contains("scripts of type [file], operation [" + context.getKey() + "] and lang [" + MockScriptEngine.NAME + "] are disabled"));
}
}
assertSettingDeprecationsAndWarnings(ScriptSettingsTests.buildDeprecatedSettingsArray(
new Setting[] {ScriptService.SCRIPT_AUTO_RELOAD_ENABLED_SETTING}, scriptSettings,
"script.engine." + MockScriptEngine.NAME + ".file.aggs",
"script.engine." + MockScriptEngine.NAME + ".file.search",
"script.engine." + MockScriptEngine.NAME + ".file.update",
"script.engine." + MockScriptEngine.NAME + ".file.ingest"),
"File scripts are deprecated. Use stored or inline scripts instead.");
}
}

View File

@ -1,112 +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.script;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.InternalSettingsPlugin;
import org.elasticsearch.watcher.ResourceWatcherService;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.notNullValue;
public class NativeScriptTests extends ESTestCase {
public void testNativeScript() throws InterruptedException {
Settings settings = Settings.builder()
.put("node.name", "testNativeScript")
.put(Environment.PATH_HOME_SETTING.getKey(), createTempDir())
.build();
ScriptModule scriptModule = new ScriptModule(settings, new Environment(settings), null,
singletonList(new NativeScriptEngine(settings, singletonMap("my", new MyNativeScriptFactory()))), emptyList());
List<Setting<?>> scriptSettings = scriptModule.getSettings();
scriptSettings.add(InternalSettingsPlugin.VERSION_CREATED);
Script script = new Script(ScriptType.INLINE, NativeScriptEngine.NAME, "my", Collections.emptyMap());
CompiledScript compiledScript = scriptModule.getScriptService().compile(script, ScriptContext.Standard.SEARCH);
ExecutableScript executable = scriptModule.getScriptService().executable(compiledScript, script.getParams());
assertThat(executable.run().toString(), equalTo("test"));
assertWarnings("Native scripts are deprecated. Use a custom ScriptEngine to write scripts in java.");
}
public void testFineGrainedSettingsDontAffectNativeScripts() throws IOException {
Settings.Builder builder = Settings.builder();
if (randomBoolean()) {
ScriptType scriptType = randomFrom(ScriptType.values());
builder.put("script" + "." + scriptType.getName(), randomBoolean());
} else {
ScriptContext scriptContext = randomFrom(ScriptContext.Standard.values());
builder.put("script" + "." + scriptContext.getKey(), randomBoolean());
}
Settings settings = builder.put(Environment.PATH_HOME_SETTING.getKey(), createTempDir()).build();
Environment environment = new Environment(settings);
ResourceWatcherService resourceWatcherService = new ResourceWatcherService(settings, null);
Map<String, NativeScriptFactory> nativeScriptFactoryMap = new HashMap<>();
nativeScriptFactoryMap.put("my", new MyNativeScriptFactory());
ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(Collections.singleton(new NativeScriptEngine(settings,
nativeScriptFactoryMap)));
ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(new ArrayList<>());
ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
ScriptService scriptService = new ScriptService(settings, environment, resourceWatcherService, scriptEngineRegistry,
scriptContextRegistry, scriptSettings);
for (ScriptContext scriptContext : scriptContextRegistry.scriptContexts()) {
assertThat(scriptService.compile(new Script(ScriptType.INLINE, NativeScriptEngine.NAME, "my", Collections.emptyMap()),
scriptContext), notNullValue());
}
assertWarnings("Native scripts are deprecated. Use a custom ScriptEngine to write scripts in java.");
}
public static class MyNativeScriptFactory implements NativeScriptFactory {
@Override
public ExecutableScript newScript(@Nullable Map<String, Object> params) {
return new MyScript();
}
@Override
public boolean needsScores() {
return false;
}
@Override
public String getName() {
return "my";
}
}
static class MyScript extends AbstractExecutableScript {
@Override
public Object run() {
return "test";
}
}
}

View File

@ -45,8 +45,6 @@ public class ScriptContextTests extends ESTestCase {
ScriptService makeScriptService() throws Exception {
Settings settings = Settings.builder()
.put(Environment.PATH_HOME_SETTING.getKey(), createTempDir())
// no file watching, so we don't need a ResourceWatcherService
.put(ScriptService.SCRIPT_AUTO_RELOAD_ENABLED_SETTING.getKey(), "false")
.put(SCRIPT_PLUGIN_CUSTOM_SETTING, "false")
.put(SCRIPT_ENGINE_CUSTOM_SETTING, "false")
.build();
@ -59,7 +57,7 @@ public class ScriptContextTests extends ESTestCase {
new ScriptContext.Plugin(PLUGIN_NAME, "custom_globally_disabled_op"));
ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(customContexts);
scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
ScriptService scriptService = new ScriptService(settings, new Environment(settings), null, scriptEngineRegistry, scriptContextRegistry, scriptSettings);
ScriptService scriptService = new ScriptService(settings, scriptEngineRegistry, scriptContextRegistry, scriptSettings);
ClusterState empty = ClusterState.builder(new ClusterName("_name")).build();
ScriptMetaData smd = empty.metaData().custom(ScriptMetaData.TYPE);
@ -85,8 +83,7 @@ public class ScriptContextTests extends ESTestCase {
}
}
assertSettingDeprecationsAndWarnings(
ScriptSettingsTests.buildDeprecatedSettingsArray(new Setting[] {ScriptService.SCRIPT_AUTO_RELOAD_ENABLED_SETTING},
scriptSettings, SCRIPT_PLUGIN_CUSTOM_SETTING, SCRIPT_ENGINE_CUSTOM_SETTING));
ScriptSettingsTests.buildDeprecatedSettingsArray(scriptSettings, SCRIPT_PLUGIN_CUSTOM_SETTING, SCRIPT_ENGINE_CUSTOM_SETTING));
}
public void testCustomScriptContextSettings() throws Exception {
@ -104,8 +101,7 @@ public class ScriptContextTests extends ESTestCase {
assertNotNull(scriptService.compile(script, ScriptContext.Standard.SEARCH));
assertNotNull(scriptService.compile(script, new ScriptContext.Plugin(PLUGIN_NAME, "custom_op")));
assertSettingDeprecationsAndWarnings(
ScriptSettingsTests.buildDeprecatedSettingsArray(new Setting[] {ScriptService.SCRIPT_AUTO_RELOAD_ENABLED_SETTING},
scriptSettings, SCRIPT_PLUGIN_CUSTOM_SETTING, SCRIPT_ENGINE_CUSTOM_SETTING));
ScriptSettingsTests.buildDeprecatedSettingsArray(scriptSettings, SCRIPT_PLUGIN_CUSTOM_SETTING, SCRIPT_ENGINE_CUSTOM_SETTING));
}
public void testUnknownPluginScriptContext() throws Exception {
@ -120,8 +116,7 @@ public class ScriptContextTests extends ESTestCase {
}
}
assertSettingDeprecationsAndWarnings(
ScriptSettingsTests.buildDeprecatedSettingsArray(new Setting[] {ScriptService.SCRIPT_AUTO_RELOAD_ENABLED_SETTING},
scriptSettings, SCRIPT_PLUGIN_CUSTOM_SETTING, SCRIPT_ENGINE_CUSTOM_SETTING));
ScriptSettingsTests.buildDeprecatedSettingsArray(scriptSettings, SCRIPT_PLUGIN_CUSTOM_SETTING, SCRIPT_ENGINE_CUSTOM_SETTING));
}
public void testUnknownCustomScriptContext() throws Exception {
@ -142,7 +137,6 @@ public class ScriptContextTests extends ESTestCase {
}
}
assertSettingDeprecationsAndWarnings(
ScriptSettingsTests.buildDeprecatedSettingsArray(new Setting[] {ScriptService.SCRIPT_AUTO_RELOAD_ENABLED_SETTING},
scriptSettings, SCRIPT_PLUGIN_CUSTOM_SETTING, SCRIPT_ENGINE_CUSTOM_SETTING));
ScriptSettingsTests.buildDeprecatedSettingsArray(scriptSettings, SCRIPT_PLUGIN_CUSTOM_SETTING, SCRIPT_ENGINE_CUSTOM_SETTING));
}
}

View File

@ -1,184 +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.script;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.plugins.ScriptPlugin;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.test.ESIntegTestCase.Scope;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import static org.hamcrest.Matchers.equalTo;
@ClusterScope(scope = Scope.SUITE, numDataNodes = 3)
public class ScriptFieldIT extends ESIntegTestCase {
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return Arrays.asList(CustomScriptPlugin.class);
}
static int[] intArray = { Integer.MAX_VALUE, Integer.MIN_VALUE, 3 };
static long[] longArray = { Long.MAX_VALUE, Long.MIN_VALUE, 9223372036854775807L };
static float[] floatArray = { Float.MAX_VALUE, Float.MIN_VALUE, 3.3f };
static double[] doubleArray = { Double.MAX_VALUE, Double.MIN_VALUE, 3.3d };
public void testNativeScript() throws InterruptedException, ExecutionException {
indexRandom(true, client().prepareIndex("test", "type1", "1").setSource("text", "doc1"), client()
.prepareIndex("test", "type1", "2").setSource("text", "doc2"),
client().prepareIndex("test", "type1", "3").setSource("text", "doc3"), client().prepareIndex("test", "type1", "4")
.setSource("text", "doc4"), client().prepareIndex("test", "type1", "5").setSource("text", "doc5"), client()
.prepareIndex("test", "type1", "6").setSource("text", "doc6"));
client().admin().indices().prepareFlush("test").execute().actionGet();
SearchResponse sr = client().prepareSearch("test").setQuery(QueryBuilders.matchAllQuery())
.addScriptField("int", new Script(ScriptType.INLINE, "native", "int", Collections.emptyMap()))
.addScriptField("float", new Script(ScriptType.INLINE, "native", "float", Collections.emptyMap()))
.addScriptField("double", new Script(ScriptType.INLINE, "native", "double", Collections.emptyMap()))
.addScriptField("long", new Script(ScriptType.INLINE, "native", "long", Collections.emptyMap())).execute().actionGet();
assertThat(sr.getHits().getHits().length, equalTo(6));
for (SearchHit hit : sr.getHits().getHits()) {
Object result = hit.getFields().get("int").getValues().get(0);
assertThat(result, equalTo((Object) intArray));
result = hit.getFields().get("long").getValues().get(0);
assertThat(result, equalTo((Object) longArray));
result = hit.getFields().get("float").getValues().get(0);
assertThat(result, equalTo((Object) floatArray));
result = hit.getFields().get("double").getValues().get(0);
assertThat(result, equalTo((Object) doubleArray));
}
}
public static class IntArrayScriptFactory implements NativeScriptFactory {
@Override
public ExecutableScript newScript(@Nullable Map<String, Object> params) {
return new IntScript();
}
@Override
public boolean needsScores() {
return false;
}
@Override
public String getName() {
return "int";
}
}
static class IntScript extends AbstractSearchScript {
@Override
public Object run() {
return intArray;
}
}
public static class LongArrayScriptFactory implements NativeScriptFactory {
@Override
public ExecutableScript newScript(@Nullable Map<String, Object> params) {
return new LongScript();
}
@Override
public boolean needsScores() {
return false;
}
@Override
public String getName() {
return "long";
}
}
static class LongScript extends AbstractSearchScript {
@Override
public Object run() {
return longArray;
}
}
public static class FloatArrayScriptFactory implements NativeScriptFactory {
@Override
public ExecutableScript newScript(@Nullable Map<String, Object> params) {
return new FloatScript();
}
@Override
public boolean needsScores() {
return false;
}
@Override
public String getName() {
return "float";
}
}
static class FloatScript extends AbstractSearchScript {
@Override
public Object run() {
return floatArray;
}
}
public static class DoubleArrayScriptFactory implements NativeScriptFactory {
@Override
public ExecutableScript newScript(@Nullable Map<String, Object> params) {
return new DoubleScript();
}
@Override
public boolean needsScores() {
return false;
}
@Override
public String getName() {
return "double";
}
}
static class DoubleScript extends AbstractSearchScript {
@Override
public Object run() {
return doubleArray;
}
}
public static class CustomScriptPlugin extends Plugin implements ScriptPlugin {
@Override
public List<NativeScriptFactory> getNativeScripts() {
return Arrays.asList(new IntArrayScriptFactory(), new LongArrayScriptFactory(), new FloatArrayScriptFactory(),
new DoubleArrayScriptFactory());
}
}
}

View File

@ -65,10 +65,7 @@ public class ScriptModesTests extends ESTestCase {
}
scriptContextRegistry = new ScriptContextRegistry(contexts.values());
scriptContexts = scriptContextRegistry.scriptContexts().toArray(new ScriptContext[scriptContextRegistry.scriptContexts().size()]);
scriptEngines = buildScriptEnginesByLangMap(newHashSet(
//add the native engine just to make sure it gets filtered out
new NativeScriptEngine(Settings.EMPTY, Collections.<String, NativeScriptFactory>emptyMap()),
new CustomScriptEngine()));
scriptEngines = buildScriptEnginesByLangMap(newHashSet(new CustomScriptEngine()));
ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(scriptEngines.values());
scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
checkedSettings = new HashSet<>();
@ -76,19 +73,12 @@ public class ScriptModesTests extends ESTestCase {
assertScriptModesNonNull = true;
}
@After
public void assertNativeScriptsAreAlwaysAllowed() {
if (assertScriptModesNonNull) {
assertThat(scriptModes.getScriptEnabled(NativeScriptEngine.NAME, randomFrom(ScriptType.values()), randomFrom(scriptContexts)), equalTo(true));
}
}
@After
public void assertAllSettingsWereChecked() {
if (assertScriptModesNonNull) {
assertThat(scriptModes, notNullValue());
int numberOfSettings = ScriptType.values().length * scriptContextRegistry.scriptContexts().size();
numberOfSettings += 3; // for top-level inline/store/file settings
numberOfSettings += 2; // for top-level inline/store settings
assertThat(scriptModes.scriptEnabled.size(), equalTo(numberOfSettings));
if (assertAllSettingsWereChecked) {
assertThat(checkedSettings.size(), equalTo(numberOfSettings));
@ -98,7 +88,6 @@ public class ScriptModesTests extends ESTestCase {
public void testDefaultSettings() {
this.scriptModes = new ScriptModes(scriptContextRegistry, scriptSettings, Settings.EMPTY);
assertScriptModesAllOps(true, ScriptType.FILE);
assertScriptModesAllOps(false, ScriptType.STORED, ScriptType.INLINE);
}
@ -136,9 +125,6 @@ public class ScriptModesTests extends ESTestCase {
for (int i = 0; i < randomInt; i++) {
assertScriptModesAllOps(randomScriptModes[i], randomScriptTypes[i]);
}
if (randomScriptTypesSet.contains(ScriptType.FILE) == false) {
assertScriptModesAllOps(true, ScriptType.FILE);
}
if (randomScriptTypesSet.contains(ScriptType.STORED) == false) {
assertScriptModesAllOps(false, ScriptType.STORED);
}
@ -174,7 +160,6 @@ public class ScriptModesTests extends ESTestCase {
}
ScriptContext[] complementOf = complementOf(randomScriptContexts);
assertScriptModes(true, new ScriptType[]{ScriptType.FILE}, complementOf);
assertScriptModes(false, new ScriptType[]{ScriptType.STORED, ScriptType.INLINE}, complementOf);
assertSettingDeprecationsAndWarnings(
ScriptSettingsTests.buildDeprecatedSettingsArray(scriptSettings, deprecated.toArray(new String[] {})));
@ -190,7 +175,7 @@ public class ScriptModesTests extends ESTestCase {
this.scriptModes = new ScriptModes(scriptContextRegistry, scriptSettings, builder.build());
assertScriptModesAllTypes(false, scriptContext);
ScriptContext[] complementOf = complementOf(scriptContext);
assertScriptModes(true, new ScriptType[]{ScriptType.FILE, ScriptType.STORED}, complementOf);
assertScriptModes(true, new ScriptType[]{ScriptType.STORED}, complementOf);
assertScriptModes(true, new ScriptType[]{ScriptType.INLINE}, complementOf);
assertSettingDeprecationsAndWarnings(
ScriptSettingsTests.buildDeprecatedSettingsArray(
@ -247,11 +232,6 @@ public class ScriptModesTests extends ESTestCase {
return NAME;
}
@Override
public String getExtension() {
return NAME;
}
@Override
public Object compile(String scriptName, String scriptSource, Map<String, String> params) {
return null;

View File

@ -18,27 +18,7 @@
*/
package org.elasticsearch.script;
import org.elasticsearch.ResourceNotFoundException;
import org.elasticsearch.action.admin.cluster.storedscripts.GetStoredScriptRequest;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.breaker.CircuitBreakingException;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.Streams;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.env.Environment;
import org.elasticsearch.search.lookup.SearchLookup;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.junit.Before;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
@ -48,15 +28,30 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import org.elasticsearch.ResourceNotFoundException;
import org.elasticsearch.action.admin.cluster.storedscripts.GetStoredScriptRequest;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.breaker.CircuitBreakingException;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.env.Environment;
import org.elasticsearch.search.lookup.SearchLookup;
import org.elasticsearch.test.ESTestCase;
import org.junit.Before;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.sameInstance;
//TODO: this needs to be a base test class, and all scripting engines extend it
public class ScriptServiceTests extends ESTestCase {
private ResourceWatcherService resourceWatcherService;
private ScriptEngine scriptEngine;
private ScriptEngine dangerousScriptEngine;
private Map<String, ScriptEngine> scriptEnginesByLangMap;
@ -65,13 +60,11 @@ public class ScriptServiceTests extends ESTestCase {
private ScriptSettings scriptSettings;
private ScriptContext[] scriptContexts;
private ScriptService scriptService;
private Path scriptsFilePath;
private Settings baseSettings;
private static final Map<ScriptType, Boolean> DEFAULT_SCRIPT_ENABLED = new HashMap<>();
static {
DEFAULT_SCRIPT_ENABLED.put(ScriptType.FILE, true);
DEFAULT_SCRIPT_ENABLED.put(ScriptType.STORED, false);
DEFAULT_SCRIPT_ENABLED.put(ScriptType.INLINE, false);
}
@ -84,7 +77,6 @@ public class ScriptServiceTests extends ESTestCase {
.put(Environment.PATH_CONF_SETTING.getKey(), genericConfigFolder)
.put(ScriptService.SCRIPT_MAX_COMPILATIONS_PER_MINUTE.getKey(), 10000)
.build();
resourceWatcherService = new ResourceWatcherService(baseSettings, null);
scriptEngine = new TestEngine();
dangerousScriptEngine = new TestDangerousEngine();
TestEngine defaultScriptServiceEngine = new TestEngine(Script.DEFAULT_SCRIPT_LANG) {};
@ -112,15 +104,12 @@ public class ScriptServiceTests extends ESTestCase {
scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
scriptContexts = scriptContextRegistry.scriptContexts().toArray(new ScriptContext[scriptContextRegistry.scriptContexts().size()]);
logger.info("--> setup script service");
scriptsFilePath = genericConfigFolder.resolve("scripts");
Files.createDirectories(scriptsFilePath);
}
private void buildScriptService(Settings additionalSettings) throws IOException {
Settings finalSettings = Settings.builder().put(baseSettings).put(additionalSettings).build();
Environment environment = new Environment(finalSettings);
// TODO:
scriptService = new ScriptService(finalSettings, environment, resourceWatcherService, scriptEngineRegistry, scriptContextRegistry, scriptSettings) {
scriptService = new ScriptService(finalSettings, scriptEngineRegistry, scriptContextRegistry, scriptSettings) {
@Override
StoredScriptSource getScriptFromClusterState(String id, String lang) {
//mock the script that gets retrieved from an index
@ -162,51 +151,6 @@ public class ScriptServiceTests extends ESTestCase {
}
}
public void testScriptsWithoutExtensions() throws IOException {
buildScriptService(Settings.EMPTY);
Path testFileNoExt = scriptsFilePath.resolve("test_no_ext");
Path testFileWithExt = scriptsFilePath.resolve("test_script.test");
Streams.copy("test_file_no_ext".getBytes("UTF-8"), Files.newOutputStream(testFileNoExt));
Streams.copy("test_file".getBytes("UTF-8"), Files.newOutputStream(testFileWithExt));
resourceWatcherService.notifyNow();
CompiledScript compiledScript = scriptService.compile(new Script(ScriptType.FILE, "test", "test_script", Collections.emptyMap()),
ScriptContext.Standard.SEARCH);
assertThat(compiledScript.compiled(), equalTo((Object) "compiled_test_file"));
Files.delete(testFileNoExt);
Files.delete(testFileWithExt);
resourceWatcherService.notifyNow();
try {
scriptService.compile(new Script(ScriptType.FILE, "test", "test_script", Collections.emptyMap()), ScriptContext.Standard.SEARCH);
fail("the script test_script should no longer exist");
} catch (IllegalArgumentException ex) {
assertThat(ex.getMessage(), containsString("unable to find file script [test_script] using lang [test]"));
}
assertWarnings("File scripts are deprecated. Use stored or inline scripts instead.");
}
public void testScriptCompiledOnceHiddenFileDetected() throws IOException {
buildScriptService(Settings.EMPTY);
Path testHiddenFile = scriptsFilePath.resolve(".hidden_file");
Streams.copy("test_hidden_file".getBytes("UTF-8"), Files.newOutputStream(testHiddenFile));
Path testFileScript = scriptsFilePath.resolve("file_script.test");
Streams.copy("test_file_script".getBytes("UTF-8"), Files.newOutputStream(testFileScript));
resourceWatcherService.notifyNow();
CompiledScript compiledScript = scriptService.compile(new Script(ScriptType.FILE, "test", "file_script", Collections.emptyMap()),
ScriptContext.Standard.SEARCH);
assertThat(compiledScript.compiled(), equalTo((Object) "compiled_test_file_script"));
Files.delete(testHiddenFile);
Files.delete(testFileScript);
resourceWatcherService.notifyNow();
assertWarnings("File scripts are deprecated. Use stored or inline scripts instead.");
}
public void testInlineScriptCompiledOnceCache() throws IOException {
buildScriptService(Settings.EMPTY);
CompiledScript compiledScript1 = scriptService.compile(new Script(ScriptType.INLINE, "test", "1+1", Collections.emptyMap()),
@ -281,26 +225,11 @@ public class ScriptServiceTests extends ESTestCase {
public void testDefaultBehaviourFineGrainedSettings() throws IOException {
Settings.Builder builder = Settings.builder();
//rarely inject the default settings, which have no effect
boolean deprecate = false;
if (rarely()) {
builder.put("script.file", "true");
deprecate = true;
}
buildScriptService(builder.build());
createFileScripts("dtest");
for (ScriptContext scriptContext : scriptContexts) {
// only file scripts are accepted by default
assertCompileRejected("dtest", "script", ScriptType.INLINE, scriptContext);
assertCompileRejected("dtest", "script", ScriptType.STORED, scriptContext);
assertCompileAccepted("dtest", "file_script", ScriptType.FILE, scriptContext);
}
if (deprecate) {
assertSettingDeprecationsAndWarnings(ScriptSettingsTests.buildDeprecatedSettingsArray(scriptSettings, "script.file"),
"File scripts are deprecated. Use stored or inline scripts instead.");
} else {
assertWarnings("File scripts are deprecated. Use stored or inline scripts instead.");
}
}
@ -369,12 +298,9 @@ public class ScriptServiceTests extends ESTestCase {
}
buildScriptService(builder.build());
createFileScripts("expression", "mustache", "dtest");
for (ScriptType scriptType : ScriptType.values()) {
//make sure file scripts have a different name than inline ones.
//Otherwise they are always considered file ones as they can be found in the static cache.
String script = scriptType == ScriptType.FILE ? "file_script" : "script";
String script = "script";
for (ScriptContext scriptContext : this.scriptContexts) {
//fallback mechanism: 1) engine specific settings 2) op based settings 3) source based settings
Boolean scriptEnabled = engineSettings.get(dangerousScriptEngine.getType() + "." + scriptType + "." + scriptContext.getKey());
@ -397,8 +323,7 @@ public class ScriptServiceTests extends ESTestCase {
}
}
assertSettingDeprecationsAndWarnings(
ScriptSettingsTests.buildDeprecatedSettingsArray(scriptSettings, deprecated.toArray(new String[] {})),
"File scripts are deprecated. Use stored or inline scripts instead.");
ScriptSettingsTests.buildDeprecatedSettingsArray(scriptSettings, deprecated.toArray(new String[] {})));
}
public void testCompileNonRegisteredContext() throws IOException {
@ -463,14 +388,6 @@ public class ScriptServiceTests extends ESTestCase {
ScriptSettingsTests.buildDeprecatedSettingsArray(scriptSettings, "script.inline"));
}
public void testFileScriptCountedInCompilationStats() throws IOException {
buildScriptService(Settings.EMPTY);
createFileScripts("test");
scriptService.compile(new Script(ScriptType.FILE, "test", "file_script", Collections.emptyMap()), randomFrom(scriptContexts));
assertEquals(1L, scriptService.stats().getCompilations());
assertWarnings("File scripts are deprecated. Use stored or inline scripts instead.");
}
public void testIndexedScriptCountedInCompilationStats() throws IOException {
buildScriptService(Settings.EMPTY);
scriptService.compile(new Script(ScriptType.STORED, "test", "script", Collections.emptyMap()), randomFrom(scriptContexts));
@ -542,14 +459,6 @@ public class ScriptServiceTests extends ESTestCase {
assertNull(scriptService.getStoredScript(cs, new GetStoredScriptRequest("_id", "_lang")));
}
private void createFileScripts(String... langs) throws IOException {
for (String lang : langs) {
Path scriptPath = scriptsFilePath.resolve("file_script." + lang);
Streams.copy("10".getBytes("UTF-8"), Files.newOutputStream(scriptPath));
}
resourceWatcherService.notifyNow();
}
private void assertCompileRejected(String lang, String script, ScriptType scriptType, ScriptContext scriptContext) {
try {
scriptService.compile(new Script(scriptType, lang, script, Collections.emptyMap()), scriptContext);
@ -585,11 +494,6 @@ public class ScriptServiceTests extends ESTestCase {
return name;
}
@Override
public String getExtension() {
return name;
}
@Override
public Object compile(String scriptName, String scriptText, Map<String, String> params) {
return "compiled_" + scriptText;
@ -625,11 +529,6 @@ public class ScriptServiceTests extends ESTestCase {
return NAME;
}
@Override
public String getExtension() {
return NAME;
}
@Override
public Object compile(String scriptName, String scriptSource, Map<String, String> params) {
return "compiled_" + scriptSource;

View File

@ -33,12 +33,9 @@ import static org.hamcrest.Matchers.equalTo;
public class ScriptSettingsTests extends ESTestCase {
public static Setting<?>[] buildDeprecatedSettingsArray(ScriptSettings scriptSettings, String... keys) {
return buildDeprecatedSettingsArray(null, scriptSettings, keys);
}
public static Setting<?>[] buildDeprecatedSettingsArray(Setting<?>[] deprecated, ScriptSettings scriptSettings, String... keys) {
Setting<?>[] settings = new Setting[keys.length + (deprecated == null ? 0 : deprecated.length)];
public static Setting<?>[] buildDeprecatedSettingsArray(ScriptSettings scriptSettings, String... keys) {
Setting<?>[] settings = new Setting[keys.length];
int count = 0;
for (Setting<?> setting : scriptSettings.getSettings()) {
@ -49,10 +46,6 @@ public class ScriptSettingsTests extends ESTestCase {
}
}
if (deprecated != null) {
System.arraycopy(deprecated, 0, settings, keys.length, deprecated.length);
}
return settings;
}
@ -82,11 +75,6 @@ public class ScriptSettingsTests extends ESTestCase {
return NAME;
}
@Override
public String getExtension() {
return NAME;
}
@Override
public Object compile(String scriptName, String scriptSource, Map<String, String> params) {
return null;

View File

@ -35,12 +35,10 @@ import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.plugins.PluginsService;
import org.elasticsearch.plugins.ScriptPlugin;
import org.elasticsearch.script.AbstractSearchScript;
import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.NativeScriptFactory;
import org.elasticsearch.script.MockScriptPlugin;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.search.lookup.LeafFieldsLookup;
import org.elasticsearch.tasks.TaskInfo;
import org.elasticsearch.test.ESIntegTestCase;
@ -51,8 +49,10 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import static org.elasticsearch.index.query.QueryBuilders.scriptQuery;
import static org.elasticsearch.search.SearchCancellationIT.ScriptedBlockPlugin.SCRIPT_NAME;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
@ -93,8 +93,8 @@ public class SearchCancellationIT extends ESIntegTestCase {
plugins.addAll(pluginsService.filterPlugins(ScriptedBlockPlugin.class));
}
for (ScriptedBlockPlugin plugin : plugins) {
plugin.scriptedBlockFactory.reset();
plugin.scriptedBlockFactory.enableBlock();
plugin.reset();
plugin.enableBlock();
}
return plugins;
}
@ -104,7 +104,7 @@ public class SearchCancellationIT extends ESIntegTestCase {
assertBusy(() -> {
int numberOfBlockedPlugins = 0;
for (ScriptedBlockPlugin plugin : plugins) {
numberOfBlockedPlugins += plugin.scriptedBlockFactory.hits.get();
numberOfBlockedPlugins += plugin.hits.get();
}
logger.info("The plugin blocked on {} out of {} shards", numberOfBlockedPlugins, numberOfShards);
assertThat(numberOfBlockedPlugins, greaterThan(0));
@ -113,7 +113,7 @@ public class SearchCancellationIT extends ESIntegTestCase {
private void disableBlocks(List<ScriptedBlockPlugin> plugins) throws Exception {
for (ScriptedBlockPlugin plugin : plugins) {
plugin.scriptedBlockFactory.disableBlock();
plugin.disableBlock();
}
}
@ -148,7 +148,7 @@ public class SearchCancellationIT extends ESIntegTestCase {
logger.info("Executing search");
ActionFuture<SearchResponse> searchResponse = client().prepareSearch("test").setQuery(
scriptQuery(new Script(
ScriptType.INLINE, "native", NativeTestScriptedBlockFactory.TEST_NATIVE_BLOCK_SCRIPT, Collections.emptyMap())))
ScriptType.INLINE, "mockscript", SCRIPT_NAME, Collections.emptyMap())))
.execute();
awaitForBlock(plugins);
@ -166,7 +166,7 @@ public class SearchCancellationIT extends ESIntegTestCase {
logger.info("Executing search");
ActionFuture<SearchResponse> searchResponse = client().prepareSearch("test")
.addScriptField("test_field",
new Script(ScriptType.INLINE, "native", NativeTestScriptedBlockFactory.TEST_NATIVE_BLOCK_SCRIPT, Collections.emptyMap())
new Script(ScriptType.INLINE, "mockscript", SCRIPT_NAME, Collections.emptyMap())
).execute();
awaitForBlock(plugins);
@ -187,7 +187,7 @@ public class SearchCancellationIT extends ESIntegTestCase {
.setSize(5)
.setQuery(
scriptQuery(new Script(
ScriptType.INLINE, "native", NativeTestScriptedBlockFactory.TEST_NATIVE_BLOCK_SCRIPT, Collections.emptyMap())))
ScriptType.INLINE, "mockscript", SCRIPT_NAME, Collections.emptyMap())))
.execute();
awaitForBlock(plugins);
@ -217,15 +217,15 @@ public class SearchCancellationIT extends ESIntegTestCase {
.setSize(2)
.setQuery(
scriptQuery(new Script(
ScriptType.INLINE, "native", NativeTestScriptedBlockFactory.TEST_NATIVE_BLOCK_SCRIPT, Collections.emptyMap())))
ScriptType.INLINE, "mockscript", SCRIPT_NAME, Collections.emptyMap())))
.get();
assertNotNull(searchResponse.getScrollId());
// Enable block so the second request would block
for (ScriptedBlockPlugin plugin : plugins) {
plugin.scriptedBlockFactory.reset();
plugin.scriptedBlockFactory.enableBlock();
plugin.reset();
plugin.enableBlock();
}
String scrollId = searchResponse.getScrollId();
@ -247,30 +247,13 @@ public class SearchCancellationIT extends ESIntegTestCase {
}
public static class ScriptedBlockPlugin extends Plugin implements ScriptPlugin {
private NativeTestScriptedBlockFactory scriptedBlockFactory;
public ScriptedBlockPlugin() {
scriptedBlockFactory = new NativeTestScriptedBlockFactory();
}
@Override
public List<NativeScriptFactory> getNativeScripts() {
return Collections.singletonList(scriptedBlockFactory);
}
}
private static class NativeTestScriptedBlockFactory implements NativeScriptFactory {
public static final String TEST_NATIVE_BLOCK_SCRIPT = "native_test_search_block_script";
public static class ScriptedBlockPlugin extends MockScriptPlugin {
static final String SCRIPT_NAME = "search_block";
private final AtomicInteger hits = new AtomicInteger();
private final AtomicBoolean shouldBlock = new AtomicBoolean(true);
NativeTestScriptedBlockFactory() {
}
public void reset() {
hits.set(0);
}
@ -284,24 +267,10 @@ public class SearchCancellationIT extends ESIntegTestCase {
}
@Override
public ExecutableScript newScript(Map<String, Object> params) {
return new NativeTestScriptedBlock();
}
@Override
public boolean needsScores() {
return false;
}
@Override
public String getName() {
return TEST_NATIVE_BLOCK_SCRIPT;
}
public class NativeTestScriptedBlock extends AbstractSearchScript {
@Override
public Object run() {
Loggers.getLogger(SearchCancellationIT.class).info("Blocking on the document {}", fields().get("_uid"));
public Map<String, Function<Map<String, Object>, Object>> pluginScripts() {
return Collections.singletonMap(SCRIPT_NAME, params -> {
LeafFieldsLookup fieldsLookup = (LeafFieldsLookup) params.get("_fields");
Loggers.getLogger(SearchCancellationIT.class).info("Blocking on the document {}", fieldsLookup.get("_uid"));
hits.incrementAndGet();
try {
awaitBusy(() -> shouldBlock.get() == false);
@ -309,8 +278,7 @@ public class SearchCancellationIT extends ESIntegTestCase {
throw new RuntimeException(e);
}
return true;
}
});
}
}
}

View File

@ -23,22 +23,20 @@ import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.plugins.ScriptPlugin;
import org.elasticsearch.script.AbstractSearchScript;
import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.NativeScriptFactory;
import org.elasticsearch.script.MockScriptPlugin;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.test.ESIntegTestCase;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import static org.elasticsearch.action.support.WriteRequest.RefreshPolicy.IMMEDIATE;
import static org.elasticsearch.index.query.QueryBuilders.scriptQuery;
import static org.elasticsearch.search.SearchTimeoutIT.ScriptedTimeoutPlugin.SCRIPT_NAME;
import static org.hamcrest.Matchers.equalTo;
@ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.SUITE)
@ -59,49 +57,23 @@ public class SearchTimeoutIT extends ESIntegTestCase {
SearchResponse searchResponse = client().prepareSearch("test").setTimeout(new TimeValue(10, TimeUnit.MILLISECONDS))
.setQuery(scriptQuery(
new Script(ScriptType.INLINE, "native", NativeTestScriptedTimeout.TEST_NATIVE_SCRIPT_TIMEOUT, Collections.emptyMap())))
new Script(ScriptType.INLINE, "mockscript", SCRIPT_NAME, Collections.emptyMap())))
.execute().actionGet();
assertThat(searchResponse.isTimedOut(), equalTo(true));
}
public static class ScriptedTimeoutPlugin extends Plugin implements ScriptPlugin {
public static class ScriptedTimeoutPlugin extends MockScriptPlugin {
static final String SCRIPT_NAME = "search_timeout";
@Override
public List<NativeScriptFactory> getNativeScripts() {
return Collections.singletonList(new NativeTestScriptedTimeout.Factory());
public Map<String, Function<Map<String, Object>, Object>> pluginScripts() {
return Collections.singletonMap(SCRIPT_NAME, params -> {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return true;
});
}
}
public static class NativeTestScriptedTimeout extends AbstractSearchScript {
public static final String TEST_NATIVE_SCRIPT_TIMEOUT = "native_test_search_timeout_script";
public static class Factory implements NativeScriptFactory {
@Override
public ExecutableScript newScript(Map<String, Object> params) {
return new NativeTestScriptedTimeout();
}
@Override
public boolean needsScores() {
return false;
}
@Override
public String getName() {
return TEST_NATIVE_SCRIPT_TIMEOUT;
}
}
@Override
public Object run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return true;
}
}
}

View File

@ -34,7 +34,6 @@ import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.search.aggregations.AggregationExecutionException;
import org.elasticsearch.search.aggregations.InternalAggregation;
import org.elasticsearch.search.aggregations.bucket.DateScriptMocks.DateScriptsMockPlugin;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
import org.elasticsearch.search.aggregations.bucket.histogram.ExtendedBounds;
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
@ -53,6 +52,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@ -184,8 +184,7 @@ public class DateHistogramIT extends ESIntegTestCase {
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return Arrays.asList(
DateScriptsMockPlugin.class);
return Collections.singleton(DateScriptMocksPlugin.class);
}
@After
@ -608,7 +607,7 @@ public class DateHistogramIT extends ESIntegTestCase {
SearchResponse response = client().prepareSearch("idx")
.addAggregation(dateHistogram("histo")
.field("date")
.script(new Script(ScriptType.INLINE, "native", DateScriptMocks.PlusOneMonthScript.NAME, params))
.script(new Script(ScriptType.INLINE, "mockscript", DateScriptMocksPlugin.LONG_PLUS_ONE_MONTH, params))
.dateHistogramInterval(DateHistogramInterval.MONTH)).execute().actionGet();
assertSearchResponse(response);
@ -747,7 +746,7 @@ public class DateHistogramIT extends ESIntegTestCase {
SearchResponse response = client().prepareSearch("idx")
.addAggregation(dateHistogram("histo")
.field("dates")
.script(new Script(ScriptType.INLINE, "native", DateScriptMocks.PlusOneMonthScript.NAME, params))
.script(new Script(ScriptType.INLINE, "mockscript", DateScriptMocksPlugin.LONG_PLUS_ONE_MONTH, params))
.dateHistogramInterval(DateHistogramInterval.MONTH)).execute().actionGet();
assertSearchResponse(response);
@ -799,8 +798,9 @@ public class DateHistogramIT extends ESIntegTestCase {
Map<String, Object> params = new HashMap<>();
params.put("fieldname", "date");
SearchResponse response = client().prepareSearch("idx")
.addAggregation(dateHistogram("histo").script(new Script(ScriptType.INLINE, "native", DateScriptMocks.ExtractFieldScript.NAME,
params)).dateHistogramInterval(DateHistogramInterval.MONTH))
.addAggregation(dateHistogram("histo").script(
new Script(ScriptType.INLINE, "mockscript", DateScriptMocksPlugin.EXTRACT_FIELD, params))
.dateHistogramInterval(DateHistogramInterval.MONTH))
.execute().actionGet();
assertSearchResponse(response);
@ -837,8 +837,9 @@ public class DateHistogramIT extends ESIntegTestCase {
Map<String, Object> params = new HashMap<>();
params.put("fieldname", "dates");
SearchResponse response = client().prepareSearch("idx")
.addAggregation(dateHistogram("histo").script(new Script(ScriptType.INLINE, "native", DateScriptMocks.ExtractFieldScript.NAME,
params)).dateHistogramInterval(DateHistogramInterval.MONTH))
.addAggregation(dateHistogram("histo").script(
new Script(ScriptType.INLINE, "mockscript", DateScriptMocksPlugin.EXTRACT_FIELD, params))
.dateHistogramInterval(DateHistogramInterval.MONTH))
.execute().actionGet();
assertSearchResponse(response);
@ -1329,7 +1330,7 @@ public class DateHistogramIT extends ESIntegTestCase {
Map<String, Object> params = new HashMap<>();
params.put("fieldname", "d");
SearchResponse r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(dateHistogram("histo").field("d")
.script(new Script(ScriptType.INLINE, "native", DateScriptMocks.PlusOneMonthScript.NAME, params))
.script(new Script(ScriptType.INLINE, "mockscript", DateScriptMocksPlugin.LONG_PLUS_ONE_MONTH, params))
.dateHistogramInterval(DateHistogramInterval.MONTH)).get();
assertSearchResponse(r);

View File

@ -26,7 +26,6 @@ import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.search.aggregations.InternalAggregation;
import org.elasticsearch.search.aggregations.bucket.DateScriptMocks.DateScriptsMockPlugin;
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
import org.elasticsearch.search.aggregations.bucket.range.Range;
import org.elasticsearch.search.aggregations.bucket.range.Range.Bucket;
@ -40,6 +39,7 @@ import org.joda.time.DateTimeZone;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -111,8 +111,7 @@ public class DateRangeIT extends ESIntegTestCase {
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return Arrays.asList(
DateScriptsMockPlugin.class);
return Collections.singleton(DateScriptMocksPlugin.class);
}
public void testDateMath() throws Exception {
@ -122,7 +121,7 @@ public class DateRangeIT extends ESIntegTestCase {
if (randomBoolean()) {
rangeBuilder.field("date");
} else {
rangeBuilder.script(new Script(ScriptType.INLINE, "native", DateScriptMocks.ExtractFieldScript.NAME, params));
rangeBuilder.script(new Script(ScriptType.INLINE, "mockscript", DateScriptMocksPlugin.EXTRACT_FIELD, params));
}
SearchResponse response = client()
.prepareSearch("idx")
@ -544,7 +543,7 @@ public class DateRangeIT extends ESIntegTestCase {
SearchResponse response = client().prepareSearch("idx")
.addAggregation(dateRange("range")
.field("dates")
.script(new Script(ScriptType.INLINE, "native", DateScriptMocks.PlusOneMonthScript.NAME, params))
.script(new Script(ScriptType.INLINE, "mockscript", DateScriptMocksPlugin.DOUBLE_PLUS_ONE_MONTH, params))
.addUnboundedTo(date(2, 15)).addRange(date(2, 15), date(3, 15)).addUnboundedFrom(date(3, 15))).execute()
.actionGet();
@ -600,7 +599,7 @@ public class DateRangeIT extends ESIntegTestCase {
params.put("fieldname", "date");
SearchResponse response = client().prepareSearch("idx")
.addAggregation(dateRange("range")
.script(new Script(ScriptType.INLINE, "native", DateScriptMocks.ExtractFieldScript.NAME, params))
.script(new Script(ScriptType.INLINE, "mockscript", DateScriptMocksPlugin.EXTRACT_FIELD, params))
.addUnboundedTo(date(2, 15))
.addRange(date(2, 15), date(3, 15))
.addUnboundedFrom(date(3, 15)))
@ -662,7 +661,7 @@ public class DateRangeIT extends ESIntegTestCase {
SearchResponse response = client()
.prepareSearch("idx")
.addAggregation(
dateRange("range").script(new Script(ScriptType.INLINE, "native", DateScriptMocks.ExtractFieldScript.NAME, params))
dateRange("range").script(new Script(ScriptType.INLINE, "mockscript", DateScriptMocksPlugin.EXTRACT_FIELD, params))
.addUnboundedTo(date(2, 15)).addRange(date(2, 15), date(3, 15))
.addUnboundedFrom(date(3, 15))).execute().actionGet();
@ -905,7 +904,7 @@ public class DateRangeIT extends ESIntegTestCase {
Map<String, Object> params = new HashMap<>();
params.put("fieldname", "date");
SearchResponse r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(dateRange("foo").field("date")
.script(new Script(ScriptType.INLINE, "native", DateScriptMocks.PlusOneMonthScript.NAME, params))
.script(new Script(ScriptType.INLINE, "mockscript", DateScriptMocksPlugin.DOUBLE_PLUS_ONE_MONTH, params))
.addRange(new DateTime(2012, 1, 1, 0, 0, 0, 0, DateTimeZone.UTC), new DateTime(2013, 1, 1, 0, 0, 0, 0, DateTimeZone.UTC)))
.get();
assertSearchResponse(r);

View File

@ -1,130 +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.search.aggregations.bucket;
import org.elasticsearch.common.inject.internal.Nullable;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.plugins.ScriptPlugin;
import org.elasticsearch.script.AbstractSearchScript;
import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.NativeScriptFactory;
import org.elasticsearch.script.ScriptModule;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Mock scripts shared by DateRangeIT and DateHistogramIT
*/
public class DateScriptMocks {
/**
* Mock plugin for the {@link DateScriptMocks.ExtractFieldScript} and {@link DateScriptMocks.PlusOneMonthScript}
*/
public static class DateScriptsMockPlugin extends Plugin implements ScriptPlugin {
@Override
public List<NativeScriptFactory> getNativeScripts() {
return Arrays.asList(new ExtractFieldScriptFactory(), new PlusOneMonthScriptFactory());
}
}
public static class ExtractFieldScriptFactory implements NativeScriptFactory {
@Override
public ExecutableScript newScript(@Nullable Map<String, Object> params) {
return new ExtractFieldScript((String) params.get("fieldname"));
}
@Override
public boolean needsScores() {
return false;
}
@Override
public String getName() {
return ExtractFieldScript.NAME;
}
}
public static class ExtractFieldScript extends AbstractSearchScript {
public static final String NAME = "extract_field";
private String fieldname;
public ExtractFieldScript(String fieldname) {
this.fieldname = fieldname;
}
@Override
public Object run() {
return doc().get(fieldname);
}
}
public static class PlusOneMonthScriptFactory implements NativeScriptFactory {
@Override
public ExecutableScript newScript(Map<String, Object> params) {
return new PlusOneMonthScript();
}
@Override
public boolean needsScores() {
return false;
}
@Override
public String getName() {
return PlusOneMonthScript.NAME;
}
}
/**
* This mock script takes date field value and adds one month to the returned date
*/
public static class PlusOneMonthScript extends AbstractSearchScript {
public static final String NAME = "date_plus_1_month";
private Map<String, Object> vars = new HashMap<>();
@Override
public void setNextVar(String name, Object value) {
vars.put(name, value);
}
@Override
public long runAsLong() {
return new DateTime((long) vars.get("_value"), DateTimeZone.UTC).plusMonths(1).getMillis();
}
@Override
public double runAsDouble() {
return new DateTime(Double.valueOf((double) vars.get("_value")).longValue(), DateTimeZone.UTC).plusMonths(1).getMillis();
}
@Override
public Object run() {
return new UnsupportedOperationException();
}
}
}

View File

@ -0,0 +1,56 @@
/*
* 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.search.aggregations.bucket;
import org.elasticsearch.script.MockScriptPlugin;
import org.elasticsearch.search.lookup.LeafDocLookup;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
/**
* Mock scripts shared by DateRangeIT and DateHistogramIT.
*
* Provides {@link DateScriptMocksPlugin#EXTRACT_FIELD}, {@link DateScriptMocksPlugin#DOUBLE_PLUS_ONE_MONTH},
* and {@link DateScriptMocksPlugin#LONG_PLUS_ONE_MONTH} scripts.
*/
public class DateScriptMocksPlugin extends MockScriptPlugin {
static final String EXTRACT_FIELD = "extract_field";
static final String DOUBLE_PLUS_ONE_MONTH = "double_date_plus_1_month";
static final String LONG_PLUS_ONE_MONTH = "long_date_plus_1_month";
@Override
public Map<String, Function<Map<String, Object>, Object>> pluginScripts() {
Map<String, Function<Map<String, Object>, Object>> scripts = new HashMap<>();
scripts.put(EXTRACT_FIELD, params -> {
LeafDocLookup docLookup = (LeafDocLookup) params.get("doc");
String fieldname = (String) params.get("fieldname");
return docLookup.get(fieldname);
});
scripts.put(DOUBLE_PLUS_ONE_MONTH, params ->
new DateTime(Double.valueOf((double) params.get("_value")).longValue(), DateTimeZone.UTC).plusMonths(1).getMillis());
scripts.put(LONG_PLUS_ONE_MONTH, params ->
new DateTime((long) params.get("_value"), DateTimeZone.UTC).plusMonths(1).getMillis());
return scripts;
}
}

View File

@ -18,27 +18,23 @@
*/
package org.elasticsearch.search.aggregations.bucket;
import org.elasticsearch.action.search.SearchPhaseExecutionException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.function.Function;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchPhaseExecutionException;
import org.elasticsearch.cluster.health.ClusterHealthStatus;
import org.elasticsearch.common.inject.internal.Nullable;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.plugins.ScriptPlugin;
import org.elasticsearch.script.AbstractSearchScript;
import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.NativeScriptFactory;
import org.elasticsearch.script.MockScriptPlugin;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.range.Range;
import org.elasticsearch.test.ESIntegTestCase;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchResponse;
import static org.hamcrest.Matchers.containsString;
@ -47,6 +43,13 @@ import static org.hamcrest.Matchers.instanceOf;
@ESIntegTestCase.SuiteScopeTestCase
public class IpRangeIT extends ESIntegTestCase {
public static class DummyScriptPlugin extends MockScriptPlugin {
@Override
public Map<String, Function<Map<String, Object>, Object>> pluginScripts() {
return Collections.singletonMap("dummy", params -> null);
}
}
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return Arrays.asList(DummyScriptPlugin.class);
@ -210,7 +213,7 @@ public class IpRangeIT extends ESIntegTestCase {
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> client().prepareSearch("idx").addAggregation(
AggregationBuilders.ipRange("my_range")
.script(new Script(ScriptType.INLINE, "native", DummyScript.NAME, Collections.emptyMap())) ).get());
.script(new Script(ScriptType.INLINE, "mockscript", "dummy", Collections.emptyMap())) ).get());
assertThat(e.getMessage(), containsString("[ip_range] does not support scripts"));
}
@ -219,7 +222,7 @@ public class IpRangeIT extends ESIntegTestCase {
() -> client().prepareSearch("idx").addAggregation(
AggregationBuilders.ipRange("my_range")
.field("ip")
.script(new Script(ScriptType.INLINE, "native", DummyScript.NAME, Collections.emptyMap())) ).get());
.script(new Script(ScriptType.INLINE, "mockscript", "dummy", Collections.emptyMap())) ).get());
assertThat(e.getMessage(), containsString("[ip_range] does not support scripts"));
}
@ -236,39 +239,4 @@ public class IpRangeIT extends ESIntegTestCase {
assertEquals(rootCause.getMessage(), "No [ranges] specified for the [my_range] aggregation");
}
}
public static class DummyScriptPlugin extends Plugin implements ScriptPlugin {
@Override
public List<NativeScriptFactory> getNativeScripts() {
return Collections.singletonList(new DummyScriptFactory());
}
}
public static class DummyScriptFactory implements NativeScriptFactory {
public DummyScriptFactory() {}
@Override
public ExecutableScript newScript(@Nullable Map<String, Object> params) {
return new DummyScript();
}
@Override
public boolean needsScores() {
return false;
}
@Override
public String getName() {
return DummyScript.NAME;
}
}
private static class DummyScript extends AbstractSearchScript {
public static final String NAME = "dummy";
@Override
public Object run() {
return null;
}
}
}

View File

@ -31,16 +31,13 @@ import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.index.query.QueryShardException;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.plugins.ScriptPlugin;
import org.elasticsearch.plugins.SearchPlugin;
import org.elasticsearch.script.NativeScriptFactory;
import org.elasticsearch.script.MockScriptPlugin;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.filter.InternalFilter;
import org.elasticsearch.search.aggregations.bucket.script.NativeSignificanceScoreScriptNoParams;
import org.elasticsearch.search.aggregations.bucket.script.NativeSignificanceScoreScriptWithParams;
import org.elasticsearch.search.aggregations.bucket.significant.SignificantTerms;
import org.elasticsearch.search.aggregations.bucket.significant.SignificantTermsAggregatorFactory;
import org.elasticsearch.search.aggregations.bucket.significant.heuristics.ChiSquare;
@ -64,6 +61,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.function.Function;
import static java.util.Collections.singletonList;
import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_REPLICAS;
@ -168,7 +166,7 @@ public class SignificantTermsSignificanceScoreIT extends ESIntegTestCase {
}
}
public static class CustomSignificanceHeuristicPlugin extends Plugin implements ScriptPlugin, SearchPlugin {
public static class CustomSignificanceHeuristicPlugin extends MockScriptPlugin implements SearchPlugin {
@Override
public List<SearchExtensionSpec<SignificanceHeuristic, SignificanceHeuristicParser>> getSignificanceHeuristics() {
return singletonList(new SearchExtensionSpec<SignificanceHeuristic, SignificanceHeuristicParser>(SimpleHeuristic.NAME,
@ -176,9 +174,22 @@ public class SignificantTermsSignificanceScoreIT extends ESIntegTestCase {
}
@Override
public List<NativeScriptFactory> getNativeScripts() {
return Arrays.asList(new NativeSignificanceScoreScriptNoParams.Factory(),
new NativeSignificanceScoreScriptWithParams.Factory());
public Map<String, Function<Map<String, Object>, Object>> pluginScripts() {
Map<String, Function<Map<String, Object>, Object>> scripts = new HashMap<>();
scripts.put("script_with_params", params -> {
double factor = ((Number) params.get("param")).doubleValue();
return factor * (longValue(params.get("_subset_freq")) + longValue(params.get("_subset_size")) +
longValue(params.get("_superset_freq")) + longValue(params.get("_superset_size"))) / factor;
});
scripts.put("script_no_params", params ->
longValue(params.get("_subset_freq")) + longValue(params.get("_subset_size")) +
longValue(params.get("_superset_freq")) + longValue(params.get("_superset_size"))
);
return scripts;
}
private static long longValue(Object value) {
return ((ScriptHeuristic.LongAccessor) value).longValue();
}
}
@ -514,9 +525,9 @@ public class SignificantTermsSignificanceScoreIT extends ESIntegTestCase {
if (randomBoolean()) {
Map<String, Object> params = new HashMap<>();
params.put("param", randomIntBetween(1, 100));
script = new Script(ScriptType.INLINE, "native", "native_significance_score_script_with_params", params);
script = new Script(ScriptType.INLINE, "mockscript", "script_with_params", params);
} else {
script = new Script(ScriptType.INLINE, "native", "native_significance_score_script_no_params", Collections.emptyMap());
script = new Script(ScriptType.INLINE, "mockscript", "script_no_params", Collections.emptyMap());
}
return new ScriptHeuristic(script);
}

View File

@ -418,11 +418,6 @@ public class AvgIT extends AbstractNumericTestCase {
return NAME;
}
@Override
public String getExtension() {
return NAME;
}
@Override
public Object compile(String scriptName, String scriptSource, Map<String, String> params) {
return scriptSource;
@ -523,11 +518,6 @@ public class AvgIT extends AbstractNumericTestCase {
return NAME;
}
@Override
public String getExtension() {
return NAME;
}
@Override
public Object compile(String scriptName, String scriptSource, Map<String, String> params) {
return scriptSource;

View File

@ -815,44 +815,6 @@ public class ScriptedMetricIT extends ESIntegTestCase {
assertThat(((Number) object).longValue(), equalTo(numDocs * 3));
}
public void testInitMapCombineReduceWithParamsFile() {
Map<String, Object> varsMap = new HashMap<>();
varsMap.put("multiplier", 1);
Map<String, Object> params = new HashMap<>();
params.put("_agg", new ArrayList<>());
params.put("vars", varsMap);
SearchResponse response = client()
.prepareSearch("idx")
.setQuery(matchAllQuery())
.addAggregation(
scriptedMetric("scripted")
.params(params)
.initScript(new Script(ScriptType.FILE, CustomScriptPlugin.NAME, "init_script", Collections.emptyMap()))
.mapScript(new Script(ScriptType.FILE, CustomScriptPlugin.NAME, "map_script", Collections.emptyMap()))
.combineScript(
new Script(ScriptType.FILE, CustomScriptPlugin.NAME, "combine_script", Collections.emptyMap()))
.reduceScript(
new Script(ScriptType.FILE, CustomScriptPlugin.NAME, "reduce_script", Collections.emptyMap())))
.get();
assertSearchResponse(response);
assertThat(response.getHits().getTotalHits(), equalTo(numDocs));
Aggregation aggregation = response.getAggregations().get("scripted");
assertThat(aggregation, notNullValue());
assertThat(aggregation, instanceOf(ScriptedMetric.class));
ScriptedMetric scriptedMetricAggregation = (ScriptedMetric) aggregation;
assertThat(scriptedMetricAggregation.getName(), equalTo("scripted"));
assertThat(scriptedMetricAggregation.aggregation(), notNullValue());
assertThat(scriptedMetricAggregation.aggregation(), instanceOf(ArrayList.class));
List<?> aggregationList = (List<?>) scriptedMetricAggregation.aggregation();
assertThat(aggregationList.size(), equalTo(1));
Object object = aggregationList.get(0);
assertThat(object, notNullValue());
assertThat(object, instanceOf(Number.class));
assertThat(((Number) object).longValue(), equalTo(numDocs * 3));
}
public void testInitMapCombineReduceWithParamsAsSubAgg() {
Map<String, Object> varsMap = new HashMap<>();
varsMap.put("multiplier", 1);

View File

@ -418,11 +418,6 @@ public class SumIT extends AbstractNumericTestCase {
return NAME;
}
@Override
public String getExtension() {
return NAME;
}
@Override
public Object compile(String scriptName, String scriptSource, Map<String, String> params) {
return scriptSource;
@ -530,11 +525,6 @@ public class SumIT extends AbstractNumericTestCase {
return NAME;
}
@Override
public String getExtension() {
return NAME;
}
@Override
public Object compile(String scriptName, String scriptSource, Map<String, String> params) {
return scriptSource;

View File

@ -272,11 +272,6 @@ public class ValueCountIT extends ESIntegTestCase {
return NAME;
}
@Override
public String getExtension() {
return NAME;
}
@Override
public Object compile(String scriptName, String scriptSource, Map<String, String> params) {
return scriptSource;

View File

@ -114,9 +114,6 @@ public class InternalScriptedMetricTests extends InternalAggregationTestCase<Int
*/
@Override
protected ScriptService mockScriptService() {
Settings settings = Settings.builder()
.put(Environment.PATH_HOME_SETTING.getKey(), createTempDir())
.build();
// mock script always retuns the size of the input aggs list as result
@SuppressWarnings("unchecked")
MockScriptEngine scriptEngine = new MockScriptEngine(MockScriptEngine.NAME,
@ -127,7 +124,7 @@ public class InternalScriptedMetricTests extends InternalAggregationTestCase<Int
ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(Collections.emptyList());
ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
try {
return new ScriptService(settings, new Environment(settings), null, scriptEngineRegistry, scriptContextRegistry,
return new ScriptService(Settings.EMPTY, scriptEngineRegistry, scriptContextRegistry,
scriptSettings);
} catch (IOException e) {
throw new ElasticsearchException(e);

View File

@ -198,15 +198,13 @@ public class ScriptedMetricAggregatorTests extends AggregatorTestCase {
@Override
protected QueryShardContext queryShardContextMock(MapperService mapperService, final MappedFieldType[] fieldTypes,
CircuitBreakerService circuitBreakerService) {
Settings settings = Settings.builder().put(Environment.PATH_HOME_SETTING.getKey(), createTempDir()).build();
MockScriptEngine scriptEngine = new MockScriptEngine(MockScriptEngine.NAME, SCRIPTS);
ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(Collections.singletonList(scriptEngine));
ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(Collections.emptyList());
ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
ScriptService scriptService;
try {
scriptService = new ScriptService(settings, new Environment(settings), null, scriptEngineRegistry, scriptContextRegistry,
scriptSettings);
scriptService = new ScriptService(Settings.EMPTY, scriptEngineRegistry, scriptContextRegistry, scriptSettings);
} catch (IOException e) {
throw new ElasticsearchException(e);
}

View File

@ -19,22 +19,29 @@
package org.elasticsearch.search.functionscore;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.search.Explanation;
import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.lucene.search.function.CombineFunction;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.fielddata.ScriptDocValues;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.script.AbstractDoubleSearchScript;
import org.elasticsearch.plugins.ScriptPlugin;
import org.elasticsearch.script.CompiledScript;
import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.ExplainableSearchScript;
import org.elasticsearch.script.NativeScriptFactory;
import org.elasticsearch.script.LeafSearchScript;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptEngine;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.script.SearchScript;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.lookup.LeafDocLookup;
import org.elasticsearch.search.lookup.SearchLookup;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.test.ESIntegTestCase.Scope;
@ -60,12 +67,77 @@ import static org.hamcrest.Matchers.equalTo;
@ClusterScope(scope = Scope.SUITE, supportsDedicatedMasters = false, numDataNodes = 1)
public class ExplainableScriptIT extends ESIntegTestCase {
public static class ExplainableScriptPlugin extends Plugin implements ScriptPlugin {
@Override
public ScriptEngine getScriptEngine(Settings settings) {
return new ScriptEngine() {
@Override
public String getType() {
return "test";
}
@Override
public Object compile(String scriptName, String scriptSource, Map<String, String> params) {
assert scriptSource.equals("explainable_script");
return null;
}
@Override
public ExecutableScript executable(CompiledScript compiledScript, @Nullable Map<String, Object> vars) {
throw new UnsupportedOperationException();
}
@Override
public SearchScript search(CompiledScript compiledScript, SearchLookup lookup, @Nullable Map<String, Object> vars) {
return new SearchScript() {
@Override
public LeafSearchScript getLeafSearchScript(LeafReaderContext context) throws IOException {
return new MyScript(lookup.doc().getLeafDocLookup(context));
}
@Override
public boolean needsScores() {
return false;
}
};
}
@Override
public void close() {}
};
}
}
static class MyScript implements ExplainableSearchScript {
LeafDocLookup docLookup;
MyScript(LeafDocLookup docLookup) {
this.docLookup = docLookup;
}
@Override
public void setDocument(int doc) {
docLookup.setDocument(doc);
}
@Override
public Explanation explain(Explanation subQueryScore) throws IOException {
Explanation scoreExp = Explanation.match(subQueryScore.getValue(), "_score: ", subQueryScore);
return Explanation.match((float) (runAsDouble()), "This script returned " + runAsDouble(), scoreExp);
}
@Override
public double runAsDouble() {
return ((Number) ((ScriptDocValues) docLookup.get("number_field")).getValues().get(0)).doubleValue();
}
}
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return Arrays.asList(ExplainableScriptPlugin.class);
}
public void testNativeExplainScript() throws InterruptedException, IOException, ExecutionException {
public void testExplainScript() throws InterruptedException, IOException, ExecutionException {
List<IndexRequestBuilder> indexRequests = new ArrayList<>();
for (int i = 0; i < 20; i++) {
indexRequests.add(client().prepareIndex("test", "type").setId(Integer.toString(i)).setSource(
@ -78,7 +150,7 @@ public class ExplainableScriptIT extends ESIntegTestCase {
searchSource().explain(true).query(
functionScoreQuery(termQuery("text", "text"),
scriptFunction(
new Script(ScriptType.INLINE, "native", "native_explainable_script", Collections.emptyMap())))
new Script(ScriptType.INLINE, "test", "explainable_script", Collections.emptyMap())))
.boostMode(CombineFunction.REPLACE)))).actionGet();
ElasticsearchAssertions.assertNoFailures(response);
@ -89,39 +161,10 @@ public class ExplainableScriptIT extends ESIntegTestCase {
assertThat(hit.getId(), equalTo(Integer.toString(idCounter)));
assertThat(hit.getExplanation().toString(),
containsString(Double.toString(idCounter) + " = This script returned " + Double.toString(idCounter)));
assertThat(hit.getExplanation().toString(), containsString("freq=1.0 = termFreq=1.0"));
assertThat(hit.getExplanation().toString(), containsString("freq=1.0"));
assertThat(hit.getExplanation().toString(), containsString("termFreq=1.0"));
assertThat(hit.getExplanation().getDetails().length, equalTo(2));
idCounter--;
}
}
public static class MyNativeScriptFactory implements NativeScriptFactory {
@Override
public ExecutableScript newScript(@Nullable Map<String, Object> params) {
return new MyScript();
}
@Override
public boolean needsScores() {
return true;
}
@Override
public String getName() {
return "native_explainable_script";
}
}
static class MyScript extends AbstractDoubleSearchScript implements ExplainableSearchScript, ExecutableScript {
@Override
public Explanation explain(Explanation subQueryScore) throws IOException {
Explanation scoreExp = Explanation.match(subQueryScore.getValue(), "_score: ", subQueryScore);
return Explanation.match((float) (runAsDouble()), "This script returned " + runAsDouble(), scoreExp);
}
@Override
public double runAsDouble() {
return ((Number) ((ScriptDocValues) doc().get("number_field")).getValues().get(0)).doubleValue();
}
}
}

View File

@ -1,35 +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.search.functionscore;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.plugins.ScriptPlugin;
import org.elasticsearch.script.NativeScriptFactory;
import java.util.Collections;
import java.util.List;
public class ExplainableScriptPlugin extends Plugin implements ScriptPlugin {
@Override
public List<NativeScriptFactory> getNativeScripts() {
return Collections.singletonList(new ExplainableScriptIT.MyNativeScriptFactory());
}
}

View File

@ -93,8 +93,7 @@ public abstract class AbstractSortTestCase<T extends SortBuilder<T>> extends EST
ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(Collections.emptyList());
ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(Collections.singletonList(new TestEngine()));
ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
scriptService = new ScriptService(baseSettings, environment,
new ResourceWatcherService(baseSettings, null), scriptEngineRegistry, scriptContextRegistry, scriptSettings) {
scriptService = new ScriptService(baseSettings, scriptEngineRegistry, scriptContextRegistry, scriptSettings) {
@Override
public CompiledScript compile(Script script, ScriptContext scriptContext) {
return new CompiledScript(ScriptType.INLINE, "mockName", "test", script);

View File

@ -1030,11 +1030,6 @@ public class SuggestSearchIT extends ESIntegTestCase {
return NAME;
}
@Override
public String getExtension() {
return NAME;
}
@Override
public Object compile(String scriptName, String scriptSource, Map<String, String> params) {
return scriptSource;

View File

@ -65,12 +65,10 @@ public class TribeServiceTests extends ESTestCase {
.put("node.name", "nodename")
.put("path.home", "some/path")
.put("path.conf", "conf/path")
.put("path.scripts", "scripts/path")
.put("path.logs", "logs/path").build();
Settings clientSettings = TribeService.buildClientSettings("tribe1", "parent_id", globalSettings, Settings.EMPTY);
assertEquals("some/path", clientSettings.get("path.home"));
assertEquals("conf/path", clientSettings.get("path.conf"));
assertEquals("scripts/path", clientSettings.get("path.scripts"));
assertEquals("logs/path", clientSettings.get("path.logs"));
Settings tribeSettings = Settings.builder()
@ -79,7 +77,6 @@ public class TribeServiceTests extends ESTestCase {
TribeService.buildClientSettings("tribe1", "parent_id", globalSettings, tribeSettings);
});
assertTrue(e.getMessage(), e.getMessage().contains("Setting [path.home] not allowed in tribe client"));
assertSettingDeprecationsAndWarnings(new Setting[] {Environment.PATH_SCRIPTS_SETTING});
}
public void testPassthroughSettings() {

View File

@ -1,117 +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.update;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.plugins.ScriptPlugin;
import org.elasticsearch.script.AbstractExecutableScript;
import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.NativeScriptEngine;
import org.elasticsearch.script.NativeScriptFactory;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.test.ESIntegTestCase.Scope;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.hamcrest.Matchers.hasKey;
import static org.hamcrest.Matchers.is;
@ClusterScope(scope= Scope.SUITE, numDataNodes =1)
public class UpdateByNativeScriptIT extends ESIntegTestCase {
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return Arrays.asList(CustomNativeScriptFactory.TestPlugin.class);
}
public void testThatUpdateUsingNativeScriptWorks() throws Exception {
createIndex("test");
index("test", "type", "1", "text", "value");
Map<String, Object> params = new HashMap<>();
params.put("foo", "SETVALUE");
client().prepareUpdate("test", "type", "1")
.setScript(new Script(ScriptType.INLINE, NativeScriptEngine.NAME, "custom", params)).get();
Map<String, Object> data = client().prepareGet("test", "type", "1").get().getSource();
assertThat(data, hasKey("foo"));
assertThat(data.get("foo").toString(), is("SETVALUE"));
}
public static class CustomNativeScriptFactory implements NativeScriptFactory {
public static class TestPlugin extends Plugin implements ScriptPlugin {
@Override
public List<NativeScriptFactory> getNativeScripts() {
return Collections.singletonList(new CustomNativeScriptFactory());
}
}
@Override
public ExecutableScript newScript(@Nullable Map<String, Object> params) {
return new CustomScript(params);
}
@Override
public boolean needsScores() {
return false;
}
@Override
public String getName() {
return "custom";
}
}
static class CustomScript extends AbstractExecutableScript {
private Map<String, Object> params;
private Map<String, Object> vars = new HashMap<>(2);
CustomScript(Map<String, Object> params) {
this.params = params;
}
@Override
public Object run() {
if (vars.containsKey("ctx") && vars.get("ctx") instanceof Map) {
Map ctx = (Map) vars.get("ctx");
if (ctx.containsKey("_source") && ctx.get("_source") instanceof Map) {
Map source = (Map) ctx.get("_source");
source.putAll(params);
}
}
// return value does not matter, the UpdateHelper class
return null;
}
@Override
public void setNextVar(String name, Object value) {
vars.put(name, value);
}
}
}

View File

@ -91,11 +91,6 @@ public class UpdateIT extends ESIntegTestCase {
return NAME;
}
@Override
public String getExtension() {
return NAME;
}
@Override
public Object compile(String scriptName, String scriptSource, Map<String, String> params) {
return new Object(); // unused
@ -164,11 +159,6 @@ public class UpdateIT extends ESIntegTestCase {
return NAME;
}
@Override
public String getExtension() {
return NAME;
}
@Override
public Object compile(String scriptName, String scriptSource, Map<String, String> params) {
return scriptSource;
@ -230,11 +220,6 @@ public class UpdateIT extends ESIntegTestCase {
return NAME;
}
@Override
public String getExtension() {
return NAME;
}
@Override
public Object compile(String scriptName, String scriptSource, Map<String, String> params) {
return new Object(); // unused
@ -297,11 +282,6 @@ public class UpdateIT extends ESIntegTestCase {
return NAME;
}
@Override
public String getExtension() {
return NAME;
}
@Override
public Object compile(String scriptName, String scriptSource, Map<String, String> params) {
return new Object(); // unused

View File

@ -304,7 +304,6 @@ configure(distributions.findAll { ['deb', 'rpm'].contains(it.name) }) {
/* Explicitly declare the outputs so that gradle won't skip this task if
one of the other tasks like createEtc run first and create the packaging
directory as a side effect. */
outputs.dir("${packagingFiles}/scripts")
outputs.dir("${packagingFiles}/env")
outputs.dir("${packagingFiles}/systemd")
}
@ -314,14 +313,8 @@ configure(distributions.findAll { ['deb', 'rpm'].contains(it.name) }) {
dirMode 0750
}
task createEtcScripts(type: EmptyDirTask) {
dependsOn createEtc
dir "${packagingFiles}/etc/elasticsearch/scripts"
dirMode 0750
}
task fillEtc(type: Copy) {
dependsOn createEtc, createEtcScripts
dependsOn createEtc
with configFiles
into "${packagingFiles}/etc/elasticsearch"
/* Explicitly declare the output files so this task doesn't consider itself

View File

@ -21,70 +21,74 @@ import java.util.regex.Matcher
import org.elasticsearch.gradle.LoggedExec
/**
* This is a dummy project which does a local worktree checkout of the previous
* major version's stable branch, and builds a snapshot. This allows backcompat
* tests in the next major version to test against the next unreleased minor
* version, without relying on snapshots.
* This is a dummy project which does a local checkout of the previous
* wire compat version's branch, and builds a snapshot. This allows backcompat
* tests to test against the next unreleased version, closest to this version,
* without relying on snapshots.
*/
apply plugin: 'distribution'
String bwcVersion = wireCompatVersions[-1]
if (bwcVersion.endsWith('-SNAPSHOT')) {
apply plugin: 'distribution'
File checkoutDir = file("${buildDir}/bwc/checkout-5.x")
task createClone(type: LoggedExec) {
onlyIf { checkoutDir.exists() == false }
commandLine = ['git', 'clone', rootDir, checkoutDir]
}
def (String major, String minor, String bugfix) = bwcVersion.split('\\.')
String bwcBranch = bugfix == '0-SNAPSHOT' ? "${major}.x" : "${major}.${minor}"
File checkoutDir = file("${buildDir}/bwc/checkout-${bwcBranch}")
task createClone(type: LoggedExec) {
onlyIf { checkoutDir.exists() == false }
commandLine = ['git', 'clone', rootDir, checkoutDir]
}
// we use regular Exec here to ensure we always get output, regardless of logging level
task findUpstream(type: Exec) {
dependsOn createClone
workingDir = checkoutDir
commandLine = ['git', 'remote', '-v']
ignoreExitValue = true
ByteArrayOutputStream output = new ByteArrayOutputStream()
standardOutput = output
doLast {
if (execResult.exitValue != 0) {
output.toString('UTF-8').eachLine { line -> logger.error(line) }
execResult.assertNormalExitValue()
}
project.ext.upstreamExists = false
output.toString('UTF-8').eachLine {
if (it.contains("upstream")) {
project.ext.upstreamExists = true
// we use regular Exec here to ensure we always get output, regardless of logging level
task findUpstream(type: Exec) {
dependsOn createClone
workingDir = checkoutDir
commandLine = ['git', 'remote', '-v']
ignoreExitValue = true
ByteArrayOutputStream output = new ByteArrayOutputStream()
standardOutput = output
doLast {
if (execResult.exitValue != 0) {
output.toString('UTF-8').eachLine { line -> logger.error(line) }
execResult.assertNormalExitValue()
}
project.ext.upstreamExists = false
output.toString('UTF-8').eachLine {
if (it.contains("upstream")) {
project.ext.upstreamExists = true
}
}
}
}
}
task addUpstream(type: LoggedExec) {
dependsOn findUpstream
onlyIf { project.ext.upstreamExists == false }
workingDir = checkoutDir
commandLine = ['git', 'remote', 'add', 'upstream', 'https://github.com/elastic/elasticsearch.git']
}
task addUpstream(type: LoggedExec) {
dependsOn findUpstream
onlyIf { project.ext.upstreamExists == false }
workingDir = checkoutDir
commandLine = ['git', 'remote', 'add', 'upstream', 'https://github.com/elastic/elasticsearch.git']
}
task fetchLatest(type: LoggedExec) {
onlyIf { project.gradle.startParameter.isOffline() == false }
dependsOn addUpstream
workingDir = checkoutDir
commandLine = ['git', 'fetch', 'upstream']
}
task fetchLatest(type: LoggedExec) {
onlyIf { project.gradle.startParameter.isOffline() == false }
dependsOn addUpstream
workingDir = checkoutDir
commandLine = ['git', 'fetch', 'upstream']
}
task checkoutBwcBranch(type: LoggedExec) {
dependsOn fetchLatest
workingDir = checkoutDir
commandLine = ['git', 'checkout', 'upstream/5.x']
}
task checkoutBwcBranch(type: LoggedExec) {
dependsOn fetchLatest
workingDir = checkoutDir
commandLine = ['git', 'checkout', "upstream/${bwcBranch}"]
}
File bwcZip = file("${checkoutDir}/distribution/zip/build/distributions/elasticsearch-${bwcVersion}.zip")
task buildBwcVersion(type: GradleBuild) {
dependsOn checkoutBwcBranch
dir = checkoutDir
tasks = [':distribution:zip:assemble']
}
File bwcZip = file("${checkoutDir}/distribution/zip/build/distributions/elasticsearch-${bwcVersion}.zip")
task buildBwcVersion(type: GradleBuild) {
dependsOn checkoutBwcBranch
dir = checkoutDir
tasks = [':distribution:zip:assemble']
}
artifacts {
'default' file: bwcZip, name: 'elasticsearch', type: 'zip', builtBy: buildBwcVersion
artifacts {
'default' file: bwcZip, name: 'elasticsearch', type: 'zip', builtBy: buildBwcVersion
}
}

View File

@ -66,12 +66,6 @@ integTestCluster {
Closure configFile = {
extraConfigFile it, "src/test/cluster/config/$it"
}
configFile 'scripts/calculate_score.painless'
configFile 'scripts/my_script.painless'
configFile 'scripts/my_init_script.painless'
configFile 'scripts/my_map_script.painless'
configFile 'scripts/my_combine_script.painless'
configFile 'scripts/my_reduce_script.painless'
configFile 'analysis/example_word_list.txt'
configFile 'analysis/hyphenation_patterns.xml'
configFile 'analysis/synonym.txt'
@ -371,3 +365,38 @@ buildRestTests.setups['exams'] = '''
{"grade": 100}
{"index":{}}
{"grade": 50}'''
buildRestTests.setups['stored_example_script'] = '''
# Simple script to load a field. Not really a good example, but a simple one.
- do:
put_script:
id: "my_script"
body: { "script": { "lang": "painless", "code": "doc[params.field].value" } }
- match: { acknowledged: true }
'''
buildRestTests.setups['stored_scripted_metric_script'] = '''
- do:
put_script:
id: "my_init_script"
body: { "script": { "lang": "painless", "code": "params._agg.transactions = []" } }
- match: { acknowledged: true }
- do:
put_script:
id: "my_map_script"
body: { "script": { "lang": "painless", "code": "params._agg.transactions.add(doc.type.value == 'sale' ? doc.amount.value : -1 * doc.amount.value)" } }
- match: { acknowledged: true }
- do:
put_script:
id: "my_combine_script"
body: { "script": { "lang": "painless", "code": "double profit = 0;for (t in params._agg.transactions) { profit += t; } return profit" } }
- match: { acknowledged: true }
- do:
put_script:
id: "my_reduce_script"
body: { "script": { "lang": "painless", "code": "double profit = 0;for (a in params._aggs) { profit += a; } return profit" } }
- match: { acknowledged: true }
'''

View File

@ -149,7 +149,7 @@ It is also possible to customize the key for each range:
}
--------------------------------------------------
This will interpret the `script` parameter as an `inline` script with the `painless` script language and no script parameters. To use a file script use the following syntax:
This will interpret the `script` parameter as an `inline` script with the `painless` script language and no script parameters. To use a stored script use the following syntax:
[source,js]
--------------------------------------------------
@ -158,7 +158,7 @@ This will interpret the `script` parameter as an `inline` script with the `painl
"price_ranges" : {
"range" : {
"script" : {
"file": "my_script",
"stored": "my_script",
"params": {
"field": "price"
}
@ -174,8 +174,6 @@ This will interpret the `script` parameter as an `inline` script with the `painl
}
--------------------------------------------------
TIP: for indexed scripts replace the `file` parameter with an `id` parameter.
==== Value Script
Lets say the product prices are in USD but we would like to get the price ranges in EURO. We can use value script to convert the prices prior the aggregation (assuming conversion rate of 0.8)

View File

@ -469,7 +469,7 @@ Generating the terms using a script:
}
--------------------------------------------------
This will interpret the `script` parameter as an `inline` script with the default script language and no script parameters. To use a file script use the following syntax:
This will interpret the `script` parameter as an `inline` script with the default script language and no script parameters. To use a stored script use the following syntax:
[source,js]
--------------------------------------------------
@ -478,7 +478,7 @@ This will interpret the `script` parameter as an `inline` script with the defaul
"genres" : {
"terms" : {
"script" : {
"file": "my_script",
"stored": "my_script",
"params": {
"field": "genre"
}
@ -489,9 +489,6 @@ This will interpret the `script` parameter as an `inline` script with the defaul
}
--------------------------------------------------
TIP: for indexed scripts replace the `file` parameter with an `id` parameter.
==== Value Script
[source,js]

View File

@ -57,7 +57,7 @@ POST /exams/_search?size=0
// CONSOLE
// TEST[setup:exams]
This will interpret the `script` parameter as an `inline` script with the `painless` script language and no script parameters. To use a file script use the following syntax:
This will interpret the `script` parameter as an `inline` script with the `painless` script language and no script parameters. To use a stored script use the following syntax:
[source,js]
--------------------------------------------------
@ -67,7 +67,7 @@ POST /exams/_search?size=0
"avg_grade" : {
"avg" : {
"script" : {
"file": "my_script",
"stored": "my_script",
"params": {
"field": "grade"
}
@ -78,9 +78,7 @@ POST /exams/_search?size=0
}
--------------------------------------------------
// CONSOLE
// TEST[setup:exams]
TIP: for indexed scripts replace the `file` parameter with an `id` parameter.
// TEST[setup:exams,stored_example_script]
===== Value Script

View File

@ -197,7 +197,7 @@ POST /sales/_search?size=0
// CONSOLE
// TEST[setup:sales]
This will interpret the `script` parameter as an `inline` script with the `painless` script language and no script parameters. To use a file script use the following syntax:
This will interpret the `script` parameter as an `inline` script with the `painless` script language and no script parameters. To use a stored script use the following syntax:
[source,js]
--------------------------------------------------
@ -207,7 +207,7 @@ POST /sales/_search?size=0
"type_promoted_count" : {
"cardinality" : {
"script" : {
"file": "my_script",
"stored": "my_script",
"params": {
"type_field": "type",
"promoted_field": "promoted"
@ -221,8 +221,6 @@ POST /sales/_search?size=0
// CONSOLE
// TEST[skip:no script]
TIP: for indexed scripts replace the `file` parameter with an `id` parameter.
==== Missing value
The `missing` parameter defines how documents that are missing a value should be treated.

View File

@ -109,7 +109,7 @@ This will interpret the `script` parameter as an `inline` script with the `painl
"grades_stats" : {
"extended_stats" : {
"script" : {
"file": "my_script",
"stored": "my_script",
"params": {
"field": "grade"
}
@ -120,8 +120,6 @@ This will interpret the `script` parameter as an `inline` script with the `painl
}
--------------------------------------------------
TIP: for indexed scripts replace the `file` parameter with an `id` parameter.
===== Value Script
It turned out that the exam was way above the level of the students and a grade correction needs to be applied. We can use value script to get the new stats:

View File

@ -67,7 +67,7 @@ POST /sales/_search
// TEST[setup:sales]
This will use the <<modules-scripting-painless, Painless>> scripting language
and no script parameters. To use a file script use the following syntax:
and no script parameters. To use a stored script use the following syntax:
[source,js]
--------------------------------------------------
@ -77,7 +77,7 @@ POST /sales/_search
"max_price" : {
"max" : {
"script" : {
"file": "my_script",
"stored": "my_script",
"params": {
"field": "price"
}
@ -88,9 +88,7 @@ POST /sales/_search
}
--------------------------------------------------
// CONSOLE
// TEST[setup:sales]
TIP: For indexed scripts replace the `file` parameter with an `id` parameter.
// TEST[setup:sales,stored_example_script]
==== Value Script

View File

@ -68,7 +68,7 @@ POST /sales/_search
// TEST[setup:sales]
This will use the <<modules-scripting-painless, Painless>> scripting language
and no script parameters. To use a file script use the following syntax:
and no script parameters. To use a stored script use the following syntax:
[source,js]
--------------------------------------------------
@ -78,7 +78,7 @@ POST /sales/_search
"min_price" : {
"min" : {
"script" : {
"file": "my_script",
"stored": "my_script",
"params": {
"field": "price"
}
@ -89,9 +89,7 @@ POST /sales/_search
}
--------------------------------------------------
// CONSOLE
// TEST[setup:sales]
TIP: For indexed scripts replace the `file` parameter with an `id` parameter.
// TEST[setup:sales,stored_example_script]
==== Value Script

View File

@ -187,7 +187,7 @@ a script to convert them on-the-fly:
script to generate values which percentiles are calculated on
<2> Scripting supports parameterized input just like any other script
This will interpret the `script` parameter as an `inline` script with the `painless` script language and no script parameters. To use a file script use the following syntax:
This will interpret the `script` parameter as an `inline` script with the `painless` script language and no script parameters. To use a stored script use the following syntax:
[source,js]
--------------------------------------------------
@ -196,7 +196,7 @@ This will interpret the `script` parameter as an `inline` script with the `painl
"load_time_outlier" : {
"percentiles" : {
"script" : {
"file": "my_script",
"stored": "my_script",
"params" : {
"timeUnit" : 1000
}
@ -207,8 +207,6 @@ This will interpret the `script` parameter as an `inline` script with the `painl
}
--------------------------------------------------
TIP: for indexed scripts replace the `file` parameter with an `id` parameter.
[[search-aggregations-metrics-percentile-aggregation-approximation]]
==== Percentiles are (usually) approximate

View File

@ -136,7 +136,7 @@ a script to convert them on-the-fly:
script to generate values which percentile ranks are calculated on
<2> Scripting supports parameterized input just like any other script
This will interpret the `script` parameter as an `inline` script with the `painless` script language and no script parameters. To use a file script use the following syntax:
This will interpret the `script` parameter as an `inline` script with the `painless` script language and no script parameters. To use a stored script use the following syntax:
[source,js]
--------------------------------------------------
@ -146,7 +146,7 @@ This will interpret the `script` parameter as an `inline` script with the `painl
"percentile_ranks" : {
"values" : [3, 5],
"script" : {
"file": "my_script",
"stored": "my_script",
"params" : {
"timeUnit" : 1000
}
@ -157,8 +157,6 @@ This will interpret the `script` parameter as an `inline` script with the `painl
}
--------------------------------------------------
TIP: for indexed scripts replace the `file` parameter with an `id` parameter.
==== HDR Histogram
experimental[]

View File

@ -50,7 +50,7 @@ The response for the above aggregation:
// TESTRESPONSE[s/"took": 218/"took": $body.took/]
// TESTRESPONSE[s/\.\.\./"_shards": $body._shards, "hits": $body.hits, "timed_out": false,/]
The above example can also be specified using file scripts as follows:
The above example can also be specified using stored scripts as follows:
[source,js]
--------------------------------------------------
@ -60,20 +60,20 @@ POST ledger/_search?size=0
"profit": {
"scripted_metric": {
"init_script" : {
"file": "my_init_script"
"stored": "my_init_script"
},
"map_script" : {
"file": "my_map_script"
"stored": "my_map_script"
},
"combine_script" : {
"file": "my_combine_script"
"stored": "my_combine_script"
},
"params": {
"field": "amount", <1>
"_agg": {} <2>
},
"reduce_script" : {
"file": "my_reduce_script"
"stored": "my_reduce_script"
}
}
}
@ -81,7 +81,7 @@ POST ledger/_search?size=0
}
--------------------------------------------------
// CONSOLE
// TEST[setup:ledger]
// TEST[setup:ledger,stored_scripted_metric_script]
<1> script parameters for `init`, `map` and `combine` scripts must be specified
in a global `params` object so that it can be share between the scripts.

View File

@ -65,7 +65,7 @@ POST /exams/_search?size=0
// CONSOLE
// TEST[setup:exams]
This will interpret the `script` parameter as an `inline` script with the `painless` script language and no script parameters. To use a file script use the following syntax:
This will interpret the `script` parameter as an `inline` script with the `painless` script language and no script parameters. To use a stored script use the following syntax:
[source,js]
--------------------------------------------------
@ -75,7 +75,7 @@ POST /exams/_search?size=0
"grades_stats" : {
"stats" : {
"script" : {
"file": "my_script",
"stored": "my_script",
"params" : {
"field" : "grade"
}
@ -86,9 +86,7 @@ POST /exams/_search?size=0
}
--------------------------------------------------
// CONSOLE
// TEST[setup:exams]
TIP: for indexed scripts replace the `file` parameter with an `id` parameter.
// TEST[setup:exams,stored_example_script]
===== Value Script

View File

@ -71,7 +71,7 @@ POST /sales/_search?size=0
// CONSOLE
// TEST[setup:sales]
This will interpret the `script` parameter as an `inline` script with the `painless` script language and no script parameters. To use a file script use the following syntax:
This will interpret the `script` parameter as an `inline` script with the `painless` script language and no script parameters. To use a stored script use the following syntax:
[source,js]
--------------------------------------------------
@ -88,7 +88,7 @@ POST /sales/_search?size=0
"hat_prices" : {
"sum" : {
"script" : {
"file": "my_script",
"stored": "my_script",
"params" : {
"field" : "price"
}
@ -99,9 +99,7 @@ POST /sales/_search?size=0
}
--------------------------------------------------
// CONSOLE
// TEST[setup:sales]
TIP: for indexed scripts replace the `file` parameter with an `id` parameter.
// TEST[setup:sales,stored_example_script]
===== Value Script

View File

@ -58,7 +58,7 @@ POST /sales/_search?size=0
// CONSOLE
// TEST[setup:sales]
This will interpret the `script` parameter as an `inline` script with the `painless` script language and no script parameters. To use a file script use the following syntax:
This will interpret the `script` parameter as an `inline` script with the `painless` script language and no script parameters. To use a stored script use the following syntax:
[source,js]
--------------------------------------------------
@ -68,7 +68,7 @@ POST /sales/_search?size=0
"types_count" : {
"value_count" : {
"script" : {
"file": "my_script",
"stored": "my_script",
"params" : {
"field" : "type"
}
@ -79,6 +79,4 @@ POST /sales/_search?size=0
}
--------------------------------------------------
// CONSOLE
// TEST[setup:sales]
TIP: for indexed scripts replace the `file` parameter with an `id` parameter.
// TEST[setup:sales,stored_example_script]

View File

@ -1698,7 +1698,7 @@ Renames an existing field. If the field doesn't exist or the new name is already
[[script-processor]]
=== Script Processor
Allows inline, stored, and file scripts to be executed within ingest pipelines.
Allows inline and stored scripts to be executed within ingest pipelines.
See <<modules-scripting-using, How to use scripts>> to learn more about writing scripts. The Script Processor
leverages caching of compiled scripts for improved performance. Since the
@ -1712,13 +1712,12 @@ caching see <<modules-scripting-using-caching, Script Caching>>.
|======
| Name | Required | Default | Description
| `lang` | no | "painless" | The scripting language
| `file` | no | - | The script file to refer to
| `id` | no | - | The stored script id to refer to
| `inline` | no | - | An inline script to be executed
| `params` | no | - | Script Parameters
|======
One of `file`, `id`, `inline` options must be provided in order to properly reference a script to execute.
One of `id` or `inline` options must be provided in order to properly reference a script to execute.
You can access the current ingest document from within the script context by using the `ctx` variable.

View File

@ -6,6 +6,11 @@
The Groovy, JavaScript, and Python scripting languages were deprecated in
elasticsearch 5.0 and have now been removed. Use painless instead.
==== Native scripts removed
Native scripts have been removed. Instead,
<<modules-scripting-engine, implement a `ScriptEngine`>>.
==== Date fields now return dates
`doc.some_date_field.value` now returns ++ReadableDateTime++s instead of

View File

@ -144,12 +144,9 @@ or disabled based on where they are stored. For example:
-----------------------------------
script.inline: false <1>
script.stored: false <2>
script.file: true <3>
-----------------------------------
<1> Refuse to run scripts provided inline in the API.
<2> Refuse to run scripts stored using the API.
<3> Run scripts found on the filesystem in `/etc/elasticsearch/scripts`
(rpm or deb) or `config/scripts` (zip or tar).
NOTE: These settings override the defaults mentioned
<<modules-scripting-security-do-no-weaken, above>>. Recreating the defaults
@ -194,14 +191,14 @@ settings. They have two forms:
[source,yaml]
------------------------
script.engine.{lang}.{inline|file|stored}.{context}: true|false
script.engine.{lang}.{inline|stored}.{context}: true|false
------------------------
And
[source,yaml]
------------------------
script.engine.{lang}.{inline|file|stored}: true|false
script.engine.{lang}.{inline|stored}: true|false
------------------------
For example:
@ -210,7 +207,6 @@ For example:
-----------------------------------
script.inline: false <1>
script.stored: false <1>
script.file: false <1>
script.engine.painless.inline: true <2>
script.engine.painless.stored.search: true <3>

View File

@ -8,13 +8,13 @@ the same pattern:
-------------------------------------
"script": {
"lang": "...", <1>
"inline" | "stored" | "file": "...", <2>
"inline" | "stored": "...", <2>
"params": { ... } <3>
}
-------------------------------------
// NOTCONSOLE
<1> The language the script is written in, which defaults to `painless`.
<2> The script itself which may be specified as `inline`, `stored`, or `file`.
<2> The script itself which may be specified as `inline` or `stored`.
<3> Any named parameters that should be passed into the script.
For example, the following script is used in a search request to return a
@ -55,18 +55,12 @@ GET my_index/_search
setting `script.default_lang` to the appropriate language.
`inline`, `stored`, `file`::
`inline`, `stored`::
Specifies the source of the script. An `inline` script is specified
`inline` as in the example above, a `stored` script is specified `stored`
and is retrieved from the cluster state (see <<modules-scripting-stored-scripts,Stored Scripts>>),
and a `file` script is retrieved from a file in the `config/scripts`
directory (see <<modules-scripting-file-scripts, File Scripts>>).
+
While languages like `expression` and `painless` can be used out of the box as
inline or stored scripts, other languages can only be
specified as `file` unless you first adjust the default
<<modules-scripting-security,scripting security settings>>.
`inline` as in the example above. A `stored` script is specified `stored`
and is retrieved from the cluster state (see <<modules-scripting-stored-scripts,Stored Scripts>>).
`params`::
@ -114,72 +108,6 @@ minute will be compiled. You can change this setting dynamically by setting
========================================
[float]
[[modules-scripting-file-scripts]]
=== File-based Scripts
To increase security, non-sandboxed languages can only be specified in script
files stored on every node in the cluster. File scripts must be saved in the
`scripts` directory whose default location depends on whether you use the
<<zip-targz-layout,`zip`/`tar.gz`>> (`$ES_HOME/config/scripts/`),
<<rpm-layout,RPM>>, or <<deb-layout,Debian>> package. The default may be
changed with the `path.scripts` setting.
The languages which are assumed to be safe by default are: `painless`,
`expression`, and `mustache` (used for search and query templates).
Any files placed in the `scripts` directory will be compiled automatically
when the node starts up and then <<reload-scripts,every 60 seconds thereafter>>.
The file should be named as follows: `{script-name}.{lang}`. For instance,
the following example creates a Groovy script called `calculate-score`:
[source,sh]
--------------------------------------------------
cat "Math.log(_score * 2) + params.my_modifier" > config/scripts/calculate_score.painless
--------------------------------------------------
This script can be used as follows:
[source,js]
--------------------------------------------------
GET my_index/_search
{
"query": {
"script": {
"script": {
"lang": "painless", <1>
"file": "calculate_score", <2>
"params": {
"my_modifier": 2
}
}
}
}
}
--------------------------------------------------
// CONSOLE
// TEST[continued]
<1> The language of the script, which should correspond with the script file suffix.
<2> The name of the script, which should be the name of the file.
The `script` directory may contain sub-directories, in which case the
hierarchy of directories is flattened and concatenated with underscores. A
script in `group1/group2/my_script.painless` should use `group1_group2_myscript`
as the `file` name.
[[reload-scripts]]
[float]
==== Automatic script reloading
The `scripts` directory will be rescanned every `60s` (configurable with the
`resource.reload.interval` setting) and new, changed, or removed scripts will
be compiled, updated, or deleted from the script cache.
Script reloading can be completely disabled by setting
`script.auto_reload_enabled` to `false`.
[float]
[[modules-scripting-stored-scripts]]
=== Stored Scripts

View File

@ -90,7 +90,6 @@ configuration options are passed down from the tribe node to each node client:
* `path.home`
* `path.conf`
* `path.logs`
* `path.scripts`
* `shield.*`
Almost any setting (except for `path.*`) may be configured at the node client
@ -109,16 +108,14 @@ include:
[source,yaml]
------------------------
path.scripts: some/path/to/config <1>
network.host: 192.168.1.5 <2>
network.host: 192.168.1.5 <1>
tribe:
t1:
cluster.name: cluster_one
t2:
cluster.name: cluster_two
network.host: 10.1.2.3 <3>
network.host: 10.1.2.3 <2>
------------------------
<1> The `path.scripts` setting is inherited by both `t1` and `t2`.
<2> The `network.host` setting is inherited by `t1`.
<3> The `t3` node client overrides the inherited from the tribe node.
<1> The `network.host` setting is inherited by `t1`.
<2> The `t3` node client overrides the inherited from the tribe node.

View File

@ -402,27 +402,8 @@ The previous query will be rendered as:
[[pre-registered-templates]]
===== Pre-registered template
You can register search templates by storing it in the `config/scripts` directory, in a file using the `.mustache` extension.
In order to execute the stored template, reference it by it's name under the `template` key:
[source,js]
------------------------------------------
GET _search/template
{
"file": "storedTemplate", <1>
"params": {
"query_string": "search for these words"
}
}
------------------------------------------
// CONSOLE
// TEST[catch:request]
<1> Name of the query template in `config/scripts/`, i.e., `storedTemplate.mustache`.
You can also register search templates by storing it in the cluster state.
There are REST APIs to manage these indexed templates.
You can register search templates by storing them in the cluster state.
There are REST APIs to manage these stored templates.
[source,js]
------------------------------------------
@ -501,7 +482,7 @@ because we'll use it later.
//////////////////////////
To use an indexed template at search time use:
To use a stored template at search time use:
[source,js]
------------------------------------------
@ -515,7 +496,7 @@ GET _search/template
------------------------------------------
// CONSOLE
// TEST[catch:missing]
<1> Name of the query template stored in the `.scripts` index.
<1> Name of the stored template script.
[float]
==== Validating templates
@ -556,22 +537,6 @@ This call will return the rendered template:
// TESTRESPONSE
<1> `status` array has been populated with values from the `params` object.
File and indexed templates can also be rendered by replacing `inline` with
`file` or `id` respectively. For example, to render a file template
[source,js]
------------------------------------------
GET _render/template
{
"file": "my_template",
"params": {
"status": [ "pending", "published" ]
}
}
------------------------------------------
// CONSOLE
// TEST[catch:request]
Pre-registered templates can also be rendered using
[source,js]
@ -594,7 +559,7 @@ You can use `explain` parameter when running a template:
------------------------------------------
GET _search/template
{
"file": "my_template",
"id": "my_template",
"params": {
"status": [ "pending", "published" ]
},
@ -602,7 +567,7 @@ GET _search/template
}
------------------------------------------
// CONSOLE
// TEST[catch:request]
// TEST[catch:missing]
[float]
===== Profiling
@ -613,7 +578,7 @@ You can use `profile` parameter when running a template:
------------------------------------------
GET _search/template
{
"file": "my_template",
"id": "my_template",
"params": {
"status": [ "pending", "published" ]
},
@ -621,7 +586,7 @@ GET _search/template
}
------------------------------------------
// CONSOLE
// TEST[catch:request]
// TEST[catch:missing]
[[multi-search-template]]
== Multi Search Template
@ -656,8 +621,6 @@ $ cat requests
{"inline": {"query": {"{{query_type}}": {"name": "{{name}}" }}}, "params": {"query_type": "match_phrase_prefix", "name": "Smith"}}
{"index": "_all"}
{"id": "template_1", "params": {"query_string": "search for these words" }} <2>
{"types": "users"}
{"file": "template_2", "params": {"field_name": "fullname", "field_value": "john smith" }} <3>
$ curl -H "Content-Type: application/x-ndjson" -XGET localhost:9200/_msearch/template --data-binary "@requests"; echo
--------------------------------------------------
@ -667,8 +630,6 @@ $ curl -H "Content-Type: application/x-ndjson" -XGET localhost:9200/_msearch/tem
<2> Search template request based on a stored template
<3> Search template request based on a file template
The response returns a `responses` array, which includes the search template
response for each search template request matching its order in the original
multi search template request. If there was a complete failure for that specific

View File

@ -225,11 +225,6 @@ locations for a Debian-based system:
d| Not configured
| path.repo
| script
| Location of script files.
| /etc/elasticsearch/scripts
| path.scripts
|=======================================================================
include::next-steps.asciidoc[]

View File

@ -213,11 +213,6 @@ locations for an RPM-based system:
d| Not configured
| path.repo
| script
| Location of script files.
| /etc/elasticsearch/scripts
| path.scripts
|=======================================================================
include::next-steps.asciidoc[]

View File

@ -255,11 +255,6 @@ directory so that you do not delete important data later on.
d| Not configured
| path.repo
| script
| Location of script files.
| %ES_HOME%\scripts
| path.scripts
|=======================================================================
include::next-steps.asciidoc[]

View File

@ -187,11 +187,6 @@ directory so that you do not delete important data later on.
d| Not configured
| path.repo
| script
| Location of script files.
| $ES_HOME/scripts
| path.scripts
|=======================================================================

View File

@ -37,7 +37,6 @@ import static org.elasticsearch.common.Strings.hasLength;
import static org.elasticsearch.ingest.ConfigurationUtils.newConfigurationException;
import static org.elasticsearch.ingest.ConfigurationUtils.readOptionalMap;
import static org.elasticsearch.ingest.ConfigurationUtils.readOptionalStringProperty;
import static org.elasticsearch.script.ScriptType.FILE;
import static org.elasticsearch.script.ScriptType.INLINE;
import static org.elasticsearch.script.ScriptType.STORED;
@ -100,19 +99,17 @@ public final class ScriptProcessor extends AbstractProcessor {
Map<String, Object> config) throws Exception {
String lang = readOptionalStringProperty(TYPE, processorTag, config, "lang");
String inline = readOptionalStringProperty(TYPE, processorTag, config, "inline");
String file = readOptionalStringProperty(TYPE, processorTag, config, "file");
String id = readOptionalStringProperty(TYPE, processorTag, config, "id");
Map<String, ?> params = readOptionalMap(TYPE, processorTag, config, "params");
boolean containsNoScript = !hasLength(file) && !hasLength(id) && !hasLength(inline);
boolean containsNoScript = !hasLength(id) && !hasLength(inline);
if (containsNoScript) {
throw newConfigurationException(TYPE, processorTag, null, "Need [file], [id], or [inline] parameter to refer to scripts");
throw newConfigurationException(TYPE, processorTag, null, "Need [id] or [inline] parameter to refer to scripts");
}
boolean moreThanOneConfigured = (Strings.hasLength(file) && Strings.hasLength(id)) ||
(Strings.hasLength(file) && Strings.hasLength(inline)) || (Strings.hasLength(id) && Strings.hasLength(inline));
boolean moreThanOneConfigured = Strings.hasLength(id) && Strings.hasLength(inline);
if (moreThanOneConfigured) {
throw newConfigurationException(TYPE, processorTag, null, "Only one of [file], [id], or [inline] may be configured");
throw newConfigurationException(TYPE, processorTag, null, "Only one of [id] or [inline] may be configured");
}
if (lang == null) {
@ -125,10 +122,7 @@ public final class ScriptProcessor extends AbstractProcessor {
final Script script;
String scriptPropertyUsed;
if (Strings.hasLength(file)) {
script = new Script(FILE, lang, file, (Map<String, Object>)params);
scriptPropertyUsed = "file";
} else if (Strings.hasLength(inline)) {
if (Strings.hasLength(inline)) {
script = new Script(INLINE, lang, inline, (Map<String, Object>)params);
scriptPropertyUsed = "inline";
} else if (Strings.hasLength(id)) {

View File

@ -44,7 +44,6 @@ public class ScriptProcessorFactoryTests extends ESTestCase {
Map<String, String> map = new HashMap<>();
map.put("id", "stored");
map.put("inline", "inline");
map.put("file", "file");
ingestScriptParamToType = Collections.unmodifiableMap(map);
}
@ -55,7 +54,7 @@ public class ScriptProcessorFactoryTests extends ESTestCase {
public void testFactoryValidationWithDefaultLang() throws Exception {
Map<String, Object> configMap = new HashMap<>();
String randomType = randomFrom("id", "inline", "file");
String randomType = randomFrom("id", "inline");
configMap.put(randomType, "foo");
ScriptProcessor processor = factory.create(null, randomAlphaOfLength(10), configMap);
assertThat(processor.getScript().getLang(), equalTo(Script.DEFAULT_SCRIPT_LANG));
@ -65,7 +64,7 @@ public class ScriptProcessorFactoryTests extends ESTestCase {
public void testFactoryValidationWithParams() throws Exception {
Map<String, Object> configMap = new HashMap<>();
String randomType = randomFrom("id", "inline", "file");
String randomType = randomFrom("id", "inline");
Map<String, Object> randomParams = Collections.singletonMap(randomAlphaOfLength(10), randomAlphaOfLength(10));
configMap.put(randomType, "foo");
configMap.put("params", randomParams);
@ -77,19 +76,13 @@ public class ScriptProcessorFactoryTests extends ESTestCase {
public void testFactoryValidationForMultipleScriptingTypes() throws Exception {
Map<String, Object> configMap = new HashMap<>();
String randomType = randomFrom("id", "inline", "file");
String otherRandomType = randomFrom("id", "inline", "file");
while (randomType.equals(otherRandomType)) {
otherRandomType = randomFrom("id", "inline", "file");
}
configMap.put(randomType, "foo");
configMap.put(otherRandomType, "bar");
configMap.put("id", "foo");
configMap.put("inline", "bar");
configMap.put("lang", "mockscript");
ElasticsearchException exception = expectThrows(ElasticsearchException.class,
() -> factory.create(null, randomAlphaOfLength(10), configMap));
assertThat(exception.getMessage(), is("Only one of [file], [id], or [inline] may be configured"));
assertThat(exception.getMessage(), is("Only one of [id] or [inline] may be configured"));
}
public void testFactoryValidationAtLeastOneScriptingType() throws Exception {
@ -99,11 +92,11 @@ public class ScriptProcessorFactoryTests extends ESTestCase {
ElasticsearchException exception = expectThrows(ElasticsearchException.class,
() -> factory.create(null, randomAlphaOfLength(10), configMap));
assertThat(exception.getMessage(), is("Need [file], [id], or [inline] parameter to refer to scripts"));
assertThat(exception.getMessage(), is("Need [id] or [inline] parameter to refer to scripts"));
}
public void testFactoryInvalidateWithInvalidCompiledScript() throws Exception {
String randomType = randomFrom("inline", "file", "id");
String randomType = randomFrom("inline", "id");
ScriptService mockedScriptService = mock(ScriptService.class);
ScriptException thrownException = new ScriptException("compile-time exception", new RuntimeException(),
Collections.emptyList(), "script", "mockscript");

View File

@ -69,11 +69,6 @@ public class ExpressionScriptEngine extends AbstractComponent implements ScriptE
return NAME;
}
@Override
public String getExtension() {
return NAME;
}
@Override
public Object compile(String scriptName, String scriptSource, Map<String, String> params) {
// classloader created here

View File

@ -31,5 +31,4 @@ integTestCluster {
setting 'script.inline', 'true'
setting 'script.stored', 'true'
setting 'script.max_compilations_per_minute', '1000'
setting 'path.scripts', "${project.buildDir}/resources/test/templates"
}

View File

@ -85,11 +85,6 @@ public final class MustacheScriptEngine implements ScriptEngine {
return NAME;
}
@Override
public String getExtension() {
return NAME;
}
@Override
public ExecutableScript executable(CompiledScript compiledScript,
@Nullable Map<String, Object> vars) {

View File

@ -53,10 +53,6 @@ public class RestSearchTemplateAction extends BaseRestHandler {
PARSER.declareField((parser, request, s) ->
request.setScriptParams(parser.map())
, new ParseField("params"), ObjectParser.ValueType.OBJECT);
PARSER.declareString((request, s) -> {
request.setScriptType(ScriptType.FILE);
request.setScript(s);
}, new ParseField("file"));
PARSER.declareString((request, s) -> {
request.setScriptType(ScriptType.STORED);
request.setScript(s);

View File

@ -101,26 +101,6 @@ public class SearchTemplateRequestTests extends ESTestCase {
assertThat((List<String>) request.getScriptParams().get("status"), hasItems("pending", "published"));
}
public void testParseFileTemplate() throws Exception {
String source = "{'file' : 'fileTemplate'}";
SearchTemplateRequest request = RestSearchTemplateAction.parse(newParser(source));
assertThat(request.getScript(), equalTo("fileTemplate"));
assertThat(request.getScriptType(), equalTo(ScriptType.FILE));
assertThat(request.getScriptParams(), nullValue());
}
public void testParseFileTemplateWithParams() throws Exception {
String source = "{'file' : 'template_foo', 'params' : {'foo': 'bar', 'size': 500}}";
SearchTemplateRequest request = RestSearchTemplateAction.parse(newParser(source));
assertThat(request.getScript(), equalTo("template_foo"));
assertThat(request.getScriptType(), equalTo(ScriptType.FILE));
assertThat(request.getScriptParams().size(), equalTo(2));
assertThat(request.getScriptParams(), hasEntry("foo", "bar"));
assertThat(request.getScriptParams(), hasEntry("size", 500));
}
public void testParseStoredTemplate() throws Exception {
String source = "{'id' : 'storedTemplate'}";

View File

@ -29,23 +29,6 @@
- match: { template_output.query.match.text: "bar" }
- match: { template_output.aggs.my_terms.terms.field: "field1" }
---
"File Template validate tests":
- do:
render_search_template:
body: { "file": "file_search_template", "params": { "my_value": "foo", "my_field": "field1" } }
- match: { template_output.query.match.text: "foo" }
- match: { template_output.aggs.my_terms.terms.field: "field1" }
- do:
render_search_template:
body: { "file": "file_search_template", "params": { "my_value": "bar", "my_field": "my_other_field" } }
- match: { template_output.query.match.text: "bar" }
- match: { template_output.aggs.my_terms.terms.field: "my_other_field" }
---
"Inline Template validate tests":
@ -148,9 +131,3 @@
search_template:
body: { "id" : "1", "params" : { "my_value" : "value1_foo", "my_size" : 1 } }
- match: { hits.total: 1 }
- do:
catch: /unable.to.find.file.script.\[simple1\].using.lang.\[mustache\]/
search_template:
body: { "file" : "simple1"}

View File

@ -22,12 +22,6 @@
- match: { hits.total: 1 }
- do:
search_template:
body: { "file" : "file_search_template", "params": { "my_value": "value1", "my_field" : "_type" } }
- match: { hits.total: 1 }
- do:
put_template:
id: "1"
@ -93,23 +87,29 @@
- do:
indices.refresh: {}
- do:
put_template:
id: "template_1"
body: { "template": { "query": { "match": { "{{field}}": { "query" : "{{value}}", "operator" : "{{operator}}{{^operator}}or{{/operator}}" } } }, "size": "{{size}}" } }
- match: { acknowledged: true }
- do:
search_template:
body: { "file" : "template_1", "params": { "size": "2", "field": "theField", "value": "foo" } }
body: { "id" : "template_1", "params": { "size": "2", "field": "theField", "value": "foo" } }
- match: { hits.total: 4 }
- length: { hits.hits: 2 }
- do:
search_template:
body: { "file" : "template_1", "params": { "size": "2", "field": "otherField", "value": "foo" } }
body: { "id" : "template_1", "params": { "size": "2", "field": "otherField", "value": "foo" } }
- match: { hits.total: 1 }
- length: { hits.hits: 1 }
- do:
search_template:
body: { "file" : "template_1", "params": { "size": "2", "field": "otherField", "value": "foo" }, "explain" : true }
body: { "id" : "template_1", "params": { "size": "2", "field": "otherField", "value": "foo" }, "explain" : true }
- match: { hits.total: 1 }
- length: { hits.hits: 1 }
@ -117,7 +117,7 @@
- do:
search_template:
body: { "file" : "template_1", "params": { "size": "2", "field": "otherField", "value": "foo" }, "profile" : true }
body: { "id" : "template_1", "params": { "size": "2", "field": "otherField", "value": "foo" }, "profile" : true }
- match: { hits.total: 1 }
- length: { hits.hits: 1 }

View File

@ -157,41 +157,3 @@ setup:
- match: { responses.1.hits.total: 1 }
- match: { responses.2.hits.total: 1 }
---
"Basic multi-search using file template":
- do:
render_search_template:
body: { "file": "template_1", "params": { "field": "foo", "value": "bar", "size": 20 } }
- match: { template_output.query.match.foo.query: "bar" }
- match: { template_output.query.match.foo.operator: "or" }
- match: { template_output.size: 20 }
- do:
msearch_template:
body:
- index: index_*
- file: template_1
params:
field: "foo"
value: "foo"
size: 10
- index: _all
- file: template_1
params:
field: "foo"
value: "bar"
operator: "and"
size: 50
- index: index_2
- file: template_1
params:
field: "foo"
value: "foo"
size: 0
- match: { responses.0.hits.total: 2 }
- match: { responses.1.hits.total: 1 }
- match: { responses.2.hits.total: 1 }

Some files were not shown because too many files have changed in this diff Show More