X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=netconf%2Fnetconf-topology-singleton%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fnetconf%2Ftopology%2Fsingleton%2Fimpl%2FRemoteDeviceConnectorImpl.java;h=0de0ea6bc3d39bc6921b985382b7c66e4c1035ac;hb=90dcdd5d040eb22b74e87baccffd70a30d93bfc0;hp=a9acbe0c04f473811691f239b3746c818d07fc56;hpb=71f65f66e59aedd94762954ea055531d8f2c9ea8;p=netconf.git diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/RemoteDeviceConnectorImpl.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/RemoteDeviceConnectorImpl.java index a9acbe0c04..0de0ea6bc3 100644 --- a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/RemoteDeviceConnectorImpl.java +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/RemoteDeviceConnectorImpl.java @@ -5,34 +5,34 @@ * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ - package org.opendaylight.netconf.topology.singleton.impl; +import static com.google.common.base.Preconditions.checkState; +import static java.util.Objects.requireNonNull; + import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Preconditions; -import com.google.common.collect.Lists; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; -import io.netty.util.concurrent.EventExecutor; import java.math.BigDecimal; import java.net.InetSocketAddress; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Optional; -import javax.annotation.Nullable; import org.opendaylight.aaa.encrypt.AAAEncryptionService; import org.opendaylight.netconf.api.NetconfMessage; import org.opendaylight.netconf.client.NetconfClientSessionListener; import org.opendaylight.netconf.client.conf.NetconfClientConfiguration; import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfiguration; import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfigurationBuilder; +import org.opendaylight.netconf.nettyutil.ReconnectStrategyFactory; +import org.opendaylight.netconf.nettyutil.TimedReconnectStrategyFactory; import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler; import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.LoginPasswordHandler; +import org.opendaylight.netconf.sal.connect.api.DeviceActionFactory; import org.opendaylight.netconf.sal.connect.api.RemoteDevice; import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler; import org.opendaylight.netconf.sal.connect.netconf.LibraryModulesSchemas; @@ -48,18 +48,16 @@ import org.opendaylight.netconf.sal.connect.netconf.sal.KeepaliveSalFacade; import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfKeystoreAdapter; import org.opendaylight.netconf.sal.connect.netconf.schema.YangLibrarySchemaYangSourceProvider; import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId; +import org.opendaylight.netconf.sal.connect.util.SslHandlerFactoryImpl; import org.opendaylight.netconf.topology.singleton.api.RemoteDeviceConnector; -import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfConnectorDTO; import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup; import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils; -import org.opendaylight.protocol.framework.ReconnectStrategy; -import org.opendaylight.protocol.framework.ReconnectStrategyFactory; -import org.opendaylight.protocol.framework.TimedReconnectStrategy; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Host; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; +import org.opendaylight.netconf.topology.spi.NetconfConnectorDTO; +import org.opendaylight.netconf.topology.spi.NetconfNodeUtils; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri; import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode; import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.parameters.OdlHelloMessageCapabilities; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.parameters.Protocol; import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.available.capabilities.AvailableCapability.CapabilityOrigin; import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.Credentials; import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.KeyAuth; @@ -69,6 +67,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev15 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.login.pw.LoginPassword; import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.login.pw.unencrypted.LoginPasswordUnencrypted; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; +import org.opendaylight.yangtools.yang.common.Decimal64; import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier; import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource; import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource; @@ -88,17 +87,21 @@ public class RemoteDeviceConnectorImpl implements RemoteDeviceConnector { private final String privateKeyPath; private final String privateKeyPassphrase; private final AAAEncryptionService encryptionService; - private NetconfConnectorDTO deviceCommunicatorDTO; private final NetconfKeystoreAdapter keystoreAdapter; + private final DeviceActionFactory deviceActionFactory; - public RemoteDeviceConnectorImpl(final NetconfTopologySetup netconfTopologyDeviceSetup, - final RemoteDeviceId remoteDeviceId) { + // FIXME: this seems to be a builder-like transition between {start,stop}RemoteDeviceConnection. More documentation + // is needed, as to what the lifecycle is here. + private NetconfConnectorDTO deviceCommunicatorDTO; - this.netconfTopologyDeviceSetup = Preconditions.checkNotNull(netconfTopologyDeviceSetup); + public RemoteDeviceConnectorImpl(final NetconfTopologySetup netconfTopologyDeviceSetup, + final RemoteDeviceId remoteDeviceId, final DeviceActionFactory deviceActionFactory) { + this.netconfTopologyDeviceSetup = requireNonNull(netconfTopologyDeviceSetup); this.remoteDeviceId = remoteDeviceId; - this.privateKeyPath = netconfTopologyDeviceSetup.getPrivateKeyPath(); - this.privateKeyPassphrase = netconfTopologyDeviceSetup.getPrivateKeyPassphrase(); - this.encryptionService = netconfTopologyDeviceSetup.getEncryptionService(); + this.deviceActionFactory = requireNonNull(deviceActionFactory); + privateKeyPath = netconfTopologyDeviceSetup.getPrivateKeyPath(); + privateKeyPassphrase = netconfTopologyDeviceSetup.getPrivateKeyPassphrase(); + encryptionService = netconfTopologyDeviceSetup.getEncryptionService(); keystoreAdapter = new NetconfKeystoreAdapter(netconfTopologyDeviceSetup.getDataBroker()); } @@ -107,11 +110,10 @@ public class RemoteDeviceConnectorImpl implements RemoteDeviceConnector { final NetconfNode netconfNode = netconfTopologyDeviceSetup.getNode().augmentation(NetconfNode.class); final NodeId nodeId = netconfTopologyDeviceSetup.getNode().getNodeId(); - Preconditions.checkNotNull(netconfNode.getHost()); - Preconditions.checkNotNull(netconfNode.getPort()); - Preconditions.checkNotNull(netconfNode.isTcpOnly()); + requireNonNull(netconfNode.getHost()); + requireNonNull(netconfNode.getPort()); - this.deviceCommunicatorDTO = createDeviceCommunicator(nodeId, netconfNode, deviceHandler); + deviceCommunicatorDTO = createDeviceCommunicator(nodeId, netconfNode, deviceHandler); final NetconfDeviceCommunicator deviceCommunicator = deviceCommunicatorDTO.getCommunicator(); final NetconfClientSessionListener netconfClientSessionListener = deviceCommunicatorDTO.getSessionListener(); final NetconfReconnectingClientConfiguration clientConfig = @@ -126,7 +128,7 @@ public class RemoteDeviceConnectorImpl implements RemoteDeviceConnector { } @Override - public void onFailure(@Nullable final Throwable throwable) { + public void onFailure(final Throwable throwable) { LOG.error("{}: Connector failed", remoteDeviceId, throwable); } }, MoreExecutors.directExecutor()); @@ -149,24 +151,24 @@ public class RemoteDeviceConnectorImpl implements RemoteDeviceConnector { final RemoteDeviceHandler deviceHandler) { //setup default values since default value is not supported in mdsal final long defaultRequestTimeoutMillis = node.getDefaultRequestTimeoutMillis() == null - ? NetconfTopologyUtils.DEFAULT_REQUEST_TIMEOUT_MILLIS : node.getDefaultRequestTimeoutMillis(); + ? NetconfTopologyUtils.DEFAULT_REQUEST_TIMEOUT_MILLIS : node.getDefaultRequestTimeoutMillis().toJava(); final long keepaliveDelay = node.getKeepaliveDelay() == null - ? NetconfTopologyUtils.DEFAULT_KEEPALIVE_DELAY : node.getKeepaliveDelay(); - final boolean reconnectOnChangedSchema = node.isReconnectOnChangedSchema() == null - ? NetconfTopologyUtils.DEFAULT_RECONNECT_ON_CHANGED_SCHEMA : node.isReconnectOnChangedSchema(); + ? NetconfTopologyUtils.DEFAULT_KEEPALIVE_DELAY : node.getKeepaliveDelay().toJava(); + final boolean reconnectOnChangedSchema = node.getReconnectOnChangedSchema() == null + ? NetconfTopologyUtils.DEFAULT_RECONNECT_ON_CHANGED_SCHEMA : node.getReconnectOnChangedSchema(); - RemoteDeviceHandler salFacade = deviceHandler; + RemoteDeviceHandler salFacade = requireNonNull(deviceHandler); if (keepaliveDelay > 0) { LOG.info("{}: Adding keepalive facade.", remoteDeviceId); salFacade = new KeepaliveSalFacade(remoteDeviceId, salFacade, - netconfTopologyDeviceSetup.getKeepaliveExecutor().getExecutor(), keepaliveDelay, + netconfTopologyDeviceSetup.getKeepaliveExecutor(), keepaliveDelay, defaultRequestTimeoutMillis); } final NetconfDevice.SchemaResourcesDTO schemaResourcesDTO = netconfTopologyDeviceSetup.getSchemaResourcesDTO(); // pre register yang library sources as fallback schemas to schema registry - final List> registeredYangLibSources = Lists.newArrayList(); + final List> registeredYangLibSources = new ArrayList<>(); if (node.getYangLibrary() != null) { final String yangLibURL = node.getYangLibrary().getYangLibraryUrl().getValue(); final String yangLibUsername = node.getYangLibrary().getUsername(); @@ -194,14 +196,17 @@ public class RemoteDeviceConnectorImpl implements RemoteDeviceConnector { } final RemoteDevice device; - if (node.isSchemaless()) { - device = new SchemalessNetconfDevice(remoteDeviceId, salFacade); + if (node.getSchemaless()) { + device = new SchemalessNetconfDevice(netconfTopologyDeviceSetup.getBaseSchemas(), remoteDeviceId, + salFacade); } else { device = new NetconfDeviceBuilder() .setReconnectOnSchemasChange(reconnectOnChangedSchema) .setSchemaResourcesDTO(schemaResourcesDTO) - .setGlobalProcessingExecutor(netconfTopologyDeviceSetup.getProcessingExecutor().getExecutor()) + .setGlobalProcessingExecutor(netconfTopologyDeviceSetup.getProcessingExecutor()) + .setBaseSchemas(netconfTopologyDeviceSetup.getBaseSchemas()) .setId(remoteDeviceId) + .setDeviceActionFactory(deviceActionFactory) .setSalFacade(salFacade) .build(); } @@ -209,25 +214,23 @@ public class RemoteDeviceConnectorImpl implements RemoteDeviceConnector { final Optional userCapabilities = getUserCapabilities(node); final int rpcMessageLimit = node.getConcurrentRpcLimit() == null - ? NetconfTopologyUtils.DEFAULT_CONCURRENT_RPC_LIMIT : node.getConcurrentRpcLimit(); + ? NetconfTopologyUtils.DEFAULT_CONCURRENT_RPC_LIMIT : node.getConcurrentRpcLimit().toJava(); if (rpcMessageLimit < 1) { LOG.info("{}: Concurrent rpc limit is smaller than 1, no limit will be enforced.", remoteDeviceId); } - NetconfDeviceCommunicator netconfDeviceCommunicator = - userCapabilities.isPresent() ? new NetconfDeviceCommunicator(remoteDeviceId, device, - new UserPreferences(userCapabilities.get(), - Objects.isNull(node.getYangModuleCapabilities()) - ? false : node.getYangModuleCapabilities().isOverride(), - Objects.isNull(node.getNonModuleCapabilities()) - ? false : node.getNonModuleCapabilities().isOverride()), rpcMessageLimit) + NetconfDeviceCommunicator netconfDeviceCommunicator = userCapabilities.isPresent() + ? new NetconfDeviceCommunicator(remoteDeviceId, device, new UserPreferences(userCapabilities.get(), + node.getYangModuleCapabilities() == null ? false : node.getYangModuleCapabilities().getOverride(), + node.getNonModuleCapabilities() == null ? false : node.getNonModuleCapabilities().getOverride()), + rpcMessageLimit) : new NetconfDeviceCommunicator(remoteDeviceId, device, rpcMessageLimit); if (salFacade instanceof KeepaliveSalFacade) { ((KeepaliveSalFacade)salFacade).setListener(netconfDeviceCommunicator); } - return new NetconfConnectorDTO(netconfDeviceCommunicator, salFacade); + return new NetconfConnectorDTO(netconfDeviceCommunicator, salFacade, registeredYangLibSources); } private static Optional getUserCapabilities(final NetconfNode node) { @@ -242,7 +245,7 @@ public class RemoteDeviceConnectorImpl implements RemoteDeviceConnector { //non-module capabilities should not exist in yang module capabilities final NetconfSessionPreferences netconfSessionPreferences = NetconfSessionPreferences.fromStrings(capabilities); - Preconditions.checkState(netconfSessionPreferences.getNonModuleCaps().isEmpty(), + checkState(netconfSessionPreferences.getNonModuleCaps().isEmpty(), "List yang-module-capabilities/capability should contain only module based capabilities. " + "Non-module capabilities used: " + netconfSessionPreferences.getNonModuleCaps()); @@ -253,63 +256,65 @@ public class RemoteDeviceConnectorImpl implements RemoteDeviceConnector { return Optional.of(NetconfSessionPreferences.fromStrings(capabilities, CapabilityOrigin.UserDefined)); } - //TODO: duplicate code - private static InetSocketAddress getSocketAddress(final Host host, final int port) { - if (host.getDomainName() != null) { - return new InetSocketAddress(host.getDomainName().getValue(), port); - } else { - final IpAddress ipAddress = host.getIpAddress(); - final String ip = ipAddress.getIpv4Address() != null ? ipAddress.getIpv4Address().getValue() : - ipAddress.getIpv6Address().getValue(); - return new InetSocketAddress(ip, port); - } - } - @VisibleForTesting NetconfReconnectingClientConfiguration getClientConfig(final NetconfClientSessionListener listener, final NetconfNode node) { //setup default values since default value is not supported in mdsal final long clientConnectionTimeoutMillis = node.getConnectionTimeoutMillis() == null - ? NetconfTopologyUtils.DEFAULT_CONNECTION_TIMEOUT_MILLIS : node.getConnectionTimeoutMillis(); + ? NetconfTopologyUtils.DEFAULT_CONNECTION_TIMEOUT_MILLIS : node.getConnectionTimeoutMillis().toJava(); final long maxConnectionAttempts = node.getMaxConnectionAttempts() == null - ? NetconfTopologyUtils.DEFAULT_MAX_CONNECTION_ATTEMPTS : node.getMaxConnectionAttempts(); + ? NetconfTopologyUtils.DEFAULT_MAX_CONNECTION_ATTEMPTS : node.getMaxConnectionAttempts().toJava(); final int betweenAttemptsTimeoutMillis = node.getBetweenAttemptsTimeoutMillis() == null - ? NetconfTopologyUtils.DEFAULT_BETWEEN_ATTEMPTS_TIMEOUT_MILLIS : node.getBetweenAttemptsTimeoutMillis(); - final BigDecimal sleepFactor = node.getSleepFactor() == null + ? NetconfTopologyUtils.DEFAULT_BETWEEN_ATTEMPTS_TIMEOUT_MILLIS + : node.getBetweenAttemptsTimeoutMillis().toJava(); + final boolean isTcpOnly = node.getTcpOnly() == null + ? NetconfTopologyUtils.DEFAULT_IS_TCP_ONLY : node.getTcpOnly(); + final Decimal64 sleepFactor = node.getSleepFactor() == null ? NetconfTopologyUtils.DEFAULT_SLEEP_FACTOR : node.getSleepFactor(); - final InetSocketAddress socketAddress = getSocketAddress(node.getHost(), node.getPort().getValue()); + final InetSocketAddress socketAddress = NetconfNodeUtils.toInetSocketAddress(node); final ReconnectStrategyFactory sf = - new TimedReconnectStrategyFactory(netconfTopologyDeviceSetup.getEventExecutor(), maxConnectionAttempts, - betweenAttemptsTimeoutMillis, sleepFactor); - final ReconnectStrategy strategy = sf.createReconnectStrategy(); - - final AuthenticationHandler authHandler = getHandlerFromCredentials(node.getCredentials()); - - final NetconfReconnectingClientConfigurationBuilder builder = - NetconfReconnectingClientConfigurationBuilder.create() - .withAddress(socketAddress) - .withConnectionTimeoutMillis(clientConnectionTimeoutMillis) - .withReconnectStrategy(strategy) - .withAuthHandler(authHandler) - .withProtocol(node.isTcpOnly() - ? NetconfClientConfiguration.NetconfClientProtocol.TCP - : NetconfClientConfiguration.NetconfClientProtocol.SSH) - .withConnectStrategyFactory(sf) - .withSessionListener(listener); + new TimedReconnectStrategyFactory(netconfTopologyDeviceSetup.getEventExecutor(), maxConnectionAttempts, + betweenAttemptsTimeoutMillis, BigDecimal.valueOf(sleepFactor.unscaledValue(), sleepFactor.scale())); + + + final NetconfReconnectingClientConfigurationBuilder reconnectingClientConfigurationBuilder; + final Protocol protocol = node.getProtocol(); + if (isTcpOnly) { + reconnectingClientConfigurationBuilder = NetconfReconnectingClientConfigurationBuilder.create() + .withProtocol(NetconfClientConfiguration.NetconfClientProtocol.TCP) + .withAuthHandler(getHandlerFromCredentials(node.getCredentials())); + } else if (protocol == null || protocol.getName() == Protocol.Name.SSH) { + reconnectingClientConfigurationBuilder = NetconfReconnectingClientConfigurationBuilder.create() + .withProtocol(NetconfClientConfiguration.NetconfClientProtocol.SSH) + .withAuthHandler(getHandlerFromCredentials(node.getCredentials())); + } else if (protocol.getName() == Protocol.Name.TLS) { + reconnectingClientConfigurationBuilder = NetconfReconnectingClientConfigurationBuilder.create() + .withSslHandlerFactory(new SslHandlerFactoryImpl(keystoreAdapter, protocol.getSpecification())) + .withProtocol(NetconfClientConfiguration.NetconfClientProtocol.TLS); + } else { + throw new IllegalStateException("Unsupported protocol type: " + protocol.getName()); + } final List odlHelloCapabilities = getOdlHelloCapabilities(node); if (odlHelloCapabilities != null) { - builder.withOdlHelloCapabilities(odlHelloCapabilities); + reconnectingClientConfigurationBuilder.withOdlHelloCapabilities(odlHelloCapabilities); } - return builder.build(); + + return reconnectingClientConfigurationBuilder + .withAddress(socketAddress) + .withConnectionTimeoutMillis(clientConnectionTimeoutMillis) + .withReconnectStrategy(sf.createReconnectStrategy()) + .withConnectStrategyFactory(sf) + .withSessionListener(listener) + .build(); } private static List getOdlHelloCapabilities(final NetconfNode node) { final OdlHelloMessageCapabilities helloCapabilities = node.getOdlHelloMessageCapabilities(); - return helloCapabilities != null ? helloCapabilities.getCapability() : null; + return helloCapabilities != null ? List.copyOf(helloCapabilities.getCapability()) : null; } private AuthenticationHandler getHandlerFromCredentials(final Credentials credentials) { @@ -338,30 +343,4 @@ public class RemoteDeviceConnectorImpl implements RemoteDeviceConnector { } throw new IllegalStateException("Unsupported credential type: " + credentials.getClass()); } - - private static final class TimedReconnectStrategyFactory implements ReconnectStrategyFactory { - private final Long connectionAttempts; - private final EventExecutor executor; - private final double sleepFactor; - private final int minSleep; - - TimedReconnectStrategyFactory(final EventExecutor executor, final Long maxConnectionAttempts, - final int minSleep, final BigDecimal sleepFactor) { - if (maxConnectionAttempts != null && maxConnectionAttempts > 0) { - connectionAttempts = maxConnectionAttempts; - } else { - connectionAttempts = null; - } - - this.sleepFactor = sleepFactor.doubleValue(); - this.executor = executor; - this.minSleep = minSleep; - } - - @Override - public ReconnectStrategy createReconnectStrategy() { - return new TimedReconnectStrategy(executor, minSleep, - minSleep, sleepFactor, null /*maxSleep*/, connectionAttempts, null /*deadline*/); - } - } }