Skip to content
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 get stored script and delete stored script to high level REST API #31355

Merged

Conversation

vladimirdolzhenko
Copy link
Contributor

@vladimirdolzhenko vladimirdolzhenko commented Jun 15, 2018

Add get stored script and delete stored script to High Level REST API Client
Relates to #27205

@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-core-infra

@vladimirdolzhenko vladimirdolzhenko changed the title get and delete stored script high level REST API Add get stored script and delete stored script to high level REST API Jun 15, 2018
Copy link
Member

@javanna javanna left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

left some comments, thanks @vladimirdolzhenko

@@ -877,6 +879,18 @@ static Request getTemplates(GetIndexTemplatesRequest getIndexTemplatesRequest) t
return request;
}

static Request getStoredScript(GetStoredScriptRequest getStoredScriptRequest) {
String endpoint = new EndpointBuilder().addPathPart("_scripts").addPathPart(getStoredScriptRequest.id()).build();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the first one should be addPathPartAsIs

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

++

}

static Request deleteStoredScript(DeleteStoredScriptRequest deleteStoredScriptRequest) {
String endpoint = new EndpointBuilder().addPathPart("_scripts").addPathPart(deleteStoredScriptRequest.id()).build();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here too, addPartAsIs for _scripts

* @return the response
* @throws IOException in case there is a problem sending the request or parsing back the response
*/
public GetStoredScriptResponse getStoredScript(GetStoredScriptRequest request, RequestOptions options) throws IOException {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the SPEC have get_script, can we call these methods getScript ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove stored from all methods names?

* @return the response
* @throws IOException in case there is a problem sending the request or parsing back the response
*/
public DeleteStoredScriptResponse deleteStoredScript(DeleteStoredScriptRequest request, RequestOptions options) throws IOException {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here too, remove the stored part


Request request = RequestConverters.getStoredScript(storedScriptRequest);
assertThat(request.getEndpoint(), equalTo("/_scripts/" + storedScriptRequest.id()));
assertThat(request.getParameters(), equalTo(expectedParams));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to create a new map right? you can just assert that parameters is empty.

@@ -149,3 +149,13 @@ The Java High Level REST Client supports the following Tasks APIs:

include::tasks/list_tasks.asciidoc[]
include::tasks/cancel_tasks.asciidoc[]

== Scripts
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move them up with the top-level API? We try to align this with the API categories from the SPEC

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looking again, I think that it's fine to have them grouped under scripts although the spec puts them in the top-level API. Things are a bit different in the es reference docs. Call it Scripts APIs though .

source.toXContent(builder, params);
public boolean isFragment() {
return true;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this method is not meant to be overridden. Please use ToXContentFragment instead of ToXContentObject if needed. Yet normally responses are objects rather than fragments, you sure about this?


builder.endObject();
}
response.toXContent(builder, channel.request());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can make the response a StatusToXContentObject and then use RestStatusToXContentListener here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

StatusToXContentObject starts to conflict with ToXContentFragment

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and RestStatusToXContentListener does not work with fragment - RestGetStoredScriptAction as well adds id into response

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I said above, this probably should not be a fragment, I don't get why it would need to be.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is a manual serialization performed in RestGetStoredScriptAction - it adds as well id of script in front of GetStoredScriptResponse - agreed to move id within GetStoredScriptResponse, make it StatusToXContentObject and drop fragment

builder.field(OPTIONS_PARSE_FIELD.getPreferredName(), options);
if (options.isEmpty() == false) {
builder.field(OPTIONS_PARSE_FIELD.getPreferredName(), options);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we need this change? it seems like it changes the existing StoredScriptSource output, that may be risky to do, not sure.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is a custom serialization performed in RestGetStoredScriptAction - I use a standard StoredScriptSource.toXContent but it violates test rest-api-spec/test/painless/16_update2.yml - it expects that empty options are not shows at all. Deserialization of empty options or no-options are equal - resolves to empty map.

I traced call sites - seems no any other usages of StoredScriptSource.toXContent + other tests passes fine.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok thanks


private StoredScriptSource scriptSource() {
return new StoredScriptSource("lang", "code",
Collections.singletonMap(Script.CONTENT_TYPE_OPTION, XContentType.JSON.mediaType()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we randomize how this instance gets created?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed

@javanna
Copy link
Member

javanna commented Jun 15, 2018

one more thing @vladimirdolzhenko the docs don't seem to build, can you check that please?

…i-spec; cleaned RestGetStoredScriptAction up and GetStoredScriptResponse.toXContent
Copy link
Member

@javanna javanna left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

left a few more comments, mostly minors.

// end::delete-stored-script-execute

// tag::delete-stored-script-response
assertThat(deleteResponse.isAcknowledged(), equalTo(true)); // <1>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer that we don't show assertions in the docs output, but rather just assign values to variables, which is more aligned with what users will do in their applications.

// end::get-stored-script-execute

// tag::get-stored-script-response
final StoredScriptSource source = getResponse.getSource(); // <1>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it worth expanding on how to interact with StoredScriptSource?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed

["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/StoredScriptsDocumentationIT.java[delete-stored-script-execute]
--------------------------------------------------
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we are missing the optional parameters section here that describe the two supported timeouts.

* @return the response
* @throws IOException in case there is a problem sending the request or parsing back the response
*/
public GetStoredScriptResponse getStoredScript(GetStoredScriptRequest request, RequestOptions options) throws IOException {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove stored from all methods names?

@@ -149,3 +149,13 @@ The Java High Level REST Client supports the following Tasks APIs:

include::tasks/list_tasks.asciidoc[]
include::tasks/cancel_tasks.asciidoc[]

== Scripts
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looking again, I think that it's fine to have them grouped under scripts although the spec puts them in the top-level API. Things are a bit different in the es reference docs. Call it Scripts APIs though .

public XContentBuilder field(ParseField field, String value) throws IOException {
return field(field.getPreferredName(), value);
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I wonder what these method buy us, my concern is that we have already a lot of methods in XContentBuilder. After all callers only have to call the other variant of these methods and pass in field.getPreferredName(). I am a bit on the fence on this. Maybe let's try and do it separately and see what others think about it.


builder.field(_ID_PARSE_FIELD, id);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we may have a small problem here, when toXContent is called on an object deserialized from a previous version that didn't send the _id .

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nope, actually RestGetStoredScriptAction adds that _id manually (out of GetStoredScriptRequest.toXContent)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you added id as a member, which is great. It is now being serialized over the wire, but nodes on previous versions don't send it. If you are deserializing from a previous version this one will be null, and what will happen when you call toXcontent against such an object? I am not sure whether it will be NPE or the id will be printed out null, maybe just the latter, can you check?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed - use writeOptionalString instead of writeString (to avoid NPE on serialization) - while I don't see anything more how we can handle this case

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if it prints out null it may be ok, if it gives NPE we need a null check, that's what I meant.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it prints out null :

public XContentBuilder field(String name, String value) throws IOException {
        if (value == null) {
            return nullField(name);
        }
        ensureNameNotNull(name);
        generator.writeStringField(name, value);
        return this;
    }

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for checking, that is fine then

private StoredScriptSource source;

GetStoredScriptResponse() {
}

GetStoredScriptResponse(StoredScriptSource source) {
GetStoredScriptResponse(String id) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we can do without this constructor and always use the other that accepts both id and source? otherwise make this one private at least?

builder.field(OPTIONS_PARSE_FIELD.getPreferredName(), options);
if (options.isEmpty() == false) {
builder.field(OPTIONS_PARSE_FIELD.getPreferredName(), options);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok thanks

return s -> "script.options".equals(s);
}

private StoredScriptSource scriptSource() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

static? and call it randomScriptSource?

@vladimirdolzhenko
Copy link
Contributor Author

thanks @javanna for your comments, could you pls have another look into this ?

Copy link
Member

@javanna javanna left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks @vladimirdolzhenko I left a couple of things but LGTM, feel free to push once those are addressed.

return request;
}

static Request deleteScript(DeleteStoredScriptRequest deleteStoredScriptRequest) {
String endpoint = new EndpointBuilder().addPathPartAsIs("_scripts").addPathPart(deleteStoredScriptRequest.id()).build();
Request request = new Request(HttpDelete.METHOD_NAME, endpoint);
Params params = new Params(request);
params.withTimeout(deleteStoredScriptRequest.timeout());
params.withMasterTimeout(deleteStoredScriptRequest.masterNodeTimeout());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also set them to some value?

@@ -51,7 +51,7 @@
String id = (String) a[0];
boolean found = (Boolean)a[1];
StoredScriptSource scriptSource = (StoredScriptSource)a[2];
return found ? new GetStoredScriptResponse(id, scriptSource) : new GetStoredScriptResponse(id);
return found ? new GetStoredScriptResponse(id, scriptSource) : new GetStoredScriptResponse();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought that you wanted to set the id in both cases and that the else block should become new GetStoredScriptResponse(id, null)

@@ -148,7 +144,7 @@ public void writeTo(StreamOutput out) throws IOException {
}
}
if (out.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) {
out.writeString(id);
out.writeOptionalString(id);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You already have a conditional based on the version, if a version supports it, it will always send it. Making it optional helps in case something that is deserialized from a previous version is sent back to another node. I am not sure we ever do those multiple roundtrips with this API, hence I don't think we need to make it optional. If this is due to my previous comment on id being potentially null, I didn't mean to make you make this change. I rather meant to protect toXcontent from potential NPEs if they may happen.

@@ -47,7 +47,7 @@ public String getName() {
public RestChannelConsumer prepareRequest(final RestRequest request, NodeClient client) throws IOException {
String id = request.param("id");
GetStoredScriptRequest getRequest = new GetStoredScriptRequest(id);

getRequest.masterNodeTimeout(request.paramAsTime("master_timeout", getRequest.masterNodeTimeout()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you also add this to the SPEC if it's supported?

@@ -134,7 +134,7 @@ public void testStartEndArray() throws IOException {

public void testField() throws IOException {
expectValueException(() -> BytesReference.bytes(builder().field("foo")));
expectNonNullFieldException(() -> BytesReference.bytes(builder().field(null)));
expectNonNullFieldException(() -> BytesReference.bytes(builder().field((String)null)));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should not be needed anymore

DeleteStoredScriptRequest deleteStoredScriptRequest = new DeleteStoredScriptRequest("x-script");

Map<String, String> expectedParams = new HashMap<>();
setRandomTimeout(deleteStoredScriptRequest::timeout, AcknowledgedRequest.DEFAULT_ACK_TIMEOUT, expectedParams);
Copy link
Contributor Author

@vladimirdolzhenko vladimirdolzhenko Jun 19, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@javanna I guess you mean some value like this

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes ;)

@vladimirdolzhenko vladimirdolzhenko merged commit 04e4e44 into elastic:master Jun 19, 2018
@vladimirdolzhenko vladimirdolzhenko deleted the get_delete_stored_script branch June 19, 2018 12:21
dnhatn added a commit that referenced this pull request Jun 19, 2018
* master:
  Add get stored script and delete stored script to high level REST API - post backport fix
  Add get stored script and delete stored script to high level REST API (#31355)
  Core: Combine Action and GenericAction (#31405)
  Fix reference to XContentBuilder.string() (#31337)
  Avoid sending duplicate remote failed shard requests (#31313)
  Fix defaults in GeoShapeFieldMapper output (#31302)
  RestAPI: Reject forcemerge requests with a body (#30792)
  Packaging: Remove windows bin files from the tar distribution (#30596)
  Docs: Use the default distribution to test docs (#31251)
  [DOCS] Adds testing for security APIs (#31345)
  Clarify that IP range data can be specified in CIDR notation. (#31374)
  Use system context for cluster state update tasks (#31241)
  Percentile/Ranks should return null instead of NaN when empty (#30460)
  REST high-level client: add validate query API (#31077)
  Move language analyzers from server to analysis-common module. (#31300)
  [Test] Fix :example-plugins:rest-handler on Windows
  Expose lucene's RemoveDuplicatesTokenFilter (#31275)
  Reload secure settings for plugins (#31383)
  Remove some cases in FieldTypeLookupTests that are no longer relevant. (#31381)
  Ensure we don't use a remote profile if cluster name matches (#31331)
  [TEST] Double write alias fault (#30942)
  [DOCS] Fix version in SQL JDBC Maven template
  [DOCS] Improve install and setup section for SQL JDBC
  SQL: Fix rest endpoint names in node stats (#31371)
  Support for remote path in reindex api - post backport fix Closes #22913
  [ML] Put ML filter API response should contain the filter (#31362)
  Support for remote path in reindex api (#31290)
  Add byte array pooling to nio http transport (#31349)
  Remove trial status info from start trial doc (#31365)
  [DOCS] Adds links to release notes and highlights
  add is-write-index flag to aliases (#30942)
  Add rollover-creation-date setting to rolled over index (#31144)
  [ML] Hold ML filter items in sorted set (#31338)
  [Tests] Fix edge case in ScriptedMetricAggregatorTests (#31357)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants