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 io.netty.util.concurrent.EventExecutor;
20 import java.math.BigDecimal;
21 import java.net.InetSocketAddress;
23 import java.util.ArrayList;
24 import java.util.HashMap;
25 import java.util.List;
27 import org.opendaylight.aaa.encrypt.AAAEncryptionService;
28 import org.opendaylight.controller.config.threadpool.ScheduledThreadPool;
29 import org.opendaylight.controller.config.threadpool.ThreadPool;
30 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
31 import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
32 import org.opendaylight.netconf.api.NetconfMessage;
33 import org.opendaylight.netconf.client.NetconfClientDispatcher;
34 import org.opendaylight.netconf.client.NetconfClientSessionListener;
35 import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
36 import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfiguration;
37 import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfigurationBuilder;
38 import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler;
39 import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.LoginPassword;
40 import org.opendaylight.netconf.sal.connect.api.RemoteDevice;
41 import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
42 import org.opendaylight.netconf.sal.connect.netconf.LibraryModulesSchemas;
43 import org.opendaylight.netconf.sal.connect.netconf.NetconfDevice;
44 import org.opendaylight.netconf.sal.connect.netconf.NetconfDeviceBuilder;
45 import org.opendaylight.netconf.sal.connect.netconf.NetconfStateSchemasResolverImpl;
46 import org.opendaylight.netconf.sal.connect.netconf.SchemalessNetconfDevice;
47 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
48 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCommunicator;
49 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
50 import org.opendaylight.netconf.sal.connect.netconf.listener.UserPreferences;
51 import org.opendaylight.netconf.sal.connect.netconf.sal.KeepaliveSalFacade;
52 import org.opendaylight.netconf.sal.connect.netconf.schema.YangLibrarySchemaYangSourceProvider;
53 import org.opendaylight.netconf.sal.connect.util.AuthEncryptor;
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;
166 protected SchemaSourceRegistry schemaRegistry = DEFAULT_SCHEMA_REPOSITORY;
167 protected SchemaRepository schemaRepository = DEFAULT_SCHEMA_REPOSITORY;
168 protected SchemaContextFactory schemaContextFactory = DEFAULT_SCHEMA_CONTEXT_FACTORY;
170 protected final HashMap<NodeId, NetconfConnectorDTO> activeConnectors = new HashMap<>();
172 protected final AAAEncryptionService encryptionService;
174 protected AbstractNetconfTopology(final String topologyId, final NetconfClientDispatcher clientDispatcher,
175 final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor,
176 final ThreadPool processingExecutor,
177 final SchemaRepositoryProvider schemaRepositoryProvider,
178 final DataBroker dataBroker, final DOMMountPointService mountPointService,
179 final AAAEncryptionService encryptionService) {
180 this.topologyId = topologyId;
181 this.clientDispatcher = clientDispatcher;
182 this.eventExecutor = eventExecutor;
183 this.keepaliveExecutor = keepaliveExecutor;
184 this.processingExecutor = processingExecutor;
185 this.sharedSchemaRepository = schemaRepositoryProvider.getSharedSchemaRepository();
186 this.dataBroker = dataBroker;
187 this.mountPointService = mountPointService;
188 this.encryptionService = encryptionService;
191 public void setSchemaRegistry(final SchemaSourceRegistry schemaRegistry) {
192 this.schemaRegistry = schemaRegistry;
195 public void setSchemaContextFactory(final SchemaContextFactory schemaContextFactory) {
196 this.schemaContextFactory = schemaContextFactory;
200 public ListenableFuture<NetconfDeviceCapabilities> connectNode(final NodeId nodeId, final Node configNode) {
201 LOG.info("Connecting RemoteDevice{{}} , with config {}", nodeId, configNode);
202 return setupConnection(nodeId, configNode);
206 public ListenableFuture<Void> disconnectNode(final NodeId nodeId) {
207 LOG.debug("Disconnecting RemoteDevice{{}}", nodeId.getValue());
208 if (!activeConnectors.containsKey(nodeId)) {
209 return Futures.immediateFailedFuture(
210 new IllegalStateException("Unable to disconnect device that is not connected"));
213 // retrieve connection, and disconnect it
214 final NetconfConnectorDTO connectorDTO = activeConnectors.remove(nodeId);
215 connectorDTO.getCommunicator().close();
216 connectorDTO.getFacade().close();
217 return Futures.immediateFuture(null);
220 protected ListenableFuture<NetconfDeviceCapabilities> setupConnection(final NodeId nodeId,
221 final Node configNode) {
222 final NetconfNode netconfNode = configNode.getAugmentation(NetconfNode.class);
224 AuthEncryptor.encryptIfNeeded(nodeId, netconfNode, encryptionService, topologyId, dataBroker);
226 Preconditions.checkNotNull(netconfNode.getHost());
227 Preconditions.checkNotNull(netconfNode.getPort());
228 Preconditions.checkNotNull(netconfNode.isTcpOnly());
230 final NetconfConnectorDTO deviceCommunicatorDTO = createDeviceCommunicator(nodeId, netconfNode);
231 final NetconfDeviceCommunicator deviceCommunicator = deviceCommunicatorDTO.getCommunicator();
232 final NetconfClientSessionListener netconfClientSessionListener = deviceCommunicatorDTO.getSessionListener();
233 final NetconfReconnectingClientConfiguration clientConfig =
234 getClientConfig(netconfClientSessionListener, netconfNode);
235 final ListenableFuture<NetconfDeviceCapabilities> future =
236 deviceCommunicator.initializeRemoteConnection(clientDispatcher, clientConfig);
238 activeConnectors.put(nodeId, deviceCommunicatorDTO);
240 Futures.addCallback(future, new FutureCallback<NetconfDeviceCapabilities>() {
242 public void onSuccess(final NetconfDeviceCapabilities result) {
243 LOG.debug("Connector for : " + nodeId.getValue() + " started succesfully");
247 public void onFailure(final Throwable throwable) {
248 LOG.error("Connector for : " + nodeId.getValue() + " failed");
249 // remove this node from active connectors?
256 protected NetconfConnectorDTO createDeviceCommunicator(final NodeId nodeId,
257 final NetconfNode node) {
258 //setup default values since default value is not supported in mdsal
259 final Long defaultRequestTimeoutMillis = node.getDefaultRequestTimeoutMillis() == null
260 ? DEFAULT_REQUEST_TIMEOUT_MILLIS : node.getDefaultRequestTimeoutMillis();
261 final Long keepaliveDelay = node.getKeepaliveDelay() == null
262 ? DEFAULT_KEEPALIVE_DELAY : node.getKeepaliveDelay();
263 final Boolean reconnectOnChangedSchema = node.isReconnectOnChangedSchema() == null
264 ? DEFAULT_RECONNECT_ON_CHANGED_SCHEMA : node.isReconnectOnChangedSchema();
266 final IpAddress ipAddress = node.getHost().getIpAddress();
267 final InetSocketAddress address = new InetSocketAddress(ipAddress.getIpv4Address() != null
268 ? ipAddress.getIpv4Address().getValue() : ipAddress.getIpv6Address().getValue(),
269 node.getPort().getValue());
270 final RemoteDeviceId remoteDeviceId = new RemoteDeviceId(nodeId.getValue(), address);
272 RemoteDeviceHandler<NetconfSessionPreferences> salFacade =
273 createSalFacade(remoteDeviceId);
275 if (keepaliveDelay > 0) {
276 LOG.warn("Adding keepalive facade, for device {}", nodeId);
277 salFacade = new KeepaliveSalFacade(remoteDeviceId, salFacade, keepaliveExecutor.getExecutor(),
278 keepaliveDelay, defaultRequestTimeoutMillis);
281 // pre register yang library sources as fallback schemas to schema registry
282 final List<SchemaSourceRegistration<YangTextSchemaSource>> registeredYangLibSources = Lists.newArrayList();
283 if (node.getYangLibrary() != null) {
284 final String yangLibURL = node.getYangLibrary().getYangLibraryUrl().getValue();
285 final String yangLibUsername = node.getYangLibrary().getUsername();
286 final String yangLigPassword = node.getYangLibrary().getPassword();
288 final LibraryModulesSchemas libraryModulesSchemas;
289 if (yangLibURL != null) {
290 if (yangLibUsername != null && yangLigPassword != null) {
291 libraryModulesSchemas = LibraryModulesSchemas.create(yangLibURL, yangLibUsername, yangLigPassword);
293 libraryModulesSchemas = LibraryModulesSchemas.create(yangLibURL);
296 for (final Map.Entry<SourceIdentifier, URL> sourceIdentifierURLEntry
297 : libraryModulesSchemas.getAvailableModels().entrySet()) {
298 registeredYangLibSources
299 .add(schemaRegistry.registerSchemaSource(
300 new YangLibrarySchemaYangSourceProvider(remoteDeviceId,
301 libraryModulesSchemas.getAvailableModels()),
302 PotentialSchemaSource.create(sourceIdentifierURLEntry.getKey(),
303 YangTextSchemaSource.class, PotentialSchemaSource.Costs.REMOTE_IO.getValue())));
308 final NetconfDevice.SchemaResourcesDTO schemaResourcesDTO = setupSchemaCacheDTO(nodeId, node);
309 final RemoteDevice<NetconfSessionPreferences, NetconfMessage, NetconfDeviceCommunicator> device;
310 if (node.isSchemaless()) {
311 device = new SchemalessNetconfDevice(remoteDeviceId, salFacade);
313 device = new NetconfDeviceBuilder()
314 .setReconnectOnSchemasChange(reconnectOnChangedSchema)
315 .setSchemaResourcesDTO(schemaResourcesDTO)
316 .setGlobalProcessingExecutor(processingExecutor.getExecutor())
317 .setId(remoteDeviceId)
318 .setSalFacade(salFacade)
322 final Optional<UserPreferences> userCapabilities = getUserCapabilities(node);
323 final int rpcMessageLimit =
324 node.getConcurrentRpcLimit() == null ? DEFAULT_CONCURRENT_RPC_LIMIT : node.getConcurrentRpcLimit();
326 if (rpcMessageLimit < 1) {
327 LOG.info("Concurrent rpc limit is smaller than 1, no limit will be enforced for device {}", remoteDeviceId);
330 return new NetconfConnectorDTO(userCapabilities.isPresent()
331 ? new NetconfDeviceCommunicator(remoteDeviceId, device, userCapabilities.get(), rpcMessageLimit)
332 : new NetconfDeviceCommunicator(remoteDeviceId, device, rpcMessageLimit), salFacade);
335 protected NetconfDevice.SchemaResourcesDTO setupSchemaCacheDTO(final NodeId nodeId, final NetconfNode node) {
336 // Setup information related to the SchemaRegistry, SchemaResourceFactory, etc.
337 NetconfDevice.SchemaResourcesDTO schemaResourcesDTO = null;
338 final String moduleSchemaCacheDirectory = node.getSchemaCacheDirectory();
339 // Only checks to ensure the String is not empty or null; further checks related to directory
340 // accessibility and file permissionsare handled during the FilesystemSchemaSourceCache initialization.
341 if (!Strings.isNullOrEmpty(moduleSchemaCacheDirectory)) {
342 // If a custom schema cache directory is specified, create the backing DTO; otherwise,
343 // the SchemaRegistry and SchemaContextFactory remain the default values.
344 if (!moduleSchemaCacheDirectory.equals(DEFAULT_CACHE_DIRECTORY)) {
345 // Multiple modules may be created at once;
346 // synchronize to avoid issues with data consistency among threads.
347 synchronized (SCHEMA_RESOURCES_DTO_MAP) {
348 // Look for the cached DTO to reuse SchemaRegistry and SchemaContextFactory variables
349 // if they already exist
350 schemaResourcesDTO = SCHEMA_RESOURCES_DTO_MAP.get(moduleSchemaCacheDirectory);
351 if (schemaResourcesDTO == null) {
352 schemaResourcesDTO = createSchemaResourcesDTO(moduleSchemaCacheDirectory);
353 schemaResourcesDTO.getSchemaRegistry().registerSchemaSourceListener(
354 TextToASTTransformer.create((SchemaRepository) schemaResourcesDTO.getSchemaRegistry(),
355 schemaResourcesDTO.getSchemaRegistry())
357 SCHEMA_RESOURCES_DTO_MAP.put(moduleSchemaCacheDirectory, schemaResourcesDTO);
360 LOG.info("Netconf connector for device {} will use schema cache directory {} instead of {}",
361 nodeId.getValue(), moduleSchemaCacheDirectory, DEFAULT_CACHE_DIRECTORY);
364 LOG.warn("schema-cache-directory for {} is null or empty; using the default {}",
365 nodeId.getValue(), QUALIFIED_DEFAULT_CACHE_DIRECTORY);
368 if (schemaResourcesDTO == null) {
369 schemaResourcesDTO = new NetconfDevice.SchemaResourcesDTO(schemaRegistry, schemaRepository,
370 schemaContextFactory, new NetconfStateSchemasResolverImpl());
373 return schemaResourcesDTO;
377 * Creates the backing Schema classes for a particular directory.
379 * @param moduleSchemaCacheDirectory The string directory relative to "cache"
380 * @return A DTO containing the Schema classes for the Netconf mount.
382 private NetconfDevice.SchemaResourcesDTO createSchemaResourcesDTO(final String moduleSchemaCacheDirectory) {
383 final SharedSchemaRepository repository = new SharedSchemaRepository(moduleSchemaCacheDirectory);
384 final SchemaContextFactory schemaContextFactory
385 = repository.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT);
386 setSchemaRegistry(repository);
387 setSchemaContextFactory(schemaContextFactory);
388 final FilesystemSchemaSourceCache<YangTextSchemaSource> deviceCache =
389 createDeviceFilesystemCache(moduleSchemaCacheDirectory);
390 repository.registerSchemaSourceListener(deviceCache);
391 return new NetconfDevice.SchemaResourcesDTO(repository, repository, schemaContextFactory,
392 new NetconfStateSchemasResolverImpl());
396 * Creates a <code>FilesystemSchemaSourceCache</code> for the custom schema cache directory.
398 * @param schemaCacheDirectory The custom cache directory relative to "cache"
399 * @return A <code>FilesystemSchemaSourceCache</code> for the custom schema cache directory
401 private FilesystemSchemaSourceCache<YangTextSchemaSource> createDeviceFilesystemCache(
402 final String schemaCacheDirectory) {
403 final String relativeSchemaCacheDirectory = CACHE_DIRECTORY + File.separator + schemaCacheDirectory;
404 return new FilesystemSchemaSourceCache<>(schemaRegistry, YangTextSchemaSource.class,
405 new File(relativeSchemaCacheDirectory));
408 public NetconfReconnectingClientConfiguration getClientConfig(final NetconfClientSessionListener listener,
409 final NetconfNode node) {
411 //setup default values since default value is not supported in mdsal
412 final long clientConnectionTimeoutMillis = node.getConnectionTimeoutMillis() == null
413 ? DEFAULT_CONNECTION_TIMEOUT_MILLIS : node.getConnectionTimeoutMillis();
414 final long maxConnectionAttempts = node.getMaxConnectionAttempts() == null
415 ? DEFAULT_MAX_CONNECTION_ATTEMPTS : node.getMaxConnectionAttempts();
416 final int betweenAttemptsTimeoutMillis = node.getBetweenAttemptsTimeoutMillis() == null
417 ? DEFAULT_BETWEEN_ATTEMPTS_TIMEOUT_MILLIS : node.getBetweenAttemptsTimeoutMillis();
418 final BigDecimal sleepFactor = node.getSleepFactor() == null ? DEFAULT_SLEEP_FACTOR : node.getSleepFactor();
420 final InetSocketAddress socketAddress = getSocketAddress(node.getHost(), node.getPort().getValue());
422 final ReconnectStrategyFactory sf = new TimedReconnectStrategyFactory(eventExecutor,
423 maxConnectionAttempts, betweenAttemptsTimeoutMillis, sleepFactor);
424 final ReconnectStrategy strategy = sf.createReconnectStrategy();
426 final AuthenticationHandler authHandler;
427 final Credentials credentials = node.getCredentials();
428 if (credentials instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114
429 .netconf.node.credentials.credentials.LoginPassword) {
430 authHandler = new LoginPassword(
431 ((org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114
432 .netconf.node.credentials.credentials.LoginPassword) credentials).getUsername(),
433 ((org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114
434 .netconf.node.credentials.credentials.LoginPassword) credentials).getPassword(),
437 throw new IllegalStateException("Only login/password authentification is supported");
440 return NetconfReconnectingClientConfigurationBuilder.create()
441 .withAddress(socketAddress)
442 .withConnectionTimeoutMillis(clientConnectionTimeoutMillis)
443 .withReconnectStrategy(strategy)
444 .withAuthHandler(authHandler)
445 .withProtocol(node.isTcpOnly() ? NetconfClientConfiguration.NetconfClientProtocol.TCP :
446 NetconfClientConfiguration.NetconfClientProtocol.SSH)
447 .withConnectStrategyFactory(sf)
448 .withSessionListener(listener)
452 protected abstract RemoteDeviceHandler<NetconfSessionPreferences> createSalFacade(RemoteDeviceId id);
454 private InetSocketAddress getSocketAddress(final Host host, final int port) {
455 if (host.getDomainName() != null) {
456 return new InetSocketAddress(host.getDomainName().getValue(), port);
458 final IpAddress ipAddress = host.getIpAddress();
459 final String ip = ipAddress.getIpv4Address() != null
460 ? ipAddress.getIpv4Address().getValue() : ipAddress.getIpv6Address().getValue();
461 return new InetSocketAddress(ip, port);
465 private Optional<UserPreferences> getUserCapabilities(final NetconfNode node) {
466 // if none of yang-module-capabilities or non-module-capabilities is specified
467 // just return absent
468 if (node.getYangModuleCapabilities() == null && node.getNonModuleCapabilities() == null) {
469 return Optional.absent();
472 final List<String> capabilities = new ArrayList<>();
474 boolean overrideYangModuleCaps = false;
475 if (node.getYangModuleCapabilities() != null) {
476 capabilities.addAll(node.getYangModuleCapabilities().getCapability());
477 overrideYangModuleCaps = node.getYangModuleCapabilities().isOverride();
480 //non-module capabilities should not exist in yang module capabilities
481 final NetconfSessionPreferences netconfSessionPreferences = NetconfSessionPreferences.fromStrings(capabilities);
482 Preconditions.checkState(netconfSessionPreferences.getNonModuleCaps().isEmpty(),
483 "List yang-module-capabilities/capability should contain only module based capabilities. "
484 + "Non-module capabilities used: " + netconfSessionPreferences.getNonModuleCaps());
486 boolean overrideNonModuleCaps = false;
487 if (node.getNonModuleCapabilities() != null) {
488 capabilities.addAll(node.getNonModuleCapabilities().getCapability());
489 overrideNonModuleCaps = node.getNonModuleCapabilities().isOverride();
492 return Optional.of(new UserPreferences(NetconfSessionPreferences
493 .fromStrings(capabilities, CapabilityOrigin.UserDefined), overrideYangModuleCaps, overrideNonModuleCaps));
496 private static final class TimedReconnectStrategyFactory implements ReconnectStrategyFactory {
497 private final Long connectionAttempts;
498 private final EventExecutor executor;
499 private final double sleepFactor;
500 private final int minSleep;
502 TimedReconnectStrategyFactory(final EventExecutor executor, final Long maxConnectionAttempts,
503 final int minSleep, final BigDecimal sleepFactor) {
504 if (maxConnectionAttempts != null && maxConnectionAttempts > 0) {
505 connectionAttempts = maxConnectionAttempts;
507 connectionAttempts = null;
510 this.sleepFactor = sleepFactor.doubleValue();
511 this.executor = executor;
512 this.minSleep = minSleep;
516 public ReconnectStrategy createReconnectStrategy() {
517 final Long maxSleep = null;
518 final Long deadline = null;
520 return new TimedReconnectStrategy(executor, minSleep,
521 minSleep, sleepFactor, maxSleep, connectionAttempts, deadline);
525 protected static class NetconfConnectorDTO implements AutoCloseable {
527 private final NetconfDeviceCommunicator communicator;
528 private final RemoteDeviceHandler<NetconfSessionPreferences> facade;
530 public NetconfConnectorDTO(final NetconfDeviceCommunicator communicator,
531 final RemoteDeviceHandler<NetconfSessionPreferences> facade) {
532 this.communicator = communicator;
533 this.facade = facade;
536 public NetconfDeviceCommunicator getCommunicator() {
540 public RemoteDeviceHandler<NetconfSessionPreferences> getFacade() {
544 public NetconfClientSessionListener getSessionListener() {
549 public void close() {
550 communicator.close();