This design is intended to address the following issues:
KNOX-179@jira: Simple way to introduce new servlet filters into the chains
KNOX-103@jira: Support multiple <pattern> children in <resource> for gateway.xml
KNOX-177@jira: Simplify service deployment contributor implementation
Each of these issues stem This issue stems from what is currently expected of a ServiceDeploymentContributor
in its contributeService
method.
Basically each service deployment contributor is expected to build its own filter chain.
This is currently done by making calls to Deploymentcontext.contributeFilter
.
While this provides a great deal of flexibility for each service to define a custom chain we have found that this isn't commonly necessary.
Furthermore it makes if very difficult if not impossible to introduce new provider/filters in a chain without impacting all services.
This design will provide an abstraction to the service deployment contributors that can create either a default or specifically configured chain of providers/filters.
The goal is to support a pattern in service deployment contributors that looks like this:
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
public void contributeService( DeploymentContext context, Service service ) throws Exception { String chain = null; // Default if null, otherwise specific chain name defined in topoloy.xml Map<String,Map<String,String>> List<ServiceParamDescriptor> params = null; // Default if null, otherwise map of per provider role map of name/value pairs. ResourceDescriptor resource = context.addResource() resource.role( "WEBHDFS" ); resource.pattern( "webhdfs/v1/?**" ); resource.pattern( "webhdfs/v1/**?**" ); context.contributeChain( service, resource, chain, params ); } | ||||||||
Code Block | xml | xml | ||||||
title | Sample Topology Descriptor | |||||||
linenumbers | true |
The over all context into which the method above fits into the deployment infrastructure is shown in the sequence diagram below.
PlantUML |
---|
@startuml
title Contribute Chain
hide footbox
autonumber
participant "Deployment\nFactory\n(df)" as df
participant "Deployment\nContext\n(dc)" as dc
participant "Service\nDeployment\nContributor\n(sdc)" as sdc
participant "Provider\nDeployment\nContributor\n(pdc)" as pdc
activate df
create dc
df -> dc: new
df -> sdc: contributeService(dc)
activate sdc
sdc -> dc: contributeChain()
activate dc
dc -> pdc: contributeFilter()
deactivate dc
sdc --> df
deactivate sdc
deactivate df
@endup
|
The method below shows a more complete example of a contributeService method as it might be implemented for WebHDFS.
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
public void interfacecontributeService( DeploymentContext { context, Service GatewayConfigservice getGatewayConfig(); throws Topology getTopology(); Exception { WebArchive getWebArchive(); WebAppDescriptor getWebAppDescriptor UrlRewriteRulesDescriptor serviceRules = loadRulesFromClassPath(); GatewayDescriptor getGatewayDescriptor(); void contributeChain( UrlRewriteRulesDescriptor clusterRules = context.getDescriptor( "rewrite" ); clusterRules.addRules( Service service, serviceRules ); ResourceDescriptor resource,; String chainName,List<ServiceParamDescriptor> params; resource List<ServiceParamDescriptor> params = context.getGatewayDescriptor().addResource(); void addDescriptor( String name, Object descriptorresource.role( "WEBHDFS" ); <T> T getDescriptor( String nameresource.pattern( "webhdfs/v1/?**" ); } | ||||||||
Code Block | ||||||||
java | java | |||||||
title | ServiceDeploymentContributor | |||||||
linenumbers | true | public interface ServiceDeploymentContributor { // The role of this service deployment contributor. e.g. WEBHDFS String getRole(); // The name of this service deployment contributor. Not used yet. String getName(); // Called after provider initializeContribution methods and in arbitrary order relative to other service contributors. void initializeContribution( DeploymentContext context ); // Called per service based on the service's role. // Returns a list of resources it added to the descriptor. void contributeService( DeploymentContext context, Service service ) throws Exception; // Called after all contributors and before provider finalizeContribution methods. void finalizeContribution( DeploymentContext context ); } resource.pattern( "webhdfs/v1/**?**" ); params = new ArrayList<ServiceParamDescriptor>(); params.add( resource.createParam().role( "rewrite", "request.url", "/webhdfs/namenode/inbound/path" ); params.add( resource.createParam().role( "rewrite", "response.headers", "/webhdfs/namenode/outbound/headers" ); context.contributeChain( service, resource, params ); resource = context.getGatewayDescriptor().addResource(); resource.role( "WEBHDFS" ); resource.pattern( "webhdfs/data/v1/**?**" ); params = new ArrayList<ServiceParamDescriptor>(); params.add( resource.createParam().role( "rewrite", "request.url", "/webhdfs/datanode/inbound/path" ); context.contributeChain( service, resource, params ); } |
This is a sketch of how topology files would need to be extended to support the external chain definitions.
See table below for details on the new elements introduced.
Note: I don't really like the names for provider-ref and chain-ref but I can't come up with anything better.
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
<topology>
<gateway>
<provider>
<role>...</role>
<name>...</name>
<param><name>...</name><value>...</value></param>
</provider>
<chain>
<name>...</name>
<provider-ref>
<role>...</role>
<name>...</name>
<param><name>...</name><value>...</value></param>
</provider-ref>
<provider-ref>...</provider-ref>
</chain>
<chain>...</chain>
</gateway>
<service>
<role>...</role>
<url>...</url>
<chain-ref>
<name>...</name>
<param><role></role><name></name><value></value></param>
</chain-ref>
<param><name></name><value></value></param>
</service>
</topology>
|
Details on the new elements within the topology are described below.
Path | Description |
---|---|
topology/gateway/chain | This defines a new chain structure and configuration for use by services. There will be a "built-in" chain named "default". |
topology/gateway/chain/name | Specifies the name of the chain so that it can be referenced by services. |
topology/gateway/chain/provider-ref | References a configured or default provider. May repeat. |
topology/gateway/chain/provider-ref/role | A required role of a provider to be included in the chain. |
topology/gateway/chain/provider-ref/name | An optional name of a specific provider for the given role. |
topology/gateway/chain/provider-ref/param | Optional config parameters to augment the provider's configuration. |
topology/service/chain-ref | Selects a specific chain to use for the service. May repeat. |
topology/service/chain-ref/name | Specifies the name of the chain to use for the service. Default is "default" |
topology/service/chain-ref/param | Optional parameters to augment the chain and provider configuration. |
topology/service/chain-ref/param/role | A role name to disambiguate which provider the param is intended. |
topology/service/param | Configuration parameters used by the service. May repeat. |
This shows the new method contributeChain()
that would be added to the DeploymentContext interface.
The existing contributeFilter method would be deprecated.
This is actually a point worth further discussion.
Is there a use case where a service might want to define a chain this way?
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
public interface DeploymentContext {
...
@Deprecated
void contributeFilter(
Service service,
ResourceDescriptor resource,
String role,
String name,
List<FilterParamDescriptor> params );
void contributeChain( | ||||||||
Code Block | ||||||||
java | java | |||||||
title | ProviderDeploymentContributor | |||||||
linenumbers | true | public interface ProviderDeploymentContributor { // The role this provider supports (e.g. authentication) String getRole(); // In the topology the provider will have an optional name element. If it is present // then the framework will look for the the provider deployment contributor with the correct // role and name. String getName(); // All provider initializeContribution methods are called first in arbitrary order. void initializeContribution( DeploymentContext context ); // Called for each provider in the topology based on the role and optionally name. void contributeProvider( DeploymentContext context, Provider provider ); // This will be called indirectly by a ServiceDeploymentContributor when it needs a filter // contributed for this providers role. A ServiceDeploymentContributor may request a specific // provider by role and name otherwise the default provider for the role will be used. void contributeFilter( DeploymentContext context, Provider provider, Service service, ResourceDescriptor resource, List<FilterParamDescriptor>List<ServiceParamDescriptor> params ); ... } |
This shows the relevant portions of the existing, unmodified ServiceDeploymentContributor interface.
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
public interface ServiceDeploymentContributor { ... // AllCalled providerper finalizeContributionservice methodsbased areon calledthe last in arbitrary orderservice's role. void finalizeContributioncontributeService( DeploymentContext context, Service service ) throws Exception; ... } |
This shows the relevant portions of the existing, unmodified ProviderDeploymentContributor interface.
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
public interface ProviderDeploymentContributor {
...
// This will be called indirectly by a ServiceDeploymentContributor when it asks
// for a chain to be contributed via DeploymentContext.contributeChain.
void contributeFilter(
DeploymentContext context,
Provider provider,
Service service,
ResourceDescriptor resource,
List<FilterParamDescriptor> params );
...
} | ||||||||
PlantUML | ||||||||
| ||||||||
@startuml
title Contribute Chain
hide footbox
autonumber
participant "Deployment\nFactory\n(df)" as df
participant "Deployment\nContext\n(dc)" as dc
participant "Service\nDeployment\nContributor\n(sdc)" as sdc
participant "Provider\nDeployment\nContributor\n(pdc)" as pdc
activate df
create dc
df -> dc: new
df -> sdc: contributeService(dc)
activate sdc
sdc -> dc: contributeChain()
activate dc
dc -> pdc: contributeFilter()
deactivate dc
sdc --> df
deactivate sdc
deactivate df
@endup
|