Scripting: add support for fine-grained settings

Allow to on/off scripting based on their source (where they get loaded from), the  operation that executes them and their language.

The settings cover the following combinations:

- mode: on, off, sandbox
- source: indexed, dynamic, file
- engine: groovy, expressions, mustache, etc
- operation: update, search, aggs, mapping

The following settings are supported for every engine:

script.engine.groovy.indexed.update:    sandbox/on/off
script.engine.groovy.indexed.search:    sandbox/on/off
script.engine.groovy.indexed.aggs:      sandbox/on/off
script.engine.groovy.indexed.mapping:   sandbox/on/off
script.engine.groovy.dynamic.update:    sandbox/on/off
script.engine.groovy.dynamic.search:    sandbox/on/off
script.engine.groovy.dynamic.aggs:      sandbox/on/off
script.engine.groovy.dynamic.mapping:   sandbox/on/off
script.engine.groovy.file.update:       sandbox/on/off
script.engine.groovy.file.search:       sandbox/on/off
script.engine.groovy.file.aggs:         sandbox/on/off
script.engine.groovy.file.mapping:      sandbox/on/off

For ease of use, the following more generic settings are supported too:

script.indexed: sandbox/on/off
script.dynamic: sandbox/on/off
script.file:    sandbox/on/off

script.update:  sandbox/on/off
script.search:  sandbox/on/off
script.aggs:    sandbox/on/off
script.mapping: sandbox/on/off

These will be used to calculate the more specific settings, using the stricter setting of each combination. Operation based settings have precedence over conflicting source based ones.

Note that the `mustache` engine is affected by generic settings applied to any language, while native scripts aren't as they are static by definition.

Also, the previous `script.disable_dynamic` setting can now be deprecated.

Closes #6418
Closes #10116
Closes #10274
This commit is contained in:
javanna 2015-03-06 18:38:11 +01:00 committed by Luca Cavanna
parent 442f539802
commit d9d1e6a67a
31 changed files with 1569 additions and 127 deletions

View File

@ -436,7 +436,7 @@ def smoke_test_release(release, files, expected_hash, plugins):
else:
background = '-d'
print(' Starting elasticsearch deamon from [%s]' % os.path.join(tmp_dir, 'elasticsearch-%s' % release))
run('%s; %s -Des.node.name=smoke_tester -Des.cluster.name=prepare_release -Des.discovery.zen.ping.multicast.enabled=false -Des.script.disable_dynamic=false %s'
run('%s; %s -Des.node.name=smoke_tester -Des.cluster.name=prepare_release -Des.discovery.zen.ping.multicast.enabled=false -Des.script.inline=on -Des.script.indexed=on %s'
% (java_exe(), es_run_path, background))
conn = HTTPConnection('127.0.0.1', 9200, 20);
wait_for_node_startup()

View File

@ -135,7 +135,8 @@ def start_node(version, release_dir, data_dir, tcp_port, http_port):
'-Des.cluster.name=bwc_index_' + version,
'-Des.network.host=localhost',
'-Des.discovery.zen.ping.multicast.enabled=false',
'-Des.script.disable_dynamic=true',
'-Des.script.inline=on',
'-Des.script.indexed=on',
'-Des.transport.tcp.port=%s' % tcp_port,
'-Des.http.port=%s' % http_port
]

View File

@ -107,7 +107,8 @@ def start_node(version, data_dir, node_dir, unicast_host_list, tcp_port, http_po
'-Des.path.data=%s' % data_dir, '-Des.cluster.name=upgrade_test',
'-Des.discovery.zen.ping.unicast.hosts=%s' % unicast_host_list,
'-Des.discovery.zen.ping.multicast.enabled=false',
'-Des.script.disable_dynamic=true',
'-Des.script.inline=on',
'-Des.script.indexed=on',
'-Des.transport.tcp.port=%s' % tcp_port,
'-Des.http.port=%s' % http_port,
foreground], stdout=subprocess.PIPE, stderr=subprocess.PIPE)

View File

@ -146,9 +146,9 @@ named `group1_group2_test`.
[float]
=== Indexed Scripts
If dynamic scripting is enabled, Elasticsearch allows you to store scripts
in an internal index known as `.scripts` and reference them by id. There are
REST endpoints to manage indexed scripts as follows:
Elasticsearch allows you to store scripts in an internal index known as
`.scripts` and reference them by id. There are REST endpoints to manage
indexed scripts as follows:
Requests to the scripts endpoint look like :
[source,js]
@ -197,8 +197,6 @@ curl -XPOST localhost:9200/_search -d '{
}
}'
--------------------------------------------------
Note that you must have dynamic scripting enabled to use indexed scripts
at query time.
The script can be viewed by:
[source,js]
@ -224,43 +222,118 @@ curl -XDELETE localhost:9200/_scripts/groovy/indexedCalculateScore
[float]
[[enable-dynamic-scripting]]
=== Enabling dynamic scripting
We recommend running Elasticsearch behind an application or proxy, which
protects Elasticsearch from the outside world. If users are allowed to run
dynamic scripts (even in a search request), then they have the same access to
your box as the user that Elasticsearch is running as. For this reason dynamic
scripting is allowed only for sandboxed languages by default.
inline scripts (even in a search request) or indexed scripts, then they have
the same access to your box as the user that Elasticsearch is running as. For
this reason dynamic scripting is allowed only for sandboxed languages by default.
The script engines that currently support sandboxing are `mustache` and
`expressions`.
First, you should not run Elasticsearch as the `root` user, as this would allow
a script to access or do *anything* on your server, without limitations. Second,
you should not expose Elasticsearch directly to users, but instead have a proxy
application inbetween. If you *do* intend to expose Elasticsearch directly to
your users, then you have to decide whether you trust them enough to run scripts
on your box or not. If you do, you can enable dynamic scripting by adding the
following setting to the `config/elasticsearch.yml` file on every node:
on your box or not.
deprecated[1.6.0, the `script.disable_dynamic` setting is deprecated in favour of fine-grained settings described as follows]
coming[1.6.0, Fine-grained script settings replace the `script.disable_dynamic` setting]
It is possible to enable scripts based on their source, for
every script engine, through the following settings that need to be added to the
`config/elasticsearch.yml` file on every node.
[source,yaml]
-----------------------------------
script.disable_dynamic: false
script.inline: on
script.indexed: on
-----------------------------------
While this still allows execution of named scripts provided in the config, or
_native_ Java scripts registered through plugins, it also allows users to run
arbitrary scripts via the API. Instead of sending the name of the file as the
script, the body of the script can be sent instead.
script, the body of the script can be sent instead or retrieved from the
`.scripts` indexed if previously stored.
There are three possible configuration values for the `script.disable_dynamic`
setting, the default value is `sandbox`:
There are three possible configuration values for any of the fine-grained
script settings:
[cols="<,<",options="header",]
|=======================================================================
|Value |Description
| `true` |all dynamic scripting is disabled, scripts must be placed in the `config/scripts` directory.
| `false` |all dynamic scripting is enabled, scripts may be sent as strings in requests.
| `sandbox` |scripts may be sent as strings for languages that are sandboxed.
| `off` |scripting is turned off completely, in the context of the setting being set.
| `on` |scripting is turned on, in the context of the setting being set.
| `sandbox` |scripts may be executed only for languages that are sandboxed (`mustache` and `expressions`)
|=======================================================================
The default values are the following:
[source,yaml]
-----------------------------------
script.inline: sandbox
script.indexed: sandbox
script.file: on
-----------------------------------
NOTE: Global scripting settings affect the `mustache` scripting language.
<<search-template,Search templates>> internally use the `mustache` language,
and will still be enabled by default as the `mustache` engine is sandboxed,
but they will be enabled/disabled according to fine-grained settings
specified in `elasticsearch.yml`. coming[1.6.0, `mustache` scripts were previously always on regardless of whether dynamic scripts were enabled or not]
It is also possible to control which operations can execute scripts. The
supported operations are:
[cols="<,<",options="header",]
|=======================================================================
|Value |Description
| `aggs` |Aggregations (wherever they may be used)
| `mapping` |Mappings (script transform feature)
| `search` |Search api, Percolator api and Suggester api (e.g filters, script_fields)
| `update` |Update api
|=======================================================================
The following example disables scripting for `update` and `mapping` operations,
regardless of the script source, for any engine. Scripts can still be
executed from sandboxed languages as part of `aggregations` and `search`
operations though, as the above defaults still get applied.
[source,yaml]
-----------------------------------
script.update: off
script.mapping: off
-----------------------------------
Generic settings get applied in order, operation based ones have precedence
over source based ones. Language specific settings are supported too. They
need to be prefixed with the `script.engine.<engine>` prefix and have
precedence over any other generic settings.
[source,yaml]
-----------------------------------
script.engine.groovy.file.aggs: on
script.engine.groovy.file.mapping: on
script.engine.groovy.file.search: on
script.engine.groovy.file.update: on
script.engine.groovy.indexed.aggs: on
script.engine.groovy.indexed.mapping: off
script.engine.groovy.indexed.search: on
script.engine.groovy.indexed.update: off
script.engine.groovy.inline.aggs: on
script.engine.groovy.inline.mapping: off
script.engine.groovy.inline.search: off
script.engine.groovy.inline.update: off
-----------------------------------
[float]
=== Default Scripting Language

View File

@ -25,6 +25,11 @@ For more information on how Mustache templating and what kind of templating you
can do with it check out the http://mustache.github.io/mustache.5.html[online
documentation of the mustache project].
NOTE: The mustache language is implemented in elasticsearch as a sandboxed
scripting language, hence it obeys settings that may be used to enable or
disable scripts per language, source and operation as described in
<<enable-dynamic-scripting, scripting docs>> coming[1.6.0, `mustache` scripts were always on before and it wasn't possible to disable them].
[float]
==== More template examples
@ -296,4 +301,4 @@ GET /_search/template
}
}
------------------------------------------
<1> Name of the the query template stored in the .scripts index.
<1> Name of the the query template stored in the `.scripts` index.

View File

@ -46,6 +46,7 @@ import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.index.shard.IndexShard;
import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptContext;
import org.elasticsearch.search.fetch.source.FetchSourceContext;
import org.elasticsearch.search.lookup.SourceLookup;
@ -93,7 +94,7 @@ public class UpdateHelper extends AbstractComponent {
ctx.put("op", "create");
ctx.put("_source", upsertDoc);
try {
ExecutableScript script = scriptService.executable(request.scriptLang, request.script, request.scriptType, request.scriptParams);
ExecutableScript script = scriptService.executable(request.scriptLang, request.script, request.scriptType, ScriptContext.UPDATE, request.scriptParams);
script.setNextVar("ctx", ctx);
script.run();
// we need to unwrap the ctx...
@ -191,7 +192,7 @@ public class UpdateHelper extends AbstractComponent {
ctx.put("_source", sourceAndContent.v2());
try {
ExecutableScript script = scriptService.executable(request.scriptLang, request.script, request.scriptType, request.scriptParams);
ExecutableScript script = scriptService.executable(request.scriptLang, request.script, request.scriptType, ScriptContext.UPDATE, request.scriptParams);
script.setNextVar("ctx", ctx);
script.run();
// we need to unwrap the ctx...

View File

@ -65,7 +65,7 @@ import org.elasticsearch.index.mapper.object.ObjectMapper;
import org.elasticsearch.index.mapper.object.RootObjectMapper;
import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptService.ScriptType;
import org.elasticsearch.script.ScriptContext;
import java.io.IOException;
import java.util.ArrayList;
@ -79,6 +79,7 @@ import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import static com.google.common.collect.Lists.newArrayList;
import static org.elasticsearch.script.ScriptService.*;
/**
*
@ -759,7 +760,7 @@ public class DocumentMapper implements ToXContent {
public Map<String, Object> transformSourceAsMap(Map<String, Object> sourceAsMap) {
try {
// We use the ctx variable and the _source name to be consistent with the update api.
ExecutableScript executable = scriptService.executable(language, script, scriptType, parameters);
ExecutableScript executable = scriptService.executable(language, script, scriptType, ScriptContext.MAPPING, parameters);
Map<String, Object> ctx = new HashMap<>(1);
ctx.put("_source", sourceAsMap);
executable.setNextVar("ctx", ctx);

View File

@ -32,6 +32,7 @@ import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.lucene.HashedBytesRef;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.script.ScriptParameterParser;
import org.elasticsearch.script.*;
import org.elasticsearch.script.ScriptParameterParser.ScriptParameterValue;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.SearchScript;
@ -133,7 +134,7 @@ public class ScriptFilterParser implements FilterParser {
public ScriptFilter(String scriptLang, String script, ScriptService.ScriptType scriptType, Map<String, Object> params, ScriptService scriptService, SearchLookup searchLookup) {
this.script = script;
this.params = params;
this.searchScript = scriptService.search(searchLookup, scriptLang, script, scriptType, newHashMap(params));
this.searchScript = scriptService.search(searchLookup, scriptLang, script, scriptType, ScriptContext.SEARCH, newHashMap(params));
}
@Override

View File

@ -27,6 +27,7 @@ import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptContext;
import org.elasticsearch.script.mustache.MustacheScriptEngineService;
import java.io.IOException;
@ -76,7 +77,7 @@ public class TemplateQueryParser implements QueryParser {
public Query parse(QueryParseContext parseContext) throws IOException {
XContentParser parser = parseContext.parser();
TemplateContext templateContext = parse(parser, PARAMS, parametersToTypes);
ExecutableScript executable = this.scriptService.executable(MustacheScriptEngineService.NAME, templateContext.template(), templateContext.scriptType(), templateContext.params());
ExecutableScript executable = this.scriptService.executable(MustacheScriptEngineService.NAME, templateContext.template(), templateContext.scriptType(), ScriptContext.SEARCH, templateContext.params());
BytesReference querySource = (BytesReference) executable.run();

View File

@ -28,7 +28,7 @@ import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.index.query.QueryParsingException;
import org.elasticsearch.index.query.functionscore.ScoreFunctionParser;
import org.elasticsearch.script.ScriptParameterParser;
import org.elasticsearch.script.*;
import org.elasticsearch.script.ScriptParameterParser.ScriptParameterValue;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.SearchScript;
@ -87,7 +87,7 @@ public class ScriptScoreFunctionParser implements ScoreFunctionParser {
SearchScript searchScript;
try {
searchScript = parseContext.scriptService().search(parseContext.lookup(), scriptParameterParser.lang(), script, scriptType, vars);
searchScript = parseContext.scriptService().search(parseContext.lookup(), scriptParameterParser.lang(), script, scriptType, ScriptContext.SEARCH, vars);
return new ScriptScoreFunction(script, vars, searchScript);
} catch (Exception e) {
throw new QueryParsingException(parseContext.index(), NAMES[0] + " the script could not be loaded", e);

View File

@ -0,0 +1,38 @@
/*
* 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.util.Locale;
/**
* Operation/api that uses a script as part of its execution.
* Note that the suggest api is considered part of search for simplicity, as well as the percolate api.
*/
public enum ScriptContext {
MAPPING,
UPDATE,
SEARCH,
AGGS;
@Override
public String toString() {
return name().toLowerCase(Locale.ROOT);
}
}

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.script;
import org.elasticsearch.ElasticsearchIllegalArgumentException;
import org.elasticsearch.common.Booleans;
import java.util.Locale;
/**
* Mode for a specific script, used for script settings.
* Defines whether a certain script or catefory of scripts can be executed or not, or whether it can
* only be executed by a sandboxed scripting language.
*/
enum ScriptMode {
ON,
OFF,
SANDBOX;
static ScriptMode parse(String input) {
input = input.toLowerCase(Locale.ROOT);
if (Booleans.isExplicitTrue(input)) {
return ON;
}
if (Booleans.isExplicitFalse(input)) {
return OFF;
}
if (SANDBOX.toString().equals(input)) {
return SANDBOX;
}
throw new ElasticsearchIllegalArgumentException("script mode [" + input + "] not supported");
}
@Override
public String toString() {
return name().toLowerCase(Locale.ROOT);
}
}

View File

@ -0,0 +1,209 @@
/*
* 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 com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.elasticsearch.ElasticsearchIllegalArgumentException;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.script.ScriptService.ScriptType;
import java.util.*;
/**
* Holds the {@link org.elasticsearch.script.ScriptMode}s for each of the different scripting languages available,
* each script source and each scripted operation.
*/
public class ScriptModes {
static final String SCRIPT_SETTINGS_PREFIX = "script.";
static final String ENGINE_SETTINGS_PREFIX = "script.engine";
final ImmutableMap<String, ScriptMode> scriptModes;
ScriptModes(Map<String, ScriptEngineService> scriptEngines, Settings settings, ESLogger logger) {
//filter out the native engine as we don't want to apply fine grained settings to it.
//native scripts are always on as they are static by definition.
Map<String, ScriptEngineService> filteredEngines = Maps.newHashMap(scriptEngines);
filteredEngines.remove(NativeScriptEngineService.NAME);
this.scriptModes = buildScriptModeSettingsMap(settings, filteredEngines, logger);
}
private ImmutableMap<String, ScriptMode> buildScriptModeSettingsMap(Settings settings, Map<String, ScriptEngineService> scriptEngines, ESLogger logger) {
HashMap<String, ScriptMode> scriptModesMap = Maps.newHashMap();
//file scripts are enabled by default, for any language
addGlobalScriptTypeModes(scriptEngines.keySet(), ScriptType.FILE, ScriptMode.ON, scriptModesMap);
//indexed scripts are enabled by default only for sandboxed languages
addGlobalScriptTypeModes(scriptEngines.keySet(), ScriptType.INDEXED, ScriptMode.SANDBOX, scriptModesMap);
//dynamic scripts are enabled by default only for sandboxed languages
addGlobalScriptTypeModes(scriptEngines.keySet(), ScriptType.INLINE, ScriptMode.SANDBOX, scriptModesMap);
List<String> processedSettings = Lists.newArrayList();
processSourceBasedGlobalSettings(settings, scriptEngines, processedSettings, scriptModesMap);
processOperationBasedGlobalSettings(settings, scriptEngines, processedSettings, scriptModesMap);
processEngineSpecificSettings(settings, scriptEngines, processedSettings, scriptModesMap);
processDisableDynamicDeprecatedSetting(settings, scriptEngines, processedSettings, scriptModesMap, logger);
return ImmutableMap.copyOf(scriptModesMap);
}
private static void processSourceBasedGlobalSettings(Settings settings, Map<String, ScriptEngineService> scriptEngines, List<String> processedSettings, Map<String, ScriptMode> scriptModes) {
//read custom source based settings for all operations (e.g. script.indexed: on)
for (ScriptType scriptType : ScriptType.values()) {
String scriptTypeSetting = settings.get(SCRIPT_SETTINGS_PREFIX + scriptType);
if (Strings.hasLength(scriptTypeSetting)) {
ScriptMode scriptTypeMode = ScriptMode.parse(scriptTypeSetting);
processedSettings.add(SCRIPT_SETTINGS_PREFIX + scriptType + ": " + scriptTypeMode);
addGlobalScriptTypeModes(scriptEngines.keySet(), scriptType, scriptTypeMode, scriptModes);
}
}
}
private static void processOperationBasedGlobalSettings(Settings settings, Map<String, ScriptEngineService> scriptEngines, List<String> processedSettings, Map<String, ScriptMode> scriptModes) {
//read custom op based settings for all sources (e.g. script.aggs: off)
//op based settings take precedence over source based settings, hence they get expanded later
for (ScriptContext scriptContext : ScriptContext.values()) {
ScriptMode scriptMode = getScriptContextMode(settings, SCRIPT_SETTINGS_PREFIX, scriptContext);
if (scriptMode != null) {
processedSettings.add(SCRIPT_SETTINGS_PREFIX + scriptContext + ": " + scriptMode);
addGlobalScriptContextModes(scriptEngines.keySet(), scriptContext, scriptMode, scriptModes);
}
}
}
private static void processEngineSpecificSettings(Settings settings, Map<String, ScriptEngineService> scriptEngines, List<String> processedSettings, Map<String, ScriptMode> scriptModes) {
Map<String, Settings> langGroupedSettings = settings.getGroups(ENGINE_SETTINGS_PREFIX, true);
for (Map.Entry<String, Settings> langSettings : langGroupedSettings.entrySet()) {
//read engine specific settings that refer to a non existing script lang will be ignored
ScriptEngineService scriptEngineService = scriptEngines.get(langSettings.getKey());
if (scriptEngineService != null) {
String enginePrefix = ScriptModes.ENGINE_SETTINGS_PREFIX + "." + langSettings.getKey() + ".";
for (ScriptType scriptType : ScriptType.values()) {
String scriptTypePrefix = scriptType + ".";
for (ScriptContext scriptContext : ScriptContext.values()) {
ScriptMode scriptMode = getScriptContextMode(langSettings.getValue(), scriptTypePrefix, scriptContext);
if (scriptMode != null) {
processedSettings.add(enginePrefix + scriptTypePrefix + scriptContext + ": " + scriptMode);
addScriptMode(scriptEngineService, scriptType, scriptContext, scriptMode, scriptModes);
}
}
}
}
}
}
private void processDisableDynamicDeprecatedSetting(Settings settings, Map<String, ScriptEngineService> scriptEngines,
List<String> processedSettings, Map<String, ScriptMode> scriptModes, ESLogger logger) {
//read deprecated disable_dynamic setting, apply only if none of the new settings is used
String disableDynamicSetting = settings.get(ScriptService.DISABLE_DYNAMIC_SCRIPTING_SETTING);
if (disableDynamicSetting != null) {
if (processedSettings.isEmpty()) {
ScriptService.DynamicScriptDisabling dynamicScriptDisabling = ScriptService.DynamicScriptDisabling.parse(disableDynamicSetting);
switch(dynamicScriptDisabling) {
case EVERYTHING_ALLOWED:
addGlobalScriptTypeModes(scriptEngines.keySet(), ScriptType.INDEXED, ScriptMode.ON, scriptModes);
addGlobalScriptTypeModes(scriptEngines.keySet(), ScriptType.INLINE, ScriptMode.ON, scriptModes);
break;
case ONLY_DISK_ALLOWED:
addGlobalScriptTypeModes(scriptEngines.keySet(), ScriptType.INDEXED, ScriptMode.OFF, scriptModes);
addGlobalScriptTypeModes(scriptEngines.keySet(), ScriptType.INLINE, ScriptMode.OFF, scriptModes);
break;
}
logger.warn("deprecated setting [{}] is set, replace with fine-grained scripting settings (e.g. script.inline, script.indexed, script.file)", ScriptService.DISABLE_DYNAMIC_SCRIPTING_SETTING);
} else {
processedSettings.add(ScriptService.DISABLE_DYNAMIC_SCRIPTING_SETTING + ": " + disableDynamicSetting);
throw new ElasticsearchIllegalArgumentException("conflicting scripting settings have been specified, use either "
+ ScriptService.DISABLE_DYNAMIC_SCRIPTING_SETTING + " (deprecated) or the newer fine-grained settings (e.g. script.inline, script.indexed, script.file), not both at the same time:\n" + processedSettings);
}
}
}
private static ScriptMode getScriptContextMode(Settings settings, String prefix, ScriptContext scriptContext) {
String settingValue = settings.get(prefix + scriptContext);
if (Strings.hasLength(settingValue)) {
return ScriptMode.parse(settingValue);
}
return null;
}
private static void addGlobalScriptTypeModes(Set<String> langs, ScriptType scriptType, ScriptMode scriptMode, Map<String, ScriptMode> scriptModes) {
for (String lang : langs) {
for (ScriptContext scriptContext : ScriptContext.values()) {
addScriptMode(lang, scriptType, scriptContext, scriptMode, scriptModes);
}
}
}
private static void addGlobalScriptContextModes(Set<String> langs, ScriptContext scriptContext, ScriptMode scriptMode, Map<String, ScriptMode> scriptModes) {
for (String lang : langs) {
for (ScriptType scriptType : ScriptType.values()) {
addScriptMode(lang, scriptType, scriptContext, scriptMode, scriptModes);
}
}
}
private static void addScriptMode(ScriptEngineService scriptEngineService, ScriptType scriptType, ScriptContext scriptContext,
ScriptMode scriptMode, Map<String, ScriptMode> scriptModes) {
//expand the lang specific settings to all of the different names given to each scripting language
for (String scriptEngineName : scriptEngineService.types()) {
addScriptMode(scriptEngineName, scriptType, scriptContext, scriptMode, scriptModes);
}
}
private static void addScriptMode(String lang, ScriptType scriptType, ScriptContext scriptContext, ScriptMode scriptMode, Map<String, ScriptMode> scriptModes) {
scriptModes.put(ENGINE_SETTINGS_PREFIX + "." + lang + "." + scriptType + "." + scriptContext, scriptMode);
}
/**
* Returns the script mode for a script of a certain written in a certain language,
* of a certain type and executing as part of a specific operation/api.
*
* @param lang the language that the script is written in
* @param scriptType the type of the script
* @param scriptContext the api that requires the execution of the script
* @return whether scripts are on, off, or enabled only for sandboxed languages
*/
public ScriptMode getScriptMode(String lang, ScriptType scriptType, ScriptContext scriptContext) {
//native scripts are always on as they are static by definition
if (NativeScriptEngineService.NAME.equals(lang)) {
return ScriptMode.ON;
}
ScriptMode scriptMode = scriptModes.get(ENGINE_SETTINGS_PREFIX + "." + lang + "." + scriptType + "." + scriptContext);
if (scriptMode == null) {
throw new ElasticsearchIllegalArgumentException("script mode not found for lang [" + lang + "], script_type [" + scriptType + "], operation [" + scriptContext + "]");
}
return scriptMode;
}
@Override
public String toString() {
//order settings by key before printing them out, for readability
TreeMap<String, ScriptMode> scriptModesTreeMap = new TreeMap<>();
scriptModesTreeMap.putAll(scriptModes);
StringBuilder stringBuilder = new StringBuilder();
for (Map.Entry<String, ScriptMode> stringScriptModeEntry : scriptModesTreeMap.entrySet()) {
stringBuilder.append(stringScriptModeEntry.getKey()).append(": ").append(stringScriptModeEntry.getValue()).append("\n");
}
return stringBuilder.toString();
}
}

View File

@ -60,7 +60,6 @@ import org.elasticsearch.env.Environment;
import org.elasticsearch.index.query.TemplateQueryParser;
import org.elasticsearch.node.settings.NodeSettingsService;
import org.elasticsearch.script.groovy.GroovyScriptEngineService;
import org.elasticsearch.script.mustache.MustacheScriptEngineService;
import org.elasticsearch.search.lookup.SearchLookup;
import org.elasticsearch.watcher.FileChangesListener;
import org.elasticsearch.watcher.FileWatcher;
@ -86,9 +85,8 @@ public class ScriptService extends AbstractComponent implements Closeable {
public static final String DISABLE_DYNAMIC_SCRIPTING_SETTING = "script.disable_dynamic";
public static final String SCRIPT_CACHE_SIZE_SETTING = "script.cache.max_size";
public static final String SCRIPT_CACHE_EXPIRE_SETTING = "script.cache.expire";
public static final String DISABLE_DYNAMIC_SCRIPTING_DEFAULT = "sandbox";
public static final String SCRIPT_INDEX = ".scripts";
public static final String DEFAULT_LANG = "groovy";
public static final String DEFAULT_LANG = GroovyScriptEngineService.NAME;
public static final String SCRIPT_AUTO_RELOAD_ENABLED_SETTING = "script.auto_reload_enabled";
private final String defaultLang;
@ -103,7 +101,7 @@ public class ScriptService extends AbstractComponent implements Closeable {
private final Path scriptsDirectory;
private final FileWatcher fileWatcher;
private final DynamicScriptDisabling dynamicScriptingDisabled;
private final ScriptModes scriptModes;
private Client client = null;
@ -154,7 +152,6 @@ public class ScriptService extends AbstractComponent implements Closeable {
logger.debug("using script cache with max_size [{}], expire [{}]", cacheMaxSize, cacheExpire);
this.defaultLang = settings.get(DEFAULT_SCRIPTING_LANGUAGE_SETTING, DEFAULT_LANG);
this.dynamicScriptingDisabled = DynamicScriptDisabling.parse(settings.get(DISABLE_DYNAMIC_SCRIPTING_SETTING, DISABLE_DYNAMIC_SCRIPTING_DEFAULT));
CacheBuilder cacheBuilder = CacheBuilder.newBuilder();
if (cacheMaxSize >= 0) {
@ -179,6 +176,8 @@ public class ScriptService extends AbstractComponent implements Closeable {
this.scriptEnginesByLang = enginesByLangBuilder.build();
this.scriptEnginesByExt = enginesByExtBuilder.build();
this.scriptModes = new ScriptModes(this.scriptEnginesByLang, settings, logger);
// add file watcher for static scripts
scriptsDirectory = env.configFile().resolve("scripts");
if (logger.isTraceEnabled()) {
@ -239,10 +238,31 @@ public class ScriptService extends AbstractComponent implements Closeable {
return scriptEngineService;
}
/**
* Checks if a script can be executed and compiles it if needed, or returns the previously compiled and cached script.
*/
public CompiledScript compile(String lang, String script, ScriptType scriptType, ScriptContext scriptContext) {
assert script != null;
assert scriptType != null;
assert scriptContext != null;
if (lang == null) {
lang = defaultLang;
}
ScriptEngineService scriptEngineService = getScriptEngineServiceForLang(lang);
if (canExecuteScript(lang, scriptEngineService, scriptType, scriptContext) == false) {
throw new ScriptException("scripts of type [" + scriptType + "], operation [" + scriptContext + "] and lang [" + lang + "] are disabled");
}
return compileInternal(lang, script, scriptType);
}
/**
* Compiles a script straight-away, or returns the previously compiled and cached script, without checking if it can be executed based on settings.
*/
public CompiledScript compile(String lang, String script, ScriptType scriptType) {
public CompiledScript compileInternal(String lang, String script, ScriptType scriptType) {
assert script != null;
assert scriptType != null;
if (lang == null) {
lang = defaultLang;
}
@ -261,20 +281,14 @@ public class ScriptService extends AbstractComponent implements Closeable {
return compiled;
}
verifyDynamicScripting(lang, scriptEngineService);
if (scriptType == ScriptType.INDEXED) {
if (client == null) {
throw new ElasticsearchIllegalArgumentException("Got an indexed script with no Client registered.");
}
final IndexedScript indexedScript = new IndexedScript(lang, script);
script = getScriptFromIndex(client, indexedScript.lang, indexedScript.id);
script = getScriptFromIndex(indexedScript.lang, indexedScript.id);
}
CompiledScript compiled = cache.getIfPresent(cacheKey);
if (compiled == null) {
//Either an un-cached inline script or an indexed script
// not the end of the world if we compile it twice...
compiled = new CompiledScript(lang, scriptEngineService.compile(script));
//Since the cache key is the script content itself we don't need to
//invalidate/check the cache if an indexed script changes.
@ -283,12 +297,6 @@ public class ScriptService extends AbstractComponent implements Closeable {
return compiled;
}
private void verifyDynamicScripting(String lang, ScriptEngineService scriptEngineService) {
if (!dynamicScriptEnabled(lang, scriptEngineService)) {
throw new ScriptException("dynamic scripting for [" + lang + "] disabled");
}
}
public void queryScriptIndex(GetIndexedScriptRequest request, final ActionListener<GetResponse> listener) {
String scriptLang = validateScriptLanguage(request.scriptLang());
GetRequest getRequest = new GetRequest(request, SCRIPT_INDEX).type(scriptLang).id(request.id())
@ -306,7 +314,10 @@ public class ScriptService extends AbstractComponent implements Closeable {
return scriptLang;
}
private String getScriptFromIndex(Client client, String scriptLang, String id) {
String getScriptFromIndex(String scriptLang, String id) {
if (client == null) {
throw new ElasticsearchIllegalArgumentException("Got an indexed script with no Client registered.");
}
scriptLang = validateScriptLanguage(scriptLang);
GetRequest getRequest = new GetRequest(SCRIPT_INDEX, scriptLang, id);
GetResponse responseFields = client.get(getRequest).actionGet();
@ -325,10 +336,16 @@ public class ScriptService extends AbstractComponent implements Closeable {
//Just try and compile it
//This will have the benefit of also adding the script to the cache if it compiles
try {
CompiledScript compiledScript = compile(scriptLang, context.template(), ScriptType.INLINE);
if (compiledScript == null) {
throw new ElasticsearchIllegalArgumentException("Unable to parse [" + context.template() +
"] lang [" + scriptLang + "] (ScriptService.compile returned null)");
//we don't know yet what the script will be used for, but if all of the operations for this lang with
//indexed scripts are disabled, it makes no sense to even compile it and cache it.
if (isAnyScriptContextEnabled(scriptLang, getScriptEngineServiceForLang(scriptLang), ScriptType.INDEXED)) {
CompiledScript compiledScript = compileInternal(scriptLang, context.template(), ScriptType.INLINE);
if (compiledScript == null) {
throw new ElasticsearchIllegalArgumentException("Unable to parse [" + context.template() +
"] lang [" + scriptLang + "] (ScriptService.compile returned null)");
}
} else {
logger.warn("skipping compile of script [{}], lang [{}] as all scripted operations are disabled for indexed scripts", context.template(), scriptLang);
}
} catch (Exception e) {
throw new ElasticsearchIllegalArgumentException("Unable to parse [" + context.template() +
@ -392,8 +409,8 @@ public class ScriptService extends AbstractComponent implements Closeable {
/**
* Compiles (or retrieves from cache) and executes the provided script
*/
public ExecutableScript executable(String lang, String script, ScriptType scriptType, Map<String, Object> vars) {
return executable(compile(lang, script, scriptType), vars);
public ExecutableScript executable(String lang, String script, ScriptType scriptType, ScriptContext scriptContext, Map<String, Object> vars) {
return executable(compile(lang, script, scriptType, scriptContext), vars);
}
/**
@ -406,22 +423,33 @@ public class ScriptService extends AbstractComponent implements Closeable {
/**
* Compiles (or retrieves from cache) and executes the provided search script
*/
public SearchScript search(SearchLookup lookup, String lang, String script, ScriptType scriptType, @Nullable Map<String, Object> vars) {
CompiledScript compiledScript = compile(lang, script, scriptType);
public SearchScript search(SearchLookup lookup, String lang, String script, ScriptType scriptType, ScriptContext scriptContext, @Nullable Map<String, Object> vars) {
CompiledScript compiledScript = compile(lang, script, scriptType, scriptContext);
return getScriptEngineServiceForLang(compiledScript.lang()).search(compiledScript.compiled(), lookup, vars);
}
private boolean dynamicScriptEnabled(String lang, ScriptEngineService scriptEngineService) {
// Templating languages (mustache) and native scripts are always
// allowed, "native" executions are registered through plugins
if (this.dynamicScriptingDisabled == DynamicScriptDisabling.EVERYTHING_ALLOWED ||
NativeScriptEngineService.NAME.equals(lang) || MustacheScriptEngineService.NAME.equals(lang)) {
return true;
private boolean isAnyScriptContextEnabled(String lang, ScriptEngineService scriptEngineService, ScriptType scriptType) {
for (ScriptContext scriptContext : ScriptContext.values()) {
if (canExecuteScript(lang, scriptEngineService, scriptType, scriptContext)) {
return true;
}
}
if (this.dynamicScriptingDisabled == DynamicScriptDisabling.ONLY_DISK_ALLOWED) {
return false;
return false;
}
private boolean canExecuteScript(String lang, ScriptEngineService scriptEngineService, ScriptType scriptType, ScriptContext scriptContext) {
assert lang != null;
ScriptMode mode = scriptModes.getScriptMode(lang, scriptType, scriptContext);
switch (mode) {
case ON:
return true;
case OFF:
return false;
case SANDBOX:
return scriptEngineService.sandboxed();
default:
throw new ElasticsearchIllegalArgumentException("script mode [" + mode + "] not supported");
}
return scriptEngineService.sandboxed();
}
/**
@ -474,11 +502,17 @@ public class ScriptService extends AbstractComponent implements Closeable {
logger.warn("no script engine found for [{}]", scriptNameExt.v2());
} else {
try {
logger.info("compiling script file [{}]", file.toAbsolutePath());
try(InputStreamReader reader = new InputStreamReader(Files.newInputStream(file), Charsets.UTF_8)) {
String script = Streams.copyToString(reader);
CacheKey cacheKey = newCacheKey(engineService, scriptNameExt.v1());
staticCache.put(cacheKey, new CompiledScript(engineService.types()[0], engineService.compile(script)));
//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.types()[0], engineService, ScriptType.FILE)) {
logger.info("compiling script file [{}]", file.toAbsolutePath());
try(InputStreamReader reader = new InputStreamReader(Files.newInputStream(file), Charsets.UTF_8)) {
String script = Streams.copyToString(reader);
CacheKey cacheKey = newCacheKey(engineService, scriptNameExt.v1());
staticCache.put(cacheKey, new CompiledScript(engineService.types()[0], engineService.compile(script)));
}
} else {
logger.warn("skipping compile of script file [{}] as all scripted operations are disabled for file scripts", file.toAbsolutePath());
}
} catch (Throwable e) {
logger.warn("failed to load/compile script [{}]", e, scriptNameExt.v1());
@ -560,6 +594,11 @@ public class ScriptService extends AbstractComponent implements Closeable {
out.writeVInt(INLINE_VAL); //Default to inline
}
}
@Override
public String toString() {
return name().toLowerCase(Locale.ROOT);
}
}
private static CacheKey newCacheKey(ScriptEngineService engineService, String script) {

View File

@ -72,6 +72,7 @@ import org.elasticsearch.indices.IndicesWarmer.WarmerContext;
import org.elasticsearch.indices.cache.query.IndicesQueryCache;
import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptContext;
import org.elasticsearch.script.mustache.MustacheScriptEngineService;
import org.elasticsearch.search.dfs.CachedDfSource;
import org.elasticsearch.search.dfs.DfsPhase;
@ -628,7 +629,7 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
final ExecutableScript executable;
if (hasLength(request.templateName())) {
executable = this.scriptService.executable(MustacheScriptEngineService.NAME, request.templateName(), request.templateType(), request.templateParams());
executable = this.scriptService.executable(MustacheScriptEngineService.NAME, request.templateName(), request.templateType(), ScriptContext.SEARCH, request.templateParams());
} else {
if (!hasLength(request.templateSource())) {
return;
@ -668,7 +669,7 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
if (!hasLength(templateContext.template())) {
throw new ElasticsearchParseException("Template must have [template] field configured");
}
executable = this.scriptService.executable(MustacheScriptEngineService.NAME, templateContext.template(), templateContext.scriptType(), templateContext.params());
executable = this.scriptService.executable(MustacheScriptEngineService.NAME, templateContext.template(), templateContext.scriptType(), ScriptContext.SEARCH, templateContext.params());
}
BytesReference processedQuery = (BytesReference) executable.run();

View File

@ -33,6 +33,7 @@ import org.elasticsearch.index.query.QueryParsingException;
import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.ScriptParameterParser;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptContext;
import org.elasticsearch.search.aggregations.InternalAggregation;
import java.io.IOException;
@ -85,7 +86,7 @@ public class ScriptHeuristic extends SignificanceHeuristic {
}
public void initialize(InternalAggregation.ReduceContext context) {
script = context.scriptService().executable(scriptLang, scriptString, scriptType, params);
script = context.scriptService().executable(scriptLang, scriptString, scriptType, ScriptContext.AGGS, params);
script.setNextVar("_subset_freq", subsetDfHolder);
script.setNextVar("_subset_size", subsetSizeHolder);
script.setNextVar("_superset_freq", supersetDfHolder);
@ -170,7 +171,7 @@ public class ScriptHeuristic extends SignificanceHeuristic {
}
ExecutableScript searchScript;
try {
searchScript = scriptService.executable(scriptLang, script, scriptType, params);
searchScript = scriptService.executable(scriptLang, script, scriptType, ScriptContext.AGGS, params);
} catch (Exception e) {
throw new ElasticsearchParseException("The script [" + script + "] could not be loaded", e);
}

View File

@ -25,6 +25,7 @@ import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.ScriptService.ScriptType;
import org.elasticsearch.script.ScriptContext;
import org.elasticsearch.search.aggregations.AggregationStreams;
import org.elasticsearch.search.aggregations.InternalAggregation;
import org.elasticsearch.search.aggregations.metrics.InternalMetricsAggregation;
@ -98,7 +99,7 @@ public class InternalScriptedMetric extends InternalMetricsAggregation implement
}
params.put("_aggs", aggregationObjects);
ExecutableScript script = reduceContext.scriptService().executable(firstAggregation.scriptLang, firstAggregation.reduceScript,
firstAggregation.scriptType, params);
firstAggregation.scriptType, ScriptContext.AGGS, params);
aggregation = script.run();
} else {
aggregation = aggregationObjects;

View File

@ -23,6 +23,7 @@ import org.apache.lucene.index.LeafReaderContext;
import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptService.ScriptType;
import org.elasticsearch.script.ScriptContext;
import org.elasticsearch.script.SearchScript;
import org.elasticsearch.search.SearchParseException;
import org.elasticsearch.search.aggregations.Aggregator;
@ -73,11 +74,11 @@ public class ScriptedMetricAggregator extends MetricsAggregator {
}
ScriptService scriptService = context.searchContext().scriptService();
if (initScript != null) {
scriptService.executable(scriptLang, initScript, initScriptType, this.params).run();
scriptService.executable(scriptLang, initScript, initScriptType, ScriptContext.AGGS, this.params).run();
}
this.mapScript = scriptService.search(context.searchContext().lookup(), scriptLang, mapScript, mapScriptType, this.params);
this.mapScript = scriptService.search(context.searchContext().lookup(), scriptLang, mapScript, mapScriptType, ScriptContext.AGGS, this.params);
if (combineScript != null) {
this.combineScript = scriptService.executable(scriptLang, combineScript, combineScriptType, this.params);
this.combineScript = scriptService.executable(scriptLang, combineScript, combineScriptType, ScriptContext.AGGS, this.params);
} else {
this.combineScript = null;
}

View File

@ -31,6 +31,7 @@ import org.elasticsearch.index.mapper.ip.IpFieldMapper;
import org.elasticsearch.script.ScriptParameterParser;
import org.elasticsearch.script.ScriptParameterParser.ScriptParameterValue;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptContext;
import org.elasticsearch.script.SearchScript;
import org.elasticsearch.search.SearchParseException;
import org.elasticsearch.search.aggregations.InternalAggregation;
@ -187,7 +188,7 @@ public class ValuesSourceParser<VS extends ValuesSource> {
}
private SearchScript createScript() {
return input.script == null ? null : context.scriptService().search(context.lookup(), input.lang, input.script, input.scriptType, input.params);
return input.script == null ? null : context.scriptService().search(context.lookup(), input.lang, input.script, input.scriptType, ScriptContext.AGGS, input.params);
}
private static ValueFormat resolveFormat(@Nullable String format, @Nullable ValueType valueType) {

View File

@ -23,6 +23,7 @@ import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.script.ScriptParameterParser;
import org.elasticsearch.script.ScriptParameterParser.ScriptParameterValue;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptContext;
import org.elasticsearch.script.SearchScript;
import org.elasticsearch.search.SearchParseElement;
import org.elasticsearch.search.internal.SearchContext;
@ -78,7 +79,7 @@ public class ScriptFieldsParseElement implements SearchParseElement {
script = scriptValue.script();
scriptType = scriptValue.scriptType();
}
SearchScript searchScript = context.scriptService().search(context.lookup(), scriptParameterParser.lang(), script, scriptType, params);
SearchScript searchScript = context.scriptService().search(context.lookup(), scriptParameterParser.lang(), script, scriptType, ScriptContext.SEARCH, params);
context.scriptFields().add(new ScriptFieldsContext.ScriptField(fieldName, searchScript, ignoreException));
}
}

View File

@ -35,6 +35,7 @@ import org.elasticsearch.index.fielddata.fieldcomparator.DoubleValuesComparatorS
import org.elasticsearch.index.query.support.NestedInnerQueryParseSupport;
import org.elasticsearch.index.search.nested.NonNestedDocsFilter;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptContext;
import org.elasticsearch.script.SearchScript;
import org.elasticsearch.search.MultiValueMode;
import org.elasticsearch.search.SearchParseException;
@ -116,7 +117,7 @@ public class ScriptSortParser implements SortParser {
if (type == null) {
throw new SearchParseException(context, "_script sorting requires setting the type of the script");
}
final SearchScript searchScript = context.scriptService().search(context.lookup(), scriptLang, script, scriptType, params);
final SearchScript searchScript = context.scriptService().search(context.lookup(), scriptLang, script, scriptType, ScriptContext.SEARCH, params);
if (STRING_SORT_TYPE.equals(type) && (sortMode == MultiValueMode.SUM || sortMode == MultiValueMode.AVG)) {
throw new SearchParseException(context, "type [string] doesn't support mode [" + sortMode + "]");

View File

@ -30,7 +30,8 @@ import org.elasticsearch.index.analysis.ShingleTokenFilterFactory;
import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.script.CompiledScript;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptService.ScriptType;
import org.elasticsearch.script.ScriptContext;
import org.elasticsearch.script.mustache.MustacheScriptEngineService;
import org.elasticsearch.search.suggest.SuggestContextParser;
import org.elasticsearch.search.suggest.SuggestUtils;
@ -152,7 +153,7 @@ public final class PhraseSuggestParser implements SuggestContextParser {
if (suggestion.getCollateQueryScript() != null) {
throw new ElasticsearchIllegalArgumentException("suggester[phrase][collate] query already set, doesn't support additional [" + fieldName + "]");
}
CompiledScript compiledScript = suggester.scriptService().compile(MustacheScriptEngineService.NAME, templateNameOrTemplateContent, ScriptService.ScriptType.INLINE);
CompiledScript compiledScript = suggester.scriptService().compile(MustacheScriptEngineService.NAME, templateNameOrTemplateContent, ScriptType.INLINE, ScriptContext.SEARCH);
if ("query".equals(fieldName)) {
suggestion.setCollateQueryScript(compiledScript);
} else {

View File

@ -20,24 +20,44 @@
package org.elasticsearch.script;
import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.script.expression.ExpressionScriptEngineService;
import org.elasticsearch.script.groovy.GroovyScriptEngineService;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.test.ElasticsearchIntegrationTest;
import org.junit.Test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.*;
public class IndexedScriptTests extends ElasticsearchIntegrationTest {
@Override
protected Settings nodeSettings(int nodeOrdinal) {
ImmutableSettings.Builder builder = ImmutableSettings.builder().put(super.nodeSettings(nodeOrdinal));
builder.put("script.engine.groovy.indexed.update", "off");
builder.put("script.engine.groovy.indexed.search", "on");
builder.put("script.engine.groovy.indexed.aggs", "on");
builder.put("script.engine.groovy.inline.aggs", "off");
builder.put("script.engine.expression.indexed.update", "off");
builder.put("script.engine.expression.indexed.search", "off");
builder.put("script.engine.expression.indexed.aggs", "off");
builder.put("script.engine.expression.indexed.mapping", "off");
return builder.build();
}
@Test
public void testFieldIndexedScript() throws ExecutionException, InterruptedException{
public void testFieldIndexedScript() throws ExecutionException, InterruptedException {
List<IndexRequestBuilder> builders = new ArrayList<>();
builders.add(client().prepareIndex(ScriptService.SCRIPT_INDEX, "groovy", "script1").setSource("{" +
"\"script\":\"2\""+
@ -66,4 +86,67 @@ public class IndexedScriptTests extends ElasticsearchIntegrationTest {
assertThat((Integer)sh.field("test1").getValue(), equalTo(2));
assertThat((Integer)sh.field("test2").getValue(), equalTo(6));
}
@Test
public void testDisabledUpdateIndexedScriptsOnly() {
if (randomBoolean()) {
client().preparePutIndexedScript(GroovyScriptEngineService.NAME, "script1", "{\"script\":\"2\"}").get();
} else {
client().prepareIndex(ScriptService.SCRIPT_INDEX, GroovyScriptEngineService.NAME, "script1").setSource("{\"script\":\"2\"}").get();
}
client().prepareIndex("test", "scriptTest", "1").setSource("{\"theField\":\"foo\"}").get();
try {
client().prepareUpdate("test", "scriptTest", "1").setScript("script1", ScriptService.ScriptType.INDEXED).setScriptLang(GroovyScriptEngineService.NAME).get();
fail("update script should have been rejected");
} catch(Exception e) {
assertThat(e.getMessage(), containsString("failed to execute script"));
assertThat(ExceptionsHelper.detailedMessage(e), containsString("scripts of type [indexed], operation [update] and lang [groovy] are disabled"));
}
}
@Test
public void testDisabledAggsDynamicScripts() {
//dynamic scripts don't need to be enabled for an indexed script to be indexed and later on executed
if (randomBoolean()) {
client().preparePutIndexedScript(GroovyScriptEngineService.NAME, "script1", "{\"script\":\"2\"}").get();
} else {
client().prepareIndex(ScriptService.SCRIPT_INDEX, GroovyScriptEngineService.NAME, "script1").setSource("{\"script\":\"2\"}").get();
}
client().prepareIndex("test", "scriptTest", "1").setSource("{\"theField\":\"foo\"}").get();
refresh();
String source = "{\"aggs\": {\"test\": { \"terms\" : { \"script_id\":\"script1\" } } } }";
SearchResponse searchResponse = client().prepareSearch("test").setSource(source).get();
assertHitCount(searchResponse, 1);
assertThat(searchResponse.getAggregations().get("test"), notNullValue());
}
@Test
public void testAllOpsDisabledIndexedScripts() throws IOException {
if (randomBoolean()) {
client().preparePutIndexedScript(ExpressionScriptEngineService.NAME, "script1", "{\"script\":\"2\"}").get();
} else {
client().prepareIndex(ScriptService.SCRIPT_INDEX, ExpressionScriptEngineService.NAME, "script1").setSource("{\"script\":\"2\"}").get();
}
client().prepareIndex("test", "scriptTest", "1").setSource("{\"theField\":\"foo\"}").get();
try {
client().prepareUpdate("test", "scriptTest", "1").setScript("script1", ScriptService.ScriptType.INDEXED).setScriptLang(ExpressionScriptEngineService.NAME).get();
fail("update script should have been rejected");
} catch(Exception e) {
assertThat(e.getMessage(), containsString("failed to execute script"));
assertThat(ExceptionsHelper.detailedMessage(e), containsString("scripts of type [indexed], operation [update] and lang [expression] are disabled"));
}
try {
String query = "{ \"script_fields\" : { \"test1\" : { \"script_id\" : \"script1\", \"lang\":\"expression\" }}}";
client().prepareSearch().setSource(query).setIndices("test").setTypes("scriptTest").get();
fail("search script should have been rejected");
} catch(Exception e) {
assertThat(e.getMessage(), containsString("scripts of type [indexed], operation [search] and lang [expression] are disabled"));
}
try {
String source = "{\"aggs\": {\"test\": { \"terms\" : { \"script_id\":\"script1\", \"script_lang\":\"expression\" } } } }";
client().prepareSearch("test").setSource(source).get();
} catch(Exception e) {
assertThat(e.getMessage(), containsString("scripts of type [indexed], operation [aggs] and lang [expression] are disabled"));
}
}
}

View File

@ -19,20 +19,29 @@
package org.elasticsearch.script;
import com.google.common.collect.ImmutableSet;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.inject.Injector;
import org.elasticsearch.common.inject.ModulesBuilder;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsModule;
import org.elasticsearch.env.Environment;
import org.elasticsearch.node.settings.NodeSettingsService;
import org.elasticsearch.script.ScriptService.ScriptType;
import org.elasticsearch.test.ElasticsearchTestCase;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.threadpool.ThreadPoolModule;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.junit.Test;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.notNullValue;
public class NativeScriptTests extends ElasticsearchTestCase {
@ -49,11 +58,49 @@ public class NativeScriptTests extends ElasticsearchTestCase {
ScriptService scriptService = injector.getInstance(ScriptService.class);
ExecutableScript executable = scriptService.executable(NativeScriptEngineService.NAME, "my", ScriptService.ScriptType.INLINE, null);
ExecutableScript executable = scriptService.executable(NativeScriptEngineService.NAME, "my", ScriptType.INLINE, ScriptContext.SEARCH, null);
assertThat(executable.run().toString(), equalTo("test"));
terminate(injector.getInstance(ThreadPool.class));
}
@Test
public void testFineGrainedSettingsDontAffectNativeScripts() throws IOException {
ImmutableSettings.Builder builder = ImmutableSettings.settingsBuilder();
if (randomBoolean()) {
ScriptType scriptType = randomFrom(ScriptType.values());
builder.put(ScriptModes.SCRIPT_SETTINGS_PREFIX + scriptType, randomFrom(ScriptMode.values()));
} else {
ScriptContext scriptContext = randomFrom(ScriptContext.values());
builder.put(ScriptModes.SCRIPT_SETTINGS_PREFIX + scriptContext, randomFrom(ScriptMode.values()));
}
Settings settings = builder.build();
Environment environment = new Environment(settings);
ResourceWatcherService resourceWatcherService = new ResourceWatcherService(settings, null);
Map<String, NativeScriptFactory> nativeScriptFactoryMap = new HashMap<>();
nativeScriptFactoryMap.put("my", new MyNativeScriptFactory());
Set<ScriptEngineService> scriptEngineServices = ImmutableSet.<ScriptEngineService>of(new NativeScriptEngineService(settings, nativeScriptFactoryMap));
ScriptService scriptService = new ScriptService(settings, environment, scriptEngineServices, resourceWatcherService, new NodeSettingsService(settings));
for (ScriptContext scriptContext : ScriptContext.values()) {
assertThat(scriptService.compile(NativeScriptEngineService.NAME, "my", ScriptType.INLINE, scriptContext), notNullValue());
}
}
@Test
public void testDisableDynamicDoesntAffectNativeScripts() throws IOException {
Settings settings = ImmutableSettings.settingsBuilder().put(ScriptService.DISABLE_DYNAMIC_SCRIPTING_SETTING, randomFrom("true", "false", "sandbox")).build();
Environment environment = new Environment(settings);
ResourceWatcherService resourceWatcherService = new ResourceWatcherService(settings, null);
Map<String, NativeScriptFactory> nativeScriptFactoryMap = new HashMap<>();
nativeScriptFactoryMap.put("my", new MyNativeScriptFactory());
Set<ScriptEngineService> scriptEngineServices = ImmutableSet.<ScriptEngineService>of(new NativeScriptEngineService(settings, nativeScriptFactoryMap));
ScriptService scriptService = new ScriptService(settings, environment, scriptEngineServices, resourceWatcherService, new NodeSettingsService(settings));
for (ScriptContext scriptContext : ScriptContext.values()) {
assertThat(scriptService.compile(NativeScriptEngineService.NAME, "my", ScriptType.INLINE, scriptContext), notNullValue());
}
}
static class MyNativeScriptFactory implements NativeScriptFactory {
@Override
public ExecutableScript newScript(@Nullable Map<String, Object> params) {

View File

@ -18,9 +18,11 @@
*/
package org.elasticsearch.script;
import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.script.mustache.MustacheScriptEngineService;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.test.ElasticsearchIntegrationTest;
import org.junit.Test;
@ -31,6 +33,7 @@ import java.util.concurrent.ExecutionException;
import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
//Use Suite scope so that paths get set correctly
@ -41,19 +44,22 @@ public class OnDiskScriptTests extends ElasticsearchIntegrationTest {
public Settings nodeSettings(int nodeOrdinal) {
//Set path so ScriptService will pick up the test scripts
return settingsBuilder().put(super.nodeSettings(nodeOrdinal))
.put("path.conf", this.getResourcePath("config")).build();
.put("path.conf", this.getResourcePath("config"))
.put("script.engine.expression.file.aggs", "off")
.put("script.engine.mustache.file.aggs", "off")
.put("script.engine.mustache.file.search", "off")
.put("script.engine.mustache.file.mapping", "off")
.put("script.engine.mustache.file.update", "off").build();
}
@Test
public void testFieldOnDiskScript() throws ExecutionException, InterruptedException {
List<IndexRequestBuilder> builders = new ArrayList<>();
builders.add(client().prepareIndex("test", "scriptTest", "1").setSource("{\"theField\":\"foo\"}"));
builders.add(client().prepareIndex("test", "scriptTest", "2").setSource("{\"theField\":\"foo 2\"}"));
builders.add(client().prepareIndex("test", "scriptTest", "3").setSource("{\"theField\":\"foo 3\"}"));
builders.add(client().prepareIndex("test", "scriptTest", "4").setSource("{\"theField\":\"foo 4\"}"));
builders.add(client().prepareIndex("test", "scriptTest", "5").setSource("{\"theField\":\"bar\"}"));
indexRandom(true, builders);
String query = "{ \"query\" : { \"match_all\": {}} , \"script_fields\" : { \"test1\" : { \"script_file\" : \"script1\" }, \"test2\" : { \"script_file\" : \"script2\", \"params\":{\"factor\":3} }}, size:1}";
@ -67,14 +73,12 @@ public class OnDiskScriptTests extends ElasticsearchIntegrationTest {
@Test
public void testOnDiskScriptsSameNameDifferentLang() throws ExecutionException, InterruptedException {
List<IndexRequestBuilder> builders = new ArrayList<>();
builders.add(client().prepareIndex("test", "scriptTest", "1").setSource("{\"theField\":\"foo\"}"));
builders.add(client().prepareIndex("test", "scriptTest", "2").setSource("{\"theField\":\"foo 2\"}"));
builders.add(client().prepareIndex("test", "scriptTest", "3").setSource("{\"theField\":\"foo 3\"}"));
builders.add(client().prepareIndex("test", "scriptTest", "4").setSource("{\"theField\":\"foo 4\"}"));
builders.add(client().prepareIndex("test", "scriptTest", "5").setSource("{\"theField\":\"bar\"}"));
indexRandom(true, builders);
String query = "{ \"query\" : { \"match_all\": {}} , \"script_fields\" : { \"test1\" : { \"script_file\" : \"script1\" }, \"test2\" : { \"script_file\" : \"script1\", \"lang\":\"expression\" }}, size:1}";
@ -85,4 +89,60 @@ public class OnDiskScriptTests extends ElasticsearchIntegrationTest {
assertThat((Integer)sh.field("test1").getValue(), equalTo(2));
assertThat((Double)sh.field("test2").getValue(), equalTo(10d));
}
@Test
public void testPartiallyDisabledOnDiskScripts() throws ExecutionException, InterruptedException {
//test that although aggs are disabled for expression, search scripts work fine
List<IndexRequestBuilder> builders = new ArrayList<>();
builders.add(client().prepareIndex("test", "scriptTest", "1").setSource("{\"theField\":\"foo\"}"));
builders.add(client().prepareIndex("test", "scriptTest", "2").setSource("{\"theField\":\"foo 2\"}"));
builders.add(client().prepareIndex("test", "scriptTest", "3").setSource("{\"theField\":\"foo 3\"}"));
builders.add(client().prepareIndex("test", "scriptTest", "4").setSource("{\"theField\":\"foo 4\"}"));
builders.add(client().prepareIndex("test", "scriptTest", "5").setSource("{\"theField\":\"bar\"}"));
indexRandom(true, builders);
String source = "{\"aggs\": {\"test\": { \"terms\" : { \"script_file\":\"script1\", \"lang\": \"expression\" } } } }";
try {
client().prepareSearch("test").setSource(source).get();
fail("aggs script should have been rejected");
} catch(Exception e) {
assertThat(ExceptionsHelper.detailedMessage(e), containsString("scripts of type [file], operation [aggs] and lang [expression] are disabled"));
}
String query = "{ \"query\" : { \"match_all\": {}} , \"script_fields\" : { \"test1\" : { \"script_file\" : \"script1\", \"lang\":\"expression\" }}, size:1}";
SearchResponse searchResponse = client().prepareSearch().setSource(query).setIndices("test").setTypes("scriptTest").get();
assertHitCount(searchResponse, 5);
assertTrue(searchResponse.getHits().hits().length == 1);
SearchHit sh = searchResponse.getHits().getAt(0);
assertThat((Double)sh.field("test1").getValue(), equalTo(10d));
}
@Test
public void testAllOpsDisabledOnDiskScripts() {
//whether we even compile or cache the on disk scripts doesn't change the end result (the returned error)
client().prepareIndex("test", "scriptTest", "1").setSource("{\"theField\":\"foo\"}").get();
refresh();
String source = "{\"aggs\": {\"test\": { \"terms\" : { \"script_file\":\"script1\", \"lang\": \"mustache\" } } } }";
try {
client().prepareSearch("test").setSource(source).get();
fail("aggs script should have been rejected");
} catch(Exception e) {
assertThat(ExceptionsHelper.detailedMessage(e), containsString("scripts of type [file], operation [aggs] and lang [mustache] are disabled"));
}
String query = "{ \"query\" : { \"match_all\": {}} , \"script_fields\" : { \"test1\" : { \"script_file\" : \"script1\", \"lang\":\"mustache\" }}, size:1}";
try {
client().prepareSearch().setSource(query).setIndices("test").setTypes("scriptTest").get();
fail("search script should have been rejected");
} catch(Exception e) {
assertThat(ExceptionsHelper.detailedMessage(e), containsString("scripts of type [file], operation [search] and lang [mustache] are disabled"));
}
try {
client().prepareUpdate("test", "scriptTest", "1").setScript("script1", ScriptService.ScriptType.FILE).setScriptLang(MustacheScriptEngineService.NAME).get();
fail("update script should have been rejected");
} catch(Exception e) {
assertThat(e.getMessage(), containsString("failed to execute script"));
assertThat(ExceptionsHelper.detailedMessage(e), containsString("scripts of type [file], operation [update] and lang [mustache] are disabled"));
}
}
}

View File

@ -19,13 +19,14 @@
package org.elasticsearch.script;
import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.script.groovy.GroovyScriptEngineService;
import org.elasticsearch.test.ElasticsearchIntegrationTest;
import org.junit.Test;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.containsString;
/**
* Test that a system where the sandbox is disabled while dynamic scripting is
@ -38,8 +39,7 @@ public class SandboxDisabledTests extends ElasticsearchIntegrationTest {
protected Settings nodeSettings(int nodeOrdinal) {
return ImmutableSettings.settingsBuilder().put(super.nodeSettings(nodeOrdinal))
.put(GroovyScriptEngineService.GROOVY_SCRIPT_SANDBOX_ENABLED, false)
.put(ScriptService.DISABLE_DYNAMIC_SCRIPTING_SETTING, true)
.build();
.put("script.inline", false).build();
}
@Test
@ -51,8 +51,7 @@ public class SandboxDisabledTests extends ElasticsearchIntegrationTest {
"\"sort\":{\"_script\": {\"script\": \"doc['foo'].value + 2\", \"type\": \"number\", \"lang\": \"groovy\"}}}").get();
fail("shards should fail because the sandbox and dynamic scripting are disabled");
} catch (Exception e) {
assertThat(e.getMessage().contains("dynamic scripting for [groovy] disabled"), equalTo(true));
assertThat(ExceptionsHelper.detailedMessage(e), containsString("scripts of type [inline], operation [search] and lang [groovy] are disabled"));
}
}
}

View File

@ -0,0 +1,567 @@
/*
* 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 com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import org.elasticsearch.ElasticsearchIllegalArgumentException;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.script.ScriptService.ScriptType;
import org.elasticsearch.script.expression.ExpressionScriptEngineService;
import org.elasticsearch.script.groovy.GroovyScriptEngineService;
import org.elasticsearch.script.mustache.MustacheScriptEngineService;
import org.elasticsearch.search.lookup.SearchLookup;
import org.elasticsearch.test.ElasticsearchTestCase;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.notNullValue;
public class ScriptModesTests extends ElasticsearchTestCase {
private static final Set<String> ALL_LANGS = ImmutableSet.of(GroovyScriptEngineService.NAME, MustacheScriptEngineService.NAME, ExpressionScriptEngineService.NAME, "custom", "test");
static final String[] ENABLE_VALUES = new String[]{"on", "true", "yes", "1"};
static final String[] DISABLE_VALUES = new String[]{"off", "false", "no", "0"};
private Map<String, ScriptEngineService> scriptEngines;
private ScriptModes scriptModes;
private Set<String> checkedSettings;
private boolean assertAllSettingsWereChecked;
private boolean assertScriptModesNonNull;
@Before
public void setupScriptEngines() {
scriptEngines = buildScriptEnginesByLangMap(ImmutableSet.of(
new GroovyScriptEngineService(ImmutableSettings.EMPTY),
new MustacheScriptEngineService(ImmutableSettings.EMPTY),
new ExpressionScriptEngineService(ImmutableSettings.EMPTY),
//add the native engine just to make sure it gets filtered out
new NativeScriptEngineService(ImmutableSettings.EMPTY, Collections.<String, NativeScriptFactory>emptyMap()),
new CustomScriptEngineService()));
checkedSettings = new HashSet<>();
assertAllSettingsWereChecked = true;
assertScriptModesNonNull = true;
}
@After
public void assertNativeScriptsAreAlwaysAllowed() {
if (assertScriptModesNonNull) {
assertThat(scriptModes.getScriptMode(NativeScriptEngineService.NAME, randomFrom(ScriptType.values()), randomFrom(ScriptContext.values())), equalTo(ScriptMode.ON));
}
}
@After
public void assertAllSettingsWereChecked() {
if (assertScriptModesNonNull) {
assertThat(scriptModes, notNullValue());
//4 is the number of engines (native excluded), custom is counted twice though as it's associated with two different names
int numberOfSettings = 5 * ScriptType.values().length * ScriptContext.values().length;
assertThat(scriptModes.scriptModes.size(), equalTo(numberOfSettings));
if (assertAllSettingsWereChecked) {
assertThat(checkedSettings.size(), equalTo(numberOfSettings));
}
}
}
@Test
public void testDefaultSettings() {
this.scriptModes = new ScriptModes(scriptEngines, ImmutableSettings.EMPTY, Loggers.getLogger(ScriptModesTests.class));
assertScriptModesAllOps(ScriptMode.ON, ALL_LANGS, ScriptType.FILE);
assertScriptModesAllOps(ScriptMode.SANDBOX, ALL_LANGS, ScriptType.INDEXED, ScriptType.INLINE);
}
@Test
public void testDefaultSettingsDisableDynamicTrue() {
//verify that disable_dynamic setting gets still read and applied, iff new settings are not present
this.scriptModes = new ScriptModes(scriptEngines, ImmutableSettings.builder().put(ScriptService.DISABLE_DYNAMIC_SCRIPTING_SETTING, randomFrom("true", "all")).build(), Loggers.getLogger(ScriptModesTests.class));
assertScriptModesAllOps(ScriptMode.ON, ALL_LANGS, ScriptType.FILE);
assertScriptModesAllOps(ScriptMode.OFF, ALL_LANGS, ScriptType.INDEXED, ScriptType.INLINE);
}
@Test
public void testDefaultSettingsEnableDynamicFalse() {
//verify that disable_dynamic setting gets still read and applied, iff new settings are not present
this.scriptModes = new ScriptModes(scriptEngines, ImmutableSettings.builder().put(ScriptService.DISABLE_DYNAMIC_SCRIPTING_SETTING, randomFrom("false", "none")).build(), Loggers.getLogger(ScriptModesTests.class));
assertScriptModesAllOps(ScriptMode.ON, ALL_LANGS, ScriptType.FILE, ScriptType.INDEXED, ScriptType.INLINE);
}
@Test
public void testDefaultSettingsDisableDynamicSandbox() {
//verify that disable_dynamic setting gets still read and applied, iff new settings are not present
this.scriptModes = new ScriptModes(scriptEngines, ImmutableSettings.builder().put(ScriptService.DISABLE_DYNAMIC_SCRIPTING_SETTING, ScriptMode.SANDBOX).build(), Loggers.getLogger(ScriptModesTests.class));
assertScriptModesAllOps(ScriptMode.ON, ALL_LANGS, ScriptType.FILE);
assertScriptModesAllOps(ScriptMode.SANDBOX, ALL_LANGS, ScriptType.INDEXED, ScriptType.INLINE);
}
@Test
public void testConflictingSettings() {
assertScriptModesNonNull = false;
ImmutableSettings.Builder builder = ImmutableSettings.builder()
.put(ScriptService.DISABLE_DYNAMIC_SCRIPTING_SETTING, randomFrom("all", "true", "none", "false", "sandbox", "sandboxed"));
int iterations = randomIntBetween(1, 5);
for (int i = 0; i < iterations; i++) {
if (randomBoolean()) {
builder.put("script." + randomFrom(ScriptType.values()), randomFrom(ScriptMode.values()));
} else {
if (randomBoolean()) {
builder.put(ScriptModes.SCRIPT_SETTINGS_PREFIX + randomFrom(ScriptContext.values()), randomFrom(ScriptMode.values()));
} else {
builder.put(specificEngineOpSettings(GroovyScriptEngineService.NAME, randomFrom(ScriptType.values()), randomFrom(ScriptContext.values())), randomFrom(ScriptMode.values()));
}
}
}
Settings settings = builder.build();
try {
this.scriptModes = new ScriptModes(scriptEngines, settings, Loggers.getLogger(ScriptModesTests.class));
fail("ScriptModes should have thrown an error due to conflicting settings");
} catch(ElasticsearchIllegalArgumentException e) {
assertThat(e.getMessage(), containsString("conflicting scripting settings have been specified"));
for (Map.Entry<String, String> scriptSettingEntry : settings.getAsSettings("script").getAsMap().entrySet()) {
assertThat(e.getMessage(), containsString(ScriptModes.SCRIPT_SETTINGS_PREFIX + scriptSettingEntry.getKey() + ": " + scriptSettingEntry.getValue()));
}
}
}
@Test(expected = ElasticsearchIllegalArgumentException.class)
public void testMissingSetting() {
assertAllSettingsWereChecked = false;
this.scriptModes = new ScriptModes(scriptEngines, ImmutableSettings.EMPTY, Loggers.getLogger(ScriptModesTests.class));
scriptModes.getScriptMode("non_existing", randomFrom(ScriptType.values()), randomFrom(ScriptContext.values()));
}
@Test
public void testEnableInlineGenericSettings() {
ImmutableSettings.Builder builder = ImmutableSettings.builder().put("script.inline", randomFrom(ENABLE_VALUES));
this.scriptModes = new ScriptModes(scriptEngines, builder.build(), Loggers.getLogger(ScriptModesTests.class));
assertScriptModesAllOps(ScriptMode.ON, ALL_LANGS, ScriptType.FILE, ScriptType.INLINE);
assertScriptModesAllOps(ScriptMode.SANDBOX, ALL_LANGS, ScriptType.INDEXED);
}
@Test
public void testDisableInlineGenericSettings() {
ImmutableSettings.Builder builder = ImmutableSettings.builder().put("script.inline", randomFrom(DISABLE_VALUES));
this.scriptModes = new ScriptModes(scriptEngines, builder.build(), Loggers.getLogger(ScriptModesTests.class));
assertScriptModesAllOps(ScriptMode.ON, ALL_LANGS, ScriptType.FILE);
assertScriptModesAllOps(ScriptMode.SANDBOX, ALL_LANGS, ScriptType.INDEXED);
assertScriptModesAllOps(ScriptMode.OFF, ALL_LANGS, ScriptType.INLINE);
}
@Test
public void testSandboxInlineGenericSettings() {
ImmutableSettings.Builder builder = ImmutableSettings.builder().put("script.inline", randomFrom(ScriptMode.SANDBOX));
//nothing changes if setting set is same as default
this.scriptModes = new ScriptModes(scriptEngines, builder.build(), Loggers.getLogger(ScriptModesTests.class));
assertScriptModesAllOps(ScriptMode.ON, ALL_LANGS, ScriptType.FILE);
assertScriptModesAllOps(ScriptMode.SANDBOX, ALL_LANGS, ScriptType.INDEXED, ScriptType.INLINE);
}
@Test
public void testEnableIndexedGenericSettings() {
ImmutableSettings.Builder builder = ImmutableSettings.builder().put("script.indexed", randomFrom(ENABLE_VALUES));
this.scriptModes = new ScriptModes(scriptEngines, builder.build(), Loggers.getLogger(ScriptModesTests.class));
assertScriptModesAllOps(ScriptMode.ON, ALL_LANGS, ScriptType.FILE, ScriptType.INDEXED);
assertScriptModesAllOps(ScriptMode.SANDBOX, ALL_LANGS, ScriptType.INLINE);
}
@Test
public void testDisableIndexedGenericSettings() {
ImmutableSettings.Builder builder = ImmutableSettings.builder().put("script.indexed", randomFrom(DISABLE_VALUES));
this.scriptModes = new ScriptModes(scriptEngines, builder.build(), Loggers.getLogger(ScriptModesTests.class));
assertScriptModesAllOps(ScriptMode.ON, ALL_LANGS, ScriptType.FILE);
assertScriptModesAllOps(ScriptMode.OFF, ALL_LANGS, ScriptType.INDEXED);
assertScriptModesAllOps(ScriptMode.SANDBOX, ALL_LANGS, ScriptType.INLINE);
}
@Test
public void testSandboxIndexedGenericSettings() {
ImmutableSettings.Builder builder = ImmutableSettings.builder().put("script.indexed", ScriptMode.SANDBOX);
//nothing changes if setting set is same as default
this.scriptModes = new ScriptModes(scriptEngines, builder.build(), Loggers.getLogger(ScriptModesTests.class));
assertScriptModesAllOps(ScriptMode.ON, ALL_LANGS, ScriptType.FILE);
assertScriptModesAllOps(ScriptMode.SANDBOX, ALL_LANGS, ScriptType.INDEXED, ScriptType.INLINE);
}
@Test
public void testEnableFileGenericSettings() {
ImmutableSettings.Builder builder = ImmutableSettings.builder().put("script.file", randomFrom(ENABLE_VALUES));
//nothing changes if setting set is same as default
this.scriptModes = new ScriptModes(scriptEngines, builder.build(), Loggers.getLogger(ScriptModesTests.class));
assertScriptModesAllOps(ScriptMode.ON, ALL_LANGS, ScriptType.FILE);
assertScriptModesAllOps(ScriptMode.SANDBOX, ALL_LANGS, ScriptType.INDEXED, ScriptType.INLINE);
}
@Test
public void testDisableFileGenericSettings() {
ImmutableSettings.Builder builder = ImmutableSettings.builder().put("script.file", randomFrom(DISABLE_VALUES));
this.scriptModes = new ScriptModes(scriptEngines, builder.build(), Loggers.getLogger(ScriptModesTests.class));
assertScriptModesAllOps(ScriptMode.OFF, ALL_LANGS, ScriptType.FILE);
assertScriptModesAllOps(ScriptMode.SANDBOX, ALL_LANGS, ScriptType.INDEXED, ScriptType.INLINE);
}
@Test
public void testSandboxFileGenericSettings() {
ImmutableSettings.Builder builder = ImmutableSettings.builder().put("script.file", ScriptMode.SANDBOX);
//nothing changes if setting set is same as default
this.scriptModes = new ScriptModes(scriptEngines, builder.build(), Loggers.getLogger(ScriptModesTests.class));
assertScriptModesAllOps(ScriptMode.SANDBOX, ALL_LANGS, ScriptType.FILE, ScriptType.INDEXED, ScriptType.INLINE);
}
@Test
public void testMultipleScriptTypeGenericSettings() {
ImmutableSettings.Builder builder = ImmutableSettings.builder().put("script.file", ScriptMode.SANDBOX).put("script.inline", randomFrom(DISABLE_VALUES));
this.scriptModes = new ScriptModes(scriptEngines, builder.build(), Loggers.getLogger(ScriptModesTests.class));
assertScriptModesAllOps(ScriptMode.SANDBOX, ALL_LANGS, ScriptType.FILE);
assertScriptModesAllOps(ScriptMode.SANDBOX, ALL_LANGS, ScriptType.INDEXED);
assertScriptModesAllOps(ScriptMode.OFF, ALL_LANGS, ScriptType.INLINE);
}
@Test
public void testEnableMappingGenericSettings() {
ImmutableSettings.Builder builder = ImmutableSettings.builder().put("script.mapping", randomFrom(ENABLE_VALUES));
this.scriptModes = new ScriptModes(scriptEngines, builder.build(), Loggers.getLogger(ScriptModesTests.class));
assertScriptModesAllTypes(ScriptMode.ON, ALL_LANGS, ScriptContext.MAPPING);
assertScriptModes(ScriptMode.ON, ALL_LANGS, new ScriptType[]{ScriptType.FILE}, ScriptContext.AGGS, ScriptContext.SEARCH, ScriptContext.UPDATE);
assertScriptModes(ScriptMode.SANDBOX, ALL_LANGS, new ScriptType[]{ScriptType.INDEXED, ScriptType.INLINE}, ScriptContext.AGGS, ScriptContext.SEARCH, ScriptContext.UPDATE);
}
@Test
public void testDisableMappingGenericSettings() {
ImmutableSettings.Builder builder = ImmutableSettings.builder().put("script.mapping", randomFrom(DISABLE_VALUES));
this.scriptModes = new ScriptModes(scriptEngines, builder.build(), Loggers.getLogger(ScriptModesTests.class));
assertScriptModesAllTypes(ScriptMode.OFF, ALL_LANGS, ScriptContext.MAPPING);
assertScriptModes(ScriptMode.ON, ALL_LANGS, new ScriptType[]{ScriptType.FILE}, ScriptContext.AGGS, ScriptContext.SEARCH, ScriptContext.UPDATE);
assertScriptModes(ScriptMode.SANDBOX, ALL_LANGS, new ScriptType[]{ScriptType.INDEXED, ScriptType.INLINE}, ScriptContext.AGGS, ScriptContext.SEARCH, ScriptContext.UPDATE);
}
@Test
public void testSandboxMappingGenericSettings() {
ImmutableSettings.Builder builder = ImmutableSettings.builder().put("script.mapping", ScriptMode.SANDBOX);
this.scriptModes = new ScriptModes(scriptEngines, builder.build(), Loggers.getLogger(ScriptModesTests.class));
assertScriptModesAllTypes(ScriptMode.SANDBOX, ALL_LANGS, ScriptContext.MAPPING);
assertScriptModes(ScriptMode.ON, ALL_LANGS, new ScriptType[]{ScriptType.FILE}, ScriptContext.AGGS, ScriptContext.SEARCH, ScriptContext.UPDATE);
assertScriptModes(ScriptMode.SANDBOX, ALL_LANGS, new ScriptType[]{ScriptType.INDEXED, ScriptType.INLINE}, ScriptContext.AGGS, ScriptContext.SEARCH, ScriptContext.UPDATE);
}
@Test
public void testEnableSearchGenericSettings() {
ImmutableSettings.Builder builder = ImmutableSettings.builder().put("script.search", randomFrom(ENABLE_VALUES));
this.scriptModes = new ScriptModes(scriptEngines, builder.build(), Loggers.getLogger(ScriptModesTests.class));
assertScriptModesAllTypes(ScriptMode.ON, ALL_LANGS, ScriptContext.SEARCH);
assertScriptModes(ScriptMode.ON, ALL_LANGS, new ScriptType[]{ScriptType.FILE}, ScriptContext.AGGS, ScriptContext.MAPPING, ScriptContext.UPDATE);
assertScriptModes(ScriptMode.SANDBOX, ALL_LANGS, new ScriptType[]{ScriptType.INDEXED, ScriptType.INLINE}, ScriptContext.AGGS, ScriptContext.MAPPING, ScriptContext.UPDATE);
}
@Test
public void testDisableSearchGenericSettings() {
ImmutableSettings.Builder builder = ImmutableSettings.builder().put("script.search", randomFrom(DISABLE_VALUES));
this.scriptModes = new ScriptModes(scriptEngines, builder.build(), Loggers.getLogger(ScriptModesTests.class));
assertScriptModesAllTypes(ScriptMode.OFF, ALL_LANGS, ScriptContext.SEARCH);
assertScriptModes(ScriptMode.ON, ALL_LANGS, new ScriptType[]{ScriptType.FILE}, ScriptContext.AGGS, ScriptContext.MAPPING, ScriptContext.UPDATE);
assertScriptModes(ScriptMode.SANDBOX, ALL_LANGS, new ScriptType[]{ScriptType.INDEXED, ScriptType.INLINE}, ScriptContext.AGGS, ScriptContext.MAPPING, ScriptContext.UPDATE);
}
@Test
public void testSandboxSearchGenericSettings() {
ImmutableSettings.Builder builder = ImmutableSettings.builder().put("script.search", ScriptMode.SANDBOX);
this.scriptModes = new ScriptModes(scriptEngines, builder.build(), Loggers.getLogger(ScriptModesTests.class));
assertScriptModesAllTypes(ScriptMode.SANDBOX, ALL_LANGS, ScriptContext.SEARCH);
assertScriptModes(ScriptMode.ON, ALL_LANGS, new ScriptType[]{ScriptType.FILE}, ScriptContext.AGGS, ScriptContext.MAPPING, ScriptContext.UPDATE);
assertScriptModes(ScriptMode.SANDBOX, ALL_LANGS, new ScriptType[]{ScriptType.INDEXED, ScriptType.INLINE}, ScriptContext.AGGS, ScriptContext.MAPPING, ScriptContext.UPDATE);
}
@Test
public void testEnableAggsGenericSettings() {
ImmutableSettings.Builder builder = ImmutableSettings.builder().put("script.aggs", randomFrom(ENABLE_VALUES));
this.scriptModes = new ScriptModes(scriptEngines, builder.build(), Loggers.getLogger(ScriptModesTests.class));
assertScriptModesAllTypes(ScriptMode.ON, ALL_LANGS, ScriptContext.AGGS);
assertScriptModes(ScriptMode.ON, ALL_LANGS, new ScriptType[]{ScriptType.FILE}, ScriptContext.SEARCH, ScriptContext.MAPPING, ScriptContext.UPDATE);
assertScriptModes(ScriptMode.SANDBOX, ALL_LANGS, new ScriptType[]{ScriptType.INDEXED, ScriptType.INLINE}, ScriptContext.SEARCH, ScriptContext.MAPPING, ScriptContext.UPDATE);
}
@Test
public void testDisableAggsGenericSettings() {
ImmutableSettings.Builder builder = ImmutableSettings.builder().put("script.aggs", randomFrom(DISABLE_VALUES));
this.scriptModes = new ScriptModes(scriptEngines, builder.build(), Loggers.getLogger(ScriptModesTests.class));
assertScriptModesAllTypes(ScriptMode.OFF, ALL_LANGS, ScriptContext.AGGS);
assertScriptModes(ScriptMode.ON, ALL_LANGS, new ScriptType[]{ScriptType.FILE}, ScriptContext.SEARCH, ScriptContext.MAPPING, ScriptContext.UPDATE);
assertScriptModes(ScriptMode.SANDBOX, ALL_LANGS, new ScriptType[]{ScriptType.INDEXED, ScriptType.INLINE}, ScriptContext.SEARCH, ScriptContext.MAPPING, ScriptContext.UPDATE);
}
@Test
public void testSandboxAggsGenericSettings() {
ImmutableSettings.Builder builder = ImmutableSettings.builder().put("script.aggs", ScriptMode.SANDBOX);
this.scriptModes = new ScriptModes(scriptEngines, builder.build(), Loggers.getLogger(ScriptModesTests.class));
assertScriptModesAllTypes(ScriptMode.SANDBOX, ALL_LANGS, ScriptContext.AGGS);
assertScriptModes(ScriptMode.ON, ALL_LANGS, new ScriptType[]{ScriptType.FILE}, ScriptContext.SEARCH, ScriptContext.MAPPING, ScriptContext.UPDATE);
assertScriptModes(ScriptMode.SANDBOX, ALL_LANGS, new ScriptType[]{ScriptType.INDEXED, ScriptType.INLINE}, ScriptContext.SEARCH, ScriptContext.MAPPING, ScriptContext.UPDATE);
}
@Test
public void testEnableUpdateGenericSettings() {
ImmutableSettings.Builder builder = ImmutableSettings.builder().put("script.update", randomFrom(ENABLE_VALUES));
this.scriptModes = new ScriptModes(scriptEngines, builder.build(), Loggers.getLogger(ScriptModesTests.class));
assertScriptModesAllTypes(ScriptMode.ON, ALL_LANGS, ScriptContext.UPDATE);
assertScriptModes(ScriptMode.ON, ALL_LANGS, new ScriptType[]{ScriptType.FILE}, ScriptContext.SEARCH, ScriptContext.MAPPING, ScriptContext.AGGS);
assertScriptModes(ScriptMode.SANDBOX, ALL_LANGS, new ScriptType[]{ScriptType.INDEXED, ScriptType.INLINE}, ScriptContext.SEARCH, ScriptContext.MAPPING, ScriptContext.AGGS);
}
@Test
public void testDisableUpdateGenericSettings() {
ImmutableSettings.Builder builder = ImmutableSettings.builder().put("script.update", randomFrom(DISABLE_VALUES));
this.scriptModes = new ScriptModes(scriptEngines, builder.build(), Loggers.getLogger(ScriptModesTests.class));
assertScriptModesAllTypes(ScriptMode.OFF, ALL_LANGS, ScriptContext.UPDATE);
assertScriptModes(ScriptMode.ON, ALL_LANGS, new ScriptType[]{ScriptType.FILE}, ScriptContext.SEARCH, ScriptContext.MAPPING, ScriptContext.AGGS);
assertScriptModes(ScriptMode.SANDBOX, ALL_LANGS, new ScriptType[]{ScriptType.INDEXED, ScriptType.INLINE}, ScriptContext.SEARCH, ScriptContext.MAPPING, ScriptContext.AGGS);
}
@Test
public void testSandboxUpdateGenericSettings() {
ImmutableSettings.Builder builder = ImmutableSettings.builder().put("script.update", ScriptMode.SANDBOX);
this.scriptModes = new ScriptModes(scriptEngines, builder.build(), Loggers.getLogger(ScriptModesTests.class));
assertScriptModesAllTypes(ScriptMode.SANDBOX, ALL_LANGS, ScriptContext.UPDATE);
assertScriptModes(ScriptMode.ON, ALL_LANGS, new ScriptType[]{ScriptType.FILE}, ScriptContext.SEARCH, ScriptContext.MAPPING, ScriptContext.AGGS);
assertScriptModes(ScriptMode.SANDBOX, ALL_LANGS, new ScriptType[]{ScriptType.INDEXED, ScriptType.INLINE}, ScriptContext.SEARCH, ScriptContext.MAPPING, ScriptContext.AGGS);
}
@Test
public void testMultipleScriptContextGenericSettings() {
ImmutableSettings.Builder builder = ImmutableSettings.builder().put("script.update", ScriptMode.SANDBOX)
.put("script.aggs", randomFrom(DISABLE_VALUES))
.put("script.search", randomFrom(ENABLE_VALUES));
this.scriptModes = new ScriptModes(scriptEngines, builder.build(), Loggers.getLogger(ScriptModesTests.class));
assertScriptModesAllTypes(ScriptMode.SANDBOX, ALL_LANGS, ScriptContext.UPDATE);
assertScriptModesAllTypes(ScriptMode.OFF, ALL_LANGS, ScriptContext.AGGS);
assertScriptModesAllTypes(ScriptMode.ON, ALL_LANGS, ScriptContext.SEARCH);
assertScriptModes(ScriptMode.ON, ALL_LANGS, new ScriptType[]{ScriptType.FILE}, ScriptContext.MAPPING);
assertScriptModes(ScriptMode.SANDBOX, ALL_LANGS, new ScriptType[]{ScriptType.INDEXED, ScriptType.INLINE}, ScriptContext.MAPPING);
}
@Test
public void testConflictingScriptTypeAndOpGenericSettings() {
ImmutableSettings.Builder builder = ImmutableSettings.builder().put("script.update", randomFrom(DISABLE_VALUES))
.put("script.indexed", randomFrom(ENABLE_VALUES)).put("script.inline", ScriptMode.SANDBOX);
//operations generic settings have precedence over script type generic settings
this.scriptModes = new ScriptModes(scriptEngines, builder.build(), Loggers.getLogger(ScriptModesTests.class));
assertScriptModesAllTypes(ScriptMode.OFF, ALL_LANGS, ScriptContext.UPDATE);
assertScriptModes(ScriptMode.ON, ALL_LANGS, new ScriptType[]{ScriptType.FILE, ScriptType.INDEXED}, ScriptContext.MAPPING, ScriptContext.AGGS, ScriptContext.SEARCH);
assertScriptModes(ScriptMode.SANDBOX, ALL_LANGS, new ScriptType[]{ScriptType.INLINE}, ScriptContext.MAPPING, ScriptContext.AGGS, ScriptContext.SEARCH);
}
@Test
public void testEngineSpecificSettings() {
ImmutableSettings.Builder builder = ImmutableSettings.builder()
.put(specificEngineOpSettings(GroovyScriptEngineService.NAME, ScriptType.INLINE, ScriptContext.MAPPING), randomFrom(DISABLE_VALUES))
.put(specificEngineOpSettings(GroovyScriptEngineService.NAME, ScriptType.INLINE, ScriptContext.UPDATE), randomFrom(DISABLE_VALUES));
ImmutableSet<String> groovyLangSet = ImmutableSet.of(GroovyScriptEngineService.NAME);
Set<String> allButGroovyLangSet = new HashSet<>(ALL_LANGS);
allButGroovyLangSet.remove(GroovyScriptEngineService.NAME);
this.scriptModes = new ScriptModes(scriptEngines, builder.build(), Loggers.getLogger(ScriptModesTests.class));
assertScriptModes(ScriptMode.OFF, groovyLangSet, new ScriptType[]{ScriptType.INLINE}, ScriptContext.MAPPING, ScriptContext.UPDATE);
assertScriptModes(ScriptMode.SANDBOX, groovyLangSet, new ScriptType[]{ScriptType.INLINE}, ScriptContext.SEARCH, ScriptContext.AGGS);
assertScriptModesAllOps(ScriptMode.SANDBOX, allButGroovyLangSet, ScriptType.INLINE);
assertScriptModesAllOps(ScriptMode.SANDBOX, ALL_LANGS, ScriptType.INDEXED);
assertScriptModesAllOps(ScriptMode.ON, ALL_LANGS, ScriptType.FILE);
}
@Test
public void testInteractionBetweenGenericAndEngineSpecificSettings() {
ImmutableSettings.Builder builder = ImmutableSettings.builder().put("script.inline", randomFrom(DISABLE_VALUES))
.put(specificEngineOpSettings(MustacheScriptEngineService.NAME, ScriptType.INLINE, ScriptContext.AGGS), randomFrom(ENABLE_VALUES))
.put(specificEngineOpSettings(MustacheScriptEngineService.NAME, ScriptType.INLINE, ScriptContext.SEARCH), randomFrom(ENABLE_VALUES));
ImmutableSet<String> mustacheLangSet = ImmutableSet.of(MustacheScriptEngineService.NAME);
Set<String> allButMustacheLangSet = new HashSet<>(ALL_LANGS);
allButMustacheLangSet.remove(MustacheScriptEngineService.NAME);
this.scriptModes = new ScriptModes(scriptEngines, builder.build(), Loggers.getLogger(ScriptModesTests.class));
assertScriptModes(ScriptMode.ON, mustacheLangSet, new ScriptType[]{ScriptType.INLINE}, ScriptContext.AGGS, ScriptContext.SEARCH);
assertScriptModes(ScriptMode.OFF, mustacheLangSet, new ScriptType[]{ScriptType.INLINE}, ScriptContext.MAPPING, ScriptContext.UPDATE);
assertScriptModesAllOps(ScriptMode.OFF, allButMustacheLangSet, ScriptType.INLINE);
assertScriptModesAllOps(ScriptMode.SANDBOX, ALL_LANGS, ScriptType.INDEXED);
assertScriptModesAllOps(ScriptMode.ON, ALL_LANGS, ScriptType.FILE);
}
@Test
public void testDefaultSettingsToString() {
assertAllSettingsWereChecked = false;
this.scriptModes = new ScriptModes(scriptEngines, ImmutableSettings.EMPTY, Loggers.getLogger(ScriptModesTests.class));
assertThat(scriptModes.toString(), equalTo(
"script.engine.custom.file.aggs: on\n" +
"script.engine.custom.file.mapping: on\n" +
"script.engine.custom.file.search: on\n" +
"script.engine.custom.file.update: on\n" +
"script.engine.custom.indexed.aggs: sandbox\n" +
"script.engine.custom.indexed.mapping: sandbox\n" +
"script.engine.custom.indexed.search: sandbox\n" +
"script.engine.custom.indexed.update: sandbox\n" +
"script.engine.custom.inline.aggs: sandbox\n" +
"script.engine.custom.inline.mapping: sandbox\n" +
"script.engine.custom.inline.search: sandbox\n" +
"script.engine.custom.inline.update: sandbox\n" +
"script.engine.expression.file.aggs: on\n" +
"script.engine.expression.file.mapping: on\n" +
"script.engine.expression.file.search: on\n" +
"script.engine.expression.file.update: on\n" +
"script.engine.expression.indexed.aggs: sandbox\n" +
"script.engine.expression.indexed.mapping: sandbox\n" +
"script.engine.expression.indexed.search: sandbox\n" +
"script.engine.expression.indexed.update: sandbox\n" +
"script.engine.expression.inline.aggs: sandbox\n" +
"script.engine.expression.inline.mapping: sandbox\n" +
"script.engine.expression.inline.search: sandbox\n" +
"script.engine.expression.inline.update: sandbox\n" +
"script.engine.groovy.file.aggs: on\n" +
"script.engine.groovy.file.mapping: on\n" +
"script.engine.groovy.file.search: on\n" +
"script.engine.groovy.file.update: on\n" +
"script.engine.groovy.indexed.aggs: sandbox\n" +
"script.engine.groovy.indexed.mapping: sandbox\n" +
"script.engine.groovy.indexed.search: sandbox\n" +
"script.engine.groovy.indexed.update: sandbox\n" +
"script.engine.groovy.inline.aggs: sandbox\n" +
"script.engine.groovy.inline.mapping: sandbox\n" +
"script.engine.groovy.inline.search: sandbox\n" +
"script.engine.groovy.inline.update: sandbox\n" +
"script.engine.mustache.file.aggs: on\n" +
"script.engine.mustache.file.mapping: on\n" +
"script.engine.mustache.file.search: on\n" +
"script.engine.mustache.file.update: on\n" +
"script.engine.mustache.indexed.aggs: sandbox\n" +
"script.engine.mustache.indexed.mapping: sandbox\n" +
"script.engine.mustache.indexed.search: sandbox\n" +
"script.engine.mustache.indexed.update: sandbox\n" +
"script.engine.mustache.inline.aggs: sandbox\n" +
"script.engine.mustache.inline.mapping: sandbox\n" +
"script.engine.mustache.inline.search: sandbox\n" +
"script.engine.mustache.inline.update: sandbox\n" +
"script.engine.test.file.aggs: on\n" +
"script.engine.test.file.mapping: on\n" +
"script.engine.test.file.search: on\n" +
"script.engine.test.file.update: on\n" +
"script.engine.test.indexed.aggs: sandbox\n" +
"script.engine.test.indexed.mapping: sandbox\n" +
"script.engine.test.indexed.search: sandbox\n" +
"script.engine.test.indexed.update: sandbox\n" +
"script.engine.test.inline.aggs: sandbox\n" +
"script.engine.test.inline.mapping: sandbox\n" +
"script.engine.test.inline.search: sandbox\n" +
"script.engine.test.inline.update: sandbox\n"));
}
private void assertScriptModesAllOps(ScriptMode expectedScriptMode, Set<String> langs, ScriptType... scriptTypes) {
assertScriptModes(expectedScriptMode, langs, scriptTypes, ScriptContext.values());
}
private void assertScriptModesAllTypes(ScriptMode expectedScriptMode, Set<String> langs, ScriptContext... scriptContexts) {
assertScriptModes(expectedScriptMode, langs, ScriptType.values(), scriptContexts);
}
private void assertScriptModes(ScriptMode expectedScriptMode, Set<String> langs, ScriptType[] scriptTypes, ScriptContext... scriptContexts) {
assert langs.size() > 0;
assert scriptTypes.length > 0;
assert scriptContexts.length > 0;
for (String lang : langs) {
for (ScriptType scriptType : scriptTypes) {
for (ScriptContext scriptContext : scriptContexts) {
assertThat(lang + "." + scriptType + "." + scriptContext + " doesn't have the expected value", scriptModes.getScriptMode(lang, scriptType, scriptContext), equalTo(expectedScriptMode));
checkedSettings.add(lang + "." + scriptType + "." + scriptContext);
}
}
}
}
private static String specificEngineOpSettings(String lang, ScriptType scriptType, ScriptContext scriptContext) {
return ScriptModes.ENGINE_SETTINGS_PREFIX + "." + lang + "." + scriptType + "." + scriptContext;
}
static ImmutableMap<String, ScriptEngineService> buildScriptEnginesByLangMap(Set<ScriptEngineService> scriptEngines) {
ImmutableMap.Builder<String, ScriptEngineService> builder = ImmutableMap.builder();
for (ScriptEngineService scriptEngine : scriptEngines) {
for (String type : scriptEngine.types()) {
builder.put(type, scriptEngine);
}
}
return builder.build();
}
private static class CustomScriptEngineService implements ScriptEngineService {
@Override
public String[] types() {
return new String[]{"custom", "test"};
}
@Override
public String[] extensions() {
return new String[0];
}
@Override
public boolean sandboxed() {
return false;
}
@Override
public Object compile(String script) {
return null;
}
@Override
public ExecutableScript executable(Object compiledScript, @Nullable Map<String, Object> vars) {
return null;
}
@Override
public SearchScript search(Object compiledScript, SearchLookup lookup, @Nullable Map<String, Object> vars) {
return null;
}
@Override
public Object execute(Object compiledScript, Map<String, Object> vars) {
return null;
}
@Override
public Object unwrap(Object value) {
return null;
}
@Override
public void close() {
}
@Override
public void scriptRemoved(@Nullable CompiledScript script) {
}
}
}

View File

@ -22,11 +22,14 @@ import com.google.common.collect.ImmutableSet;
import org.elasticsearch.ElasticsearchIllegalArgumentException;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.io.Streams;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.node.settings.NodeSettingsService;
import org.elasticsearch.script.ScriptService.ScriptType;
import org.elasticsearch.script.expression.ExpressionScriptEngineService;
import org.elasticsearch.script.groovy.GroovyScriptEngineService;
import org.elasticsearch.script.mustache.MustacheScriptEngineService;
import org.elasticsearch.search.lookup.SearchLookup;
import org.elasticsearch.test.ElasticsearchTestCase;
import org.elasticsearch.watcher.ResourceWatcherService;
@ -36,7 +39,9 @@ import org.junit.Test;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
import static org.hamcrest.Matchers.*;
@ -47,31 +52,50 @@ import static org.hamcrest.Matchers.*;
public class ScriptServiceTests extends ElasticsearchTestCase {
private ResourceWatcherService resourceWatcherService;
private Set<ScriptEngineService> scriptEngineServices;
private Map<String, ScriptEngineService> scriptEnginesByLangMap;
private ScriptService scriptService;
private Path scriptsFilePath;
private Settings baseSettings;
private static final Map<ScriptType, ScriptMode> DEFAULT_SCRIPT_MODES = new HashMap<>();
static {
DEFAULT_SCRIPT_MODES.put(ScriptType.FILE, ScriptMode.ON);
DEFAULT_SCRIPT_MODES.put(ScriptType.INDEXED, ScriptMode.SANDBOX);
DEFAULT_SCRIPT_MODES.put(ScriptType.INLINE, ScriptMode.SANDBOX);
}
@Before
public void setup() throws IOException {
Path genericConfigFolder = newTempDirPath();
Settings settings = settingsBuilder()
baseSettings = settingsBuilder()
.put("path.conf", genericConfigFolder)
.build();
Environment environment = new Environment(settings);
resourceWatcherService = new ResourceWatcherService(settings, null);
resourceWatcherService = new ResourceWatcherService(baseSettings, null);
scriptEngineServices = ImmutableSet.of(new TestEngineService(), new GroovyScriptEngineService(baseSettings),
new ExpressionScriptEngineService(baseSettings), new MustacheScriptEngineService(baseSettings));
scriptEnginesByLangMap = ScriptModesTests.buildScriptEnginesByLangMap(scriptEngineServices);
logger.info("--> setup script service");
scriptService = new ScriptService(settings, environment,
ImmutableSet.of(new TestEngineService(), new GroovyScriptEngineService(settings), new ExpressionScriptEngineService(settings)),
resourceWatcherService, new NodeSettingsService(settings));
scriptsFilePath = genericConfigFolder.resolve("scripts");
Files.createDirectories(scriptsFilePath);
}
private void buildScriptService(Settings additionalSettings) throws IOException {
Settings finalSettings = ImmutableSettings.builder().put(baseSettings).put(additionalSettings).build();
Environment environment = new Environment(finalSettings);
scriptService = new ScriptService(finalSettings, environment, scriptEngineServices, resourceWatcherService, new NodeSettingsService(finalSettings)) {
@Override
String getScriptFromIndex(String scriptLang, String id) {
//mock the script that gets retrieved from an index
return "100";
}
};
}
@Test
public void testScriptsWithoutExtensions() throws IOException {
buildScriptService(ImmutableSettings.EMPTY);
logger.info("--> setup two test files one with extension and another without");
Path testFileNoExt = scriptsFilePath.resolve("test_no_ext");
Path testFileWithExt = scriptsFilePath.resolve("test_script.tst");
@ -80,7 +104,7 @@ public class ScriptServiceTests extends ElasticsearchTestCase {
resourceWatcherService.notifyNow();
logger.info("--> verify that file with extension was correctly processed");
CompiledScript compiledScript = scriptService.compile("test", "test_script", ScriptService.ScriptType.FILE);
CompiledScript compiledScript = scriptService.compile("test", "test_script", ScriptType.FILE, ScriptContext.SEARCH);
assertThat(compiledScript.compiled(), equalTo((Object) "compiled_test_file"));
logger.info("--> delete both files");
@ -90,7 +114,7 @@ public class ScriptServiceTests extends ElasticsearchTestCase {
logger.info("--> verify that file with extension was correctly removed");
try {
scriptService.compile("test", "test_script", ScriptService.ScriptType.FILE);
scriptService.compile("test", "test_script", ScriptType.FILE, ScriptContext.SEARCH);
fail("the script test_script should no longer exist");
} catch (ElasticsearchIllegalArgumentException ex) {
assertThat(ex.getMessage(), containsString("Unable to find on disk script test_script"));
@ -99,36 +123,261 @@ public class ScriptServiceTests extends ElasticsearchTestCase {
@Test
public void testScriptsSameNameDifferentLanguage() throws IOException {
Path groovyScriptPath = scriptsFilePath.resolve("script.groovy");
Path expScriptPath = scriptsFilePath.resolve("script.expression");
Streams.copy("10".getBytes("UTF-8"), Files.newOutputStream(groovyScriptPath));
Streams.copy("20".getBytes("UTF-8"), Files.newOutputStream(expScriptPath));
resourceWatcherService.notifyNow();
CompiledScript groovyScript = scriptService.compile(GroovyScriptEngineService.NAME, "script", ScriptService.ScriptType.FILE);
buildScriptService(ImmutableSettings.EMPTY);
createFileScripts("groovy", "expression");
CompiledScript groovyScript = scriptService.compile(GroovyScriptEngineService.NAME, "file_script", ScriptType.FILE, randomFrom(ScriptContext.values()));
assertThat(groovyScript.lang(), equalTo(GroovyScriptEngineService.NAME));
CompiledScript expressionScript = scriptService.compile(ExpressionScriptEngineService.NAME, "script", ScriptService.ScriptType.FILE);
CompiledScript expressionScript = scriptService.compile(ExpressionScriptEngineService.NAME, "file_script", ScriptType.FILE, randomFrom(ScriptContext.values()));
assertThat(expressionScript.lang(), equalTo(ExpressionScriptEngineService.NAME));
}
@Test
public void testInlineScriptCompiledOnceMultipleLangAcronyms() throws IOException {
CompiledScript compiledScript1 = scriptService.compile("test", "test_script", ScriptService.ScriptType.INLINE);
CompiledScript compiledScript2 = scriptService.compile("test2", "test_script", ScriptService.ScriptType.INLINE);
buildScriptService(ImmutableSettings.EMPTY);
CompiledScript compiledScript1 = scriptService.compile("test", "script", ScriptType.INLINE, randomFrom(ScriptContext.values()));
CompiledScript compiledScript2 = scriptService.compile("test2", "script", ScriptType.INLINE, randomFrom(ScriptContext.values()));
assertThat(compiledScript1, sameInstance(compiledScript2));
}
@Test
public void testFileScriptCompiledOnceMultipleLangAcronyms() throws IOException {
Path scriptPath = scriptsFilePath.resolve("test_script.tst");
Streams.copy("test_file".getBytes("UTF-8"), Files.newOutputStream(scriptPath));
resourceWatcherService.notifyNow();
CompiledScript compiledScript1 = scriptService.compile("test", "test_script", ScriptService.ScriptType.FILE);
CompiledScript compiledScript2 = scriptService.compile("test2", "test_script", ScriptService.ScriptType.FILE);
buildScriptService(ImmutableSettings.EMPTY);
createFileScripts("test");
CompiledScript compiledScript1 = scriptService.compile("test", "file_script", ScriptType.FILE, randomFrom(ScriptContext.values()));
CompiledScript compiledScript2 = scriptService.compile("test2", "file_script", ScriptType.FILE, randomFrom(ScriptContext.values()));
assertThat(compiledScript1, sameInstance(compiledScript2));
}
@Test
public void testDefaultBehaviourFineGrainedSettings() throws IOException {
ImmutableSettings.Builder builder = ImmutableSettings.builder();
//rarely inject the default settings, which have no effect
if (rarely()) {
builder.put("script.file", randomFrom(ScriptModesTests.ENABLE_VALUES));
}
if (rarely()) {
builder.put("script.indexed", ScriptMode.SANDBOX);
}
if (rarely()) {
builder.put("script.inline", ScriptMode.SANDBOX);
}
buildScriptService(builder.build());
createFileScripts("groovy", "expression", "mustache", "test");
for (ScriptContext scriptContext : ScriptContext.values()) {
//groovy is not sandboxed, only file scripts are enabled by default
assertCompileRejected(GroovyScriptEngineService.NAME, "script", ScriptType.INLINE, scriptContext);
assertCompileRejected(GroovyScriptEngineService.NAME, "script", ScriptType.INDEXED, scriptContext);
assertCompileAccepted(GroovyScriptEngineService.NAME, "file_script", ScriptType.FILE, scriptContext);
//expression engine is sandboxed, all scripts are enabled by default
assertCompileAccepted(ExpressionScriptEngineService.NAME, "script", ScriptType.INLINE, scriptContext);
assertCompileAccepted(ExpressionScriptEngineService.NAME, "script", ScriptType.INDEXED, scriptContext);
assertCompileAccepted(ExpressionScriptEngineService.NAME, "file_script", ScriptType.FILE, scriptContext);
//mustache engine is sandboxed, all scripts are enabled by default
assertCompileAccepted(MustacheScriptEngineService.NAME, "script", ScriptType.INLINE, scriptContext);
assertCompileAccepted(MustacheScriptEngineService.NAME, "script", ScriptType.INDEXED, scriptContext);
assertCompileAccepted(MustacheScriptEngineService.NAME, "file_script", ScriptType.FILE, scriptContext);
//custom engine is sandboxed, all scripts are enabled by default
assertCompileAccepted("test", "script", ScriptType.INLINE, scriptContext);
assertCompileAccepted("test", "script", ScriptType.INDEXED, scriptContext);
assertCompileAccepted("test", "file_script", ScriptType.FILE, scriptContext);
}
}
@Test
public void testDisableDynamicDeprecatedSetting() throws IOException {
ImmutableSettings.Builder builder = ImmutableSettings.builder();
ScriptService.DynamicScriptDisabling dynamicScriptDisabling = randomFrom(ScriptService.DynamicScriptDisabling.values());
switch(dynamicScriptDisabling) {
case EVERYTHING_ALLOWED:
builder.put("script.disable_dynamic", randomFrom("false", "none"));
break;
case ONLY_DISK_ALLOWED:
builder.put("script.disable_dynamic", randomFrom("true", "all"));
break;
case SANDBOXED_ONLY:
builder.put("script.disable_dynamic", randomFrom("sandbox", "sandboxed"));
break;
}
buildScriptService(builder.build());
createFileScripts("groovy", "expression", "mustache", "test");
for (ScriptContext scriptContext : ScriptContext.values()) {
for (ScriptEngineService scriptEngineService : scriptEngineServices) {
for (String lang : scriptEngineService.types()) {
assertCompileAccepted(lang, "file_script", ScriptType.FILE, scriptContext);
switch (dynamicScriptDisabling) {
case EVERYTHING_ALLOWED:
assertCompileAccepted(lang, "script", ScriptType.INDEXED, scriptContext);
assertCompileAccepted(lang, "script", ScriptType.INLINE, scriptContext);
break;
case ONLY_DISK_ALLOWED:
assertCompileRejected(lang, "script", ScriptType.INDEXED, scriptContext);
assertCompileRejected(lang, "script", ScriptType.INLINE, scriptContext);
break;
case SANDBOXED_ONLY:
if (scriptEngineService.sandboxed()) {
assertCompileAccepted(lang, "script", ScriptType.INDEXED, scriptContext);
assertCompileAccepted(lang, "script", ScriptType.INLINE, scriptContext);
} else {
assertCompileRejected(lang, "script", ScriptType.INDEXED, scriptContext);
assertCompileRejected(lang, "script", ScriptType.INLINE, scriptContext);
}
break;
}
}
}
}
}
@Test
public void testFineGrainedSettings() throws IOException {
//collect the fine-grained settings to set for this run
int numScriptSettings = randomIntBetween(0, ScriptType.values().length);
Map<ScriptType, ScriptMode> scriptSourceSettings = new HashMap<>();
for (int i = 0; i < numScriptSettings; i++) {
ScriptType scriptType;
do {
scriptType = randomFrom(ScriptType.values());
} while (scriptSourceSettings.containsKey(scriptType));
scriptSourceSettings.put(scriptType, randomFrom(ScriptMode.values()));
}
int numScriptContextSettings = randomIntBetween(0, ScriptContext.values().length);
Map<ScriptContext, ScriptMode> scriptContextSettings = new HashMap<>();
for (int i = 0; i < numScriptContextSettings; i++) {
ScriptContext scriptContext;
do {
scriptContext = randomFrom(ScriptContext.values());
} while (scriptContextSettings.containsKey(scriptContext));
scriptContextSettings.put(scriptContext, randomFrom(ScriptMode.values()));
}
int numEngineSettings = randomIntBetween(0, 10);
Map<String, ScriptMode> engineSettings = new HashMap<>();
for (int i = 0; i < numEngineSettings; i++) {
String settingKey;
do {
ScriptEngineService[] scriptEngineServices = this.scriptEngineServices.toArray(new ScriptEngineService[this.scriptEngineServices.size()]);
ScriptEngineService scriptEngineService = randomFrom(scriptEngineServices);
ScriptType scriptType = randomFrom(ScriptType.values());
ScriptContext scriptContext = randomFrom(ScriptContext.values());
settingKey = scriptEngineService.types()[0] + "." + scriptType + "." + scriptContext;
} while(engineSettings.containsKey(settingKey));
engineSettings.put(settingKey, randomFrom(ScriptMode.values()));
}
//set the selected fine-grained settings
ImmutableSettings.Builder builder = ImmutableSettings.builder();
for (Map.Entry<ScriptType, ScriptMode> entry : scriptSourceSettings.entrySet()) {
switch (entry.getValue()) {
case ON:
builder.put(ScriptModes.SCRIPT_SETTINGS_PREFIX + entry.getKey(), randomFrom(ScriptModesTests.ENABLE_VALUES));
break;
case OFF:
builder.put(ScriptModes.SCRIPT_SETTINGS_PREFIX + entry.getKey(), randomFrom(ScriptModesTests.DISABLE_VALUES));
break;
case SANDBOX:
builder.put(ScriptModes.SCRIPT_SETTINGS_PREFIX + entry.getKey(), ScriptMode.SANDBOX);
break;
}
}
for (Map.Entry<ScriptContext, ScriptMode> entry : scriptContextSettings.entrySet()) {
switch (entry.getValue()) {
case ON:
builder.put(ScriptModes.SCRIPT_SETTINGS_PREFIX + entry.getKey(), randomFrom(ScriptModesTests.ENABLE_VALUES));
break;
case OFF:
builder.put(ScriptModes.SCRIPT_SETTINGS_PREFIX + entry.getKey(), randomFrom(ScriptModesTests.DISABLE_VALUES));
break;
case SANDBOX:
builder.put(ScriptModes.SCRIPT_SETTINGS_PREFIX + entry.getKey(), ScriptMode.SANDBOX);
break;
}
}
for (Map.Entry<String, ScriptMode> entry : engineSettings.entrySet()) {
int delimiter = entry.getKey().indexOf('.');
String part1 = entry.getKey().substring(0, delimiter);
String part2 = entry.getKey().substring(delimiter + 1);
String lang = randomFrom(scriptEnginesByLangMap.get(part1).types());
switch (entry.getValue()) {
case ON:
builder.put(ScriptModes.ENGINE_SETTINGS_PREFIX + "." + lang + "." + part2, randomFrom(ScriptModesTests.ENABLE_VALUES));
break;
case OFF:
builder.put(ScriptModes.ENGINE_SETTINGS_PREFIX + "." + lang + "." + part2, randomFrom(ScriptModesTests.DISABLE_VALUES));
break;
case SANDBOX:
builder.put(ScriptModes.ENGINE_SETTINGS_PREFIX + "." + lang + "." + part2, ScriptMode.SANDBOX);
break;
}
}
buildScriptService(builder.build());
createFileScripts("groovy", "expression", "mustache", "test");
for (ScriptEngineService scriptEngineService : scriptEngineServices) {
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";
for (ScriptContext scriptContext : ScriptContext.values()) {
//fallback mechanism: 1) engine specific settings 2) op based settings 3) source based settings
ScriptMode scriptMode = engineSettings.get(scriptEngineService.types()[0] + "." + scriptType + "." + scriptContext);
;
if (scriptMode == null) {
scriptMode = scriptContextSettings.get(scriptContext);
}
if (scriptMode == null) {
scriptMode = scriptSourceSettings.get(scriptType);
}
if (scriptMode == null) {
scriptMode = DEFAULT_SCRIPT_MODES.get(scriptType);
}
for (String lang : scriptEngineService.types()) {
switch (scriptMode) {
case ON:
assertCompileAccepted(lang, script, scriptType, scriptContext);
break;
case OFF:
assertCompileRejected(lang, script, scriptType, scriptContext);
break;
case SANDBOX:
if (scriptEngineService.sandboxed()) {
assertCompileAccepted(lang, script, scriptType, scriptContext);
} else {
assertCompileRejected(lang, script, scriptType, scriptContext);
}
break;
}
}
}
}
}
}
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(lang, script, scriptType, scriptContext);
fail("compile should have been rejected for lang [" + lang + "], script_type [" + scriptType + "], scripted_op [" + scriptContext + "]");
} catch(ScriptException e) {
//all good
}
}
private void assertCompileAccepted(String lang, String script, ScriptType scriptType, ScriptContext scriptContext) {
assertThat(scriptService.compile(lang, script, scriptType, scriptContext), notNullValue());
}
public static class TestEngineService implements ScriptEngineService {
@Override

View File

@ -117,7 +117,8 @@ public abstract class ElasticsearchSingleNodeTest extends ElasticsearchTestCase
.put("node.name", nodeName())
.put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 1)
.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0)
.put("script.disable_dynamic", false)
.put("script.inline", "on")
.put("script.indexed", "on")
.put(EsExecutors.PROCESSORS, 1) // limit the number of threads created
.put("http.enabled", false)
.put("config.ignore_system_properties", true) // make sure we get what we set :)

View File

@ -269,7 +269,8 @@ public final class InternalTestCluster extends TestCluster {
builder.put("http.port", basePort+101 + "-" + (basePort+200));
builder.put("config.ignore_system_properties", true);
builder.put("node.mode", NODE_MODE);
builder.put("script.disable_dynamic", false);
builder.put("script.indexed", "on");
builder.put("script.inline", "on");
builder.put("http.pipelining", enableHttpPipelining);
builder.put("plugins." + PluginsService.LOAD_PLUGIN_FROM_CLASSPATH, false);
builder.put(NodeEnvironment.SETTING_CUSTOM_DATA_PATH_ENABLED, true);