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 a Painless Context REST API #39382

Merged
merged 36 commits into from
Mar 14, 2019
Merged

Add a Painless Context REST API #39382

merged 36 commits into from
Mar 14, 2019

Conversation

jdconrad
Copy link
Contributor

This PR adds an internal REST API for querying context information about Painless whitelists.

Commands include the following:
GET /_scripts/painless/_context -- retrieves a list of contexts
GET /_scripts/painless/_context?context=%name% retrieves all available information about the API for this specific context

In the future it should be easy to expand the API for external consumption or use with a web based IDE for retrieving info about a single type/single method, etc.

The follow up for this is to add a gradle task that can process these commands and generate whitelist API docs to keep them up-to-date.

@jdconrad jdconrad added >enhancement :Core/Infra/Scripting Scripting abstractions, Painless, and Mustache v8.0.0 v7.2.0 labels Feb 25, 2019
@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-core-infra

Copy link
Member

@martijnvg martijnvg left a comment

Choose a reason for hiding this comment

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

The direction looks good. I left some comments about serialization.


public static class Request extends ActionRequest {

private String scriptContextName;
Copy link
Member

Choose a reason for hiding this comment

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

This fields needs to be serialized. This can be done by adding a constructor that accepts StreamInput and overwrite the writeTo method.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

}

public Response(StreamInput input) {
throw new UnsupportedOperationException();
Copy link
Member

Choose a reason for hiding this comment

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

We should have binary serialization here too. (implement this constructor and implement writeTo() method)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.


public static class Response extends ActionResponse implements ToXContentObject {

private final PainlessScriptEngine painlessScriptEngine;
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 that PainlessScriptEngine should't be exposed in this response class. This something internal to painless itself. I think it makes more sense to introduce a simple pojo classes that are exposed here and that can serialize the information that users of this api need. The transport action can then built the response class with the pojo classes based on the painless script engine instance.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I considered this and wasn't sure it was the right thing to do since so much information is being copied from the PainlessLookup. But based on your feedback it makes sense for the serialization and encapsulation, so I'll work on changing it. Thanks for this feedback!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added several POJOs to accommodate this.

@jdconrad
Copy link
Contributor Author

@martijnvg Thank you for the comments! Will take a look soon.

@jdconrad
Copy link
Contributor Author

jdconrad commented Mar 5, 2019

@martijnvg I think I've addressed all the serialization issues. Would you please take another look when you get the chance? Thanks in advance!

@jdconrad
Copy link
Contributor Author

jdconrad commented Mar 8, 2019

@elasticmachine run elasticsearch-ci/1

@jdconrad
Copy link
Contributor Author

jdconrad commented Mar 11, 2019

@martijnvg I added comprehensive serialization tests. I also added a pair of yaml tests that execute against the two queries, but given the nature of the responses it was unrealistic to add checks against them at this time since the contains assertion will not work against lists.
Edit: Ready for re-review when you have the chance. Thanks!

Copy link
Member

@martijnvg martijnvg left a comment

Choose a reason for hiding this comment

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

I also added a pair of yaml tests that execute against the two queries, but given the nature of the responses it was unrealistic to add checks against them at this time since the contains assertion will not work against lists.

See my comment in PainlessContextInfo constructor, maybe we can assert the response.


public static class TransportAction extends HandledTransportAction<Request, Response> {

PainlessScriptEngine painlessScriptEngine;
Copy link
Member

Choose a reason for hiding this comment

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

maybe make this field final?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

public static final ParseField NAME = new ParseField("name");
public static final ParseField CLASSES = new ParseField("classes");
public static final ParseField IMPORTED_METHODS = new ParseField("imported_methods");
public static final ParseField ClASS_BINDINGS = new ParseField("class_bindings");
Copy link
Member

Choose a reason for hiding this comment

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

should ClASS_BINDINGS be CLASS_BINDINGS

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Man, your eyes are way better than mine. Fixed.

painlessLookup.getClasses().stream().map(
javaClass -> new PainlessContextClassInfo(javaClass, painlessLookup.lookupPainlessClass(javaClass))
).collect(Collectors.toList()),
painlessLookup.getImportedPainlessMethodsKeys().stream().map(importedPainlessMethodKey -> {
Copy link
Member

Choose a reason for hiding this comment

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

maybe add .sort(custom comparator) to the chaining here in order to generate consistent response?
This will then also allow to the test the response in the yaml test?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorted everything that made sense to sort.

@jdconrad
Copy link
Contributor Author

@martijnvg So I changed the following:

  1. Added a new field to PainlessContextClassInfo called imported that says if a class can be accessed through it's imported name (java.lang.Object -> Object)
  2. Simplified the response object for the action to have data structures more in line with what's actually being returned and sort the contexts upon return for easier testing.
  3. Sorted constructors, methods, and fields with PainlessContextClassInfo. Sorted the classes within PainlessContextInfo.
  4. Added numerous matches against the yaml tests (thanks for the tip about lists again :) )

Ready for the next round of review.

Copy link
Member

@martijnvg martijnvg left a comment

Choose a reason for hiding this comment

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

LGTM - Thanks @jdconrad this looks great.
I only left a minor comment.

public Response(StreamInput in) throws IOException {
super(in);
scriptContextNames = in.readBoolean() ? in.readStringList() : null;
painlessContextInfo = in.readBoolean() ? new PainlessContextInfo(in) : null;
Copy link
Member

Choose a reason for hiding this comment

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

instead of the ternary expressions maybe use: readOptionalWriteable(...) and just use an empty list for scriptContextNames (if there isn't anything)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you for readOptionalWritable! That's what I was looking for, but failed to find it.

out.writeStringCollection(scriptContextNames);
}

if (painlessContextInfo == null) {
Copy link
Member

Choose a reason for hiding this comment

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

same as the previous comment, maybe use writeOptionalWriteable(...) and empty list for scriptContextNames ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same as above.

@jdconrad
Copy link
Contributor Author

jdconrad commented Mar 13, 2019

@martijnvg Thank you for all the iterations of review! Will commit as soon as CI passes.

@jdconrad jdconrad removed the request for review from rjernst March 13, 2019 17:13
@martijnvg
Copy link
Member

@jdconrad Looks great!

@jdconrad jdconrad merged commit d803676 into elastic:master Mar 14, 2019
jdconrad added a commit that referenced this pull request Mar 14, 2019
This PR adds an internal REST API for querying context information about 
Painless whitelists.

Commands include the following:
GET /_scripts/painless/_context -- retrieves a list of contexts
GET /_scripts/painless/_context?context=%name% retrieves all available 
information about the API for this specific context
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
:Core/Infra/Scripting Scripting abstractions, Painless, and Mustache >enhancement v7.2.0 v8.0.0-alpha1
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants