Skip to content

Commit

Permalink
KNOX-2395 - Make Gateway Services Pluggable (#358)
Browse files Browse the repository at this point in the history
  • Loading branch information
smolnar82 committed Jul 14, 2020
1 parent 5c1992e commit ae5c586
Show file tree
Hide file tree
Showing 52 changed files with 2,056 additions and 185 deletions.
4 changes: 4 additions & 0 deletions gateway-release/home/conf/gateway-site.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ limitations under the License.
-->
<configuration>

<property>
<name>gateway.service.alias.impl</name>
<value>org.apache.knox.gateway.services.security.impl.RemoteAliasService</value>
</property>
<property>
<name>gateway.port</name>
<value>8443</value>
Expand Down
4 changes: 4 additions & 0 deletions gateway-server/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@
<groupId>org.apache.knox</groupId>
<artifactId>gateway-topology-hadoop-xml</artifactId>
</dependency>
<dependency>
<groupId>org.apache.knox</groupId>
<artifactId>gateway-service-hashicorp-vault</artifactId>
</dependency>
<dependency>
<groupId>org.apache.knox</groupId>
<artifactId>gateway-i18n</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -698,4 +698,10 @@ void errorRespondingToConfigChange(String source,

@Message(level = MessageLevel.ERROR, text = "Error creating provider descriptor {0} from topology {1}, cause: {2}")
void errorSavingDescriptorConfiguration(String providerPath, String topologyName, String message);

@Message(level = MessageLevel.ERROR, text = "No service found by type {0}")
void noServiceFound(String serviceType);

@Message(level = MessageLevel.INFO, text = "Using {0} implementation for {1}")
void usingServiceImplementation(String implementation, String serviceType);
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ public class GatewayConfigImpl extends Configuration implements GatewayConfig {

private static final String[] GATEWAY_CONFIG_FILENAMES = {GATEWAY_CONFIG_FILE_PREFIX + "-default.xml", GATEWAY_CONFIG_FILE_PREFIX + "-site.xml"};

private static final String GATEWAY_SERVICE_PREFIX = GATEWAY_CONFIG_FILE_PREFIX + ".service.";
public static final String HTTP_HOST = GATEWAY_CONFIG_FILE_PREFIX + ".host";
public static final String HTTP_PORT = GATEWAY_CONFIG_FILE_PREFIX + ".port";
public static final String HTTP_PATH = GATEWAY_CONFIG_FILE_PREFIX + ".path";
Expand Down Expand Up @@ -1165,4 +1166,10 @@ public boolean isKnoxTokenPermissiveValidationEnabled() {
return getBoolean(KNOX_TOKEN_PERMISSIVE_VALIDATION_ENABLED,
KNOX_TOKEN_PERMISSIVE_VALIDATION_ENABLED_DEFAULT);
}

@Override
public String getServiceParameter(String service, String parameter) {
return get(GATEWAY_SERVICE_PREFIX + service + "." + parameter, "");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,77 +17,42 @@
*/
package org.apache.knox.gateway.services;

import java.util.List;
import java.util.Map;

import org.apache.knox.gateway.config.GatewayConfig;
import org.apache.knox.gateway.deploy.DeploymentContext;
import org.apache.knox.gateway.descriptor.FilterParamDescriptor;
import org.apache.knox.gateway.descriptor.ResourceDescriptor;
import org.apache.knox.gateway.service.config.remote.RemoteConfigurationRegistryClientServiceFactory;
import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClientService;
import org.apache.knox.gateway.services.security.impl.RemoteAliasService;
import org.apache.knox.gateway.services.topology.impl.DefaultTopologyService;
import org.apache.knox.gateway.services.security.impl.DefaultAliasService;
import org.apache.knox.gateway.services.security.impl.DefaultCryptoService;
import org.apache.knox.gateway.services.security.impl.DefaultKeystoreService;
import org.apache.knox.gateway.services.security.impl.CLIMasterService;
import org.apache.knox.gateway.topology.Provider;

import java.util.List;
import java.util.Map;

public class CLIGatewayServices extends AbstractGatewayServices {

private final GatewayServiceFactory gatewayServiceFactory = new GatewayServiceFactory();

public CLIGatewayServices() {
super("Services", "GatewayServices");
}

@Override
public void init(GatewayConfig config, Map<String,String> options) throws ServiceLifecycleException {
CLIMasterService ms = new CLIMasterService();
ms.init(config, options);
addService(ServiceType.MASTER_SERVICE, ms);

DefaultKeystoreService ks = new DefaultKeystoreService();
ks.setMasterService(ms);
ks.init(config, options);
addService(ServiceType.KEYSTORE_SERVICE, ks);

DefaultAliasService defaultAlias = new DefaultAliasService();
defaultAlias.setKeystoreService(ks);
defaultAlias.setMasterService(ms);
defaultAlias.init(config, options);
addService(ServiceType.MASTER_SERVICE, gatewayServiceFactory.create(this, ServiceType.MASTER_SERVICE, config, options, CLIMasterService.class.getName()));
addService(ServiceType.KEYSTORE_SERVICE, gatewayServiceFactory.create(this, ServiceType.KEYSTORE_SERVICE, config, options));

/*
Doesn't make sense for this to be set to the remote alias service since the impl could
be remote itself. This uses the default alias service in case of ZK digest authentication.
IE: If ZK digest auth and using ZK remote alias service, then wouldn't be able to connect
to ZK anyway due to the circular dependency.
*/
final RemoteConfigurationRegistryClientService registryClientService =
RemoteConfigurationRegistryClientServiceFactory.newInstance(config);
registryClientService.setAliasService(defaultAlias);
registryClientService.init(config, options);
addService(ServiceType.REMOTE_REGISTRY_CLIENT_SERVICE, registryClientService);
addService(ServiceType.REMOTE_REGISTRY_CLIENT_SERVICE, gatewayServiceFactory.create(this, ServiceType.REMOTE_REGISTRY_CLIENT_SERVICE, config, options));

addService(ServiceType.ALIAS_SERVICE, gatewayServiceFactory.create(this, ServiceType.ALIAS_SERVICE, config, options));

/* create an instance so that it can be passed to other services */
final RemoteAliasService alias = new RemoteAliasService(defaultAlias, ms);
/*
* Setup and initialize remote Alias Service.
* NOTE: registryClientService.init() needs to
* be called before alias.start();
*/
alias.init(config, options);
addService(ServiceType.ALIAS_SERVICE, alias);

DefaultCryptoService crypto = new DefaultCryptoService();
crypto.setKeystoreService(ks);
crypto.setAliasService(alias);
crypto.init(config, options);
addService(ServiceType.CRYPTO_SERVICE, crypto);
addService(ServiceType.CRYPTO_SERVICE, gatewayServiceFactory.create(this, ServiceType.CRYPTO_SERVICE, config, options));

DefaultTopologyService tops = new DefaultTopologyService();
tops.init( config, options );
addService(ServiceType.TOPOLOGY_SERVICE, tops);
addService(ServiceType.TOPOLOGY_SERVICE, gatewayServiceFactory.create(this, ServiceType.TOPOLOGY_SERVICE, config, options));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,138 +17,67 @@
*/
package org.apache.knox.gateway.services;

import java.util.List;
import java.util.Map;

import org.apache.knox.gateway.GatewayMessages;
import org.apache.knox.gateway.config.GatewayConfig;
import org.apache.knox.gateway.deploy.DeploymentContext;
import org.apache.knox.gateway.descriptor.FilterParamDescriptor;
import org.apache.knox.gateway.descriptor.ResourceDescriptor;
import org.apache.knox.gateway.i18n.messages.MessagesFactory;
import org.apache.knox.gateway.service.config.remote.RemoteConfigurationRegistryClientServiceFactory;
import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClientService;
import org.apache.knox.gateway.services.registry.impl.DefaultServiceDefinitionRegistry;
import org.apache.knox.gateway.services.metrics.impl.DefaultMetricsService;
import org.apache.knox.gateway.services.security.KeystoreService;
import org.apache.knox.gateway.services.security.impl.RemoteAliasService;
import org.apache.knox.gateway.services.token.impl.AliasBasedTokenStateService;
import org.apache.knox.gateway.services.topology.impl.DefaultClusterConfigurationMonitorService;
import org.apache.knox.gateway.services.topology.impl.DefaultTopologyService;
import org.apache.knox.gateway.services.hostmap.impl.DefaultHostMapperService;
import org.apache.knox.gateway.services.registry.impl.DefaultServiceRegistryService;
import org.apache.knox.gateway.services.security.KeystoreServiceException;
import org.apache.knox.gateway.services.security.impl.DefaultAliasService;
import org.apache.knox.gateway.services.security.impl.DefaultCryptoService;
import org.apache.knox.gateway.services.security.impl.DefaultKeystoreService;
import org.apache.knox.gateway.services.security.impl.DefaultMasterService;
import org.apache.knox.gateway.services.security.impl.JettySSLService;
import org.apache.knox.gateway.services.token.impl.DefaultTokenAuthorityService;
import org.apache.knox.gateway.topology.Provider;

import java.util.List;
import java.util.Map;

public class DefaultGatewayServices extends AbstractGatewayServices {
private static GatewayMessages log = MessagesFactory.get( GatewayMessages.class );
private final GatewayServiceFactory gatewayServiceFactory = new GatewayServiceFactory();

public DefaultGatewayServices() {
super("Services", "GatewayServices");
}

@Override
public void init(GatewayConfig config, Map<String,String> options) throws ServiceLifecycleException {
DefaultMasterService ms = new DefaultMasterService();
ms.init(config, options);
addService(ServiceType.MASTER_SERVICE, ms);

DefaultKeystoreService ks = new DefaultKeystoreService();
ks.setMasterService(ms);
ks.init(config, options);
addService(ServiceType.KEYSTORE_SERVICE, ks);

final DefaultAliasService defaultAlias = new DefaultAliasService();
defaultAlias.setKeystoreService(ks);
defaultAlias.setMasterService(ms);
defaultAlias.init(config, options);
//order is important: different service factory implementations may use already added services
addService(ServiceType.MASTER_SERVICE, gatewayServiceFactory.create(this, ServiceType.MASTER_SERVICE, config, options));
addService(ServiceType.KEYSTORE_SERVICE, gatewayServiceFactory.create(this, ServiceType.KEYSTORE_SERVICE, config, options));

/*
Doesn't make sense for this to be set to the remote alias service since the impl could
be remote itself. This uses the default alias service in case of ZK digest authentication.
IE: If ZK digest auth and using ZK remote alias service, then wouldn't be able to connect
to ZK anyway due to the circular dependency.
*/
final RemoteConfigurationRegistryClientService registryClientService =
RemoteConfigurationRegistryClientServiceFactory.newInstance(config);
registryClientService.setAliasService(defaultAlias);
registryClientService.init(config, options);
addService(ServiceType.REMOTE_REGISTRY_CLIENT_SERVICE, registryClientService);
addService(ServiceType.REMOTE_REGISTRY_CLIENT_SERVICE, gatewayServiceFactory.create(this, ServiceType.REMOTE_REGISTRY_CLIENT_SERVICE, config, options));

addService(ServiceType.ALIAS_SERVICE, gatewayServiceFactory.create(this, ServiceType.ALIAS_SERVICE, config, options));

/* create an instance so that it can be passed to other services */
final RemoteAliasService alias = new RemoteAliasService(defaultAlias, ms);
/*
* Setup and initialize remote Alias Service.
* NOTE: registryClientService.init() needs to
* be called before alias.start();
*/
alias.init(config, options);
addService(ServiceType.ALIAS_SERVICE, alias);
addService(ServiceType.CRYPTO_SERVICE, gatewayServiceFactory.create(this, ServiceType.CRYPTO_SERVICE, config, options));

DefaultCryptoService crypto = new DefaultCryptoService();
crypto.setKeystoreService(ks);
crypto.setAliasService(alias);
crypto.init(config, options);
addService(ServiceType.CRYPTO_SERVICE, crypto);

JettySSLService ssl = new JettySSLService();
ssl.setAliasService(alias);
ssl.setKeystoreService(ks);
ssl.init(config, options);
addService(ServiceType.SSL_SERVICE, ssl);
addService(ServiceType.SSL_SERVICE, gatewayServiceFactory.create(this, ServiceType.SSL_SERVICE, config, options));

// The DefaultTokenAuthorityService needs to be initialized after the JettySSLService to ensure
// that the signing keystore is available for it.
DefaultTokenAuthorityService ts = new DefaultTokenAuthorityService();
ts.setAliasService(alias);
ts.setKeystoreService(ks);
ts.init(config, options);
// prolly should not allow the token service to be looked up?
addService(ServiceType.TOKEN_SERVICE, ts);

AliasBasedTokenStateService tss = new AliasBasedTokenStateService();
tss.setAliasService(alias);
tss.init(config, options);
addService(ServiceType.TOKEN_STATE_SERVICE, tss);

DefaultServiceRegistryService sr = new DefaultServiceRegistryService();
sr.setCryptoService( crypto );
sr.init( config, options );
addService(ServiceType.SERVICE_REGISTRY_SERVICE, sr);

DefaultHostMapperService hm = new DefaultHostMapperService();
hm.init( config, options );
addService(ServiceType.HOST_MAPPING_SERVICE, hm );

DefaultServerInfoService sis = new DefaultServerInfoService();
sis.init( config, options );
addService(ServiceType.SERVER_INFO_SERVICE, sis );

DefaultClusterConfigurationMonitorService ccs = new DefaultClusterConfigurationMonitorService();
ccs.setAliasService(alias);
ccs.setKeystoreService(ks);
ccs.init(config, options);
addService(ServiceType.CLUSTER_CONFIGURATION_MONITOR_SERVICE, ccs);

DefaultTopologyService tops = new DefaultTopologyService();
tops.setAliasService(alias);
tops.init( config, options );
addService(ServiceType.TOPOLOGY_SERVICE, tops );

DefaultServiceDefinitionRegistry sdr = new DefaultServiceDefinitionRegistry();
sdr.init( config, options );
addService(ServiceType.SERVICE_DEFINITION_REGISTRY, sdr );

DefaultMetricsService metricsService = new DefaultMetricsService();
metricsService.init( config, options );
addService(ServiceType.METRICS_SERVICE, metricsService );
// probably should not allow the token service to be looked up?
addService(ServiceType.TOKEN_SERVICE, gatewayServiceFactory.create(this, ServiceType.TOKEN_SERVICE, config, options));

addService(ServiceType.TOKEN_STATE_SERVICE, gatewayServiceFactory.create(this, ServiceType.TOKEN_STATE_SERVICE, config, options));

addService(ServiceType.SERVICE_REGISTRY_SERVICE, gatewayServiceFactory.create(this, ServiceType.SERVICE_REGISTRY_SERVICE, config, options));

addService(ServiceType.HOST_MAPPING_SERVICE, gatewayServiceFactory.create(this, ServiceType.HOST_MAPPING_SERVICE, config, options));

addService(ServiceType.SERVER_INFO_SERVICE, gatewayServiceFactory.create(this, ServiceType.SERVER_INFO_SERVICE, config, options));

addService(ServiceType.CLUSTER_CONFIGURATION_MONITOR_SERVICE, gatewayServiceFactory.create(this, ServiceType.CLUSTER_CONFIGURATION_MONITOR_SERVICE, config, options));

addService(ServiceType.TOPOLOGY_SERVICE, gatewayServiceFactory.create(this, ServiceType.TOPOLOGY_SERVICE, config, options));

addService(ServiceType.SERVICE_DEFINITION_REGISTRY, gatewayServiceFactory.create(this, ServiceType.SERVICE_DEFINITION_REGISTRY, config, options));

addService(ServiceType.METRICS_SERVICE, gatewayServiceFactory.create(this, ServiceType.METRICS_SERVICE, config, options));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.knox.gateway.services;

import java.util.Map;
import java.util.ServiceLoader;

import org.apache.knox.gateway.GatewayMessages;
import org.apache.knox.gateway.config.GatewayConfig;
import org.apache.knox.gateway.i18n.messages.MessagesFactory;

public class GatewayServiceFactory implements ServiceFactory {
private static final GatewayMessages LOG = MessagesFactory.get(GatewayMessages.class);
private ServiceLoader<ServiceFactory> serviceFactories;

@Override
public Service create(GatewayServices gatewayServices, ServiceType serviceType, GatewayConfig gatewayConfig, Map<String, String> options) throws ServiceLifecycleException {
return create(gatewayServices, serviceType, gatewayConfig, options, null);
}

@Override
public Service create(GatewayServices gatewayServices, ServiceType serviceType, GatewayConfig gatewayConfig, Map<String, String> options, String implementation)
throws ServiceLifecycleException {
Service service = null;
for (ServiceFactory serviceFactory : getServiceFactories()) {
service = implementation == null ? serviceFactory.create(gatewayServices, serviceType, gatewayConfig, options)
: serviceFactory.create(gatewayServices, serviceType, gatewayConfig, options, implementation);
if (service != null) {
break;
}
}
if (service != null) {
service.init(gatewayConfig, options);
} else {
LOG.noServiceFound(serviceType.getServiceTypeName());
}
return service;
}

private ServiceLoader<ServiceFactory> getServiceFactories() {
if (serviceFactories == null) {
serviceFactories = ServiceLoader.load(ServiceFactory.class);
}
return serviceFactories;
}
}
Loading

0 comments on commit ae5c586

Please sign in to comment.