Teach NETCONF about YANG 1.1 actions in cluster topology
[netconf.git] / netconf / netconf-topology-singleton / src / main / java / org / opendaylight / netconf / topology / singleton / impl / RemoteDeviceConnectorImpl.java
index da2831a6f4b2bf51ce111e054f7e9eb4206493bc..955f465ee76a7483fc25c090690f4abc3427752a 100644 (file)
@@ -5,11 +5,12 @@
  * 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;
@@ -21,9 +22,7 @@ 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;
@@ -34,6 +33,7 @@ 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;
@@ -49,6 +49,7 @@ 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;
@@ -58,6 +59,7 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.
 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;
@@ -88,12 +90,15 @@ public class RemoteDeviceConnectorImpl implements RemoteDeviceConnector {
     private final AAAEncryptionService encryptionService;
     private NetconfConnectorDTO deviceCommunicatorDTO;
     private final NetconfKeystoreAdapter keystoreAdapter;
+    private final DeviceActionFactory deviceActionFactory;
 
     public RemoteDeviceConnectorImpl(final NetconfTopologySetup netconfTopologyDeviceSetup,
-                                     final RemoteDeviceId remoteDeviceId) {
+                                     final RemoteDeviceId remoteDeviceId,
+                                     final DeviceActionFactory deviceActionFactory) {
 
-        this.netconfTopologyDeviceSetup = Preconditions.checkNotNull(netconfTopologyDeviceSetup);
+        this.netconfTopologyDeviceSetup = requireNonNull(netconfTopologyDeviceSetup);
         this.remoteDeviceId = remoteDeviceId;
+        this.deviceActionFactory = requireNonNull(deviceActionFactory);
         this.privateKeyPath = netconfTopologyDeviceSetup.getPrivateKeyPath();
         this.privateKeyPassphrase = netconfTopologyDeviceSetup.getPrivateKeyPassphrase();
         this.encryptionService = netconfTopologyDeviceSetup.getEncryptionService();
@@ -105,9 +110,8 @@ 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);
         final NetconfDeviceCommunicator deviceCommunicator = deviceCommunicatorDTO.getCommunicator();
@@ -124,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());
@@ -200,6 +204,7 @@ public class RemoteDeviceConnectorImpl implements RemoteDeviceConnector {
                     .setSchemaResourcesDTO(schemaResourcesDTO)
                     .setGlobalProcessingExecutor(netconfTopologyDeviceSetup.getProcessingExecutor())
                     .setId(remoteDeviceId)
+                    .setDeviceActionFactory(deviceActionFactory)
                     .setSalFacade(salFacade)
                     .build();
         }
@@ -216,10 +221,9 @@ public class RemoteDeviceConnectorImpl implements RemoteDeviceConnector {
         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)
+                 node.getYangModuleCapabilities() == null ? false : node.getYangModuleCapabilities().isOverride(),
+                 node.getNonModuleCapabilities() == null ? false : node.getNonModuleCapabilities().isOverride()),
+             rpcMessageLimit)
             : new NetconfDeviceCommunicator(remoteDeviceId, device, rpcMessageLimit);
 
         if (salFacade instanceof KeepaliveSalFacade) {
@@ -240,7 +244,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());
 
@@ -274,6 +278,8 @@ public class RemoteDeviceConnectorImpl implements RemoteDeviceConnector {
                 ? NetconfTopologyUtils.DEFAULT_MAX_CONNECTION_ATTEMPTS : node.getMaxConnectionAttempts();
         final int betweenAttemptsTimeoutMillis = node.getBetweenAttemptsTimeoutMillis() == null
                 ? NetconfTopologyUtils.DEFAULT_BETWEEN_ATTEMPTS_TIMEOUT_MILLIS : node.getBetweenAttemptsTimeoutMillis();
+        final boolean isTcpOnly = node.isTcpOnly() == null
+                ? NetconfTopologyUtils.DEFAULT_IS_TCP_ONLY : node.isTcpOnly();
         final BigDecimal sleepFactor = node.getSleepFactor() == null
                 ? NetconfTopologyUtils.DEFAULT_SLEEP_FACTOR : node.getSleepFactor();
 
@@ -283,25 +289,37 @@ public class RemoteDeviceConnectorImpl implements RemoteDeviceConnector {
                 new TimedReconnectStrategyFactory(netconfTopologyDeviceSetup.getEventExecutor(), maxConnectionAttempts,
                         betweenAttemptsTimeoutMillis, sleepFactor);
 
-        final AuthenticationHandler authHandler = getHandlerFromCredentials(node.getCredentials());
 
-        final NetconfReconnectingClientConfigurationBuilder builder =
-                NetconfReconnectingClientConfigurationBuilder.create()
-                        .withAddress(socketAddress)
-                        .withConnectionTimeoutMillis(clientConnectionTimeoutMillis)
-                        .withReconnectStrategy(sf.createReconnectStrategy())
-                        .withAuthHandler(authHandler)
-                        .withProtocol(node.isTcpOnly()
-                                ? NetconfClientConfiguration.NetconfClientProtocol.TCP
-                                : NetconfClientConfiguration.NetconfClientProtocol.SSH)
-                        .withConnectStrategyFactory(sf)
-                        .withSessionListener(listener);
+        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<Uri> 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<Uri> getOdlHelloCapabilities(final NetconfNode node) {