Scripting: Add optional context parameter to put stored script requests (#25014)

This commit adds an optional `context` url parameter to the put stored
script request. When a context is specified, the script is compiled
against that context before storing, as a validation the script will
work when used in that context.
This commit is contained in:
Ryan Ernst 2017-06-01 17:53:48 -07:00 committed by GitHub
parent 39e59b49b1
commit 8d88b94372
7 changed files with 37 additions and 11 deletions

View File

@ -38,6 +38,7 @@ public class PutStoredScriptRequest extends AcknowledgedRequest<PutStoredScriptR
private String id; private String id;
private String lang; private String lang;
private String context;
private BytesReference content; private BytesReference content;
private XContentType xContentType; private XContentType xContentType;
@ -45,10 +46,11 @@ public class PutStoredScriptRequest extends AcknowledgedRequest<PutStoredScriptR
super(); super();
} }
public PutStoredScriptRequest(String id, String lang, BytesReference content, XContentType xContentType) { public PutStoredScriptRequest(String id, String lang, String context, BytesReference content, XContentType xContentType) {
super(); super();
this.id = id; this.id = id;
this.lang = lang; this.lang = lang;
this.context = context;
this.content = content; this.content = content;
this.xContentType = Objects.requireNonNull(xContentType); this.xContentType = Objects.requireNonNull(xContentType);
} }
@ -94,6 +96,15 @@ public class PutStoredScriptRequest extends AcknowledgedRequest<PutStoredScriptR
return this; return this;
} }
public String context() {
return context;
}
public PutStoredScriptRequest context(String context) {
this.context = context;
return this;
}
public BytesReference content() { public BytesReference content() {
return content; return content;
} }
@ -128,6 +139,9 @@ public class PutStoredScriptRequest extends AcknowledgedRequest<PutStoredScriptR
} else { } else {
xContentType = XContentFactory.xContentType(content); xContentType = XContentFactory.xContentType(content);
} }
if (in.getVersion().onOrAfter(Version.V_6_0_0_alpha2)) {
context = in.readOptionalString();
}
} }
@Override @Override
@ -140,6 +154,9 @@ public class PutStoredScriptRequest extends AcknowledgedRequest<PutStoredScriptR
if (out.getVersion().onOrAfter(Version.V_5_3_0)) { if (out.getVersion().onOrAfter(Version.V_5_3_0)) {
xContentType.writeTo(out); xContentType.writeTo(out);
} }
if (out.getVersion().onOrAfter(Version.V_6_0_0_alpha2)) {
out.writeOptionalString(context);
}
} }
@Override @Override

View File

@ -50,6 +50,7 @@ public class RestPutStoredScriptAction extends BaseRestHandler {
public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException {
String id = request.param("id"); String id = request.param("id");
String lang = request.param("lang"); String lang = request.param("lang");
String context = request.param("context");
// In the case where only {lang} is not null, we make it {id} because of // In the case where only {lang} is not null, we make it {id} because of
// name ordering issues in the handlers' paths. // name ordering issues in the handlers' paths.
@ -65,7 +66,7 @@ public class RestPutStoredScriptAction extends BaseRestHandler {
"specifying lang [" + lang + "] as part of the url path is deprecated, use request content instead"); "specifying lang [" + lang + "] as part of the url path is deprecated, use request content instead");
} }
PutStoredScriptRequest putRequest = new PutStoredScriptRequest(id, lang, content, request.getXContentType()); PutStoredScriptRequest putRequest = new PutStoredScriptRequest(id, lang, context, content, request.getXContentType());
return channel -> client.admin().cluster().putStoredScript(putRequest, new AcknowledgedRestListener<>(channel)); return channel -> client.admin().cluster().putStoredScript(putRequest, new AcknowledgedRestListener<>(channel));
} }
} }

View File

@ -431,14 +431,12 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust
} else if (isAnyContextEnabled() == false) { } else if (isAnyContextEnabled() == false) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"cannot put [" + ScriptType.STORED + "] script, no script contexts are enabled"); "cannot put [" + ScriptType.STORED + "] script, no script contexts are enabled");
} else { } else if (request.context() != null) {
// TODO: executable context here is just a placeholder, replace with optional context name passed into PUT stored script req ScriptContext<?> context = contexts.get(request.context());
Object compiled = scriptEngine.compile(request.id(), source.getCode(), ExecutableScript.CONTEXT, Collections.emptyMap()); if (context == null) {
throw new IllegalArgumentException("Unknown context [" + request.context() + "]");
if (compiled == null) {
throw new IllegalArgumentException("failed to parse/compile stored script [" + request.id() + "]" +
(source.getCode() == null ? "" : " using code [" + source.getCode() + "]"));
} }
scriptEngine.compile(request.id(), source.getCode(), context, Collections.emptyMap());
} }
} catch (ScriptException good) { } catch (ScriptException good) {
throw good; throw good;

View File

@ -32,7 +32,8 @@ import java.util.Base64;
public class PutStoredScriptRequestTests extends ESTestCase { public class PutStoredScriptRequestTests extends ESTestCase {
public void testSerialization() throws IOException { public void testSerialization() throws IOException {
PutStoredScriptRequest storedScriptRequest = new PutStoredScriptRequest("foo", "bar", new BytesArray("{}"), XContentType.JSON); PutStoredScriptRequest storedScriptRequest =
new PutStoredScriptRequest("foo", "bar", "context", new BytesArray("{}"), XContentType.JSON);
assertEquals(XContentType.JSON, storedScriptRequest.xContentType()); assertEquals(XContentType.JSON, storedScriptRequest.xContentType());
try (BytesStreamOutput output = new BytesStreamOutput()) { try (BytesStreamOutput output = new BytesStreamOutput()) {
@ -44,6 +45,7 @@ public class PutStoredScriptRequestTests extends ESTestCase {
assertEquals(XContentType.JSON, serialized.xContentType()); assertEquals(XContentType.JSON, serialized.xContentType());
assertEquals(storedScriptRequest.lang(), serialized.lang()); assertEquals(storedScriptRequest.lang(), serialized.lang());
assertEquals(storedScriptRequest.id(), serialized.id()); assertEquals(storedScriptRequest.id(), serialized.id());
assertEquals(storedScriptRequest.context(), serialized.context());
} }
} }
} }

View File

@ -26,6 +26,7 @@ import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.action.AcknowledgedRestListener; import org.elasticsearch.rest.action.AcknowledgedRestListener;
import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.Script; import org.elasticsearch.script.Script;
import java.io.IOException; import java.io.IOException;
@ -47,7 +48,8 @@ public class RestPutSearchTemplateAction extends BaseRestHandler {
String id = request.param("id"); String id = request.param("id");
BytesReference content = request.content(); BytesReference content = request.content();
PutStoredScriptRequest put = new PutStoredScriptRequest(id, Script.DEFAULT_TEMPLATE_LANG, content, request.getXContentType()); PutStoredScriptRequest put = new PutStoredScriptRequest(id, Script.DEFAULT_TEMPLATE_LANG, ExecutableScript.CONTEXT.name,
content, request.getXContentType());
return channel -> client.admin().cluster().putStoredScript(put, new AcknowledgedRestListener<>(channel)); return channel -> client.admin().cluster().putStoredScript(put, new AcknowledgedRestListener<>(channel));
} }
} }

View File

@ -38,10 +38,12 @@
catch: request catch: request
put_script: put_script:
id: "1" id: "1"
context: "search"
body: { "script": {"lang": "painless", "code": "_score * foo bar + doc['myParent.weight'].value"} } body: { "script": {"lang": "painless", "code": "_score * foo bar + doc['myParent.weight'].value"} }
- do: - do:
catch: /compile error/ catch: /compile error/
put_script: put_script:
id: "1" id: "1"
context: "search"
body: { "script": {"lang": "painless", "code": "_score * foo bar + doc['myParent.weight'].value"} } body: { "script": {"lang": "painless", "code": "_score * foo bar + doc['myParent.weight'].value"} }

View File

@ -18,6 +18,10 @@
} }
}, },
"params" : { "params" : {
"context": {
"type" : "string",
"description" : "Context name to compile script against"
}
} }
}, },
"body": { "body": {