mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-03-25 01:19:02 +00:00
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:
parent
442f539802
commit
d9d1e6a67a
@ -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()
|
||||
|
@ -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
|
||||
]
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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...
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
|
38
src/main/java/org/elasticsearch/script/ScriptContext.java
Normal file
38
src/main/java/org/elasticsearch/script/ScriptContext.java
Normal 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);
|
||||
}
|
||||
}
|
56
src/main/java/org/elasticsearch/script/ScriptMode.java
Normal file
56
src/main/java/org/elasticsearch/script/ScriptMode.java
Normal 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);
|
||||
}
|
||||
}
|
209
src/main/java/org/elasticsearch/script/ScriptModes.java
Normal file
209
src/main/java/org/elasticsearch/script/ScriptModes.java
Normal 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();
|
||||
}
|
||||
}
|
@ -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) {
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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 + "]");
|
||||
|
@ -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 {
|
||||
|
@ -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"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
567
src/test/java/org/elasticsearch/script/ScriptModesTests.java
Normal file
567
src/test/java/org/elasticsearch/script/ScriptModesTests.java
Normal 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) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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 :)
|
||||
|
@ -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);
|
||||
|
@ -0,0 +1 @@
|
||||
20
|
Loading…
x
Reference in New Issue
Block a user