-
Notifications
You must be signed in to change notification settings - Fork 3.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
xds: unify client and server handling HttpConnectionManager #8228
xds: unify client and server handling HttpConnectionManager #8228
Conversation
…I listener and network filter in TCP listener's filter chain.
…unified_lds_message_handler_for_client_and_server
…nt and server side. This adds the requirement for server side HttpConnectionManager to have either RDS or inlined RouteConfiguration.
…unified_lds_message_handler_for_client_and_server
…ering cluster_manager LB policy config parser is able to handle config with empty childPolicy.
7772fc8
to
f735616
Compare
Added support for Route with non-forwarding action and did more cleanup for tests. Also, the PR description is updated. PTAL. |
Added a test case for covering parsing RBACPerRoute. CIs should pass after #8262 is merged. |
…unified_lds_message_handler_for_client_and_server
"FilterChain " + proto.getName() + " contains filter " + filter.getName() | ||
+ " with unsupported typed_config type " + any.getTypeUrl()); | ||
} | ||
// Any filters after the first HttpConnectionManager are ignored. |
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.
The code doesn't actually ignore filters after the first HCM. If you break the loop after line 335 it would have.
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.
Why? there is a if (httpConnectionManager == null)
statement guarding the code of parsing HCM. We still want to loop over the list of network filters, just in case there are filters with duplicated name or filters other than HCM.
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.
... We still want to loop over the list of network filters, just in case there are filters with duplicated name or filters other than HCM.
That is not ignoring and the comment is wrong. But if the code matches the spec (from A36 gRFC) then it's a minor issue. The spec tells to validate all of them but not use any for processing. So the code seems to be right (but the comment doesn't match)
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.
Well, the comment is really intend to mean we will take the first HttpConnectionManager. I will update or delete the comment if you think that is confusing.
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.
Deleted the comment.
if (filter == null) { | ||
Filter filter = filterRegistry.get(typeUrl); | ||
if (filter == null || (!isForClient && filter.isSupportedOnClients()) | ||
|| (isForClient && filter.isSupportedOnServers())) { |
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.
This expression should be:
if (filter == null || (isForClient && !filter.isSupportedOnClients())
|| (!isForClient && !filter.isSupportedOnServers()))
Basically: if I am processing for-client but the filter-is-not-supported-on-clients OR I am processing for-server but the filter-is-not-supported-on-servers
The 2 are not equivalent because isSupportedOnClients()
and isSupportedOnServers()
are not opposite of each other.
Tests should also be added/modified to enforce the correct logic.
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.
Ahhh, good catch. !isForClient
== isForServer, this is awkward. I wish I could use an enum instead of a boolean. But thought that's an overkill for such a small thing. I will fix and add some test.
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.
Fixed, and enabled Router filter for server side. It will be used for both client and server, and we can easily use it in the test to cover this logic. Also, I deleted the newly added interface methods isSupportedOnClients()
and isSupportedOnServers()
. Those are redundant, can just check with instance of ClientInterceptorBuilder
and instance of ServerInterceptorBuilder
. It's cumbersome to have two sources of truth.
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.
Those are redundant, can just check with instance of ClientInterceptorBuilder and instance of ServerInterceptorBuilder. It's cumbersome to have two sources of truth.
Yes but isSupported...
are more readable and I prefer those. These could have been made default methods in the interface with the correct Java version.
} | ||
Message rawConfig = anyConfig; | ||
if (anyConfig.getTypeUrl().equals(TYPE_URL_TYPED_STRUCT)) { |
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.
anyConfig.getTypeUrl()
should be same as typeUrl
so no need to use the longer expression?
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.
Sounds good. Updated.
case FILTER_ACTION: | ||
return StructOrError.fromError("Unsupported action type: filter_action"); | ||
return StructOrError.fromError( | ||
"Route [" + proto.getName() + "] with unsupported action type: filter_action"); |
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.
Why not simplify:
case REDIRECT:
case DIRECT_RESPONSE:
case FILTER_ACTION:
return StructOrError.fromError(
"Route [" + proto.getName() + "] with unsupported action type: " + proto.getActionCase());
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.
Updated.
…mentation is supported for client/server. Also implement the Router filter for server side's usage.
…entation can be used for client/server.
if (isOptional) { | ||
return null; | ||
} else { | ||
return StructOrError.fromError( | ||
"HttpFilter [" + filterName + "] is not optional and has an unsupported config type: " | ||
+ typeUrl); | ||
"HttpFilter [" + filterName + "](" + typeUrl + ") is required but unsupported for " |
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.
I noticed you don't have a test to verify this error generation. So the original bug on lines 523-524 went undetected.
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.
Actually it is tested. See tests started with parseHttpFilter_
:
- The RouterFilter is supported for both client and server, so we use it to cover the branch
isForClient && (filter instanceof ClientInterceptorBuilder)
and!isForClient && (filter instanceof ServerInterceptorBuilder)
. - The FaultFilter is supported for client only, so we used it to cover the branch
!isForClient && !(filter instanceof ServerInterceptorBuilder)
- The RbacFilter is supported for server only, so we used it to cover the branch
isForClient && !(filter instanceof ClientInterceptorBuilder)
The four branches covered all forClient + supported/unsupported and forServer + supported/unsupported cases.
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.
Eliminated the boolean zen in line 523-524, filter == null ||
is not needed, its included in instanceof
.
import java.util.concurrent.ScheduledExecutorService; | ||
import javax.annotation.Nullable; | ||
|
||
/** | ||
* Router filter implementation. Currently this filter does not parse any field in the config. | ||
*/ | ||
enum RouterFilter implements Filter, ClientInterceptorBuilder { | ||
enum RouterFilter implements Filter, ClientInterceptorBuilder, ServerInterceptorBuilder { |
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.
Not from this PR but why use enum
when clearly this type is not used to enumerate constants? enum
works given how this is used but I wouldn't think of the RouterFilter
as an enum.
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.
In Java, enum types are considered to be a special type of class. When creating an enum class, the compiler will create instances (objects) of each enum constants. So enum can be an easy trick to create singletons.
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.
LG. I have left a comment about an error case not being tested. It will be good to address that.
Enables parsing HttpConnectionManager filter for the server side TCP listener, with the same codepath for handling it on the client side. Major changes include:
LdsUpdate
with HttpConnectionManager. NowLdsUpdate
is an oneof ofHttpConnectionManager
(for client side) orListener
(for server side). Each ofListener
'sFiliterChain
contains an HttpConnectionManager (required).Listener
(for server side), put it into ClientXdsClient. The common part of validating/parsing HttpConnectionManager is reused/shared for client side.name
of FilterChain in the parsed form. As specified by the API, each FilterChain has a unique name. If the name is not provided by the control plane, a UUID is used. FilterChain names can be used for bookkeeping a set of FilterChain easily (e.g., used as map key).isSupportedOnClients()
andisSupportedOnServers()
to theFilter
interface. Parsing the top-level HttpFilter requires knowing if the HttpFilter implementation is supported for the target usage (client-side or server-side). Note, parsing override HttpFilter configs does not need to know whether the config is used for an HttpFilter that is only supported for the client-side or server side.