-
Notifications
You must be signed in to change notification settings - Fork 24.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add put stored script support to high-level rest client #31323
Changes from 7 commits
9d06e09
f9da579
a3fa752
09be31d
dd3bd38
27dccd1
82a8611
3e55b99
11098dc
27a9906
2488452
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,6 +30,8 @@ | |
import org.elasticsearch.action.admin.cluster.storedscripts.DeleteStoredScriptResponse; | ||
import org.elasticsearch.action.admin.cluster.storedscripts.GetStoredScriptRequest; | ||
import org.elasticsearch.action.admin.cluster.storedscripts.GetStoredScriptResponse; | ||
import org.elasticsearch.action.admin.cluster.storedscripts.PutStoredScriptRequest; | ||
import org.elasticsearch.action.admin.cluster.storedscripts.PutStoredScriptResponse; | ||
import org.elasticsearch.action.bulk.BulkRequest; | ||
import org.elasticsearch.action.bulk.BulkResponse; | ||
import org.elasticsearch.action.delete.DeleteRequest; | ||
|
@@ -712,6 +714,35 @@ public void deleteScriptAsync(DeleteStoredScriptRequest request, RequestOptions | |
DeleteStoredScriptResponse::fromXContent, listener, emptySet()); | ||
} | ||
|
||
/** | ||
* Puts an stored script using the Scripting API. | ||
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/6.2/modules-scripting.html"> Scripting API | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. pls refer to |
||
* on elastic.co</a> | ||
* @param putStoredScriptRequest the request | ||
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized | ||
* @return the response | ||
* @throws IOException in case there is a problem sending the request or parsing back the response | ||
*/ | ||
public PutStoredScriptResponse putScript(PutStoredScriptRequest putStoredScriptRequest, | ||
RequestOptions options) throws IOException { | ||
return performRequestAndParseEntity(putStoredScriptRequest, RequestConverters::putScript, options, | ||
PutStoredScriptResponse::fromXContent, emptySet()); | ||
} | ||
|
||
/** | ||
* Asynchronously puts an stored script using the Scripting API. | ||
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/6.2/modules-scripting.html"> Scripting API | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here - pls refer to |
||
* on elastic.co</a> | ||
* @param putStoredScriptRequest the request | ||
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized | ||
* @param listener the listener to be notified upon request completion | ||
*/ | ||
public void putScriptAsync(PutStoredScriptRequest putStoredScriptRequest, RequestOptions options, | ||
ActionListener<PutStoredScriptResponse> listener) { | ||
performRequestAsyncAndParseEntity(putStoredScriptRequest, RequestConverters::putScript, options, | ||
PutStoredScriptResponse::fromXContent, listener, emptySet()); | ||
} | ||
|
||
/** | ||
* Asynchronously executes a request using the Field Capabilities API. | ||
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-field-caps.html">Field Capabilities API | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,6 +40,7 @@ | |
import org.elasticsearch.action.admin.cluster.snapshots.delete.DeleteSnapshotRequest; | ||
import org.elasticsearch.action.admin.cluster.storedscripts.DeleteStoredScriptRequest; | ||
import org.elasticsearch.action.admin.cluster.storedscripts.GetStoredScriptRequest; | ||
import org.elasticsearch.action.admin.cluster.storedscripts.PutStoredScriptRequest; | ||
import org.elasticsearch.action.admin.indices.alias.Alias; | ||
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; | ||
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions; | ||
|
@@ -2055,6 +2056,42 @@ public void testGetTemplateRequest() throws Exception { | |
assertThat(request.getEntity(), nullValue()); | ||
} | ||
|
||
public void testPutScript() throws Exception { | ||
PutStoredScriptRequest putStoredScriptRequest = new PutStoredScriptRequest(); | ||
|
||
String id = randomAlphaOfLengthBetween(5, 10); | ||
putStoredScriptRequest.id(id); | ||
|
||
XContentType xContentType = randomFrom(XContentType.values()); | ||
try (XContentBuilder builder = XContentBuilder.builder(xContentType.xContent())) { | ||
builder.startObject(); | ||
builder.startObject("script") | ||
.field("lang", "painless") | ||
.field("source", "Math.log(_score * 2) + params.multiplier") | ||
.endObject(); | ||
builder.endObject(); | ||
|
||
putStoredScriptRequest.content(BytesReference.bytes(builder), xContentType); | ||
} | ||
|
||
Map<String, String> expectedParams = new HashMap<>(); | ||
setRandomMasterTimeout(putStoredScriptRequest, expectedParams); | ||
setRandomTimeout(putStoredScriptRequest::timeout, AcknowledgedRequest.DEFAULT_ACK_TIMEOUT, expectedParams); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. here we should test the context param too? |
||
|
||
if(randomBoolean()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: space between |
||
String context = randomAlphaOfLengthBetween(5, 10); | ||
putStoredScriptRequest.context(context); | ||
expectedParams.put("context", context); | ||
} | ||
|
||
Request request = RequestConverters.putScript(putStoredScriptRequest); | ||
|
||
assertThat(request.getEndpoint(), equalTo("/_scripts/" + id)); | ||
assertThat(request.getParameters(), equalTo(expectedParams)); | ||
assertThat(request.getEntity(), notNullValue()); | ||
assertToXContentBody(putStoredScriptRequest, request.getEntity()); | ||
} | ||
|
||
public void testGetScriptRequest() { | ||
GetStoredScriptRequest getStoredScriptRequest = new GetStoredScriptRequest("x-script"); | ||
Map<String, String> expectedParams = new HashMap<>(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
package org.elasticsearch.client;/* | ||
package org.elasticsearch.client; | ||
/* | ||
* Licensed to Elasticsearch under one or more contributor | ||
* license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright | ||
|
@@ -17,50 +18,39 @@ | |
* under the License. | ||
*/ | ||
|
||
|
||
import org.apache.http.entity.ContentType; | ||
import org.apache.http.entity.StringEntity; | ||
import org.apache.http.util.EntityUtils; | ||
import org.elasticsearch.ElasticsearchStatusException; | ||
import org.elasticsearch.action.admin.cluster.storedscripts.DeleteStoredScriptRequest; | ||
import org.elasticsearch.action.admin.cluster.storedscripts.DeleteStoredScriptResponse; | ||
import org.elasticsearch.action.admin.cluster.storedscripts.GetStoredScriptRequest; | ||
import org.elasticsearch.action.admin.cluster.storedscripts.GetStoredScriptResponse; | ||
import org.elasticsearch.common.Strings; | ||
import org.elasticsearch.common.xcontent.ToXContent; | ||
import org.elasticsearch.action.admin.cluster.storedscripts.PutStoredScriptRequest; | ||
import org.elasticsearch.common.bytes.BytesArray; | ||
import org.elasticsearch.common.xcontent.XContentType; | ||
import org.elasticsearch.rest.RestStatus; | ||
import org.elasticsearch.script.Script; | ||
import org.elasticsearch.script.StoredScriptSource; | ||
|
||
import java.util.Collections; | ||
import java.util.Map; | ||
|
||
import static java.util.Collections.emptyMap; | ||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; | ||
import static org.elasticsearch.common.xcontent.support.XContentMapValues.extractValue; | ||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; | ||
import static org.hamcrest.Matchers.equalTo; | ||
|
||
public class StoredScriptsIT extends ESRestHighLevelClientTestCase { | ||
|
||
final String id = "calculate-score"; | ||
private static final String id = "calculate-score"; | ||
|
||
public void testGetStoredScript() throws Exception { | ||
final StoredScriptSource scriptSource = | ||
new StoredScriptSource("painless", | ||
"Math.log(_score * 2) + params.my_modifier", | ||
Collections.singletonMap(Script.CONTENT_TYPE_OPTION, XContentType.JSON.mediaType())); | ||
|
||
final String script = Strings.toString(scriptSource.toXContent(jsonBuilder(), ToXContent.EMPTY_PARAMS)); | ||
// TODO: change to HighLevel PutStoredScriptRequest when it will be ready | ||
// so far - using low-level REST API | ||
Response putResponse = | ||
adminClient() | ||
.performRequest("PUT", "/_scripts/calculate-score", emptyMap(), | ||
new StringEntity("{\"script\":" + script + "}", | ||
ContentType.APPLICATION_JSON)); | ||
assertEquals(putResponse.getStatusLine().getReasonPhrase(), 200, putResponse.getStatusLine().getStatusCode()); | ||
assertEquals("{\"acknowledged\":true}", EntityUtils.toString(putResponse.getEntity())); | ||
|
||
GetStoredScriptRequest getRequest = new GetStoredScriptRequest("calculate-score"); | ||
PutStoredScriptRequest request = | ||
new PutStoredScriptRequest(id, "search", new BytesArray("{}"), XContentType.JSON, scriptSource); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💯 |
||
assertAcked(execute(request, highLevelClient()::putScript, highLevelClient()::putScriptAsync)); | ||
|
||
GetStoredScriptRequest getRequest = new GetStoredScriptRequest(id); | ||
getRequest.masterNodeTimeout("50s"); | ||
|
||
GetStoredScriptResponse getResponse = execute(getRequest, highLevelClient()::getScript, | ||
|
@@ -75,25 +65,14 @@ public void testDeleteStoredScript() throws Exception { | |
"Math.log(_score * 2) + params.my_modifier", | ||
Collections.singletonMap(Script.CONTENT_TYPE_OPTION, XContentType.JSON.mediaType())); | ||
|
||
final String script = Strings.toString(scriptSource.toXContent(jsonBuilder(), ToXContent.EMPTY_PARAMS)); | ||
// TODO: change to HighLevel PutStoredScriptRequest when it will be ready | ||
// so far - using low-level REST API | ||
Response putResponse = | ||
adminClient() | ||
.performRequest("PUT", "/_scripts/" + id, emptyMap(), | ||
new StringEntity("{\"script\":" + script + "}", | ||
ContentType.APPLICATION_JSON)); | ||
assertEquals(putResponse.getStatusLine().getReasonPhrase(), 200, putResponse.getStatusLine().getStatusCode()); | ||
assertEquals("{\"acknowledged\":true}", EntityUtils.toString(putResponse.getEntity())); | ||
PutStoredScriptRequest request = | ||
new PutStoredScriptRequest(id, "search", new BytesArray("{}"), XContentType.JSON, scriptSource); | ||
assertAcked(execute(request, highLevelClient()::putScript, highLevelClient()::putScriptAsync)); | ||
|
||
DeleteStoredScriptRequest deleteRequest = new DeleteStoredScriptRequest(id); | ||
deleteRequest.masterNodeTimeout("50s"); | ||
deleteRequest.timeout("50s"); | ||
|
||
DeleteStoredScriptResponse deleteResponse = execute(deleteRequest, highLevelClient()::deleteScript, | ||
highLevelClient()::deleteScriptAsync); | ||
|
||
assertThat(deleteResponse.isAcknowledged(), equalTo(true)); | ||
assertAcked(execute(deleteRequest, highLevelClient()::deleteScript, highLevelClient()::deleteScriptAsync)); | ||
|
||
GetStoredScriptRequest getRequest = new GetStoredScriptRequest(id); | ||
|
||
|
@@ -102,4 +81,21 @@ public void testDeleteStoredScript() throws Exception { | |
highLevelClient()::getScriptAsync)); | ||
assertThat(statusException.status(), equalTo(RestStatus.NOT_FOUND)); | ||
} | ||
|
||
public void testPutScript() throws Exception { | ||
final StoredScriptSource scriptSource = | ||
new StoredScriptSource("painless", | ||
"Math.log(_score * 2) + params.my_modifier", | ||
Collections.singletonMap(Script.CONTENT_TYPE_OPTION, XContentType.JSON.mediaType())); | ||
|
||
PutStoredScriptRequest request = | ||
new PutStoredScriptRequest(id, "search", new BytesArray("{}"), XContentType.JSON, scriptSource); | ||
assertAcked(execute(request, highLevelClient()::putScript, highLevelClient()::putScriptAsync)); | ||
|
||
Map<String, Object> script = getAsMap("/_scripts/" + id); | ||
assertThat(extractValue("_id", script), equalTo(id)); | ||
assertThat(extractValue("found", script), equalTo(true)); | ||
assertThat(extractValue("script.lang", script), equalTo("painless")); | ||
assertThat(extractValue("script.source", script), equalTo("Math.log(_score * 2) + params.my_modifier")); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't we also support a
context
parameter?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry for asking that, I do not really understand what does
context
mean here. After searching documentation I only found two docs:https://www.elastic.co/guide/en/elasticsearch/painless/master/painless-execute-api.html
https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-scripting-security.html
where should I put the parameter?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't be sorry, I can explain! at REST, we also accept the
context
query_string parameter. It is a string and PutStoredScriptRequest already supports it, you just have to read it from the request and set the corresponding parameter so that we pass it through to the REST layer.