All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.cdap.cdap.internal.app.runtime.distributed.remote.RemoteExecutionDiscoveryService Maven / Gradle / Ivy
/*
* Copyright © 2019-2021 Cask Data, Inc.
*
* Licensed 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 io.cdap.cdap.internal.app.runtime.distributed.remote;
import io.cdap.cdap.api.common.Bytes;
import io.cdap.cdap.common.conf.CConfiguration;
import io.cdap.cdap.common.conf.Constants;
import io.cdap.cdap.common.discovery.URIScheme;
import io.cdap.cdap.common.utils.Networks;
import io.cdap.cdap.internal.app.runtime.distributed.runtimejob.DefaultRuntimeJob;
import io.cdap.cdap.internal.app.runtime.monitor.proxy.ServiceSocksProxy;
import io.cdap.cdap.master.spi.discovery.DefaultServiceDiscovered;
import io.cdap.cdap.proto.ProgramType;
import io.cdap.cdap.proto.id.NamespaceId;
import io.cdap.cdap.runtime.spi.RuntimeMonitorType;
import org.apache.twill.common.Cancellable;
import org.apache.twill.discovery.Discoverable;
import org.apache.twill.discovery.DiscoveryService;
import org.apache.twill.discovery.DiscoveryServiceClient;
import org.apache.twill.discovery.ServiceDiscovered;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.inject.Inject;
/**
* A discovery service implementation used in remote runtime execution. It has a fixed list of services
* that will go through {@link ServiceSocksProxy}, hence won't resolve the service name to an actual address.
* It also use the {@link CConfiguration} as the backing store for service announcements, which is suitable for
* the current remote runtime that has some "mini" system services running in the {@link DefaultRuntimeJob}.
*/
public class RemoteExecutionDiscoveryService implements DiscoveryServiceClient, DiscoveryService {
private static final Logger LOG = LoggerFactory.getLogger(RemoteExecutionDiscoveryService.class);
private final CConfiguration cConf;
private final Map services;
private final Discoverable runtimeMonitorDiscoverable;
@Inject
RemoteExecutionDiscoveryService(CConfiguration cConf, RuntimeMonitorType monitorType) {
this.cConf = cConf;
this.services = new ConcurrentHashMap<>();
this.runtimeMonitorDiscoverable = createMonitorDiscoverable(cConf, monitorType);
}
@Override
public synchronized Cancellable register(Discoverable discoverable) {
String serviceName = discoverable.getName();
DefaultServiceDiscovered serviceDiscovered = services.computeIfAbsent(serviceName, DefaultServiceDiscovered::new);
// Add the address to cConf
String key = Constants.RuntimeMonitor.DISCOVERY_SERVICE_PREFIX + serviceName;
Networks.addDiscoverable(cConf, key, discoverable);
LOG.debug("Discoverable {} with address {} added to configuration with payload {}",
discoverable.getName(), discoverable.getSocketAddress(), Bytes.toString(discoverable.getPayload()));
// Update the ServiceDiscovered
updateServiceDiscovered(serviceDiscovered, cConf, key);
return () -> {
synchronized (RemoteExecutionDiscoveryService.this) {
Networks.removeDiscoverable(cConf, key, discoverable);
updateServiceDiscovered(serviceDiscovered, cConf, key);
}
};
}
@Override
public ServiceDiscovered discover(String name) {
// In Remote runtime, we don't support program discovery except for the SYSTEM namespace.
for (ProgramType programType : ProgramType.values()) {
if (programType.isDiscoverable()
&& name.startsWith(programType.getDiscoverableTypeName() + ".")
&& !name.startsWith(programType.getDiscoverableTypeName() + "." + NamespaceId.SYSTEM.getNamespace() + ".")) {
return new DefaultServiceDiscovered(name);
}
}
// Discovery for system services
DefaultServiceDiscovered serviceDiscovered = services.get(name);
String key = Constants.RuntimeMonitor.DISCOVERY_SERVICE_PREFIX + name;
// Use a while loop to resolve races between discover and cancellable of register
while (serviceDiscovered == null) {
// Try to add the ServiceDiscovered object
serviceDiscovered = new DefaultServiceDiscovered(name);
synchronized (this) {
updateServiceDiscovered(serviceDiscovered, cConf, key);
services.putIfAbsent(name, serviceDiscovered);
}
serviceDiscovered = services.get(name);
}
return serviceDiscovered;
}
private void updateServiceDiscovered(DefaultServiceDiscovered serviceDiscovered, CConfiguration cConf, String key) {
String name = serviceDiscovered.getName();
Set discoverables = Networks.getDiscoverables(cConf, key);
if (discoverables.isEmpty()) {
Discoverable discoverable;
if (name.equals(runtimeMonitorDiscoverable.getName())) {
discoverable = runtimeMonitorDiscoverable;
} else {
// If there is no address from the configuration, assuming it is using the service proxy,
// hence the discovery name is the hostname. Also use port == 0 so that the RemoteExecutionProxySelector
// knows that it need to use service proxy.
URIScheme scheme = cConf.getBoolean(Constants.Security.SSL.INTERNAL_ENABLED) ? URIScheme.HTTPS : URIScheme.HTTP;
discoverable = scheme.createDiscoverable(name, InetSocketAddress.createUnresolved(name, 0));
}
discoverables = Collections.singleton(discoverable);
}
if (LOG.isDebugEnabled()) {
for (Discoverable d : discoverables) {
LOG.debug("Update discoverable {} with address {} and payload {}",
d.getName(), d.getSocketAddress(), Bytes.toString(d.getPayload()));
}
}
serviceDiscovered.setDiscoverables(discoverables);
}
/**
* Creates a {@link Discoverable} for the runtime monitor service.
*/
private static Discoverable createMonitorDiscoverable(CConfiguration cConf, RuntimeMonitorType monitorType) {
if (monitorType == RuntimeMonitorType.URL) {
// For monitor type URL, the monitor url is always set
String url = cConf.get(Constants.RuntimeMonitor.MONITOR_URL);
try {
return URIScheme.createDiscoverable(Constants.Service.RUNTIME, new URL(url));
} catch (MalformedURLException e) {
throw new IllegalArgumentException("Invalid monitor URL " + url, e);
}
}
// If there is no runtime monitor URL, default to the service socks proxy mechanism, in which the
// hostname is the service name with port == 0.
URIScheme scheme = cConf.getBoolean(Constants.RuntimeMonitor.SSL_ENABLED) ? URIScheme.HTTPS : URIScheme.HTTP;
return scheme.createDiscoverable(Constants.Service.RUNTIME,
InetSocketAddress.createUnresolved(Constants.Service.RUNTIME, 0));
}
}