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

Adding ApiFilteringActionFilter #97985

Merged
merged 4 commits into from Jul 26, 2023

Conversation

masseyke
Copy link
Member

@masseyke masseyke commented Jul 26, 2023

This PR adds an abstract ActionFilter meant to be extended in serverless modules that need to redact part of a response. When an implementing class is registered with a plugin, filterResponse() is applied if the transport action being called is the actionName passed to the constructor and the response's class is the responseClass passed to the constructor.

@elasticsearchmachine
Copy link
Collaborator

Hi @masseyke, I've created a changelog YAML for you.

Copy link
Member

@rjernst rjernst left a comment

Choose a reason for hiding this comment

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

Looks pretty good, I have a couple suggestions.


public abstract Class<Res> getResponseClass();

public abstract CheckedFunction<Res, Res, Exception> getFilteringFunction();
Copy link
Member

Choose a reason for hiding this comment

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

Is there a reason we need the extra level of indirection? Couldn't this be protected abstract Res filterResponse(Res response) throws Exception?

Copy link
Member Author

@masseyke masseyke Jul 26, 2023

Choose a reason for hiding this comment

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

Yeah I just did it this way because that's what ActionListener::map (which is consuming this) requires. But no reason to leak that detail here I poorly refactored some code I'd written before.


private final ThreadContext threadContext;

public ApiFilteringActionFilter(ThreadContext threadContext) {
Copy link
Member

Choose a reason for hiding this comment

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

nit: This could be protected

);
}

public abstract String getActionName();
Copy link
Member

Choose a reason for hiding this comment

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

This could be passed in as a ctor arg instead of having a dynamic method?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah good point.


public abstract String getActionName();

public abstract Class<Res> getResponseClass();
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 above, might be less boiler plate to pass this as a ctor arg

…nstructor, simplifying the filter method signature
…/elasticsearch into adding-ApiFilteringActionFilter
@masseyke masseyke marked this pull request as ready for review July 26, 2023 21:03
@masseyke masseyke requested a review from rjernst July 26, 2023 21:03
@elasticsearchmachine elasticsearchmachine added the Team:Core/Infra Meta label for core/infra team label Jul 26, 2023
@elasticsearchmachine
Copy link
Collaborator

Pinging @elastic/es-core-infra (Team:Core/Infra)

@masseyke masseyke requested a review from pgomulka July 26, 2023 21:04
Copy link
Member

@rjernst rjernst left a comment

Choose a reason for hiding this comment

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

LGTM

@SuppressWarnings("unchecked")
private <Response extends ActionResponse> Response filter(Response response) throws Exception {
if (response.getClass().equals(responseClass)) {
return (Response) filterResponse((Res) response);
Copy link
Member

Choose a reason for hiding this comment

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

Are the casts necessary? Seems like the types match.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think that they are necessary. The problem is that ActionFilter doesn't have class-level generic types I could take advantage of -- they're just on the apply method. I introduced generic types at the class level of ApiFilteringActionFilter so that I could use them throughout the class. They're the same as the ones for the apply method, but the compiler doesn't know that. So I have to do the cast. I think the fix would be to add types at the class level for ActionFilter, but I wasn't sure what all that might break (since it can be used in 3rd-party plugins). Let me know if you're seeing something I'm not seeing though.

Copy link
Member

Choose a reason for hiding this comment

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

Ah sorry, I see it is necessary for the argument to cast, but since Res is already a Response, no cast should be necessary?

Copy link
Member Author

Choose a reason for hiding this comment

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

The compiler disagrees with you :)

> Task :x-pack:plugin:core:compileJava FAILED
/Users/kmassey/workspace/elasticsearch/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/api/filtering/ApiFilteringActionFilter.java:59: error: incompatible types: Res cannot be converted to Response
            return filterResponse((Res) response);
                                 ^
  where Res,Response are type-variables:
    Res extends ActionResponse declared in class ApiFilteringActionFilter
    Response extends ActionResponse declared in method <Response>filter(Response)
1 error

Copy link
Member

Choose a reason for hiding this comment

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

Ok, I see, the names are quite confusing. :) Both Res and Response implement ActionFilter, but there is no association between the two. We can improve this in the future.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm going to go ahead and merge this so that I can get some other PRs going, but let me know if I'm missing something and I'll fix this in a followup PR.

@masseyke masseyke merged commit 157b8f8 into elastic:main Jul 26, 2023
12 checks passed
@masseyke masseyke deleted the adding-ApiFilteringActionFilter branch July 26, 2023 21:57
Copy link
Contributor

@pgomulka pgomulka left a comment

Choose a reason for hiding this comment

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

LGTM

felixbarny pushed a commit to felixbarny/elasticsearch that referenced this pull request Aug 3, 2023
This adds an abstract ActionFilter meant to be extended in serverless modules that need
to redact part of a response. When an implementing class is registered with a plugin,
filterResponse() is applied if the transport action being called is the actionName passed
to the constructor and the response's class is the responseClass passed to the constructor.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
:Core/Infra/Plugins Plugin API and infrastructure >enhancement Team:Core/Infra Meta label for core/infra team v8.10.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants