2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.netconf.topology;
11 import com.google.common.base.Optional;
12 import com.google.common.base.Preconditions;
13 import com.google.common.base.Strings;
14 import com.google.common.collect.Lists;
15 import com.google.common.util.concurrent.FutureCallback;
16 import com.google.common.util.concurrent.Futures;
17 import com.google.common.util.concurrent.ListenableFuture;
18 import com.google.common.util.concurrent.MoreExecutors;
19 import io.netty.util.concurrent.EventExecutor;
21 import java.math.BigDecimal;
22 import java.net.InetSocketAddress;
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.List;
28 import org.opendaylight.aaa.encrypt.AAAEncryptionService;
29 import org.opendaylight.controller.config.threadpool.ScheduledThreadPool;
30 import org.opendaylight.controller.config.threadpool.ThreadPool;
31 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
32 import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
33 import org.opendaylight.netconf.api.NetconfMessage;
34 import org.opendaylight.netconf.client.NetconfClientDispatcher;
35 import org.opendaylight.netconf.client.NetconfClientSessionListener;
36 import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
37 import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfiguration;
38 import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfigurationBuilder;
39 import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler;
40 import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.PublicKeyAuth;
41 import org.opendaylight.netconf.sal.connect.api.RemoteDevice;
42 import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
43 import org.opendaylight.netconf.sal.connect.netconf.LibraryModulesSchemas;
44 import org.opendaylight.netconf.sal.connect.netconf.NetconfDevice;
45 import org.opendaylight.netconf.sal.connect.netconf.NetconfDeviceBuilder;
46 import org.opendaylight.netconf.sal.connect.netconf.NetconfStateSchemasResolverImpl;
47 import org.opendaylight.netconf.sal.connect.netconf.SchemalessNetconfDevice;
48 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
49 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCommunicator;
50 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
51 import org.opendaylight.netconf.sal.connect.netconf.listener.UserPreferences;
52 import org.opendaylight.netconf.sal.connect.netconf.sal.KeepaliveSalFacade;
53 import org.opendaylight.netconf.sal.connect.netconf.schema.YangLibrarySchemaYangSourceProvider;
54 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
55 import org.opendaylight.netconf.topology.api.NetconfTopology;
56 import org.opendaylight.netconf.topology.api.SchemaRepositoryProvider;
57 import org.opendaylight.protocol.framework.ReconnectStrategy;
58 import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
59 import org.opendaylight.protocol.framework.TimedReconnectStrategy;
60 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Host;
61 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.available.capabilities.AvailableCapability.CapabilityOrigin;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.Credentials;
65 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
66 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
67 import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
68 import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
69 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter;
70 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
71 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
72 import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
73 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration;
74 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
75 import org.opendaylight.yangtools.yang.model.repo.util.FilesystemSchemaSourceCache;
76 import org.opendaylight.yangtools.yang.parser.repo.SharedSchemaRepository;
77 import org.opendaylight.yangtools.yang.parser.util.TextToASTTransformer;
78 import org.slf4j.Logger;
79 import org.slf4j.LoggerFactory;
81 public abstract class AbstractNetconfTopology implements NetconfTopology {
83 private static final Logger LOG = LoggerFactory.getLogger(AbstractNetconfTopology.class);
85 protected static final long DEFAULT_REQUEST_TIMEOUT_MILLIS = 60000L;
86 protected static final int DEFAULT_KEEPALIVE_DELAY = 0;
87 protected static final boolean DEFAULT_RECONNECT_ON_CHANGED_SCHEMA = false;
88 protected static final int DEFAULT_CONCURRENT_RPC_LIMIT = 0;
89 private static final int DEFAULT_MAX_CONNECTION_ATTEMPTS = 0;
90 private static final int DEFAULT_BETWEEN_ATTEMPTS_TIMEOUT_MILLIS = 2000;
91 private static final long DEFAULT_CONNECTION_TIMEOUT_MILLIS = 20000L;
92 private static final BigDecimal DEFAULT_SLEEP_FACTOR = new BigDecimal(1.5);
94 // constants related to Schema Cache(s)
96 * Filesystem based caches are stored relative to the cache directory.
98 private static final String CACHE_DIRECTORY = "cache";
101 * The default cache directory relative to <code>CACHE_DIRECTORY</code>.
103 private static final String DEFAULT_CACHE_DIRECTORY = "schema";
106 * The qualified schema cache directory <code>cache/schema</code>.
108 private static final String QUALIFIED_DEFAULT_CACHE_DIRECTORY =
109 CACHE_DIRECTORY + File.separator + DEFAULT_CACHE_DIRECTORY;
112 * The name for the default schema repository.
114 private static final String DEFAULT_SCHEMA_REPOSITORY_NAME = "sal-netconf-connector";
117 * The default schema repository in the case that one is not specified.
119 private static final SharedSchemaRepository DEFAULT_SCHEMA_REPOSITORY =
120 new SharedSchemaRepository(DEFAULT_SCHEMA_REPOSITORY_NAME);
123 * The default <code>FilesystemSchemaSourceCache</code>, which stores cached files in <code>cache/schema</code>.
125 private static final FilesystemSchemaSourceCache<YangTextSchemaSource> DEFAULT_CACHE =
126 new FilesystemSchemaSourceCache<>(DEFAULT_SCHEMA_REPOSITORY, YangTextSchemaSource.class,
127 new File(QUALIFIED_DEFAULT_CACHE_DIRECTORY));
130 * The default factory for creating <code>SchemaContext</code> instances.
132 private static final SchemaContextFactory DEFAULT_SCHEMA_CONTEXT_FACTORY =
133 DEFAULT_SCHEMA_REPOSITORY.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT);
136 * Keeps track of initialized Schema resources. A Map is maintained in which the key represents the name
137 * of the schema cache directory, and the value is a corresponding <code>SchemaResourcesDTO</code>. The
138 * <code>SchemaResourcesDTO</code> is essentially a container that allows for the extraction of the
139 * <code>SchemaRegistry</code> and <code>SchemaContextFactory</code> which should be used for a particular
140 * Netconf mount. Access to <code>SCHEMA_RESOURCES_DTO_MAP</code> should be surrounded by appropriate
141 * synchronization locks.
143 private static final Map<String, NetconfDevice.SchemaResourcesDTO> SCHEMA_RESOURCES_DTO_MAP = new HashMap<>();
145 // Initializes default constant instances for the case when the default schema repository
146 // directory cache/schema is used.
148 SCHEMA_RESOURCES_DTO_MAP.put(DEFAULT_CACHE_DIRECTORY,
149 new NetconfDevice.SchemaResourcesDTO(DEFAULT_SCHEMA_REPOSITORY, DEFAULT_SCHEMA_REPOSITORY,
150 DEFAULT_SCHEMA_CONTEXT_FACTORY,
151 new NetconfStateSchemasResolverImpl()));
152 DEFAULT_SCHEMA_REPOSITORY.registerSchemaSourceListener(DEFAULT_CACHE);
153 DEFAULT_SCHEMA_REPOSITORY.registerSchemaSourceListener(
154 TextToASTTransformer.create(DEFAULT_SCHEMA_REPOSITORY, DEFAULT_SCHEMA_REPOSITORY));
157 protected final String topologyId;
158 private final NetconfClientDispatcher clientDispatcher;
159 private final EventExecutor eventExecutor;
160 protected final ScheduledThreadPool keepaliveExecutor;
161 protected final ThreadPool processingExecutor;
162 protected final SharedSchemaRepository sharedSchemaRepository;
163 protected final DataBroker dataBroker;
164 protected final DOMMountPointService mountPointService;
165 protected SchemaSourceRegistry schemaRegistry = DEFAULT_SCHEMA_REPOSITORY;
166 protected SchemaRepository schemaRepository = DEFAULT_SCHEMA_REPOSITORY;
167 protected SchemaContextFactory schemaContextFactory = DEFAULT_SCHEMA_CONTEXT_FACTORY;
168 protected String privateKeyPath;
169 protected String privateKeyPassphrase;
170 protected final AAAEncryptionService encryptionService;
171 protected final HashMap<NodeId, NetconfConnectorDTO> activeConnectors = new HashMap<>();
173 protected AbstractNetconfTopology(final String topologyId, final NetconfClientDispatcher clientDispatcher,
174 final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor,
175 final ThreadPool processingExecutor,
176 final SchemaRepositoryProvider schemaRepositoryProvider,
177 final DataBroker dataBroker, final DOMMountPointService mountPointService,
178 final AAAEncryptionService encryptionService) {
179 this.topologyId = topologyId;
180 this.clientDispatcher = clientDispatcher;
181 this.eventExecutor = eventExecutor;
182 this.keepaliveExecutor = keepaliveExecutor;
183 this.processingExecutor = processingExecutor;
184 this.sharedSchemaRepository = schemaRepositoryProvider.getSharedSchemaRepository();
185 this.dataBroker = dataBroker;
186 this.mountPointService = mountPointService;
187 this.encryptionService = encryptionService;
190 public void setSchemaRegistry(final SchemaSourceRegistry schemaRegistry) {
191 this.schemaRegistry = schemaRegistry;
194 public void setSchemaContextFactory(final SchemaContextFactory schemaContextFactory) {
195 this.schemaContextFactory = schemaContextFactory;
199 public ListenableFuture<NetconfDeviceCapabilities> connectNode(final NodeId nodeId, final Node configNode) {
200 LOG.info("Connecting RemoteDevice{{}} , with config {}", nodeId, configNode);
201 return setupConnection(nodeId, configNode);
205 public ListenableFuture<Void> disconnectNode(final NodeId nodeId) {
206 LOG.debug("Disconnecting RemoteDevice{{}}", nodeId.getValue());
207 if (!activeConnectors.containsKey(nodeId)) {
208 return Futures.immediateFailedFuture(
209 new IllegalStateException("Unable to disconnect device that is not connected"));
212 // retrieve connection, and disconnect it
213 final NetconfConnectorDTO connectorDTO = activeConnectors.remove(nodeId);
214 connectorDTO.getCommunicator().close();
215 connectorDTO.getFacade().close();
216 return Futures.immediateFuture(null);
219 protected ListenableFuture<NetconfDeviceCapabilities> setupConnection(final NodeId nodeId,
220 final Node configNode) {
221 final NetconfNode netconfNode = configNode.getAugmentation(NetconfNode.class);
223 Preconditions.checkNotNull(netconfNode.getHost());
224 Preconditions.checkNotNull(netconfNode.getPort());
225 Preconditions.checkNotNull(netconfNode.isTcpOnly());
227 final NetconfConnectorDTO deviceCommunicatorDTO = createDeviceCommunicator(nodeId, netconfNode);
228 final NetconfDeviceCommunicator deviceCommunicator = deviceCommunicatorDTO.getCommunicator();
229 final NetconfClientSessionListener netconfClientSessionListener = deviceCommunicatorDTO.getSessionListener();
230 final NetconfReconnectingClientConfiguration clientConfig =
231 getClientConfig(netconfClientSessionListener, netconfNode);
232 final ListenableFuture<NetconfDeviceCapabilities> future =
233 deviceCommunicator.initializeRemoteConnection(clientDispatcher, clientConfig);
235 activeConnectors.put(nodeId, deviceCommunicatorDTO);
237 Futures.addCallback(future, new FutureCallback<NetconfDeviceCapabilities>() {
239 public void onSuccess(final NetconfDeviceCapabilities result) {
240 LOG.debug("Connector for : " + nodeId.getValue() + " started succesfully");
244 public void onFailure(final Throwable throwable) {
245 LOG.error("Connector for : " + nodeId.getValue() + " failed");
246 // remove this node from active connectors?
248 }, MoreExecutors.directExecutor());
253 protected NetconfConnectorDTO createDeviceCommunicator(final NodeId nodeId,
254 final NetconfNode node) {
255 //setup default values since default value is not supported in mdsal
256 final Long defaultRequestTimeoutMillis = node.getDefaultRequestTimeoutMillis() == null
257 ? DEFAULT_REQUEST_TIMEOUT_MILLIS : node.getDefaultRequestTimeoutMillis();
258 final Long keepaliveDelay = node.getKeepaliveDelay() == null
259 ? DEFAULT_KEEPALIVE_DELAY : node.getKeepaliveDelay();
260 final Boolean reconnectOnChangedSchema = node.isReconnectOnChangedSchema() == null
261 ? DEFAULT_RECONNECT_ON_CHANGED_SCHEMA : node.isReconnectOnChangedSchema();
263 final IpAddress ipAddress = node.getHost().getIpAddress();
264 final InetSocketAddress address = new InetSocketAddress(ipAddress.getIpv4Address() != null
265 ? ipAddress.getIpv4Address().getValue() : ipAddress.getIpv6Address().getValue(),
266 node.getPort().getValue());
267 final RemoteDeviceId remoteDeviceId = new RemoteDeviceId(nodeId.getValue(), address);
269 RemoteDeviceHandler<NetconfSessionPreferences> salFacade =
270 createSalFacade(remoteDeviceId);
272 if (keepaliveDelay > 0) {
273 LOG.warn("Adding keepalive facade, for device {}", nodeId);
274 salFacade = new KeepaliveSalFacade(remoteDeviceId, salFacade, keepaliveExecutor.getExecutor(),
275 keepaliveDelay, defaultRequestTimeoutMillis);
278 // pre register yang library sources as fallback schemas to schema registry
279 final List<SchemaSourceRegistration<YangTextSchemaSource>> registeredYangLibSources = Lists.newArrayList();
280 if (node.getYangLibrary() != null) {
281 final String yangLibURL = node.getYangLibrary().getYangLibraryUrl().getValue();
282 final String yangLibUsername = node.getYangLibrary().getUsername();
283 final String yangLigPassword = node.getYangLibrary().getPassword();
285 final LibraryModulesSchemas libraryModulesSchemas;
286 if (yangLibURL != null) {
287 if (yangLibUsername != null && yangLigPassword != null) {
288 libraryModulesSchemas = LibraryModulesSchemas.create(yangLibURL, yangLibUsername, yangLigPassword);
290 libraryModulesSchemas = LibraryModulesSchemas.create(yangLibURL);
293 for (final Map.Entry<SourceIdentifier, URL> sourceIdentifierURLEntry
294 : libraryModulesSchemas.getAvailableModels().entrySet()) {
295 registeredYangLibSources
296 .add(schemaRegistry.registerSchemaSource(
297 new YangLibrarySchemaYangSourceProvider(remoteDeviceId,
298 libraryModulesSchemas.getAvailableModels()),
299 PotentialSchemaSource.create(sourceIdentifierURLEntry.getKey(),
300 YangTextSchemaSource.class, PotentialSchemaSource.Costs.REMOTE_IO.getValue())));
305 final NetconfDevice.SchemaResourcesDTO schemaResourcesDTO = setupSchemaCacheDTO(nodeId, node);
306 final RemoteDevice<NetconfSessionPreferences, NetconfMessage, NetconfDeviceCommunicator> device;
307 if (node.isSchemaless()) {
308 device = new SchemalessNetconfDevice(remoteDeviceId, salFacade);
310 device = new NetconfDeviceBuilder()
311 .setReconnectOnSchemasChange(reconnectOnChangedSchema)
312 .setSchemaResourcesDTO(schemaResourcesDTO)
313 .setGlobalProcessingExecutor(processingExecutor.getExecutor())
314 .setId(remoteDeviceId)
315 .setSalFacade(salFacade)
319 final Optional<UserPreferences> userCapabilities = getUserCapabilities(node);
320 final int rpcMessageLimit =
321 node.getConcurrentRpcLimit() == null ? DEFAULT_CONCURRENT_RPC_LIMIT : node.getConcurrentRpcLimit();
323 if (rpcMessageLimit < 1) {
324 LOG.info("Concurrent rpc limit is smaller than 1, no limit will be enforced for device {}", remoteDeviceId);
327 return new NetconfConnectorDTO(userCapabilities.isPresent()
328 ? new NetconfDeviceCommunicator(remoteDeviceId, device, userCapabilities.get(), rpcMessageLimit)
329 : new NetconfDeviceCommunicator(remoteDeviceId, device, rpcMessageLimit), salFacade);
332 protected NetconfDevice.SchemaResourcesDTO setupSchemaCacheDTO(final NodeId nodeId, final NetconfNode node) {
333 // Setup information related to the SchemaRegistry, SchemaResourceFactory, etc.
334 NetconfDevice.SchemaResourcesDTO schemaResourcesDTO = null;
335 final String moduleSchemaCacheDirectory = node.getSchemaCacheDirectory();
336 // Only checks to ensure the String is not empty or null; further checks related to directory
337 // accessibility and file permissionsare handled during the FilesystemSchemaSourceCache initialization.
338 if (!Strings.isNullOrEmpty(moduleSchemaCacheDirectory)) {
339 // If a custom schema cache directory is specified, create the backing DTO; otherwise,
340 // the SchemaRegistry and SchemaContextFactory remain the default values.
341 if (!moduleSchemaCacheDirectory.equals(DEFAULT_CACHE_DIRECTORY)) {
342 // Multiple modules may be created at once;
343 // synchronize to avoid issues with data consistency among threads.
344 synchronized (SCHEMA_RESOURCES_DTO_MAP) {
345 // Look for the cached DTO to reuse SchemaRegistry and SchemaContextFactory variables
346 // if they already exist
347 schemaResourcesDTO = SCHEMA_RESOURCES_DTO_MAP.get(moduleSchemaCacheDirectory);
348 if (schemaResourcesDTO == null) {
349 schemaResourcesDTO = createSchemaResourcesDTO(moduleSchemaCacheDirectory);
350 schemaResourcesDTO.getSchemaRegistry().registerSchemaSourceListener(
351 TextToASTTransformer.create((SchemaRepository) schemaResourcesDTO.getSchemaRegistry(),
352 schemaResourcesDTO.getSchemaRegistry())
354 SCHEMA_RESOURCES_DTO_MAP.put(moduleSchemaCacheDirectory, schemaResourcesDTO);
357 LOG.info("Netconf connector for device {} will use schema cache directory {} instead of {}",
358 nodeId.getValue(), moduleSchemaCacheDirectory, DEFAULT_CACHE_DIRECTORY);
361 LOG.warn("schema-cache-directory for {} is null or empty; using the default {}",
362 nodeId.getValue(), QUALIFIED_DEFAULT_CACHE_DIRECTORY);
365 if (schemaResourcesDTO == null) {
366 schemaResourcesDTO = new NetconfDevice.SchemaResourcesDTO(schemaRegistry, schemaRepository,
367 schemaContextFactory, new NetconfStateSchemasResolverImpl());
370 return schemaResourcesDTO;
374 * Creates the backing Schema classes for a particular directory.
376 * @param moduleSchemaCacheDirectory The string directory relative to "cache"
377 * @return A DTO containing the Schema classes for the Netconf mount.
379 private NetconfDevice.SchemaResourcesDTO createSchemaResourcesDTO(final String moduleSchemaCacheDirectory) {
380 final SharedSchemaRepository repository = new SharedSchemaRepository(moduleSchemaCacheDirectory);
381 final SchemaContextFactory schemaContextFactory
382 = repository.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT);
383 setSchemaRegistry(repository);
384 setSchemaContextFactory(schemaContextFactory);
385 final FilesystemSchemaSourceCache<YangTextSchemaSource> deviceCache =
386 createDeviceFilesystemCache(moduleSchemaCacheDirectory);
387 repository.registerSchemaSourceListener(deviceCache);
388 return new NetconfDevice.SchemaResourcesDTO(repository, repository, schemaContextFactory,
389 new NetconfStateSchemasResolverImpl());
393 * Creates a <code>FilesystemSchemaSourceCache</code> for the custom schema cache directory.
395 * @param schemaCacheDirectory The custom cache directory relative to "cache"
396 * @return A <code>FilesystemSchemaSourceCache</code> for the custom schema cache directory
398 private FilesystemSchemaSourceCache<YangTextSchemaSource> createDeviceFilesystemCache(
399 final String schemaCacheDirectory) {
400 final String relativeSchemaCacheDirectory = CACHE_DIRECTORY + File.separator + schemaCacheDirectory;
401 return new FilesystemSchemaSourceCache<>(schemaRegistry, YangTextSchemaSource.class,
402 new File(relativeSchemaCacheDirectory));
406 * Sets the private key path from location specified in configuration file using blueprint.
408 public void setPrivateKeyPath(String privateKeyPath) {
409 this.privateKeyPath = privateKeyPath;
413 * Sets the private key passphrase from location specified in configuration file using blueprint.
415 public void setPrivateKeyPassphrase(String privateKeyPassphrase) {
416 this.privateKeyPassphrase = privateKeyPassphrase;
419 public NetconfReconnectingClientConfiguration getClientConfig(final NetconfClientSessionListener listener,
420 final NetconfNode node) {
422 //setup default values since default value is not supported in mdsal
423 final long clientConnectionTimeoutMillis = node.getConnectionTimeoutMillis() == null
424 ? DEFAULT_CONNECTION_TIMEOUT_MILLIS : node.getConnectionTimeoutMillis();
425 final long maxConnectionAttempts = node.getMaxConnectionAttempts() == null
426 ? DEFAULT_MAX_CONNECTION_ATTEMPTS : node.getMaxConnectionAttempts();
427 final int betweenAttemptsTimeoutMillis = node.getBetweenAttemptsTimeoutMillis() == null
428 ? DEFAULT_BETWEEN_ATTEMPTS_TIMEOUT_MILLIS : node.getBetweenAttemptsTimeoutMillis();
429 final BigDecimal sleepFactor = node.getSleepFactor() == null ? DEFAULT_SLEEP_FACTOR : node.getSleepFactor();
431 final InetSocketAddress socketAddress = getSocketAddress(node.getHost(), node.getPort().getValue());
433 final ReconnectStrategyFactory sf = new TimedReconnectStrategyFactory(eventExecutor,
434 maxConnectionAttempts, betweenAttemptsTimeoutMillis, sleepFactor);
435 final ReconnectStrategy strategy = sf.createReconnectStrategy();
437 final AuthenticationHandler authHandler;
438 final Credentials credentials = node.getCredentials();
439 if (credentials instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114
440 .netconf.node.credentials.credentials.LoginPassword) {
441 authHandler = new PublicKeyAuth(
442 ((org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114
443 .netconf.node.credentials.credentials.LoginPassword) credentials).getUsername(),
444 ((org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114
445 .netconf.node.credentials.credentials.LoginPassword) credentials).getPassword(),
446 privateKeyPath, privateKeyPassphrase, encryptionService);
448 throw new IllegalStateException("Only login/password authentification is supported");
451 return NetconfReconnectingClientConfigurationBuilder.create()
452 .withAddress(socketAddress)
453 .withConnectionTimeoutMillis(clientConnectionTimeoutMillis)
454 .withReconnectStrategy(strategy)
455 .withAuthHandler(authHandler)
456 .withProtocol(node.isTcpOnly() ? NetconfClientConfiguration.NetconfClientProtocol.TCP :
457 NetconfClientConfiguration.NetconfClientProtocol.SSH)
458 .withConnectStrategyFactory(sf)
459 .withSessionListener(listener)
463 protected abstract RemoteDeviceHandler<NetconfSessionPreferences> createSalFacade(RemoteDeviceId id);
465 private InetSocketAddress getSocketAddress(final Host host, final int port) {
466 if (host.getDomainName() != null) {
467 return new InetSocketAddress(host.getDomainName().getValue(), port);
469 final IpAddress ipAddress = host.getIpAddress();
470 final String ip = ipAddress.getIpv4Address() != null
471 ? ipAddress.getIpv4Address().getValue() : ipAddress.getIpv6Address().getValue();
472 return new InetSocketAddress(ip, port);
476 private Optional<UserPreferences> getUserCapabilities(final NetconfNode node) {
477 // if none of yang-module-capabilities or non-module-capabilities is specified
478 // just return absent
479 if (node.getYangModuleCapabilities() == null && node.getNonModuleCapabilities() == null) {
480 return Optional.absent();
483 final List<String> capabilities = new ArrayList<>();
485 boolean overrideYangModuleCaps = false;
486 if (node.getYangModuleCapabilities() != null) {
487 capabilities.addAll(node.getYangModuleCapabilities().getCapability());
488 overrideYangModuleCaps = node.getYangModuleCapabilities().isOverride();
491 //non-module capabilities should not exist in yang module capabilities
492 final NetconfSessionPreferences netconfSessionPreferences = NetconfSessionPreferences.fromStrings(capabilities);
493 Preconditions.checkState(netconfSessionPreferences.getNonModuleCaps().isEmpty(),
494 "List yang-module-capabilities/capability should contain only module based capabilities. "
495 + "Non-module capabilities used: " + netconfSessionPreferences.getNonModuleCaps());
497 boolean overrideNonModuleCaps = false;
498 if (node.getNonModuleCapabilities() != null) {
499 capabilities.addAll(node.getNonModuleCapabilities().getCapability());
500 overrideNonModuleCaps = node.getNonModuleCapabilities().isOverride();
503 return Optional.of(new UserPreferences(NetconfSessionPreferences
504 .fromStrings(capabilities, CapabilityOrigin.UserDefined), overrideYangModuleCaps, overrideNonModuleCaps));
507 private static final class TimedReconnectStrategyFactory implements ReconnectStrategyFactory {
508 private final Long connectionAttempts;
509 private final EventExecutor executor;
510 private final double sleepFactor;
511 private final int minSleep;
513 TimedReconnectStrategyFactory(final EventExecutor executor, final Long maxConnectionAttempts,
514 final int minSleep, final BigDecimal sleepFactor) {
515 if (maxConnectionAttempts != null && maxConnectionAttempts > 0) {
516 connectionAttempts = maxConnectionAttempts;
518 connectionAttempts = null;
521 this.sleepFactor = sleepFactor.doubleValue();
522 this.executor = executor;
523 this.minSleep = minSleep;
527 public ReconnectStrategy createReconnectStrategy() {
528 final Long maxSleep = null;
529 final Long deadline = null;
531 return new TimedReconnectStrategy(executor, minSleep,
532 minSleep, sleepFactor, maxSleep, connectionAttempts, deadline);
536 protected static class NetconfConnectorDTO implements AutoCloseable {
538 private final NetconfDeviceCommunicator communicator;
539 private final RemoteDeviceHandler<NetconfSessionPreferences> facade;
541 public NetconfConnectorDTO(final NetconfDeviceCommunicator communicator,
542 final RemoteDeviceHandler<NetconfSessionPreferences> facade) {
543 this.communicator = communicator;
544 this.facade = facade;
547 public NetconfDeviceCommunicator getCommunicator() {
551 public RemoteDeviceHandler<NetconfSessionPreferences> getFacade() {
555 public NetconfClientSessionListener getSessionListener() {
560 public void close() {
561 communicator.close();