Change Namespace for Stored Script to Only Use Id (elastic/elasticsearch#4387)

Changes the behavior in x-pack necessary to support the elasticsearch change elastic/elasticsearch#22206.

Original commit: elastic/x-pack-elasticsearch@916e72e263
This commit is contained in:
Jack Conradson 2017-01-31 13:28:03 -08:00 committed by GitHub
parent 81171bb6ff
commit 7f0ecc4b30
12 changed files with 102 additions and 52 deletions

View File

@ -37,9 +37,12 @@ public class TextTemplate implements ToXContent {
public TextTemplate(String template, @Nullable XContentType contentType, ScriptType type,
@Nullable Map<String, Object> params) {
Map<String, String> options = new HashMap<>();
if (contentType != null) {
options.put(Script.CONTENT_TYPE_OPTION, contentType.mediaType());
Map<String, String> options = null;
if (type == ScriptType.INLINE) {
options = new HashMap<>();
if (contentType != null) {
options.put(Script.CONTENT_TYPE_OPTION, contentType.mediaType());
}
}
if (params == null) {
params = new HashMap<>();
@ -62,7 +65,7 @@ public class TextTemplate implements ToXContent {
}
public XContentType getContentType() {
if (script == null) {
if (script == null || script.getOptions() == null) {
return null;
}
@ -112,7 +115,15 @@ public class TextTemplate implements ToXContent {
if (parser.currentToken() == XContentParser.Token.VALUE_STRING) {
return new TextTemplate(parser.text());
} else {
return new TextTemplate(Script.parse(parser, Script.DEFAULT_TEMPLATE_LANG));
Script template = Script.parse(parser, Script.DEFAULT_TEMPLATE_LANG);
// for deprecation of stored script namespaces the default lang is ignored,
// so the template lang must be set for a stored script
if (template.getType() == ScriptType.STORED) {
template = new Script(ScriptType.STORED, Script.DEFAULT_TEMPLATE_LANG, template.getIdOrCode(), template.getParams());
}
return new TextTemplate(template);
}
}
}

View File

@ -13,6 +13,7 @@ import org.elasticsearch.script.CompiledScript;
import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.xpack.watcher.Watcher;
import java.util.Collections;
@ -34,8 +35,7 @@ public class TextTemplateEngine extends AbstractComponent {
}
String template = textTemplate.getTemplate();
XContentType contentType = detectContentType(template);
Map<String, String> compileParams = compileParams(contentType);
String mediaType = compileParams(detectContentType(template));
template = trimContentType(textTemplate);
Map<String, Object> mergedModel = new HashMap<>();
@ -44,12 +44,18 @@ public class TextTemplateEngine extends AbstractComponent {
}
mergedModel.putAll(model);
Map<String, String> options = new HashMap<>();
if (textTemplate.getContentType() != null) {
options.put(Script.CONTENT_TYPE_OPTION, textTemplate.getContentType().mediaType());
Map<String, String> options = null;
if (textTemplate.getType() == ScriptType.INLINE) {
options = new HashMap<>();
if (textTemplate.getScript() != null && textTemplate.getScript().getOptions() != null) {
options.putAll(textTemplate.getScript().getOptions());
}
options.put(Script.CONTENT_TYPE_OPTION, mediaType);
}
Script script = new Script(textTemplate.getType(), "mustache", template, options, mergedModel);
CompiledScript compiledScript = service.compile(script, Watcher.SCRIPT_CONTEXT, compileParams);
CompiledScript compiledScript = service.compile(script, Watcher.SCRIPT_CONTEXT);
ExecutableScript executable = service.executable(compiledScript, model);
Object result = executable.run();
if (result instanceof BytesReference) {
@ -88,11 +94,11 @@ public class TextTemplateEngine extends AbstractComponent {
return null;
}
private Map<String, String> compileParams(XContentType contentType) {
private String compileParams(XContentType contentType) {
if (contentType == XContentType.JSON) {
return Collections.singletonMap("content_type", "application/json");
return "application/json";
} else {
return Collections.singletonMap("content_type", "text/plain");
return "text/plain";
}
}
}

View File

@ -45,7 +45,7 @@ public final class ScriptCondition extends Condition {
super(TYPE);
this.scriptService = scriptService;
this.script = script;
compiledScript = scriptService.compile(script, Watcher.SCRIPT_CONTEXT, Collections.emptyMap());
compiledScript = scriptService.compile(script, Watcher.SCRIPT_CONTEXT);
}
public Script getScript() {

View File

@ -247,6 +247,13 @@ public class WatcherSearchTemplateRequest implements ToXContentObject {
DEFAULT_INDICES_OPTIONS);
} else if (TEMPLATE_FIELD.match(currentFieldName)) {
template = Script.parse(parser, Script.DEFAULT_TEMPLATE_LANG);
// for deprecation of stored script namespaces the default lang is ignored,
// so the template lang must be set for a stored script
if (template.getType() == ScriptType.STORED) {
template = new Script(
ScriptType.STORED, Script.DEFAULT_TEMPLATE_LANG, template.getIdOrCode(), template.getParams());
}
} else {
throw new ElasticsearchParseException("could not read search request. unexpected object field [" +
currentFieldName + "]");

View File

@ -52,9 +52,8 @@ public class WatcherSearchTemplateService extends AbstractComponent {
watcherContextParams.putAll(source.getParams());
}
// Templates are always of lang mustache:
Script template = new Script(source.getType(), "mustache", source.getIdOrCode(), source.getOptions(), watcherContextParams
);
CompiledScript compiledScript = scriptService.compile(template, Watcher.SCRIPT_CONTEXT, Collections.emptyMap());
Script template = new Script(source.getType(), "mustache", source.getIdOrCode(), source.getOptions(), watcherContextParams);
CompiledScript compiledScript = scriptService.compile(template, Watcher.SCRIPT_CONTEXT);
return (BytesReference) scriptService.executable(compiledScript, template.getParams()).run();
}

View File

@ -34,7 +34,7 @@ public class ExecutableScriptTransform extends ExecutableTransform<ScriptTransfo
this.scriptService = scriptService;
Script script = transform.getScript();
// try to compile so we catch syntax errors early
scriptService.compile(script, Watcher.SCRIPT_CONTEXT, Collections.emptyMap());
scriptService.compile(script, Watcher.SCRIPT_CONTEXT);
}
@Override
@ -54,7 +54,7 @@ public class ExecutableScriptTransform extends ExecutableTransform<ScriptTransfo
model.putAll(script.getParams());
}
model.putAll(createCtxModel(ctx, payload));
CompiledScript compiledScript = scriptService.compile(script, Watcher.SCRIPT_CONTEXT, Collections.emptyMap());
CompiledScript compiledScript = scriptService.compile(script, Watcher.SCRIPT_CONTEXT);
ExecutableScript executable = scriptService.executable(compiledScript, model);
Object value = executable.run();
if (value instanceof Map) {

View File

@ -58,8 +58,9 @@ public class TextTemplateTests extends ESTestCase {
ScriptType type = randomFrom(ScriptType.values());
CompiledScript compiledScript = mock(CompiledScript.class);
when(service.compile(new Script(type, lang, templateText, merged), Watcher.SCRIPT_CONTEXT,
Collections.singletonMap("content_type", "text/plain"))).thenReturn(compiledScript);
when(service.compile(new Script(type, lang, templateText,
type == ScriptType.INLINE ? Collections.singletonMap("content_type", "text/plain") : null,
merged), Watcher.SCRIPT_CONTEXT)).thenReturn(compiledScript);
when(service.executable(compiledScript, model)).thenReturn(script);
when(script.run()).thenReturn("rendered_text");
@ -71,15 +72,16 @@ public class TextTemplateTests extends ESTestCase {
String templateText = "_template";
Map<String, Object> params = singletonMap("key", "param_val");
Map<String, Object> model = singletonMap("key", "model_val");
ScriptType scriptType = randomFrom(ScriptType.values());
ScriptType type = randomFrom(ScriptType.values());
CompiledScript compiledScript = mock(CompiledScript.class);
when(service.compile(new Script(scriptType, lang, templateText, model), Watcher.SCRIPT_CONTEXT,
Collections.singletonMap("content_type", "text/plain"))).thenReturn(compiledScript);
when(service.compile(new Script(type, lang, templateText,
type == ScriptType.INLINE ? Collections.singletonMap("content_type", "text/plain") : null,
model), Watcher.SCRIPT_CONTEXT)).thenReturn(compiledScript);
when(service.executable(compiledScript, model)).thenReturn(script);
when(script.run()).thenReturn("rendered_text");
TextTemplate template = templateBuilder(scriptType, templateText, params);
TextTemplate template = templateBuilder(type, templateText, params);
assertThat(engine.render(template, model), is("rendered_text"));
}
@ -88,8 +90,9 @@ public class TextTemplateTests extends ESTestCase {
Map<String, Object> model = singletonMap("key", "model_val");
CompiledScript compiledScript = mock(CompiledScript.class);
when(service.compile(new Script(ScriptType.INLINE, lang, templateText, model), Watcher.SCRIPT_CONTEXT,
Collections.singletonMap("content_type", "text/plain"))).thenReturn(compiledScript);
when(service.compile(new Script(ScriptType.INLINE, lang, templateText,
Collections.singletonMap("content_type", "text/plain"), model), Watcher.SCRIPT_CONTEXT))
.thenReturn(compiledScript);
when(service.executable(compiledScript, model)).thenReturn(script);
when(script.run()).thenReturn("rendered_text");

View File

@ -240,7 +240,7 @@ public class ScriptConditionTests extends ESTestCase {
default:
throw illegalArgument("unsupported script type [{}]", scriptType);
}
if (scriptLang != null) {
if (scriptLang != null && scriptType != ScriptType.STORED) {
builder.field("lang", scriptLang);
}
return builder.endObject();

View File

@ -261,9 +261,9 @@ public class BasicWatcherTests extends AbstractWatcherIntegrationTestCase {
public void testConditionSearchWithIndexedTemplate() throws Exception {
SearchSourceBuilder searchSourceBuilder = searchSource().query(matchQuery("level", "a"));
assertAcked(client().admin().cluster().preparePutStoredScript()
.setScriptLang("mustache")
.setLang("mustache")
.setId("my-template")
.setSource(jsonBuilder().startObject().field("template").value(searchSourceBuilder).endObject().bytes())
.setContent(jsonBuilder().startObject().field("template").value(searchSourceBuilder).endObject().bytes())
.get());
Script template = new Script(ScriptType.STORED, "mustache", "my-template", Collections.emptyMap());

View File

@ -126,8 +126,8 @@ public class TransformIntegrationTests extends AbstractWatcherIntegrationTestCas
logger.info("testing script transform with an indexed script");
assertAcked(client().admin().cluster().preparePutStoredScript()
.setId("my-script")
.setScriptLang("painless")
.setSource(new BytesArray("{\"script\" : \"['key3' : ctx.payload.key1 + ctx.payload.key2]\"}"))
.setLang("painless")
.setContent(new BytesArray("{\"script\" : \"['key3' : ctx.payload.key1 + ctx.payload.key2]\"}"))
.get());
script = new Script(ScriptType.STORED, "painless", "my-script", Collections.emptyMap());
} else {

View File

@ -61,7 +61,7 @@ public class ScriptTransformTests extends ESTestCase {
Map<String, Object> params = Collections.emptyMap();
Script script = new Script(type, "_lang", "_script", params);
CompiledScript compiledScript = mock(CompiledScript.class);
when(service.compile(script, Watcher.SCRIPT_CONTEXT, Collections.emptyMap())).thenReturn(compiledScript);
when(service.compile(script, Watcher.SCRIPT_CONTEXT)).thenReturn(compiledScript);
ExecutableScriptTransform transform = new ExecutableScriptTransform(new ScriptTransform(script), logger, service);
WatchExecutionContext ctx = mockExecutionContext("_name", EMPTY_PAYLOAD);
@ -89,7 +89,7 @@ public class ScriptTransformTests extends ESTestCase {
Map<String, Object> params = Collections.emptyMap();
Script script = new Script(type, "_lang", "_script", params);
CompiledScript compiledScript = mock(CompiledScript.class);
when(service.compile(script, Watcher.SCRIPT_CONTEXT, Collections.emptyMap())).thenReturn(compiledScript);
when(service.compile(script, Watcher.SCRIPT_CONTEXT)).thenReturn(compiledScript);
ExecutableScriptTransform transform = new ExecutableScriptTransform(new ScriptTransform(script), logger, service);
WatchExecutionContext ctx = mockExecutionContext("_name", EMPTY_PAYLOAD);
@ -115,7 +115,7 @@ public class ScriptTransformTests extends ESTestCase {
Map<String, Object> params = Collections.emptyMap();
Script script = new Script(type, "_lang", "_script", params);
CompiledScript compiledScript = mock(CompiledScript.class);
when(service.compile(script, Watcher.SCRIPT_CONTEXT, Collections.emptyMap())).thenReturn(compiledScript);
when(service.compile(script, Watcher.SCRIPT_CONTEXT)).thenReturn(compiledScript);
ExecutableScriptTransform transform = new ExecutableScriptTransform(new ScriptTransform(script), logger, service);
WatchExecutionContext ctx = mockExecutionContext("_name", EMPTY_PAYLOAD);
@ -141,14 +141,16 @@ public class ScriptTransformTests extends ESTestCase {
ScriptType type = randomFrom(ScriptType.values());
XContentBuilder builder = jsonBuilder().startObject();
builder.field(scriptTypeField(type), "_script");
builder.field("lang", "_lang");
if (type != ScriptType.STORED) {
builder.field("lang", "_lang");
}
builder.startObject("params").field("key", "value").endObject();
builder.endObject();
XContentParser parser = createParser(builder);
parser.nextToken();
ExecutableScriptTransform transform = new ScriptTransformFactory(Settings.EMPTY, service).parseExecutable("_id", parser);
Script script = new Script(type, "_lang", "_script", singletonMap("key", "value"));
Script script = new Script(type, type == ScriptType.STORED ? null : "_lang", "_script", singletonMap("key", "value"));
assertThat(transform.transform().getScript(), equalTo(script));
}
@ -167,7 +169,7 @@ public class ScriptTransformTests extends ESTestCase {
String errorMessage = "expected error message";
ScriptException scriptException = new ScriptException(errorMessage, new RuntimeException("foo"),
Collections.emptyList(), "whatever", "whatever");
when(scriptService.compile(anyObject(), eq(Watcher.SCRIPT_CONTEXT), anyObject())).thenThrow(scriptException);
when(scriptService.compile(anyObject(), eq(Watcher.SCRIPT_CONTEXT))).thenThrow(scriptException);
ScriptTransformFactory transformFactory = new ScriptTransformFactory(Settings.builder().build(), scriptService);
@ -198,7 +200,13 @@ public class ScriptTransformTests extends ESTestCase {
parser.nextToken();
ScriptTransform scriptCondition = transformFactory.parseTransform("_watch", parser);
Exception e = expectThrows(IllegalArgumentException.class, () -> transformFactory.createExecutable(scriptCondition));
assertThat(e.getMessage(), containsString("script_lang not supported [not_a_valid_lang]"));
if (scriptType == ScriptType.STORED) {
assertThat(e.getMessage(), containsString("unable to get stored script with unsupported lang [not_a_valid_lang]"));
assertWarnings("specifying the field [lang] for executing stored scripts is deprecated;" +
" use only the field [stored] to specify an <id>");
} else {
assertThat(e.getMessage(), containsString("script_lang not supported [not_a_valid_lang]"));
}
}
static String scriptTypeField(ScriptType type) {

View File

@ -2,17 +2,22 @@
# See https://github.com/elastic/x-plugins/issues/4237
---
"Test transform scripts are updated on execution":
- skip:
features: warnings
- do:
cluster.health:
wait_for_status: yellow
- do:
put_script:
id: transform-script
lang: painless
lang: transform-script
body: >
{
"script":"return [ 'email': 'foo@bar.org' ]"
"script":{
"lang": "painless",
"code":"return [ 'email': 'foo@bar.org' ]"
}
}
- do:
@ -53,11 +58,14 @@
- do:
put_script:
id: transform-script
lang: painless
lang: transform-script
body: >
{
"script":"return [ 'email': 'foo@example.org' ]"
"script":
{
"lang": "painless",
"code":"return [ 'email': 'foo@example.org' ]"
}
}
- do:
@ -69,17 +77,23 @@
---
"Test condition scripts are updated on execution":
- skip:
features: warnings
- do:
cluster.health:
wait_for_status: yellow
- do:
put_script:
id: condition-script
lang: painless
lang: condition-script
body: >
{
"script":"return false"
"script":
{
"lang": "painless",
"code": "return false"
}
}
- do:
@ -120,11 +134,13 @@
- do:
put_script:
id: condition-script
lang: painless
lang: condition-script
body: >
{
"script":"return true"
"script": {
"lang": "painless",
"code": "return true"
}
}
- do: