Scripting: Remove support for deprecated StoredScript contexts (#31394)
Removes support for storing scripts without the usual json around the script. So You can no longer do: ``` POST _scripts/<templatename> { "query": { "match": { "title": "{{query_string}}" } } } ``` and must instead do: ``` POST _scripts/<templatename> { "script": { "lang": "mustache", "source": { "query": { "match": { "title": "{{query_string}}" } } } } } ``` This improves error reporting when you attempt to store a script but don't quite get the syntax right. Before, there was a good chance that we'd think of it as a "raw" template and just store it. Now we won't do that. Nice.
This commit is contained in:
parent
894fb97ad7
commit
40b822c878
|
@ -75,3 +75,7 @@ will be for such settings to be copied on such operations. To enable users in
|
||||||
`copy_settings` parameter was added on the REST layer. As this behavior will be
|
`copy_settings` parameter was added on the REST layer. As this behavior will be
|
||||||
the only behavior in 8.0.0, this parameter is deprecated in 7.0.0 for removal in
|
the only behavior in 8.0.0, this parameter is deprecated in 7.0.0 for removal in
|
||||||
8.0.0.
|
8.0.0.
|
||||||
|
|
||||||
|
==== The deprecated stored script contexts have now been removed
|
||||||
|
When putting stored scripts, support for storing them with the deprecated `template` context or without a context is
|
||||||
|
now removed. Scripts must be stored using the `script` context as mentioned in the documentation.
|
||||||
|
|
|
@ -23,7 +23,6 @@ import org.elasticsearch.action.admin.cluster.storedscripts.GetStoredScriptRespo
|
||||||
import org.elasticsearch.action.bulk.BulkRequestBuilder;
|
import org.elasticsearch.action.bulk.BulkRequestBuilder;
|
||||||
import org.elasticsearch.action.search.SearchRequest;
|
import org.elasticsearch.action.search.SearchRequest;
|
||||||
import org.elasticsearch.common.bytes.BytesArray;
|
import org.elasticsearch.common.bytes.BytesArray;
|
||||||
import org.elasticsearch.common.bytes.BytesReference;
|
|
||||||
import org.elasticsearch.common.xcontent.XContentType;
|
import org.elasticsearch.common.xcontent.XContentType;
|
||||||
import org.elasticsearch.common.xcontent.json.JsonXContent;
|
import org.elasticsearch.common.xcontent.json.JsonXContent;
|
||||||
import org.elasticsearch.plugins.Plugin;
|
import org.elasticsearch.plugins.Plugin;
|
||||||
|
@ -152,25 +151,22 @@ public class SearchTemplateIT extends ESSingleNodeTestCase {
|
||||||
public void testIndexedTemplateClient() throws Exception {
|
public void testIndexedTemplateClient() throws Exception {
|
||||||
assertAcked(client().admin().cluster().preparePutStoredScript()
|
assertAcked(client().admin().cluster().preparePutStoredScript()
|
||||||
.setId("testTemplate")
|
.setId("testTemplate")
|
||||||
.setContent(new BytesArray("{" +
|
.setContent(
|
||||||
"\"template\":{" +
|
new BytesArray(
|
||||||
" \"query\":{" +
|
"{" +
|
||||||
" \"match\":{" +
|
" \"script\": {" +
|
||||||
" \"theField\" : \"{{fieldParam}}\"}" +
|
" \"lang\": \"mustache\"," +
|
||||||
" }" +
|
" \"source\": {" +
|
||||||
"}" +
|
" \"query\": {" +
|
||||||
"}"), XContentType.JSON));
|
" \"match\": {" +
|
||||||
|
" \"theField\": \"{{fieldParam}}\"" +
|
||||||
|
" }" +
|
||||||
assertAcked(client().admin().cluster().preparePutStoredScript()
|
" }" +
|
||||||
.setId("testTemplate").setContent(new BytesArray("{" +
|
" }" +
|
||||||
"\"template\":{" +
|
" }" +
|
||||||
" \"query\":{" +
|
"}"
|
||||||
" \"match\":{" +
|
),
|
||||||
" \"theField\" : \"{{fieldParam}}\"}" +
|
XContentType.JSON));
|
||||||
" }" +
|
|
||||||
"}" +
|
|
||||||
"}"), XContentType.JSON));
|
|
||||||
|
|
||||||
GetStoredScriptResponse getResponse = client().admin().cluster()
|
GetStoredScriptResponse getResponse = client().admin().cluster()
|
||||||
.prepareGetStoredScript("testTemplate").get();
|
.prepareGetStoredScript("testTemplate").get();
|
||||||
|
@ -198,41 +194,32 @@ public class SearchTemplateIT extends ESSingleNodeTestCase {
|
||||||
|
|
||||||
getResponse = client().admin().cluster().prepareGetStoredScript("testTemplate").get();
|
getResponse = client().admin().cluster().prepareGetStoredScript("testTemplate").get();
|
||||||
assertNull(getResponse.getSource());
|
assertNull(getResponse.getSource());
|
||||||
assertWarnings("the template context is now deprecated. Specify templates in a \"script\" element.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testIndexedTemplate() throws Exception {
|
public void testIndexedTemplate() throws Exception {
|
||||||
assertAcked(client().admin().cluster().preparePutStoredScript()
|
|
||||||
.setId("1a")
|
String script =
|
||||||
.setContent(new BytesArray("{" +
|
"{" +
|
||||||
"\"template\":{" +
|
" \"script\": {" +
|
||||||
" \"query\":{" +
|
" \"lang\": \"mustache\"," +
|
||||||
" \"match\":{" +
|
" \"source\": {" +
|
||||||
" \"theField\" : \"{{fieldParam}}\"}" +
|
" \"query\": {" +
|
||||||
" }" +
|
" \"match\": {" +
|
||||||
"}" +
|
" \"theField\": \"{{fieldParam}}\"" +
|
||||||
"}"
|
" }" +
|
||||||
), XContentType.JSON)
|
" }" +
|
||||||
|
" }" +
|
||||||
|
" }" +
|
||||||
|
"}";
|
||||||
|
|
||||||
|
assertAcked(
|
||||||
|
client().admin().cluster().preparePutStoredScript().setId("1a").setContent(new BytesArray(script), XContentType.JSON)
|
||||||
);
|
);
|
||||||
assertAcked(client().admin().cluster().preparePutStoredScript()
|
assertAcked(
|
||||||
.setId("2")
|
client().admin().cluster().preparePutStoredScript().setId("2").setContent(new BytesArray(script), XContentType.JSON)
|
||||||
.setContent(new BytesArray("{" +
|
|
||||||
"\"template\":{" +
|
|
||||||
" \"query\":{" +
|
|
||||||
" \"match\":{" +
|
|
||||||
" \"theField\" : \"{{fieldParam}}\"}" +
|
|
||||||
" }" +
|
|
||||||
"}" +
|
|
||||||
"}"), XContentType.JSON)
|
|
||||||
);
|
);
|
||||||
assertAcked(client().admin().cluster().preparePutStoredScript()
|
assertAcked(
|
||||||
.setId("3")
|
client().admin().cluster().preparePutStoredScript().setId("3").setContent(new BytesArray(script), XContentType.JSON)
|
||||||
.setContent(new BytesArray("{" +
|
|
||||||
"\"template\":{" +
|
|
||||||
" \"match\":{" +
|
|
||||||
" \"theField\" : \"{{fieldParam}}\"}" +
|
|
||||||
" }" +
|
|
||||||
"}"), XContentType.JSON)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
BulkRequestBuilder bulkRequestBuilder = client().prepareBulk();
|
BulkRequestBuilder bulkRequestBuilder = client().prepareBulk();
|
||||||
|
@ -268,7 +255,6 @@ public class SearchTemplateIT extends ESSingleNodeTestCase {
|
||||||
.setScript("2").setScriptType(ScriptType.STORED).setScriptParams(templateParams)
|
.setScript("2").setScriptType(ScriptType.STORED).setScriptParams(templateParams)
|
||||||
.get();
|
.get();
|
||||||
assertHitCount(searchResponse.getResponse(), 1);
|
assertHitCount(searchResponse.getResponse(), 1);
|
||||||
assertWarnings("the template context is now deprecated. Specify templates in a \"script\" element.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Relates to #10397
|
// Relates to #10397
|
||||||
|
@ -282,13 +268,27 @@ public class SearchTemplateIT extends ESSingleNodeTestCase {
|
||||||
client().admin().indices().prepareRefresh().get();
|
client().admin().indices().prepareRefresh().get();
|
||||||
|
|
||||||
int iterations = randomIntBetween(2, 11);
|
int iterations = randomIntBetween(2, 11);
|
||||||
|
String query =
|
||||||
|
"{" +
|
||||||
|
" \"script\": {" +
|
||||||
|
" \"lang\": \"mustache\"," +
|
||||||
|
" \"source\": {" +
|
||||||
|
" \"query\": {" +
|
||||||
|
" \"match_phrase_prefix\": {" +
|
||||||
|
" \"searchtext\": {" +
|
||||||
|
" \"query\": \"{{P_Keyword1}}\"," +
|
||||||
|
" \"slop\": {{slop}}" +
|
||||||
|
" }" +
|
||||||
|
" }" +
|
||||||
|
" }" +
|
||||||
|
" }" +
|
||||||
|
" }" +
|
||||||
|
"}";
|
||||||
for (int i = 1; i < iterations; i++) {
|
for (int i = 1; i < iterations; i++) {
|
||||||
assertAcked(client().admin().cluster().preparePutStoredScript()
|
assertAcked(client().admin().cluster().preparePutStoredScript()
|
||||||
.setId("git01")
|
.setId("git01")
|
||||||
.setContent(new BytesArray(
|
.setContent(new BytesArray(query.replace("{{slop}}", Integer.toString(-1))), XContentType.JSON)
|
||||||
"{\"template\":{\"query\": {\"match_phrase_prefix\": {\"searchtext\": {\"query\": \"{{P_Keyword1}}\","
|
);
|
||||||
+ "\"slop\": -1}}}}}"),
|
|
||||||
XContentType.JSON));
|
|
||||||
|
|
||||||
GetStoredScriptResponse getResponse = client().admin().cluster().prepareGetStoredScript("git01").get();
|
GetStoredScriptResponse getResponse = client().admin().cluster().prepareGetStoredScript("git01").get();
|
||||||
assertNotNull(getResponse.getSource());
|
assertNotNull(getResponse.getSource());
|
||||||
|
@ -304,8 +304,8 @@ public class SearchTemplateIT extends ESSingleNodeTestCase {
|
||||||
|
|
||||||
assertAcked(client().admin().cluster().preparePutStoredScript()
|
assertAcked(client().admin().cluster().preparePutStoredScript()
|
||||||
.setId("git01")
|
.setId("git01")
|
||||||
.setContent(new BytesArray("{\"query\": {\"match_phrase_prefix\": {\"searchtext\": {\"query\": \"{{P_Keyword1}}\"," +
|
.setContent(new BytesArray(query.replace("{{slop}}", Integer.toString(0))), XContentType.JSON)
|
||||||
"\"slop\": 0}}}}"), XContentType.JSON));
|
);
|
||||||
|
|
||||||
SearchTemplateResponse searchResponse = new SearchTemplateRequestBuilder(client())
|
SearchTemplateResponse searchResponse = new SearchTemplateRequestBuilder(client())
|
||||||
.setRequest(new SearchRequest("testindex").types("test"))
|
.setRequest(new SearchRequest("testindex").types("test"))
|
||||||
|
@ -313,16 +313,30 @@ public class SearchTemplateIT extends ESSingleNodeTestCase {
|
||||||
.get();
|
.get();
|
||||||
assertHitCount(searchResponse.getResponse(), 1);
|
assertHitCount(searchResponse.getResponse(), 1);
|
||||||
}
|
}
|
||||||
assertWarnings("the template context is now deprecated. Specify templates in a \"script\" element.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testIndexedTemplateWithArray() throws Exception {
|
public void testIndexedTemplateWithArray() throws Exception {
|
||||||
String multiQuery = "{\"query\":{\"terms\":{\"theField\":[\"{{#fieldParam}}\",\"{{.}}\",\"{{/fieldParam}}\"]}}}";
|
String multiQuery =
|
||||||
|
"{\n" +
|
||||||
|
" \"script\": {\n" +
|
||||||
|
" \"lang\": \"mustache\",\n" +
|
||||||
|
" \"source\": {\n" +
|
||||||
|
" \"query\": {\n" +
|
||||||
|
" \"terms\": {\n" +
|
||||||
|
" \"theField\": [\n" +
|
||||||
|
" \"{{#fieldParam}}\",\n" +
|
||||||
|
" \"{{.}}\",\n" +
|
||||||
|
" \"{{/fieldParam}}\"\n" +
|
||||||
|
" ]\n" +
|
||||||
|
" }\n" +
|
||||||
|
" }\n" +
|
||||||
|
" }\n" +
|
||||||
|
" }\n" +
|
||||||
|
"}";
|
||||||
assertAcked(
|
assertAcked(
|
||||||
client().admin().cluster().preparePutStoredScript()
|
client().admin().cluster().preparePutStoredScript()
|
||||||
.setId("4")
|
.setId("4")
|
||||||
.setContent(BytesReference.bytes(jsonBuilder().startObject().field("template", multiQuery).endObject()),
|
.setContent(new BytesArray(multiQuery), XContentType.JSON)
|
||||||
XContentType.JSON)
|
|
||||||
);
|
);
|
||||||
BulkRequestBuilder bulkRequestBuilder = client().prepareBulk();
|
BulkRequestBuilder bulkRequestBuilder = client().prepareBulk();
|
||||||
bulkRequestBuilder.add(client().prepareIndex("test", "type", "1").setSource("{\"theField\":\"foo\"}", XContentType.JSON));
|
bulkRequestBuilder.add(client().prepareIndex("test", "type", "1").setSource("{\"theField\":\"foo\"}", XContentType.JSON));
|
||||||
|
@ -342,7 +356,6 @@ public class SearchTemplateIT extends ESSingleNodeTestCase {
|
||||||
.setScript("4").setScriptType(ScriptType.STORED).setScriptParams(arrayTemplateParams)
|
.setScript("4").setScriptType(ScriptType.STORED).setScriptParams(arrayTemplateParams)
|
||||||
.get();
|
.get();
|
||||||
assertHitCount(searchResponse.getResponse(), 5);
|
assertHitCount(searchResponse.getResponse(), 5);
|
||||||
assertWarnings("the template context is now deprecated. Specify templates in a \"script\" element.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,11 +114,7 @@ public class GetStoredScriptResponse extends ActionResponse implements StatusToX
|
||||||
super.readFrom(in);
|
super.readFrom(in);
|
||||||
|
|
||||||
if (in.readBoolean()) {
|
if (in.readBoolean()) {
|
||||||
if (in.getVersion().onOrAfter(Version.V_5_3_0)) {
|
source = new StoredScriptSource(in);
|
||||||
source = new StoredScriptSource(in);
|
|
||||||
} else {
|
|
||||||
source = new StoredScriptSource(in.readString());
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
source = null;
|
source = null;
|
||||||
}
|
}
|
||||||
|
@ -136,12 +132,7 @@ public class GetStoredScriptResponse extends ActionResponse implements StatusToX
|
||||||
out.writeBoolean(false);
|
out.writeBoolean(false);
|
||||||
} else {
|
} else {
|
||||||
out.writeBoolean(true);
|
out.writeBoolean(true);
|
||||||
|
source.writeTo(out);
|
||||||
if (out.getVersion().onOrAfter(Version.V_5_3_0)) {
|
|
||||||
source.writeTo(out);
|
|
||||||
} else {
|
|
||||||
out.writeString(source.getSource());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (out.getVersion().onOrAfter(Version.V_6_4_0)) {
|
if (out.getVersion().onOrAfter(Version.V_6_4_0)) {
|
||||||
out.writeString(id);
|
out.writeString(id);
|
||||||
|
|
|
@ -19,15 +19,12 @@
|
||||||
|
|
||||||
package org.elasticsearch.script;
|
package org.elasticsearch.script;
|
||||||
|
|
||||||
import org.elasticsearch.Version;
|
|
||||||
import org.elasticsearch.action.admin.cluster.storedscripts.GetStoredScriptResponse;
|
|
||||||
import org.elasticsearch.cluster.AbstractDiffable;
|
import org.elasticsearch.cluster.AbstractDiffable;
|
||||||
import org.elasticsearch.cluster.ClusterState;
|
import org.elasticsearch.cluster.ClusterState;
|
||||||
import org.elasticsearch.cluster.Diff;
|
import org.elasticsearch.cluster.Diff;
|
||||||
import org.elasticsearch.common.ParseField;
|
import org.elasticsearch.common.ParseField;
|
||||||
import org.elasticsearch.common.ParsingException;
|
import org.elasticsearch.common.ParsingException;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.bytes.BytesArray;
|
|
||||||
import org.elasticsearch.common.bytes.BytesReference;
|
import org.elasticsearch.common.bytes.BytesReference;
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
|
@ -69,16 +66,6 @@ public class StoredScriptSource extends AbstractDiffable<StoredScriptSource> imp
|
||||||
*/
|
*/
|
||||||
public static final ParseField SCRIPT_PARSE_FIELD = new ParseField("script");
|
public static final ParseField SCRIPT_PARSE_FIELD = new ParseField("script");
|
||||||
|
|
||||||
/**
|
|
||||||
* Standard {@link ParseField} for outer level of stored script source.
|
|
||||||
*/
|
|
||||||
public static final ParseField TEMPLATE_PARSE_FIELD = new ParseField("template");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Standard {@link ParseField} for query on the inner field.
|
|
||||||
*/
|
|
||||||
public static final ParseField TEMPLATE_NO_WRAPPER_PARSE_FIELD = new ParseField("query");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Standard {@link ParseField} for lang on the inner level.
|
* Standard {@link ParseField} for lang on the inner level.
|
||||||
*/
|
*/
|
||||||
|
@ -194,26 +181,6 @@ public class StoredScriptSource extends AbstractDiffable<StoredScriptSource> imp
|
||||||
PARSER.declareField(Builder::setOptions, XContentParser::mapStrings, OPTIONS_PARSE_FIELD, ValueType.OBJECT);
|
PARSER.declareField(Builder::setOptions, XContentParser::mapStrings, OPTIONS_PARSE_FIELD, ValueType.OBJECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static StoredScriptSource parseRemaining(Token token, XContentParser parser) throws IOException {
|
|
||||||
try (XContentBuilder builder = XContentFactory.jsonBuilder()) {
|
|
||||||
if (token != Token.START_OBJECT) {
|
|
||||||
builder.startObject();
|
|
||||||
builder.copyCurrentStructure(parser);
|
|
||||||
builder.endObject();
|
|
||||||
} else {
|
|
||||||
builder.copyCurrentStructure(parser);
|
|
||||||
}
|
|
||||||
|
|
||||||
String source = Strings.toString(builder);
|
|
||||||
|
|
||||||
if (source == null || source.isEmpty()) {
|
|
||||||
DEPRECATION_LOGGER.deprecated("empty templates should no longer be used");
|
|
||||||
}
|
|
||||||
|
|
||||||
return new StoredScriptSource(Script.DEFAULT_TEMPLATE_LANG, source, Collections.emptyMap());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This will parse XContent into a {@link StoredScriptSource}. The following formats can be parsed:
|
* This will parse XContent into a {@link StoredScriptSource}. The following formats can be parsed:
|
||||||
*
|
*
|
||||||
|
@ -271,27 +238,8 @@ public class StoredScriptSource extends AbstractDiffable<StoredScriptSource> imp
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* The simple template format:
|
* Note that the "source" parameter can also handle template parsing including from
|
||||||
*
|
* a complex JSON object.
|
||||||
* {@code
|
|
||||||
* {
|
|
||||||
* "query" : ...
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* The complex template format:
|
|
||||||
*
|
|
||||||
* {@code
|
|
||||||
* {
|
|
||||||
* "template": {
|
|
||||||
* "query" : ...
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* Note that templates can be handled as both strings and complex JSON objects.
|
|
||||||
* Also templates may be part of the 'source' parameter in a script. The Parser
|
|
||||||
* can handle this case as well.
|
|
||||||
*
|
*
|
||||||
* @param content The content from the request to be parsed as described above.
|
* @param content The content from the request to be parsed as described above.
|
||||||
* @return The parsed {@link StoredScriptSource}.
|
* @return The parsed {@link StoredScriptSource}.
|
||||||
|
@ -316,7 +264,7 @@ public class StoredScriptSource extends AbstractDiffable<StoredScriptSource> imp
|
||||||
|
|
||||||
if (token != Token.FIELD_NAME) {
|
if (token != Token.FIELD_NAME) {
|
||||||
throw new ParsingException(parser.getTokenLocation(), "unexpected token [" + token + ", expected [" +
|
throw new ParsingException(parser.getTokenLocation(), "unexpected token [" + token + ", expected [" +
|
||||||
SCRIPT_PARSE_FIELD.getPreferredName() + ", " + TEMPLATE_PARSE_FIELD.getPreferredName());
|
SCRIPT_PARSE_FIELD.getPreferredName() + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
String name = parser.currentName();
|
String name = parser.currentName();
|
||||||
|
@ -329,28 +277,9 @@ public class StoredScriptSource extends AbstractDiffable<StoredScriptSource> imp
|
||||||
} else {
|
} else {
|
||||||
throw new ParsingException(parser.getTokenLocation(), "unexpected token [" + token + "], expected [{, <source>]");
|
throw new ParsingException(parser.getTokenLocation(), "unexpected token [" + token + "], expected [{, <source>]");
|
||||||
}
|
}
|
||||||
} else if (TEMPLATE_PARSE_FIELD.getPreferredName().equals(name)) {
|
|
||||||
|
|
||||||
DEPRECATION_LOGGER.deprecated("the template context is now deprecated. Specify templates in a \"script\" element.");
|
|
||||||
|
|
||||||
token = parser.nextToken();
|
|
||||||
if (token == Token.VALUE_STRING) {
|
|
||||||
String source = parser.text();
|
|
||||||
|
|
||||||
if (source == null || source.isEmpty()) {
|
|
||||||
DEPRECATION_LOGGER.deprecated("empty templates should no longer be used");
|
|
||||||
}
|
|
||||||
|
|
||||||
return new StoredScriptSource(Script.DEFAULT_TEMPLATE_LANG, source, Collections.emptyMap());
|
|
||||||
} else {
|
|
||||||
return parseRemaining(token, parser);
|
|
||||||
}
|
|
||||||
} else if (TEMPLATE_NO_WRAPPER_PARSE_FIELD.getPreferredName().equals(name)) {
|
|
||||||
DEPRECATION_LOGGER.deprecated("the template context is now deprecated. Specify templates in a \"script\" element.");
|
|
||||||
return parseRemaining(token, parser);
|
|
||||||
} else {
|
} else {
|
||||||
DEPRECATION_LOGGER.deprecated("scripts should not be stored without a context. Specify them in a \"script\" element.");
|
throw new ParsingException(parser.getTokenLocation(), "unexpected field [" + name + "], expected [" +
|
||||||
return parseRemaining(token, parser);
|
SCRIPT_PARSE_FIELD.getPreferredName() + "]");
|
||||||
}
|
}
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
throw new UncheckedIOException(ioe);
|
throw new UncheckedIOException(ioe);
|
||||||
|
@ -397,16 +326,6 @@ public class StoredScriptSource extends AbstractDiffable<StoredScriptSource> imp
|
||||||
private final String source;
|
private final String source;
|
||||||
private final Map<String, String> options;
|
private final Map<String, String> options;
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for use with {@link GetStoredScriptResponse}
|
|
||||||
* to support the deprecated stored script namespace.
|
|
||||||
*/
|
|
||||||
public StoredScriptSource(String source) {
|
|
||||||
this.lang = null;
|
|
||||||
this.source = Objects.requireNonNull(source);
|
|
||||||
this.options = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Standard StoredScriptSource constructor.
|
* Standard StoredScriptSource constructor.
|
||||||
* @param lang The language to compile the script with. Must not be {@code null}.
|
* @param lang The language to compile the script with. Must not be {@code null}.
|
||||||
|
@ -426,35 +345,24 @@ public class StoredScriptSource extends AbstractDiffable<StoredScriptSource> imp
|
||||||
* only the source parameter will be read in as a bytes reference.
|
* only the source parameter will be read in as a bytes reference.
|
||||||
*/
|
*/
|
||||||
public StoredScriptSource(StreamInput in) throws IOException {
|
public StoredScriptSource(StreamInput in) throws IOException {
|
||||||
if (in.getVersion().onOrAfter(Version.V_5_3_0)) {
|
this.lang = in.readString();
|
||||||
this.lang = in.readString();
|
this.source = in.readString();
|
||||||
this.source = in.readString();
|
@SuppressWarnings("unchecked")
|
||||||
@SuppressWarnings("unchecked")
|
Map<String, String> options = (Map<String, String>)(Map)in.readMap();
|
||||||
Map<String, String> options = (Map<String, String>)(Map)in.readMap();
|
this.options = options;
|
||||||
this.options = options;
|
|
||||||
} else {
|
|
||||||
this.lang = null;
|
|
||||||
this.source = in.readBytesReference().utf8ToString();
|
|
||||||
this.options = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes a {@link StoredScriptSource} to a stream. Version 5.3+ will write
|
* Writes a {@link StoredScriptSource} to a stream. Will write
|
||||||
* all of the lang, source, and options parameters. For versions prior to 5.3,
|
* all of the lang, source, and options parameters.
|
||||||
* only the source parameter will be read in as a bytes reference.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void writeTo(StreamOutput out) throws IOException {
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
if (out.getVersion().onOrAfter(Version.V_5_3_0)) {
|
out.writeString(lang);
|
||||||
out.writeString(lang);
|
out.writeString(source);
|
||||||
out.writeString(source);
|
@SuppressWarnings("unchecked")
|
||||||
@SuppressWarnings("unchecked")
|
Map<String, Object> options = (Map<String, Object>)(Map)this.options;
|
||||||
Map<String, Object> options = (Map<String, Object>)(Map)this.options;
|
out.writeMap(options);
|
||||||
out.writeMap(options);
|
|
||||||
} else {
|
|
||||||
out.writeBytesReference(new BytesArray(source));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -77,14 +77,12 @@ public class ScriptMetaDataTests extends AbstractSerializingTestCase<ScriptMetaD
|
||||||
ScriptMetaData.Builder builder = new ScriptMetaData.Builder(null);
|
ScriptMetaData.Builder builder = new ScriptMetaData.Builder(null);
|
||||||
|
|
||||||
XContentBuilder sourceBuilder = XContentFactory.jsonBuilder();
|
XContentBuilder sourceBuilder = XContentFactory.jsonBuilder();
|
||||||
sourceBuilder.startObject().startObject("template").field("field", "value").endObject().endObject();
|
sourceBuilder.startObject().startObject("script")
|
||||||
builder.storeScript("template", StoredScriptSource.parse(BytesReference.bytes(sourceBuilder), sourceBuilder.contentType()));
|
.field("lang", "_lang")
|
||||||
assertWarnings("the template context is now deprecated. Specify templates in a \"script\" element.");
|
.startObject("source").field("field", "value").endObject()
|
||||||
|
.endObject().endObject();
|
||||||
sourceBuilder = XContentFactory.jsonBuilder();
|
builder.storeScript("source_template", StoredScriptSource.parse(BytesReference.bytes(sourceBuilder),
|
||||||
sourceBuilder.startObject().field("template", "value").endObject();
|
sourceBuilder.contentType()));
|
||||||
builder.storeScript("template_field", StoredScriptSource.parse(BytesReference.bytes(sourceBuilder), sourceBuilder.contentType()));
|
|
||||||
assertWarnings("the template context is now deprecated. Specify templates in a \"script\" element.");
|
|
||||||
|
|
||||||
sourceBuilder = XContentFactory.jsonBuilder();
|
sourceBuilder = XContentFactory.jsonBuilder();
|
||||||
sourceBuilder.startObject().startObject("script").field("lang", "_lang").field("source", "_source").endObject().endObject();
|
sourceBuilder.startObject().startObject("script").field("lang", "_lang").field("source", "_source").endObject().endObject();
|
||||||
|
@ -92,26 +90,25 @@ public class ScriptMetaDataTests extends AbstractSerializingTestCase<ScriptMetaD
|
||||||
|
|
||||||
ScriptMetaData scriptMetaData = builder.build();
|
ScriptMetaData scriptMetaData = builder.build();
|
||||||
assertEquals("_source", scriptMetaData.getStoredScript("script").getSource());
|
assertEquals("_source", scriptMetaData.getStoredScript("script").getSource());
|
||||||
assertEquals("{\"field\":\"value\"}", scriptMetaData.getStoredScript("template").getSource());
|
assertEquals("{\"field\":\"value\"}", scriptMetaData.getStoredScript("source_template").getSource());
|
||||||
assertEquals("value", scriptMetaData.getStoredScript("template_field").getSource());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testDiff() throws Exception {
|
public void testDiff() throws Exception {
|
||||||
ScriptMetaData.Builder builder = new ScriptMetaData.Builder(null);
|
ScriptMetaData.Builder builder = new ScriptMetaData.Builder(null);
|
||||||
builder.storeScript("1", StoredScriptSource.parse(new BytesArray("{\"foo\":\"abc\"}"), XContentType.JSON));
|
builder.storeScript("1", StoredScriptSource.parse(
|
||||||
assertWarnings("scripts should not be stored without a context. Specify them in a \"script\" element.");
|
new BytesArray("{\"script\":{\"lang\":\"mustache\",\"source\":{\"foo\":\"abc\"}}}"), XContentType.JSON));
|
||||||
builder.storeScript("2", StoredScriptSource.parse(new BytesArray("{\"foo\":\"def\"}"), XContentType.JSON));
|
builder.storeScript("2", StoredScriptSource.parse(
|
||||||
assertWarnings("scripts should not be stored without a context. Specify them in a \"script\" element.");
|
new BytesArray("{\"script\":{\"lang\":\"mustache\",\"source\":{\"foo\":\"def\"}}}"), XContentType.JSON));
|
||||||
builder.storeScript("3", StoredScriptSource.parse(new BytesArray("{\"foo\":\"ghi\"}"), XContentType.JSON));
|
builder.storeScript("3", StoredScriptSource.parse(
|
||||||
assertWarnings("scripts should not be stored without a context. Specify them in a \"script\" element.");
|
new BytesArray("{\"script\":{\"lang\":\"mustache\",\"source\":{\"foo\":\"ghi\"}}}"), XContentType.JSON));
|
||||||
ScriptMetaData scriptMetaData1 = builder.build();
|
ScriptMetaData scriptMetaData1 = builder.build();
|
||||||
|
|
||||||
builder = new ScriptMetaData.Builder(scriptMetaData1);
|
builder = new ScriptMetaData.Builder(scriptMetaData1);
|
||||||
builder.storeScript("2", StoredScriptSource.parse(new BytesArray("{\"foo\":\"changed\"}"), XContentType.JSON));
|
builder.storeScript("2", StoredScriptSource.parse(
|
||||||
assertWarnings("scripts should not be stored without a context. Specify them in a \"script\" element.");
|
new BytesArray("{\"script\":{\"lang\":\"mustache\",\"source\":{\"foo\":\"changed\"}}}"), XContentType.JSON));
|
||||||
builder.deleteScript("3");
|
builder.deleteScript("3");
|
||||||
builder.storeScript("4", StoredScriptSource.parse(new BytesArray("{\"foo\":\"jkl\"}"), XContentType.JSON));
|
builder.storeScript("4", StoredScriptSource.parse(
|
||||||
assertWarnings("scripts should not be stored without a context. Specify them in a \"script\" element.");
|
new BytesArray("{\"script\":{\"lang\":\"mustache\",\"source\":{\"foo\":\"jkl\"}}}"), XContentType.JSON));
|
||||||
ScriptMetaData scriptMetaData2 = builder.build();
|
ScriptMetaData scriptMetaData2 = builder.build();
|
||||||
|
|
||||||
ScriptMetaData.ScriptMetadataDiff diff = (ScriptMetaData.ScriptMetadataDiff) scriptMetaData2.diff(scriptMetaData1);
|
ScriptMetaData.ScriptMetadataDiff diff = (ScriptMetaData.ScriptMetadataDiff) scriptMetaData2.diff(scriptMetaData1);
|
||||||
|
|
|
@ -40,19 +40,21 @@ public class StoredScriptSourceTests extends AbstractSerializingTestCase<StoredS
|
||||||
try {
|
try {
|
||||||
XContentBuilder template = XContentBuilder.builder(xContentType.xContent());
|
XContentBuilder template = XContentBuilder.builder(xContentType.xContent());
|
||||||
template.startObject();
|
template.startObject();
|
||||||
template.startObject("query");
|
template.startObject("script");
|
||||||
template.startObject("match");
|
{
|
||||||
template.field("title", "{{query_string}}");
|
template.field("lang", "mustache");
|
||||||
template.endObject();
|
template.startObject("source");
|
||||||
|
template.startObject("query").startObject("match").field("title", "{{query_string}}").endObject();
|
||||||
|
template.endObject();
|
||||||
|
template.endObject();
|
||||||
|
}
|
||||||
template.endObject();
|
template.endObject();
|
||||||
template.endObject();
|
template.endObject();
|
||||||
Map<String, String> options = new HashMap<>();
|
Map<String, String> options = new HashMap<>();
|
||||||
if (randomBoolean()) {
|
if (randomBoolean()) {
|
||||||
options.put(Script.CONTENT_TYPE_OPTION, xContentType.mediaType());
|
options.put(Script.CONTENT_TYPE_OPTION, xContentType.mediaType());
|
||||||
}
|
}
|
||||||
StoredScriptSource source = StoredScriptSource.parse(BytesReference.bytes(template), xContentType);
|
return StoredScriptSource.parse(BytesReference.bytes(template), xContentType);
|
||||||
assertWarnings("the template context is now deprecated. Specify templates in a \"script\" element.");
|
|
||||||
return source;
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new AssertionError("Failed to create test instance", e);
|
throw new AssertionError("Failed to create test instance", e);
|
||||||
}
|
}
|
||||||
|
@ -84,7 +86,7 @@ public class StoredScriptSourceTests extends AbstractSerializingTestCase<StoredS
|
||||||
newTemplate.endObject();
|
newTemplate.endObject();
|
||||||
newTemplate.endObject();
|
newTemplate.endObject();
|
||||||
|
|
||||||
switch (between(0, 3)) {
|
switch (between(0, 2)) {
|
||||||
case 0:
|
case 0:
|
||||||
source = Strings.toString(newTemplate);
|
source = Strings.toString(newTemplate);
|
||||||
break;
|
break;
|
||||||
|
@ -92,12 +94,9 @@ public class StoredScriptSourceTests extends AbstractSerializingTestCase<StoredS
|
||||||
lang = randomAlphaOfLengthBetween(1, 20);
|
lang = randomAlphaOfLengthBetween(1, 20);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
|
default:
|
||||||
options = new HashMap<>(options);
|
options = new HashMap<>(options);
|
||||||
options.put(randomAlphaOfLengthBetween(1, 20), randomAlphaOfLengthBetween(1, 20));
|
options.put(randomAlphaOfLengthBetween(1, 20), randomAlphaOfLengthBetween(1, 20));
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
default:
|
|
||||||
return new StoredScriptSource(Strings.toString(newTemplate));
|
|
||||||
}
|
}
|
||||||
return new StoredScriptSource(lang, source, options);
|
return new StoredScriptSource(lang, source, options);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
package org.elasticsearch.script;
|
package org.elasticsearch.script;
|
||||||
|
|
||||||
import org.elasticsearch.ResourceNotFoundException;
|
import org.elasticsearch.ResourceNotFoundException;
|
||||||
|
import org.elasticsearch.common.ParsingException;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.bytes.BytesReference;
|
import org.elasticsearch.common.bytes.BytesReference;
|
||||||
import org.elasticsearch.common.io.stream.Writeable;
|
import org.elasticsearch.common.io.stream.Writeable;
|
||||||
|
@ -66,49 +67,6 @@ public class StoredScriptTests extends AbstractSerializingTestCase<StoredScriptS
|
||||||
assertThat(parsed, equalTo(source));
|
assertThat(parsed, equalTo(source));
|
||||||
}
|
}
|
||||||
|
|
||||||
// simple template value string
|
|
||||||
try (XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON)) {
|
|
||||||
builder.startObject().field("template", "code").endObject();
|
|
||||||
|
|
||||||
StoredScriptSource parsed = StoredScriptSource.parse(BytesReference.bytes(builder), XContentType.JSON);
|
|
||||||
StoredScriptSource source = new StoredScriptSource("mustache", "code", Collections.emptyMap());
|
|
||||||
|
|
||||||
assertThat(parsed, equalTo(source));
|
|
||||||
assertWarnings("the template context is now deprecated. Specify templates in a \"script\" element.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// complex template with wrapper template object
|
|
||||||
try (XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON)) {
|
|
||||||
builder.startObject().field("template").startObject().field("query", "code").endObject().endObject();
|
|
||||||
String code;
|
|
||||||
|
|
||||||
try (XContentBuilder cb = XContentFactory.contentBuilder(builder.contentType())) {
|
|
||||||
code = Strings.toString(cb.startObject().field("query", "code").endObject());
|
|
||||||
}
|
|
||||||
|
|
||||||
StoredScriptSource parsed = StoredScriptSource.parse(BytesReference.bytes(builder), XContentType.JSON);
|
|
||||||
StoredScriptSource source = new StoredScriptSource("mustache", code, Collections.emptyMap());
|
|
||||||
|
|
||||||
assertThat(parsed, equalTo(source));
|
|
||||||
assertWarnings("the template context is now deprecated. Specify templates in a \"script\" element.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// complex template with no wrapper object
|
|
||||||
try (XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON)) {
|
|
||||||
builder.startObject().field("query", "code").endObject();
|
|
||||||
String code;
|
|
||||||
|
|
||||||
try (XContentBuilder cb = XContentFactory.contentBuilder(builder.contentType())) {
|
|
||||||
code = Strings.toString(cb.startObject().field("query", "code").endObject());
|
|
||||||
}
|
|
||||||
|
|
||||||
StoredScriptSource parsed = StoredScriptSource.parse(BytesReference.bytes(builder), XContentType.JSON);
|
|
||||||
StoredScriptSource source = new StoredScriptSource("mustache", code, Collections.emptyMap());
|
|
||||||
|
|
||||||
assertThat(parsed, equalTo(source));
|
|
||||||
assertWarnings("the template context is now deprecated. Specify templates in a \"script\" element.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// complex template using script as the field name
|
// complex template using script as the field name
|
||||||
try (XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON)) {
|
try (XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON)) {
|
||||||
builder.startObject().startObject("script").field("lang", "mustache")
|
builder.startObject().startObject("script").field("lang", "mustache")
|
||||||
|
@ -206,6 +164,15 @@ public class StoredScriptTests extends AbstractSerializingTestCase<StoredScriptS
|
||||||
StoredScriptSource.parse(BytesReference.bytes(builder), XContentType.JSON));
|
StoredScriptSource.parse(BytesReference.bytes(builder), XContentType.JSON));
|
||||||
assertThat(iae.getMessage(), equalTo("illegal compiler options [{option=option}] specified"));
|
assertThat(iae.getMessage(), equalTo("illegal compiler options [{option=option}] specified"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check for unsupported template context
|
||||||
|
try (XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON)) {
|
||||||
|
builder.startObject().field("template", "code").endObject();
|
||||||
|
ParsingException pEx = expectThrows(ParsingException.class, () ->
|
||||||
|
StoredScriptSource.parse(BytesReference.bytes(builder), XContentType.JSON));
|
||||||
|
assertThat(pEx.getMessage(), equalTo("unexpected field [template], expected ["+
|
||||||
|
StoredScriptSource.SCRIPT_PARSE_FIELD.getPreferredName()+ "]"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testEmptyTemplateDeprecations() throws IOException {
|
public void testEmptyTemplateDeprecations() throws IOException {
|
||||||
|
@ -219,19 +186,6 @@ public class StoredScriptTests extends AbstractSerializingTestCase<StoredScriptS
|
||||||
assertWarnings("empty templates should no longer be used");
|
assertWarnings("empty templates should no longer be used");
|
||||||
}
|
}
|
||||||
|
|
||||||
try (XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON)) {
|
|
||||||
builder.startObject().field("template", "").endObject();
|
|
||||||
|
|
||||||
StoredScriptSource parsed = StoredScriptSource.parse(BytesReference.bytes(builder), XContentType.JSON);
|
|
||||||
StoredScriptSource source = new StoredScriptSource(Script.DEFAULT_TEMPLATE_LANG, "", Collections.emptyMap());
|
|
||||||
|
|
||||||
assertThat(parsed, equalTo(source));
|
|
||||||
assertWarnings(
|
|
||||||
"the template context is now deprecated. Specify templates in a \"script\" element.",
|
|
||||||
"empty templates should no longer be used"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
try (XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON)) {
|
try (XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON)) {
|
||||||
builder.startObject().field("script").startObject().field("lang", "mustache")
|
builder.startObject().field("script").startObject().field("lang", "mustache")
|
||||||
.field("source", "").endObject().endObject();
|
.field("source", "").endObject().endObject();
|
||||||
|
|
|
@ -220,7 +220,11 @@ public class BasicWatcherTests extends AbstractWatcherIntegrationTestCase {
|
||||||
SearchSourceBuilder searchSourceBuilder = searchSource().query(matchQuery("level", "a"));
|
SearchSourceBuilder searchSourceBuilder = searchSource().query(matchQuery("level", "a"));
|
||||||
assertAcked(client().admin().cluster().preparePutStoredScript()
|
assertAcked(client().admin().cluster().preparePutStoredScript()
|
||||||
.setId("my-template")
|
.setId("my-template")
|
||||||
.setContent(BytesReference.bytes(jsonBuilder().startObject().field("template").value(searchSourceBuilder).endObject()),
|
.setContent(BytesReference.bytes(
|
||||||
|
jsonBuilder().startObject().startObject("script")
|
||||||
|
.field("lang", "mustache")
|
||||||
|
.field("source").value(searchSourceBuilder)
|
||||||
|
.endObject().endObject()),
|
||||||
XContentType.JSON)
|
XContentType.JSON)
|
||||||
.get());
|
.get());
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue