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:
parent
39e59b49b1
commit
8d88b94372
|
@ -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
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"} }
|
||||||
|
|
|
@ -18,6 +18,10 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"params" : {
|
"params" : {
|
||||||
|
"context": {
|
||||||
|
"type" : "string",
|
||||||
|
"description" : "Context name to compile script against"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"body": {
|
"body": {
|
||||||
|
|
Loading…
Reference in New Issue