Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

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:

<topology> <gateway> <provider/> <chain name=""> <provider role="" name=""> <param name="" value=""/> </provider> <provider/> </chain> </gateway> </topology>
Code Block
java
java
titleServiceDeploymentContributor.contributeService
linenumberstrue

  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
xmlxml
titleSample Topology Descriptor
linenumberstrue


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
java
java
titleDeploymentContextWebHdfsDeploymentContributor.contributeService
linenumberstrue

  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
javajava
titleServiceDeploymentContributor
linenumberstrue

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
xml
xml
titleSample Topology Descriptor
linenumberstrue
<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
java
java
titleDeploymentContext
linenumberstrue
public interface DeploymentContext {
  ...
  @Deprecated
  void contributeFilter(
      Service service,
      ResourceDescriptor resource,
      String role,
      String name,
      List<FilterParamDescriptor> params );

  void contributeChain(
Code Block
javajava
titleProviderDeploymentContributor
linenumberstrue

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
java
java
titleServiceDeploymentContributor
linenumberstrue
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
java
java
titleProviderDeploymentContributor
linenumberstrue
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
titleSample Sequences

@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